Highlighted

Editing line/arrow shape tool

Adobe Community Professional ,
Oct 03, 2019

Copy link to clipboard

Copied

Have you ever drawn a bunch of arrows or lines then needed to change their properties? Normally, you would have to redraw them all with new parameters in the line/arrow tool. Here is a script that allows you to edit an existing line or arrow, drawn with the shape tool.

arrows.jpg

#target photoshop

//copyright 2017 Chuck Uebele, all rights reserved
//Use at your own risk.

var xmlFile = new File(Folder.desktop+'/ArrowPrefs.xml');
var xmlPref

if(xmlFile.exists){
    xmlPref = readXMLFile (xmlFile)
    //alert(xmlPref.prefs.lines.children().length())
    //alert(xmlPref.prefs.lines.children()[0].@preset)
    }
else{xmlPref = new XML('<root><prefs><lines/><arrows/></prefs>')};


//varables for lines and points
var run = true;
var lineType;
var origLineWidth;
var lineAngTan1;//from first point to oppsite side of line
var lineAngTan2;//From oppsite side of line to first point
var lineLengthAng;
var lineLength;
var lineMid1;//mid width on line from first point
var lineMid2;//mid width on line from oppsite end of line
var newWidth = 20
var ptTemp1
var ptTemp2
var ptTemp3
var ptTemp4
var dropLst = new Array()
var prefsDrop

var headIntersect1;
var headIntersect2;
//-----------
var arrowLength;
var arrowWidth;
var arrowEndsMid;
var arrowConcave;
var arrowConcaveFactor;
var arrowLengthFactor;
var arrowWidthFactor;
/////////////////

app.preferences.rulerUnits = Units.PIXELS;
try{
    var doc = activeDocument
    var sLay = doc.activeLayer
    var sLayName = sLay.name + ' Shape Path'
    var cPath = doc.pathItems.getByName(sLayName)
    var ptArray = new Array();
    var ptNewArray = new Array();
    var idPath;


//var numAnchors = cPath.subPathItems[0].pathPoints.length;
recordAnchors (cPath);
var numAnchors = ptArray.length;
    }
catch(e){
    run = false;
    var numAnchors=0
    }


switch(numAnchors){
    case 4:
        lineType = 'Normal Line'
        origLineWidth = lineL (ptArray[0][0], ptArray[0][1], ptArray[1][0], ptArray[1][1]);
        lineAngTan1 = getAng (ptArray[0][0], ptArray[0][1], ptArray[1][0], ptArray[1][1]);
        lineAngTan2 = getAng (ptArray[1][0], ptArray[1][1], ptArray[0][0], ptArray[0][1]);
        lineMid1 = [(ptArray[0][0] + ptArray[1][0])/2,(ptArray[0][1] + ptArray[1][1])/2 ];  
        lineMid2 = [(ptArray[2][0] + ptArray[3][0])/2,(ptArray[2][1] + ptArray[3][1])/2 ];
        
        ui ();
        
        ptNewArray[0] = newPt (lineMid1[0],lineMid1[1], newWidth/2, lineAngTan1);
        ptNewArray[3] = newPt (lineMid2[0],lineMid2[1], newWidth/2, lineAngTan1);
        ptNewArray[1] = newPt (lineMid1[0],lineMid1[1], newWidth/2, lineAngTan2);
        ptNewArray[2] = newPt (lineMid2[0],lineMid2[1], newWidth/2, lineAngTan2);


        break;
    case 7:
        if(Math.round (getAng (ptArray[0][0], ptArray[0][1], ptArray[6][0], ptArray[6][1]))==Math.round (getAng (ptArray[1][0], ptArray[1][1], ptArray[2][0], ptArray[2][1]))){
            //alert('end')
            lineType = 'Single Arrow End';
            origLineWidth = lineL (ptArray[0][0], ptArray[0][1], ptArray[1][0], ptArray[1][1]);
            lineAngTan1 = getAng (ptArray[0][0], ptArray[0][1], ptArray[1][0], ptArray[1][1]);
            lineAngTan2 = getAng (ptArray[1][0], ptArray[1][1], ptArray[0][0], ptArray[0][1]);
            lineMid1 = [(ptArray[1][0] + ptArray[0][0])/2,(ptArray[1][1] + ptArray[0][1])/2 ];  
            lineMid2 = [(ptArray[2][0] + ptArray[6][0])/2,(ptArray[2][1] + ptArray[6][1])/2 ];
            arrowEndsMid = [(ptArray[3][0] + ptArray[5][0])/2,(ptArray[3][1] + ptArray[5][1])/2 ];            
            arrowLength = lineL (ptArray[4][0], ptArray[4][1], arrowEndsMid[0], arrowEndsMid[1]);              
            arrowWidth = lineL (ptArray[5][0], ptArray[5][1], ptArray[3][0], ptArray[3][1]);            
            arrowConcaveFactor = getConcaveFactor (ptArray[6][0], ptArray[6][1], ptArray[0][0], ptArray[0][1], ptArray[4][0], ptArray[4][1], ptArray[5][0], ptArray[5][1], ptArray[3][0], ptArray[3][1]);
            arrowLengthFactor = Math.round((arrowLength/origLineWidth)*100);
            arrowWidthFactor = Math.round((arrowWidth/origLineWidth)*100);            
            lineLengthAng = getAng (arrowEndsMid[0], arrowEndsMid[1],ptArray[4][0], ptArray[4][1]);
            //////////////////////////////////////
            ui ()
            //New points
            arrowEndsMid = newPt (ptArray[4][0], ptArray[4][1], newWidth*arrowLengthFactor*.01, lineLengthAng);            
            ptNewArray[5] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan1);
            ptNewArray[3] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan2);
            ptNewArray[1] = newPt (lineMid1[0], lineMid1[1], newWidth/2, lineAngTan2);
            ptNewArray[0] = newPt (lineMid1[0], lineMid1[1], newWidth/2, lineAngTan1);           
            ptTemp1 = newPt (lineMid2[0], lineMid2[1], newWidth/2, lineAngTan1);            
            ptTemp2 = newPt (lineMid2[0], lineMid2[1], newWidth/2, lineAngTan2);              
            headIntersect1= getIntersect (ptTemp1[0], ptTemp1[1], ptNewArray[0][0], ptNewArray[0][1], ptArray[4][0], ptArray[4][1], ptNewArray[5][0], ptNewArray[5][1]);            
            headIntersect2= getIntersect (ptTemp2[0], ptTemp2[1], ptNewArray[1][0], ptNewArray[1][1], ptArray[4][0], ptArray[4][1], ptNewArray[3][0], ptNewArray[3][1]);            
            ptTemp3 = getIntersect (ptTemp1[0], ptTemp1[1], ptNewArray[0][0], ptNewArray[0][1], ptNewArray[5][0], ptNewArray[5][1], ptNewArray[3][0], ptNewArray[3][1]);            
            ptTemp4 = getIntersect (ptTemp2[0], ptTemp2[1], ptNewArray[1][0], ptNewArray[1][1], ptNewArray[5][0], ptNewArray[5][1], ptNewArray[3][0], ptNewArray[3][1]);            
            arrowConcave = lineL (headIntersect1[0], headIntersect1[1], ptTemp3[0], ptTemp3[1])*arrowConcaveFactor*.01;            
            ptNewArray[6] = newPt (ptTemp3[0], ptTemp3[1], -arrowConcave, lineLengthAng);            
            ptNewArray[2] = newPt (ptTemp4[0], ptTemp4[1], -arrowConcave, lineLengthAng);           
            }
        else{
            //alert('beginning')  
            lineType = 'Single Arrow Start';
            origLineWidth = lineL (ptArray[0][0], ptArray[0][1], ptArray[4][0], ptArray[4][1]);
            lineAngTan1 = getAng (ptArray[0][0], ptArray[0][1], ptArray[4][0], ptArray[4][1]);
            lineAngTan2 = getAng (ptArray[4][0], ptArray[4][1], ptArray[0][0], ptArray[0][1]);
            lineMid1 = [(ptArray[4][0] + ptArray[0][0])/2,(ptArray[4][1] + ptArray[0][1])/2 ];  
            lineMid2 = [(ptArray[5][0] + ptArray[6][0])/2,(ptArray[5][1] + ptArray[6][1])/2 ];
            arrowEndsMid = [(ptArray[1][0] + ptArray[3][0])/2,(ptArray[1][1] + ptArray[3][1])/2 ]
            arrowLength = lineL (ptArray[2][0], ptArray[2][1], arrowEndsMid[0], arrowEndsMid[1]);         
            arrowWidth = lineL (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
            arrowConcaveFactor = getConcaveFactor (ptArray[0][0], ptArray[0][1], ptArray[6][0], ptArray[6][1], ptArray[2][0], ptArray[2][1], ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1])
            arrowLengthFactor = Math.round((arrowLength/origLineWidth)*100);
            arrowWidthFactor = Math.round((arrowWidth/origLineWidth)*100);
            lineLengthAng = getAng (arrowEndsMid[0], arrowEndsMid[1],ptArray[2][0], ptArray[2][1]);
              
            //////////////////////////////////////
            ui ()
            //New points
            arrowEndsMid = newPt (ptArray[2][0], ptArray[2][1], newWidth*arrowLengthFactor*.01, lineLengthAng);
            ptNewArray[1] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan1);
            ptNewArray[3] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan2);
            ptNewArray[5] = newPt (lineMid2[0], lineMid2[1], newWidth/2, lineAngTan2);
            ptNewArray[6] = newPt (lineMid2[0], lineMid2[1], newWidth/2, lineAngTan1);
            ptTemp1 = newPt (lineMid1[0], lineMid1[1], newWidth/2, lineAngTan1);
            ptTemp2 = newPt (lineMid1[0], lineMid1[1], newWidth/2, lineAngTan2);    
            headIntersect1= getIntersect (ptTemp1[0], ptTemp1[1], ptNewArray[6][0], ptNewArray[6][1], ptArray[2][0], ptArray[2][1], ptNewArray[1][0], ptNewArray[1][1])
            headIntersect2= getIntersect (ptTemp2[0], ptTemp2[1], ptNewArray[5][0], ptNewArray[5][1], ptArray[2][0], ptArray[2][1], ptNewArray[3][0], ptNewArray[3][1])
            ptTemp3 = getIntersect (ptTemp1[0], ptTemp1[1], ptNewArray[6][0], ptNewArray[6][1], ptNewArray[1][0], ptNewArray[1][1], ptNewArray[3][0], ptNewArray[3][1])
            ptTemp4 = getIntersect (ptTemp2[0], ptTemp2[1], ptNewArray[5][0], ptNewArray[5][1], ptNewArray[1][0], ptNewArray[1][1], ptNewArray[3][0], ptNewArray[3][1])
            arrowConcave = lineL (headIntersect1[0], headIntersect1[1], ptTemp3[0], ptTemp3[1])*arrowConcaveFactor*.01;
            ptNewArray[0] = newPt (ptTemp3[0], ptTemp3[1], -arrowConcave, lineLengthAng);
            ptNewArray[4] = newPt (ptTemp4[0], ptTemp4[1], -arrowConcave, lineLengthAng);
            }
    
        break;
    case 10:
            lineType = 'Double Arrow';
            origLineWidth = lineL (ptArray[0][0], ptArray[0][1], ptArray[4][0], ptArray[4][1]);
            lineAngTan1 = getAng (ptArray[0][0], ptArray[0][1], ptArray[4][0], ptArray[4][1]);
            lineAngTan2 = getAng (ptArray[4][0], ptArray[4][1], ptArray[0][0], ptArray[0][1]);                 
            arrowEndsMid = [(ptArray[1][0] + ptArray[3][0])/2,(ptArray[1][1] + ptArray[3][1])/2 ];            
            arrowLength = lineL (ptArray[2][0], ptArray[2][1], arrowEndsMid[0], arrowEndsMid[1]);             
            arrowWidth = lineL (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);            
            arrowConcaveFactor = getConcaveFactor (ptArray[0][0], ptArray[0][1], ptArray[9][0], ptArray[9][1], ptArray[2][0], ptArray[2][1], ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
            arrowLengthFactor = Math.round((arrowLength/origLineWidth)*100);
            arrowWidthFactor = Math.round((arrowWidth/origLineWidth)*100);
            lineLengthAng = getAng (ptArray[7][0], ptArray[7][1],ptArray[2][0], ptArray[2][1]);    
            /////////////////////////////////////////////
            ui ()
            //new points
            arrowEndsMid = newPt (ptArray[2][0], ptArray[2][1], newWidth*arrowLengthFactor*.01, lineLengthAng);
            ptNewArray[1] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan1);            
            ptNewArray[3] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan2);
            arrowEndsMid = newPt (ptArray[7][0], ptArray[7][1], -newWidth*arrowLengthFactor*.01, lineLengthAng); 
            ptNewArray[8] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan1);            
            ptNewArray[6] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan2);            
            ptTemp1 = newPt (ptArray[2][0], ptArray[2][1], newWidth/2, lineAngTan1);
            var ptTemp1a = newPt (ptArray[7][0], ptArray[7][1], newWidth/2, lineAngTan1);
            ptTemp2 = newPt (ptArray[2][0], ptArray[2][1], newWidth/2, lineAngTan2);
            var ptTemp2a = newPt (ptArray[7][0], ptArray[7][1], newWidth/2, lineAngTan2);
            
            headIntersect1= getIntersect (ptTemp1[0], ptTemp1[1], ptTemp1a[0], ptTemp1a[1], ptArray[2][0], ptArray[2][1], ptNewArray[1][0], ptNewArray[1][1]);
            headIntersect2= getIntersect (ptTemp2[0], ptTemp2[1], ptTemp2a[0], ptTemp2a[1], ptArray[2][0], ptArray[2][1], ptNewArray[3][0], ptNewArray[3][1]);
            var headIntersect3= getIntersect (ptTemp1[0], ptTemp1[1], ptTemp1a[0], ptTemp1a[1], ptArray[7][0], ptArray[7][1], ptNewArray[8][0], ptNewArray[8][1]);
            var headIntersect4= getIntersect (ptTemp2[0], ptTemp2[1], ptTemp2a[0], ptTemp2a[1], ptArray[7][0], ptArray[7][1], ptNewArray[6][0], ptNewArray[6][1]); 
            ptTemp3 = getIntersect (ptTemp1[0], ptTemp1[1], ptTemp1a[0], ptTemp1a[1], ptNewArray[1][0], ptNewArray[1][1], ptNewArray[3][0], ptNewArray[3][1]);
            var ptTemp3a = getIntersect (ptTemp2[0], ptTemp2[1], ptTemp2a[0], ptTemp2a[1], ptNewArray[1][0], ptNewArray[1][1], ptNewArray[3][0], ptNewArray[3][1]);
            ptTemp4 = getIntersect (ptTemp1[0], ptTemp1[1], ptTemp1a[0], ptTemp1a[1], ptNewArray[6][0], ptNewArray[6][1], ptNewArray[8][0], ptNewArray[8][1]);
            var ptTemp4a = getIntersect (ptTemp2[0], ptTemp2[1], ptTemp2a[0], ptTemp2a[1], ptNewArray[6][0], ptNewArray[6][1], ptNewArray[8][0], ptNewArray[8][1]);
            
           arrowConcave = lineL (headIntersect1[0], headIntersect1[1], ptTemp3[0], ptTemp3[1])*arrowConcaveFactor*.01;
           ptNewArray[0] = newPt (ptTemp3[0], ptTemp3[1], -arrowConcave, lineLengthAng);
           ptNewArray[4] = newPt (ptTemp3a[0], ptTemp3a[1], -arrowConcave, lineLengthAng);      
           
           ptNewArray[9] = newPt (ptTemp4[0], ptTemp4[1], arrowConcave, lineLengthAng);
           ptNewArray[5] = newPt (ptTemp4a[0], ptTemp4a[1], arrowConcave, lineLengthAng);              
            
        break;
        default:
        run = false;
        alert("The layer selected didn't match the criteria for a line or arrow")
    }//end switch

if(run){
    var myPathInfo = mkNewPathInfo ();
    deltPath ();
    var tempPath = app.activeDocument.pathItems.add( 'temp', myPathInfo);
    selPath ();
    doc.activeLayer = sLay;
    mkPath ()
    tempPath.remove();
    }

////////////////////////////////////
function ui(){
    var dlg = new Window('dialog','Edit Line Tool Line');
        dlg.alignChildren = ['left','top'];
            dlg.lType = dlg.add('statictext',undefined,lineType);        
            dlg.wGp = dlg.add('group');
                dlg.wGp.alignChildren = ['left','top'];
                dlg.wGp.sTxts = dlg.wGp.add('statictext',undefined,'Line Width');
                dlg.wGp.eTxt = dlg.wGp.add('edittext',undefined,Math.round(origLineWidth));
                    dlg.wGp.eTxt.size = [50,12];
                dlg.wGp.sTxte = dlg.wGp.add('statictext',undefined,'px');
                
            if(lineType!='Normal Line'){
                for(var i=0;i<xmlPref.prefs.arrows.children().length();i++){
                    dropLst[i]= xmlPref.prefs.arrows.children()[i].@preset
                    }
                }
            else{
                for(var i=0;i<xmlPref.prefs.lines.children().length();i++){
                    dropLst[i]= xmlPref.prefs.lines.children()[i].@preset
                    }               
                }
            if(lineType!='Normal Line'){
                dlg.aLgp = dlg.add('group');
                    dlg.aLgp.alignChildren = ['left','top'];
                    dlg.aLgp.sTxts = dlg.aLgp.add('statictext',undefined,'Arrow Length');
                    dlg.aLgp.ALen = dlg.aLgp.add('edittext',undefined,arrowLengthFactor);
                        dlg.aLgp.ALen.size = [50,12];
                    dlg.aLgp.sTxte = dlg.aLgp.add('statictext',undefined,'%');
                    
                dlg.aWgp = dlg.add('group');
                    dlg.aWgp.alignChildren = ['left','top'];
                    dlg.aWgp.sTxts = dlg.aWgp.add('statictext',undefined,'Arrow Width');
                    dlg.aWgp.AWid = dlg.aWgp.add('edittext',undefined,arrowWidthFactor);
                        dlg.aWgp.AWid.size = [50,12];
                    dlg.aWgp.sTxte = dlg.aWgp.add('statictext',undefined,'%');     
                    
                dlg.aConGp = dlg.add('group');
                    dlg.aConGp.alignChildren = ['left','top'];
                    dlg.aConGp.sTxts = dlg.aConGp.add('statictext',undefined,'Arrow Concave');
                    dlg.aConGp.ACon = dlg.aConGp.add('edittext',undefined,arrowConcaveFactor);
                        dlg.aConGp.ACon.size = [50,12];
                    dlg.aConGp.sTxte = dlg.aConGp.add('statictext',undefined,'%');                      
                }
            
            dlg.btnGp = dlg.add('group');
            dlg.btnGp.okay = dlg.btnGp.add('button',undefined,'Okay');
            dlg.btnGp.cancel = dlg.btnGp.add('button',undefined,'Cancel');
            
        dlg.prefsPn = dlg.add('panel',undefined,'Preferences');
            dlg.prefsPn.alignChildren = ['left','top'];
            dlg.prefsPn.save = dlg.prefsPn.add('button',undefined,'Save Preference');
            dlg.prefsPn.del = dlg.prefsPn.add('button',undefined,'Delete Preference');
            
            prefsDrop = dlg.prefsPn.add('dropdownlist',undefined,dropLst);
            prefsDrop.title = 'Load Preferences';            
            prefsDrop.size = [300,25];      
            
        prefsDrop.onChange = function(){
            if(lineType!='Normal Line'){
                dlg.wGp.eTxt.text = xmlPref.prefs.arrows.children()[parseInt(prefsDrop.selection)].width
                dlg.aLgp.ALen.text = xmlPref.prefs.arrows.children()[parseInt(prefsDrop.selection)].leng
                dlg.aWgp.AWid.text = xmlPref.prefs.arrows.children()[parseInt(prefsDrop.selection)].aWidth
                dlg.aConGp.ACon.text = xmlPref.prefs.arrows.children()[parseInt(prefsDrop.selection)].concave
                }
            else{
                dlg.wGp.eTxt.text = xmlPref.prefs.lines.children()[parseInt(prefsDrop.selection)].width
                }
            };
            
        dlg.wGp.eTxt.onChange = function(){
            textToNum (1, 1000, dlg.wGp.eTxt, origLineWidth);
            }
        if(lineType!='Normal Line'){        
            dlg.aLgp.ALen.onChange = function(){
                textToNum (1, 10000, dlg.aLgp.ALen, arrowLengthFactor);
                }       
            
            dlg.aWgp.AWid.onChange = function(){
                textToNum (1, 10000, dlg.aWgp.AWid, arrowWidthFactor);
                } 
            
            dlg.aWgp.AWid.onChange = function(){
                textToNum (-50, 50, dlg.aConGp.ACon, arrowConcaveFactor);
                }    
        }//end if
            
            dlg.prefsPn.save.onClick = function(){
                savePrefs ();

                }
            
            dlg.prefsPn.del.onClick = function(){
                if(prefsDrop.selection != null){
                    var selc = parseInt(prefsDrop.selection);                    
                    prefsDrop.remove(selc);
                    if(lineType!='Normal Line'){
                        delete xmlPref.prefs.arrows.children()[selc];
                        }
                    else{
                        delete xmlPref.prefs.lines.children()[selc];
                        }
                    writeXMLFile (xmlFile, xmlPref)
                    }

                }            
            
        dlg.btnGp.okay.onClick = function(){
            dlg.close();
            newWidth = parseInt (dlg.wGp.eTxt.text);
                if(lineType!='Normal Line'){
                arrowLengthFactor = parseInt (dlg.aLgp.ALen.text);
                arrowWidthFactor = parseInt (dlg.aWgp.AWid.text);
                arrowConcaveFactor = parseInt (dlg.aConGp.ACon.text);
                }
            }
        
        dlg.btnGp.cancel.onClick = function(){            
            run = false;
            dlg.close()
            }  
//==================
function savePrefs(){
    var newName = prompt ('Enter New Profile Name', '', 'Save Preferences');
    var prefGood = true;
    for(var i=0;i<prefsDrop.items.length;i++){
        if(prefsDrop.items[i].text == newName){
            newName = prompt ('That preset exists\nPlease choose a unique name','', 'Save Preferences' );
            i=0
            }
        }
        prefsDrop.add('item',newName)
        if(lineType=='Normal Line'){
            xmlPref.prefs.lines.appendChild (XML('<line preset="'+ newName+ '"><width>'+dlg.wGp.eTxt.text+'</width></line>'));
            }
        else{   
            xmlPref.prefs.arrows.appendChild (XML('<arrow preset="'+ newName+ '"><width>'+dlg.wGp.eTxt.text+'</width><leng>'+dlg.aLgp.ALen.text+'</leng><aWidth>'+dlg.aWgp.AWid.text+'</aWidth><concave>'+dlg.aConGp.ACon.text+'</concave></arrow>'));
            }
        writeXMLFile (xmlFile, xmlPref) 

    }

//=====================        
    dlg.show();
    }

function textToNum(sMin,sMax,e,def){
    def=Math.round (def)
	var sHold = def;
			if(isNaN(parseInt(e.text))){
			alert('"' + e.text + '" is not a number\nEnter a value between ' + sMin + '-' + sMax );
			e.text = def};
            else{
                sHold = parseInt(e.text)
			if(sHold < sMin){
				rangeAlert();
				sHold = sMin;				
				};
			if(sHold > sMax){
				rangeAlert();
				sHold = sMax;
				};
			e.text = sHold;
            }
	function rangeAlert(){alert('Number range must be between ' + sMin + '-' + sMax)}; 
};//end function textToNum

function getConcaveFactor(x1,y1,x2,y2, x3, y3, x4, y4, x5, y5){//1 & 2 =  shaft pt 1 &2; 3 & 4 = arrow length line; 5 = tail point opp side
    var ptAH = getIntersect (x1, y1, x2, y2, x3, y3, x4, y4);//intersection of shaft with sides of arrowhead
    //mkDot (ptAH)
    var ptTail = getIntersect (x1, y1, x2, y2, x4, y4, x5, y5);//Intersection of arrow tip ends cross shaft
    var conTotalLen = lineL (x1, y1, ptAH[0], ptAH[1]);//gets total length to see if the concave goes in toward the arrowhead or out (-)
    var conFullLen =  lineL (ptTail[0], ptTail[1], ptAH[0], ptAH[1]);//length of arrow from end tips to intersection with shaft
    var conF = lineL (x1, y1, ptTail[0], ptTail[1])/conFullLen
    if(conTotalLen>conFullLen){conF*=-1}
    return Math.round(conF*100)
    }

function getIntersect(x1,y1,x2,y2, x3, y3, x4, y4){
    var slope1 = (y1-y2)/(x1-x2);
    var bIntersect1 = y1-(slope1*x1)
    var slope2 = (y3-y4)/(x3-x4);
    var bIntersect2 = y3-(slope2*x3)  
    var xNew ;
    var yNew;
    if(bIntersect1=='-Infinity'||bIntersect1=='Infinity'){
        xNew=x1;
        yNew = slope2*xNew + bIntersect2;
        }
    else if(bIntersect2=='-Infinity'||bIntersect2=='Infinity'){
        xNew = x3;
        yNew = slope1*xNew + bIntersect1;
        }
    else{
        xNew= (-(bIntersect1-bIntersect2))/(slope1-slope2);
        yNew = slope1*xNew + bIntersect1
        }
    
    
    return [xNew,yNew]
    }

function recordAnchors(pathObj){
    ptArray = new Array();
    for(var i=0;i<pathObj.subPathItems[0].pathPoints.length;i++){
        ptNewArray [i] = ptArray[i] = pathObj.subPathItems[0].pathPoints[i].anchor;
        }//end loop
    }//end function

function mkNewPathInfo(){
    var pathArray = new Array();
    var piArray = new Array();
    for(var i=0;i<ptNewArray.length;i++){
         piArray[i] = new PathPointInfo;
         piArray[i].kind = cPath.subPathItems[0].pathPoints[i].kind; 
         piArray[i].anchor = ptNewArray[i];
         piArray[i].leftDirection = ptNewArray[i];
         piArray[i].rightDirection = ptNewArray[i];
        }//end loop
    pathArray[0] = new SubPathInfo();
    pathArray[0].operation = cPath.subPathItems[0].operation;
    pathArray[0].closed = cPath.subPathItems[0].closed;
    pathArray[0].entireSubPath = piArray;  
    return pathArray;
    };//end function

/////////////////////
    function extractSubPathInfo(pathObj,oldPoint,newPoint){
        var pathArray = new Array();
        var pl = pathObj.subPathItems.length;
        for(var s=0;s<pl;s++){
            var pArray = new Array();
              for(var i=0;i<pathObj.subPathItems[s].pathPoints.length;i++){
                 pArray[i] = new PathPointInfo;
                 pArray[i].kind = pathObj.subPathItems[s].pathPoints[i].kind;
             if(pathObj.subPathItems[s].pathPoints[i].anchor[0]==oldPoint[0] &&
                   pathObj.subPathItems[s].pathPoints[i].anchor[1]==oldPoint[1]){
                pArray[i].anchor = newPoint;
                pArray[i].leftDirection = newPoint;
                pArray[i].rightDirection = newPoint;
             }else{
                pArray[i].anchor = pathObj.subPathItems[s].pathPoints[i].anchor;
                pArray[i].leftDirection = pathObj.subPathItems[s].pathPoints[i].leftDirection;
                pArray[i].rightDirection = pathObj.subPathItems[s].pathPoints[i].rightDirection;
             }
              };
            pathArray[pathArray.length] = new Array();
            pathArray[pathArray.length - 1] = new SubPathInfo();
            pathArray[pathArray.length - 1].operation = pathObj.subPathItems[s].operation;
            pathArray[pathArray.length - 1].closed = pathObj.subPathItems[s].closed;
            pathArray[pathArray.length - 1].entireSubPath = pArray;
        };
        return pathArray;
    };
        
    function deltPath(){
        var idDlt = charIDToTypeID( "Dlt " );
        var desc2 = new ActionDescriptor();
        var idnull = charIDToTypeID( "null" );
            var ref1 = new ActionReference();
            idPath = charIDToTypeID( "Path" );
            var idvectorMask = stringIDToTypeID( "vectorMask" );
            ref1.putEnumerated( idPath, idPath, idvectorMask );
            var idLyr = charIDToTypeID( "Lyr " );
            var idOrdn = charIDToTypeID( "Ordn" );
            var idTrgt = charIDToTypeID( "Trgt" );
            ref1.putEnumerated( idLyr, idOrdn, idTrgt );
        desc2.putReference( idnull, ref1 );
        executeAction( idDlt, desc2, DialogModes.NO );
        }
    
    function selPath(){
         var idslct = charIDToTypeID( "slct" );
            var desc2 = new ActionDescriptor();
            var idnull = charIDToTypeID( "null" );
                var ref1 = new ActionReference();
                var idPath = charIDToTypeID( "Path" );
                ref1.putName( idPath, "temp" );
            desc2.putReference( idnull, ref1 );
        executeAction( idslct, desc2, DialogModes.NO );       
        }
    
    function mkPath(){
         var idMk = charIDToTypeID( "Mk  " );
            var desc10 = new ActionDescriptor();
            var idnull = charIDToTypeID( "null" );
                var ref3 = new ActionReference();
                var idPath = charIDToTypeID( "Path" );
                ref3.putClass( idPath );
            desc10.putReference( idnull, ref3 );
            var idAt = charIDToTypeID( "At  " );
                var ref4 = new ActionReference();
                var idPath = charIDToTypeID( "Path" );
                var idPath = charIDToTypeID( "Path" );
                var idvectorMask = stringIDToTypeID( "vectorMask" );
                ref4.putEnumerated( idPath, idPath, idvectorMask );
            desc10.putReference( idAt, ref4 );
            var idUsng = charIDToTypeID( "Usng" );
                var ref5 = new ActionReference();
                var idPath = charIDToTypeID( "Path" );
                var idOrdn = charIDToTypeID( "Ordn" );
                var idTrgt = charIDToTypeID( "Trgt" );
                ref5.putEnumerated( idPath, idOrdn, idTrgt );
            desc10.putReference( idUsng, ref5 );
        executeAction( idMk, desc10, DialogModes.NO );       
        }
    
function lineL (ax,ay,bx,by){
    var x = Math.abs (ax-bx);
    var y = Math.abs (ay-by);
    var len = Math.sqrt (Math.pow (x, 2) + Math.pow (y, 2));
    return len
    }

function getAng(ax,ay,bx,by){
    var dx = ax-bx;
    var dy = ay-by;
    var theta = Math.atan2 (dy, dx);
    //theta *= 180/Math.PI
    return theta;
    }

function newPt (x1,y1,rad,ang){
    var newEnd = new Array();
    newEnd[0] = x1 + rad * Math.cos (ang);
    newEnd[1] = y1 + rad * Math.sin (ang);
    return newEnd;
    }

//===============READ/WRITE functions========================================
//=========================================================================
 function readXMLFile(file) {
	if (!file.exists) {
		alert( "Cannot find file: " + deodeURI(file.absoluteURI));
		}
	else{
		file.encoding = "UTF8";
		file.lineFeed = "unix";
		file.open("r", "TEXT", "????");
		var str = file.read();
		file.close();

		return new XML(str);
		};
};

function writeXMLFile(file, xml) {
	if (!(xml instanceof XML)) {
		alert( "Bad XML parameter");
		};
	else{
		file.encoding = "UTF8";
		file.open("w", "TEXT", "????");
		//unicode signature, this is UTF16 but will convert to UTF8 "EF BB BF"
		file.write("\uFEFF");
		file.lineFeed = "unix";
		file.write(xml.toXMLString());
		file.close();
		};
	};
 //=========================================================================

Topics

Actions and scripting, FAQ, How to

Views

337

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more

Editing line/arrow shape tool

Adobe Community Professional ,
Oct 03, 2019

Copy link to clipboard

Copied

Have you ever drawn a bunch of arrows or lines then needed to change their properties? Normally, you would have to redraw them all with new parameters in the line/arrow tool. Here is a script that allows you to edit an existing line or arrow, drawn with the shape tool.

arrows.jpg

#target photoshop

//copyright 2017 Chuck Uebele, all rights reserved
//Use at your own risk.

var xmlFile = new File(Folder.desktop+'/ArrowPrefs.xml');
var xmlPref

if(xmlFile.exists){
    xmlPref = readXMLFile (xmlFile)
    //alert(xmlPref.prefs.lines.children().length())
    //alert(xmlPref.prefs.lines.children()[0].@preset)
    }
else{xmlPref = new XML('<root><prefs><lines/><arrows/></prefs>')};


//varables for lines and points
var run = true;
var lineType;
var origLineWidth;
var lineAngTan1;//from first point to oppsite side of line
var lineAngTan2;//From oppsite side of line to first point
var lineLengthAng;
var lineLength;
var lineMid1;//mid width on line from first point
var lineMid2;//mid width on line from oppsite end of line
var newWidth = 20
var ptTemp1
var ptTemp2
var ptTemp3
var ptTemp4
var dropLst = new Array()
var prefsDrop

var headIntersect1;
var headIntersect2;
//-----------
var arrowLength;
var arrowWidth;
var arrowEndsMid;
var arrowConcave;
var arrowConcaveFactor;
var arrowLengthFactor;
var arrowWidthFactor;
/////////////////

app.preferences.rulerUnits = Units.PIXELS;
try{
    var doc = activeDocument
    var sLay = doc.activeLayer
    var sLayName = sLay.name + ' Shape Path'
    var cPath = doc.pathItems.getByName(sLayName)
    var ptArray = new Array();
    var ptNewArray = new Array();
    var idPath;


//var numAnchors = cPath.subPathItems[0].pathPoints.length;
recordAnchors (cPath);
var numAnchors = ptArray.length;
    }
catch(e){
    run = false;
    var numAnchors=0
    }


switch(numAnchors){
    case 4:
        lineType = 'Normal Line'
        origLineWidth = lineL (ptArray[0][0], ptArray[0][1], ptArray[1][0], ptArray[1][1]);
        lineAngTan1 = getAng (ptArray[0][0], ptArray[0][1], ptArray[1][0], ptArray[1][1]);
        lineAngTan2 = getAng (ptArray[1][0], ptArray[1][1], ptArray[0][0], ptArray[0][1]);
        lineMid1 = [(ptArray[0][0] + ptArray[1][0])/2,(ptArray[0][1] + ptArray[1][1])/2 ];  
        lineMid2 = [(ptArray[2][0] + ptArray[3][0])/2,(ptArray[2][1] + ptArray[3][1])/2 ];
        
        ui ();
        
        ptNewArray[0] = newPt (lineMid1[0],lineMid1[1], newWidth/2, lineAngTan1);
        ptNewArray[3] = newPt (lineMid2[0],lineMid2[1], newWidth/2, lineAngTan1);
        ptNewArray[1] = newPt (lineMid1[0],lineMid1[1], newWidth/2, lineAngTan2);
        ptNewArray[2] = newPt (lineMid2[0],lineMid2[1], newWidth/2, lineAngTan2);


        break;
    case 7:
        if(Math.round (getAng (ptArray[0][0], ptArray[0][1], ptArray[6][0], ptArray[6][1]))==Math.round (getAng (ptArray[1][0], ptArray[1][1], ptArray[2][0], ptArray[2][1]))){
            //alert('end')
            lineType = 'Single Arrow End';
            origLineWidth = lineL (ptArray[0][0], ptArray[0][1], ptArray[1][0], ptArray[1][1]);
            lineAngTan1 = getAng (ptArray[0][0], ptArray[0][1], ptArray[1][0], ptArray[1][1]);
            lineAngTan2 = getAng (ptArray[1][0], ptArray[1][1], ptArray[0][0], ptArray[0][1]);
            lineMid1 = [(ptArray[1][0] + ptArray[0][0])/2,(ptArray[1][1] + ptArray[0][1])/2 ];  
            lineMid2 = [(ptArray[2][0] + ptArray[6][0])/2,(ptArray[2][1] + ptArray[6][1])/2 ];
            arrowEndsMid = [(ptArray[3][0] + ptArray[5][0])/2,(ptArray[3][1] + ptArray[5][1])/2 ];            
            arrowLength = lineL (ptArray[4][0], ptArray[4][1], arrowEndsMid[0], arrowEndsMid[1]);              
            arrowWidth = lineL (ptArray[5][0], ptArray[5][1], ptArray[3][0], ptArray[3][1]);            
            arrowConcaveFactor = getConcaveFactor (ptArray[6][0], ptArray[6][1], ptArray[0][0], ptArray[0][1], ptArray[4][0], ptArray[4][1], ptArray[5][0], ptArray[5][1], ptArray[3][0], ptArray[3][1]);
            arrowLengthFactor = Math.round((arrowLength/origLineWidth)*100);
            arrowWidthFactor = Math.round((arrowWidth/origLineWidth)*100);            
            lineLengthAng = getAng (arrowEndsMid[0], arrowEndsMid[1],ptArray[4][0], ptArray[4][1]);
            //////////////////////////////////////
            ui ()
            //New points
            arrowEndsMid = newPt (ptArray[4][0], ptArray[4][1], newWidth*arrowLengthFactor*.01, lineLengthAng);            
            ptNewArray[5] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan1);
            ptNewArray[3] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan2);
            ptNewArray[1] = newPt (lineMid1[0], lineMid1[1], newWidth/2, lineAngTan2);
            ptNewArray[0] = newPt (lineMid1[0], lineMid1[1], newWidth/2, lineAngTan1);           
            ptTemp1 = newPt (lineMid2[0], lineMid2[1], newWidth/2, lineAngTan1);            
            ptTemp2 = newPt (lineMid2[0], lineMid2[1], newWidth/2, lineAngTan2);              
            headIntersect1= getIntersect (ptTemp1[0], ptTemp1[1], ptNewArray[0][0], ptNewArray[0][1], ptArray[4][0], ptArray[4][1], ptNewArray[5][0], ptNewArray[5][1]);            
            headIntersect2= getIntersect (ptTemp2[0], ptTemp2[1], ptNewArray[1][0], ptNewArray[1][1], ptArray[4][0], ptArray[4][1], ptNewArray[3][0], ptNewArray[3][1]);            
            ptTemp3 = getIntersect (ptTemp1[0], ptTemp1[1], ptNewArray[0][0], ptNewArray[0][1], ptNewArray[5][0], ptNewArray[5][1], ptNewArray[3][0], ptNewArray[3][1]);            
            ptTemp4 = getIntersect (ptTemp2[0], ptTemp2[1], ptNewArray[1][0], ptNewArray[1][1], ptNewArray[5][0], ptNewArray[5][1], ptNewArray[3][0], ptNewArray[3][1]);            
            arrowConcave = lineL (headIntersect1[0], headIntersect1[1], ptTemp3[0], ptTemp3[1])*arrowConcaveFactor*.01;            
            ptNewArray[6] = newPt (ptTemp3[0], ptTemp3[1], -arrowConcave, lineLengthAng);            
            ptNewArray[2] = newPt (ptTemp4[0], ptTemp4[1], -arrowConcave, lineLengthAng);           
            }
        else{
            //alert('beginning')  
            lineType = 'Single Arrow Start';
            origLineWidth = lineL (ptArray[0][0], ptArray[0][1], ptArray[4][0], ptArray[4][1]);
            lineAngTan1 = getAng (ptArray[0][0], ptArray[0][1], ptArray[4][0], ptArray[4][1]);
            lineAngTan2 = getAng (ptArray[4][0], ptArray[4][1], ptArray[0][0], ptArray[0][1]);
            lineMid1 = [(ptArray[4][0] + ptArray[0][0])/2,(ptArray[4][1] + ptArray[0][1])/2 ];  
            lineMid2 = [(ptArray[5][0] + ptArray[6][0])/2,(ptArray[5][1] + ptArray[6][1])/2 ];
            arrowEndsMid = [(ptArray[1][0] + ptArray[3][0])/2,(ptArray[1][1] + ptArray[3][1])/2 ]
            arrowLength = lineL (ptArray[2][0], ptArray[2][1], arrowEndsMid[0], arrowEndsMid[1]);         
            arrowWidth = lineL (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
            arrowConcaveFactor = getConcaveFactor (ptArray[0][0], ptArray[0][1], ptArray[6][0], ptArray[6][1], ptArray[2][0], ptArray[2][1], ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1])
            arrowLengthFactor = Math.round((arrowLength/origLineWidth)*100);
            arrowWidthFactor = Math.round((arrowWidth/origLineWidth)*100);
            lineLengthAng = getAng (arrowEndsMid[0], arrowEndsMid[1],ptArray[2][0], ptArray[2][1]);
              
            //////////////////////////////////////
            ui ()
            //New points
            arrowEndsMid = newPt (ptArray[2][0], ptArray[2][1], newWidth*arrowLengthFactor*.01, lineLengthAng);
            ptNewArray[1] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan1);
            ptNewArray[3] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan2);
            ptNewArray[5] = newPt (lineMid2[0], lineMid2[1], newWidth/2, lineAngTan2);
            ptNewArray[6] = newPt (lineMid2[0], lineMid2[1], newWidth/2, lineAngTan1);
            ptTemp1 = newPt (lineMid1[0], lineMid1[1], newWidth/2, lineAngTan1);
            ptTemp2 = newPt (lineMid1[0], lineMid1[1], newWidth/2, lineAngTan2);    
            headIntersect1= getIntersect (ptTemp1[0], ptTemp1[1], ptNewArray[6][0], ptNewArray[6][1], ptArray[2][0], ptArray[2][1], ptNewArray[1][0], ptNewArray[1][1])
            headIntersect2= getIntersect (ptTemp2[0], ptTemp2[1], ptNewArray[5][0], ptNewArray[5][1], ptArray[2][0], ptArray[2][1], ptNewArray[3][0], ptNewArray[3][1])
            ptTemp3 = getIntersect (ptTemp1[0], ptTemp1[1], ptNewArray[6][0], ptNewArray[6][1], ptNewArray[1][0], ptNewArray[1][1], ptNewArray[3][0], ptNewArray[3][1])
            ptTemp4 = getIntersect (ptTemp2[0], ptTemp2[1], ptNewArray[5][0], ptNewArray[5][1], ptNewArray[1][0], ptNewArray[1][1], ptNewArray[3][0], ptNewArray[3][1])
            arrowConcave = lineL (headIntersect1[0], headIntersect1[1], ptTemp3[0], ptTemp3[1])*arrowConcaveFactor*.01;
            ptNewArray[0] = newPt (ptTemp3[0], ptTemp3[1], -arrowConcave, lineLengthAng);
            ptNewArray[4] = newPt (ptTemp4[0], ptTemp4[1], -arrowConcave, lineLengthAng);
            }
    
        break;
    case 10:
            lineType = 'Double Arrow';
            origLineWidth = lineL (ptArray[0][0], ptArray[0][1], ptArray[4][0], ptArray[4][1]);
            lineAngTan1 = getAng (ptArray[0][0], ptArray[0][1], ptArray[4][0], ptArray[4][1]);
            lineAngTan2 = getAng (ptArray[4][0], ptArray[4][1], ptArray[0][0], ptArray[0][1]);                 
            arrowEndsMid = [(ptArray[1][0] + ptArray[3][0])/2,(ptArray[1][1] + ptArray[3][1])/2 ];            
            arrowLength = lineL (ptArray[2][0], ptArray[2][1], arrowEndsMid[0], arrowEndsMid[1]);             
            arrowWidth = lineL (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);            
            arrowConcaveFactor = getConcaveFactor (ptArray[0][0], ptArray[0][1], ptArray[9][0], ptArray[9][1], ptArray[2][0], ptArray[2][1], ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
            arrowLengthFactor = Math.round((arrowLength/origLineWidth)*100);
            arrowWidthFactor = Math.round((arrowWidth/origLineWidth)*100);
            lineLengthAng = getAng (ptArray[7][0], ptArray[7][1],ptArray[2][0], ptArray[2][1]);    
            /////////////////////////////////////////////
            ui ()
            //new points
            arrowEndsMid = newPt (ptArray[2][0], ptArray[2][1], newWidth*arrowLengthFactor*.01, lineLengthAng);
            ptNewArray[1] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan1);            
            ptNewArray[3] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan2);
            arrowEndsMid = newPt (ptArray[7][0], ptArray[7][1], -newWidth*arrowLengthFactor*.01, lineLengthAng); 
            ptNewArray[8] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan1);            
            ptNewArray[6] = newPt (arrowEndsMid[0], arrowEndsMid[1], (newWidth*arrowWidthFactor *.01)/2, lineAngTan2);            
            ptTemp1 = newPt (ptArray[2][0], ptArray[2][1], newWidth/2, lineAngTan1);
            var ptTemp1a = newPt (ptArray[7][0], ptArray[7][1], newWidth/2, lineAngTan1);
            ptTemp2 = newPt (ptArray[2][0], ptArray[2][1], newWidth/2, lineAngTan2);
            var ptTemp2a = newPt (ptArray[7][0], ptArray[7][1], newWidth/2, lineAngTan2);
            
            headIntersect1= getIntersect (ptTemp1[0], ptTemp1[1], ptTemp1a[0], ptTemp1a[1], ptArray[2][0], ptArray[2][1], ptNewArray[1][0], ptNewArray[1][1]);
            headIntersect2= getIntersect (ptTemp2[0], ptTemp2[1], ptTemp2a[0], ptTemp2a[1], ptArray[2][0], ptArray[2][1], ptNewArray[3][0], ptNewArray[3][1]);
            var headIntersect3= getIntersect (ptTemp1[0], ptTemp1[1], ptTemp1a[0], ptTemp1a[1], ptArray[7][0], ptArray[7][1], ptNewArray[8][0], ptNewArray[8][1]);
            var headIntersect4= getIntersect (ptTemp2[0], ptTemp2[1], ptTemp2a[0], ptTemp2a[1], ptArray[7][0], ptArray[7][1], ptNewArray[6][0], ptNewArray[6][1]); 
            ptTemp3 = getIntersect (ptTemp1[0], ptTemp1[1], ptTemp1a[0], ptTemp1a[1], ptNewArray[1][0], ptNewArray[1][1], ptNewArray[3][0], ptNewArray[3][1]);
            var ptTemp3a = getIntersect (ptTemp2[0], ptTemp2[1], ptTemp2a[0], ptTemp2a[1], ptNewArray[1][0], ptNewArray[1][1], ptNewArray[3][0], ptNewArray[3][1]);
            ptTemp4 = getIntersect (ptTemp1[0], ptTemp1[1], ptTemp1a[0], ptTemp1a[1], ptNewArray[6][0], ptNewArray[6][1], ptNewArray[8][0], ptNewArray[8][1]);
            var ptTemp4a = getIntersect (ptTemp2[0], ptTemp2[1], ptTemp2a[0], ptTemp2a[1], ptNewArray[6][0], ptNewArray[6][1], ptNewArray[8][0], ptNewArray[8][1]);
            
           arrowConcave = lineL (headIntersect1[0], headIntersect1[1], ptTemp3[0], ptTemp3[1])*arrowConcaveFactor*.01;
           ptNewArray[0] = newPt (ptTemp3[0], ptTemp3[1], -arrowConcave, lineLengthAng);
           ptNewArray[4] = newPt (ptTemp3a[0], ptTemp3a[1], -arrowConcave, lineLengthAng);      
           
           ptNewArray[9] = newPt (ptTemp4[0], ptTemp4[1], arrowConcave, lineLengthAng);
           ptNewArray[5] = newPt (ptTemp4a[0], ptTemp4a[1], arrowConcave, lineLengthAng);              
            
        break;
        default:
        run = false;
        alert("The layer selected didn't match the criteria for a line or arrow")
    }//end switch

if(run){
    var myPathInfo = mkNewPathInfo ();
    deltPath ();
    var tempPath = app.activeDocument.pathItems.add( 'temp', myPathInfo);
    selPath ();
    doc.activeLayer = sLay;
    mkPath ()
    tempPath.remove();
    }

////////////////////////////////////
function ui(){
    var dlg = new Window('dialog','Edit Line Tool Line');
        dlg.alignChildren = ['left','top'];
            dlg.lType = dlg.add('statictext',undefined,lineType);        
            dlg.wGp = dlg.add('group');
                dlg.wGp.alignChildren = ['left','top'];
                dlg.wGp.sTxts = dlg.wGp.add('statictext',undefined,'Line Width');
                dlg.wGp.eTxt = dlg.wGp.add('edittext',undefined,Math.round(origLineWidth));
                    dlg.wGp.eTxt.size = [50,12];
                dlg.wGp.sTxte = dlg.wGp.add('statictext',undefined,'px');
                
            if(lineType!='Normal Line'){
                for(var i=0;i<xmlPref.prefs.arrows.children().length();i++){
                    dropLst[i]= xmlPref.prefs.arrows.children()[i].@preset
                    }
                }
            else{
                for(var i=0;i<xmlPref.prefs.lines.children().length();i++){
                    dropLst[i]= xmlPref.prefs.lines.children()[i].@preset
                    }               
                }
            if(lineType!='Normal Line'){
                dlg.aLgp = dlg.add('group');
                    dlg.aLgp.alignChildren = ['left','top'];
                    dlg.aLgp.sTxts = dlg.aLgp.add('statictext',undefined,'Arrow Length');
                    dlg.aLgp.ALen = dlg.aLgp.add('edittext',undefined,arrowLengthFactor);
                        dlg.aLgp.ALen.size = [50,12];
                    dlg.aLgp.sTxte = dlg.aLgp.add('statictext',undefined,'%');
                    
                dlg.aWgp = dlg.add('group');
                    dlg.aWgp.alignChildren = ['left','top'];
                    dlg.aWgp.sTxts = dlg.aWgp.add('statictext',undefined,'Arrow Width');
                    dlg.aWgp.AWid = dlg.aWgp.add('edittext',undefined,arrowWidthFactor);
                        dlg.aWgp.AWid.size = [50,12];
                    dlg.aWgp.sTxte = dlg.aWgp.add('statictext',undefined,'%');     
                    
                dlg.aConGp = dlg.add('group');
                    dlg.aConGp.alignChildren = ['left','top'];
                    dlg.aConGp.sTxts = dlg.aConGp.add('statictext',undefined,'Arrow Concave');
                    dlg.aConGp.ACon = dlg.aConGp.add('edittext',undefined,arrowConcaveFactor);
                        dlg.aConGp.ACon.size = [50,12];
                    dlg.aConGp.sTxte = dlg.aConGp.add('statictext',undefined,'%');                      
                }
            
            dlg.btnGp = dlg.add('group');
            dlg.btnGp.okay = dlg.btnGp.add('button',undefined,'Okay');
            dlg.btnGp.cancel = dlg.btnGp.add('button',undefined,'Cancel');
            
        dlg.prefsPn = dlg.add('panel',undefined,'Preferences');
            dlg.prefsPn.alignChildren = ['left','top'];
            dlg.prefsPn.save = dlg.prefsPn.add('button',undefined,'Save Preference');
            dlg.prefsPn.del = dlg.prefsPn.add('button',undefined,'Delete Preference');
            
            prefsDrop = dlg.prefsPn.add('dropdownlist',undefined,dropLst);
            prefsDrop.title = 'Load Preferences';            
            prefsDrop.size = [300,25];      
            
        prefsDrop.onChange = function(){
            if(lineType!='Normal Line'){
                dlg.wGp.eTxt.text = xmlPref.prefs.arrows.children()[parseInt(prefsDrop.selection)].width
                dlg.aLgp.ALen.text = xmlPref.prefs.arrows.children()[parseInt(prefsDrop.selection)].leng
                dlg.aWgp.AWid.text = xmlPref.prefs.arrows.children()[parseInt(prefsDrop.selection)].aWidth
                dlg.aConGp.ACon.text = xmlPref.prefs.arrows.children()[parseInt(prefsDrop.selection)].concave
                }
            else{
                dlg.wGp.eTxt.text = xmlPref.prefs.lines.children()[parseInt(prefsDrop.selection)].width
                }
            };
            
        dlg.wGp.eTxt.onChange = function(){
            textToNum (1, 1000, dlg.wGp.eTxt, origLineWidth);
            }
        if(lineType!='Normal Line'){        
            dlg.aLgp.ALen.onChange = function(){
                textToNum (1, 10000, dlg.aLgp.ALen, arrowLengthFactor);
                }       
            
            dlg.aWgp.AWid.onChange = function(){
                textToNum (1, 10000, dlg.aWgp.AWid, arrowWidthFactor);
                } 
            
            dlg.aWgp.AWid.onChange = function(){
                textToNum (-50, 50, dlg.aConGp.ACon, arrowConcaveFactor);
                }    
        }//end if
            
            dlg.prefsPn.save.onClick = function(){
                savePrefs ();

                }
            
            dlg.prefsPn.del.onClick = function(){
                if(prefsDrop.selection != null){
                    var selc = parseInt(prefsDrop.selection);                    
                    prefsDrop.remove(selc);
                    if(lineType!='Normal Line'){
                        delete xmlPref.prefs.arrows.children()[selc];
                        }
                    else{
                        delete xmlPref.prefs.lines.children()[selc];
                        }
                    writeXMLFile (xmlFile, xmlPref)
                    }

                }            
            
        dlg.btnGp.okay.onClick = function(){
            dlg.close();
            newWidth = parseInt (dlg.wGp.eTxt.text);
                if(lineType!='Normal Line'){
                arrowLengthFactor = parseInt (dlg.aLgp.ALen.text);
                arrowWidthFactor = parseInt (dlg.aWgp.AWid.text);
                arrowConcaveFactor = parseInt (dlg.aConGp.ACon.text);
                }
            }
        
        dlg.btnGp.cancel.onClick = function(){            
            run = false;
            dlg.close()
            }  
//==================
function savePrefs(){
    var newName = prompt ('Enter New Profile Name', '', 'Save Preferences');
    var prefGood = true;
    for(var i=0;i<prefsDrop.items.length;i++){
        if(prefsDrop.items[i].text == newName){
            newName = prompt ('That preset exists\nPlease choose a unique name','', 'Save Preferences' );
            i=0
            }
        }
        prefsDrop.add('item',newName)
        if(lineType=='Normal Line'){
            xmlPref.prefs.lines.appendChild (XML('<line preset="'+ newName+ '"><width>'+dlg.wGp.eTxt.text+'</width></line>'));
            }
        else{   
            xmlPref.prefs.arrows.appendChild (XML('<arrow preset="'+ newName+ '"><width>'+dlg.wGp.eTxt.text+'</width><leng>'+dlg.aLgp.ALen.text+'</leng><aWidth>'+dlg.aWgp.AWid.text+'</aWidth><concave>'+dlg.aConGp.ACon.text+'</concave></arrow>'));
            }
        writeXMLFile (xmlFile, xmlPref) 

    }

//=====================        
    dlg.show();
    }

function textToNum(sMin,sMax,e,def){
    def=Math.round (def)
	var sHold = def;
			if(isNaN(parseInt(e.text))){
			alert('"' + e.text + '" is not a number\nEnter a value between ' + sMin + '-' + sMax );
			e.text = def};
            else{
                sHold = parseInt(e.text)
			if(sHold < sMin){
				rangeAlert();
				sHold = sMin;				
				};
			if(sHold > sMax){
				rangeAlert();
				sHold = sMax;
				};
			e.text = sHold;
            }
	function rangeAlert(){alert('Number range must be between ' + sMin + '-' + sMax)}; 
};//end function textToNum

function getConcaveFactor(x1,y1,x2,y2, x3, y3, x4, y4, x5, y5){//1 & 2 =  shaft pt 1 &2; 3 & 4 = arrow length line; 5 = tail point opp side
    var ptAH = getIntersect (x1, y1, x2, y2, x3, y3, x4, y4);//intersection of shaft with sides of arrowhead
    //mkDot (ptAH)
    var ptTail = getIntersect (x1, y1, x2, y2, x4, y4, x5, y5);//Intersection of arrow tip ends cross shaft
    var conTotalLen = lineL (x1, y1, ptAH[0], ptAH[1]);//gets total length to see if the concave goes in toward the arrowhead or out (-)
    var conFullLen =  lineL (ptTail[0], ptTail[1], ptAH[0], ptAH[1]);//length of arrow from end tips to intersection with shaft
    var conF = lineL (x1, y1, ptTail[0], ptTail[1])/conFullLen
    if(conTotalLen>conFullLen){conF*=-1}
    return Math.round(conF*100)
    }

function getIntersect(x1,y1,x2,y2, x3, y3, x4, y4){
    var slope1 = (y1-y2)/(x1-x2);
    var bIntersect1 = y1-(slope1*x1)
    var slope2 = (y3-y4)/(x3-x4);
    var bIntersect2 = y3-(slope2*x3)  
    var xNew ;
    var yNew;
    if(bIntersect1=='-Infinity'||bIntersect1=='Infinity'){
        xNew=x1;
        yNew = slope2*xNew + bIntersect2;
        }
    else if(bIntersect2=='-Infinity'||bIntersect2=='Infinity'){
        xNew = x3;
        yNew = slope1*xNew + bIntersect1;
        }
    else{
        xNew= (-(bIntersect1-bIntersect2))/(slope1-slope2);
        yNew = slope1*xNew + bIntersect1
        }
    
    
    return [xNew,yNew]
    }

function recordAnchors(pathObj){
    ptArray = new Array();
    for(var i=0;i<pathObj.subPathItems[0].pathPoints.length;i++){
        ptNewArray [i] = ptArray[i] = pathObj.subPathItems[0].pathPoints[i].anchor;
        }//end loop
    }//end function

function mkNewPathInfo(){
    var pathArray = new Array();
    var piArray = new Array();
    for(var i=0;i<ptNewArray.length;i++){
         piArray[i] = new PathPointInfo;
         piArray[i].kind = cPath.subPathItems[0].pathPoints[i].kind; 
         piArray[i].anchor = ptNewArray[i];
         piArray[i].leftDirection = ptNewArray[i];
         piArray[i].rightDirection = ptNewArray[i];
        }//end loop
    pathArray[0] = new SubPathInfo();
    pathArray[0].operation = cPath.subPathItems[0].operation;
    pathArray[0].closed = cPath.subPathItems[0].closed;
    pathArray[0].entireSubPath = piArray;  
    return pathArray;
    };//end function

/////////////////////
    function extractSubPathInfo(pathObj,oldPoint,newPoint){
        var pathArray = new Array();
        var pl = pathObj.subPathItems.length;
        for(var s=0;s<pl;s++){
            var pArray = new Array();
              for(var i=0;i<pathObj.subPathItems[s].pathPoints.length;i++){
                 pArray[i] = new PathPointInfo;
                 pArray[i].kind = pathObj.subPathItems[s].pathPoints[i].kind;
             if(pathObj.subPathItems[s].pathPoints[i].anchor[0]==oldPoint[0] &&
                   pathObj.subPathItems[s].pathPoints[i].anchor[1]==oldPoint[1]){
                pArray[i].anchor = newPoint;
                pArray[i].leftDirection = newPoint;
                pArray[i].rightDirection = newPoint;
             }else{
                pArray[i].anchor = pathObj.subPathItems[s].pathPoints[i].anchor;
                pArray[i].leftDirection = pathObj.subPathItems[s].pathPoints[i].leftDirection;
                pArray[i].rightDirection = pathObj.subPathItems[s].pathPoints[i].rightDirection;
             }
              };
            pathArray[pathArray.length] = new Array();
            pathArray[pathArray.length - 1] = new SubPathInfo();
            pathArray[pathArray.length - 1].operation = pathObj.subPathItems[s].operation;
            pathArray[pathArray.length - 1].closed = pathObj.subPathItems[s].closed;
            pathArray[pathArray.length - 1].entireSubPath = pArray;
        };
        return pathArray;
    };
        
    function deltPath(){
        var idDlt = charIDToTypeID( "Dlt " );
        var desc2 = new ActionDescriptor();
        var idnull = charIDToTypeID( "null" );
            var ref1 = new ActionReference();
            idPath = charIDToTypeID( "Path" );
            var idvectorMask = stringIDToTypeID( "vectorMask" );
            ref1.putEnumerated( idPath, idPath, idvectorMask );
            var idLyr = charIDToTypeID( "Lyr " );
            var idOrdn = charIDToTypeID( "Ordn" );
            var idTrgt = charIDToTypeID( "Trgt" );
            ref1.putEnumerated( idLyr, idOrdn, idTrgt );
        desc2.putReference( idnull, ref1 );
        executeAction( idDlt, desc2, DialogModes.NO );
        }
    
    function selPath(){
         var idslct = charIDToTypeID( "slct" );
            var desc2 = new ActionDescriptor();
            var idnull = charIDToTypeID( "null" );
                var ref1 = new ActionReference();
                var idPath = charIDToTypeID( "Path" );
                ref1.putName( idPath, "temp" );
            desc2.putReference( idnull, ref1 );
        executeAction( idslct, desc2, DialogModes.NO );       
        }
    
    function mkPath(){
         var idMk = charIDToTypeID( "Mk  " );
            var desc10 = new ActionDescriptor();
            var idnull = charIDToTypeID( "null" );
                var ref3 = new ActionReference();
                var idPath = charIDToTypeID( "Path" );
                ref3.putClass( idPath );
            desc10.putReference( idnull, ref3 );
            var idAt = charIDToTypeID( "At  " );
                var ref4 = new ActionReference();
                var idPath = charIDToTypeID( "Path" );
                var idPath = charIDToTypeID( "Path" );
                var idvectorMask = stringIDToTypeID( "vectorMask" );
                ref4.putEnumerated( idPath, idPath, idvectorMask );
            desc10.putReference( idAt, ref4 );
            var idUsng = charIDToTypeID( "Usng" );
                var ref5 = new ActionReference();
                var idPath = charIDToTypeID( "Path" );
                var idOrdn = charIDToTypeID( "Ordn" );
                var idTrgt = charIDToTypeID( "Trgt" );
                ref5.putEnumerated( idPath, idOrdn, idTrgt );
            desc10.putReference( idUsng, ref5 );
        executeAction( idMk, desc10, DialogModes.NO );       
        }
    
function lineL (ax,ay,bx,by){
    var x = Math.abs (ax-bx);
    var y = Math.abs (ay-by);
    var len = Math.sqrt (Math.pow (x, 2) + Math.pow (y, 2));
    return len
    }

function getAng(ax,ay,bx,by){
    var dx = ax-bx;
    var dy = ay-by;
    var theta = Math.atan2 (dy, dx);
    //theta *= 180/Math.PI
    return theta;
    }

function newPt (x1,y1,rad,ang){
    var newEnd = new Array();
    newEnd[0] = x1 + rad * Math.cos (ang);
    newEnd[1] = y1 + rad * Math.sin (ang);
    return newEnd;
    }

//===============READ/WRITE functions========================================
//=========================================================================
 function readXMLFile(file) {
	if (!file.exists) {
		alert( "Cannot find file: " + deodeURI(file.absoluteURI));
		}
	else{
		file.encoding = "UTF8";
		file.lineFeed = "unix";
		file.open("r", "TEXT", "????");
		var str = file.read();
		file.close();

		return new XML(str);
		};
};

function writeXMLFile(file, xml) {
	if (!(xml instanceof XML)) {
		alert( "Bad XML parameter");
		};
	else{
		file.encoding = "UTF8";
		file.open("w", "TEXT", "????");
		//unicode signature, this is UTF16 but will convert to UTF8 "EF BB BF"
		file.write("\uFEFF");
		file.lineFeed = "unix";
		file.write(xml.toXMLString());
		file.close();
		};
	};
 //=========================================================================

Topics

Actions and scripting, FAQ, How to

Views

338

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Adobe Community Professional ,
Oct 03, 2019

Copy link to clipboard

Copied

Wow, thank you!

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
Adobe Community Professional ,
Apr 04, 2020

Copy link to clipboard

Copied

Wow!

We do need a repository with such gems. do you also post them at Ps-scripts?

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
Adobe Community Professional ,
Apr 04, 2020

Copy link to clipboard

Copied

No I haven't posted it there. Having login issues,  which I just haven't bothered fixing yet.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
Adobe Community Professional ,
Apr 04, 2020

Copy link to clipboard

Copied

Administrator Tom made me a moderator there. Try again, I'll try to help.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
Adobe Community Professional ,
Apr 04, 2020

Copy link to clipboard

Copied

Will do.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
Most Valuable Participant ,
Apr 04, 2020

Copy link to clipboard

Copied

Three to One how does one add a dislike to the thread? Just kidding Chuck.  I normally just edit  them not redraw them and  usually they also need to be repositioned. After using your script I definitely would need to redraw some.

Capture.jpg

JJMack

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...
jane-e LATEST
Adobe Community Professional ,
Apr 04, 2020

Copy link to clipboard

Copied

Chuck this is very impressive and you put a lot of amazing work into it. I feel compelled, however, to give the steps in Illustrator for others who may see this thread later. I do a lot of charts with arrows and dashed lines, and then the customer wants a different arrow head or line thickness or dash spacing.

 

In Illustrator:

  • Draw and format a line (width, dash, arrowhead)
  • Drag the line into the Graphic Styles panel to create a style
  • Apply the style to appropriate lines
  • To edit: format one line, Option+Drag newly formatted line onto the existing style and all lines using the style will update.

 

I will save your script and give it a try later today. Thanks for sharing!

 

~ Jane

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Reply
Loading...