Highlighted

Changing Arrow Parameter on Line Tool

Adobe Community Professional ,
Oct 23, 2020

Copy link to clipboard

Copied

Photoshop 2021 Line Tool is different than previous versions. In previous versions the width of the line/arrow could be set. Now it's set with a stroke. In both the old and new versions, it was difficult to change the arrowhead shapes. You basically had to redraw them. This script will allow you to change an existing arrow and save the preferences so that you can change multiple arrows.

Use at your own risk.

 

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

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

if(xmlFile.exists){
    xmlPref = readXMLFile (xmlFile)
    }
else{xmlPref = new XML('<root><prefs><arrows/></prefs>')};

var doc = activeDocument
var oldPrefs = app.preferences.rulerUnits
var oldRes = doc.resolution
changeRes (72)
app.preferences.rulerUnits = Units.POINTS;

var dlg
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 arrowWidth;
var arrowHeadMid;
var arrowHeadBase;
var arrowLength;
var concaveLength;
var arrowConcave;
var arrowConcaveFactor;
var newPointArray = [];
var dropLst = new Array()
var prefsDrop
var run = true;

try{
    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;

recordAnchors (cPath);
var numAnchors = ptArray.length;

    }
catch(e){
    run = false;
    var numAnchors=0
    }

if(run){main ()}

function main(){    
    
    switch (numAnchors){
        case 0:
            alert('An arrow Layer is not selected');
            break;
        case 6:
            if(Math.round (ptArray[0][0])==Math.round (ptArray[4][0])&&Math.round (ptArray[0][1])==Math.round (ptArray[4][1])){
                lineLength = lineL (ptArray[2][0], ptArray[2][1], ptArray[5][0], ptArray[5][1]);
                arrowWidth = lineL (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
                lineLengthAng = getAng (ptArray[2][0], ptArray[2][1], ptArray[5][0], ptArray[5][1]);
                lineAngTan1 = getAng (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
                lineAngTan2 = getAng (ptArray[3][0], ptArray[3][1], ptArray[1][0], ptArray[1][1]);
                arrowHeadMid = bisect (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
                arrowHeadBase = (ptArray[0][0], ptArray[0][1]);
                arrowLength = lineL (ptArray[2][0], ptArray[2][1], arrowHeadMid[0], arrowHeadMid[1]);
                concaveLength = lineL (ptArray[2][0], ptArray[2][1], ptArray[0][0], ptArray[0][1]);
                arrowConcaveFactor = concaveLength/arrowLength;
                
                ui ();
                
                //Get new points
                 newPointArray[2] = [ptArray[2][0],ptArray[2][1]];  //tip
                 newPointArray[4] = newPointArray[0] = newPt (ptArray[2][0], ptArray[2][1], -(arrowLength*arrowConcaveFactor), lineLengthAng); // arrow base
                 var tempPt = newPt (ptArray[2][0], ptArray[2][1], -(arrowLength), lineLengthAng);//temp midpoint for arrow ends
                 newPointArray[1] = newPt (tempPt[0],tempPt[1], -(arrowWidth)/2, lineAngTan2); //first arrow end
                 newPointArray[3] = newPt (tempPt[0],tempPt[1], -(arrowWidth)/2, lineAngTan1); //second arrow end
                 newPointArray[5] = newPt (ptArray[2][0], ptArray[2][1], -(lineLength), lineLengthAng);      //arrow end         
                }
            else{
                lineLength = lineL (ptArray[0][0], ptArray[0][1], ptArray[3][0], ptArray[3][1]);
                arrowWidth = lineL (ptArray[2][0], ptArray[2][1], ptArray[4][0], ptArray[4][1]);
                lineLengthAng = getAng (ptArray[0][0], ptArray[0][1], ptArray[3][0], ptArray[3][1]);
                lineAngTan1 = getAng (ptArray[2][0], ptArray[2][1], ptArray[4][0], ptArray[4][1]);
                lineAngTan2 = getAng (ptArray[4][0], ptArray[4][1], ptArray[2][0], ptArray[2][1]);
                arrowHeadMid = bisect (ptArray[2][0], ptArray[2][1], ptArray[4][0], ptArray[4][1]);
                arrowHeadBase = (ptArray[3][0], ptArray[3][1]);               
                arrowLength = lineL (ptArray[3][0], ptArray[3][1], arrowHeadMid[0], arrowHeadMid[1]);
                concaveLength = lineL (ptArray[3][0], ptArray[3][1], ptArray[1][0], ptArray[1][1]);
                arrowConcaveFactor = concaveLength/arrowLength;  
                
                ui ();
                
                //Get new points
                 newPointArray[3] = [ptArray[3][0],ptArray[3][1]];  //tip
                 newPointArray[5] = newPointArray[1] = newPt (ptArray[3][0], ptArray[3][1], (arrowLength*arrowConcaveFactor), lineLengthAng); // arrow base
                 var tempPt = newPt (ptArray[3][0], ptArray[3][1], (arrowLength), lineLengthAng);//temp midpoint for arrow ends
                 newPointArray[2] = newPt (tempPt[0],tempPt[1], -(arrowWidth)/2, lineAngTan2); //first arrow end
                 newPointArray[4] = newPt (tempPt[0],tempPt[1], -(arrowWidth)/2, lineAngTan1); //second arrow end
                 newPointArray[0] = newPt (ptArray[3][0], ptArray[3][1], (lineLength), lineLengthAng);      //arrow end              
                }
            break;
        case 10:
                lineLength = lineL (ptArray[2][0], ptArray[2][1], ptArray[7][0], ptArray[7][1]);
                arrowWidth = lineL (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
                lineLengthAng = getAng (ptArray[2][0], ptArray[2][1], ptArray[7][0], ptArray[7][1]);
                lineAngTan1 = getAng (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
                lineAngTan2 = getAng (ptArray[3][0], ptArray[3][1], ptArray[1][0], ptArray[1][1]);
                arrowHeadMid = bisect (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
                arrowHeadBase = (ptArray[0][0], ptArray[0][1]);
                arrowLength = lineL (ptArray[2][0], ptArray[2][1], arrowHeadMid[0], arrowHeadMid[1]);
                concaveLength = lineL (ptArray[2][0], ptArray[2][1], ptArray[0][0], ptArray[0][1]);
                arrowConcaveFactor = concaveLength/arrowLength;     
                
                ui ();
                
                 //Get new points
                 newPointArray[2] = [ptArray[2][0],ptArray[2][1]];  //tip1
                 newPointArray[7] = [ptArray[7][0],ptArray[7][1]];  //tip2
                 newPointArray[4] = newPointArray[0] = newPt (ptArray[2][0], ptArray[2][1], -(arrowLength*arrowConcaveFactor), lineLengthAng); // arrow base 1
                 newPointArray[5] = newPointArray[9] = newPt (ptArray[7][0], ptArray[7][1], (arrowLength*arrowConcaveFactor), lineLengthAng); // arrow base 2
                 var tempPt1 = newPt (ptArray[2][0], ptArray[2][1], -(arrowLength), lineLengthAng);//temp midpoint for arrow ends 1
                 var tempPt2 = newPt (ptArray[7][0], ptArray[7][1], (arrowLength), lineLengthAng);//temp midpoint for arrow ends 2                 
                 newPointArray[1] = newPt (tempPt1[0],tempPt1[1], -(arrowWidth)/2, lineAngTan2); //first arrow end 1
                 newPointArray[6] = newPt (tempPt2[0],tempPt2[1], -(arrowWidth)/2, lineAngTan2); //first arrow end 2
                 newPointArray[3] = newPt (tempPt1[0],tempPt1[1], -(arrowWidth)/2, lineAngTan1); //second arrow end 1
                 newPointArray[8] = newPt (tempPt2[0],tempPt2[1], -(arrowWidth)/2, lineAngTan1); //second arrow end 2
                 //newPointArray[5] = newPt (ptArray[2][0], ptArray[2][1], -(lineLength), lineLengthAng);      //arrow end  
                           
                
            break;        
        };

    var myPathInfo = mkNewPathInfo ();
    deltPath ();
    var tempPath = app.activeDocument.pathItems.add( 'temp', myPathInfo);
    selPath ();
    doc.activeLayer = sLay;
    mkPath ()
    tempPath.remove();
 
app.preferences.rulerUnits = oldPrefs;       
changeRes (oldRes)

}//end function run

function ui(){
         dlg = new Window('dialog','Edit Arrow');
            dlg.alignChildren = ['left','top'];   
                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,arrowLength.toFixed (2));
                        dlg.aLgp.ALen.size = [50,12];
                    dlg.aLgp.sTxte = dlg.aLgp.add('statictext',undefined,'px');
                    
                for(var i=0;i<xmlPref.prefs.arrows.children().length();i++){
                    dropLst[i]= xmlPref.prefs.arrows.children()[i].@preset
                    }                    
                    
                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,arrowWidth.toFixed (2));
                        dlg.aWgp.AWid.size = [50,12];
                    dlg.aWgp.sTxte = dlg.aWgp.add('statictext',undefined,'px');     
                    
                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,((1-arrowConcaveFactor)*100).toFixed (2));
                        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(){
                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
            };
        
        dlg.aLgp.ALen.onChange = function(){
            textToNum (1, 10000, dlg.aLgp.ALen, arrowLength);
            }       
        
        dlg.aWgp.AWid.onChange = function(){
            textToNum (1, 50000, dlg.aWgp.AWid, arrowWidth);
            } 
        
        dlg.aConGp.ACon.onChange = function(){
            textToNum (-50, 50, dlg.aConGp.ACon, arrowConcaveFactor);
            }    

            
        dlg.prefsPn.save.onClick = function(){
            savePrefs ();

                }
            
            dlg.prefsPn.del.onClick = function(){
                if(prefsDrop.selection != null){
                    var selc = parseInt(prefsDrop.selection);                    
                    prefsDrop.remove(selc);
                    delete xmlPref.prefs.arrows.children()[selc];
                    writeXMLFile (xmlFile, xmlPref)
                    }
                }                        
                                
                    
        dlg.btnGp.okay.onClick = function(){
            dlg.close();
                arrowLength = parseInt (dlg.aLgp.ALen.text);
                arrowWidth = parseInt (dlg.aWgp.AWid.text);
                arrowConcaveFactor = (100 - parseInt (dlg.aConGp.ACon.text))*.01;
                }

        dlg.btnGp.cancel.onClick = function(){            
            run = false;
            dlg.close()
            }                      
            
    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 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 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;
    }

function bisect(x1,y1,x2,y2){
    var midPoint = new Array();
    midPoint[0] = (x1+x2)/2;
    midPoint[1] = (y1+y2)/2;
    return midPoint;
    }

/////////////////////
    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 mkNewPathInfo(){
    var pathArray = new Array();
    var piArray = new Array();
    for(var i=0;i<newPointArray.length;i++){
         piArray[i] = new PathPointInfo;
         piArray[i].kind = PointKind.CORNERPOINT; 
         piArray[i].anchor = newPointArray[i];
         piArray[i].leftDirection = newPointArray[i];
         piArray[i].rightDirection = newPointArray[i];
        }//end loop
    pathArray[0] = new SubPathInfo();
    pathArray[0].operation = ShapeOperation.SHAPEXOR;
    pathArray[0].closed = true;
    pathArray[0].entireSubPath = piArray;  
    return pathArray;
    };//end function      

function changeRes(res){
        var idImgS = charIDToTypeID( "ImgS" );
        var desc15 = new ActionDescriptor();
        var idRslt = charIDToTypeID( "Rslt" );
        var idRsl = charIDToTypeID( "#Rsl" );
        desc15.putUnitDouble( idRslt, idRsl, res );
    executeAction( idImgS, desc15, DialogModes.NO );
    }

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)  
xmlPref.prefs.arrows.appendChild (XML('<arrow preset="'+ newName+ '"><leng>'+dlg.aLgp.ALen.text+'</leng><aWidth>'+dlg.aWgp.AWid.text+'</aWidth><concave>'+dlg.aConGp.ACon.text+'</concave></arrow>'));
        writeXMLFile (xmlFile, xmlPref) 

    }

//===============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, How to

Views

261

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

Changing Arrow Parameter on Line Tool

Adobe Community Professional ,
Oct 23, 2020

Copy link to clipboard

Copied

Photoshop 2021 Line Tool is different than previous versions. In previous versions the width of the line/arrow could be set. Now it's set with a stroke. In both the old and new versions, it was difficult to change the arrowhead shapes. You basically had to redraw them. This script will allow you to change an existing arrow and save the preferences so that you can change multiple arrows.

Use at your own risk.

 

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

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

if(xmlFile.exists){
    xmlPref = readXMLFile (xmlFile)
    }
else{xmlPref = new XML('<root><prefs><arrows/></prefs>')};

var doc = activeDocument
var oldPrefs = app.preferences.rulerUnits
var oldRes = doc.resolution
changeRes (72)
app.preferences.rulerUnits = Units.POINTS;

var dlg
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 arrowWidth;
var arrowHeadMid;
var arrowHeadBase;
var arrowLength;
var concaveLength;
var arrowConcave;
var arrowConcaveFactor;
var newPointArray = [];
var dropLst = new Array()
var prefsDrop
var run = true;

try{
    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;

recordAnchors (cPath);
var numAnchors = ptArray.length;

    }
catch(e){
    run = false;
    var numAnchors=0
    }

if(run){main ()}

function main(){    
    
    switch (numAnchors){
        case 0:
            alert('An arrow Layer is not selected');
            break;
        case 6:
            if(Math.round (ptArray[0][0])==Math.round (ptArray[4][0])&&Math.round (ptArray[0][1])==Math.round (ptArray[4][1])){
                lineLength = lineL (ptArray[2][0], ptArray[2][1], ptArray[5][0], ptArray[5][1]);
                arrowWidth = lineL (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
                lineLengthAng = getAng (ptArray[2][0], ptArray[2][1], ptArray[5][0], ptArray[5][1]);
                lineAngTan1 = getAng (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
                lineAngTan2 = getAng (ptArray[3][0], ptArray[3][1], ptArray[1][0], ptArray[1][1]);
                arrowHeadMid = bisect (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
                arrowHeadBase = (ptArray[0][0], ptArray[0][1]);
                arrowLength = lineL (ptArray[2][0], ptArray[2][1], arrowHeadMid[0], arrowHeadMid[1]);
                concaveLength = lineL (ptArray[2][0], ptArray[2][1], ptArray[0][0], ptArray[0][1]);
                arrowConcaveFactor = concaveLength/arrowLength;
                
                ui ();
                
                //Get new points
                 newPointArray[2] = [ptArray[2][0],ptArray[2][1]];  //tip
                 newPointArray[4] = newPointArray[0] = newPt (ptArray[2][0], ptArray[2][1], -(arrowLength*arrowConcaveFactor), lineLengthAng); // arrow base
                 var tempPt = newPt (ptArray[2][0], ptArray[2][1], -(arrowLength), lineLengthAng);//temp midpoint for arrow ends
                 newPointArray[1] = newPt (tempPt[0],tempPt[1], -(arrowWidth)/2, lineAngTan2); //first arrow end
                 newPointArray[3] = newPt (tempPt[0],tempPt[1], -(arrowWidth)/2, lineAngTan1); //second arrow end
                 newPointArray[5] = newPt (ptArray[2][0], ptArray[2][1], -(lineLength), lineLengthAng);      //arrow end         
                }
            else{
                lineLength = lineL (ptArray[0][0], ptArray[0][1], ptArray[3][0], ptArray[3][1]);
                arrowWidth = lineL (ptArray[2][0], ptArray[2][1], ptArray[4][0], ptArray[4][1]);
                lineLengthAng = getAng (ptArray[0][0], ptArray[0][1], ptArray[3][0], ptArray[3][1]);
                lineAngTan1 = getAng (ptArray[2][0], ptArray[2][1], ptArray[4][0], ptArray[4][1]);
                lineAngTan2 = getAng (ptArray[4][0], ptArray[4][1], ptArray[2][0], ptArray[2][1]);
                arrowHeadMid = bisect (ptArray[2][0], ptArray[2][1], ptArray[4][0], ptArray[4][1]);
                arrowHeadBase = (ptArray[3][0], ptArray[3][1]);               
                arrowLength = lineL (ptArray[3][0], ptArray[3][1], arrowHeadMid[0], arrowHeadMid[1]);
                concaveLength = lineL (ptArray[3][0], ptArray[3][1], ptArray[1][0], ptArray[1][1]);
                arrowConcaveFactor = concaveLength/arrowLength;  
                
                ui ();
                
                //Get new points
                 newPointArray[3] = [ptArray[3][0],ptArray[3][1]];  //tip
                 newPointArray[5] = newPointArray[1] = newPt (ptArray[3][0], ptArray[3][1], (arrowLength*arrowConcaveFactor), lineLengthAng); // arrow base
                 var tempPt = newPt (ptArray[3][0], ptArray[3][1], (arrowLength), lineLengthAng);//temp midpoint for arrow ends
                 newPointArray[2] = newPt (tempPt[0],tempPt[1], -(arrowWidth)/2, lineAngTan2); //first arrow end
                 newPointArray[4] = newPt (tempPt[0],tempPt[1], -(arrowWidth)/2, lineAngTan1); //second arrow end
                 newPointArray[0] = newPt (ptArray[3][0], ptArray[3][1], (lineLength), lineLengthAng);      //arrow end              
                }
            break;
        case 10:
                lineLength = lineL (ptArray[2][0], ptArray[2][1], ptArray[7][0], ptArray[7][1]);
                arrowWidth = lineL (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
                lineLengthAng = getAng (ptArray[2][0], ptArray[2][1], ptArray[7][0], ptArray[7][1]);
                lineAngTan1 = getAng (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
                lineAngTan2 = getAng (ptArray[3][0], ptArray[3][1], ptArray[1][0], ptArray[1][1]);
                arrowHeadMid = bisect (ptArray[1][0], ptArray[1][1], ptArray[3][0], ptArray[3][1]);
                arrowHeadBase = (ptArray[0][0], ptArray[0][1]);
                arrowLength = lineL (ptArray[2][0], ptArray[2][1], arrowHeadMid[0], arrowHeadMid[1]);
                concaveLength = lineL (ptArray[2][0], ptArray[2][1], ptArray[0][0], ptArray[0][1]);
                arrowConcaveFactor = concaveLength/arrowLength;     
                
                ui ();
                
                 //Get new points
                 newPointArray[2] = [ptArray[2][0],ptArray[2][1]];  //tip1
                 newPointArray[7] = [ptArray[7][0],ptArray[7][1]];  //tip2
                 newPointArray[4] = newPointArray[0] = newPt (ptArray[2][0], ptArray[2][1], -(arrowLength*arrowConcaveFactor), lineLengthAng); // arrow base 1
                 newPointArray[5] = newPointArray[9] = newPt (ptArray[7][0], ptArray[7][1], (arrowLength*arrowConcaveFactor), lineLengthAng); // arrow base 2
                 var tempPt1 = newPt (ptArray[2][0], ptArray[2][1], -(arrowLength), lineLengthAng);//temp midpoint for arrow ends 1
                 var tempPt2 = newPt (ptArray[7][0], ptArray[7][1], (arrowLength), lineLengthAng);//temp midpoint for arrow ends 2                 
                 newPointArray[1] = newPt (tempPt1[0],tempPt1[1], -(arrowWidth)/2, lineAngTan2); //first arrow end 1
                 newPointArray[6] = newPt (tempPt2[0],tempPt2[1], -(arrowWidth)/2, lineAngTan2); //first arrow end 2
                 newPointArray[3] = newPt (tempPt1[0],tempPt1[1], -(arrowWidth)/2, lineAngTan1); //second arrow end 1
                 newPointArray[8] = newPt (tempPt2[0],tempPt2[1], -(arrowWidth)/2, lineAngTan1); //second arrow end 2
                 //newPointArray[5] = newPt (ptArray[2][0], ptArray[2][1], -(lineLength), lineLengthAng);      //arrow end  
                           
                
            break;        
        };

    var myPathInfo = mkNewPathInfo ();
    deltPath ();
    var tempPath = app.activeDocument.pathItems.add( 'temp', myPathInfo);
    selPath ();
    doc.activeLayer = sLay;
    mkPath ()
    tempPath.remove();
 
app.preferences.rulerUnits = oldPrefs;       
changeRes (oldRes)

}//end function run

function ui(){
         dlg = new Window('dialog','Edit Arrow');
            dlg.alignChildren = ['left','top'];   
                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,arrowLength.toFixed (2));
                        dlg.aLgp.ALen.size = [50,12];
                    dlg.aLgp.sTxte = dlg.aLgp.add('statictext',undefined,'px');
                    
                for(var i=0;i<xmlPref.prefs.arrows.children().length();i++){
                    dropLst[i]= xmlPref.prefs.arrows.children()[i].@preset
                    }                    
                    
                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,arrowWidth.toFixed (2));
                        dlg.aWgp.AWid.size = [50,12];
                    dlg.aWgp.sTxte = dlg.aWgp.add('statictext',undefined,'px');     
                    
                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,((1-arrowConcaveFactor)*100).toFixed (2));
                        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(){
                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
            };
        
        dlg.aLgp.ALen.onChange = function(){
            textToNum (1, 10000, dlg.aLgp.ALen, arrowLength);
            }       
        
        dlg.aWgp.AWid.onChange = function(){
            textToNum (1, 50000, dlg.aWgp.AWid, arrowWidth);
            } 
        
        dlg.aConGp.ACon.onChange = function(){
            textToNum (-50, 50, dlg.aConGp.ACon, arrowConcaveFactor);
            }    

            
        dlg.prefsPn.save.onClick = function(){
            savePrefs ();

                }
            
            dlg.prefsPn.del.onClick = function(){
                if(prefsDrop.selection != null){
                    var selc = parseInt(prefsDrop.selection);                    
                    prefsDrop.remove(selc);
                    delete xmlPref.prefs.arrows.children()[selc];
                    writeXMLFile (xmlFile, xmlPref)
                    }
                }                        
                                
                    
        dlg.btnGp.okay.onClick = function(){
            dlg.close();
                arrowLength = parseInt (dlg.aLgp.ALen.text);
                arrowWidth = parseInt (dlg.aWgp.AWid.text);
                arrowConcaveFactor = (100 - parseInt (dlg.aConGp.ACon.text))*.01;
                }

        dlg.btnGp.cancel.onClick = function(){            
            run = false;
            dlg.close()
            }                      
            
    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 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 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;
    }

function bisect(x1,y1,x2,y2){
    var midPoint = new Array();
    midPoint[0] = (x1+x2)/2;
    midPoint[1] = (y1+y2)/2;
    return midPoint;
    }

/////////////////////
    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 mkNewPathInfo(){
    var pathArray = new Array();
    var piArray = new Array();
    for(var i=0;i<newPointArray.length;i++){
         piArray[i] = new PathPointInfo;
         piArray[i].kind = PointKind.CORNERPOINT; 
         piArray[i].anchor = newPointArray[i];
         piArray[i].leftDirection = newPointArray[i];
         piArray[i].rightDirection = newPointArray[i];
        }//end loop
    pathArray[0] = new SubPathInfo();
    pathArray[0].operation = ShapeOperation.SHAPEXOR;
    pathArray[0].closed = true;
    pathArray[0].entireSubPath = piArray;  
    return pathArray;
    };//end function      

function changeRes(res){
        var idImgS = charIDToTypeID( "ImgS" );
        var desc15 = new ActionDescriptor();
        var idRslt = charIDToTypeID( "Rslt" );
        var idRsl = charIDToTypeID( "#Rsl" );
        desc15.putUnitDouble( idRslt, idRsl, res );
    executeAction( idImgS, desc15, DialogModes.NO );
    }

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)  
xmlPref.prefs.arrows.appendChild (XML('<arrow preset="'+ newName+ '"><leng>'+dlg.aLgp.ALen.text+'</leng><aWidth>'+dlg.aWgp.AWid.text+'</aWidth><concave>'+dlg.aConGp.ACon.text+'</concave></arrow>'));
        writeXMLFile (xmlFile, xmlPref) 

    }

//===============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, How to

Views

262

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
Oct 23, 2020 0
Most Valuable Participant ,
Oct 23, 2020

Copy link to clipboard

Copied

IMO the change to the line tool in 2021 is a disaster. Chuck can you create a visible line shape layer. Adobe might as well disable disable shape option as well as  pixel.  I get  no stroke with the line shape tool do you get one?.

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...
Oct 23, 2020 1
Adobe Community Professional ,
Oct 23, 2020

Copy link to clipboard

Copied

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...
Oct 23, 2020 0
Adobe Community Professional ,
Oct 23, 2020

Copy link to clipboard

Copied

JJ, yes, I get a stroke. 

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...
Oct 23, 2020 0
Most Valuable Participant ,
Oct 23, 2020

Copy link to clipboard

Copied

It seems like I have a problem. I delete all preferences and now I do get a stroke.  It still I bummer I can set not arrows  a percentage of line weight,.

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...
Oct 23, 2020 0
Adobe Community Professional ,
Oct 23, 2020

Copy link to clipboard

Copied

Did you try and  change the position of the stroke? On the inside doesn't work.

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...
Oct 23, 2020 0
Most Valuable Participant ,
Oct 23, 2020

Copy link to clipboard

Copied

The Preference the file was "Adobe Photoshop 2021 Prefs.psp" that cause the problem and just  restored it and the does not work again.  I change the stoke location and it fix the problem.  When 2021 migrated my preferences my preference was indeed inside so I was bitten by the new line tool inside bug.  Some day Adobe may learn how to develop and test code.  I do not think that day will be within my life time though.

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...
Oct 23, 2020 0
Adobe Employee ,
Oct 23, 2020

Copy link to clipboard

Copied

Ouch.

 

It's possible that the alignment setting for stroke is shared by other tools, and by changing in one place, it works against you in another. We'll look into that. The default is center aligned. 

 

At the least we should differentiate it so that it could be set independently for the line tool.

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...
Oct 23, 2020 1
Most Valuable Participant ,
Oct 25, 2020

Copy link to clipboard

Copied

Adobe broke the line shape tool when they removed line weight. The Line Shape tool can only create arrowhead Shape layers. You have to use the rectangle shape tool to create line weight shape layers. Use both tool and merge the two shape layers to create shape layer with arrowheads you want. For if you Stroke the Arrow Shape Layers the arrow line stroke will be a 0x wide stroke line,  or a 1x wide stroke line or a 2x wide stroke line.  None of these will be the arrow shape layer you want. For only 0x wide line arrow layer arrowheads point to the correct location you do not an arrow shaft you have been shafted. 

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...
Oct 25, 2020 0
Adobe Employee ,
Oct 25, 2020

Copy link to clipboard

Copied

The line tool draws a line and an arrowhead. The line is identical to the pen tool, and one perhaps negative side effect is that strokes that are inside aligned don't appear on two-point segments. Make sure your stroke alignment is center.

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...
Oct 25, 2020 0
JJMack LATEST
Most Valuable Participant ,
Oct 25, 2020

Copy link to clipboard

Copied

The line tool is not like the pen. With the pen tool you can drag out curved line segments and straight line segments connected together.  With line tool can drag out a single straight line segment with optional  closed  arrowhead shape end point path where the point of the arrow is the pixels clicked on to create the line. Stroking  the shape along the shape's path will  extent the arrowheads past the line end point by some amount of pixels  it depends on stroke width and stroke style whether the arrow tip will be blunt, rounded, or pointed. The line tool need to have a weight option so line can have closed paths so we can create line shape layer.  Without line weight we can only create arrowhead shape layers for a line path can have on fill. Shape are fill layer with vector layer mask. A straight line path does not enclose any area so fill is not possible

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...
Oct 25, 2020 0