diff --git a/src/svgcanvas/event.js b/src/svgcanvas/event.js index 6240dc66..0b973c3e 100644 --- a/src/svgcanvas/event.js +++ b/src/svgcanvas/event.js @@ -17,9 +17,7 @@ import { import { getTransformList } from './svgtransformlist.js'; -import { - supportsNonScalingStroke, isWebkit -} from '../common/browser.js'; +import { supportsNonScalingStroke } from '../common/browser.js'; import * as draw from './draw.js'; import * as pathModule from './path.js'; import * as hstry from './history.js'; @@ -84,16 +82,25 @@ export const getBsplinePoint = function (t) { * @returns {void} */ export const mouseMoveEvent = function (evt) { - const selectedElements = eventContext_.getSelectedElements(); + const selectedElements = eventContext_.getSelectedElements; const currentZoom = eventContext_.getCurrentZoom(); + const svgRoot = eventContext_.getSVGRoot(); + const svgCanvas = eventContext_.getCanvas(); + if (!eventContext_.getStarted()) { return; } - if (evt.button === 1 || eventContext_.getCanvas().spaceKey) { return; } - - let i; let xya; let cx; let cy; let dx; let dy; let len; let angle; let box; - let selected = selectedElements[0]; - const - pt = transformPoint(evt.pageX, evt.pageY, eventContext_.getrootSctm()); + if (evt.button === 1 || svgCanvas.spaceKey) { return; } + let i; + let xya; + let cx; + let cy; + let dx; + let dy; + let len; + let angle; + let box; + let selected = selectedElements()[0]; + const pt = transformPoint(evt.pageX, evt.pageY, eventContext_.getrootSctm()); const mouseX = pt.x * currentZoom; const mouseY = pt.y * currentZoom; const shape = getElem(eventContext_.getId()); @@ -115,7 +122,7 @@ export const mouseMoveEvent = function (evt) { // 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) { + if (selectedElements()[0] !== null) { dx = x - eventContext_.getStartX(); dy = y - eventContext_.getStartY(); if (eventContext_.getCurConfig().gridSnapping) { @@ -124,9 +131,9 @@ export const mouseMoveEvent = function (evt) { } if (dx !== 0 || dy !== 0) { - len = selectedElements.length; + len = selectedElements().length; for (i = 0; i < len; ++i) { - selected = selectedElements[i]; + selected = selectedElements()[i]; if (isNullish(selected)) { break; } // if (i === 0) { // const box = utilsGetBBox(selected); @@ -136,7 +143,7 @@ export const mouseMoveEvent = function (evt) { // update the dummy transform in our transform list // to be a translate - const xform = eventContext_.getSVGRoot().createSVGTransform(); + const xform = svgRoot.createSVGTransform(); tlist = getTransformList(selected); // Note that if Webkit and there's no ID for this // element, the dummy transform may have gotten lost. @@ -150,10 +157,10 @@ export const mouseMoveEvent = function (evt) { } // update our internal bbox that we're tracking while dragging - eventContext_.getCanvas().selectorManager.requestSelector(selected).resize(); + svgCanvas.selectorManager.requestSelector(selected).resize(); } - eventContext_.getCanvas().call('transition', selectedElements); + svgCanvas.call('transition', selectedElements()); } } break; @@ -171,7 +178,7 @@ export const mouseMoveEvent = function (evt) { // - if newList contains selected, do nothing // - if newList doesn't contain selected, remove it from selected // - for any newList that was not in selectedElements, add it to selected - const elemsToRemove = selectedElements.slice(); const elemsToAdd = []; + const elemsToRemove = selectedElements().slice(); const elemsToAdd = []; const newList = eventContext_.getIntersectionList(); // For every element in the intersection, add if not present in selectedElements. @@ -179,7 +186,7 @@ export const mouseMoveEvent = function (evt) { for (i = 0; i < len; ++i) { const intElem = newList[i]; // Found an element that was not selected before, so we should add it. - if (!selectedElements.includes(intElem)) { + if (!selectedElements().includes(intElem)) { elemsToAdd.push(intElem); } // Found an element that was already selected, so we shouldn't remove it. @@ -190,11 +197,11 @@ export const mouseMoveEvent = function (evt) { } if (elemsToRemove.length > 0) { - eventContext_.getCanvas().removeFromSelection(elemsToRemove); + svgCanvas.removeFromSelection(elemsToRemove); } if (elemsToAdd.length > 0) { - eventContext_.getCanvas().addToSelection(elemsToAdd); + svgCanvas.addToSelection(elemsToAdd); } break; @@ -253,9 +260,9 @@ export const mouseMoveEvent = function (evt) { } // update the transform list with translate,scale,translate - const translateOrigin = eventContext_.getSVGRoot().createSVGTransform(); - const scale = eventContext_.getSVGRoot().createSVGTransform(); - const translateBack = eventContext_.getSVGRoot().createSVGTransform(); + const translateOrigin = svgRoot.createSVGTransform(); + const scale = svgRoot.createSVGTransform(); + const translateBack = svgRoot.createSVGTransform(); if (eventContext_.getCurConfig().gridSnapping) { left = snapToGrid(left); @@ -285,8 +292,8 @@ export const mouseMoveEvent = function (evt) { tlist.replaceItem(translateOrigin, N - 1); } - eventContext_.getCanvas().selectorManager.requestSelector(selected).resize(); - eventContext_.getCanvas().call('transition', selectedElements); + svgCanvas.selectorManager.requestSelector(selected).resize(); + svgCanvas.call('transition', selectedElements()); break; } case 'zoom': { @@ -462,7 +469,7 @@ export const mouseMoveEvent = function (evt) { height: Math.abs(realY - eventContext_.getRStartY() * currentZoom) }, 100); } - eventContext_.getCanvas().pathActions.mouseMove(x, y); + svgCanvas.pathActions.mouseMove(x, y); break; } case 'textedit': { @@ -477,7 +484,7 @@ export const mouseMoveEvent = function (evt) { // }, 100); // } - eventContext_.getCanvas().textActions.mouseMove(mouseX, mouseY); + svgCanvas.textActions.mouseMove(mouseX, mouseY); break; } case 'rotate': { @@ -497,8 +504,8 @@ export const mouseMoveEvent = function (evt) { angle = Math.round(angle / snap) * snap; } - eventContext_.getCanvas().setRotationAngle(angle < -180 ? (360 + angle) : angle, true); - eventContext_.getCanvas().call('transition', selectedElements); + svgCanvas.setRotationAngle(angle < -180 ? (360 + angle) : angle, true); + svgCanvas.call('transition', selectedElements()); break; } default: break; @@ -513,7 +520,7 @@ export const mouseMoveEvent = function (evt) { * @property {Float} mouse_y y coordinate on canvas * @property {Element} selected Refers to the first selected element */ - eventContext_.getCanvas().runExtensions('mouseMove', /** @type {module:svgcanvas.SvgCanvas#event:ext_mouseMove} */ { + svgCanvas.runExtensions('mouseMove', /** @type {module:svgcanvas.SvgCanvas#event:ext_mouseMove} */ { event: evt, mouse_x: mouseX, mouse_y: mouseY, @@ -537,6 +544,7 @@ export const mouseMoveEvent = function (evt) { export const mouseUpEvent = function (evt) { const selectedElements = eventContext_.getSelectedElements(); const currentZoom = eventContext_.getCurrentZoom(); + const svgCanvas = eventContext_.getCanvas(); if (evt.button === 2) { return; } const tempJustSelected = eventContext_.getJustSelected(); eventContext_.setJustSelected(null); @@ -594,13 +602,13 @@ export const mouseUpEvent = function (evt) { eventContext_.setCurText('font_size', selected.getAttribute('font-size')); eventContext_.setCurText('font_family', selected.getAttribute('font-family')); } - eventContext_.getCanvas().selectorManager.requestSelector(selected).showGrips(true); + svgCanvas.selectorManager.requestSelector(selected).showGrips(true); // This shouldn't be necessary as it was done on mouseDown... - // eventContext_.getCanvas().call('selected', [selected]); + // svgCanvas.call('selected', [selected]); } // always recalculate dimensions to strip off stray identity transforms - eventContext_.getCanvas().recalculateAllSelectedDimensions(); + svgCanvas.recalculateAllSelectedDimensions(); // if it was being dragged/resized if (realX !== eventContext_.getRStartX() || realY !== eventContext_.getRStartY()) { const len = selectedElements.length; @@ -608,18 +616,18 @@ export const mouseUpEvent = function (evt) { if (isNullish(selectedElements[i])) { break; } if (!selectedElements[i].firstChild) { // Not needed for groups (incorrectly resizes elems), possibly not needed at all? - eventContext_.getCanvas().selectorManager.requestSelector(selectedElements[i]).resize(); + svgCanvas.selectorManager.requestSelector(selectedElements[i]).resize(); } } // no change in position/size, so maybe we should move to pathedit } else { t = evt.target; if (selectedElements[0].nodeName === 'path' && isNullish(selectedElements[1])) { - eventContext_.getCanvas().pathActions.select(selectedElements[0]); + 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 } else if (evt.shiftKey && tempJustSelected !== t) { - eventContext_.getCanvas().removeFromSelection([ t ]); + svgCanvas.removeFromSelection([ t ]); } } // no change in mouse position @@ -640,7 +648,7 @@ export const mouseUpEvent = function (evt) { eventContext_.getRubberBox().setAttribute('display', 'none'); } const factor = evt.shiftKey ? 0.5 : 2; - eventContext_.getCanvas().call('zoomed', { + svgCanvas.call('zoomed', { x: Math.min(eventContext_.getRStartX(), realX), y: Math.min(eventContext_.getRStartY(), realY), width: Math.abs(realX - eventContext_.getRStartX()), @@ -665,7 +673,7 @@ export const mouseUpEvent = function (evt) { const commaIndex = coords.indexOf(','); keep = commaIndex >= 0 ? coords.includes(',', commaIndex + 1) : coords.includes(' ', coords.indexOf(' ') + 1); if (keep) { - element = eventContext_.getCanvas().pathActions.smoothPolylineIntoPath(element); + element = svgCanvas.pathActions.smoothPolylineIntoPath(element); } break; } case 'line': { @@ -698,7 +706,7 @@ export const mouseUpEvent = function (evt) { case 'fhellipse': if ((eventContext_.getFreehand('maxx') - eventContext_.getFreehand('minx')) > 0 && (eventContext_.getFreehand('maxy') - eventContext_.getFreehand('miny')) > 0) { - element = eventContext_.getCanvas().addSVGElementFromJson({ + element = svgCanvas.addSVGElementFromJson({ element: 'ellipse', curStyles: true, attr: { @@ -709,14 +717,14 @@ export const mouseUpEvent = function (evt) { id: eventContext_.getId() } }); - eventContext_.getCanvas().call('changed', [ element ]); + svgCanvas.call('changed', [ element ]); keep = true; } break; case 'fhrect': if ((eventContext_.getFreehand('maxx') - eventContext_.getFreehand('minx')) > 0 && (eventContext_.getFreehand('maxy') - eventContext_.getFreehand('miny')) > 0) { - element = eventContext_.getCanvas().addSVGElementFromJson({ + element = svgCanvas.addSVGElementFromJson({ element: 'rect', curStyles: true, attr: { @@ -727,14 +735,14 @@ export const mouseUpEvent = function (evt) { id: eventContext_.getId() } }); - eventContext_.getCanvas().call('changed', [ element ]); + svgCanvas.call('changed', [ element ]); keep = true; } break; case 'text': keep = true; - eventContext_.getCanvas().selectOnly([ element ]); - eventContext_.getCanvas().textActions.start(element); + svgCanvas.selectOnly([ element ]); + svgCanvas.textActions.start(element); break; case 'path': { // set element to null here so that it is not removed nor finalized @@ -742,31 +750,31 @@ export const mouseUpEvent = function (evt) { // continue to be set to true so that mouseMove happens eventContext_.setStarted(true); - const res = eventContext_.getCanvas().pathActions.mouseUp(evt, element, mouseX, mouseY); + const res = svgCanvas.pathActions.mouseUp(evt, element, mouseX, mouseY); ({ element } = res); ({ keep } = res); break; } case 'pathedit': keep = true; element = null; - eventContext_.getCanvas().pathActions.mouseUp(evt); + svgCanvas.pathActions.mouseUp(evt); break; case 'textedit': keep = false; element = null; - eventContext_.getCanvas().textActions.mouseUp(evt, mouseX, mouseY); + svgCanvas.textActions.mouseUp(evt, mouseX, mouseY); break; case 'rotate': { keep = true; element = null; eventContext_.setCurrentMode('select'); - const batchCmd = eventContext_.getCanvas().undoMgr.finishUndoableChange(); + const batchCmd = svgCanvas.undoMgr.finishUndoableChange(); if (!batchCmd.isEmpty()) { eventContext_.addCommandToHistory(batchCmd); } // perform recalculation to weed out any stray identity transforms that might get stuck - eventContext_.getCanvas().recalculateAllSelectedDimensions(); - eventContext_.getCanvas().call('changed', selectedElements); + svgCanvas.recalculateAllSelectedDimensions(); + svgCanvas.call('changed', selectedElements); break; } default: // This could occur in an extension @@ -781,7 +789,7 @@ export const mouseUpEvent = function (evt) { * @property {Float} mouse_x x coordinate on canvas * @property {Float} mouse_y y coordinate on canvas */ - const extResult = eventContext_.getCanvas().runExtensions('mouseUp', { + const extResult = svgCanvas.runExtensions('mouseUp', { event: evt, mouse_x: mouseX, mouse_y: mouseY @@ -796,7 +804,7 @@ export const mouseUpEvent = function (evt) { }); if (!keep && !isNullish(element)) { - eventContext_.getCanvas().getCurrentDrawing().releaseId(eventContext_.getId()); + svgCanvas.getCurrentDrawing().releaseId(eventContext_.getId()); element.remove(); element = null; @@ -817,21 +825,21 @@ export const mouseUpEvent = function (evt) { t.id !== 'svgcanvas' && t.id !== 'svgroot' ) { // switch into "select" mode if we've clicked on an element - eventContext_.getCanvas().setMode('select'); - eventContext_.getCanvas().selectOnly([ t ], true); + svgCanvas.setMode('select'); + svgCanvas.selectOnly([ t ], true); } } else if (!isNullish(element)) { /** * @name module:svgcanvas.SvgCanvas#addedNew * @type {boolean} */ - eventContext_.getCanvas().addedNew = true; + svgCanvas.addedNew = true; if (useUnit) { convertAttrs(element); } let aniDur = 0.2; let cAni; - const curShape = eventContext_.getCanvas().getStyle(); + const curShape = svgCanvas.getStyle(); const opacAni = eventContext_.getOpacAni(); if (opacAni.beginElement && Number.parseFloat(element.getAttribute('opacity')) !== curShape.opacity) { cAni = opacAni.cloneNode(true); @@ -854,14 +862,14 @@ export const mouseUpEvent = function (evt) { element.setAttribute('style', 'pointer-events:inherit'); cleanupElement(element); if (eventContext_.getCurrentMode() === 'path') { - eventContext_.getCanvas().pathActions.toEditMode(element); + svgCanvas.pathActions.toEditMode(element); } else if (eventContext_.getCurConfig().selectNew) { - eventContext_.getCanvas().selectOnly([ element ], true); + svgCanvas.selectOnly([ element ], true); } // we create the insert command that is stored on the stack // undo means to call cmd.unapply(), redo means to call cmd.apply() eventContext_.addCommandToHistory(new InsertElementCommand(element)); - eventContext_.getCanvas().call('changed', [ element ]); + svgCanvas.call('changed', [ element ]); }, aniDur * 1000); } eventContext_.setStartTransform(null); @@ -871,13 +879,14 @@ export const dblClickEvent = function (evt) { const selectedElements = eventContext_.getSelectedElements(); const evtTarget = evt.target; const parent = evtTarget.parentNode; + const svgCanvas = eventContext_.getCanvas(); - let mouseTarget = eventContext_.getCanvas().getMouseTarget(evt); + let mouseTarget = svgCanvas.getMouseTarget(evt); const { tagName } = mouseTarget; if (tagName === 'text' && eventContext_.getCurrentMode() !== 'textedit') { const pt = transformPoint(evt.pageX, evt.pageY, eventContext_.getrootSctm()); - eventContext_.getCanvas().textActions.select(mouseTarget, pt.x, pt.y); + svgCanvas.textActions.select(mouseTarget, pt.x, pt.y); } // Do nothing if already in current group @@ -888,9 +897,9 @@ export const dblClickEvent = function (evt) { // this (similar to editing rotated paths) // Ungroup and regroup - eventContext_.getCanvas().pushGroupProperties(mouseTarget); + svgCanvas.pushGroupProperties(mouseTarget); mouseTarget = selectedElements[0]; - eventContext_.getCanvas().clearSelection(true); + svgCanvas.clearSelection(true); } // Reset context if (eventContext_.getCurrentGroup()) { @@ -898,8 +907,8 @@ export const dblClickEvent = function (evt) { } if ((parent.tagName !== 'g' && parent.tagName !== 'a') || - parent === eventContext_.getCanvas().getCurrentDrawing().getCurrentLayer() || - mouseTarget === eventContext_.getCanvas().selectorManager.selectorParentGroup + parent === svgCanvas.getCurrentDrawing().getCurrentLayer() || + mouseTarget === svgCanvas.selectorManager.selectorParentGroup ) { // Escape from in-group edit return; @@ -919,17 +928,19 @@ export const dblClickEvent = function (evt) { */ export const mouseDownEvent = function (evt) { const dataStorage = eventContext_.getDataStorage(); - const selectedElements = eventContext_.getSelectedElements(); + const selectedElements = eventContext_.getSelectedElements; const currentZoom = eventContext_.getCurrentZoom(); - const curShape = eventContext_.getCanvas().getStyle(); const svgCanvas = eventContext_.getCanvas(); + const curShape = svgCanvas.getStyle(); + const svgRoot = eventContext_.getSVGRoot(); const { $id } = svgCanvas; - if (eventContext_.getCanvas().spaceKey || evt.button === 1) { return; } - const rightClick = evt.button === 2; + if (svgCanvas.spaceKey || evt.button === 1) { return; } + + const rightClick = (evt.button === 2); if (evt.altKey) { // duplicate when dragging - eventContext_.getCanvas().cloneSelectedElements(0, 0); + svgCanvas.cloneSelectedElements(0, 0); } eventContext_.setRootSctm($id('svgcontent').querySelector('g').getScreenCTM().inverse()); @@ -947,7 +958,7 @@ export const mouseDownEvent = function (evt) { let x = mouseX / currentZoom; let y = mouseY / currentZoom; - let mouseTarget = eventContext_.getCanvas().getMouseTarget(evt); + let mouseTarget = svgCanvas.getMouseTarget(evt); if (mouseTarget.tagName === 'a' && mouseTarget.childNodes.length === 1) { mouseTarget = mouseTarget.firstChild; @@ -971,18 +982,19 @@ export const mouseDownEvent = function (evt) { // if it is a selector grip, then it must be a single element selected, // set the mouseTarget to that and update the mode to rotate/resize - if (mouseTarget === eventContext_.getCanvas().selectorManager.selectorParentGroup && !isNullish(selectedElements[0])) { + if (mouseTarget === svgCanvas.selectorManager.selectorParentGroup && !isNullish(selectedElements()[0])) { const grip = evt.target; const griptype = dataStorage.get(grip, 'type'); // rotating if (griptype === 'rotate') { eventContext_.setCurrentMode('rotate'); + // eventContext_.setCurrentRotateMode(dataStorage.get(grip, 'dir')); // resizing } else if (griptype === 'resize') { eventContext_.setCurrentMode('resize'); eventContext_.setCurrentResizeMode(dataStorage.get(grip, 'dir')); } - mouseTarget = selectedElements[0]; + mouseTarget = selectedElements()[0]; } eventContext_.setStartTransform(mouseTarget.getAttribute('transform')); @@ -994,39 +1006,39 @@ export const mouseDownEvent = function (evt) { eventContext_.setCurrentResizeMode('none'); if (rightClick) { eventContext_.setStarted(false); } - if (mouseTarget !== eventContext_.getSVGRoot()) { + if (mouseTarget !== svgRoot) { // 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 // element to selection) if (!evt.shiftKey) { // No need to do the call here as it will be done on addToSelection - eventContext_.getCanvas().clearSelection(true); + svgCanvas.clearSelection(true); } - eventContext_.getCanvas().addToSelection([ mouseTarget ]); + svgCanvas.addToSelection([ mouseTarget ]); eventContext_.setJustSelected(mouseTarget); - eventContext_.getCanvas().pathActions.clear(); + svgCanvas.pathActions.clear(); } // 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 - for (const selectedElement of selectedElements) { + for (const selectedElement of selectedElements()) { if (isNullish(selectedElement)) { continue; } const slist = getTransformList(selectedElement); if (slist.numberOfItems) { - slist.insertItemBefore(eventContext_.getSVGRoot().createSVGTransform(), 0); + slist.insertItemBefore(svgRoot.createSVGTransform(), 0); } else { - slist.appendItem(eventContext_.getSVGRoot().createSVGTransform()); + slist.appendItem(svgRoot.createSVGTransform()); } } } } else if (!rightClick) { - eventContext_.getCanvas().clearSelection(); + svgCanvas.clearSelection(); eventContext_.setCurrentMode('multiselect'); if (isNullish(eventContext_.getRubberBox())) { - eventContext_.setRubberBox(eventContext_.getCanvas().selectorManager.getRubberBandBox()); + eventContext_.setRubberBox(svgCanvas.selectorManager.getRubberBandBox()); } eventContext_.setRStartX(eventContext_.getRStartX() * currentZoom); eventContext_.setRStartY(eventContext_.getRStartY() * currentZoom); @@ -1043,7 +1055,7 @@ export const mouseDownEvent = function (evt) { case 'zoom': eventContext_.setStarted(true); if (isNullish(eventContext_.getRubberBox())) { - eventContext_.setRubberBox(eventContext_.getCanvas().selectorManager.getRubberBandBox()); + eventContext_.setRubberBox(svgCanvas.selectorManager.getRubberBandBox()); } assignAttributes(eventContext_.getRubberBox(), { x: realX * currentZoom, @@ -1072,43 +1084,13 @@ export const mouseDownEvent = function (evt) { const pos = getRotationAngle(mouseTarget) ? 1 : 0; if (hasMatrixTransform(tlist)) { - tlist.insertItemBefore(eventContext_.getSVGRoot().createSVGTransform(), pos); - tlist.insertItemBefore(eventContext_.getSVGRoot().createSVGTransform(), pos); - tlist.insertItemBefore(eventContext_.getSVGRoot().createSVGTransform(), pos); + tlist.insertItemBefore(svgRoot.createSVGTransform(), pos); + tlist.insertItemBefore(svgRoot.createSVGTransform(), pos); + tlist.insertItemBefore(svgRoot.createSVGTransform(), pos); } else { - tlist.appendItem(eventContext_.getSVGRoot().createSVGTransform()); - tlist.appendItem(eventContext_.getSVGRoot().createSVGTransform()); - tlist.appendItem(eventContext_.getSVGRoot().createSVGTransform()); - - if (supportsNonScalingStroke()) { - // Handle crash for newer Chrome and Safari 6 (Mobile and Desktop): - // https://code.google.com/p/svg-edit/issues/detail?id=904 - // Chromium issue: https://code.google.com/p/chromium/issues/detail?id=114625 - // TODO: Remove this workaround once vendor fixes the issue - const iswebkit = isWebkit(); - - let delayedStroke; - if (iswebkit) { - delayedStroke = function (ele) { - const stroke_ = ele.getAttribute('stroke'); - ele.removeAttribute('stroke'); - // Re-apply stroke after delay. Anything higher than 1 seems to cause flicker - if (stroke_ !== null) setTimeout(function () { ele.setAttribute('stroke', stroke_); }, 0); - }; - } - mouseTarget.style.vectorEffect = 'non-scaling-stroke'; - if (iswebkit) { delayedStroke(mouseTarget); } - - const all = mouseTarget.getElementsByTagName('*'); - const len = all.length; - for (let i = 0; i < len; i++) { - if (!all[i].style) { // mathML - continue; - } - all[i].style.vectorEffect = 'non-scaling-stroke'; - if (iswebkit) { delayedStroke(all[i]); } - } - } + tlist.appendItem(svgRoot.createSVGTransform()); + tlist.appendItem(svgRoot.createSVGTransform()); + tlist.appendItem(svgRoot.createSVGTransform()); } break; } @@ -1124,12 +1106,12 @@ export const mouseDownEvent = function (evt) { eventContext_.setDAttr(realX + ',' + realY + ' '); // Commented out as doing nothing now: // strokeW = parseFloat(curShape.stroke_width) === 0 ? 1 : curShape.stroke_width; - eventContext_.getCanvas().addSVGElementFromJson({ + svgCanvas.addSVGElementFromJson({ element: 'polyline', curStyles: true, attr: { points: eventContext_.getDAttr(), - id: eventContext_.getCanvas().getNextId(), + id: svgCanvas.getNextId(), fill: 'none', opacity: curShape.opacity / 2, 'stroke-linecap': 'round', @@ -1143,14 +1125,14 @@ export const mouseDownEvent = function (evt) { break; case 'image': { eventContext_.setStarted(true); - const newImage = eventContext_.getCanvas().addSVGElementFromJson({ + const newImage = svgCanvas.addSVGElementFromJson({ element: 'image', attr: { x, y, width: 0, height: 0, - id: eventContext_.getCanvas().getNextId(), + id: svgCanvas.getNextId(), opacity: curShape.opacity / 2, style: 'pointer-events:inherit' } @@ -1166,7 +1148,7 @@ export const mouseDownEvent = function (evt) { eventContext_.setStarted(true); eventContext_.setStartX(x); eventContext_.setStartY(y); - eventContext_.getCanvas().addSVGElementFromJson({ + svgCanvas.addSVGElementFromJson({ element: 'rect', curStyles: true, attr: { @@ -1174,7 +1156,7 @@ export const mouseDownEvent = function (evt) { y, width: 0, height: 0, - id: eventContext_.getCanvas().getNextId(), + id: svgCanvas.getNextId(), opacity: curShape.opacity / 2 } }); @@ -1182,7 +1164,7 @@ export const mouseDownEvent = function (evt) { case 'line': { eventContext_.setStarted(true); const strokeW = Number(curShape.stroke_width) === 0 ? 1 : curShape.stroke_width; - eventContext_.getCanvas().addSVGElementFromJson({ + svgCanvas.addSVGElementFromJson({ element: 'line', curStyles: true, attr: { @@ -1190,7 +1172,7 @@ export const mouseDownEvent = function (evt) { y1: y, x2: x, y2: y, - id: eventContext_.getCanvas().getNextId(), + id: svgCanvas.getNextId(), stroke: curShape.stroke, 'stroke-width': strokeW, 'stroke-dasharray': curShape.stroke_dasharray, @@ -1205,21 +1187,21 @@ export const mouseDownEvent = function (evt) { break; } case 'circle': eventContext_.setStarted(true); - eventContext_.getCanvas().addSVGElementFromJson({ + svgCanvas.addSVGElementFromJson({ element: 'circle', curStyles: true, attr: { cx: x, cy: y, r: 0, - id: eventContext_.getCanvas().getNextId(), + id: svgCanvas.getNextId(), opacity: curShape.opacity / 2 } }); break; case 'ellipse': eventContext_.setStarted(true); - eventContext_.getCanvas().addSVGElementFromJson({ + svgCanvas.addSVGElementFromJson({ element: 'ellipse', curStyles: true, attr: { @@ -1227,20 +1209,20 @@ export const mouseDownEvent = function (evt) { cy: y, rx: 0, ry: 0, - id: eventContext_.getCanvas().getNextId(), + id: svgCanvas.getNextId(), opacity: curShape.opacity / 2 } }); break; case 'text': eventContext_.setStarted(true); - /* const newText = */ eventContext_.getCanvas().addSVGElementFromJson({ + /* const newText = */ svgCanvas.addSVGElementFromJson({ element: 'text', curStyles: true, attr: { x, y, - id: eventContext_.getCanvas().getNextId(), + id: svgCanvas.getNextId(), fill: eventContext_.getCurText('fill'), 'stroke-width': eventContext_.getCurText('stroke_width'), 'font-size': eventContext_.getCurText('font_size'), @@ -1257,19 +1239,19 @@ export const mouseDownEvent = function (evt) { case 'pathedit': eventContext_.setStartX(eventContext_.getStartX() * currentZoom); eventContext_.setStartY(eventContext_.getStartY() * currentZoom); - eventContext_.getCanvas().pathActions.mouseDown(evt, mouseTarget, eventContext_.getStartX(), eventContext_.getStartY()); + svgCanvas.pathActions.mouseDown(evt, mouseTarget, eventContext_.getStartX(), eventContext_.getStartY()); eventContext_.setStarted(true); break; case 'textedit': eventContext_.setStartX(eventContext_.getStartX() * currentZoom); eventContext_.setStartY(eventContext_.getStartY() * currentZoom); - eventContext_.getCanvas().textActions.mouseDown(evt, mouseTarget, eventContext_.getStartX(), eventContext_.getStartY()); + svgCanvas.textActions.mouseDown(evt, mouseTarget, eventContext_.getStartX(), eventContext_.getStartY()); eventContext_.setStarted(true); break; case 'rotate': eventContext_.setStarted(true); // we are starting an undoable change (a drag-rotation) - eventContext_.getCanvas().undoMgr.beginUndoableChange('transform', selectedElements); + svgCanvas.undoMgr.beginUndoableChange('transform', selectedElements()); break; default: // This could occur in an extension @@ -1285,11 +1267,11 @@ export const mouseDownEvent = function (evt) { * @property {Float} start_y y coordinate on canvas * @property {Element[]} selectedElements An array of the selected Elements */ - const extResult = eventContext_.getCanvas().runExtensions('mouseDown', { + const extResult = svgCanvas.runExtensions('mouseDown', { event: evt, start_x: eventContext_.getStartX(), start_y: eventContext_.getStartY(), - selectedElements + selectedElements: selectedElements() }, true); extResult.forEach(function(r){ @@ -1380,9 +1362,9 @@ export const DOMMouseScrollEvent = function (e) { y: topLeftNewCanvas.y - rulerwidth + editorFullH / 2 }; - eventContext_.getCanvas().setZoom(zoomlevel); + svgCanvas.setZoom(zoomlevel); document.getElementById('zoom').value = ((zoomlevel * 100).toFixed(1)); - eventContext_.getCanvas().call('updateCanvas', { center: false, newCtr }); - eventContext_.getCanvas().call('zoomDone'); + svgCanvas.call('updateCanvas', { center: false, newCtr }); + svgCanvas.call('zoomDone'); }; diff --git a/src/svgcanvas/svg-exec.js b/src/svgcanvas/svg-exec.js index c5e5b100..a83c6f68 100644 --- a/src/svgcanvas/svg-exec.js +++ b/src/svgcanvas/svg-exec.js @@ -36,6 +36,7 @@ const { let svgContext_ = null; let $id = null; +let svgCanvas = null; /** * @function module:svg-exec.init @@ -44,7 +45,7 @@ let $id = null; */ export const init = function (svgContext) { svgContext_ = svgContext; - const svgCanvas = svgContext_.getCanvas(); + svgCanvas = svgContext_.getCanvas(); $id = svgCanvas.$id; }; @@ -55,9 +56,9 @@ export const init = function (svgContext) { */ export const svgCanvasToString = function () { // keep calling it until there are none to remove - while (svgContext_.getCanvas().removeUnusedDefElems() > 0) { } // eslint-disable-line no-empty + while (svgCanvas.removeUnusedDefElems() > 0) { } // eslint-disable-line no-empty - svgContext_.getCanvas().pathActions.clear(true); + svgCanvas.pathActions.clear(true); // Keep SVG-Edit comment on top const childNodesElems = svgContext_.getSVGContent().childNodes; @@ -70,7 +71,7 @@ export const svgCanvasToString = function () { // Move out of in-group editing mode if (svgContext_.getCurrentGroup()) { draw.leaveContext(); - svgContext_.getCanvas().selectOnly([ svgContext_.getCurrentGroup() ]); + svgCanvas.selectOnly([ svgContext_.getCurrentGroup() ]); } const nakedSvgs = []; @@ -92,12 +93,12 @@ export const svgCanvasToString = function () { element.replaceWith(svg); } }); - const output = this.svgToString(svgContext_.getSVGContent(), 0); + const output = svgCanvas.svgToString(svgContext_.getSVGContent(), 0); // Rewrap gsvg if (nakedSvgs.length) { Array.prototype.forEach.call(nakedSvgs, function (el) { - svgContext_.getCanvas().groupSvgElem(el); + svgCanvas.groupSvgElem(el); }); } @@ -130,7 +131,7 @@ export const svgToString = function (elem, indent) { out.push('<'); out.push(elem.nodeName); if (elem.id === 'svgcontent') { // Process root element separately - const res = svgContext_.getCanvas().getResolution(); + const res = svgCanvas.getResolution(); const vb = ''; // TODO: Allow this by dividing all values by current baseVal @@ -211,7 +212,7 @@ export const svgToString = function (elem, indent) { if (attrVal.startsWith('pointer-events')) { continue; } if (attr.localName === 'class' && attrVal.startsWith('se_')) { continue; } out.push(' '); - if (attr.localName === 'd') { attrVal = svgContext_.getCanvas().pathActions.convertPath(elem, true); } + if (attr.localName === 'd') { attrVal = svgCanvas.pathActions.convertPath(elem, true); } if (!isNaN(attrVal)) { attrVal = shortFloat(attrVal); } else if (unitRe.test(attrVal)) { @@ -249,7 +250,7 @@ export const svgToString = function (elem, indent) { switch (child.nodeType) { case 1: // element node out.push('\n'); - out.push(this.svgToString(child, indent)); + out.push(svgCanvas.svgToString(child, indent)); break; case 3: { // text node const str = child.nodeValue.replace(/^\s+|\s+$/g, ''); @@ -311,7 +312,7 @@ export const setSvgString = function (xmlString, preventUndo) { return false; } - this.prepareSvg(newDoc); + svgCanvas.prepareSvg(newDoc); const batchCmd = new BatchCommand('Change Source'); @@ -333,10 +334,10 @@ export const setSvgString = function (xmlString, preventUndo) { svgContext_.getSVGRoot().append(svgContext_.getSVGContent()); const content = svgContext_.getSVGContent(); - svgContext_.getCanvas().current_drawing_ = new draw.Drawing(svgContext_.getSVGContent(), svgContext_.getIdPrefix()); + svgCanvas.current_drawing_ = new draw.Drawing(svgContext_.getSVGContent(), svgContext_.getIdPrefix()); // retrieve or set the nonce - const nonce = svgContext_.getCanvas().getCurrentDrawing().getNonce(); + const nonce = svgCanvas.getCurrentDrawing().getNonce(); if (nonce) { svgContext_.call('setnonce', nonce); } else { @@ -347,7 +348,7 @@ export const setSvgString = function (xmlString, preventUndo) { const elements = content.querySelectorAll('image'); Array.prototype.forEach.call(elements, function (image) { preventClickDefault(image); - const val = svgContext_.getCanvas().getHref(image); + const val = svgCanvas.getHref(image); if (val) { if (val.startsWith('data:')) { // Check if an SVG-edit data URI @@ -364,7 +365,7 @@ export const setSvgString = function (xmlString, preventUndo) { } } // Add to encodableImages if it loads - svgContext_.getCanvas().embedImage(val); + svgCanvas.embedImage(val); } }); @@ -374,15 +375,15 @@ export const setSvgString = function (xmlString, preventUndo) { // Skip if it's in a if (getClosest(element.parentNode, 'defs')) { return; } - svgContext_.getCanvas().uniquifyElems(element); + svgCanvas.uniquifyElems(element); // Check if it already has a gsvg group const pa = element.parentNode; if (pa.childNodes.length === 1 && pa.nodeName === 'g') { dataStorage.put(pa, 'gsvg', element); - pa.id = pa.id || svgContext_.getCanvas().getNextId(); + pa.id = pa.id || svgCanvas.getNextId(); } else { - svgContext_.getCanvas().groupSvgElem(element); + svgCanvas.groupSvgElem(element); } }); @@ -398,9 +399,9 @@ export const setSvgString = function (xmlString, preventUndo) { // Set ref element for elements // TODO: This should also be done if the object is re-added through "redo" - svgContext_.getCanvas().setUseData(content); + svgCanvas.setUseData(content); - svgContext_.getCanvas().convertGradients(content); + svgCanvas.convertGradients(content); const attrs = { id: 'svgcontent', @@ -437,7 +438,7 @@ export const setSvgString = function (xmlString, preventUndo) { Array.prototype.forEach.call(chiElems, function (chiElem) { const visElems = chiElem.querySelectorAll(svgContext_.getVisElems()); Array.prototype.forEach.call(visElems, function (elem) { - if (!elem.id) { elem.id = svgContext_.getCanvas().getNextId(); } + if (!elem.id) { elem.id = svgCanvas.getNextId(); } }); }); @@ -456,8 +457,8 @@ export const setSvgString = function (xmlString, preventUndo) { for (const [ key, value ] of Object.entries(attrs)) { content.setAttribute(key, value); } - this.contentW = attrs.width; - this.contentH = attrs.height; + svgCanvas.contentW = attrs.width; + svgCanvas.contentH = attrs.height; batchCmd.addSubCommand(new InsertElementCommand(svgContext_.getSVGContent())); // update root to the correct size @@ -471,9 +472,9 @@ export const setSvgString = function (xmlString, preventUndo) { // reset transform lists resetListMap(); - svgContext_.getCanvas().clearSelection(); + svgCanvas.clearSelection(); pathModule.clearData(); - svgContext_.getSVGRoot().append(svgContext_.getCanvas().selectorManager.selectorParentGroup); + svgContext_.getSVGRoot().append(svgCanvas.selectorManager.selectorParentGroup); if (!preventUndo) svgContext_.addCommandToHistory(batchCmd); svgContext_.call('changed', [ svgContext_.getSVGContent() ]); @@ -524,7 +525,7 @@ export const importSvgString = function (xmlString) { // convert string into XML document const newDoc = text2xml(xmlString); - this.prepareSvg(newDoc); + svgCanvas.prepareSvg(newDoc); // import new svg document into our document // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() @@ -532,7 +533,7 @@ export const importSvgString = function (xmlString) { ? svgContext_.getDOMDocument().adoptNode(newDoc.documentElement) : svgContext_.getDOMDocument().importNode(newDoc.documentElement, true); - svgContext_.getCanvas().uniquifyElems(svg); + svgCanvas.uniquifyElems(svg); const innerw = convertToNum('width', svg.getAttribute('width')); const innerh = convertToNum('height', svg.getAttribute('height')); @@ -574,7 +575,7 @@ export const importSvgString = function (xmlString) { for (const attr of attrs) { // Ok for `NamedNodeMap` symbol.setAttribute(attr.nodeName, attr.value); } - symbol.id = svgContext_.getCanvas().getNextId(); + symbol.id = svgCanvas.getNextId(); // Store data svgContext_.setImportIds(uid, { @@ -587,18 +588,18 @@ export const importSvgString = function (xmlString) { } useEl = svgContext_.getDOMDocument().createElementNS(NS.SVG, 'use'); - useEl.id = svgContext_.getCanvas().getNextId(); - svgContext_.getCanvas().setHref(useEl, '#' + symbol.id); + useEl.id = svgCanvas.getNextId(); + svgCanvas.setHref(useEl, '#' + symbol.id); - (svgContext_.getCurrentGroup() || svgContext_.getCanvas().getCurrentDrawing().getCurrentLayer()).append(useEl); + (svgContext_.getCurrentGroup() || svgCanvas.getCurrentDrawing().getCurrentLayer()).append(useEl); batchCmd.addSubCommand(new InsertElementCommand(useEl)); - svgContext_.getCanvas().clearSelection(); + svgCanvas.clearSelection(); useEl.setAttribute('transform', ts); recalculateDimensions(useEl); dataStorage.put(useEl, 'symbol', symbol); dataStorage.put(useEl, 'ref', symbol); - svgContext_.getCanvas().addToSelection([ useEl ]); + svgCanvas.addToSelection([ useEl ]); // TODO: Find way to add this in a recalculateDimensions-parsable way // if (vb[0] !== 0 || vb[1] !== 0) { @@ -646,7 +647,7 @@ export const embedImage = function (src) { } catch (e) { svgContext_.setEncodableImages(src, false); } - svgContext_.getCanvas().setGoodImage(src); + svgCanvas.setGoodImage(src); resolve(svgContext_.getEncodableImages(src)); }); imgI.addEventListener("error", (e) => { @@ -667,10 +668,10 @@ export const embedImage = function (src) { */ export const save = function (opts) { // remove the selected outline before serializing - svgContext_.getCanvas().clearSelection(); + svgCanvas.clearSelection(); // Update save options if provided if (opts) { - const saveOptions = svgContext_.getCanvas().mergeDeep(svgContext_.getSvgOption(), opts); + const saveOptions = svgCanvas.mergeDeep(svgContext_.getSvgOption(), opts); for (const [ key, value ] of Object.entries(saveOptions)) { svgContext_.setSvgOption(key, value); } @@ -678,7 +679,7 @@ export const save = function (opts) { svgContext_.setSvgOption('apply', true); // no need for doctype, see https://jwatt.org/svg/authoring/#doctype-declaration - const str = svgContext_.getCanvas().svgCanvasToString(); + const str = svgCanvas.svgCanvasToString(); svgContext_.call('saved', str); }; /** @@ -694,7 +695,7 @@ export const save = function (opts) { function getIssues() { const uiStrings = svgContext_.getUIStrings(); // remove the selected outline before serializing - svgContext_.getCanvas().clearSelection(); + svgCanvas.clearSelection(); // Check for known CanVG issues const issues = []; @@ -752,7 +753,7 @@ export const rasterExport = async function (imgType, quality, exportWindowName, const type = imgType === 'ICO' ? 'BMP' : (imgType || 'PNG'); const mimeType = 'image/' + type.toLowerCase(); const { issues, issueCodes } = getIssues(); - const svg = this.svgCanvasToString(); + const svg = svgCanvas.svgCanvasToString(); if (!$id('export_canvas')) { const canvasEx = document.createElement('CANVAS'); @@ -761,8 +762,8 @@ export const rasterExport = async function (imgType, quality, exportWindowName, document.body.appendChild(canvasEx); } const c = $id('export_canvas'); - c.style.width = svgContext_.getCanvas().contentW + "px"; - c.style.height = svgContext_.getCanvas().contentH + "px"; + c.style.width = svgCanvas.contentW + "px"; + c.style.height = svgCanvas.contentH + "px"; const canvg = svgContext_.getcanvg(); const ctx = c.getContext('2d'); const v = canvg.fromString(ctx, svg); @@ -837,7 +838,7 @@ export const exportPDF = async ( exportWindowName, outputType = isChrome() ? 'save' : undefined ) => { - const res = svgContext_.getCanvas().getResolution(); + const res = svgCanvas.getResolution(); const orientation = res.w > res.h ? 'landscape' : 'portrait'; const unit = 'pt'; // curConfig.baseUnit; // We could use baseUnit, but that is presumably not intended for export purposes @@ -848,7 +849,7 @@ export const exportPDF = async ( format: [ res.w, res.h ] // , compressPdf: true }); - const docTitle = svgContext_.getCanvas().getDocumentTitle(); + const docTitle = svgCanvas.getDocumentTitle(); doc.setProperties({ title: docTitle /* , subject: '', @@ -908,7 +909,7 @@ export const uniquifyElemsMethod = function (g) { const attrnode = n.getAttributeNode(attr); if (attrnode) { // the incoming file has been sanitized, so we should be able to safely just strip off the leading # - const url = svgContext_.getCanvas().getUrlFromAttr(attrnode.value); + const url = svgCanvas.getUrlFromAttr(attrnode.value); const refid = url ? url.substr(1) : null; if (refid) { if (!(refid in ids)) { @@ -921,7 +922,7 @@ export const uniquifyElemsMethod = function (g) { }); // check xlink:href now - const href = svgContext_.getCanvas().getHref(n); + const href = svgCanvas.getHref(n); // TODO: what if an or element refers to an element internally? if (href && refElems.includes(n.nodeName)) { const refid = href.substr(1); @@ -941,7 +942,7 @@ export const uniquifyElemsMethod = function (g) { if (!oldid) { continue; } const { elem } = ids[oldid]; if (elem) { - const newid = svgContext_.getCanvas().getNextId(); + const newid = svgCanvas.getNextId(); // assign element its new id elem.id = newid; @@ -959,7 +960,7 @@ export const uniquifyElemsMethod = function (g) { let k = hreffers.length; while (k--) { const hreffer = hreffers[k]; - svgContext_.getCanvas().setHref(hreffer, '#' + newid); + svgCanvas.setHref(hreffer, '#' + newid); } } } @@ -981,8 +982,8 @@ export const setUseDataMethod = function (parent) { Array.prototype.forEach.call(elems, function (el, _) { const dataStorage = svgContext_.getDataStorage(); - const id = svgContext_.getCanvas().getHref(el).substr(1); - const refElem = svgContext_.getCanvas().getElem(id); + const id = svgCanvas.getHref(el).substr(1); + const refElem = svgCanvas.getElem(id); if (!refElem) { return; } dataStorage.put(el, 'ref', refElem); if (refElem.tagName === 'symbol' || refElem.tagName === 'svg') { @@ -1016,7 +1017,7 @@ export const removeUnusedDefElemsMethod = function () { for (i = 0; i < allLen; i++) { const el = allEls[i]; for (j = 0; j < alen; j++) { - const ref = svgContext_.getCanvas().getUrlFromAttr(el.getAttribute(attrs[j])); + const ref = svgCanvas.getUrlFromAttr(el.getAttribute(attrs[j])); if (ref) { defelemUses.push(ref.substr(1)); } @@ -1080,7 +1081,7 @@ export const convertGradientsMethod = function (elem) { x1: grad.getAttribute('x1'), y1: grad.getAttribute('y1'), x2: grad.getAttribute('x2'), - y2: grad.getAttribute('y2'), + y2: grad.getAttribute('y2') }; // If has transform, convert