Merge pull request #690 from SVG-Edit/fix-#689

Fix #689
master
JFH 2022-01-01 22:50:20 -03:00 committed by GitHub
commit eb3567dc69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 175 additions and 151 deletions

View File

@ -1,5 +1,6 @@
# SVG-Edit CHANGES # SVG-Edit CHANGES
## 7.1.1
- Fix an issue when moving a text with an existing transformation (issue #689)
## 7.1.0 ## 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 - 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). - move to a new linter (standard).

View File

@ -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: 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 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) [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 ## Installation
### Quick install ### Quick install

View File

@ -66,28 +66,6 @@ exports[`use all parts of svg-edit > check tool_path_change_node_xy #0`] = `
</body> </body>
`; `;
exports[`use all parts of svg-edit > check tool_path_openclose #0`] = `
<body>
<svg
width="640"
height="480"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
>
<g class="layer">
<title>Layer 1</title>
<path
d="m201,246l-51,-146l-25,100c55.16667,65.16667 172.83333,215.33333 148.625,173c-24.20833,-42.33333 -64.29167,-106.16667 -72.625,-127z"
fill="#FF0000"
id="svg_1"
stroke="#000000"
stroke-width="5"
></path>
</g>
</svg>
</body>
`;
exports[`use all parts of svg-edit > check tool_path_change_seg_type #0`] = ` exports[`use all parts of svg-edit > check tool_path_change_seg_type #0`] = `
<body> <body>
<svg <svg
@ -131,3 +109,25 @@ exports[`use all parts of svg-edit > check tool_path_change_clone_node #0`] = `
</svg> </svg>
</body> </body>
`; `;
exports[`use all parts of svg-edit > check tool_path_openclose #0`] = `
<body>
<svg
width="640"
height="480"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
>
<g class="layer">
<title>Layer 1</title>
<path
d="m201,246l-51,-146l-25,100c55.16667,65.16667 172.83333,215.33333 148.625,173c-24.20833,-42.33333 -64.29167,-106.16667 -72.625,-127z"
fill="#FF0000"
id="svg_1"
stroke="#000000"
stroke-width="5"
></path>
</g>
</svg>
</body>
`;

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "svgedit", "name": "svgedit",
"version": "7.1.0", "version": "7.1.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "svgedit", "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)", "license": "(MIT AND Apache-2.0 AND ISC AND LGPL-3.0-or-later AND X11)",
"dependencies": { "dependencies": {
"@babel/polyfill": "7.12.1", "@babel/polyfill": "7.12.1",

View File

@ -1,6 +1,6 @@
{ {
"name": "svgedit", "name": "svgedit",
"version": "7.1.0", "version": "7.1.1",
"description": "Powerful SVG-Editor for your browser ", "description": "Powerful SVG-Editor for your browser ",
"main": "dist/Editor.js", "main": "dist/Editor.js",
"module": "dist/Editor.js", "module": "dist/Editor.js",

View File

@ -12,7 +12,7 @@ let svgCanvas = null
* @param {module:blur.blurContext} blurContext * @param {module:blur.blurContext} blurContext
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
} }

View File

@ -36,7 +36,7 @@ let svgCanvas = null
* @param {module:svgcanvas.SvgCanvas#event:pointsAdded} editorContext * @param {module:svgcanvas.SvgCanvas#event:pointsAdded} editorContext
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
} }

View File

@ -754,7 +754,7 @@ let svgCanvas
* @param {module:draw.DrawCanvasInit} canvas * @param {module:draw.DrawCanvasInit} canvas
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
} }

View File

@ -22,7 +22,7 @@ let svgCanvas = null
* @param {module:elem-get-set.elemContext} elemContext * @param {module:elem-get-set.elemContext} elemContext
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
} }

View File

@ -34,7 +34,7 @@ export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
} }
export const getBsplinePoint = (t) => { const getBsplinePoint = (t) => {
const spline = { x: 0, y: 0 } const spline = { x: 0, y: 0 }
const p0 = { x: svgCanvas.getControllPoint2('x'), y: svgCanvas.getControllPoint2('y') } const p0 = { x: svgCanvas.getControllPoint2('x'), y: svgCanvas.getControllPoint2('y') }
const p1 = { x: svgCanvas.getControllPoint1('x'), y: svgCanvas.getControllPoint1('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 * @param {MouseEvent} evt
@ -78,12 +97,16 @@ export const getBsplinePoint = (t) => {
* @returns {void} * @returns {void}
*/ */
export const mouseMoveEvent = (evt) => { 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 selectedElements = svgCanvas.getSelectedElements()
const zoom = svgCanvas.getZoom() const zoom = svgCanvas.getZoom()
const svgRoot = svgCanvas.getSvgRoot() const svgRoot = svgCanvas.getSvgRoot()
const selected = selectedElements[0]
if (!svgCanvas.getStarted()) { return }
if (evt.button === 1 || svgCanvas.spaceKey) { return }
let i let i
let xya let xya
@ -94,7 +117,7 @@ export const mouseMoveEvent = (evt) => {
let len let len
let angle let angle
let box let box
let selected = selectedElements[0]
const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm()) const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm())
const mouseX = pt.x * zoom const mouseX = pt.x * zoom
const mouseY = pt.y * zoom const mouseY = pt.y * zoom
@ -110,14 +133,13 @@ export const mouseMoveEvent = (evt) => {
y = snapToGrid(y) y = snapToGrid(y)
} }
evt.preventDefault()
let tlist let tlist
switch (svgCanvas.getCurrentMode()) { switch (svgCanvas.getCurrentMode()) {
case 'select': { case 'select': {
// we temporarily use a translate on the element(s) being dragged // we temporarily use a translate on the element(s) being dragged
// this transform is removed upon mousing up and the element is // this transform is removed upon mousing up and the element is
// relocated to the new location // relocated to the new location
if (selectedElements[0] !== null) { if (selected) {
dx = x - svgCanvas.getStartX() dx = x - svgCanvas.getStartX()
dy = y - svgCanvas.getStartY() dy = y - svgCanvas.getStartY()
if (svgCanvas.getCurConfig().gridSnapping) { if (svgCanvas.getCurConfig().gridSnapping) {
@ -125,35 +147,20 @@ export const mouseMoveEvent = (evt) => {
dy = snapToGrid(dy) dy = snapToGrid(dy)
} }
if (dx !== 0 || dy !== 0) { if (dx || dy) {
len = selectedElements.length selectedElements.forEach((el) => {
for (i = 0; i < len; ++i) { if (el) {
selected = selectedElements[i] updateTransformList(svgRoot, el, dx, dy)
if (isNullish(selected)) { break } // update our internal bbox that we're tracking while dragging
// update the dummy transform in our transform list svgCanvas.selectorManager.requestSelector(el).resize()
// 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)
} }
})
// update our internal bbox that we're tracking while dragging
svgCanvas.selectorManager.requestSelector(selected).resize()
}
svgCanvas.call('transition', selectedElements) svgCanvas.call('transition', selectedElements)
} }
} }
break break
} case 'multiselect': { }
case 'multiselect': {
realX *= zoom realX *= zoom
realY *= zoom realY *= zoom
assignAttributes(svgCanvas.getRubberBox(), { assignAttributes(svgCanvas.getRubberBox(), {
@ -194,10 +201,11 @@ export const mouseMoveEvent = (evt) => {
} }
break break
} case 'resize': { }
// we track the resize bounding box and translate/scale the selected element case 'resize': {
// while the mouse is down, when mouse goes up, we use this to recalculate // we track the resize bounding box and translate/scale the selected element
// the shape's coordinates // while the mouse is down, when mouse goes up, we use this to recalculate
// the shape's coordinates
tlist = selected.transform.baseVal tlist = selected.transform.baseVal
const hasMatrix = hasMatrixTransform(tlist) const hasMatrix = hasMatrixTransform(tlist)
box = hasMatrix ? svgCanvas.getInitBbox() : getBBox(selected) box = hasMatrix ? svgCanvas.getInitBbox() : getBBox(selected)
@ -285,7 +293,8 @@ export const mouseMoveEvent = (evt) => {
svgCanvas.call('transition', selectedElements) svgCanvas.call('transition', selectedElements)
break break
} case 'zoom': { }
case 'zoom': {
realX *= zoom realX *= zoom
realY *= zoom realY *= zoom
assignAttributes(svgCanvas.getRubberBox(), { assignAttributes(svgCanvas.getRubberBox(), {
@ -295,13 +304,15 @@ export const mouseMoveEvent = (evt) => {
height: Math.abs(realY - svgCanvas.getRStartY() * zoom) height: Math.abs(realY - svgCanvas.getRStartY() * zoom)
}, 100) }, 100)
break break
} case 'text': { }
case 'text': {
assignAttributes(shape, { assignAttributes(shape, {
x, x,
y y
}, 1000) }, 1000)
break break
} case 'line': { }
case 'line': {
if (svgCanvas.getCurConfig().gridSnapping) { if (svgCanvas.getCurConfig().gridSnapping) {
x = snapToGrid(x) x = snapToGrid(x)
y = snapToGrid(y) y = snapToGrid(y)
@ -319,12 +330,10 @@ export const mouseMoveEvent = (evt) => {
shape.setAttribute('x2', x2) shape.setAttribute('x2', x2)
shape.setAttribute('y2', y2) shape.setAttribute('y2', y2)
break break
} case 'foreignObject': }
// fall through case 'foreignObject': // fall through
case 'square': case 'square':
// fall through
case 'rect': case 'rect':
// fall through
case 'image': { case 'image': {
const square = (svgCanvas.getCurrentMode() === 'square') || evt.shiftKey const square = (svgCanvas.getCurrentMode() === 'square') || evt.shiftKey
let let
@ -355,7 +364,8 @@ export const mouseMoveEvent = (evt) => {
}, 1000) }, 1000)
break break
} case 'circle': { }
case 'circle': {
cx = Number(shape.getAttribute('cx')) cx = Number(shape.getAttribute('cx'))
cy = Number(shape.getAttribute('cy')) cy = Number(shape.getAttribute('cy'))
let rad = Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - 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) shape.setAttribute('r', rad)
break break
} case 'ellipse': { }
case 'ellipse': {
cx = Number(shape.getAttribute('cx')) cx = Number(shape.getAttribute('cx'))
cy = Number(shape.getAttribute('cy')) cy = Number(shape.getAttribute('cy'))
if (svgCanvas.getCurConfig().gridSnapping) { if (svgCanvas.getCurConfig().gridSnapping) {
@ -387,8 +398,8 @@ export const mouseMoveEvent = (evt) => {
} }
// Fallthrough // Fallthrough
case 'fhpath': { case 'fhpath': {
// dAttr += + realX + ',' + realY + ' '; // dAttr += + realX + ',' + realY + ' ';
// shape.setAttribute('points', dAttr); // shape.setAttribute('points', dAttr);
svgCanvas.setEnd('x', realX) svgCanvas.setEnd('x', realX)
svgCanvas.setEnd('y', realY) svgCanvas.setEnd('y', realY)
if (svgCanvas.getControllPoint2('x') && svgCanvas.getControllPoint2('y')) { if (svgCanvas.getControllPoint2('x') && svgCanvas.getControllPoint2('y')) {
@ -421,9 +432,9 @@ export const mouseMoveEvent = (evt) => {
svgCanvas.setControllPoint1('y', svgCanvas.getStart('y')) svgCanvas.setControllPoint1('y', svgCanvas.getStart('y'))
svgCanvas.setStart({ x: svgCanvas.getEnd('x'), y: svgCanvas.getEnd('y') }) svgCanvas.setStart({ x: svgCanvas.getEnd('x'), y: svgCanvas.getEnd('y') })
break break
// update path stretch line coordinates // update path stretch line coordinates
} case 'path': }
// fall through case 'path': // fall through
case 'pathedit': { case 'pathedit': {
x *= zoom x *= zoom
y *= zoom y *= zoom
@ -461,7 +472,8 @@ export const mouseMoveEvent = (evt) => {
svgCanvas.pathActions.mouseMove(x, y) svgCanvas.pathActions.mouseMove(x, y)
break break
} case 'textedit': { }
case 'textedit': {
x *= zoom x *= zoom
y *= zoom y *= zoom
// if (svgCanvas.getRubberBox() && svgCanvas.getRubberBox().getAttribute('display') !== 'none') { // if (svgCanvas.getRubberBox() && svgCanvas.getRubberBox().getAttribute('display') !== 'none') {
@ -476,7 +488,8 @@ export const mouseMoveEvent = (evt) => {
svgCanvas.textActions.mouseMove(mouseX, mouseY) svgCanvas.textActions.mouseMove(mouseX, mouseY)
break break
} case 'rotate': { }
case 'rotate': {
box = getBBox(selected) box = getBBox(selected)
cx = box.x + box.width / 2 cx = box.x + box.width / 2
cy = box.y + box.height / 2 cy = box.y + box.height / 2
@ -496,19 +509,21 @@ export const mouseMoveEvent = (evt) => {
svgCanvas.setRotationAngle(angle < -180 ? (360 + angle) : angle, true) svgCanvas.setRotationAngle(angle < -180 ? (360 + angle) : angle, true)
svgCanvas.call('transition', selectedElements) svgCanvas.call('transition', selectedElements)
break break
} default: }
default:
console.error(`unknown mode=${svgCanvas.getCurrentMode()}`)
break break
} }
/** /**
* The mouse has moved on the canvas area. * The mouse has moved on the canvas area.
* @event module:svgcanvas.SvgCanvas#event:ext_mouseMove * @event module:svgcanvas.SvgCanvas#event:ext_mouseMove
* @type {PlainObject} * @type {PlainObject}
* @property {MouseEvent} event The event object * @property {MouseEvent} event The event object
* @property {Float} mouse_x x coordinate on canvas * @property {Float} mouse_x x coordinate on canvas
* @property {Float} mouse_y y coordinate on canvas * @property {Float} mouse_y y coordinate on canvas
* @property {Element} selected Refers to the first selected element * @property {Element} selected Refers to the first selected element
*/ */
svgCanvas.runExtensions('mouseMove', /** @type {module:svgcanvas.SvgCanvas#event:ext_mouseMove} */ { svgCanvas.runExtensions('mouseMove', /** @type {module:svgcanvas.SvgCanvas#event:ext_mouseMove} */ {
event: evt, event: evt,
mouse_x: mouseX, mouse_x: mouseX,
@ -543,12 +558,13 @@ export const mouseOutEvent = () => {
* @returns {void} * @returns {void}
*/ */
export const mouseUpEvent = (evt) => { export const mouseUpEvent = (evt) => {
if (evt.button === 2) { return }
if (!svgCanvas.getStarted()) { return }
const selectedElements = svgCanvas.getSelectedElements() const selectedElements = svgCanvas.getSelectedElements()
const zoom = svgCanvas.getZoom() const zoom = svgCanvas.getZoom()
if (evt.button === 2) { return }
const tempJustSelected = svgCanvas.getJustSelected() const tempJustSelected = svgCanvas.getJustSelected()
svgCanvas.setJustSelected(null) svgCanvas.setJustSelected(null)
if (!svgCanvas.getStarted()) { return }
const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm()) const pt = transformPoint(evt.clientX, evt.clientY, svgCanvas.getrootSctm())
const mouseX = pt.x * zoom const mouseX = pt.x * zoom
const mouseY = pt.y * zoom const mouseY = pt.y * zoom
@ -566,7 +582,7 @@ export const mouseUpEvent = (evt) => {
svgCanvas.setStarted(false) svgCanvas.setStarted(false)
let t let t
switch (svgCanvas.getCurrentMode()) { switch (svgCanvas.getCurrentMode()) {
// intentionally fall-through to select here // intentionally fall-through to select here
case 'resize': case 'resize':
case 'multiselect': case 'multiselect':
if (svgCanvas.getRubberBox()) { if (svgCanvas.getRubberBox()) {
@ -577,9 +593,9 @@ export const mouseUpEvent = (evt) => {
// Fallthrough // Fallthrough
case 'select': case 'select':
if (selectedElements[0]) { if (selectedElements[0]) {
// if we only have one selected element // if we only have one selected element
if (!selectedElements[1]) { 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] const selected = selectedElements[0]
switch (selected.tagName) { switch (selected.tagName) {
case 'g': case 'g':
@ -587,6 +603,10 @@ export const mouseUpEvent = (evt) => {
case 'image': case 'image':
case 'foreignObject': case 'foreignObject':
break break
case 'text':
svgCanvas.setCurText('font_size', selected.getAttribute('font-size'))
svgCanvas.setCurText('font_family', selected.getAttribute('font-family'))
// fallthrough
default: default:
svgCanvas.setCurProperties('fill', selected.getAttribute('fill')) svgCanvas.setCurProperties('fill', selected.getAttribute('fill'))
svgCanvas.setCurProperties('fill_opacity', selected.getAttribute('fill-opacity')) 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_linejoin', selected.getAttribute('stroke-linejoin'))
svgCanvas.setCurProperties('stroke_linecap', selected.getAttribute('stroke-linecap')) 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) svgCanvas.selectorManager.requestSelector(selected).showGrips(true)
} }
// always recalculate dimensions to strip off stray identity transforms // always recalculate dimensions to strip off stray identity transforms
@ -612,13 +627,13 @@ export const mouseUpEvent = (evt) => {
for (let i = 0; i < len; ++i) { for (let i = 0; i < len; ++i) {
if (isNullish(selectedElements[i])) { break } 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 { } else {
t = evt.target t = evt.target
if (selectedElements[0].nodeName === 'path' && isNullish(selectedElements[1])) { if (selectedElements[0].nodeName === 'path' && isNullish(selectedElements[1])) {
svgCanvas.pathActions.select(selectedElements[0]) svgCanvas.pathActions.select(selectedElements[0])
// if it was a path // if it was a path
// else, if it was selected and this is a shift-click, remove it from selection // else, if it was selected and this is a shift-click, remove it from selection
} else if (evt.shiftKey && tempJustSelected !== t) { } else if (evt.shiftKey && tempJustSelected !== t) {
svgCanvas.removeFromSelection([t]) svgCanvas.removeFromSelection([t])
} }
@ -648,10 +663,10 @@ export const mouseUpEvent = (evt) => {
}) })
return return
} case 'fhpath': { } case 'fhpath': {
// Check that the path contains at least 2 points; a degenerate one-point path // Check that the path contains at least 2 points; a degenerate one-point path
// causes problems. // causes problems.
// Webkit ignores how we set the points attribute with commas and uses space // 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 // to separate all coordinates, see https://bugs.webkit.org/show_bug.cgi?id=29870
svgCanvas.setSumDistance(0) svgCanvas.setSumDistance(0)
svgCanvas.setControllPoint2('x', 0) svgCanvas.setControllPoint2('x', 0)
svgCanvas.setControllPoint2('y', 0) svgCanvas.setControllPoint2('y', 0)
@ -736,7 +751,7 @@ export const mouseUpEvent = (evt) => {
svgCanvas.textActions.start(element) svgCanvas.textActions.start(element)
break break
case 'path': { 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 element = null
// continue to be set to true so that mouseMove happens // continue to be set to true so that mouseMove happens
svgCanvas.setStarted(true) svgCanvas.setStarted(true)
@ -768,7 +783,7 @@ export const mouseUpEvent = (evt) => {
svgCanvas.call('changed', selectedElements) svgCanvas.call('changed', selectedElements)
break break
} default: } default:
// This could occur in an extension // This could occur in an extension
break break
} }
@ -786,7 +801,7 @@ export const mouseUpEvent = (evt) => {
mouse_y: mouseY mouse_y: mouseY
}, true) }, true)
extResult.forEach(function (r) { extResult.forEach((r) => {
if (r) { if (r) {
keep = r.keep || keep; keep = r.keep || keep;
({ element } = r) ({ element } = r)
@ -847,7 +862,7 @@ export const mouseUpEvent = (evt) => {
// Ideally this would be done on the endEvent of the animation, // Ideally this would be done on the endEvent of the animation,
// but that doesn't seem to be supported in Webkit // but that doesn't seem to be supported in Webkit
setTimeout(function () { setTimeout(() => {
if (cAni) { cAni.remove() } if (cAni) { cAni.remove() }
element.setAttribute('opacity', curShape.opacity) element.setAttribute('opacity', curShape.opacity)
element.setAttribute('style', 'pointer-events:inherit') element.setAttribute('style', 'pointer-events:inherit')
@ -996,6 +1011,13 @@ export const mouseDownEvent = (evt) => {
svgCanvas.setStartTransform(mouseTarget.getAttribute('transform')) svgCanvas.setStartTransform(mouseTarget.getAttribute('transform'))
const tlist = mouseTarget.transform.baseVal 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()) { switch (svgCanvas.getCurrentMode()) {
case 'select': case 'select':
svgCanvas.setStarted(true) svgCanvas.setStarted(true)
@ -1003,12 +1025,12 @@ export const mouseDownEvent = (evt) => {
if (rightClick) { svgCanvas.setStarted(false) } if (rightClick) { svgCanvas.setStarted(false) }
if (mouseTarget !== svgRoot) { 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)) { if (!selectedElements.includes(mouseTarget)) {
// only clear selection if shift is not pressed (otherwise, add // only clear selection if shift is not pressed (otherwise, add
// element to selection) // element to selection)
if (!evt.shiftKey) { 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.clearSelection(true)
} }
svgCanvas.addToSelection([mouseTarget]) svgCanvas.addToSelection([mouseTarget])
@ -1018,8 +1040,8 @@ export const mouseDownEvent = (evt) => {
// else if it's a path, go into pathedit mode in mouseup // else if it's a path, go into pathedit mode in mouseup
if (!rightClick) { if (!rightClick) {
// insert a dummy transform so if the element(s) are moved it will have // insert a dummy transform so if the element(s) are moved it will have
// a transform to use for its translate // a transform to use for its translate
for (const selectedElement of selectedElements) { for (const selectedElement of selectedElements) {
if (isNullish(selectedElement)) { continue } if (isNullish(selectedElement)) { continue }
const slist = selectedElement.transform?.baseVal const slist = selectedElement.transform?.baseVal
@ -1250,7 +1272,7 @@ export const mouseDownEvent = (evt) => {
svgCanvas.undoMgr.beginUndoableChange('transform', selectedElements) svgCanvas.undoMgr.beginUndoableChange('transform', selectedElements)
break break
default: default:
// This could occur in an extension // This could occur in an extension
break break
} }

View File

@ -25,7 +25,7 @@ let svgdoc_ = null
* @param {module:json.jsonContext} jsonContext * @param {module:json.jsonContext} jsonContext
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
svgdoc_ = canvas.getDOMDocument() svgdoc_ = canvas.getDOMDocument()
} }

View File

@ -14,7 +14,7 @@ let svgCanvas = null
* @param {module:paste-elem.pasteContext} pasteContext * @param {module:paste-elem.pasteContext} pasteContext
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
} }

View File

@ -26,7 +26,7 @@ let path = null
* @param {module:path-actions.svgCanvas} pathActionsContext * @param {module:path-actions.svgCanvas} pathActionsContext
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
} }

View File

@ -23,7 +23,7 @@ let svgCanvas = null
* @param {module:path-actions.svgCanvas} pathMethodsContext * @param {module:path-actions.svgCanvas} pathMethodsContext
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
} }

View File

@ -41,7 +41,7 @@ let svgCanvas
* @param {module:recalculate.EditorContext} editorContext * @param {module:recalculate.EditorContext} editorContext
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
} }
@ -53,7 +53,7 @@ export const init = function (canvas) {
* @param {Float} ty - The translation's y value * @param {Float} ty - The translation's y value
* @returns {void} * @returns {void}
*/ */
export const updateClipPath = function (attr, tx, ty) { export const updateClipPath = (attr, tx, ty) => {
const path = getRefElem(attr).firstChild const path = getRefElem(attr).firstChild
const cpXform = path.transform.baseVal const cpXform = path.transform.baseVal
const newxlate = svgCanvas.getSvgRoot().createSVGTransform() const newxlate = svgCanvas.getSvgRoot().createSVGTransform()
@ -71,7 +71,7 @@ export const updateClipPath = function (attr, tx, ty) {
* @param {Element} selected - The DOM element to recalculate * @param {Element} selected - The DOM element to recalculate
* @returns {Command} Undo command object with the resulting change * @returns {Command} Undo command object with the resulting change
*/ */
export const recalculateDimensions = function (selected) { export const recalculateDimensions = (selected) => {
if (!selected) return null if (!selected) return null
const svgroot = svgCanvas.getSvgRoot() const svgroot = svgCanvas.getSvgRoot()
const dataStorage = svgCanvas.getDataStorage() const dataStorage = svgCanvas.getDataStorage()
@ -215,12 +215,9 @@ export const recalculateDimensions = function (selected) {
} // switch on element type to get initial values } // switch on element type to get initial values
if (attrs.length) { if (attrs.length) {
Array.prototype.forEach.call(attrs, function (attr) { attrs.forEach((attr) => {
changes[attr] = selected.getAttribute(attr) changes[attr] = convertToNum(attr, selected.getAttribute(attr))
}) })
for (const [attr, val] of Object.entries(changes)) {
changes[attr] = convertToNum(attr, val)
}
} else if (gsvg) { } else if (gsvg) {
// GSVG exception // GSVG exception
changes = { changes = {
@ -271,6 +268,7 @@ export const recalculateDimensions = function (selected) {
} }
} }
} }
const N = tlist.numberOfItems const N = tlist.numberOfItems
let tx = 0; let ty = 0; let operation = 0 let tx = 0; let ty = 0; let operation = 0

View File

@ -35,7 +35,7 @@ let svgCanvas = null
* @param {module:selected-elem.elementContext} elementContext * @param {module:selected-elem.elementContext} elementContext
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
} }

View File

@ -26,7 +26,7 @@ let svgCanvas = null
* @param {module:selection.selectionContext} selectionContext * @param {module:selection.selectionContext} selectionContext
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
} }
@ -37,7 +37,7 @@ export const init = function (canvas) {
* @type {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection} * @type {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection}
* @fires module:selection.SvgCanvas#event:selected * @fires module:selection.SvgCanvas#event:selected
*/ */
export const clearSelectionMethod = function (noCall) { export const clearSelectionMethod = (noCall) => {
const selectedElements = svgCanvas.getSelectedElements() const selectedElements = svgCanvas.getSelectedElements()
selectedElements.forEach((elem) => { selectedElements.forEach((elem) => {
if (!elem) { if (!elem) {
@ -59,7 +59,7 @@ export const clearSelectionMethod = function (noCall) {
* @type {module:path.EditorContext#addToSelection} * @type {module:path.EditorContext#addToSelection}
* @fires module:selection.SvgCanvas#event:selected * @fires module:selection.SvgCanvas#event:selected
*/ */
export const addToSelectionMethod = function (elemsToAdd, showGrips) { export const addToSelectionMethod = (elemsToAdd, showGrips) => {
const selectedElements = svgCanvas.getSelectedElements() const selectedElements = svgCanvas.getSelectedElements()
if (!elemsToAdd.length) { if (!elemsToAdd.length) {
return return
@ -115,7 +115,7 @@ export const addToSelectionMethod = function (elemsToAdd, showGrips) {
// make sure the elements are in the correct order // make sure the elements are in the correct order
// See: https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition // 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) { if (a && b && a.compareDocumentPosition) {
return 3 - (b.compareDocumentPosition(a) & 6) return 3 - (b.compareDocumentPosition(a) & 6)
} }
@ -134,7 +134,7 @@ export const addToSelectionMethod = function (elemsToAdd, showGrips) {
* @name module:svgcanvas.SvgCanvas#getMouseTarget * @name module:svgcanvas.SvgCanvas#getMouseTarget
* @type {module:path.EditorContext#getMouseTarget} * @type {module:path.EditorContext#getMouseTarget}
*/ */
export const getMouseTargetMethod = function (evt) { export const getMouseTargetMethod = (evt) => {
if (!evt) { if (!evt) {
return null return null
} }
@ -212,12 +212,12 @@ export const getMouseTargetMethod = function (evt) {
* @returns {GenericArray<module:svgcanvas.ExtensionStatus>|module:svgcanvas.ExtensionStatus|false} See {@tutorial ExtensionDocs} on the ExtensionStatus. * @returns {GenericArray<module:svgcanvas.ExtensionStatus>|module:svgcanvas.ExtensionStatus|false} See {@tutorial ExtensionDocs} on the ExtensionStatus.
*/ */
/* eslint-enable max-len */ /* eslint-enable max-len */
export const runExtensionsMethod = function ( export const runExtensionsMethod = (
action, action,
vars, vars,
returnArray, returnArray,
nameFilter nameFilter
) { ) => {
let result = returnArray ? [] : false let result = returnArray ? [] : false
for (const [name, ext] of Object.entries(svgCanvas.getExtensions())) { for (const [name, ext] of Object.entries(svgCanvas.getExtensions())) {
if (nameFilter && !nameFilter(name)) { if (nameFilter && !nameFilter(name)) {
@ -245,7 +245,7 @@ export const runExtensionsMethod = function (
* @param {Element} parent - The parent DOM element to search within * @param {Element} parent - The parent DOM element to search within
* @returns {ElementAndBBox[]} An array with objects that include: * @returns {ElementAndBBox[]} An array with objects that include:
*/ */
export const getVisibleElementsAndBBoxes = function (parent) { export const getVisibleElementsAndBBoxes = (parent) => {
if (!parent) { if (!parent) {
const svgContent = svgCanvas.getSvgContent() const svgContent = svgCanvas.getSvgContent()
parent = svgContent.children // Prevent layers from being included parent = svgContent.children // Prevent layers from being included
@ -272,7 +272,7 @@ export const getVisibleElementsAndBBoxes = function (parent) {
* @param {SVGRect} rect * @param {SVGRect} rect
* @returns {Element[]|NodeList} Bbox elements * @returns {Element[]|NodeList} Bbox elements
*/ */
export const getIntersectionListMethod = function (rect) { export const getIntersectionListMethod = (rect) => {
const zoom = svgCanvas.getZoom() const zoom = svgCanvas.getZoom()
if (!svgCanvas.getRubberBox()) { if (!svgCanvas.getRubberBox()) {
return null return null
@ -335,7 +335,7 @@ export const getIntersectionListMethod = function (rect) {
* @param {Element} elem - SVG element to wrap * @param {Element} elem - SVG element to wrap
* @returns {void} * @returns {void}
*/ */
export const groupSvgElem = function (elem) { export const groupSvgElem = (elem) => {
const dataStorage = svgCanvas.getDataStorage() const dataStorage = svgCanvas.getDataStorage()
const g = document.createElementNS(NS.SVG, 'g') const g = document.createElementNS(NS.SVG, 'g')
elem.replaceWith(g) elem.replaceWith(g)
@ -350,7 +350,7 @@ export const groupSvgElem = function (elem) {
* @param {XMLDocument} newDoc - The SVG DOM document * @param {XMLDocument} newDoc - The SVG DOM document
* @returns {void} * @returns {void}
*/ */
export const prepareSvg = function (newDoc) { export const prepareSvg = (newDoc) => {
svgCanvas.sanitizeSvg(newDoc.documentElement) svgCanvas.sanitizeSvg(newDoc.documentElement)
// convert paths into absolute commands // convert paths into absolute commands
@ -371,7 +371,7 @@ export const prepareSvg = function (newDoc) {
* @fires module:svgcanvas.SvgCanvas#event:changed * @fires module:svgcanvas.SvgCanvas#event:changed
* @returns {void} * @returns {void}
*/ */
export const setRotationAngle = function (val, preventUndo) { export const setRotationAngle = (val, preventUndo) => {
const selectedElements = svgCanvas.getSelectedElements() const selectedElements = svgCanvas.getSelectedElements()
// ensure val is the proper type // ensure val is the proper type
val = Number.parseFloat(val) val = Number.parseFloat(val)
@ -441,7 +441,7 @@ export const setRotationAngle = function (val, preventUndo) {
* @fires module:svgcanvas.SvgCanvas#event:changed * @fires module:svgcanvas.SvgCanvas#event:changed
* @returns {void} * @returns {void}
*/ */
export const recalculateAllSelectedDimensions = function () { export const recalculateAllSelectedDimensions = () => {
const text = const text =
svgCanvas.getCurrentResizeMode() === 'none' ? 'position' : 'size' svgCanvas.getCurrentResizeMode() === 'none' ? 'position' : 'size'
const batchCmd = new BatchCommand(text) const batchCmd = new BatchCommand(text)

View File

@ -41,7 +41,7 @@ let svgCanvas = null
* @param {module:svg-exec.SvgCanvas#init} svgContext * @param {module:svg-exec.SvgCanvas#init} svgContext
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
} }

View File

@ -23,7 +23,7 @@ let svgCanvas = null
* @param {module:text-actions.svgCanvas} textActionsContext * @param {module:text-actions.svgCanvas} textActionsContext
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
} }

View File

@ -80,7 +80,7 @@ let svgroot_ = null
* @param {module:utilities.EditorContext} canvas * @param {module:utilities.EditorContext} canvas
* @returns {void} * @returns {void}
*/ */
export const init = function (canvas) { export const init = (canvas) => {
svgCanvas = canvas svgCanvas = canvas
svgroot_ = canvas.getSvgRoot() svgroot_ = canvas.getSvgRoot()
} }