UNPKG

svg-parse-path-normalized

Version:

Parse svg path data from string and normalize it to calculable value arrays

190 lines (165 loc) 6 kB
/** * custom pathData() and setPathData() methods * browser only **/ // retrieve pathdata from svg geometry elements SVGGeometryElement.prototype.getPathDataConverted = function (options = {}) { let pathData = []; let type = this.nodeName; let d, x, y, width, height, r, rx, ry, cx, cy; /** * bugfix fro chromium * ensures we can get the absolute baseVal.values */ if (type !== 'path') { css = window.getComputedStyle(this).fill } switch (type) { case 'path': d = this.getAttribute("d"); pathData = parsePathDataNormalized(d); break; case 'rect': x = this.x.baseVal.value; y = this.y.baseVal.value; width = this.width.baseVal.value; height = this.height.baseVal.value; rx = this.rx.baseVal.value; ry = this.ry.baseVal.value; if (!rx && !ry) { pathData = [ { type: "M", values: [x, y] }, { type: "H", values: [x + width] }, { type: "V", values: [y + height] }, { type: "H", values: [x] }, { type: "Z", values: [] } ]; } else { if (rx > width / 2) { rx = width / 2; } if (ry > height / 2) { ry = height / 2; } pathData = [ { type: "M", values: [x + rx, y] }, { type: "H", values: [x + width - rx] }, { type: "A", values: [rx, ry, 0, 0, 1, x + width, y + ry] }, { type: "V", values: [y + height - ry] }, { type: "A", values: [rx, ry, 0, 0, 1, x + width - rx, y + height] }, { type: "H", values: [x + rx] }, { type: "A", values: [rx, ry, 0, 0, 1, x, y + height - ry] }, { type: "V", values: [y + ry] }, { type: "A", values: [rx, ry, 0, 0, 1, x + rx, y] }, { type: "Z", values: [] } ]; } break; case 'circle': case 'ellipse': cx = this.cx.baseVal.value; cy = this.cy.baseVal.value; if (type === 'circle') { r = this.r.baseVal.value; } rx = this.rx ? this.rx.baseVal.value : r; ry = this.ry ? this.ry.baseVal.value : r; pathData = [ { type: "M", values: [cx + rx, cy] }, { type: "A", values: [rx, ry, 0, 1, 1, cx - rx, cy] }, { type: "A", values: [rx, ry, 0, 1, 1, cx + rx, cy] }, ]; break; case 'line': pathData = [ { type: "M", values: [this.x1.baseVal.value, this.y1.baseVal.value] }, { type: "L", values: [this.x2.baseVal.value, this.y2.baseVal.value] } ]; break; case 'polygon': case 'polyline': for (let i = 0; i < this.points.numberOfItems; i++) { let point = this.points.getItem(i); pathData.push({ type: (i === 0 ? "M" : "L"), values: [point.x, point.y] }); } if (type === 'polygon') { pathData.push({ type: "Z", values: [] }); } break; } /** * normalize commands * for processing you usually need * absolute and longhand commands */ let defaults = { normalize: false, toAbsolute: false, arcToCubic: false, arcAccuracy: 1, quadraticToCubic: false, toLonghands: false, } options = { ...defaults, ...options } if (options.normalize === true) { options = { toAbsolute: true, arcToCubic: true, arcAccuracy: 1, quadraticToCubic: true, toLonghands: true, } } if (Object.keys(options).length) { pathData = convertPathData(pathData, options) } return pathData; }; /** * retrieve patData from primitives: * <circle>, <ellipse>, <rect>, <polygon>, <polyline>, <line>, */ SVGGeometryElement.prototype.convertShapeToPath = function (options = {}) { let pathData = this.getPathDataConverted(options); // create path element let path = document.createElementNS("http://www.w3.org/2000/svg", "path"); // get all attributes as object const setAttributes = (el, attributes, exclude = []) => { for (key in attributes) { if (exclude.indexOf(key) === -1) { el.setAttribute(key, attributes[key]); } } } const getAttributes = (el) => { let attArr = [...el.attributes]; let attObj = {}; attArr.forEach((att) => { attObj[att.nodeName] = att.nodeValue; }); return attObj; } let attributes = getAttributes(this); //exclude attributes not needed for paths let exclude = ["x", "y", "x1", "y1", "x2", "y2", "cx", "cy", "r", "rx", "ry", "points", "width", "height"]; // copy attributes to path and set pathData setAttributes(path, attributes, exclude); decimals = options.decimals ? options.decimals : -1 minify = options.minify ? options.minify : -1 path.setPathDataConverted(pathData, decimals, minify); this.replaceWith(path); return path; } SVGPathElement.prototype.setPathDataConverted = function (pathData, decimals = -1, minify = false) { this.setAttribute('d', pathDataToD(pathData, decimals, minify)) }