diff --git a/apps/plotly_examples/package.json b/apps/plotly_examples/package.json index 08ab8b9167..4fe610296a 100644 --- a/apps/plotly_examples/package.json +++ b/apps/plotly_examples/package.json @@ -94,7 +94,8 @@ "@playwright/test": "^1.49.1", "@types/node": "^22.10.7", "@types/react": "17.0.44", - "@types/react-dom": "17.0.15" + "@types/react-dom": "17.0.15", + "parse-svg-path": "^0.1.2" }, "resolutions": { "@types/react": "17.0.44", diff --git a/apps/plotly_examples/src/components/parse-svg-path.d.ts b/apps/plotly_examples/src/components/parse-svg-path.d.ts new file mode 100644 index 0000000000..8dbfa2f3fe --- /dev/null +++ b/apps/plotly_examples/src/components/parse-svg-path.d.ts @@ -0,0 +1,3 @@ +declare module 'parse-svg-path' { + export default function parse(path: string): any[]; + } \ No newline at end of file diff --git a/apps/plotly_examples/src/components/plotly-symbol-defs.ts b/apps/plotly_examples/src/components/plotly-symbol-defs.ts new file mode 100644 index 0000000000..be36f9310d --- /dev/null +++ b/apps/plotly_examples/src/components/plotly-symbol-defs.ts @@ -0,0 +1,817 @@ +'use strict'; + +import parseSvgPath from 'parse-svg-path'; + +function round(x: number, n?: number): number { + if (typeof n === 'number') { + const factor = Math.pow(10, n); + return Math.round(x * factor) / factor; + } + return Math.round(x); +} + +/** 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; + +export const symbols = { + circle: { + n: 0, + f: function(r: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: number, angle: any, standoff: any) { + 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: null) { + return angle === null; +} + +var lastPathIn: any, lastPathOut: string; +var lastAngle: any, lastStandoff: any; + +function align(angle: number, standoff: any, path: string) { + 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: number, xy: any[]) { + 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; +} \ No newline at end of file diff --git a/apps/plotly_examples/src/components/utils.ts b/apps/plotly_examples/src/components/utils.ts index 21f8c16dac..75380e20e0 100644 --- a/apps/plotly_examples/src/components/utils.ts +++ b/apps/plotly_examples/src/components/utils.ts @@ -1,3 +1,5 @@ +import { symbols } from './plotly-symbol-defs'; + export function saveSelection(key: string, value: string) { let appKey = `FluentChartTest_${key}`; localStorage.setItem(appKey, value); @@ -10,4 +12,17 @@ export function getSelection(key: string, defaultValue: string): string { } export const SCHEMA_KEY = 'Schema'; -export const SCHEMA_KEY_DEFAULT = '001' \ No newline at end of file + +export function symbolWithMargin(symbolFn: (size: number) => string, size: number, margin = 1) { + const adjustedSize = Math.max(0, size - 2 * margin); + let path = symbolFn(adjustedSize); + // Offset the path by +1px in both x and y directions + path = path.replace(/([ML])\s*(-?\d+\.?\d*)\s*,\s*(-?\d+\.?\d*)/g, (match, cmd, x, y) => { + return `${cmd} ${parseFloat(x) + margin},${parseFloat(y) + margin}`; + }); + return path; +} + +export function getSymbolPathByName(symbolName: keyof typeof symbols, size: number, margin = 1) { + return symbolWithMargin((s) => symbols[symbolName].f(s, 0, 0), size, margin); +} \ No newline at end of file