From b10f4be943a930587a139a7a017f76030e1d3729 Mon Sep 17 00:00:00 2001 From: JFH <20402845+jfhenon@users.noreply.github.com> Date: Sat, 1 Jan 2022 09:27:35 -0300 Subject: [PATCH 1/7] move was not properly handling when a transform was already on the element --- src/svgcanvas/event.js | 197 ++++++++++++++++++++++------------------- 1 file changed, 106 insertions(+), 91 deletions(-) diff --git a/src/svgcanvas/event.js b/src/svgcanvas/event.js index 339ab7bf..9f76d650 100644 --- a/src/svgcanvas/event.js +++ b/src/svgcanvas/event.js @@ -34,7 +34,7 @@ export const init = (canvas) => { svgCanvas = canvas } -export const getBsplinePoint = (t) => { +const getBsplinePoint = (t) => { const spline = { x: 0, y: 0 } const p0 = { x: svgCanvas.getControllPoint2('x'), y: svgCanvas.getControllPoint2('y') } const p1 = { x: svgCanvas.getControllPoint1('x'), y: svgCanvas.getControllPoint1('y') } @@ -70,6 +70,25 @@ export const getBsplinePoint = (t) => { } } +// update the dummy transform in our transform list +// to be a translate. We need to check if there was a transformation +// to avoid loosing it +const updateTransformList = (svgRoot, element, dx, dy) => { + const xform = svgRoot.createSVGTransform() + xform.setTranslate(dx, dy) + const tlist = element.transform?.baseVal + if (tlist.numberOfItems) { + const firstItem = tlist.getItem(0) + if (firstItem.type === 2) { // SVG_TRANSFORM_TRANSLATE = 2 + tlist.replaceItem(xform, 0) + } else { + tlist.insertItemBefore(xform, 0) + } + } else { + tlist.appendItem(xform) + } +} + /** * * @param {MouseEvent} evt @@ -78,12 +97,16 @@ export const getBsplinePoint = (t) => { * @returns {void} */ export const mouseMoveEvent = (evt) => { + // if the mouse is move without dragging an element, just return. + if (!svgCanvas.getStarted()) { return } + if (evt.button === 1 || svgCanvas.spaceKey) { return } + + evt.preventDefault() + const selectedElements = svgCanvas.getSelectedElements() const zoom = svgCanvas.getZoom() const svgRoot = svgCanvas.getSvgRoot() - - if (!svgCanvas.getStarted()) { return } - if (evt.button === 1 || svgCanvas.spaceKey) { return } + const selected = selectedElements[0] let i let xya @@ -94,7 +117,7 @@ export const mouseMoveEvent = (evt) => { let len let angle let box - let selected = selectedElements[0] + const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm()) const mouseX = pt.x * zoom const mouseY = pt.y * zoom @@ -110,14 +133,13 @@ export const mouseMoveEvent = (evt) => { y = snapToGrid(y) } - evt.preventDefault() let tlist switch (svgCanvas.getCurrentMode()) { case 'select': { - // we temporarily use a translate on the element(s) being dragged - // this transform is removed upon mousing up and the element is - // relocated to the new location - if (selectedElements[0] !== null) { + // we temporarily use a translate on the element(s) being dragged + // this transform is removed upon mousing up and the element is + // relocated to the new location + if (selected) { dx = x - svgCanvas.getStartX() dy = y - svgCanvas.getStartY() if (svgCanvas.getCurConfig().gridSnapping) { @@ -125,35 +147,20 @@ export const mouseMoveEvent = (evt) => { dy = snapToGrid(dy) } - if (dx !== 0 || dy !== 0) { - len = selectedElements.length - for (i = 0; i < len; ++i) { - selected = selectedElements[i] - if (isNullish(selected)) { break } - // update the dummy transform in our transform list - // to be a translate - const xform = svgRoot.createSVGTransform() - tlist = selected.transform?.baseVal - // Note that if Webkit and there's no ID for this - // element, the dummy transform may have gotten lost. - // This results in unexpected behaviour - - xform.setTranslate(dx, dy) - if (tlist.numberOfItems) { - tlist.replaceItem(xform, 0) - } else { - tlist.appendItem(xform) + if (dx || dy) { + selectedElements.forEach((el) => { + if (el) { + updateTransformList(svgRoot, el, dx, dy) + // update our internal bbox that we're tracking while dragging + svgCanvas.selectorManager.requestSelector(el).resize() } - - // update our internal bbox that we're tracking while dragging - svgCanvas.selectorManager.requestSelector(selected).resize() - } - + }) svgCanvas.call('transition', selectedElements) } } break - } case 'multiselect': { + } + case 'multiselect': { realX *= zoom realY *= zoom assignAttributes(svgCanvas.getRubberBox(), { @@ -194,10 +201,11 @@ export const mouseMoveEvent = (evt) => { } break - } case 'resize': { - // we track the resize bounding box and translate/scale the selected element - // while the mouse is down, when mouse goes up, we use this to recalculate - // the shape's coordinates + } + case 'resize': { + // we track the resize bounding box and translate/scale the selected element + // while the mouse is down, when mouse goes up, we use this to recalculate + // the shape's coordinates tlist = selected.transform.baseVal const hasMatrix = hasMatrixTransform(tlist) box = hasMatrix ? svgCanvas.getInitBbox() : getBBox(selected) @@ -285,7 +293,8 @@ export const mouseMoveEvent = (evt) => { svgCanvas.call('transition', selectedElements) break - } case 'zoom': { + } + case 'zoom': { realX *= zoom realY *= zoom assignAttributes(svgCanvas.getRubberBox(), { @@ -295,13 +304,15 @@ export const mouseMoveEvent = (evt) => { height: Math.abs(realY - svgCanvas.getRStartY() * zoom) }, 100) break - } case 'text': { + } + case 'text': { assignAttributes(shape, { x, y }, 1000) break - } case 'line': { + } + case 'line': { if (svgCanvas.getCurConfig().gridSnapping) { x = snapToGrid(x) y = snapToGrid(y) @@ -319,12 +330,10 @@ export const mouseMoveEvent = (evt) => { shape.setAttribute('x2', x2) shape.setAttribute('y2', y2) break - } case 'foreignObject': - // fall through + } + case 'foreignObject': // fall through case 'square': - // fall through case 'rect': - // fall through case 'image': { const square = (svgCanvas.getCurrentMode() === 'square') || evt.shiftKey let @@ -355,7 +364,8 @@ export const mouseMoveEvent = (evt) => { }, 1000) break - } case 'circle': { + } + case 'circle': { cx = Number(shape.getAttribute('cx')) cy = Number(shape.getAttribute('cy')) let rad = Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)) @@ -364,7 +374,8 @@ export const mouseMoveEvent = (evt) => { } shape.setAttribute('r', rad) break - } case 'ellipse': { + } + case 'ellipse': { cx = Number(shape.getAttribute('cx')) cy = Number(shape.getAttribute('cy')) if (svgCanvas.getCurConfig().gridSnapping) { @@ -387,8 +398,8 @@ export const mouseMoveEvent = (evt) => { } // Fallthrough case 'fhpath': { - // dAttr += + realX + ',' + realY + ' '; - // shape.setAttribute('points', dAttr); + // dAttr += + realX + ',' + realY + ' '; + // shape.setAttribute('points', dAttr); svgCanvas.setEnd('x', realX) svgCanvas.setEnd('y', realY) if (svgCanvas.getControllPoint2('x') && svgCanvas.getControllPoint2('y')) { @@ -421,9 +432,9 @@ export const mouseMoveEvent = (evt) => { svgCanvas.setControllPoint1('y', svgCanvas.getStart('y')) svgCanvas.setStart({ x: svgCanvas.getEnd('x'), y: svgCanvas.getEnd('y') }) break - // update path stretch line coordinates - } case 'path': - // fall through + // update path stretch line coordinates + } + case 'path': // fall through case 'pathedit': { x *= zoom y *= zoom @@ -461,7 +472,8 @@ export const mouseMoveEvent = (evt) => { svgCanvas.pathActions.mouseMove(x, y) break - } case 'textedit': { + } + case 'textedit': { x *= zoom y *= zoom // if (svgCanvas.getRubberBox() && svgCanvas.getRubberBox().getAttribute('display') !== 'none') { @@ -476,7 +488,8 @@ export const mouseMoveEvent = (evt) => { svgCanvas.textActions.mouseMove(mouseX, mouseY) break - } case 'rotate': { + } + case 'rotate': { box = getBBox(selected) cx = box.x + box.width / 2 cy = box.y + box.height / 2 @@ -496,19 +509,21 @@ export const mouseMoveEvent = (evt) => { svgCanvas.setRotationAngle(angle < -180 ? (360 + angle) : angle, true) svgCanvas.call('transition', selectedElements) break - } default: + } + default: + console.error(`unknown mode=${svgCanvas.getCurrentMode()}`) break } /** -* The mouse has moved on the canvas area. -* @event module:svgcanvas.SvgCanvas#event:ext_mouseMove -* @type {PlainObject} -* @property {MouseEvent} event The event object -* @property {Float} mouse_x x coordinate on canvas -* @property {Float} mouse_y y coordinate on canvas -* @property {Element} selected Refers to the first selected element -*/ + * The mouse has moved on the canvas area. + * @event module:svgcanvas.SvgCanvas#event:ext_mouseMove + * @type {PlainObject} + * @property {MouseEvent} event The event object + * @property {Float} mouse_x x coordinate on canvas + * @property {Float} mouse_y y coordinate on canvas + * @property {Element} selected Refers to the first selected element + */ svgCanvas.runExtensions('mouseMove', /** @type {module:svgcanvas.SvgCanvas#event:ext_mouseMove} */ { event: evt, mouse_x: mouseX, @@ -543,12 +558,13 @@ export const mouseOutEvent = () => { * @returns {void} */ export const mouseUpEvent = (evt) => { + if (evt.button === 2) { return } + if (!svgCanvas.getStarted()) { return } + const selectedElements = svgCanvas.getSelectedElements() const zoom = svgCanvas.getZoom() - if (evt.button === 2) { return } const tempJustSelected = svgCanvas.getJustSelected() svgCanvas.setJustSelected(null) - if (!svgCanvas.getStarted()) { return } const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm()) const mouseX = pt.x * zoom const mouseY = pt.y * zoom @@ -566,7 +582,7 @@ export const mouseUpEvent = (evt) => { svgCanvas.setStarted(false) let t switch (svgCanvas.getCurrentMode()) { - // intentionally fall-through to select here + // intentionally fall-through to select here case 'resize': case 'multiselect': if (svgCanvas.getRubberBox()) { @@ -577,9 +593,9 @@ export const mouseUpEvent = (evt) => { // Fallthrough case 'select': if (selectedElements[0]) { - // if we only have one selected element + // if we only have one selected element if (!selectedElements[1]) { - // set our current stroke/fill properties to the element's + // set our current stroke/fill properties to the element's const selected = selectedElements[0] switch (selected.tagName) { case 'g': @@ -587,6 +603,10 @@ export const mouseUpEvent = (evt) => { case 'image': case 'foreignObject': break + case 'text': + svgCanvas.setCurText('font_size', selected.getAttribute('font-size')) + svgCanvas.setCurText('font_family', selected.getAttribute('font-family')) + // fallthrough default: svgCanvas.setCurProperties('fill', selected.getAttribute('fill')) svgCanvas.setCurProperties('fill_opacity', selected.getAttribute('fill-opacity')) @@ -597,11 +617,6 @@ export const mouseUpEvent = (evt) => { svgCanvas.setCurProperties('stroke_linejoin', selected.getAttribute('stroke-linejoin')) svgCanvas.setCurProperties('stroke_linecap', selected.getAttribute('stroke-linecap')) } - - if (selected.tagName === 'text') { - svgCanvas.setCurText('font_size', selected.getAttribute('font-size')) - svgCanvas.setCurText('font_family', selected.getAttribute('font-family')) - } svgCanvas.selectorManager.requestSelector(selected).showGrips(true) } // always recalculate dimensions to strip off stray identity transforms @@ -612,13 +627,13 @@ export const mouseUpEvent = (evt) => { for (let i = 0; i < len; ++i) { if (isNullish(selectedElements[i])) { break } } - // no change in position/size, so maybe we should move to pathedit + // no change in position/size, so maybe we should move to pathedit } else { t = evt.target if (selectedElements[0].nodeName === 'path' && isNullish(selectedElements[1])) { svgCanvas.pathActions.select(selectedElements[0]) - // if it was a path - // else, if it was selected and this is a shift-click, remove it from selection + // if it was a path + // else, if it was selected and this is a shift-click, remove it from selection } else if (evt.shiftKey && tempJustSelected !== t) { svgCanvas.removeFromSelection([t]) } @@ -648,10 +663,10 @@ export const mouseUpEvent = (evt) => { }) return } case 'fhpath': { - // Check that the path contains at least 2 points; a degenerate one-point path - // causes problems. - // Webkit ignores how we set the points attribute with commas and uses space - // to separate all coordinates, see https://bugs.webkit.org/show_bug.cgi?id=29870 + // Check that the path contains at least 2 points; a degenerate one-point path + // causes problems. + // Webkit ignores how we set the points attribute with commas and uses space + // to separate all coordinates, see https://bugs.webkit.org/show_bug.cgi?id=29870 svgCanvas.setSumDistance(0) svgCanvas.setControllPoint2('x', 0) svgCanvas.setControllPoint2('y', 0) @@ -736,7 +751,7 @@ export const mouseUpEvent = (evt) => { svgCanvas.textActions.start(element) break case 'path': { - // set element to null here so that it is not removed nor finalized + // set element to null here so that it is not removed nor finalized element = null // continue to be set to true so that mouseMove happens svgCanvas.setStarted(true) @@ -768,7 +783,7 @@ export const mouseUpEvent = (evt) => { svgCanvas.call('changed', selectedElements) break } default: - // This could occur in an extension + // This could occur in an extension break } @@ -786,7 +801,7 @@ export const mouseUpEvent = (evt) => { mouse_y: mouseY }, true) - extResult.forEach(function (r) { + extResult.forEach((r) => { if (r) { keep = r.keep || keep; ({ element } = r) @@ -847,7 +862,7 @@ export const mouseUpEvent = (evt) => { // Ideally this would be done on the endEvent of the animation, // but that doesn't seem to be supported in Webkit - setTimeout(function () { + setTimeout(() => { if (cAni) { cAni.remove() } element.setAttribute('opacity', curShape.opacity) element.setAttribute('style', 'pointer-events:inherit') @@ -1003,12 +1018,12 @@ export const mouseDownEvent = (evt) => { if (rightClick) { svgCanvas.setStarted(false) } if (mouseTarget !== svgRoot) { - // if this element is not yet selected, clear selection and select it + // if this element is not yet selected, clear selection and select it if (!selectedElements.includes(mouseTarget)) { - // only clear selection if shift is not pressed (otherwise, add - // element to selection) + // only clear selection if shift is not pressed (otherwise, add + // element to selection) if (!evt.shiftKey) { - // No need to do the call here as it will be done on addToSelection + // No need to do the call here as it will be done on addToSelection svgCanvas.clearSelection(true) } svgCanvas.addToSelection([mouseTarget]) @@ -1018,8 +1033,8 @@ export const mouseDownEvent = (evt) => { // else if it's a path, go into pathedit mode in mouseup if (!rightClick) { - // insert a dummy transform so if the element(s) are moved it will have - // a transform to use for its translate + // insert a dummy transform so if the element(s) are moved it will have + // a transform to use for its translate for (const selectedElement of selectedElements) { if (isNullish(selectedElement)) { continue } const slist = selectedElement.transform?.baseVal @@ -1250,7 +1265,7 @@ export const mouseDownEvent = (evt) => { svgCanvas.undoMgr.beginUndoableChange('transform', selectedElements) break default: - // This could occur in an extension + // This could occur in an extension break } From 82fab95988dadaeb1a832c699a56483c46183821 Mon Sep 17 00:00:00 2001 From: JFH <20402845+jfhenon@users.noreply.github.com> Date: Sat, 1 Jan 2022 09:27:45 -0300 Subject: [PATCH 2/7] minor es6 improvements --- src/svgcanvas/blur-event.js | 2 +- src/svgcanvas/coords.js | 2 +- src/svgcanvas/draw.js | 2 +- src/svgcanvas/elem-get-set.js | 2 +- src/svgcanvas/json.js | 2 +- src/svgcanvas/paste-elem.js | 2 +- src/svgcanvas/path-actions.js | 2 +- src/svgcanvas/path-method.js | 2 +- src/svgcanvas/recalculate.js | 8 ++++---- src/svgcanvas/selected-elem.js | 2 +- src/svgcanvas/selection.js | 26 +++++++++++++------------- src/svgcanvas/svg-exec.js | 2 +- src/svgcanvas/text-actions.js | 2 +- src/svgcanvas/utilities.js | 2 +- 14 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/svgcanvas/blur-event.js b/src/svgcanvas/blur-event.js index 7acda3c9..8cd945f9 100644 --- a/src/svgcanvas/blur-event.js +++ b/src/svgcanvas/blur-event.js @@ -12,7 +12,7 @@ let svgCanvas = null * @param {module:blur.blurContext} blurContext * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas } diff --git a/src/svgcanvas/coords.js b/src/svgcanvas/coords.js index fca06b54..c86bd6d3 100644 --- a/src/svgcanvas/coords.js +++ b/src/svgcanvas/coords.js @@ -36,7 +36,7 @@ let svgCanvas = null * @param {module:svgcanvas.SvgCanvas#event:pointsAdded} editorContext * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas } diff --git a/src/svgcanvas/draw.js b/src/svgcanvas/draw.js index 0e23ea14..997c4963 100644 --- a/src/svgcanvas/draw.js +++ b/src/svgcanvas/draw.js @@ -754,7 +754,7 @@ let svgCanvas * @param {module:draw.DrawCanvasInit} canvas * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas } diff --git a/src/svgcanvas/elem-get-set.js b/src/svgcanvas/elem-get-set.js index 5dd14fcb..854c78bf 100644 --- a/src/svgcanvas/elem-get-set.js +++ b/src/svgcanvas/elem-get-set.js @@ -22,7 +22,7 @@ let svgCanvas = null * @param {module:elem-get-set.elemContext} elemContext * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas } diff --git a/src/svgcanvas/json.js b/src/svgcanvas/json.js index 0c00f05a..3537c9cf 100644 --- a/src/svgcanvas/json.js +++ b/src/svgcanvas/json.js @@ -25,7 +25,7 @@ let svgdoc_ = null * @param {module:json.jsonContext} jsonContext * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas svgdoc_ = canvas.getDOMDocument() } diff --git a/src/svgcanvas/paste-elem.js b/src/svgcanvas/paste-elem.js index f112a48b..8050c61c 100644 --- a/src/svgcanvas/paste-elem.js +++ b/src/svgcanvas/paste-elem.js @@ -14,7 +14,7 @@ let svgCanvas = null * @param {module:paste-elem.pasteContext} pasteContext * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas } diff --git a/src/svgcanvas/path-actions.js b/src/svgcanvas/path-actions.js index b6349392..6deecbb2 100644 --- a/src/svgcanvas/path-actions.js +++ b/src/svgcanvas/path-actions.js @@ -26,7 +26,7 @@ let path = null * @param {module:path-actions.svgCanvas} pathActionsContext * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas } diff --git a/src/svgcanvas/path-method.js b/src/svgcanvas/path-method.js index fa5b1ad8..30890d31 100644 --- a/src/svgcanvas/path-method.js +++ b/src/svgcanvas/path-method.js @@ -23,7 +23,7 @@ let svgCanvas = null * @param {module:path-actions.svgCanvas} pathMethodsContext * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas } diff --git a/src/svgcanvas/recalculate.js b/src/svgcanvas/recalculate.js index f2a1a045..343f9a36 100644 --- a/src/svgcanvas/recalculate.js +++ b/src/svgcanvas/recalculate.js @@ -41,7 +41,7 @@ let svgCanvas * @param {module:recalculate.EditorContext} editorContext * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas } @@ -53,7 +53,7 @@ export const init = function (canvas) { * @param {Float} ty - The translation's y value * @returns {void} */ -export const updateClipPath = function (attr, tx, ty) { +export const updateClipPath = (attr, tx, ty) => { const path = getRefElem(attr).firstChild const cpXform = path.transform.baseVal const newxlate = svgCanvas.getSvgRoot().createSVGTransform() @@ -71,7 +71,7 @@ export const updateClipPath = function (attr, tx, ty) { * @param {Element} selected - The DOM element to recalculate * @returns {Command} Undo command object with the resulting change */ -export const recalculateDimensions = function (selected) { +export const recalculateDimensions = (selected) => { if (!selected) return null const svgroot = svgCanvas.getSvgRoot() const dataStorage = svgCanvas.getDataStorage() @@ -215,7 +215,7 @@ export const recalculateDimensions = function (selected) { } // switch on element type to get initial values if (attrs.length) { - Array.prototype.forEach.call(attrs, function (attr) { + Array.prototype.forEach.call(attrs, (attr) => { changes[attr] = selected.getAttribute(attr) }) for (const [attr, val] of Object.entries(changes)) { diff --git a/src/svgcanvas/selected-elem.js b/src/svgcanvas/selected-elem.js index f97a06ab..544d65dc 100644 --- a/src/svgcanvas/selected-elem.js +++ b/src/svgcanvas/selected-elem.js @@ -35,7 +35,7 @@ let svgCanvas = null * @param {module:selected-elem.elementContext} elementContext * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas } diff --git a/src/svgcanvas/selection.js b/src/svgcanvas/selection.js index a16c5f29..744d9585 100644 --- a/src/svgcanvas/selection.js +++ b/src/svgcanvas/selection.js @@ -26,7 +26,7 @@ let svgCanvas = null * @param {module:selection.selectionContext} selectionContext * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas } @@ -37,7 +37,7 @@ export const init = function (canvas) { * @type {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection} * @fires module:selection.SvgCanvas#event:selected */ -export const clearSelectionMethod = function (noCall) { +export const clearSelectionMethod = (noCall) => { const selectedElements = svgCanvas.getSelectedElements() selectedElements.forEach((elem) => { if (!elem) { @@ -59,7 +59,7 @@ export const clearSelectionMethod = function (noCall) { * @type {module:path.EditorContext#addToSelection} * @fires module:selection.SvgCanvas#event:selected */ -export const addToSelectionMethod = function (elemsToAdd, showGrips) { +export const addToSelectionMethod = (elemsToAdd, showGrips) => { const selectedElements = svgCanvas.getSelectedElements() if (!elemsToAdd.length) { return @@ -115,7 +115,7 @@ export const addToSelectionMethod = function (elemsToAdd, showGrips) { // make sure the elements are in the correct order // See: https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition - selectedElements.sort(function (a, b) { + selectedElements.sort((a, b) => { if (a && b && a.compareDocumentPosition) { return 3 - (b.compareDocumentPosition(a) & 6) } @@ -134,7 +134,7 @@ export const addToSelectionMethod = function (elemsToAdd, showGrips) { * @name module:svgcanvas.SvgCanvas#getMouseTarget * @type {module:path.EditorContext#getMouseTarget} */ -export const getMouseTargetMethod = function (evt) { +export const getMouseTargetMethod = (evt) => { if (!evt) { return null } @@ -212,12 +212,12 @@ export const getMouseTargetMethod = function (evt) { * @returns {GenericArray|module:svgcanvas.ExtensionStatus|false} See {@tutorial ExtensionDocs} on the ExtensionStatus. */ /* eslint-enable max-len */ -export const runExtensionsMethod = function ( +export const runExtensionsMethod = ( action, vars, returnArray, nameFilter -) { +) => { let result = returnArray ? [] : false for (const [name, ext] of Object.entries(svgCanvas.getExtensions())) { if (nameFilter && !nameFilter(name)) { @@ -245,7 +245,7 @@ export const runExtensionsMethod = function ( * @param {Element} parent - The parent DOM element to search within * @returns {ElementAndBBox[]} An array with objects that include: */ -export const getVisibleElementsAndBBoxes = function (parent) { +export const getVisibleElementsAndBBoxes = (parent) => { if (!parent) { const svgContent = svgCanvas.getSvgContent() parent = svgContent.children // Prevent layers from being included @@ -272,7 +272,7 @@ export const getVisibleElementsAndBBoxes = function (parent) { * @param {SVGRect} rect * @returns {Element[]|NodeList} Bbox elements */ -export const getIntersectionListMethod = function (rect) { +export const getIntersectionListMethod = (rect) => { const zoom = svgCanvas.getZoom() if (!svgCanvas.getRubberBox()) { return null @@ -335,7 +335,7 @@ export const getIntersectionListMethod = function (rect) { * @param {Element} elem - SVG element to wrap * @returns {void} */ -export const groupSvgElem = function (elem) { +export const groupSvgElem = (elem) => { const dataStorage = svgCanvas.getDataStorage() const g = document.createElementNS(NS.SVG, 'g') elem.replaceWith(g) @@ -350,7 +350,7 @@ export const groupSvgElem = function (elem) { * @param {XMLDocument} newDoc - The SVG DOM document * @returns {void} */ -export const prepareSvg = function (newDoc) { +export const prepareSvg = (newDoc) => { svgCanvas.sanitizeSvg(newDoc.documentElement) // convert paths into absolute commands @@ -371,7 +371,7 @@ export const prepareSvg = function (newDoc) { * @fires module:svgcanvas.SvgCanvas#event:changed * @returns {void} */ -export const setRotationAngle = function (val, preventUndo) { +export const setRotationAngle = (val, preventUndo) => { const selectedElements = svgCanvas.getSelectedElements() // ensure val is the proper type val = Number.parseFloat(val) @@ -441,7 +441,7 @@ export const setRotationAngle = function (val, preventUndo) { * @fires module:svgcanvas.SvgCanvas#event:changed * @returns {void} */ -export const recalculateAllSelectedDimensions = function () { +export const recalculateAllSelectedDimensions = () => { const text = svgCanvas.getCurrentResizeMode() === 'none' ? 'position' : 'size' const batchCmd = new BatchCommand(text) diff --git a/src/svgcanvas/svg-exec.js b/src/svgcanvas/svg-exec.js index f1f246fc..04a57469 100644 --- a/src/svgcanvas/svg-exec.js +++ b/src/svgcanvas/svg-exec.js @@ -41,7 +41,7 @@ let svgCanvas = null * @param {module:svg-exec.SvgCanvas#init} svgContext * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas } diff --git a/src/svgcanvas/text-actions.js b/src/svgcanvas/text-actions.js index 0a42517f..0f017c06 100644 --- a/src/svgcanvas/text-actions.js +++ b/src/svgcanvas/text-actions.js @@ -23,7 +23,7 @@ let svgCanvas = null * @param {module:text-actions.svgCanvas} textActionsContext * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas } diff --git a/src/svgcanvas/utilities.js b/src/svgcanvas/utilities.js index 0d9c5dcc..3db8461b 100644 --- a/src/svgcanvas/utilities.js +++ b/src/svgcanvas/utilities.js @@ -80,7 +80,7 @@ let svgroot_ = null * @param {module:utilities.EditorContext} canvas * @returns {void} */ -export const init = function (canvas) { +export const init = (canvas) => { svgCanvas = canvas svgroot_ = canvas.getSvgRoot() } From 3410ece268ca08e21fa4d9f5011c1250251b9fd9 Mon Sep 17 00:00:00 2001 From: JFH <20402845+jfhenon@users.noreply.github.com> Date: Sat, 1 Jan 2022 14:17:29 -0300 Subject: [PATCH 3/7] using consolidate() to simplify transformations this has the effect to create a matrix transform so this avoid mixing the translation transform cause by the move with existing transformations on the object. --- src/svgcanvas/recalculate.js | 125 +---------------------------------- src/svgcanvas/svgcanvas.js | 2 +- 2 files changed, 4 insertions(+), 123 deletions(-) diff --git a/src/svgcanvas/recalculate.js b/src/svgcanvas/recalculate.js index 343f9a36..e218e920 100644 --- a/src/svgcanvas/recalculate.js +++ b/src/svgcanvas/recalculate.js @@ -10,7 +10,7 @@ import { getRotationAngle, getHref, getBBox, getRefElem } from './utilities.js' import { BatchCommand, ChangeElementCommand } from './history.js' import { remapElement } from './coords.js' import { - isIdentity, matrixMultiply, transformPoint, transformListToTransform, + matrixMultiply, transformPoint, transformListToTransform, hasMatrixTransform } from './math.js' import { @@ -19,28 +19,6 @@ import { let svgCanvas -/** -* @interface module:recalculate.EditorContext -*/ -/** - * @function module:recalculate.EditorContext#getSvgRoot - * @returns {SVGSVGElement} The root DOM element - */ -/** - * @function module:recalculate.EditorContext#getStartTransform - * @returns {string} -*/ -/** - * @function module:recalculate.EditorContext#setStartTransform - * @param {string} transform - * @returns {void} - */ - -/** -* @function module:recalculate.init -* @param {module:recalculate.EditorContext} editorContext -* @returns {void} -*/ export const init = (canvas) => { svgCanvas = canvas } @@ -76,96 +54,15 @@ export const recalculateDimensions = (selected) => { const svgroot = svgCanvas.getSvgRoot() const dataStorage = svgCanvas.getDataStorage() const tlist = selected.transform?.baseVal - // remove any unnecessary transforms - if (tlist && tlist.numberOfItems > 0) { - let k = tlist.numberOfItems - const noi = k - while (k--) { - const xform = tlist.getItem(k) - if (xform.type === 0) { - tlist.removeItem(k) - // remove identity matrices - } else if (xform.type === 1) { - if (isIdentity(xform.matrix)) { - if (noi === 1) { - // Overcome Chrome bug (though only when noi is 1) with - // `removeItem` preventing `removeAttribute` from - // subsequently working - // See https://bugs.chromium.org/p/chromium/issues/detail?id=843901 - selected.removeAttribute('transform') - return null - } - tlist.removeItem(k) - } - // remove zero-degree rotations - } else if (xform.type === 4 && xform.angle === 0) { - tlist.removeItem(k) - } - } - // End here if all it has is a rotation - if (tlist.numberOfItems === 1 && - getRotationAngle(selected)) { return null } - } // if this element had no transforms, we are done if (!tlist || tlist.numberOfItems === 0) { - // Chrome apparently had a bug that requires clearing the attribute first. - selected.setAttribute('transform', '') - // However, this still next line currently doesn't work at all in Chrome - selected.removeAttribute('transform') - // selected.transform.baseVal.clear(); // Didn't help for Chrome bug return null } - // TODO: Make this work for more than 2 - if (tlist) { - let mxs = [] - let k = tlist.numberOfItems - while (k--) { - const xform = tlist.getItem(k) - if (xform.type === 1) { - mxs.push([xform.matrix, k]) - } else if (mxs.length) { - mxs = [] - } - } - if (mxs.length === 2) { - const mNew = svgroot.createSVGTransformFromMatrix(matrixMultiply(mxs[1][0], mxs[0][0])) - tlist.removeItem(mxs[0][1]) - tlist.removeItem(mxs[1][1]) - tlist.insertItemBefore(mNew, mxs[1][1]) - } + // consolidate transforms using standard SVG + tlist.consolidate() - // combine matrix + translate - k = tlist.numberOfItems - if (k >= 2 && tlist.getItem(k - 2).type === 1 && tlist.getItem(k - 1).type === 2) { - const mt = svgroot.createSVGTransform() - - const m = matrixMultiply( - tlist.getItem(k - 2).matrix, - tlist.getItem(k - 1).matrix - ) - mt.setMatrix(m) - tlist.removeItem(k - 2) - tlist.removeItem(k - 2) - tlist.appendItem(mt) - } - } - - // If it still has a single [M] or [R][M], return null too (prevents BatchCommand from being returned). - switch (selected.tagName) { - // Ignore these elements, as they can absorb the [M] - case 'line': - case 'polyline': - case 'polygon': - case 'path': - break - default: - if ((tlist.numberOfItems === 1 && tlist.getItem(0).type === 1) || - (tlist.numberOfItems === 2 && tlist.getItem(0).type === 1 && tlist.getItem(0).type === 4)) { - return null - } - } // Grouped SVG element const gsvg = (dataStorage.has(selected, 'gsvg')) ? dataStorage.get(selected, 'gsvg') : undefined // we know we have some transforms, so set up return variable @@ -305,22 +202,6 @@ export const recalculateDimensions = (selected) => { const m = transformListToTransform(childTlist).matrix - // Convert a matrix to a scale if applicable - // if (hasMatrixTransform(childTlist) && childTlist.numberOfItems == 1) { - // if (m.b==0 && m.c==0 && m.e==0 && m.f==0) { - // childTlist.removeItem(0); - // const translateOrigin = svgroot.createSVGTransform(), - // scale = svgroot.createSVGTransform(), - // translateBack = svgroot.createSVGTransform(); - // translateOrigin.setTranslate(0, 0); - // scale.setScale(m.a, m.d); - // translateBack.setTranslate(0, 0); - // childTlist.appendItem(translateBack); - // childTlist.appendItem(scale); - // childTlist.appendItem(translateOrigin); - // } - // } - const angle = getRotationAngle(child) oldStartTransform = svgCanvas.getStartTransform() // const childxforms = []; diff --git a/src/svgcanvas/svgcanvas.js b/src/svgcanvas/svgcanvas.js index ad78176a..03d8896b 100644 --- a/src/svgcanvas/svgcanvas.js +++ b/src/svgcanvas/svgcanvas.js @@ -301,7 +301,7 @@ class SvgCanvas { getSelectedElements () { return this.selectedElements } setSelectedElements (key, value) { this.selectedElements[key] = value } setEmptySelectedElements () { this.selectedElements = [] } - getSvgRoot () { return this.svgroot } + getSvgRoot () { return this.svgroot } // @returns {SVGSVGElement} The root DOM element getDOMDocument () { return this.svgdoc } getDOMContainer () { return this.container } getCurConfig () { return this.curConfig } From 4586feaa5e327bb80c38623b4570bd5225b6129e Mon Sep 17 00:00:00 2001 From: JFH <20402845+jfhenon@users.noreply.github.com> Date: Sat, 1 Jan 2022 18:03:16 -0300 Subject: [PATCH 4/7] in progress --- src/svgcanvas/event.js | 1 + src/svgcanvas/recalculate.js | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/svgcanvas/event.js b/src/svgcanvas/event.js index 9f76d650..c1655828 100644 --- a/src/svgcanvas/event.js +++ b/src/svgcanvas/event.js @@ -571,6 +571,7 @@ export const mouseUpEvent = (evt) => { const x = mouseX / zoom const y = mouseY / zoom + console.log(svgCanvas.getId()) let element = getElement(svgCanvas.getId()) let keep = false diff --git a/src/svgcanvas/recalculate.js b/src/svgcanvas/recalculate.js index e218e920..c3881db7 100644 --- a/src/svgcanvas/recalculate.js +++ b/src/svgcanvas/recalculate.js @@ -112,12 +112,9 @@ export const recalculateDimensions = (selected) => { } // switch on element type to get initial values if (attrs.length) { - Array.prototype.forEach.call(attrs, (attr) => { - changes[attr] = selected.getAttribute(attr) + attrs.forEach((attr) => { + changes[attr] = convertToNum(attr, selected.getAttribute(attr)) }) - for (const [attr, val] of Object.entries(changes)) { - changes[attr] = convertToNum(attr, val) - } } else if (gsvg) { // GSVG exception changes = { @@ -168,7 +165,9 @@ export const recalculateDimensions = (selected) => { } } } + const N = tlist.numberOfItems + console.log(N) let tx = 0; let ty = 0; let operation = 0 let firstM From a6773f8fea380378f3b2c0df2e08fbf89a43c5dc Mon Sep 17 00:00:00 2001 From: JFH <20402845+jfhenon@users.noreply.github.com> Date: Sat, 1 Jan 2022 19:05:46 -0300 Subject: [PATCH 5/7] Revert "using consolidate() to simplify transformations" This reverts commit 3410ece268ca08e21fa4d9f5011c1250251b9fd9. --- src/svgcanvas/recalculate.js | 125 ++++++++++++++++++++++++++++++++++- src/svgcanvas/svgcanvas.js | 2 +- 2 files changed, 123 insertions(+), 4 deletions(-) diff --git a/src/svgcanvas/recalculate.js b/src/svgcanvas/recalculate.js index c3881db7..22180bfa 100644 --- a/src/svgcanvas/recalculate.js +++ b/src/svgcanvas/recalculate.js @@ -10,7 +10,7 @@ import { getRotationAngle, getHref, getBBox, getRefElem } from './utilities.js' import { BatchCommand, ChangeElementCommand } from './history.js' import { remapElement } from './coords.js' import { - matrixMultiply, transformPoint, transformListToTransform, + isIdentity, matrixMultiply, transformPoint, transformListToTransform, hasMatrixTransform } from './math.js' import { @@ -19,6 +19,28 @@ import { let svgCanvas +/** +* @interface module:recalculate.EditorContext +*/ +/** + * @function module:recalculate.EditorContext#getSvgRoot + * @returns {SVGSVGElement} The root DOM element + */ +/** + * @function module:recalculate.EditorContext#getStartTransform + * @returns {string} +*/ +/** + * @function module:recalculate.EditorContext#setStartTransform + * @param {string} transform + * @returns {void} + */ + +/** +* @function module:recalculate.init +* @param {module:recalculate.EditorContext} editorContext +* @returns {void} +*/ export const init = (canvas) => { svgCanvas = canvas } @@ -54,15 +76,96 @@ export const recalculateDimensions = (selected) => { const svgroot = svgCanvas.getSvgRoot() const dataStorage = svgCanvas.getDataStorage() const tlist = selected.transform?.baseVal + // remove any unnecessary transforms + if (tlist && tlist.numberOfItems > 0) { + let k = tlist.numberOfItems + const noi = k + while (k--) { + const xform = tlist.getItem(k) + if (xform.type === 0) { + tlist.removeItem(k) + // remove identity matrices + } else if (xform.type === 1) { + if (isIdentity(xform.matrix)) { + if (noi === 1) { + // Overcome Chrome bug (though only when noi is 1) with + // `removeItem` preventing `removeAttribute` from + // subsequently working + // See https://bugs.chromium.org/p/chromium/issues/detail?id=843901 + selected.removeAttribute('transform') + return null + } + tlist.removeItem(k) + } + // remove zero-degree rotations + } else if (xform.type === 4 && xform.angle === 0) { + tlist.removeItem(k) + } + } + // End here if all it has is a rotation + if (tlist.numberOfItems === 1 && + getRotationAngle(selected)) { return null } + } // if this element had no transforms, we are done if (!tlist || tlist.numberOfItems === 0) { + // Chrome apparently had a bug that requires clearing the attribute first. + selected.setAttribute('transform', '') + // However, this still next line currently doesn't work at all in Chrome + selected.removeAttribute('transform') + // selected.transform.baseVal.clear(); // Didn't help for Chrome bug return null } - // consolidate transforms using standard SVG - tlist.consolidate() + // TODO: Make this work for more than 2 + if (tlist) { + let mxs = [] + let k = tlist.numberOfItems + while (k--) { + const xform = tlist.getItem(k) + if (xform.type === 1) { + mxs.push([xform.matrix, k]) + } else if (mxs.length) { + mxs = [] + } + } + if (mxs.length === 2) { + const mNew = svgroot.createSVGTransformFromMatrix(matrixMultiply(mxs[1][0], mxs[0][0])) + tlist.removeItem(mxs[0][1]) + tlist.removeItem(mxs[1][1]) + tlist.insertItemBefore(mNew, mxs[1][1]) + } + // combine matrix + translate + k = tlist.numberOfItems + if (k >= 2 && tlist.getItem(k - 2).type === 1 && tlist.getItem(k - 1).type === 2) { + const mt = svgroot.createSVGTransform() + + const m = matrixMultiply( + tlist.getItem(k - 2).matrix, + tlist.getItem(k - 1).matrix + ) + mt.setMatrix(m) + tlist.removeItem(k - 2) + tlist.removeItem(k - 2) + tlist.appendItem(mt) + } + } + + // If it still has a single [M] or [R][M], return null too (prevents BatchCommand from being returned). + switch (selected.tagName) { + // Ignore these elements, as they can absorb the [M] + case 'line': + case 'polyline': + case 'polygon': + case 'path': + break + default: + if ((tlist.numberOfItems === 1 && tlist.getItem(0).type === 1) || + (tlist.numberOfItems === 2 && tlist.getItem(0).type === 1 && tlist.getItem(0).type === 4)) { + return null + } + } // Grouped SVG element const gsvg = (dataStorage.has(selected, 'gsvg')) ? dataStorage.get(selected, 'gsvg') : undefined // we know we have some transforms, so set up return variable @@ -201,6 +304,22 @@ export const recalculateDimensions = (selected) => { const m = transformListToTransform(childTlist).matrix + // Convert a matrix to a scale if applicable + // if (hasMatrixTransform(childTlist) && childTlist.numberOfItems == 1) { + // if (m.b==0 && m.c==0 && m.e==0 && m.f==0) { + // childTlist.removeItem(0); + // const translateOrigin = svgroot.createSVGTransform(), + // scale = svgroot.createSVGTransform(), + // translateBack = svgroot.createSVGTransform(); + // translateOrigin.setTranslate(0, 0); + // scale.setScale(m.a, m.d); + // translateBack.setTranslate(0, 0); + // childTlist.appendItem(translateBack); + // childTlist.appendItem(scale); + // childTlist.appendItem(translateOrigin); + // } + // } + const angle = getRotationAngle(child) oldStartTransform = svgCanvas.getStartTransform() // const childxforms = []; diff --git a/src/svgcanvas/svgcanvas.js b/src/svgcanvas/svgcanvas.js index 03d8896b..ad78176a 100644 --- a/src/svgcanvas/svgcanvas.js +++ b/src/svgcanvas/svgcanvas.js @@ -301,7 +301,7 @@ class SvgCanvas { getSelectedElements () { return this.selectedElements } setSelectedElements (key, value) { this.selectedElements[key] = value } setEmptySelectedElements () { this.selectedElements = [] } - getSvgRoot () { return this.svgroot } // @returns {SVGSVGElement} The root DOM element + getSvgRoot () { return this.svgroot } getDOMDocument () { return this.svgdoc } getDOMContainer () { return this.container } getCurConfig () { return this.curConfig } From 56be0aa6c47cae6eb9c4153405380c2aa9f3faca Mon Sep 17 00:00:00 2001 From: JFH <20402845+jfhenon@users.noreply.github.com> Date: Sat, 1 Jan 2022 21:53:39 -0300 Subject: [PATCH 6/7] consolidate existing transformations before the move. --- src/svgcanvas/event.js | 8 +++++++- src/svgcanvas/recalculate.js | 1 - 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/svgcanvas/event.js b/src/svgcanvas/event.js index c1655828..fc26382a 100644 --- a/src/svgcanvas/event.js +++ b/src/svgcanvas/event.js @@ -571,7 +571,6 @@ export const mouseUpEvent = (evt) => { const x = mouseX / zoom const y = mouseY / zoom - console.log(svgCanvas.getId()) let element = getElement(svgCanvas.getId()) let keep = false @@ -1012,6 +1011,13 @@ export const mouseDownEvent = (evt) => { svgCanvas.setStartTransform(mouseTarget.getAttribute('transform')) const tlist = mouseTarget.transform.baseVal + // consolidate transforms using standard SVG but keep the transformation used for the move/scale + if (tlist.numberOfItems > 1) { + const firstTransform = tlist.getItem(0) + tlist.removeItem(0) + tlist.consolidate() + tlist.insertItemBefore(firstTransform, 0) + } switch (svgCanvas.getCurrentMode()) { case 'select': svgCanvas.setStarted(true) diff --git a/src/svgcanvas/recalculate.js b/src/svgcanvas/recalculate.js index 22180bfa..08fef8a0 100644 --- a/src/svgcanvas/recalculate.js +++ b/src/svgcanvas/recalculate.js @@ -270,7 +270,6 @@ export const recalculateDimensions = (selected) => { } const N = tlist.numberOfItems - console.log(N) let tx = 0; let ty = 0; let operation = 0 let firstM From e620ef6c05e655afc540fd66bd2a7cf054a024c1 Mon Sep 17 00:00:00 2001 From: JFH <20402845+jfhenon@users.noreply.github.com> Date: Sat, 1 Jan 2022 22:28:01 -0300 Subject: [PATCH 7/7] 7.1.1 --- CHANGES.md | 3 +- README.md | 5 ++- .../ui/__snapshots__/scenario3.js.snap | 44 +++++++++---------- package-lock.json | 4 +- package.json | 2 +- 5 files changed, 31 insertions(+), 27 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 88c0df91..e4ae358d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,6 @@ # SVG-Edit CHANGES - +## 7.1.1 +- Fix an issue when moving a text with an existing transformation (issue #689) ## 7.1.0 - Large refactoring of svgcanvas (a lot of remaining work with the goal to separate in its own package).This explains the move to a minor version - move to a new linter (standard). diff --git a/README.md b/README.md index 38cc6b38..208ca8b1 100644 --- a/README.md +++ b/README.md @@ -32,12 +32,15 @@ Please let us know with an issue or a discussions if you wish to contribute. Thanks to **Netlify**, you can test the following builds: -### [Try SVGEdit 7.1.0 here](https://svgedit.netlify.app/editor/index.html) +### [Try SVGEdit 7.1.x here](https://svgedit.netlify.app/editor/index.html) [Try SVGEdit 5.1.0 here](https://6098683962bf91702907ee33--svgedit.netlify.app/editor/svg-editor.html) [Try SVGEdit 6.1.0 here](https://60a0000fc9900b0008fd268d--svgedit.netlify.app/editor/index.html) +Additional tip: you may try a version released on NPM using unpkg for example with version 7.1.0: +[https://unpkg.com/svgedit@7.1.0/dist/editor/index.html](https://unpkg.com/svgedit@7.1.0/dist/editor/index.html) + ## Installation ### Quick install diff --git a/cypress/integration/ui/__snapshots__/scenario3.js.snap b/cypress/integration/ui/__snapshots__/scenario3.js.snap index a3c7feb0..9727d948 100644 --- a/cypress/integration/ui/__snapshots__/scenario3.js.snap +++ b/cypress/integration/ui/__snapshots__/scenario3.js.snap @@ -66,28 +66,6 @@ exports[`use all parts of svg-edit > check tool_path_change_node_xy #0`] = ` `; -exports[`use all parts of svg-edit > check tool_path_openclose #0`] = ` - - - - Layer 1 - - - - -`; - exports[`use all parts of svg-edit > check tool_path_change_seg_type #0`] = ` check tool_path_change_clone_node #0`] = ` `; + +exports[`use all parts of svg-edit > check tool_path_openclose #0`] = ` + + + + Layer 1 + + + + +`; diff --git a/package-lock.json b/package-lock.json index 249aef6c..4674e50a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "svgedit", - "version": "7.1.0", + "version": "7.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "svgedit", - "version": "7.1.0", + "version": "7.1.1", "license": "(MIT AND Apache-2.0 AND ISC AND LGPL-3.0-or-later AND X11)", "dependencies": { "@babel/polyfill": "7.12.1", diff --git a/package.json b/package.json index 32e73470..47bd07d7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svgedit", - "version": "7.1.0", + "version": "7.1.1", "description": "Powerful SVG-Editor for your browser ", "main": "dist/Editor.js", "module": "dist/Editor.js",