Merge pull request #646 from SVG-Edit/fix-path

Fix path
master
JFH 2021-09-20 09:50:52 +02:00 committed by GitHub
commit 31ce3f3c6f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 69 additions and 297 deletions

View File

@ -67,7 +67,7 @@ exports[`use all parts of svg-edit > check tool_path_change_node_xy #0`] = `
fill="#FF0000" fill="#FF0000"
stroke="#000000" stroke="#000000"
stroke-width="5" stroke-width="5"
d="M75,75L150,100L125,200L75,75z" d="M 75 75 L 150 100 L 125 200 L 75 75 z"
id="svg_1" id="svg_1"
fill-opacity="1" fill-opacity="1"
stroke-opacity="1" stroke-opacity="1"
@ -94,7 +94,7 @@ exports[`use all parts of svg-edit > check tool_path_change_seg_type #0`] = `
fill="#FF0000" fill="#FF0000"
stroke="#000000" stroke="#000000"
stroke-width="5" stroke-width="5"
d="M75,75L150,100L125,200C235.33333,330.33333 91.66667,116.66667 75,75z" d="M 75 75 L 150 100 L 125 200 C 235.33333333333331 330.33333333333337 91.66666666666667 116.66666666666666 75 75 z"
id="svg_1" id="svg_1"
fill-opacity="1" fill-opacity="1"
stroke-opacity="1" stroke-opacity="1"
@ -121,7 +121,7 @@ exports[`use all parts of svg-edit > check tool_path_change_clone_node #0`] = `
fill="#FF0000" fill="#FF0000"
stroke="#000000" stroke="#000000"
stroke-width="5" stroke-width="5"
d="M201,246L150,100L125,200C180.16666,265.16666 297.83333,415.33333 273.625,373C249.41667,330.66667 209.33334,266.83334 201,246z" d="M 201 246 L 150 100 L 125 200 C 180.16666666666666 265.1666666666667 297.8333333333333 415.33333333333337 273.625 373 C 249.41666666666669 330.66666666666663 209.33333333333334 266.8333333333333 201 246 z"
id="svg_1" id="svg_1"
fill-opacity="1" fill-opacity="1"
stroke-opacity="1" stroke-opacity="1"
@ -148,7 +148,7 @@ exports[`use all parts of svg-edit > check tool_path_openclose #0`] = `
fill="#FF0000" fill="#FF0000"
stroke="#000000" stroke="#000000"
stroke-width="5" stroke-width="5"
d="M201,246L150,100L125,200C180.16666,265.16666 297.83333,415.33333 273.625,373C249.41667,330.66667 209.33334,266.83334 201,246z" d="M 201 246 L 150 100 L 125 200 C 180.16666666666666 265.1666666666667 297.8333333333333 415.33333333333337 273.625 373 C 249.41666666666669 330.66666666666663 209.33333333333334 266.8333333333333 201 246 z"
id="svg_1" id="svg_1"
fill-opacity="1" fill-opacity="1"
stroke-opacity="1" stroke-opacity="1"

View File

@ -1,3 +1,4 @@
import 'pathseg';
import { NS } from '../../../instrumented/common/namespaces.js'; import { NS } from '../../../instrumented/common/namespaces.js';
import * as draw from '../../../instrumented/svgcanvas/draw.js'; import * as draw from '../../../instrumented/svgcanvas/draw.js';
import * as units from '../../../instrumented/common/units.js'; import * as units from '../../../instrumented/common/units.js';

View File

@ -1,5 +1,4 @@
/* eslint-disable max-len */ /* eslint-disable max-len */
import * as browser from '../../../instrumented/common/browser.js';
import * as utilities from '../../../instrumented/svgcanvas/utilities.js'; import * as utilities from '../../../instrumented/svgcanvas/utilities.js';
import { NS } from '../../../instrumented/common/namespaces.js'; import { NS } from '../../../instrumented/common/namespaces.js';
@ -161,19 +160,6 @@ describe('utilities', function () {
assert.equal(utilities.getUrlFromAttr('url("#foo")'), '#foo'); assert.equal(utilities.getUrlFromAttr('url("#foo")'), '#foo');
}); });
it('Test getPathBBox', function () {
if (browser.supportsPathBBox()) {
return;
}
const doc = utilities.text2xml('<svg></svg>');
const path = doc.createElementNS(NS.SVG, 'path');
path.setAttribute('d', 'm0,0l5,0l0,5l-5,0l0,-5z');
const bb = utilities.getPathBBox(path);
assert.equal(typeof bb, 'object', 'BBox returned object');
assert.ok(bb.x && !isNaN(bb.x));
assert.ok(bb.y && !isNaN(bb.y));
});
it('Test getPathDFromSegments', function () { it('Test getPathDFromSegments', function () {
const { getPathDFromSegments } = utilities; const { getPathDFromSegments } = utilities;
@ -226,7 +212,6 @@ describe('utilities', function () {
}); });
svgroot.append(elem); svgroot.append(elem);
const closeEnough = /M0,4 C0,2.3\d* 0.9\d*,1 2,1 L8,1 C9.0\d*,1 10,2.3\d* 10,4 L10,9 C10,10.6\d* 9.0\d*,12 8,12 L2,12 C0.9\d*,12 0,10.6\d* 0,9 L0,4 Z/; const closeEnough = /M0,4 C0,2.3\d* 0.9\d*,1 2,1 L8,1 C9.0\d*,1 10,2.3\d* 10,4 L10,9 C10,10.6\d* 9.0\d*,12 8,12 L2,12 C0.9\d*,12 0,10.6\d* 0,9 L0,4 Z/;
console.log(getPathDFromElement(elem), closeEnough);
assert.equal(closeEnough.test(getPathDFromElement(elem)), true); assert.equal(closeEnough.test(getPathDFromElement(elem)), true);
elem.remove(); elem.remove();

View File

@ -6,8 +6,6 @@
* @copyright 2010 Jeff Schiller, 2010 Alexis Deveria * @copyright 2010 Jeff Schiller, 2010 Alexis Deveria
*/ */
import 'pathseg';
import { NS } from './namespaces.js'; import { NS } from './namespaces.js';
const { userAgent } = navigator; const { userAgent } = navigator;
@ -19,31 +17,6 @@ const isChrome_ = userAgent.includes('Chrome/');
const isMac_ = userAgent.includes('Macintosh'); const isMac_ = userAgent.includes('Macintosh');
const isTouch_ = 'ontouchstart' in window; const isTouch_ = 'ontouchstart' in window;
// segList functions (for FF1.5 and 2.0)
const supportsPathReplaceItem_ = (function () {
const path = document.createElementNS(NS.SVG, 'path');
path.setAttribute('d', 'M0,0 10,10');
const seglist = path.pathSegList;
const seg = path.createSVGPathSegLinetoAbs(5, 5);
try {
seglist.replaceItem(seg, 1);
return true;
}catch (err) {/* empty */}
return false;
}());
const supportsPathInsertItemBefore_ = (function () {
const path = document.createElementNS(NS.SVG, 'path');
path.setAttribute('d', 'M0,0 10,10');
const seglist = path.pathSegList;
const seg = path.createSVGPathSegLinetoAbs(5, 5);
try {
seglist.insertItemBefore(seg, 1);
return true;
}catch (err) {/* empty */}
return false;
}());
// text character positioning (for IE9 and now Chrome) // text character positioning (for IE9 and now Chrome)
const supportsGoodTextCharPos_ = (function () { const supportsGoodTextCharPos_ = (function () {
const svgroot = document.createElementNS(NS.SVG, 'svg'); const svgroot = document.createElementNS(NS.SVG, 'svg');
@ -64,17 +37,6 @@ const supportsGoodTextCharPos_ = (function () {
} }
}()); }());
const supportsPathBBox_ = (function () {
const svgcontent = document.createElementNS(NS.SVG, 'svg');
document.documentElement.append(svgcontent);
const path = document.createElementNS(NS.SVG, 'path');
path.setAttribute('d', 'M0,0 C0,0 10,10 10,0');
svgcontent.append(path);
const bbox = path.getBBox();
svgcontent.remove();
return (bbox.height > 4 && bbox.height < 5);
}());
// Support for correct bbox sizing on groups with horizontal/vertical lines // Support for correct bbox sizing on groups with horizontal/vertical lines
const supportsHVLineContainerBBox_ = (function () { const supportsHVLineContainerBBox_ = (function () {
const svgcontent = document.createElementNS(NS.SVG, 'svg'); const svgcontent = document.createElementNS(NS.SVG, 'svg');
@ -127,24 +89,6 @@ export const isMac = () => isMac_;
*/ */
export const isTouch = () => isTouch_; export const isTouch = () => isTouch_;
/**
* @function module:browser.supportsPathReplaceItem
* @returns {boolean}
*/
export const supportsPathReplaceItem = () => supportsPathReplaceItem_;
/**
* @function module:browser.supportsPathInsertItemBefore
* @returns {boolean}
*/
export const supportsPathInsertItemBefore = () => supportsPathInsertItemBefore_;
/**
* @function module:browser.supportsPathBBox
* @returns {boolean}
*/
export const supportsPathBBox = () => supportsPathBBox_;
/** /**
* @function module:browser.supportsHVLineContainerBBox * @function module:browser.supportsHVLineContainerBBox
* @returns {boolean} * @returns {boolean}

View File

@ -365,7 +365,8 @@ class Editor extends EditorStartup {
const { workarea } = this; const { workarea } = this;
const cnvs = $id("svgcanvas"); const cnvs = $id("svgcanvas");
let w = parseFloat(getComputedStyle(workarea, null).width.replace("px", "")); let h = parseFloat(getComputedStyle(workarea, null).height.replace("px", "")); let w = parseFloat(getComputedStyle(workarea, null).width.replace("px", ""));
let h = parseFloat(getComputedStyle(workarea, null).height.replace("px", ""));
const wOrig = w; const hOrig = h; const wOrig = w; const hOrig = h;
const oldCtr = { const oldCtr = {
x: workarea.scrollLeft + wOrig / 2, x: workarea.scrollLeft + wOrig / 2,

View File

@ -48,8 +48,7 @@ Array.prototype.forEach.call(atags, function (aEle) {
post({ href, data }); post({ href, data });
return data; return data;
}) })
// eslint-disable-next-line no-console .catch( (error) => console.error(error));
.catch( (error) => console.log(error));
} }
return false; return false;
}); });

View File

@ -82,14 +82,6 @@ export default {
} }
}); });
/*
// Make sure shape uses absolute values
if ((/[a-z]/).test(currentD)) {
currentD = curLib.data[curShapeId] = canv.pathActions.convertPath(curShape);
curShape.setAttribute('d', currentD);
canv.pathActions.fixEnd(curShape);
}
*/
curShape.setAttribute('transform', 'translate(' + x + ',' + y + ') scale(0.005) translate(' + -x + ',' + -y + ')'); curShape.setAttribute('transform', 'translate(' + x + ',' + y + ') scale(0.005) translate(' + -x + ',' + -y + ')');
canv.recalculateDimensions(curShape); canv.recalculateDimensions(curShape);

View File

@ -11,7 +11,7 @@ class LayersPanel {
* @param {PlainObject} editor * @param {PlainObject} editor
*/ */
constructor(editor) { constructor(editor) {
this.updateContextPanel = editor.topPanel.updateContextPanel; this.updateContextPanel = editor.topPanel.updateContextPanel.bind(editor.topPanel);
this.editor = editor; this.editor = editor;
} }

View File

@ -782,8 +782,7 @@ class TopPanel {
editor.svgCanvas.setMode('select'); editor.svgCanvas.setMode('select');
editor.svgCanvas.selectOnly(editor.svgCanvas.getSelectedElems(), true); editor.svgCanvas.selectOnly(editor.svgCanvas.getSelectedElems(), true);
}, (error) => { }, (error) => {
// eslint-disable-next-line no-console console.error("error =", error);
console.log("error =", error);
seAlert(editor.i18next.t('tools.no_embed')); seAlert(editor.i18next.t('tools.no_embed'));
editor.svgCanvas.deleteSelectedElements(); editor.svgCanvas.deleteSelectedElements();
}); });

View File

@ -44,7 +44,6 @@ export const setBlurNoUndo = function (val) {
blurContext_.changeSelectedAttributeNoUndoMethod('filter', 'url(#' + elem.id + '_blur)'); blurContext_.changeSelectedAttributeNoUndoMethod('filter', 'url(#' + elem.id + '_blur)');
} }
if (blurContext_.isWebkit()) { if (blurContext_.isWebkit()) {
// console.log('e', elem);
elem.removeAttribute('filter'); elem.removeAttribute('filter');
elem.setAttribute('filter', 'url(#' + elem.id + '_blur)'); elem.setAttribute('filter', 'url(#' + elem.id + '_blur)');
} }

View File

@ -1,5 +1,3 @@
import { isWebkit } from '../common/browser.js';
import { convertPath } from './path.js';
import { preventClickDefault } from './utilities.js'; import { preventClickDefault } from './utilities.js';
/** /**
@ -19,13 +17,6 @@ export const copyElem = function (el, getNextId) {
newEl.removeAttribute('id'); newEl.removeAttribute('id');
newEl.id = getNextId(); newEl.id = getNextId();
// Opera's "d" value needs to be reset for Opera/Win/non-EN
// Also needed for webkit (else does not keep curved segments on clone)
if (isWebkit() && el.nodeName === 'path') {
const fixedD = convertPath(el);
newEl.setAttribute('d', fixedD);
}
// now create copies of all children // now create copies of all children
el.childNodes.forEach(function(child){ el.childNodes.forEach(function(child){
switch (child.nodeType) { switch (child.nodeType) {

View File

@ -17,9 +17,6 @@ import {
assignAttributes, getElem, getRotationAngle, snapToGrid, isNullish, assignAttributes, getElem, getRotationAngle, snapToGrid, isNullish,
getBBox as utilsGetBBox getBBox as utilsGetBBox
} from './utilities.js'; } from './utilities.js';
import {
isWebkit
} from '../common/browser.js';
let pathActionsContext_ = null; let pathActionsContext_ = null;
let editorContext_ = null; let editorContext_ = null;
@ -61,22 +58,24 @@ export const convertPath = function (pth, toRel) {
let x2 = seg.x2 || 0; let x2 = seg.x2 || 0;
let y2 = seg.y2 || 0; let y2 = seg.y2 || 0;
const type = seg.pathSegType; // const type = seg.pathSegType;
const pathMap = pathActionsContext_.getPathMap(); // const pathMap = pathActionsContext_.getPathMap();
let letter = pathMap[type][toRel ? 'toLowerCase' : 'toUpperCase'](); // let letter = pathMap[type][toRel ? 'toLowerCase' : 'toUpperCase']();
let letter = seg.pathSegTypeAsLetter;
switch (type) { switch (letter) {
case 1: // z,Z closepath (Z/z) case 'z': // z,Z closepath (Z/z)
case 'Z':
d += 'z'; d += 'z';
if (lastM && !toRel) { if (lastM && !toRel) {
curx = lastM[0]; curx = lastM[0];
cury = lastM[1]; cury = lastM[1];
} }
break; break;
case 12: // absolute horizontal line (H) case 'H': // absolute horizontal line (H)
x -= curx; x -= curx;
// Fallthrough // Fallthrough
case 13: // relative horizontal line (h) case 'h': // relative horizontal line (h)
if (toRel) { if (toRel) {
y = 0; y = 0;
curx += x; curx += x;
@ -90,10 +89,10 @@ export const convertPath = function (pth, toRel) {
// Convert to "line" for easier editing // Convert to "line" for easier editing
d += pathDSegment(letter, [ [ x, y ] ]); d += pathDSegment(letter, [ [ x, y ] ]);
break; break;
case 14: // absolute vertical line (V) case 'V': // absolute vertical line (V)
y -= cury; y -= cury;
// Fallthrough // Fallthrough
case 15: // relative vertical line (v) case 'v': // relative vertical line (v)
if (toRel) { if (toRel) {
x = 0; x = 0;
cury += y; cury += y;
@ -107,71 +106,81 @@ export const convertPath = function (pth, toRel) {
// Convert to "line" for easier editing // Convert to "line" for easier editing
d += pathDSegment(letter, [ [ x, y ] ]); d += pathDSegment(letter, [ [ x, y ] ]);
break; break;
case 2: // absolute move (M) case 'M': // absolute move (M)
case 4: // absolute line (L) case 'L': // absolute line (L)
case 18: // absolute smooth quad (T) case 'T': // absolute smooth quad (T)
case 10: // absolute elliptical arc (A)
x -= curx; x -= curx;
y -= cury; y -= cury;
// Fallthrough // Fallthrough
case 5: // relative line (l) case 'l': // relative line (l)
case 3: // relative move (m) case 'm': // relative move (m)
case 19: // relative smooth quad (t) case 't': // relative smooth quad (t)
if (toRel) { if (toRel) {
curx += x; curx += x;
cury += y; cury += y;
letter = letter.toLowerCase();
} else { } else {
x += curx; x += curx;
y += cury; y += cury;
curx = x; curx = x;
cury = y; cury = y;
letter = letter.toUpperCase();
} }
if (type === 2 || type === 3) { lastM = [ curx, cury ]; } if (letter === 'm' || letter === 'M') { lastM = [ curx, cury ]; }
d += pathDSegment(letter, [ [ x, y ] ]); d += pathDSegment(letter, [ [ x, y ] ]);
break; break;
case 6: // absolute cubic (C) case 'C': // absolute cubic (C)
x -= curx; x1 -= curx; x2 -= curx; x -= curx; x1 -= curx; x2 -= curx;
y -= cury; y1 -= cury; y2 -= cury; y -= cury; y1 -= cury; y2 -= cury;
// Fallthrough // Fallthrough
case 7: // relative cubic (c) case 'c': // relative cubic (c)
if (toRel) { if (toRel) {
curx += x; curx += x;
cury += y; cury += y;
letter = 'c';
} else { } else {
x += curx; x1 += curx; x2 += curx; x += curx; x1 += curx; x2 += curx;
y += cury; y1 += cury; y2 += cury; y += cury; y1 += cury; y2 += cury;
curx = x; curx = x;
cury = y; cury = y;
letter = 'C';
} }
d += pathDSegment(letter, [ [ x1, y1 ], [ x2, y2 ], [ x, y ] ]); d += pathDSegment(letter, [ [ x1, y1 ], [ x2, y2 ], [ x, y ] ]);
break; break;
case 8: // absolute quad (Q) case 'Q': // absolute quad (Q)
x -= curx; x1 -= curx; x -= curx; x1 -= curx;
y -= cury; y1 -= cury; y -= cury; y1 -= cury;
// Fallthrough // Fallthrough
case 9: // relative quad (q) case 'q': // relative quad (q)
if (toRel) { if (toRel) {
curx += x; curx += x;
cury += y; cury += y;
letter = 'q';
} else { } else {
x += curx; x1 += curx; x += curx; x1 += curx;
y += cury; y1 += cury; y += cury; y1 += cury;
curx = x; curx = x;
cury = y; cury = y;
letter = 'Q';
} }
d += pathDSegment(letter, [ [ x1, y1 ], [ x, y ] ]); d += pathDSegment(letter, [ [ x1, y1 ], [ x, y ] ]);
break; break;
// Fallthrough case 'A':
case 11: // relative elliptical arc (a) x -= curx;
y -= cury;
// fallthrough
case 'a': // relative elliptical arc (a)
if (toRel) { if (toRel) {
curx += x; curx += x;
cury += y; cury += y;
letter = 'a';
} else { } else {
x += curx; x += curx;
y += cury; y += cury;
curx = x; curx = x;
cury = y; cury = y;
letter = 'A';
} }
d += pathDSegment(letter, [ [ seg.r1, seg.r2 ] ], [ d += pathDSegment(letter, [ [ seg.r1, seg.r2 ] ], [
seg.angle, seg.angle,
@ -179,19 +188,21 @@ export const convertPath = function (pth, toRel) {
(seg.sweepFlag ? 1 : 0) (seg.sweepFlag ? 1 : 0)
], [ x, y ]); ], [ x, y ]);
break; break;
case 16: // absolute smooth cubic (S) case 'S': // absolute smooth cubic (S)
x -= curx; x2 -= curx; x -= curx; x2 -= curx;
y -= cury; y2 -= cury; y -= cury; y2 -= cury;
// Fallthrough // Fallthrough
case 17: // relative smooth cubic (s) case 's': // relative smooth cubic (s)
if (toRel) { if (toRel) {
curx += x; curx += x;
cury += y; cury += y;
letter = 's';
} else { } else {
x += curx; x2 += curx; x += curx; x2 += curx;
y += cury; y2 += cury; y += cury; y2 += cury;
curx = x; curx = x;
cury = y; cury = y;
letter = 'S';
} }
d += pathDSegment(letter, [ [ x2, y2 ], [ x, y ] ]); d += pathDSegment(letter, [ [ x2, y2 ], [ x, y ] ]);
break; break;
@ -1027,8 +1038,8 @@ export const pathActionsMethod = (function () {
list.appendItem(newseg); list.appendItem(newseg);
list.appendItem(closer); list.appendItem(closer);
} else { } else {
pathActionsContext_.insertItemBefore(elem, closer, openPt); list.insertItemBefore(closer, openPt);
pathActionsContext_.insertItemBefore(elem, newseg, openPt); list.insertItemBefore(newseg, openPt);
} }
path.init().selectPt(openPt + 1); path.init().selectPt(openPt + 1);
@ -1074,7 +1085,7 @@ export const pathActionsMethod = (function () {
let num = (index - lastM) - 1; let num = (index - lastM) - 1;
while (num--) { while (num--) {
pathActionsContext_.insertItemBefore(elem, list.getItem(lastM), zSeg); list.insertItemBefore(list.getItem(lastM), zSeg);
} }
const pt = list.getItem(lastM); const pt = list.getItem(lastM);
@ -1213,24 +1224,22 @@ export const pathActionsMethod = (function () {
let lastM; let lastM;
for (let i = 0; i < len; ++i) { for (let i = 0; i < len; ++i) {
const item = segList.getItem(i); const item = segList.getItem(i);
if (item.pathSegType === 2) { if (item.pathSegType === 2) { // 2 => M segment type (move to)
lastM = item; lastM = item;
} }
if (item.pathSegType === 1) { if (item.pathSegType === 1) { // 1 => Z segment type (close path)
const prev = segList.getItem(i - 1); const prev = segList.getItem(i - 1);
if (prev.x !== lastM.x || prev.y !== lastM.y) { if (prev.x !== lastM.x || prev.y !== lastM.y) {
// Add an L segment here // Add an L segment here
const newseg = elem.createSVGPathSegLinetoAbs(lastM.x, lastM.y); const newseg = elem.createSVGPathSegLinetoAbs(lastM.x, lastM.y);
pathActionsContext_.insertItemBefore(elem, newseg, i); segList.insertItemBefore(newseg, i);
// Can this be done better? // Can this be done better?
pathActionsMethod.fixEnd(elem); pathActionsMethod.fixEnd(elem);
break; break;
} }
} }
} }
editorContext_ = pathActionsContext_.getEditorContext();
if (isWebkit()) { editorContext_.resetD(elem); }
}, },
// Can't seem to use `@borrows` here, so using `@see` // Can't seem to use `@borrows` here, so using `@see`
/** /**

View File

@ -15,9 +15,6 @@ import {
assignAttributes, getRotationAngle, isNullish, assignAttributes, getRotationAngle, isNullish,
getElem getElem
} from './utilities.js'; } from './utilities.js';
import {
supportsPathInsertItemBefore, supportsPathReplaceItem, isWebkit
} from '../common/browser.js';
let pathMethodsContext_ = null; let pathMethodsContext_ = null;
let editorContext_ = null; let editorContext_ = null;
@ -31,35 +28,6 @@ export const init = function (pathMethodsContext) {
pathMethodsContext_ = pathMethodsContext; pathMethodsContext_ = pathMethodsContext;
}; };
/**
* @function module:path.insertItemBefore
* @param {Element} elem
* @param {Segment} newseg
* @param {Integer} index
* @returns {void}
*/
export const insertItemBeforeMethod = function (elem, newseg, index) {
// Support insertItemBefore on paths for FF2
const list = elem.pathSegList;
if (supportsPathInsertItemBefore()) {
list.insertItemBefore(newseg, index);
return;
}
const len = list.numberOfItems;
const arr = [];
for (let i = 0; i < len; i++) {
const curSeg = list.getItem(i);
arr.push(curSeg);
}
list.clear();
for (let i = 0; i < len; i++) {
if (i === index) { // index + 1
list.appendItem(newseg);
}
list.appendItem(arr[i]);
}
};
/* eslint-disable max-len */ /* eslint-disable max-len */
/** /**
* @function module:path.ptObjToArr * @function module:path.ptObjToArr
@ -324,25 +292,7 @@ export const replacePathSegMethod = function (type, index, pts, elem) {
const func = 'createSVGPathSeg' + pathFuncs[type]; const func = 'createSVGPathSeg' + pathFuncs[type];
const seg = pth[func](...pts); const seg = pth[func](...pts);
if (supportsPathReplaceItem()) { pth.pathSegList.replaceItem(seg, index);
pth.pathSegList.replaceItem(seg, index);
} else {
const segList = pth.pathSegList;
const len = segList.numberOfItems;
const arr = [];
for (let i = 0; i < len; i++) {
const curSeg = segList.getItem(i);
arr.push(curSeg);
}
segList.clear();
for (let i = 0; i < len; i++) {
if (i === index) {
segList.appendItem(seg);
} else {
segList.appendItem(arr[i]);
}
}
}
}; };
/** /**
* @function module:path.getSegSelector * @function module:path.getSegSelector
@ -775,8 +725,8 @@ export class Path {
break; break;
} }
} }
const list = this.elem.pathSegList;
insertItemBeforeMethod(this.elem, newseg, index); list.insertItemBefore(newseg, index);
} }
/** /**
@ -1005,7 +955,6 @@ export class Path {
* @returns {void} * @returns {void}
*/ */
endChanges (text) { endChanges (text) {
if (isWebkit()) { editorContext_.resetD(this.elem); }
const cmd = new ChangeElementCommand(this.elem, { d: this.last_d }, text); const cmd = new ChangeElementCommand(this.elem, { d: this.last_d }, text);
editorContext_.endChanges({ cmd, elem: this.elem }); editorContext_.endChanges({ cmd, elem: this.elem });
} }

View File

@ -14,7 +14,7 @@ import {
getBBox as utilsGetBBox getBBox as utilsGetBBox
} from './utilities.js'; } from './utilities.js';
import { import {
init as pathMethodInit, insertItemBeforeMethod, ptObjToArrMethod, getGripPtMethod, init as pathMethodInit, ptObjToArrMethod, getGripPtMethod,
getPointFromGripMethod, addPointGripMethod, getGripContainerMethod, addCtrlGripMethod, getPointFromGripMethod, addPointGripMethod, getGripContainerMethod, addCtrlGripMethod,
getCtrlLineMethod, getPointGripMethod, getControlPointsMethod, replacePathSegMethod, getCtrlLineMethod, getPointGripMethod, getControlPointsMethod, replacePathSegMethod,
getSegSelectorMethod, Path getSegSelectorMethod, Path
@ -103,11 +103,6 @@ let editorContext_ = null;
* If the event is "changed", an array of `Element`s is passed; if "selected", a single-item array of `Element` is passed. * If the event is "changed", an array of `Element`s is passed; if "selected", a single-item array of `Element` is passed.
* @returns {void} * @returns {void}
*/ */
/**
* @function module:path.EditorContext#resetD
* @param {SVGPathElement} p
* @returns {void}
*/
/** /**
* Note: This doesn't round to an integer necessarily. * Note: This doesn't round to an integer necessarily.
* @function module:path.EditorContext#round * @function module:path.EditorContext#round
@ -263,14 +258,6 @@ pathMethodInit(
} }
); );
/**
* @function module:path.insertItemBefore
* @param {Element} elem
* @param {Segment} newseg
* @param {Integer} index
* @returns {void}
*/
export const insertItemBefore = insertItemBeforeMethod;
/* eslint-disable max-len */ /* eslint-disable max-len */
/** /**
* @function module:path.ptObjToArr * @function module:path.ptObjToArr
@ -801,7 +788,6 @@ pathActionsInit(
addCtrlGrip, addCtrlGrip,
getCtrlLine, getCtrlLine,
replacePathSeg, replacePathSeg,
insertItemBefore,
getPointFromGrip, getPointFromGrip,
getGripPt, getGripPt,
getPath_, getPath_,

View File

@ -324,12 +324,14 @@ export const groupSvgElem = function (elem) {
* @returns {void} * @returns {void}
*/ */
export const prepareSvg = function (newDoc) { export const prepareSvg = function (newDoc) {
svgCanvas.sanitizeSvg(newDoc.documentElement); svgCanvas.sanitizeSvg(newDoc.documentElement);
// convert paths into absolute commands // convert paths into absolute commands
const paths = [ ...newDoc.getElementsByTagNameNS(NS.SVG, 'path') ]; const paths = [ ...newDoc.getElementsByTagNameNS(NS.SVG, 'path') ];
paths.forEach((path) => { paths.forEach((path) => {
path.setAttribute('d', svgCanvas.pathActions.convertPath(path)); const convertedPath = svgCanvas.pathActions.convertPath(path);
path.setAttribute('d', convertedPath);
svgCanvas.pathActions.fixEnd(path); svgCanvas.pathActions.fixEnd(path);
}); });
}; };

View File

@ -9,7 +9,7 @@
*/ */
import { Canvg as canvg } from 'canvg'; import { Canvg as canvg } from 'canvg';
import 'pathseg'; import 'pathseg'; // SVGPathSeg Polyfill (see https://github.com/progers/pathseg)
import * as pathModule from './path.js'; import * as pathModule from './path.js';
import * as hstry from './history.js'; import * as hstry from './history.js';
@ -668,16 +668,6 @@ class SvgCanvas {
* @see module:path.pathActions * @see module:path.pathActions
*/ */
canvas.pathActions = pathActions; canvas.pathActions = pathActions;
/**
* @type {module:path.EditorContext#resetD}
*/
function resetD(p) {
if (typeof pathActions.convertPath === 'function') {
p.setAttribute('d', pathActions.convertPath(p));
} else if (typeof pathActions.convertPaths === 'function') {
p.setAttribute('d', pathActions.convertPaths(p));
}
}
pathModule.init( pathModule.init(
/** /**
* @implements {module:path.EditorContext} * @implements {module:path.EditorContext}
@ -686,7 +676,6 @@ class SvgCanvas {
selectorManager, // Ok since not changing selectorManager, // Ok since not changing
canvas, // Ok since not changing canvas, // Ok since not changing
call, call,
resetD,
round, round,
clearSelection, clearSelection,
addToSelection, addToSelection,

View File

@ -12,13 +12,10 @@ import {
hasMatrixTransform, transformListToTransform, transformBox hasMatrixTransform, transformListToTransform, transformBox
} from './math.js'; } from './math.js';
import { import {
isWebkit, supportsHVLineContainerBBox, supportsPathBBox isWebkit, supportsHVLineContainerBBox
} from '../common/browser.js'; } from '../common/browser.js';
import { getClosest, mergeDeep } from '../editor/components/jgraduate/Util.js'; import { getClosest, mergeDeep } from '../editor/components/jgraduate/Util.js';
// String used to encode base64.
const KEYSTR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
// Much faster than running getBBox() every time // Much faster than running getBBox() every time
const visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use,clipPath'; const visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use,clipPath';
const visElemsArr = visElems.split(','); const visElemsArr = visElems.split(',');
@ -137,41 +134,7 @@ export const toXml = function (str) {
export function encode64(input) { export function encode64(input) {
// base64 strings are 4/3 larger than the original string // base64 strings are 4/3 larger than the original string
input = encodeUTF8(input); // convert non-ASCII characters input = encodeUTF8(input); // convert non-ASCII characters
// input = convertToXMLReferences(input); return window.btoa(input); // Use native if available
if (window.btoa) {
return window.btoa(input); // Use native if available
}
const output = new Array(Math.floor((input.length + 2) / 3) * 4);
let i = 0;
let p = 0;
do {
const chr1 = input.charCodeAt(i++);
const chr2 = input.charCodeAt(i++);
const chr3 = input.charCodeAt(i++);
/* eslint-disable no-bitwise */
const enc1 = chr1 >> 2;
const enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
let enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
let enc4 = chr3 & 63;
/* eslint-enable no-bitwise */
if (Number.isNaN(chr2)) {
enc3 = 64;
enc4 = 64;
} else if (Number.isNaN(chr3)) {
enc4 = 64;
}
output[p++] = KEYSTR.charAt(enc1);
output[p++] = KEYSTR.charAt(enc2);
output[p++] = KEYSTR.charAt(enc3);
output[p++] = KEYSTR.charAt(enc4);
} while (i < input.length);
return output.join('');
} }
/** /**
@ -181,38 +144,7 @@ export function encode64(input) {
* @returns {string} Decoded output * @returns {string} Decoded output
*/ */
export function decode64(input) { export function decode64(input) {
if (window.atob) { return decodeUTF8(window.atob(input));
return decodeUTF8(window.atob(input));
}
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
input = input.replace(/[^A-Za-z\d+/=]/g, '');
let output = '';
let i = 0;
do {
const enc1 = KEYSTR.indexOf(input.charAt(i++));
const enc2 = KEYSTR.indexOf(input.charAt(i++));
const enc3 = KEYSTR.indexOf(input.charAt(i++));
const enc4 = KEYSTR.indexOf(input.charAt(i++));
/* eslint-disable no-bitwise */
const chr1 = (enc1 << 2) | (enc2 >> 4);
const chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
const chr3 = ((enc3 & 3) << 6) | enc4;
/* eslint-enable no-bitwise */
output += String.fromCharCode(chr1);
if (enc3 !== 64) {
output += String.fromCharCode(chr2);
}
if (enc4 !== 64) {
output += String.fromCharCode(chr3);
}
} while (i < input.length);
return decodeUTF8(output);
} }
/** /**
@ -315,17 +247,13 @@ export const text2xml = function (sXML) {
let out; let dXML; let out; let dXML;
try { try {
dXML = (window.DOMParser) ? new DOMParser() : new window.ActiveXObject('Microsoft.XMLDOM'); dXML = new DOMParser();
dXML.async = false; dXML.async = false;
} catch (e) { } catch (e) {
throw new Error('XML Parser could not be instantiated'); throw new Error('XML Parser could not be instantiated');
} }
try { try {
if (dXML.loadXML) { out = dXML.parseFromString(sXML, 'text/xml');
out = (dXML.loadXML(sXML)) ? dXML : false;
} else {
out = dXML.parseFromString(sXML, 'text/xml');
}
} catch (e2) { throw new Error('Error parsing XML string'); } } catch (e2) { throw new Error('Error parsing XML string'); }
return out; return out;
}; };
@ -618,9 +546,7 @@ export const getBBox = function (elem) {
} }
break; break;
case 'path': case 'path':
if (!supportsPathBBox()) { if (selected.getBBox) {
ret = getPathBBox(selected);
} else if (selected.getBBox) {
ret = selected.getBBox(); ret = selected.getBBox();
} }
break; break;