'use strict'; var parseSvgPath = require('parse-svg-path'); var round = require('@plotly/d3').round; /** Marker symbol definitions * users can specify markers either by number or name * add 100 (or '-open') and you get an open marker * open markers have no fill and use line color as the stroke color * add 200 (or '-dot') and you get a dot in the middle * add both and you get both */ var emptyPath = 'M0,0Z'; var sqrt2 = Math.sqrt(2); var sqrt3 = Math.sqrt(3); var PI = Math.PI; var cos = Math.cos; var sin = Math.sin; module.exports = { circle: { n: 0, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rs = round(r, 2); var circle = 'M' + rs + ',0A' + rs + ',' + rs + ' 0 1,1 0,-' + rs + 'A' + rs + ',' + rs + ' 0 0,1 ' + rs + ',0Z'; return standoff ? align(angle, standoff, circle) : circle; } }, square: { n: 1, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rs = round(r, 2); return align(angle, standoff, 'M' + rs + ',' + rs + 'H-' + rs + 'V-' + rs + 'H' + rs + 'Z'); } }, diamond: { n: 2, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rd = round(r * 1.3, 2); return align(angle, standoff, 'M' + rd + ',0L0,' + rd + 'L-' + rd + ',0L0,-' + rd + 'Z'); } }, cross: { n: 3, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rc = round(r * 0.4, 2); var rc2 = round(r * 1.2, 2); return align(angle, standoff, 'M' + rc2 + ',' + rc + 'H' + rc + 'V' + rc2 + 'H-' + rc + 'V' + rc + 'H-' + rc2 + 'V-' + rc + 'H-' + rc + 'V-' + rc2 + 'H' + rc + 'V-' + rc + 'H' + rc2 + 'Z'); } }, x: { n: 4, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rx = round(r * 0.8 / sqrt2, 2); var ne = 'l' + rx + ',' + rx; var se = 'l' + rx + ',-' + rx; var sw = 'l-' + rx + ',-' + rx; var nw = 'l-' + rx + ',' + rx; return align(angle, standoff, 'M0,' + rx + ne + se + sw + se + sw + nw + sw + nw + ne + nw + ne + 'Z'); } }, 'triangle-up': { n: 5, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rt = round(r * 2 / sqrt3, 2); var r2 = round(r / 2, 2); var rs = round(r, 2); return align(angle, standoff, 'M-' + rt + ',' + r2 + 'H' + rt + 'L0,-' + rs + 'Z'); } }, 'triangle-down': { n: 6, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rt = round(r * 2 / sqrt3, 2); var r2 = round(r / 2, 2); var rs = round(r, 2); return align(angle, standoff, 'M-' + rt + ',-' + r2 + 'H' + rt + 'L0,' + rs + 'Z'); } }, 'triangle-left': { n: 7, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rt = round(r * 2 / sqrt3, 2); var r2 = round(r / 2, 2); var rs = round(r, 2); return align(angle, standoff, 'M' + r2 + ',-' + rt + 'V' + rt + 'L-' + rs + ',0Z'); } }, 'triangle-right': { n: 8, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rt = round(r * 2 / sqrt3, 2); var r2 = round(r / 2, 2); var rs = round(r, 2); return align(angle, standoff, 'M-' + r2 + ',-' + rt + 'V' + rt + 'L' + rs + ',0Z'); } }, 'triangle-ne': { n: 9, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var r1 = round(r * 0.6, 2); var r2 = round(r * 1.2, 2); return align(angle, standoff, 'M-' + r2 + ',-' + r1 + 'H' + r1 + 'V' + r2 + 'Z'); } }, 'triangle-se': { n: 10, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var r1 = round(r * 0.6, 2); var r2 = round(r * 1.2, 2); return align(angle, standoff, 'M' + r1 + ',-' + r2 + 'V' + r1 + 'H-' + r2 + 'Z'); } }, 'triangle-sw': { n: 11, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var r1 = round(r * 0.6, 2); var r2 = round(r * 1.2, 2); return align(angle, standoff, 'M' + r2 + ',' + r1 + 'H-' + r1 + 'V-' + r2 + 'Z'); } }, 'triangle-nw': { n: 12, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var r1 = round(r * 0.6, 2); var r2 = round(r * 1.2, 2); return align(angle, standoff, 'M-' + r1 + ',' + r2 + 'V-' + r1 + 'H' + r2 + 'Z'); } }, pentagon: { n: 13, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var x1 = round(r * 0.951, 2); var x2 = round(r * 0.588, 2); var y0 = round(-r, 2); var y1 = round(r * -0.309, 2); var y2 = round(r * 0.809, 2); return align(angle, standoff, 'M' + x1 + ',' + y1 + 'L' + x2 + ',' + y2 + 'H-' + x2 + 'L-' + x1 + ',' + y1 + 'L0,' + y0 + 'Z'); } }, hexagon: { n: 14, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var y0 = round(r, 2); var y1 = round(r / 2, 2); var x = round(r * sqrt3 / 2, 2); return align(angle, standoff, 'M' + x + ',-' + y1 + 'V' + y1 + 'L0,' + y0 + 'L-' + x + ',' + y1 + 'V-' + y1 + 'L0,-' + y0 + 'Z'); } }, hexagon2: { n: 15, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var x0 = round(r, 2); var x1 = round(r / 2, 2); var y = round(r * sqrt3 / 2, 2); return align(angle, standoff, 'M-' + x1 + ',' + y + 'H' + x1 + 'L' + x0 + ',0L' + x1 + ',-' + y + 'H-' + x1 + 'L-' + x0 + ',0Z'); } }, octagon: { n: 16, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var a = round(r * 0.924, 2); var b = round(r * 0.383, 2); return align(angle, standoff, 'M-' + b + ',-' + a + 'H' + b + 'L' + a + ',-' + b + 'V' + b + 'L' + b + ',' + a + 'H-' + b + 'L-' + a + ',' + b + 'V-' + b + 'Z'); } }, star: { n: 17, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rs = r * 1.4; var x1 = round(rs * 0.225, 2); var x2 = round(rs * 0.951, 2); var x3 = round(rs * 0.363, 2); var x4 = round(rs * 0.588, 2); var y0 = round(-rs, 2); var y1 = round(rs * -0.309, 2); var y3 = round(rs * 0.118, 2); var y4 = round(rs * 0.809, 2); var y5 = round(rs * 0.382, 2); return align(angle, standoff, 'M' + x1 + ',' + y1 + 'H' + x2 + 'L' + x3 + ',' + y3 + 'L' + x4 + ',' + y4 + 'L0,' + y5 + 'L-' + x4 + ',' + y4 + 'L-' + x3 + ',' + y3 + 'L-' + x2 + ',' + y1 + 'H-' + x1 + 'L0,' + y0 + 'Z'); } }, hexagram: { n: 18, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var y = round(r * 0.66, 2); var x1 = round(r * 0.38, 2); var x2 = round(r * 0.76, 2); return align(angle, standoff, 'M-' + x2 + ',0l-' + x1 + ',-' + y + 'h' + x2 + 'l' + x1 + ',-' + y + 'l' + x1 + ',' + y + 'h' + x2 + 'l-' + x1 + ',' + y + 'l' + x1 + ',' + y + 'h-' + x2 + 'l-' + x1 + ',' + y + 'l-' + x1 + ',-' + y + 'h-' + x2 + 'Z'); } }, 'star-triangle-up': { n: 19, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var x = round(r * sqrt3 * 0.8, 2); var y1 = round(r * 0.8, 2); var y2 = round(r * 1.6, 2); var rc = round(r * 4, 2); var aPart = 'A ' + rc + ',' + rc + ' 0 0 1 '; return align(angle, standoff, 'M-' + x + ',' + y1 + aPart + x + ',' + y1 + aPart + '0,-' + y2 + aPart + '-' + x + ',' + y1 + 'Z'); } }, 'star-triangle-down': { n: 20, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var x = round(r * sqrt3 * 0.8, 2); var y1 = round(r * 0.8, 2); var y2 = round(r * 1.6, 2); var rc = round(r * 4, 2); var aPart = 'A ' + rc + ',' + rc + ' 0 0 1 '; return align(angle, standoff, 'M' + x + ',-' + y1 + aPart + '-' + x + ',-' + y1 + aPart + '0,' + y2 + aPart + x + ',-' + y1 + 'Z'); } }, 'star-square': { n: 21, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rp = round(r * 1.1, 2); var rc = round(r * 2, 2); var aPart = 'A ' + rc + ',' + rc + ' 0 0 1 '; return align(angle, standoff, 'M-' + rp + ',-' + rp + aPart + '-' + rp + ',' + rp + aPart + rp + ',' + rp + aPart + rp + ',-' + rp + aPart + '-' + rp + ',-' + rp + 'Z'); } }, 'star-diamond': { n: 22, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rp = round(r * 1.4, 2); var rc = round(r * 1.9, 2); var aPart = 'A ' + rc + ',' + rc + ' 0 0 1 '; return align(angle, standoff, 'M-' + rp + ',0' + aPart + '0,' + rp + aPart + rp + ',0' + aPart + '0,-' + rp + aPart + '-' + rp + ',0' + 'Z'); } }, 'diamond-tall': { n: 23, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var x = round(r * 0.7, 2); var y = round(r * 1.4, 2); return align(angle, standoff, 'M0,' + y + 'L' + x + ',0L0,-' + y + 'L-' + x + ',0Z'); } }, 'diamond-wide': { n: 24, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var x = round(r * 1.4, 2); var y = round(r * 0.7, 2); return align(angle, standoff, 'M0,' + y + 'L' + x + ',0L0,-' + y + 'L-' + x + ',0Z'); } }, hourglass: { n: 25, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rs = round(r, 2); return align(angle, standoff, 'M' + rs + ',' + rs + 'H-' + rs + 'L' + rs + ',-' + rs + 'H-' + rs + 'Z'); }, noDot: true }, bowtie: { n: 26, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rs = round(r, 2); return align(angle, standoff, 'M' + rs + ',' + rs + 'V-' + rs + 'L-' + rs + ',' + rs + 'V-' + rs + 'Z'); }, noDot: true }, 'circle-cross': { n: 27, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rs = round(r, 2); return align(angle, standoff, 'M0,' + rs + 'V-' + rs + 'M' + rs + ',0H-' + rs + 'M' + rs + ',0A' + rs + ',' + rs + ' 0 1,1 0,-' + rs + 'A' + rs + ',' + rs + ' 0 0,1 ' + rs + ',0Z'); }, needLine: true, noDot: true }, 'circle-x': { n: 28, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rs = round(r, 2); var rc = round(r / sqrt2, 2); return align(angle, standoff, 'M' + rc + ',' + rc + 'L-' + rc + ',-' + rc + 'M' + rc + ',-' + rc + 'L-' + rc + ',' + rc + 'M' + rs + ',0A' + rs + ',' + rs + ' 0 1,1 0,-' + rs + 'A' + rs + ',' + rs + ' 0 0,1 ' + rs + ',0Z'); }, needLine: true, noDot: true }, 'square-cross': { n: 29, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rs = round(r, 2); return align(angle, standoff, 'M0,' + rs + 'V-' + rs + 'M' + rs + ',0H-' + rs + 'M' + rs + ',' + rs + 'H-' + rs + 'V-' + rs + 'H' + rs + 'Z'); }, needLine: true, noDot: true }, 'square-x': { n: 30, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rs = round(r, 2); return align(angle, standoff, 'M' + rs + ',' + rs + 'L-' + rs + ',-' + rs + 'M' + rs + ',-' + rs + 'L-' + rs + ',' + rs + 'M' + rs + ',' + rs + 'H-' + rs + 'V-' + rs + 'H' + rs + 'Z'); }, needLine: true, noDot: true }, 'diamond-cross': { n: 31, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rd = round(r * 1.3, 2); return align(angle, standoff, 'M' + rd + ',0L0,' + rd + 'L-' + rd + ',0L0,-' + rd + 'Z' + 'M0,-' + rd + 'V' + rd + 'M-' + rd + ',0H' + rd); }, needLine: true, noDot: true }, 'diamond-x': { n: 32, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rd = round(r * 1.3, 2); var r2 = round(r * 0.65, 2); return align(angle, standoff, 'M' + rd + ',0L0,' + rd + 'L-' + rd + ',0L0,-' + rd + 'Z' + 'M-' + r2 + ',-' + r2 + 'L' + r2 + ',' + r2 + 'M-' + r2 + ',' + r2 + 'L' + r2 + ',-' + r2); }, needLine: true, noDot: true }, 'cross-thin': { n: 33, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rc = round(r * 1.4, 2); return align(angle, standoff, 'M0,' + rc + 'V-' + rc + 'M' + rc + ',0H-' + rc); }, needLine: true, noDot: true, noFill: true }, 'x-thin': { n: 34, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rx = round(r, 2); return align(angle, standoff, 'M' + rx + ',' + rx + 'L-' + rx + ',-' + rx + 'M' + rx + ',-' + rx + 'L-' + rx + ',' + rx); }, needLine: true, noDot: true, noFill: true }, asterisk: { n: 35, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rc = round(r * 1.2, 2); var rs = round(r * 0.85, 2); return align(angle, standoff, 'M0,' + rc + 'V-' + rc + 'M' + rc + ',0H-' + rc + 'M' + rs + ',' + rs + 'L-' + rs + ',-' + rs + 'M' + rs + ',-' + rs + 'L-' + rs + ',' + rs); }, needLine: true, noDot: true, noFill: true }, hash: { n: 36, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var r1 = round(r / 2, 2); var r2 = round(r, 2); return align(angle, standoff, 'M' + r1 + ',' + r2 + 'V-' + r2 + 'M' + (r1 - r2) + ',-' + r2 + 'V' + r2 + 'M' + r2 + ',' + r1 + 'H-' + r2 + 'M-' + r2 + ',' + (r1 - r2) + 'H' + r2); }, needLine: true, noFill: true }, 'y-up': { n: 37, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var x = round(r * 1.2, 2); var y0 = round(r * 1.6, 2); var y1 = round(r * 0.8, 2); return align(angle, standoff, 'M-' + x + ',' + y1 + 'L0,0M' + x + ',' + y1 + 'L0,0M0,-' + y0 + 'L0,0'); }, needLine: true, noDot: true, noFill: true }, 'y-down': { n: 38, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var x = round(r * 1.2, 2); var y0 = round(r * 1.6, 2); var y1 = round(r * 0.8, 2); return align(angle, standoff, 'M-' + x + ',-' + y1 + 'L0,0M' + x + ',-' + y1 + 'L0,0M0,' + y0 + 'L0,0'); }, needLine: true, noDot: true, noFill: true }, 'y-left': { n: 39, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var y = round(r * 1.2, 2); var x0 = round(r * 1.6, 2); var x1 = round(r * 0.8, 2); return align(angle, standoff, 'M' + x1 + ',' + y + 'L0,0M' + x1 + ',-' + y + 'L0,0M-' + x0 + ',0L0,0'); }, needLine: true, noDot: true, noFill: true }, 'y-right': { n: 40, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var y = round(r * 1.2, 2); var x0 = round(r * 1.6, 2); var x1 = round(r * 0.8, 2); return align(angle, standoff, 'M-' + x1 + ',' + y + 'L0,0M-' + x1 + ',-' + y + 'L0,0M' + x0 + ',0L0,0'); }, needLine: true, noDot: true, noFill: true }, 'line-ew': { n: 41, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rc = round(r * 1.4, 2); return align(angle, standoff, 'M' + rc + ',0H-' + rc); }, needLine: true, noDot: true, noFill: true }, 'line-ns': { n: 42, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rc = round(r * 1.4, 2); return align(angle, standoff, 'M0,' + rc + 'V-' + rc); }, needLine: true, noDot: true, noFill: true }, 'line-ne': { n: 43, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rx = round(r, 2); return align(angle, standoff, 'M' + rx + ',-' + rx + 'L-' + rx + ',' + rx); }, needLine: true, noDot: true, noFill: true }, 'line-nw': { n: 44, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rx = round(r, 2); return align(angle, standoff, 'M' + rx + ',' + rx + 'L-' + rx + ',-' + rx); }, needLine: true, noDot: true, noFill: true }, 'arrow-up': { n: 45, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rx = round(r, 2); var ry = round(r * 2, 2); return align(angle, standoff, 'M0,0L-' + rx + ',' + ry + 'H' + rx + 'Z'); }, backoff: 1, noDot: true }, 'arrow-down': { n: 46, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rx = round(r, 2); var ry = round(r * 2, 2); return align(angle, standoff, 'M0,0L-' + rx + ',-' + ry + 'H' + rx + 'Z'); }, noDot: true }, 'arrow-left': { n: 47, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rx = round(r * 2, 2); var ry = round(r, 2); return align(angle, standoff, 'M0,0L' + rx + ',-' + ry + 'V' + ry + 'Z'); }, noDot: true }, 'arrow-right': { n: 48, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rx = round(r * 2, 2); var ry = round(r, 2); return align(angle, standoff, 'M0,0L-' + rx + ',-' + ry + 'V' + ry + 'Z'); }, noDot: true }, 'arrow-bar-up': { n: 49, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rx = round(r, 2); var ry = round(r * 2, 2); return align(angle, standoff, 'M-' + rx + ',0H' + rx + 'M0,0L-' + rx + ',' + ry + 'H' + rx + 'Z'); }, backoff: 1, needLine: true, noDot: true }, 'arrow-bar-down': { n: 50, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rx = round(r, 2); var ry = round(r * 2, 2); return align(angle, standoff, 'M-' + rx + ',0H' + rx + 'M0,0L-' + rx + ',-' + ry + 'H' + rx + 'Z'); }, needLine: true, noDot: true }, 'arrow-bar-left': { n: 51, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rx = round(r * 2, 2); var ry = round(r, 2); return align(angle, standoff, 'M0,-' + ry + 'V' + ry + 'M0,0L' + rx + ',-' + ry + 'V' + ry + 'Z'); }, needLine: true, noDot: true }, 'arrow-bar-right': { n: 52, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var rx = round(r * 2, 2); var ry = round(r, 2); return align(angle, standoff, 'M0,-' + ry + 'V' + ry + 'M0,0L-' + rx + ',-' + ry + 'V' + ry + 'Z'); }, needLine: true, noDot: true }, arrow: { n: 53, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var headAngle = PI / 2.5; // 36 degrees - golden ratio var x = 2 * r * cos(headAngle); var y = 2 * r * sin(headAngle); return align(angle, standoff, 'M0,0' + 'L' + -x + ',' + y + 'L' + x + ',' + y + 'Z' ); }, backoff: 0.9, noDot: true }, 'arrow-wide': { n: 54, f: function(r, angle, standoff) { if(skipAngle(angle)) return emptyPath; var headAngle = PI / 4; // 90 degrees var x = 2 * r * cos(headAngle); var y = 2 * r * sin(headAngle); return align(angle, standoff, 'M0,0' + 'L' + -x + ',' + y + 'A ' + 2 * r + ',' + 2 * r + ' 0 0 1 ' + x + ',' + y + 'Z' ); }, backoff: 0.4, noDot: true } }; function skipAngle(angle) { return angle === null; } var lastPathIn, lastPathOut; var lastAngle, lastStandoff; function align(angle, standoff, path) { if((!angle || angle % 360 === 0) && !standoff) return path; if( lastAngle === angle && lastStandoff === standoff && lastPathIn === path ) return lastPathOut; lastAngle = angle; lastStandoff = standoff; lastPathIn = path; function rotate(t, xy) { var cosT = cos(t); var sinT = sin(t); var x = xy[0]; var y = xy[1] + (standoff || 0); return [ x * cosT - y * sinT, x * sinT + y * cosT ]; } var t = angle / 180 * PI; var x = 0; var y = 0; var cmd = parseSvgPath(path); var str = ''; for(var i = 0; i < cmd.length; i++) { var cmdI = cmd[i]; var op = cmdI[0]; var x0 = x; var y0 = y; if(op === 'M' || op === 'L') { x = +cmdI[1]; y = +cmdI[2]; } else if(op === 'm' || op === 'l') { x += +cmdI[1]; y += +cmdI[2]; } else if(op === 'H') { x = +cmdI[1]; } else if(op === 'h') { x += +cmdI[1]; } else if(op === 'V') { y = +cmdI[1]; } else if(op === 'v') { y += +cmdI[1]; } else if(op === 'A') { x = +cmdI[1]; y = +cmdI[2]; var E = rotate(t, [+cmdI[6], +cmdI[7]]); cmdI[6] = E[0]; cmdI[7] = E[1]; cmdI[3] = +cmdI[3] + angle; } // change from H, V, h, v to L or l if(op === 'H' || op === 'V') op = 'L'; if(op === 'h' || op === 'v') op = 'l'; if(op === 'm' || op === 'l') { x -= x0; y -= y0; } var B = rotate(t, [x, y]); if(op === 'H' || op === 'V') op = 'L'; if( op === 'M' || op === 'L' || op === 'm' || op === 'l' ) { cmdI[1] = B[0]; cmdI[2] = B[1]; } cmdI[0] = op; str += cmdI[0] + cmdI.slice(1).join(','); } lastPathOut = str; return str; }