From cdc5b8cc759fd1182dd9043b60f5e661d1d3ece1 Mon Sep 17 00:00:00 2001 From: JFH <20402845+jfhenon@users.noreply.github.com> Date: Mon, 27 Dec 2021 00:14:18 -0300 Subject: [PATCH] in progress --- src/editor/Rulers.js | 5 +- src/editor/extensions/ext-grid/ext-grid.js | 6 +- src/svgcanvas/dataStorage.js | 28 + src/svgcanvas/event.js | 1 - src/svgcanvas/path-method.js | 2 - src/svgcanvas/path.js | 28 +- src/svgcanvas/recalculate.js | 20 - src/svgcanvas/selection.js | 2 +- src/svgcanvas/svgcanvas.js | 2189 +++++--------------- src/svgcanvas/utilities.js | 4 +- 10 files changed, 567 insertions(+), 1718 deletions(-) create mode 100644 src/svgcanvas/dataStorage.js diff --git a/src/editor/Rulers.js b/src/editor/Rulers.js index 75bd7f6a..8d1559b3 100644 --- a/src/editor/Rulers.js +++ b/src/editor/Rulers.js @@ -1,5 +1,6 @@ import { getTypeMap } from '../common/units.js'; import rulersTemplate from './templates/rulersTemplate.html'; +import SvgCanvas from '../svgcanvas/svgcanvas.js'; /** * */ @@ -22,7 +23,7 @@ class Rulers { // eslint-disable-next-line no-unsanitized/property template.innerHTML = rulersTemplate; this.editor.$svgEditor.append(template.content.cloneNode(true)); - const { $id } = this.svgCanvas; + const { $id } = SvgCanvas; this.rulerX = $id('ruler_x'); this.rulerY = $id('ruler_y'); this.rulerCorner = $id('ruler_corner'); @@ -68,7 +69,7 @@ class Rulers { const dim = isX ? 'x' : 'y'; const lentype = isX ? 'width' : 'height'; const contentDim = Number(contentElem.getAttribute(dim)); - const { $id } = this.svgCanvas; + const { $id } = SvgCanvas; const $hcanvOrig = $id('ruler_' + dim).querySelector('canvas'); // Bit of a hack to fully clear the canvas in Safari & IE9 diff --git a/src/editor/extensions/ext-grid/ext-grid.js b/src/editor/extensions/ext-grid/ext-grid.js index 3e2dc0cd..680ece4d 100644 --- a/src/editor/extensions/ext-grid/ext-grid.js +++ b/src/editor/extensions/ext-grid/ext-grid.js @@ -24,16 +24,16 @@ const loadExtensionTranslation = async function (svgEditor) { export default { name, - async init ({ NS, getTypeMap }) { + async init () { const svgEditor = this; await loadExtensionTranslation(svgEditor); const { svgCanvas } = svgEditor; - const { $id } = svgCanvas; + const { $id, NS } = svgCanvas; const svgdoc = $id('svgcanvas').ownerDocument; const { assignAttributes } = svgCanvas; const hcanvas = document.createElement('canvas'); const canvBG = $id('canvasBackground'); - const units = getTypeMap(); // Assumes prior `init()` call on `units.js` module + const units = svgCanvas.getTypeMap(); // Assumes prior `init()` call on `units.js` module const intervals = [ 0.01, 0.1, 1, 10, 100, 1000 ]; let showGrid = svgEditor.configObj.curConfig.showGrid || false; diff --git a/src/svgcanvas/dataStorage.js b/src/svgcanvas/dataStorage.js new file mode 100644 index 00000000..50b0d194 --- /dev/null +++ b/src/svgcanvas/dataStorage.js @@ -0,0 +1,28 @@ +/** A storage solution aimed at replacing jQuerys data function. +* Implementation Note: Elements are stored in a (WeakMap)[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap]. +* This makes sure the data is garbage collected when the node is removed. +*/ +const dataStorage = { + _storage: new WeakMap(), + put: function (element, key, obj) { + if (!this._storage.has(element)) { + this._storage.set(element, new Map()); + } + this._storage.get(element).set(key, obj); + }, + get: function (element, key) { + return this._storage.get(element)?.get(key); + }, + has: function (element, key) { + return this._storage.has(element) && this._storage.get(element).has(key); + }, + remove: function (element, key) { + const ret = this._storage.get(element).delete(key); + if (!this._storage.get(element).size === 0) { + this._storage.delete(element); + } + return ret; + } +}; + +export default dataStorage; diff --git a/src/svgcanvas/event.js b/src/svgcanvas/event.js index 10b93cce..664a148d 100644 --- a/src/svgcanvas/event.js +++ b/src/svgcanvas/event.js @@ -1284,7 +1284,6 @@ export const mouseDownEvent = (evt) => { * @returns {void} */ export const DOMMouseScrollEvent = (e) => { - const svgCanvas = this; // svgCanvas was bound to the handler const zoom = svgCanvas.getZoom(); const { $id } = svgCanvas; if (!e.shiftKey) { return; } diff --git a/src/svgcanvas/path-method.js b/src/svgcanvas/path-method.js index 81114d8c..9c0bd7e1 100644 --- a/src/svgcanvas/path-method.js +++ b/src/svgcanvas/path-method.js @@ -61,7 +61,6 @@ export const getGripPtMethod = function (seg, altPt) { const pt = transformPoint(out.x, out.y, pth.matrix); out = pt; } - svgCanvas = svgCanvas.getEditorContext(); const zoom = svgCanvas.getZoom(); out.x *= zoom; out.y *= zoom; @@ -85,7 +84,6 @@ export const getPointFromGripMethod = function (pt, pth) { out.x = pt.x; out.y = pt.y; } - svgCanvas = svgCanvas.getEditorContext(); const zoom = svgCanvas.getZoom(); out.x /= zoom; out.y /= zoom; diff --git a/src/svgcanvas/path.js b/src/svgcanvas/path.js index 87ee96e7..43024fd7 100644 --- a/src/svgcanvas/path.js +++ b/src/svgcanvas/path.js @@ -230,6 +230,20 @@ export let path = null; */ export const init = function (canvas) { svgCanvas = canvas; + svgCanvas.replacePathSeg = replacePathSegMethod; + svgCanvas.addPointGrip = addPointGripMethod; + svgCanvas.removePath_ = removePath_; + svgCanvas.getPath_ = getPath_; + svgCanvas.addCtrlGrip = addCtrlGripMethod; + svgCanvas.getCtrlLine = getCtrlLineMethod; + svgCanvas.getPointFromGrip = getPointFromGripMethod; + svgCanvas.setLinkControlPoints = setLinkControlPoints; + svgCanvas.getSegData = () => { return segData; }; + svgCanvas.getUIStrings= () => { return uiStrings; }; + svgCanvas.getPathObj = () => { return path; }; + svgCanvas.setPathObj = (obj) => { path = obj; }; + svgCanvas.getPathFuncs = () => { return pathFuncs; }; + svgCanvas.getLinkControlPts = () => { return linkControlPts; }; pathFuncs = [ 0, 'ClosePath' ]; const pathFuncsStrs = [ 'Moveto', 'Lineto', 'CurvetoCubic', 'CurvetoQuadratic', 'Arc', @@ -240,20 +254,8 @@ export const init = function (canvas) { pathFuncs.push(s + 'Rel'); }); pathActionsInit(svgCanvas); + pathMethodInit(svgCanvas); - pathMethodInit( - /** -* @implements {module:path-method.pathMethodsContext} -*/ - { - getSegData () { return segData; }, - getUIStrings () { return uiStrings; }, - getPathObj () { return path; }, - setPathObj (obj) { path = obj; }, - getPathFuncs () { return pathFuncs; }, - getLinkControlPts () { return linkControlPts; } - } - ); }; /* eslint-disable max-len */ diff --git a/src/svgcanvas/recalculate.js b/src/svgcanvas/recalculate.js index cb4685db..2cc8087d 100644 --- a/src/svgcanvas/recalculate.js +++ b/src/svgcanvas/recalculate.js @@ -361,28 +361,8 @@ export const recalculateDimensions = function (selected) { childTlist.appendItem(translateBack); childTlist.appendItem(scale); childTlist.appendItem(translateOrigin); - // childxforms.push(translateBack); - // childxforms.push(scale); - // childxforms.push(translateOrigin); - // logMatrix(translateBack.matrix); - // logMatrix(scale.matrix); } // not rotated batchCmd.addSubCommand(recalculateDimensions(child)); - // TODO: If any have this group as a parent and are - // referencing this child, then we need to impose a reverse - // scale on it so that when it won't get double-translated - // const uses = selected.getElementsByTagNameNS(NS.SVG, 'use'); - // const href = '#' + child.id; - // let u = uses.length; - // while (u--) { - // const useElem = uses.item(u); - // if (href == getHref(useElem)) { - // const usexlate = svgroot.createSVGTransform(); - // usexlate.setTranslate(-tx,-ty); - // useElem.transform.baseVal.insertItemBefore(usexlate,0); - // batchCmd.addSubCommand( recalculateDimensions(useElem) ); - // } - // } svgCanvas.setStartTransform(oldStartTransform); } // element } // for each child diff --git a/src/svgcanvas/selection.js b/src/svgcanvas/selection.js index 85e64cf2..e22f4c0a 100644 --- a/src/svgcanvas/selection.js +++ b/src/svgcanvas/selection.js @@ -49,7 +49,7 @@ export const clearSelectionMethod = function (noCall) { svgCanvas?.setEmptySelectedElements(); if (!noCall) { - svgCanvas.call("selected", selectionContext_.getSelectedElements()); + svgCanvas.call("selected", svgCanvas.getSelectedElements()); } }; diff --git a/src/svgcanvas/svgcanvas.js b/src/svgcanvas/svgcanvas.js index b7a6a8a1..8395bcf9 100644 --- a/src/svgcanvas/svgcanvas.js +++ b/src/svgcanvas/svgcanvas.js @@ -4,7 +4,7 @@ * * @license MIT * - * @copyright 2010 Alexis Deveria, 2010 Pavol Rusnak, 2010 Jeff Schiller + * @copyright 2010 Alexis Deveria, 2010 Pavol Rusnak, 2010 Jeff Schiller, 2021 OptimistikSAS * */ @@ -17,17 +17,10 @@ import * as draw from './draw.js'; import { init as pasteInit, pasteElementsMethod } from './paste-elem.js'; - -import { - identifyLayers, createLayer, cloneLayer, deleteCurrentLayer, - setCurrentLayer, renameCurrentLayer, setCurrentLayerPosition, - setLayerVisibility, moveSelectedToLayer, mergeLayer, mergeAllLayers, - leaveContext, setContext -} from './draw.js'; import { svgRootElement } from './svgroot.js'; import { init as undoInit, getUndoManager, changeSelectedAttributeNoUndoMethod, - changeSelectedAttributeMethod, ffClone + changeSelectedAttributeMethod } from './undo.js'; import { init as selectionInit, clearSelectionMethod, addToSelectionMethod, getMouseTargetMethod, @@ -42,16 +35,7 @@ import { dblClickEvent, mouseDownEvent, DOMMouseScrollEvent } from './event.js'; import { init as jsonInit, getJsonFromSvgElements, addSVGElementsFromJson } from './json.js'; -import { - init as elemInit, getResolutionMethod, getTitleMethod, setGroupTitleMethod, - setDocumentTitleMethod, setResolutionMethod, getEditorNSMethod, setBBoxZoomMethod, - setZoomMethod, setColorMethod, setGradientMethod, findDuplicateGradient, setPaintMethod, - setStrokeWidthMethod, setStrokeAttrMethod, getBoldMethod, setBoldMethod, getItalicMethod, - setItalicMethod, setTextAnchorMethod, getFontFamilyMethod, setFontFamilyMethod, setFontColorMethod, getFontColorMethod, - getFontSizeMethod, setFontSizeMethod, getTextMethod, setTextContentMethod, - setImageURLMethod, setLinkURLMethod, setRectRadiusMethod, makeHyperlinkMethod, - removeHyperlinkMethod, setSegTypeMethod, setBackgroundMethod -} from './elem-get-set.js'; +import * as elemGetSet from './elem-get-set.js'; import { init as selectedElemInit, moveToTopSelectedElem, moveToBottomSelectedElem, moveUpDownSelected, moveSelectedElements, cloneSelectedElements, alignSelectedElements, @@ -64,28 +48,24 @@ import { import { sanitizeSvg } from './sanitize.js'; import { getReverseNS, NS } from './namespaces.js'; import { - text2xml, assignAttributes, cleanupElement, getElem, getUrlFromAttr, - findDefs, getHref, setHref, getRefElem, getRotationAngle, getPathBBox, - preventClickDefault, walkTree, getBBoxOfElementAsPath, convertToPath, encode64, decode64, - getVisibleElements, dropXMLInternalSubset, init as utilsInit, + assignAttributes, cleanupElement, getElem, getUrlFromAttr, + findDefs, getHref, setHref, getRefElem, getRotationAngle, + getBBoxOfElementAsPath, convertToPath, encode64, decode64, + getVisibleElements, init as utilsInit, getBBox as utilsGetBBox, getStrokedBBoxDefaultVisible, isNullish, blankPageObjectURL, $id, $qa, $qq, getFeGaussianBlur, stringToHTML, insertChildAtIndex } from './utilities.js'; import { - transformPoint, matrixMultiply, hasMatrixTransform, transformListToTransform, - isIdentity, transformBox + matrixMultiply, hasMatrixTransform, transformListToTransform } from './math.js'; import { - convertToNum, getTypeMap, init as unitsInit + convertToNum, init as unitsInit, getTypeMap } from '../common/units.js'; import { svgCanvasToString, svgToString, setSvgString, exportPDF, setUseDataMethod, init as svgInit, importSvgString, embedImage, rasterExport, uniquifyElemsMethod, removeUnusedDefElemsMethod, convertGradientsMethod } from './svg-exec.js'; -import { - isChrome -} from '../common/browser.js'; // , supportsEditableText import { remapElement, init as coordsInit @@ -107,10 +87,7 @@ import { getClosest, getParents, mergeDeep } from '../editor/components/jgraduate/Util.js'; -const { - MoveElementCommand, InsertElementCommand, RemoveElementCommand, - ChangeElementCommand, BatchCommand -} = hstry; +import dataStorage from './dataStorage.js'; const visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; const refAttrs = [ 'clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke' ]; @@ -119,44 +96,11 @@ const THRESHOLD_DIST = 0.8; const STEP_COUNT = 10; const CLIPBOARD_ID = 'svgedit_clipboard'; -if (!window.console) { - window.console = {}; - window.console.log = (_str) => { /* empty fn */ }; - window.console.dir = (_str) => { /* empty fn */ }; -} -if (window.opera) { - window.console.log = (str) => { window.opera.postError(str); }; - window.console.dir = (_str) => { /* empty fn */ }; -} - -// Reenable after fixing eslint-plugin-jsdoc to handle /** * The main SvgCanvas class that manages all SVG-related functions. * @memberof module:svgcanvas * -* @borrows module:coords.remapElement as #remapElement -* @borrows module:recalculate.recalculateDimensions as #recalculateDimensions -* -* @borrows module:utilities.cleanupElement as #cleanupElement -* @borrows module:utilities.getStrokedBBoxDefaultVisible as #getStrokedBBox -* @borrows module:utilities.getVisibleElements as #getVisibleElements -* @borrows module:utilities.findDefs as #findDefs -* @borrows module:utilities.getUrlFromAttr as #getUrlFromAttr -* @borrows module:utilities.getHref as #getHref -* @borrows module:utilities.setHref as #setHref -* @borrows module:utilities.getRotationAngle as #getRotationAngle -* @borrows module:utilities.getBBox as #getBBox -* @borrows module:utilities.getElem as #getElem -* @borrows module:utilities.getRefElem as #getRefElem -* @borrows module:utilities.assignAttributes as #assignAttributes -* -* @borrows module:math.matrixMultiply as #matrixMultiply -* @borrows module:math.hasMatrixTransform as #hasMatrixTransform -* @borrows module:math.transformListToTransform as #transformListToTransform -* @borrows module:units.convertToNum as #convertToNum -* @borrows module:sanitize.sanitizeSvg as #sanitizeSvg -* @borrows module:path.pathActions.linkControlPoints as #linkControlPoints */ class SvgCanvas { /** @@ -164,114 +108,73 @@ class SvgCanvas { * @param {module:SVGeditor.configObj.curConfig} config - An object that contains configuration data */ constructor(container, config) { - // imported methods - this.getJsonFromSvgElements = getJsonFromSvgElements; - this.addSVGElemensFromJson = addSVGElementsFromJson; - this.clearSvgContentElement = clearSvgContentElementInit; - this.textActions = textActionsMethod; - this.undoMgr = getUndoManager(); - this.getIntersectionList = getIntersectionListMethod; - this.getStrokedBBox = getStrokedBBoxDefaultVisible; - this.getVisibleElements = getVisibleElements; - this.uniquifyElems = uniquifyElemsMethod; - this.setUseData = setUseDataMethod; - this.convertGradients = convertGradientsMethod; - this.setSvgString = setSvgString; - this.importSvgString = importSvgString; - this.runExtensions = runExtensionsMethod; - this.clearSelection = clearSelectionMethod; - this.addToSelection = addToSelectionMethod; + // imported function made available as methods + this.initializeSvgCanvasMethods(); + const { pathActions } = pathModule; + // initialize class variables + this.saveOptions = { round_digits: 5 }; // Object with save options + this.importIds = {}; // Object with IDs for imported files, to see if one was already added + this.extensions = {}; // Object to contain all included extensions + this.removedElements = {}; // Map of deleted reference elements + this.started = false; // Boolean indicating whether or not a draw action has been this.started + this.startTransform = null; // String with an element's initial transform attribute value + this.currentMode = 'select'; // String indicating the current editor mode + this.currentResizeMode = 'none'; // String with the current direction in which an element is being resized + this.justSelected = null; // The DOM element that was just selected + this.rubberBox = null; // DOM element for selection rectangle drawn by the user + this.curBBoxes = []; // Array of current BBoxes, used in getIntersectionList(). + this.lastClickPoint = null; // Canvas point for the most recent right click + this.events = {}; // Object to contain editor event names and callback functions + this.rootSctm = null; // Root Current Transformation Matrix in user units + this.drawnPath = null; + this.freehand = { // Mouse events + minx: null, + miny: null, + maxx: null, + maxy: null + }; + this.dAttr = null; + this.startX = null; + this.startY = null; + this.rStartX = null; + this.rStartY = null; + this.initBbox = {}; + this.sumDistance = 0; + this.controllPoint2 = { x: 0, y: 0 }; + this.controllPoint1 = { x: 0, y: 0 }; + this.start = { x: 0, y: 0 }; + this.end = { x: 0, y: 0 }; + this.bSpline = { x: 0, y: 0 }; + this.nextPos = { x: 0, y: 0 }; + this.idprefix = 'svg_'; // Prefix string for element IDs - // Default configuration options - this.curConfig = { + this.curConfig = { // Default configuration options show_outside_canvas: true, selectNew: true, dimensions: [ 640, 480 ] }; - // Update config with new one if given - this.mergeDeep = mergeDeep; if (config) { - this.curConfig = this.mergeDeep(this.curConfig, config); + this.curConfig = SvgCanvas.mergeDeep(this.curConfig, config); } - - // Array with width/height of canvas - const { dimensions } = this.curConfig; - - this.$id = $id; - this.$qq = $qq; - this.$qa = $qa; - this.encode64 = encode64; - this.decode64 = decode64; - this.stringToHTML = stringToHTML; - this.insertChildAtIndex = insertChildAtIndex; - this.getClosest = getClosest; - this.getParents = getParents; - /** A storage solution aimed at replacing jQuerys data function. - * Implementation Note: Elements are stored in a (WeakMap)[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap]. - * This makes sure the data is garbage collected when the node is removed. - */ - this.dataStorage = { - _storage: new WeakMap(), - put: function (element, key, obj) { - if (!this._storage.has(element)) { - this._storage.set(element, new Map()); - } - this._storage.get(element).set(key, obj); - }, - get: function (element, key) { - return this._storage.get(element)?.get(key); - }, - has: function (element, key) { - return this._storage.has(element) && this._storage.get(element).has(key); - }, - remove: function (element, key) { - const ret = this._storage.get(element).delete(key); - if (!this._storage.get(element).size === 0) { - this._storage.delete(element); - } - return ret; - } - }; - - this.isLayer = draw.Layer.isLayer; + this.lastGoodImgUrl = `${this.curConfig.imgPath}/logo.svg`; // String with image URL of last loadable image + const { dimensions } = this.curConfig; // Array with width/height of canvas // "document" element associated with the container (same as window.document using default svg-editor.js) // NOTE: This is not actually a SVG document, but an HTML document. this.svgdoc = window.document; - + this.container = container; // This is a container for the document being edited, not the document itself. - /** - * @name module:svgcanvas~svgroot - * @type {SVGSVGElement} - */ this.svgroot = svgRootElement(this.svgdoc, dimensions); container.append(this.svgroot); - - /** - * The actual element that represents the final output SVG element. - * @name module:svgcanvas~svgcontent - * @type {SVGSVGElement} - */ + // The actual element that represents the final output SVG element. this.svgContent = this.svgdoc.createElementNS(NS.SVG, 'svg'); - clearInit(this); this.clearSvgContentElement(); - - // Prefix string for element IDs - this.idprefix = 'svg_'; - - /** -* Current `draw.Drawing` object. -* @type {module:draw.Drawing} -* @name module:svgcanvas.SvgCanvas#current_drawing_ -*/ + //Current `draw.Drawing` object. this.current_drawing_ = new draw.Drawing(this.svgContent, this.idprefix); - /** -* Float displaying the current zoom level (1 = 100%, .5 = 50%, etc.). -* @type {Float} -*/ + // Float displaying the current zoom level (1 = 100%, .5 = 50%, etc.). this.zoom = 1; // pointer to current group (for in-group editing) @@ -293,77 +196,34 @@ class SvgCanvas { opacity: this.curConfig.initOpacity } }; - allProperties.text = this.mergeDeep({}, allProperties.shape); - allProperties.text = this.mergeDeep(allProperties.text, { + allProperties.text = SvgCanvas.mergeDeep({}, allProperties.shape); + allProperties.text = SvgCanvas.mergeDeep(allProperties.text, { fill: '#000000', stroke_width: this.curConfig.text && this.curConfig.text.stroke_width, font_size: this.curConfig.text && this.curConfig.text.font_size, font_family: this.curConfig.text && this.curConfig.text.font_family }); + this.curText = allProperties.text; // Current text style properties // Current shape style properties this.curShape = allProperties.shape; + this.curProperties = this.curShape; // Current general properties // Array with all the currently selected elements // default size of 1 until it needs to grow bigger this.selectedElements = []; jsonInit(this); - - this.matrixMultiply = matrixMultiply; - this.hasMatrixTransform = hasMatrixTransform; - this.transformListToTransform = transformListToTransform; - - /** -* Initialize from units.js. -* Send in an object implementing the ElementContainer interface (see units.js). -*/ unitsInit(this); - this.convertToNum = convertToNum; - const { pathActions } = pathModule; utilsInit(this); - this.findDefs = findDefs; - this.getUrlFromAttr = getUrlFromAttr; - this.getHref = getHref; - this.setHref = setHref; - /* const getBBox = */ this.getBBox = utilsGetBBox; - this.getRotationAngle = getRotationAngle; - this.getElem = getElem; - this.getRefElem = getRefElem; - this.assignAttributes = assignAttributes; - this.cleanupElement = cleanupElement; coordsInit(this); - this.remapElement = remapElement; recalculateInit(this); - this.recalculateDimensions = recalculateDimensions; - // import from sanitize.js - this.nsMap = getReverseNS(); - this.sanitizeSvg = sanitizeSvg; selectInit(this.curConfig, this); - this.selectorManager = getSelectorManager(); - - /** -* The "implements" should really be an intersection applying to all types rather than a union. -* @name module:svgcanvas.SvgCanvas#call -* @type {module:draw.DrawCanvasInit#call|module:path.EditorContext#call} -*/ - const call = (ev, arg) => { - if (events[ev]) { - return events[ev](window, arg); - } - return undefined; - }; - undoInit(this); selectionInit(this); - /** - * @type {module:path.EditorContext#getOpacity} - */ - const getOpacity = function () { - return this.curShape.opacity; - }; - this.getMouseTarget = getMouseTargetMethod; + this.nsMap = getReverseNS(); + this.selectorManager = getSelectorManager(); this.pathActions = pathActions; pathModule.init(this); @@ -378,360 +238,11 @@ class SvgCanvas { this.opacAni.setAttribute('fill', 'freeze'); this.svgroot.appendChild(this.opacAni); - // (function () { - // TODO For Issue 208: this is a start on a thumbnail - // const svgthumb = this.svgdoc.createElementNS(NS.SVG, 'use'); - // svgthumb.setAttribute('width', '100'); - // svgthumb.setAttribute('height', '100'); - // setHref(svgthumb, '#svgcontent'); - // svgroot.append(svgthumb); - // }()); - - /** - * @typedef {PlainObject} module:svgcanvas.SaveOptions - * @property {boolean} apply - * @property {"embed"} [image] - * @property {Integer} round_digits - */ - - // Object to contain image data for raster images that were found encodable - this.addToSelectionencodableImages = {}; - // Object with save options - this.saveOptions = { round_digits: 5 }; - // Object with IDs for imported files, to see if one was already added - this.importIds = {}; - // Current text style properties - this.curText = allProperties.text; - // Object to contain all included extensions - this.extensions = {}; - // Map of deleted reference elements - this.removedElements = {}; - - // String with image URL of last loadable image - this.lastGoodImgUrl = `${this.curConfig.imgPath}/logo.svg`; - // Boolean indicating whether or not a draw action has been this.started - this.started = false; - // String with an element's initial transform attribute value - this.startTransform = null; - // String indicating the current editor mode - this.currentMode = 'select'; - // String with the current direction in which an element is being resized - this.currentResizeMode = 'none'; - // Current general properties - this.curProperties = this.curShape; - // Array with selected elements' Bounding box object - // selectedBBoxes = new Array(1), - // The DOM element that was just selected - this.justSelected = null; - // DOM element for selection rectangle drawn by the user - this.rubberBox = null; - // Array of current BBoxes, used in getIntersectionList(). - this.curBBoxes = []; - // Canvas point for the most recent right click - this.lastClickPoint = null; - - /** -* Wrap an SVG element into a group element, mark the group as 'gsvg'. -* @function module:svgcanvas.SvgCanvas#groupSvgElem -* @param {Element} elem - SVG element to wrap -* @returns {void} -*/ - this.groupSvgElem = groupSvgElem; - - // Set scope for these functions - - // Object to contain editor event names and callback functions - const events = {}; - - this.call = call; - /** - * Array of what was changed (elements, layers). - * @event module:svgcanvas.SvgCanvas#event:changed - * @type {Element[]} - */ - /** - * Array of selected elements. - * @event module:svgcanvas.SvgCanvas#event:selected - * @type {Element[]} - */ - /** - * Array of selected elements. - * @event module:svgcanvas.SvgCanvas#event:transition - * @type {Element[]} - */ - /** - * The Element is always `SVGGElement`? - * If not `null`, will be the set current group element. - * @event module:svgcanvas.SvgCanvas#event:contextset - * @type {null|Element} - */ - /** - * @event module:svgcanvas.SvgCanvas#event:pointsAdded - * @type {PlainObject} - * @property {boolean} closedSubpath - * @property {SVGCircleElement[]} grips Grips elements - */ - - /** - * @event module:svgcanvas.SvgCanvas#event:zoomed - * @type {PlainObject} - * @property {Float} x - * @property {Float} y - * @property {Float} width - * @property {Float} height - * @property {0.5|2} factor - * @see module:SVGEditor.BBoxObjectWithFactor - */ - /** - * @event module:svgcanvas.SvgCanvas#event:updateCanvas - * @type {PlainObject} - * @property {false} center - * @property {module:math.XYObject} newCtr - */ - /** - * @typedef {PlainObject} module:svgcanvas.ExtensionInitResponsePlusName - * @implements {module:svgcanvas.ExtensionInitResponse} - * @property {string} name The extension's resolved ID (whether explicit or based on file name) - */ - /** - * Generalized extension object response of - * [`init()`]{@link module:svgcanvas.ExtensionInitCallback} - * along with the name of the extension. - * @event module:svgcanvas.SvgCanvas#event:extension_added - * @type {module:svgcanvas.ExtensionInitResponsePlusName|void} - */ - /** - * @event module:svgcanvas.SvgCanvas#event:extensions_added - * @type {void} -*/ - /** - * @typedef {PlainObject} module:svgcanvas.Message - * @property {any} data The data - * @property {string} origin The origin - */ - /** - * @event module:svgcanvas.SvgCanvas#event:message - * @type {module:svgcanvas.Message} - */ - /** - * SVG canvas converted to string. - * @event module:svgcanvas.SvgCanvas#event:saved - * @type {string} - */ - /** - * @event module:svgcanvas.SvgCanvas#event:setnonce - * @type {!(string|Integer)} - */ - /** - * @event module:svgcanvas.SvgCanvas#event:unsetnonce - * @type {void} - */ - /** - * @event module:svgcanvas.SvgCanvas#event:zoomDone - * @type {void} -*/ - /** - * @event module:svgcanvas.SvgCanvas#event:cleared - * @type {void} -*/ - - /** - * @event module:svgcanvas.SvgCanvas#event:exported - * @type {module:svgcanvas.ImageExportedResults} - */ - /** - * @event module:svgcanvas.SvgCanvas#event:exportedPDF - * @type {module:svgcanvas.PDFExportedResults} - */ - /* eslint-disable max-len */ - /** - * Creating a cover-all class until {@link https://github.com/jsdoc3/jsdoc/issues/1545} may be supported. - * `undefined` may be returned by {@link module:svgcanvas.SvgCanvas#event:extension_added} if the extension's `init` returns `undefined` It is also the type for the following events "zoomDone", "unsetnonce", "cleared", and "extensions_added". - * @event module:svgcanvas.SvgCanvas#event:GenericCanvasEvent - * @type {module:svgcanvas.SvgCanvas#event:selected|module:svgcanvas.SvgCanvas#event:changed|module:svgcanvas.SvgCanvas#event:contextset|module:svgcanvas.SvgCanvas#event:pointsAdded|module:svgcanvas.SvgCanvas#event:extension_added|module:svgcanvas.SvgCanvas#event:extensions_added|module:svgcanvas.SvgCanvas#event:message|module:svgcanvas.SvgCanvas#event:transition|module:svgcanvas.SvgCanvas#event:zoomed|module:svgcanvas.SvgCanvas#event:updateCanvas|module:svgcanvas.SvgCanvas#event:saved|module:svgcanvas.SvgCanvas#event:exported|module:svgcanvas.SvgCanvas#event:exportedPDF|module:svgcanvas.SvgCanvas#event:setnonce|module:svgcanvas.SvgCanvas#event:unsetnonce|void} - */ - /* eslint-enable max-len */ - - /** - * The promise return, if present, resolves to `undefined` - * (`extension_added`, `exported`, `saved`). - * @typedef {Promise|void} module:svgcanvas.EventHandlerReturn -*/ - - /** -* @callback module:svgcanvas.EventHandler -* @param {external:Window} win -* @param {module:svgcanvas.SvgCanvas#event:GenericCanvasEvent} arg -* @listens module:svgcanvas.SvgCanvas#event:GenericCanvasEvent -* @returns {module:svgcanvas.EventHandlerReturn} -*/ - /* eslint-disable max-len */ - /** -* Attaches a callback function to an event. -* @function module:svgcanvas.SvgCanvas#bind -* @param {"changed"|"contextset"|"selected"|"pointsAdded"|"extension_added"|"extensions_added"|"message"|"transition"|"zoomed"|"updateCanvas"|"zoomDone"|"saved"|"exported"|"exportedPDF"|"setnonce"|"unsetnonce"|"cleared"} ev - String indicating the name of the event -* @param {module:svgcanvas.EventHandler} f - The callback function to bind to the event -* @returns {module:svgcanvas.EventHandler} The previous event -*/ - /* eslint-enable max-len */ - this.bind = function (ev, f) { - const old = events[ev]; - events[ev] = f; - return old; - }; - - /** -* Runs the SVG Document through the sanitizer and then updates its paths. -* @function module:svgcanvas.SvgCanvas#prepareSvg -* @param {XMLDocument} newDoc - The SVG DOM document -* @returns {void} -*/ - this.prepareSvg = prepareSvg; - - /** -* Removes any old rotations if present, prepends a new rotation at the -* transformed center. -* @function module:svgcanvas.SvgCanvas#setRotationAngle -* @param {string|Float} val - The new rotation angle in degrees -* @param {boolean} preventUndo - Indicates whether the action should be undoable or not -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.setRotationAngle = setRotationAngle; - - /** -* Runs `recalculateDimensions` on the selected elements, -* adding the changes to a single batch command. -* @function module:svgcanvas.SvgCanvas#recalculateAllSelectedDimensions -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.recalculateAllSelectedDimensions = recalculateAllSelectedDimensions; - - /** - * Debug tool to easily see the current matrix in the browser's console. - * @function module:svgcanvas~logMatrix - * @param {SVGMatrix} m The matrix - * @returns {void} - */ - const logMatrix = function (m) { - console.info([ m.a, m.b, m.c, m.d, m.e, m.f ]); - }; - - // Root Current Transformation Matrix in user units - this.rootSctm = null; - - /** -* Group: Selection. -*/ - - // TODO: do we need to worry about selectedBBoxes here? - - /** -* Selects only the given elements, shortcut for `clearSelection(); addToSelection()`. -* @function module:svgcanvas.SvgCanvas#selectOnly -* @param {Element[]} elems - an array of DOM elements to be selected -* @param {boolean} showGrips - Indicates whether the resize grips should be shown -* @returns {void} -*/ - const selectOnly = this.selectOnly = (elems, showGrips) => { - this.clearSelection(true); - this.addToSelection(elems, showGrips); - }; - - // TODO: could use slice here to make this faster? - // TODO: should the 'selected' handler - - /** -* Removes elements from the selection. -* @function module:svgcanvas.SvgCanvas#removeFromSelection -* @param {Element[]} elemsToRemove - An array of elements to remove from selection -* @returns {void} -*/ - /* const removeFromSelection = */ this.removeFromSelection = function (elemsToRemove) { - if (isNullish(this.selectedElements[0])) { return; } - if (!elemsToRemove.length) { return; } - - // find every element and remove it from our array copy - const newSelectedItems = []; - const len = this.selectedElements.length; - for (let i = 0; i < len; ++i) { - const elem = this.selectedElements[i]; - if (elem) { - // keep the item - if (!elemsToRemove.includes(elem)) { - newSelectedItems.push(elem); - } else { // remove the item and its selector - this.selectorManager.releaseSelector(elem); - } - } - } - // the copy becomes the master now - this.selectedElements = newSelectedItems; - }; - - /** -* Clears the selection, then adds all elements in the current layer to the selection. -* @function module:svgcanvas.SvgCanvas#selectAllInCurrentLayer -* @returns {void} -*/ - this.selectAllInCurrentLayer = function () { - const currentLayer = this.getCurrentDrawing().getCurrentLayer(); - if (currentLayer) { - this.currentMode = 'select'; - if (this.currentGroup) { - selectOnly(this.currentGroup.children); - } else { - selectOnly(currentLayer.children); - } - } - }; - - this.drawnPath = null; - - // Mouse events - this.freehand = { - minx: null, - miny: null, - maxx: null, - maxy: null - }; - - this.dAttr = null; - this.startX = null; - this.startY = null; - this.rStartX = null; - this.rStartY = null; - this.initBbox = {}; - this.sumDistance = 0; - this.controllPoint2 = { x: 0, y: 0 }; - this.controllPoint1 = { x: 0, y: 0 }; - this.start = { x: 0, y: 0 }; - this.end = { x: 0, y: 0 }; - this.bSpline = { x: 0, y: 0 }; - this.nextPos = { x: 0, y: 0 }; - this.parameter; - this.nextParameter; - - /** - * @function eventInit Initialize from event.js - * @returns {void} - */ eventInit(this); - /** - * Follows these conditions: - * - When we are in a create mode, the element is added to the canvas but the - * action is not recorded until mousing up. - * - When we are in select mode, select the element, remember the position - * and do nothing else. - * @param {MouseEvent} evt - * @fires module:svgcanvas.SvgCanvas#event:ext_mouseDown - * @returns {void} - */ - - const mouseUp = mouseUpEvent.bind(this); - const mouseOut = mouseOutEvent.bind(this); - const dblClick = dblClickEvent.bind(this); + textActionsInit(this); + svgInit(this); + draw.init(this); + elemGetSet.init(this); // prevent links from being followed in the canvas const handleLinkInCanvas = function (e) { @@ -741,857 +252,21 @@ class SvgCanvas { container.addEventListener('mousedown', mouseDownEvent); container.addEventListener('mousemove', mouseMoveEvent); container.addEventListener('click', handleLinkInCanvas); - container.addEventListener('dblclick', dblClick); - container.addEventListener('mouseup', mouseUp); - container.addEventListener('mouseleave', mouseOut); + container.addEventListener('dblclick', dblClickEvent); + container.addEventListener('mouseup', mouseUpEvent); + container.addEventListener('mouseleave', mouseOutEvent); container.addEventListener('mousewheel', DOMMouseScrollEvent); container.addEventListener('DOMMouseScroll', DOMMouseScrollEvent); - textActionsInit(this); - - this.getSvgOption = () => { return this.saveOptions; }; - this.setSvgOption = (key, value) => { this.saveOptions[key] = value; }; - - svgInit(this); - - /** -* Looks at DOM elements inside the `` to see if they are referred to, -* removes them from the DOM if they are not. -* @function module:svgcanvas.SvgCanvas#removeUnusedDefElems -* @returns {Integer} The number of elements that were removed -*/ - this.removeUnusedDefElems = removeUnusedDefElemsMethod; - - /** -* Main function to set up the SVG content for output. -* @function module:svgcanvas.SvgCanvas#svgCanvasToString -* @returns {string} The SVG image for output -*/ - this.svgCanvasToString = svgCanvasToString; - - /** -* Sub function ran on each SVG element to convert it to a string as desired. -* @function module:svgcanvas.SvgCanvas#svgToString -* @param {Element} elem - The SVG element to convert -* @param {Integer} indent - Number of spaces to indent this tag -* @returns {string} The given element as an SVG tag -*/ - this.svgToString = svgToString; - - /** - * Function to run when image data is found. - * @callback module:svgcanvas.ImageEmbeddedCallback - * @param {string|false} result Data URL - * @returns {void} - */ - /** -* Converts a given image file to a data URL when possible, then runs a given callback. -* @function module:svgcanvas.SvgCanvas#embedImage -* @param {string} src - The path/URL of the image -* @returns {Promise} Resolves to a Data URL (string|false) -*/ - this.embedImage = embedImage; - - /** -* Sets a given URL to be a "last good image" URL. -* @function module:svgcanvas.SvgCanvas#setGoodImage -* @param {string} val -* @returns {void} -*/ - this.setGoodImage = function (val) { - this.lastGoodImgUrl = val; - }; - - /** -* @typedef {PlainObject} module:svgcanvas.IssuesAndCodes -* @property {string[]} issueCodes The locale-independent code names -* @property {string[]} issues The localized descriptions -*/ - - /** - * @typedef {"feGaussianBlur"|"foreignObject"|"[stroke-dasharray]"|"text"} module:svgcanvas.IssueCode - */ - /** -* @typedef {PlainObject} module:svgcanvas.ImageExportedResults -* @property {string} datauri Contents as a Data URL -* @property {string} bloburl May be the empty string -* @property {string} svg The SVG contents as a string -* @property {string[]} issues The localization messages of `issueCodes` -* @property {module:svgcanvas.IssueCode[]} issueCodes CanVG issues found with the SVG -* @property {"PNG"|"JPEG"|"BMP"|"WEBP"|"ICO"} type The chosen image type -* @property {"image/png"|"image/jpeg"|"image/bmp"|"image/webp"} mimeType The image MIME type -* @property {Float} quality A decimal between 0 and 1 (for use with JPEG or WEBP) -* @property {string} exportWindowName A convenience for passing along a `window.name` to target a window on which the export could be added -*/ - - /** -* Generates a PNG (or JPG, BMP, WEBP) Data URL based on the current image, -* then calls "exported" with an object including the string, image -* information, and any issues found. -* @function module:svgcanvas.SvgCanvas#rasterExport -* @param {"PNG"|"JPEG"|"BMP"|"WEBP"|"ICO"} [imgType="PNG"] -* @param {Float} [quality] Between 0 and 1 -* @param {string} [exportWindowName] -* @param {PlainObject} [opts] -* @param {boolean} [opts.avoidEvent] -* @fires module:svgcanvas.SvgCanvas#event:exported -* @todo Confirm/fix ICO type -* @returns {Promise} Resolves to {@link module:svgcanvas.ImageExportedResults} -*/ - this.rasterExport = rasterExport; - - /** - * @typedef {void|"save"|"arraybuffer"|"blob"|"datauristring"|"dataurlstring"|"dataurlnewwindow"|"datauri"|"dataurl"} external:jsPDF.OutputType - * @todo Newer version to add also allows these `outputType` values "bloburi"|"bloburl" which return strings, so document here and for `outputType` of `module:svgcanvas.PDFExportedResults` below if added -*/ - /** -* @typedef {PlainObject} module:svgcanvas.PDFExportedResults -* @property {string} svg The SVG PDF output -* @property {string|ArrayBuffer|Blob|window} output The output based on the `outputType`; -* if `undefined`, "datauristring", "dataurlstring", "datauri", -* or "dataurl", will be a string (`undefined` gives a document, while the others -* build as Data URLs; "datauri" and "dataurl" change the location of the current page); if -* "arraybuffer", will return `ArrayBuffer`; if "blob", returns a `Blob`; -* if "dataurlnewwindow", will change the current page's location and return a string -* if in Safari and no window object is found; otherwise opens in, and returns, a new `window` -* object; if "save", will have the same return as "dataurlnewwindow" if -* `navigator.getUserMedia` support is found without `URL.createObjectURL` support; otherwise -* returns `undefined` but attempts to save -* @property {external:jsPDF.OutputType} outputType -* @property {string[]} issues The human-readable localization messages of corresponding `issueCodes` -* @property {module:svgcanvas.IssueCode[]} issueCodes -* @property {string} exportWindowName -*/ - - /** -* Generates a PDF based on the current image, then calls "exportedPDF" with -* an object including the string, the data URL, and any issues found. -* @function module:svgcanvas.SvgCanvas#exportPDF -* @param {string} [exportWindowName] Will also be used for the download file name here -* @param {external:jsPDF.OutputType} [outputType="dataurlstring"] -* @fires module:svgcanvas.SvgCanvas#event:exportedPDF -* @returns {Promise} Resolves to {@link module:svgcanvas.PDFExportedResults} -*/ - this.exportPDF = exportPDF; - - /** -* Returns the current drawing as raw SVG XML text. -* @function module:svgcanvas.SvgCanvas#getSvgString -* @returns {string} The current drawing as raw SVG XML text. -*/ - this.getSvgString = function () { - this.saveOptions.apply = false; - return this.svgCanvasToString(); - }; - - /** -* This function determines whether to use a nonce in the prefix, when -* generating IDs for future documents in SVG-Edit. -* If you're controlling SVG-Edit externally, and want randomized IDs, call -* this BEFORE calling `svgCanvas.setSvgString`. -* @function module:svgcanvas.SvgCanvas#randomizeIds -* @param {boolean} [enableRandomization] If true, adds a nonce to the prefix. Thus -* `svgCanvas.randomizeIds() <==> svgCanvas.randomizeIds(true)` -* @returns {void} -*/ - this.randomizeIds = function (enableRandomization) { - if (arguments.length > 0 && enableRandomization === false) { - draw.randomizeIds(false, this.getCurrentDrawing()); - } else { - draw.randomizeIds(true, this.getCurrentDrawing()); - } - }; - - // Could deprecate, but besides external uses, their usage makes clear that - // canvas is a dependency for all of these - const dr = { - identifyLayers, createLayer, cloneLayer, deleteCurrentLayer, - setCurrentLayer, renameCurrentLayer, setCurrentLayerPosition, - setLayerVisibility, moveSelectedToLayer, mergeLayer, mergeAllLayers, - leaveContext, setContext - }; - Object.entries(dr).forEach(([ prop, propVal ]) => { - this[prop] = propVal; - }); - draw.init(this); - // Alias function this.linkControlPoints = pathActions.linkControlPoints; - - elemInit(this); - /** -* @function module:svgcanvas.SvgCanvas#getResolution -* @returns {DimensionsAndZoom} The current dimensions and zoom level in an object -*/ - const getResolution = this.getResolution = getResolutionMethod; - - /** -* @function module:svgcanvas.SvgCanvas#getSnapToGrid -* @returns {boolean} The current snap to grid setting -*/ - this.getSnapToGrid = function () { return this.curConfig.gridSnapping; }; - - /** -* @function module:svgcanvas.SvgCanvas#getVersion -* @returns {string} A string which describes the revision number of SvgCanvas. -*/ - this.getVersion = function () { - return 'svgcanvas.js ($Rev$)'; - }; - - /** -* Update interface strings with given values. -* @function module:svgcanvas.SvgCanvas#setUiStrings -* @param {module:path.uiStrings} strs - Object with strings (see the [locales API]{@link module:locale.LocaleStrings} and the [tutorial]{@tutorial LocaleDocs}) -* @returns {void} -*/ - this.setUiStrings = function (strs) { - Object.assign(this.uiStrings, strs.notification); - pathModule.setUiStrings(strs); - }; - - /** -* Update configuration options with given values. -* @function module:svgcanvas.SvgCanvas#setConfig -* @param {module:SVGEditor.Config} opts - Object with options -* @returns {void} -*/ - this.setConfig = function (opts) { - Object.assign(this.curConfig, opts); - }; - - /** -* @function module:svgcanvas.SvgCanvas#getTitle -* @param {Element} [elem] -* @returns {string|void} the current group/SVG's title contents or -* `undefined` if no element is passed nd there are no selected elements. -*/ - this.getTitle = getTitleMethod; - - /** -* Sets the group/SVG's title content. -* @function module:svgcanvas.SvgCanvas#setGroupTitle -* @param {string} val -* @todo Combine this with `setDocumentTitle` -* @returns {void} -*/ - this.setGroupTitle = setGroupTitleMethod; - - /** -* @function module:svgcanvas.SvgCanvas#getDocumentTitle -* @returns {string|void} The current document title or an empty string if not found -*/ - this.getDocumentTitle = function () { - return this.getTitle(this.svgContent); - }; - - /** -* Adds/updates a title element for the document with the given name. -* This is an undoable action. -* @function module:svgcanvas.SvgCanvas#setDocumentTitle -* @param {string} newTitle - String with the new title -* @returns {void} -*/ - this.setDocumentTitle = setDocumentTitleMethod; - - /** -* Returns the editor's namespace URL, optionally adding it to the root element. -* @function module:svgcanvas.SvgCanvas#getEditorNS -* @param {boolean} [add] - Indicates whether or not to add the namespace value -* @returns {string} The editor's namespace URL -*/ - this.getEditorNS = getEditorNSMethod; - - /** -* Changes the document's dimensions to the given size. -* @function module:svgcanvas.SvgCanvas#setResolution -* @param {Float|"fit"} x - Number with the width of the new dimensions in user units. -* Can also be the string "fit" to indicate "fit to content". -* @param {Float} y - Number with the height of the new dimensions in user units. -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {boolean} Indicates if resolution change was successful. -* It will fail on "fit to content" option with no content to fit to. -*/ - this.setResolution = setResolutionMethod; - - /** -* @typedef {module:jQueryAttr.Attributes} module:svgcanvas.ElementPositionInCanvas -* @property {Float} x -* @property {Float} y -*/ - - /** -* @function module:svgcanvas.SvgCanvas#getOffset -* @returns {module:svgcanvas.ElementPositionInCanvas} An object with `x`, `y` values indicating the svgcontent element's -* position in the editor's this. -*/ - this.getOffset = function () { - return { x: Number(this.svgContent.getAttribute('x')), y: Number(this.svgContent.getAttribute('y')) }; - }; - - /** - * @typedef {PlainObject} module:svgcanvas.ZoomAndBBox - * @property {Float} zoom - * @property {module:utilities.BBoxObject} bbox - */ - /** -* Sets the zoom level on the canvas-side based on the given value. -* @function module:svgcanvas.SvgCanvas#setBBoxZoom -* @param {"selection"|"canvas"|"content"|"layer"|module:SVGEditor.BBoxObjectWithFactor} val - Bounding box object to zoom to or string indicating zoom option. Note: the object value type is defined in `svg-editor.js` -* @param {Integer} editorW - The editor's workarea box's width -* @param {Integer} editorH - The editor's workarea box's height -* @returns {module:svgcanvas.ZoomAndBBox|void} -*/ - this.setBBoxZoom = setBBoxZoomMethod; - - /** -* The zoom level has changed. Supplies the new zoom level as a number (not percentage). -* @event module:svgcanvas.SvgCanvas#event:ext_zoomChanged -* @type {Float} -*/ - /** -* The bottom panel was updated. -* @event module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate -* @type {PlainObject} -* @property {boolean} nofill Indicates fill is disabled -* @property {boolean} nostroke Indicates stroke is disabled -*/ - /** -* The element selection has changed (elements were added/removed from selection). -* @event module:svgcanvas.SvgCanvas#event:ext_selectedChanged -* @type {PlainObject} -* @property {Element[]} elems Array of the newly selected elements -* @property {Element|null} selectedElement The single selected element -* @property {boolean} multiselected Indicates whether one or more elements were selected -*/ - /** -* Called when part of element is in process of changing, generally on -* mousemove actions like rotate, move, etc. -* @event module:svgcanvas.SvgCanvas#event:ext_elementTransition -* @type {PlainObject} -* @property {Element[]} elems Array of transitioning elements -*/ - /** -* One or more elements were changed. -* @event module:svgcanvas.SvgCanvas#event:ext_elementChanged -* @type {PlainObject} -* @property {Element[]} elems Array of the affected elements -*/ - /** -* Invoked as soon as the locale is ready. -* @event module:svgcanvas.SvgCanvas#event:ext_langReady -* @type {PlainObject} -* @property {string} lang The two-letter language code -* @property {module:SVGEditor.uiStrings} uiStrings -* @property {module:SVGEditor~ImportLocale} importLocale -*/ - /** -* The language was changed. Two-letter code of the new language. -* @event module:svgcanvas.SvgCanvas#event:ext_langChanged -* @type {string} -*/ - /** -* Means for an extension to add locale data. The two-letter language code. -* @event module:svgcanvas.SvgCanvas#event:ext_addLangData -* @type {PlainObject} -* @property {string} lang -* @property {module:SVGEditor~ImportLocale} importLocale -*/ - /** - * Called when new image is created. - * @event module:svgcanvas.SvgCanvas#event:ext_onNewDocument - * @type {void} - */ - /** - * Called when sidepanel is resized or toggled. - * @event module:svgcanvas.SvgCanvas#event:ext_workareaResized - * @type {void} -*/ - /** - * Called upon addition of the extension, or, if svgicons are set, - * after the icons are ready when extension SVG icons have loaded. - * @event module:svgcanvas.SvgCanvas#event:ext_callback - * @type {void} -*/ - - /** -* Sets the zoom to the given level. -* @function module:svgcanvas.SvgCanvas#setZoom -* @param {Float} zoomLevel - Float indicating the zoom level to change to -* @fires module:svgcanvas.SvgCanvas#event:ext_zoomChanged -* @returns {void} -*/ - this.setCurrentZoom = setZoomMethod; - - /** -* Group: Element Styling. -*/ - - /** -* @typedef {PlainObject} module:svgcanvas.PaintOptions -* @property {"solidColor"} type -*/ - - /** -* @function module:svgcanvas.SvgCanvas#getColor -* @param {string} type -* @returns {string|module:svgcanvas.PaintOptions|Float|module:jGraduate~Paint} The current fill/stroke option -*/ - this.getColor = function (type) { - return this.curProperties[type]; - }; - - /** -* Change the current stroke/fill color/gradient value. -* @function module:svgcanvas.SvgCanvas#setColor -* @param {string} type - String indicating fill or stroke -* @param {string} val - The value to set the stroke attribute to -* @param {boolean} preventUndo - Boolean indicating whether or not this should be an undoable option -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.setColor = setColorMethod; - - /** -* Apply the current gradient to selected element's fill or stroke. -* @function module:svgcanvas.SvgCanvas#setGradient -* @param {"fill"|"stroke"} type - String indicating "fill" or "stroke" to apply to an element -* @returns {void} -*/ - this.setGradient = setGradientMethod; - - /** -* Set a color/gradient to a fill/stroke. -* @function module:svgcanvas.SvgCanvas#setPaint -* @param {"fill"|"stroke"} type - String with "fill" or "stroke" -* @param {module:jGraduate.jGraduatePaintOptions} paint - The jGraduate paint object to apply -* @returns {void} -*/ - this.setPaint = setPaintMethod; - - /** -* @function module:svgcanvas.SvgCanvas#setStrokePaint -* @param {module:jGraduate~Paint} paint -* @returns {void} -*/ - this.setStrokePaint = function (paint) { - this.setPaint('stroke', paint); - }; - - /** -* @function module:svgcanvas.SvgCanvas#setFillPaint -* @param {module:jGraduate~Paint} paint -* @returns {void} -*/ - this.setFillPaint = function (paint) { - this.setPaint('fill', paint); - }; - - /** -* @function module:svgcanvas.SvgCanvas#getStrokeWidth -* @returns {Float|string} The current stroke-width value -*/ - this.getStrokeWidth = function () { - return this.curProperties.stroke_width; - }; - - /** -* Sets the stroke width for the current selected elements. -* When attempting to set a line's width to 0, this changes it to 1 instead. -* @function module:svgcanvas.SvgCanvas#setStrokeWidth -* @param {Float} val - A Float indicating the new stroke width value -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.setStrokeWidth = setStrokeWidthMethod; - - /** -* Set the given stroke-related attribute the given value for selected elements. -* @function module:svgcanvas.SvgCanvas#setStrokeAttr -* @param {string} attr - String with the attribute name -* @param {string|Float} val - String or number with the attribute value -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.setStrokeAttr = setStrokeAttrMethod; - - /** -* @typedef {PlainObject} module:svgcanvas.StyleOptions -* @property {string} fill -* @property {Float} fill_opacity -* @property {string} stroke -* @property {Float} stroke_width -* @property {string} stroke_dasharray -* @property {string} stroke_linejoin -* @property {string} stroke_linecap -* @property {Float} stroke_opacity -* @property {Float} opacity -*/ - - /** -* @function module:svgcanvas.SvgCanvas#getStyle -* @returns {module:svgcanvas.StyleOptions} current style options -*/ - this.getStyle = function () { - return this.curShape; - }; - - /** -* @function module:svgcanvas.SvgCanvas#getOpacity -* @returns {Float} the current opacity -*/ - this.getOpacity = getOpacity; - - /** -* Sets the given opacity on the current selected elements. -* @function module:svgcanvas.SvgCanvas#setOpacity -* @param {string} val -* @returns {void} -*/ - this.setOpacity = function (val) { - this.curShape.opacity = val; - changeSelectedAttribute('opacity', val); - }; - - /** -* @function module:svgcanvas.SvgCanvas#getFillOpacity -* @returns {Float} the current fill opacity -*/ - this.getFillOpacity = function () { - return this.curShape.fill_opacity; - }; - - /** -* @function module:svgcanvas.SvgCanvas#getStrokeOpacity -* @returns {string} the current stroke opacity -*/ - this.getStrokeOpacity = function () { - return this.curShape.stroke_opacity; - }; - - /** -* Sets the current fill/stroke opacity. -* @function module:svgcanvas.SvgCanvas#setPaintOpacity -* @param {string} type - String with "fill" or "stroke" -* @param {Float} val - Float with the new opacity value -* @param {boolean} preventUndo - Indicates whether or not this should be an undoable action -* @returns {void} -*/ - this.setPaintOpacity = function (type, val, preventUndo) { - this.curShape[type + '_opacity'] = val; - if (!preventUndo) { - changeSelectedAttribute(type + '-opacity', val); - } else { - changeSelectedAttributeNoUndo(type + '-opacity', val); - } - }; - - /** -* Gets the current fill/stroke opacity. -* @function module:svgcanvas.SvgCanvas#getPaintOpacity -* @param {"fill"|"stroke"} type - String with "fill" or "stroke" -* @returns {Float} Fill/stroke opacity -*/ - this.getPaintOpacity = function (type) { - return type === 'fill' ? this.getFillOpacity() : this.getStrokeOpacity(); - }; - - /** -* Gets the `stdDeviation` blur value of the given element. -* @function module:svgcanvas.SvgCanvas#getBlur -* @param {Element} elem - The element to check the blur value for -* @returns {string} stdDeviation blur attribute value -*/ - this.getBlur = function (elem) { - let val = 0; - if (elem) { - const filterUrl = elem.getAttribute('filter'); - if (filterUrl) { - const blur = getElem(elem.id + '_blur'); - if (blur) { - val = blur.firstChild.getAttribute('stdDeviation'); - } else { - const filterElem = getRefElem(filterUrl); - const blurElem = getFeGaussianBlur(filterElem); - if (blurElem !== null) { - val = blurElem.getAttribute('stdDeviation'); - } - } - } - } - return val; - }; - this.curCommand = null; this.filter = null; this.filterHidden = false; blurInit(this); - /** -* Sets the `stdDeviation` blur value on the selected element without being undoable. -* @function module:svgcanvas.SvgCanvas#setBlurNoUndo -* @param {Float} val - The new `stdDeviation` value -* @returns {void} -*/ - this.setBlurNoUndo = setBlurNoUndo; - - /** -* Sets the `x`, `y`, `width`, `height` values of the filter element in order to -* make the blur not be clipped. Removes them if not neeeded. -* @function module:svgcanvas.SvgCanvas#setBlurOffsets -* @param {Element} filterElem - The filter DOM element to update -* @param {Float} stdDev - The standard deviation value on which to base the offset size -* @returns {void} -*/ - this.setBlurOffsets = setBlurOffsets; - - /** -* Adds/updates the blur filter to the selected element. -* @function module:svgcanvas.SvgCanvas#setBlur -* @param {Float} val - Float with the new `stdDeviation` blur value -* @param {boolean} complete - Whether or not the action should be completed (to add to the undo manager) -* @returns {void} -*/ - this.setBlur = setBlur; - - - /** -* Check whether selected element is bold or not. -* @function module:svgcanvas.SvgCanvas#getBold -* @returns {boolean} Indicates whether or not element is bold -*/ - this.getBold = getBoldMethod; - - /** -* Make the selected element bold or normal. -* @function module:svgcanvas.SvgCanvas#setBold -* @param {boolean} b - Indicates bold (`true`) or normal (`false`) -* @returns {void} -*/ - this.setBold = setBoldMethod; - - /** -* Check whether selected element is in italics or not. -* @function module:svgcanvas.SvgCanvas#getItalic -* @returns {boolean} Indicates whether or not element is italic -*/ - this.getItalic = getItalicMethod; - - /** -* Make the selected element italic or normal. -* @function module:svgcanvas.SvgCanvas#setItalic -* @param {boolean} i - Indicates italic (`true`) or normal (`false`) -* @returns {void} -*/ - this.setItalic = setItalicMethod; - - /** -* Set the new text anchor. -* @function module:svgcanvas.SvgCanvas#setTextAnchor -* @param {string} textAnchor - The value of the text anchor (start, middle or end) -* @returns {void} -*/ - this.setTextAnchor = setTextAnchorMethod; - - /** -* @function module:svgcanvas.SvgCanvas#getFontFamily -* @returns {string} The current font family -*/ - this.getFontFamily = getFontFamilyMethod; - - /** -* Set the new font family. -* @function module:svgcanvas.SvgCanvas#setFontFamily -* @param {string} val - String with the new font family -* @returns {void} -*/ - this.setFontFamily = setFontFamilyMethod; - - /** -* Set the new font color. -* @function module:svgcanvas.SvgCanvas#setFontColor -* @param {string} val - String with the new font color -* @returns {void} -*/ - this.setFontColor = setFontColorMethod; - - /** -* @function module:svgcanvas.SvgCanvas#getFontColor -* @returns {string} The current font color -*/ - this.getFontColor = getFontColorMethod; - - /** -* @function module:svgcanvas.SvgCanvas#getFontSize -* @returns {Float} The current font size -*/ - this.getFontSize = getFontSizeMethod; - - /** -* Applies the given font size to the selected element. -* @function module:svgcanvas.SvgCanvas#setFontSize -* @param {Float} val - Float with the new font size -* @returns {void} -*/ - this.setFontSize = setFontSizeMethod; - - /** -* @function module:svgcanvas.SvgCanvas#getText -* @returns {string} The current text (`textContent`) of the selected element -*/ - this.getText = getTextMethod; - - /** -* Updates the text element with the given string. -* @function module:svgcanvas.SvgCanvas#setTextContent -* @param {string} val - String with the new text -* @returns {void} -*/ - this.setTextContent = setTextContentMethod; - - /** -* Sets the new image URL for the selected image element. Updates its size if -* a new URL is given. -* @function module:svgcanvas.SvgCanvas#setImageURL -* @param {string} val - String with the image URL/path -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.setImageURL = setImageURLMethod; - - /** -* Sets the new link URL for the selected anchor element. -* @function module:svgcanvas.SvgCanvas#setLinkURL -* @param {string} val - String with the link URL/path -* @returns {void} -*/ - this.setLinkURL = setLinkURLMethod; - - /** -* Sets the `rx` and `ry` values to the selected `rect` element -* to change its corner radius. -* @function module:svgcanvas.SvgCanvas#setRectRadius -* @param {string|Float} val - The new radius -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.setRectRadius = setRectRadiusMethod; - - /** -* Wraps the selected element(s) in an anchor element or converts group to one. -* @function module:svgcanvas.SvgCanvas#makeHyperlink -* @param {string} url -* @returns {void} -*/ - this.makeHyperlink = makeHyperlinkMethod; - - /** -* @function module:svgcanvas.SvgCanvas#removeHyperlink -* @returns {void} -*/ - this.removeHyperlink = removeHyperlinkMethod; - - /** -* Group: Element manipulation. -*/ - - /** -* Sets the new segment type to the selected segment(s). -* @function module:svgcanvas.SvgCanvas#setSegType -* @param {Integer} newType - New segment type. See {@link https://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg} for list -* @returns {void} -*/ - this.setSegType = setSegTypeMethod; - - /** -* Convert selected element to a path, or get the BBox of an element-as-path. -* @function module:svgcanvas.SvgCanvas#convertToPath -* @todo (codedread): Remove the getBBox argument and split this function into two. -* @param {Element} elem - The DOM element to be converted -* @param {boolean} getBBox - Boolean on whether or not to only return the path's BBox -* @returns {void|DOMRect|false|SVGPathElement|null} If the getBBox flag is true, the resulting path's bounding box object. -* Otherwise the resulting path element is returned. -*/ - this.convertToPath = (elem, getBBox) => { - if (isNullish(elem)) { - const elems = this.selectedElements; - elems.forEach(function(el){ - if (el) { this.convertToPath(el); } - }); - return undefined; - } - if (getBBox) { - return getBBoxOfElementAsPath(elem, this.addSVGElemensFromJson, pathActions); - } - // TODO: Why is this applying attributes from this.curShape, then inside utilities.convertToPath it's pulling addition attributes from elem? - // TODO: If convertToPath is called with one elem, this.curShape and elem are probably the same; but calling with multiple is a bug or cool feature. - const attrs = { - fill: this.curShape.fill, - 'fill-opacity': this.curShape.fill_opacity, - stroke: this.curShape.stroke, - 'stroke-width': this.curShape.stroke_width, - 'stroke-dasharray': this.curShape.stroke_dasharray, - 'stroke-linejoin': this.curShape.stroke_linejoin, - 'stroke-linecap': this.curShape.stroke_linecap, - 'stroke-opacity': this.curShape.stroke_opacity, - opacity: this.curShape.opacity, - visibility: 'hidden' - }; - return convertToPath( - elem, attrs, this.addSVGElemensFromJson, pathActions, - this.clearSelection, this.addToSelection, hstry, this.addCommandToHistory - ); - }; - - /** -* This function makes the changes to the elements. It does not add the change -* to the history stack. -* @param {string} attr - Attribute name -* @param {string|Float} newValue - String or number with the new attribute value -* @param {Element[]} elems - The DOM elements to apply the change to -* @returns {void} -*/ - const changeSelectedAttributeNoUndo = changeSelectedAttributeNoUndoMethod; - - /** -* Change the given/selected element and add the original value to the history stack. -* If you want to change all `selectedElements`, ignore the `elems` argument. -* If you want to change only a subset of `selectedElements`, then send the -* subset to this function in the `elems` argument. -* @function module:svgcanvas.SvgCanvas#changeSelectedAttribute -* @param {string} attr - String with the attribute name -* @param {string|Float} val - String or number with the new attribute value -* @param {Element[]} elems - The DOM elements to apply the change to -* @returns {void} -*/ - const changeSelectedAttribute = this.changeSelectedAttribute = changeSelectedAttributeMethod; - - /** -* Initialize from select-elem.js. -* Send in an object implementing the ElementContainer interface (see select-elem.js). -*/ selectedElemInit(this); - /** -* Removes all selected elements from the DOM and adds the change to the -* history stack. -* @function module:svgcanvas.SvgCanvas#deleteSelectedElements -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.deleteSelectedElements = deleteSelectedElements; - - /** -* Removes all selected elements from the DOM and adds the change to the -* history stack. Remembers removed elements on the clipboard. -* @function module:svgcanvas.SvgCanvas#cutSelectedElements -* @returns {void} -*/ - this.cutSelectedElements = () => { - this.copySelectedElements(); - this.deleteSelectedElements(); - }; - /** * Flash the clipboard data momentarily on localStorage so all tabs can see. * @returns {void} @@ -1625,231 +300,17 @@ class SvgCanvas { window.addEventListener('storage', storageChange, false); // Ask other tabs for sessionStorage (this is ONLY to trigger event). localStorage.setItem(CLIPBOARD_ID + '_startup', Math.random()); - /** -* Remembers the current selected elements on the clipboard. -* @function module:svgcanvas.SvgCanvas#copySelectedElements -* @returns {void} -*/ - this.copySelectedElements = copySelectedElements; pasteInit(this); - this.pasteElements = pasteElementsMethod; - - /** -* Wraps all the selected elements in a group (`g`) element. -* @function module:svgcanvas.SvgCanvas#groupSelectedElements -* @param {"a"|"g"} [type="g"] - type of element to group into, defaults to `` -* @param {string} [urlArg] -* @returns {void} -*/ - this.groupSelectedElements = groupSelectedElements; - - /** -* Pushes all appropriate parent group properties down to its children, then -* removes them from the group. -* @function module:svgcanvas.SvgCanvas#pushGroupProperties -* @param {SVGAElement|SVGGElement} g -* @param {boolean} undoable -* @returns {BatchCommand|void} -*/ - this.pushGroupProperties = pushGroupProperty; - - /** -* Unwraps all the elements in a selected group (`g`) element. This requires -* significant recalculations to apply group's transforms, etc. to its children. -* @function module:svgcanvas.SvgCanvas#ungroupSelectedElement -* @returns {void} -*/ - this.ungroupSelectedElement = ungroupSelectedElement; - - /** -* Repositions the selected element to the bottom in the DOM to appear on top of -* other elements. -* @function module:svgcanvas.SvgCanvas#moveToTopSelectedElement -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.moveToTopSelectedElement = moveToTopSelectedElem; - - /** -* Repositions the selected element to the top in the DOM to appear under -* other elements. -* @function module:svgcanvas.SvgCanvas#moveToBottomSelectedElement -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.moveToBottomSelectedElement = moveToBottomSelectedElem; - - /** -* Moves the select element up or down the stack, based on the visibly -* intersecting elements. -* @function module:svgcanvas.SvgCanvas#moveUpDownSelected -* @param {"Up"|"Down"} dir - String that's either 'Up' or 'Down' -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {void} -*/ - this.moveUpDownSelected = moveUpDownSelected; - - /** -* Moves selected elements on the X/Y axis. -* @function module:svgcanvas.SvgCanvas#moveSelectedElements -* @param {Float} dx - Float with the distance to move on the x-axis -* @param {Float} dy - Float with the distance to move on the y-axis -* @param {boolean} undoable - Boolean indicating whether or not the action should be undoable -* @fires module:svgcanvas.SvgCanvas#event:changed -* @returns {BatchCommand|void} Batch command for the move -*/ - this.moveSelectedElements = moveSelectedElements; - - /** -* Create deep DOM copies (clones) of all selected elements and move them slightly -* from their originals. -* @function module:svgcanvas.SvgCanvas#cloneSelectedElements -* @param {Float} x Float with the distance to move on the x-axis -* @param {Float} y Float with the distance to move on the y-axis -* @returns {void} -*/ - this.cloneSelectedElements = cloneSelectedElements; - - /** -* Aligns selected elements. -* @function module:svgcanvas.SvgCanvas#alignSelectedElements -* @param {string} type - String with single character indicating the alignment type -* @param {"selected"|"largest"|"smallest"|"page"} relativeTo -* @returns {void} -*/ - this.alignSelectedElements = alignSelectedElements; - - /** -* Group: Additional editor tools. -*/ - - /** -* @name module:svgcanvas.SvgCanvas#contentW -* @type {Float} -*/ - this.contentW = getResolution().w; - /** -* @name module:svgcanvas.SvgCanvas#contentH -* @type {Float} -*/ - this.contentH = getResolution().h; - - /** -* @typedef {PlainObject} module:svgcanvas.CanvasInfo -* @property {Float} x - The canvas' new x coordinate -* @property {Float} y - The canvas' new y coordinate -* @property {string} oldX - The canvas' old x coordinate -* @property {string} oldY - The canvas' old y coordinate -* @property {Float} d_x - The x position difference -* @property {Float} d_y - The y position difference -*/ - - /** -* Updates the editor canvas width/height/position after a zoom has occurred. -* @function module:svgcanvas.SvgCanvas#updateCanvas -* @param {Float} w - Float with the new width -* @param {Float} h - Float with the new height -* @fires module:svgcanvas.SvgCanvas#event:ext_canvasUpdated -* @returns {module:svgcanvas.CanvasInfo} -*/ - this.updateCanvas = updateCanvas; - - /** -* Set the background of the editor (NOT the actual document). -* @function module:svgcanvas.SvgCanvas#setBackground -* @param {string} color - String with fill color to apply -* @param {string} url - URL or path to image to use -* @returns {void} -*/ - this.setBackground = setBackgroundMethod; - - /** -* Select the next/previous element within the current layer. -* @function module:svgcanvas.SvgCanvas#cycleElement -* @param {boolean} next - true = next and false = previous element -* @fires module:svgcanvas.SvgCanvas#event:selected -* @returns {void} -*/ - this.cycleElement = cycleElement; + this.contentW = this.getResolution().w; + this.contentH = this.getResolution().h; this.clear(); - - /** -* @interface module:svgcanvas.PrivateMethods -* @type {PlainObject} -* @property {module:svgcanvas~addCommandToHistory} addCommandToHistory -* @property {module:history.HistoryCommand} BatchCommand -* @property {module:history.HistoryCommand} ChangeElementCommand -* @property {module:utilities.decode64} decode64 -* @property {module:utilities.dropXMLInternalSubset} dropXMLInternalSubset -* @property {module:utilities.encode64} encode64 -* @property {module:svgcanvas~ffClone} ffClone -* @property {module:svgcanvas~findDuplicateGradient} findDuplicateGradient -* @property {module:utilities.getPathBBox} getPathBBox -* @property {module:units.getTypeMap} getTypeMap -* @property {module:draw.identifyLayers} identifyLayers -* @property {module:history.HistoryCommand} InsertElementCommand -* @property {module:browser.isChrome} isChrome -* @property {module:math.isIdentity} isIdentity -* @property {module:svgcanvas~logMatrix} logMatrix -* @property {module:history.HistoryCommand} MoveElementCommand -* @property {module:namespaces.NS} NS -* @property {module:utilities.preventClickDefault} preventClickDefault -* @property {module:history.HistoryCommand} RemoveElementCommand -* @property {module:SVGTransformList.SVGEditTransformList} SVGEditTransformList -* @property {module:utilities.text2xml} text2xml -* @property {module:math.transformBox} transformBox -* @property {module:math.transformPoint} transformPoint -* @property {module:utilities.walkTree} walkTree -*/ - /** -* @deprecated getPrivateMethods -* Since all methods are/should be public somehow, this function should be removed; -* we might require `import` in place of this in the future once ES6 Modules -* widespread - -* Being able to access private methods publicly seems wrong somehow, -* but currently appears to be the best way to allow testing and provide -* access to them to plugins. -* @function module:svgcanvas.SvgCanvas#getPrivateMethods -* @returns {module:svgcanvas.PrivateMethods} -*/ - this.getPrivateMethods = () => { - return { - addCommandToHistory: this.addCommandToHistory, - BatchCommand, - ChangeElementCommand, - decode64, - dropXMLInternalSubset, - encode64, - ffClone, - findDefs, - findDuplicateGradient, - getElem, - getPathBBox, - getTypeMap, - getUrlFromAttr, - identifyLayers: draw.identifyLayers, - InsertElementCommand, - isChrome, - isIdentity, - logMatrix, - MoveElementCommand, - NS, - preventClickDefault, - RemoveElementCommand, - text2xml, - transformBox, - transformPoint, - walkTree - }; - }; } // End constructor + getSvgOption() { return this.saveOptions; } + setSvgOption(key, value) { this.saveOptions[key] = value; } getSelectedElements() { return this.selectedElements; } - setSelectedElements(key, value) { - this.selectedElements[key] = value; - } + setSelectedElements(key, value) { this.selectedElements[key] = value; } setEmptySelectedElements() { this.selectedElements = []; } getSvgRoot() { return this.svgroot; } getDOMDocument() { return this.svgdoc; } @@ -1868,7 +329,7 @@ class SvgCanvas { getStartTransform() { return this.startTransform; } setStartTransform(transform) { this.startTransform = transform; } getZoom () { return this.zoom; } - round(val) { return Number.parseInt(val * this.zoom) / this.zoom; } + round(val) { return Number.parseInt(val * this.zoom) / this.zoom; } createSVGElement(jsonMap) { return this.addSVGElemensFromJson(jsonMap); } getContainer() { return this.container; } setStarted(s) { this.started = s; } @@ -1885,36 +346,28 @@ class SvgCanvas { this.call('selected', grips); } /** - * @param {PlainObject} changes - * @param {ChangeElementCommand} changes.cmd - * @param {SVGPathElement} changes.elem - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ + * @param {PlainObject} changes + * @param {ChangeElementCommand} changes.cmd + * @param {SVGPathElement} changes.elem + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ endChanges({ cmd, elem }) { this.addCommandToHistory(cmd); this.call('changed', [ elem ]); } - getCurrentMode() { - return this.currentMode; - } + getCurrentMode() { return this.currentMode; } setCurrentMode(cm) { this.currentMode = cm; return this.currentMode; } - getDrawnPath() { - return this.drawnPath; - } + getDrawnPath() { return this.drawnPath; } setDrawnPath(dp) { this.drawnPath = dp; return this.drawnPath; } - setCurrentGroup(cg) { - this.currentGroup = cg; - } - changeSvgContent() { - this.call('changed', [ this.svgContent ]); - } + setCurrentGroup(cg) { this.currentGroup = cg; } + changeSvgContent() { this.call('changed', [ this.svgContent ]); } getStarted() { return this.started; } getCanvas() { return this; } getrootSctm() { return this.rootSctm; } @@ -1936,7 +389,7 @@ class SvgCanvas { getStart(key) { return this.start[key]; } getEnd(key) { return this.end[key]; } getbSpline(key) { return this.bSpline[key]; } - getNextPos(key) { return this.addToSelection.nextPos[key]; } + getNextPos(key) { return this.nextPos[key]; } getControllPoint1(key) { return this.controllPoint1[key]; } getControllPoint2(key) { return this.controllPoint2[key]; } getFreehand(key) { return this.freehand[key]; } @@ -1961,13 +414,12 @@ class SvgCanvas { setCurText(key, value) { this.curText[key] = value; } setFreehand(key, value) { this.freehand[key] = value; } setCurBBoxes(value) { this.curBBoxes = value; } + getCurBBoxes() { return this.curBBoxes; } setInitBbox(value) { this.initBbox = value; } setRootSctm(value) { this.rootSctm = value; } setCurrentResizeMode(value) { this.currentResizeMode = value; } setLastClickPoint(value) { this.lastClickPoint = value; } - getId() { - return this.getCurrentDrawing().getId(); - } + getId() { return this.getCurrentDrawing().getId(); } getUIStrings() { return this.uiStrings; } getNsMap() { return this.nsMap; } getSvgOptionApply() { return this.saveOptions.apply; } @@ -1976,7 +428,7 @@ class SvgCanvas { setEncodableImages(key, value) { this.encodableImages[key] = value; } getVisElems() { return visElems; } getIdPrefix() { return this.idprefix; } - getDataStorage() { return this.dataStorage; } + getDataStorage() { return dataStorage; } setZoom(value) { this.zoom = value; } getImportIds(key) { return this.importIds[key]; } setImportIds(key, value) { this.importIds[key] = value; } @@ -1994,23 +446,20 @@ class SvgCanvas { getSvgContent() { return this.svgContent; } getExtensions() { return this.extensions; } getSelector() { return Selector; } - + getMode() { return this.currentMode; } // The current editor mode string + getNextId() { return this.getCurrentDrawing().getNextId(); } + getCurCommand() { return this.curCommand; } + setCurCommand(value) { this.curCommand = value; } + getFilter() { return this.filter; } + setFilter(value) { this.filter = value; } + getFilterHidden() { return this.filterHidden; } + setFilterHidden(value) { this.filterHidden = value; } /** - * @function module:svgcanvas.SvgCanvas#getMode - * @returns {string} The current editor mode string + * Sets the editor's mode to the given string. + * @function module:svgcanvas.SvgCanvas#setMode + * @param {string} name - String with the new mode to change to + * @returns {void} */ - getMode() { - return this.currentMode; - } - getNextId() { - return this.getCurrentDrawing().getNextId(); - } - /** -* Sets the editor's mode to the given string. -* @function module:svgcanvas.SvgCanvas#setMode -* @param {string} name - String with the new mode to change to -* @returns {void} -*/ setMode(name) { this.pathActions.clear(true); this.textActions.clear(); @@ -2018,34 +467,26 @@ class SvgCanvas { this.currentMode = name; } /** -* Clears the current document. This is not an undoable action. -* @function module:svgcanvas.SvgCanvas#clear -* @fires module:svgcanvas.SvgCanvas#event:cleared -* @returns {void} -*/ + * Clears the current document. This is not an undoable action. + * @function module:svgcanvas.SvgCanvas#clear + * @fires module:svgcanvas.SvgCanvas#event:cleared + * @returns {void} + */ clear() { this.pathActions.clear(); - this.clearSelection(); - // clear the svgcontent node this.clearSvgContentElement(); - // create new document this.current_drawing_ = new draw.Drawing(this.svgContent); - // create empty first layer this.createLayer('Layer 1'); - // clear the undo stack this.undoMgr.resetUndoStack(); - // reset the selector manager this.selectorManager.initGroup(); - // reset the rubber band box this.rubberBox = this.selectorManager.getRubberBandBox(); - this.call('cleared'); } runExtension (name, action, vars) { @@ -2058,13 +499,13 @@ class SvgCanvas { if (name in this.extensions) { throw new Error('Cannot add extension "' + name + '", an extension by that name already exists.'); } - const argObj = this.mergeDeep(this.getPrivateMethods(), { + const argObj = { importLocale, svgroot: this.svgroot, svgContent: this.svgContent, nonce: this.getCurrentDrawing().getNonce(), selectorManager: this.selectorManager - }); + }; const extObj = await extInitFunc(argObj); if (extObj) { extObj.name = name; @@ -2072,9 +513,7 @@ class SvgCanvas { this.extensions[name] = extObj; return this.call('extension_added', extObj); } - addCommandToHistory(cmd) { - this.undoMgr.addCommandToHistory(cmd); - } + addCommandToHistory(cmd) { this.undoMgr.addCommandToHistory(cmd); } restoreRefElements(elem) { // Look for missing reference elements, restore any found const attrs = {}; @@ -2099,16 +538,418 @@ class SvgCanvas { } } } + call(ev, arg) { + if (this.events[ev]) { + return this.events[ev](window, arg); + } + return undefined; + } + /** + * Attaches a callback function to an event. + * @function module:svgcanvas.SvgCanvas#bind + * @param {string} ev - String indicating the name of the event + * @param {module:svgcanvas.EventHandler} f - The callback function to bind to the event + * @returns {module:svgcanvas.EventHandler} The previous event + */ + bind (ev, f) { + const old = this.events[ev]; + this.events[ev] = f; + return old; + } + /** + * Selects only the given elements, shortcut for `clearSelection(); addToSelection()`. + * @function module:svgcanvas.SvgCanvas#selectOnly + * @param {Element[]} elems - an array of DOM elements to be selected + * @param {boolean} showGrips - Indicates whether the resize grips should be shown + * @returns {void} + */ + selectOnly(elems, showGrips) { + this.clearSelection(true); + this.addToSelection(elems, showGrips); + } + /** + * Removes elements from the selection. + * @function module:svgcanvas.SvgCanvas#removeFromSelection + * @param {Element[]} elemsToRemove - An array of elements to remove from selection + * @returns {void} + */ + removeFromSelection(elemsToRemove) { + if (isNullish(this.selectedElements[0])) { return; } + if (!elemsToRemove.length) { return; } + + // find every element and remove it from our array copy + const newSelectedItems = []; + const len = this.selectedElements.length; + for (let i = 0; i < len; ++i) { + const elem = this.selectedElements[i]; + if (elem) { + // keep the item + if (!elemsToRemove.includes(elem)) { + newSelectedItems.push(elem); + } else { // remove the item and its selector + this.selectorManager.releaseSelector(elem); + } + } + } + // the copy becomes the master now + this.selectedElements = newSelectedItems; + } + /** + * Clears the selection, then adds all elements in the current layer to the selection. + * @function module:svgcanvas.SvgCanvas#selectAllInCurrentLayer + * @returns {void} + */ + selectAllInCurrentLayer() { + const currentLayer = this.getCurrentDrawing().getCurrentLayer(); + if (currentLayer) { + this.currentMode = 'select'; + if (this.currentGroup) { + this.selectOnly(this.currentGroup.children); + } else { + this.selectOnly(currentLayer.children); + } + } + } + getOpacity() { + return this.curShape.opacity; + } + /** + * @function module:svgcanvas.SvgCanvas#getSnapToGrid + * @returns {boolean} The current snap to grid setting + */ + getSnapToGrid() { return this.curConfig.gridSnapping; } + /** + * @function module:svgcanvas.SvgCanvas#getVersion + * @returns {string} A string which describes the revision number of SvgCanvas. + */ + getVersion() { return 'svgcanvas.js ($Rev$)'; } + /** + * Update interface strings with given values. + * @function module:svgcanvas.SvgCanvas#setUiStrings + * @param {module:path.uiStrings} strs - Object with strings (see the [locales API]{@link module:locale.LocaleStrings} and the [tutorial]{@tutorial LocaleDocs}) + * @returns {void} + */ + setUiStrings(strs) { + Object.assign(this.uiStrings, strs.notification); + pathModule.setUiStrings(strs); + } + /** + * Update configuration options with given values. + * @function module:svgcanvas.SvgCanvas#setConfig + * @param {module:SVGEditor.Config} opts - Object with options + * @returns {void} + */ + setConfig(opts) { Object.assign(this.curConfig, opts); } + /** + * @function module:svgcanvas.SvgCanvas#getDocumentTitle + * @returns {string|void} The current document title or an empty string if not found + */ + getDocumentTitle() { return this.getTitle(this.svgContent); } + getOffset() { + return { x: Number(this.svgContent.getAttribute('x')), y: Number(this.svgContent.getAttribute('y')) }; + } + getColor(type) { return this.curProperties[type]; } + setStrokePaint(paint) { this.setPaint('stroke', paint); } + /** + * @function module:svgcanvas.SvgCanvas#setFillPaint + * @param {module:jGraduate~Paint} paint + * @returns {void} + */ + setFillPaint(paint) { this.setPaint('fill', paint); } + /** + * @function module:svgcanvas.SvgCanvas#getStrokeWidth + * @returns {Float|string} The current stroke-width value + */ + getStrokeWidth() { return this.curProperties.stroke_width; } + /** + * @function module:svgcanvas.SvgCanvas#getStyle + * @returns {module:svgcanvas.StyleOptions} current style options + */ + getStyle() { return this.curShape; } + /** + * Sets the given opacity on the current selected elements. + * @function module:svgcanvas.SvgCanvas#setOpacity + * @param {string} val + * @returns {void} + */ + setOpacity(val) { + this.curShape.opacity = val; + this.changeSelectedAttribute('opacity', val); + } + /** + * @function module:svgcanvas.SvgCanvas#getFillOpacity + * @returns {Float} the current fill opacity + */ + getFillOpacity() { return this.curShape.fill_opacity; } + /** + * @function module:svgcanvas.SvgCanvas#getStrokeOpacity + * @returns {string} the current stroke opacity + */ + getStrokeOpacity() { return this.curShape.stroke_opacity; } + /** + * Sets the current fill/stroke opacity. + * @function module:svgcanvas.SvgCanvas#setPaintOpacity + * @param {string} type - String with "fill" or "stroke" + * @param {Float} val - Float with the new opacity value + * @param {boolean} preventUndo - Indicates whether or not this should be an undoable action + * @returns {void} + */ + setPaintOpacity(type, val, preventUndo) { + this.curShape[type + '_opacity'] = val; + if (!preventUndo) { + this.changeSelectedAttribute(type + '-opacity', val); + } else { + this.changeSelectedAttributeNoUndo(type + '-opacity', val); + } + } + /** + * Gets the current fill/stroke opacity. + * @function module:svgcanvas.SvgCanvas#getPaintOpacity + * @param {"fill"|"stroke"} type - String with "fill" or "stroke" + * @returns {Float} Fill/stroke opacity + */ + getPaintOpacity(type) { + return type === 'fill' ? this.getFillOpacity() : this.getStrokeOpacity(); + } + /** + * Gets the `stdDeviation` blur value of the given element. + * @function module:svgcanvas.SvgCanvas#getBlur + * @param {Element} elem - The element to check the blur value for + * @returns {string} stdDeviation blur attribute value + */ + getBlur(elem) { + let val = 0; + if (elem) { + const filterUrl = elem.getAttribute('filter'); + if (filterUrl) { + const blur = getElem(elem.id + '_blur'); + if (blur) { + val = blur.firstChild.getAttribute('stdDeviation'); + } else { + const filterElem = getRefElem(filterUrl); + const blurElem = getFeGaussianBlur(filterElem); + if (blurElem !== null) { + val = blurElem.getAttribute('stdDeviation'); + } + } + } + } + return val; + } + /** + * Sets a given URL to be a "last good image" URL. + * @function module:svgcanvas.SvgCanvas#setGoodImage + * @param {string} val + * @returns {void} + */ + setGoodImage(val) { this.lastGoodImgUrl = val; } + /** + * Returns the current drawing as raw SVG XML text. + * @function module:svgcanvas.SvgCanvas#getSvgString + * @returns {string} The current drawing as raw SVG XML text. + */ + getSvgString () { + this.saveOptions.apply = false; + return this.svgCanvasToString(); + } + /** + * This function determines whether to use a nonce in the prefix, when + * generating IDs for future documents in SVG-Edit. + * If you're controlling SVG-Edit externally, and want randomized IDs, call + * this BEFORE calling `svgCanvas.setSvgString`. + * @function module:svgcanvas.SvgCanvas#randomizeIds + * @param {boolean} [enableRandomization] If true, adds a nonce to the prefix. Thus + * `svgCanvas.randomizeIds() <==> svgCanvas.randomizeIds(true)` + * @returns {void} + */ + randomizeIds (enableRandomization) { + if (arguments.length > 0 && enableRandomization === false) { + draw.randomizeIds(false, this.getCurrentDrawing()); + } else { + draw.randomizeIds(true, this.getCurrentDrawing()); + } + } + /** + * Convert selected element to a path, or get the BBox of an element-as-path. + * @function module:svgcanvas.SvgCanvas#convertToPath + * @todo (codedread): Remove the getBBox argument and split this function into two. + * @param {Element} elem - The DOM element to be converted + * @param {boolean} getBBox - Boolean on whether or not to only return the path's BBox + * @returns {void|DOMRect|false|SVGPathElement|null} If the getBBox flag is true, the resulting path's bounding box object. + * Otherwise the resulting path element is returned. + */ + convertToPath(elem, getBBox) { + if (isNullish(elem)) { + const elems = this.selectedElements; + elems.forEach((el) => { + if (el) { this.convertToPath(el); } + }); + return undefined; + } + if (getBBox) { + return getBBoxOfElementAsPath(elem, this.addSVGElemensFromJson, this.pathActions); + } + // TODO: Why is this applying attributes from this.curShape, then inside utilities.convertToPath it's pulling addition attributes from elem? + // TODO: If convertToPath is called with one elem, this.curShape and elem are probably the same; but calling with multiple is a bug or cool feature. + const attrs = { + fill: this.curShape.fill, + 'fill-opacity': this.curShape.fill_opacity, + stroke: this.curShape.stroke, + 'stroke-width': this.curShape.stroke_width, + 'stroke-dasharray': this.curShape.stroke_dasharray, + 'stroke-linejoin': this.curShape.stroke_linejoin, + 'stroke-linecap': this.curShape.stroke_linecap, + 'stroke-opacity': this.curShape.stroke_opacity, + opacity: this.curShape.opacity, + visibility: 'hidden' + }; + return convertToPath( + elem, attrs, this.addSVGElemensFromJson, this.pathActions, + this.clearSelection, this.addToSelection, hstry, this.addCommandToHistory + ); + } + /** + * Removes all selected elements from the DOM and adds the change to the + * history stack. Remembers removed elements on the clipboard. + * @function module:svgcanvas.SvgCanvas#cutSelectedElements + * @returns {void} + */ + cutSelectedElements() { + this.copySelectedElements(); + this.deleteSelectedElements(); + } + initializeSvgCanvasMethods() { + this.getJsonFromSvgElements = getJsonFromSvgElements; + this.addSVGElemensFromJson = addSVGElementsFromJson; + this.clearSvgContentElement = clearSvgContentElementInit; + this.textActions = textActionsMethod; + this.undoMgr = getUndoManager(); + this.getIntersectionList = getIntersectionListMethod; + this.getStrokedBBox = getStrokedBBoxDefaultVisible; + this.getVisibleElements = getVisibleElements; + this.uniquifyElems = uniquifyElemsMethod; + this.setUseData = setUseDataMethod; + this.convertGradients = convertGradientsMethod; + this.setSvgString = setSvgString; + this.importSvgString = importSvgString; + this.runExtensions = runExtensionsMethod; + this.clearSelection = clearSelectionMethod; + this.addToSelection = addToSelectionMethod; + this.stringToHTML = stringToHTML; + this.insertChildAtIndex = insertChildAtIndex; + this.getClosest = getClosest; + this.getParents = getParents; + this.isLayer = draw.Layer.isLayer; + this.matrixMultiply = matrixMultiply; + this.hasMatrixTransform = hasMatrixTransform; + this.transformListToTransform = transformListToTransform; + this.convertToNum = convertToNum; + this.findDefs = findDefs; + this.getUrlFromAttr = getUrlFromAttr; + this.getHref = getHref; + this.setHref = setHref; + this.getBBox = utilsGetBBox; + this.getRotationAngle = getRotationAngle; + this.getElem = getElem; + this.getRefElem = getRefElem; + this.assignAttributes = assignAttributes; + this.cleanupElement = cleanupElement; + this.remapElement = remapElement; + this.recalculateDimensions = recalculateDimensions; + this.sanitizeSvg = sanitizeSvg; + this.groupSvgElem = groupSvgElem; // Wrap an SVG element into a group element, mark the group as 'gsvg'. + this.prepareSvg = prepareSvg; //Runs the SVG Document through the sanitizer and then updates its paths. + this.setRotationAngle = setRotationAngle; // Removes any old rotations if present, prepends a new rotation at the transformed center. + this.recalculateAllSelectedDimensions = recalculateAllSelectedDimensions; // Runs `recalculateDimensions` on selected elements,adding changes to a single batch command. + this.copySelectedElements = copySelectedElements; + this.pasteElements = pasteElementsMethod; // Remembers the current selected elements on the clipboard. + this.groupSelectedElements = groupSelectedElements; // Wraps all the selected elements in a group (`g`) element. + this.pushGroupProperties = pushGroupProperty; // Pushes all appropriate parent group properties down to its children + this.ungroupSelectedElement = ungroupSelectedElement; // Unwraps all the elements in a selected group (`g`) element + this.moveToTopSelectedElement = moveToTopSelectedElem; // Repositions the selected element to the bottom in the DOM to appear on top + this.moveToBottomSelectedElement = moveToBottomSelectedElem; // Repositions the selected element to the top in the DOM to appear under other elements + this.moveUpDownSelected = moveUpDownSelected; // Moves the select element up or down the stack, based on the visibly + this.moveSelectedElements = moveSelectedElements; // Moves selected elements on the X/Y axis. + this.cloneSelectedElements = cloneSelectedElements; // Create deep DOM copies (clones) of all selected elements and move them slightly + this.alignSelectedElements = alignSelectedElements; // Aligns selected elements. + this.updateCanvas = updateCanvas; // Updates the editor canvas width/height/position after a zoom has occurred. + this.cycleElement = cycleElement; // Select the next/previous element within the current layer. + this.getMouseTarget = getMouseTargetMethod; + this.removeUnusedDefElems = removeUnusedDefElemsMethod; //remove DOM elements inside the `` if they are notreferred to, + this.svgCanvasToString = svgCanvasToString; // Main function to set up the SVG content for output. + this.svgToString = svgToString; // Sub function ran on each SVG element to convert it to a string as desired. + this.embedImage = embedImage; // Converts a given image file to a data URL when possibl + this.rasterExport = rasterExport; // Generates a PNG (or JPG, BMP, WEBP) Data URL based on the current image + this.exportPDF = exportPDF; // Generates a PDF based on the current image, then calls "exportedPDF" + this.identifyLayers = draw.identifyLayers; + this.createLayer = draw.createLayer; + this.cloneLayer = draw.cloneLayer; + this.deleteCurrentLayer = draw.deleteCurrentLayer; + this.setCurrentLayer = draw.setCurrentLayer; + this.renameCurrentLayer = draw.renameCurrentLayer; + this.setCurrentLayerPosition = draw.setCurrentLayerPosition; + this.setLayerVisibility = draw.setLayerVisibility; + this.moveSelectedToLayer = draw.moveSelectedToLayer; + this.mergeLayer = draw.mergeLayer; + this.mergeAllLayers = draw.mergeAllLayers; + this.leaveContext = draw.leaveContext; + this.setContext = draw.setContext; + this.getBold = elemGetSet.getBoldMethod; // Check whether selected element is bold or not. + this.setBold = elemGetSet.setBoldMethod; // Make the selected element bold or normal. + this.getItalic = elemGetSet.getItalicMethod; // Check whether selected element is in italics or not. + this.setItalic = elemGetSet.setItalicMethod; // Make the selected element italic or normal. + this.setTextAnchor = elemGetSet.setTextAnchorMethod; // Set the new text anchor. + this.getFontFamily = elemGetSet.getFontFamilyMethod; // The current font family + this.setFontFamily = elemGetSet.setFontFamilyMethod; // Set the new font family. + this.setFontColor = elemGetSet.setFontColorMethod; // Set the new font color. + this.getFontColor = elemGetSet.getFontColorMethod; // The current font color + this.getFontSize = elemGetSet.getFontSizeMethod; // The current font size + this.setFontSize = elemGetSet.setFontSizeMethod; // Applies the given font size to the selected element. + this.getText = elemGetSet.getTextMethod; // current text (`textContent`) of the selected element + this.setTextContent = elemGetSet.setTextContentMethod; // Updates the text element with the given string. + this.setImageURL = elemGetSet.setImageURLMethod; // Sets the new image URL for the selected image element + this.setLinkURL = elemGetSet.setLinkURLMethod; // Sets the new link URL for the selected anchor element. + this.setRectRadius = elemGetSet.setRectRadiusMethod; // Sets the `rx` and `ry` values to the selected `rect` element + this.makeHyperlink = elemGetSet.makeHyperlinkMethod; // Wraps the selected element(s) in an anchor element or converts group to one. + this.removeHyperlink = elemGetSet.removeHyperlinkMethod; + this.setSegType = elemGetSet.setSegTypeMethod; // Sets the new segment type to the selected segment(s). + this.setStrokeWidth = elemGetSet.setStrokeWidthMethod; // Sets the stroke width for the current selected elements. + this.getResolution = elemGetSet.getResolutionMethod; // The current dimensions and zoom level in an object + this.getTitle = elemGetSet.getTitleMethod; // the current group/SVG's title contents or `undefined` if no element + this.setGroupTitle = elemGetSet.setGroupTitleMethod; // Sets the group/SVG's title content. + this.setStrokeAttr = elemGetSet.setStrokeAttrMethod; // Set the given stroke-related attribute the given value for selected elements. + this.setBackground = elemGetSet.setBackgroundMethod; // Set the background of the editor (NOT the actual document). + this.setDocumentTitle = elemGetSet.setDocumentTitleMethod; // Adds/updates a title element for the document with the given name. + this.getEditorNS = elemGetSet.getEditorNSMethod; // Returns the editor's namespace URL, optionally adding it to the root element. + this.setResolution = elemGetSet.setResolutionMethod; // Changes the document's dimensions to the given size. + this.setBBoxZoom = elemGetSet.setBBoxZoomMethod; // Sets the zoom level on the canvas-side based on the given value. + this.setCurrentZoom = elemGetSet.setZoomMethod; // Sets the zoom to the given level. + this.setColor = elemGetSet.setColorMethod; // Change the current stroke/fill color/gradien + this.setGradient = elemGetSet.setGradientMethod; // Apply the current gradient to selected element's fill or stroke. + this.setPaint = elemGetSet.setPaintMethod; // Set a color/gradient to a fill/stroke. + this.changeSelectedAttributeNoUndo = changeSelectedAttributeNoUndoMethod; // This function makes the changes to the elements. It does not add the change to the history stack. + this.changeSelectedAttribute = changeSelectedAttributeMethod; // Change the given/selected element and add the original value to the history stack. + this.deleteSelectedElements = deleteSelectedElements; // Removes all selected elements from the DOM and adds the change to the history + this.setBlurNoUndo = setBlurNoUndo; // Sets the `stdDeviation` blur value on the selected element without being undoable. + this.setBlurOffsets = setBlurOffsets; // Sets the `x`, `y`, `width`, `height` values of the filter element in order to make the blur not be clipped. Removes them if not neeeded. + this.setBlur = setBlur; // Adds/updates the blur filter to the selected element. + this.smoothControlPoints = pathModule.smoothControlPoints; + this.getTypeMap = getTypeMap; + this.NS = NS; + this.$id = $id; + this.$qq = $qq; + this.$qa = $qa; + } } // End class // attach utilities function to the class that are used by SvgEdit so // we can avoid using the whole utilities.js file in svgEdit.js -SvgCanvas.isNullish = isNullish; -SvgCanvas.encode64 = encode64; -SvgCanvas.decode64 = decode64; SvgCanvas.$id = $id; SvgCanvas.$qq = $qq; SvgCanvas.$qa = $qa; +SvgCanvas.isNullish = isNullish; +SvgCanvas.encode64 = encode64; +SvgCanvas.decode64 = decode64; SvgCanvas.mergeDeep = mergeDeep; SvgCanvas.getClosest = getClosest; SvgCanvas.getParents = getParents; diff --git a/src/svgcanvas/utilities.js b/src/svgcanvas/utilities.js index d09fde1d..40cd6a20 100644 --- a/src/svgcanvas/utilities.js +++ b/src/svgcanvas/utilities.js @@ -721,10 +721,10 @@ export const getBBoxOfElementAsPath = function (elem, addSVGElemensFromJson, pat * @param {module:path.EditorContext#addCommandToHistory|module:draw.DrawCanvasInit#addCommandToHistory} addCommandToHistory - see [canvas.addCommandToHistory]{@link module:svgcanvas~addCommandToHistory} * @returns {SVGPathElement|null} The converted path element or null if the DOM element was not recognized. */ -export const convertToPath = function ( +export const convertToPath = ( elem, attrs, addSVGElemensFromJson, pathActions, clearSelection, addToSelection, hstry, addCommandToHistory -) { +) => { const batchCmd = new hstry.BatchCommand('Convert element to Path'); // Any attribute on the element not covered by the passed-in attributes