Refactor2 (#712)
* review svg-exec * review selection.js elemgetset and selectedelems * Update svgcanvas.js
This commit is contained in:
@@ -24,13 +24,53 @@ let svgCanvas = null
|
|||||||
*/
|
*/
|
||||||
export const init = (canvas) => {
|
export const init = (canvas) => {
|
||||||
svgCanvas = canvas
|
svgCanvas = canvas
|
||||||
|
svgCanvas.getBold = getBoldMethod // Check whether selected element is bold or not.
|
||||||
|
svgCanvas.setBold = setBoldMethod // Make the selected element bold or normal.
|
||||||
|
svgCanvas.getItalic = getItalicMethod // Check whether selected element is in italics or not.
|
||||||
|
svgCanvas.setItalic = setItalicMethod // Make the selected element italic or normal.
|
||||||
|
svgCanvas.hasTextDecoration = hasTextDecorationMethod // Check whether the selected element has the given text decoration or not.
|
||||||
|
svgCanvas.addTextDecoration = addTextDecorationMethod // Adds the given value to the text decoration
|
||||||
|
svgCanvas.removeTextDecoration = removeTextDecorationMethod // Removes the given value from the text decoration
|
||||||
|
svgCanvas.setTextAnchor = setTextAnchorMethod // Set the new text anchor.
|
||||||
|
svgCanvas.setLetterSpacing = setLetterSpacingMethod // Set the new letter spacing.
|
||||||
|
svgCanvas.setWordSpacing = setWordSpacingMethod // Set the new word spacing.
|
||||||
|
svgCanvas.setTextLength = setTextLengthMethod // Set the new text length.
|
||||||
|
svgCanvas.setLengthAdjust = setLengthAdjustMethod // Set the new length adjust.
|
||||||
|
svgCanvas.getFontFamily = getFontFamilyMethod // The current font family
|
||||||
|
svgCanvas.setFontFamily = setFontFamilyMethod // Set the new font family.
|
||||||
|
svgCanvas.setFontColor = setFontColorMethod // Set the new font color.
|
||||||
|
svgCanvas.getFontColor = getFontColorMethod // The current font color
|
||||||
|
svgCanvas.getFontSize = getFontSizeMethod // The current font size
|
||||||
|
svgCanvas.setFontSize = setFontSizeMethod // Applies the given font size to the selected element.
|
||||||
|
svgCanvas.getText = getTextMethod // current text (`textContent`) of the selected element
|
||||||
|
svgCanvas.setTextContent = setTextContentMethod // Updates the text element with the given string.
|
||||||
|
svgCanvas.setImageURL = setImageURLMethod // Sets the new image URL for the selected image element
|
||||||
|
svgCanvas.setLinkURL = setLinkURLMethod // Sets the new link URL for the selected anchor element.
|
||||||
|
svgCanvas.setRectRadius = setRectRadiusMethod // Sets the `rx` and `ry` values to the selected `rect` element
|
||||||
|
svgCanvas.makeHyperlink = makeHyperlinkMethod // Wraps the selected element(s) in an anchor element or converts group to one.
|
||||||
|
svgCanvas.removeHyperlink = removeHyperlinkMethod
|
||||||
|
svgCanvas.setSegType = setSegTypeMethod // Sets the new segment type to the selected segment(s).
|
||||||
|
svgCanvas.setStrokeWidth = setStrokeWidthMethod // Sets the stroke width for the current selected elements.
|
||||||
|
svgCanvas.getResolution = getResolutionMethod // The current dimensions and zoom level in an object
|
||||||
|
svgCanvas.getTitle = getTitleMethod // the current group/SVG's title contents or `undefined` if no element
|
||||||
|
svgCanvas.setGroupTitle = setGroupTitleMethod // Sets the group/SVG's title content.
|
||||||
|
svgCanvas.setStrokeAttr = setStrokeAttrMethod // Set the given stroke-related attribute the given value for selected elements.
|
||||||
|
svgCanvas.setBackground = setBackgroundMethod // Set the background of the editor (NOT the actual document).
|
||||||
|
svgCanvas.setDocumentTitle = setDocumentTitleMethod // Adds/updates a title element for the document with the given name.
|
||||||
|
svgCanvas.getEditorNS = getEditorNSMethod // Returns the editor's namespace URL, optionally adding it to the root element.
|
||||||
|
svgCanvas.setResolution = setResolutionMethod // Changes the document's dimensions to the given size.
|
||||||
|
svgCanvas.setBBoxZoom = setBBoxZoomMethod // Sets the zoom level on the canvas-side based on the given value.
|
||||||
|
svgCanvas.setCurrentZoom = setZoomMethod // Sets the zoom to the given level.
|
||||||
|
svgCanvas.setColor = setColorMethod // Change the current stroke/fill color/gradien
|
||||||
|
svgCanvas.setGradient = setGradientMethod // Apply the current gradient to selected element's fill or stroke.
|
||||||
|
svgCanvas.setPaint = setPaintMethod // Set a color/gradient to a fill/stroke.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function module:elem-get-set.SvgCanvas#getResolution
|
* @function module:elem-get-set.SvgCanvas#getResolution
|
||||||
* @returns {DimensionsAndZoom} The current dimensions and zoom level in an object
|
* @returns {DimensionsAndZoom} The current dimensions and zoom level in an object
|
||||||
*/
|
*/
|
||||||
export const getResolutionMethod = () => {
|
const getResolutionMethod = () => {
|
||||||
const zoom = svgCanvas.getZoom()
|
const zoom = svgCanvas.getZoom()
|
||||||
const w = svgCanvas.getSvgContent().getAttribute('width') / zoom
|
const w = svgCanvas.getSvgContent().getAttribute('width') / zoom
|
||||||
const h = svgCanvas.getSvgContent().getAttribute('height') / zoom
|
const h = svgCanvas.getSvgContent().getAttribute('height') / zoom
|
||||||
@@ -48,7 +88,7 @@ export const getResolutionMethod = () => {
|
|||||||
* @returns {string|void} the current group/SVG's title contents or
|
* @returns {string|void} the current group/SVG's title contents or
|
||||||
* `undefined` if no element is passed nd there are no selected elements.
|
* `undefined` if no element is passed nd there are no selected elements.
|
||||||
*/
|
*/
|
||||||
export const getTitleMethod = (elem) => {
|
const getTitleMethod = (elem) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const dataStorage = svgCanvas.getDataStorage()
|
const dataStorage = svgCanvas.getDataStorage()
|
||||||
elem = elem || selectedElements[0]
|
elem = elem || selectedElements[0]
|
||||||
@@ -74,7 +114,7 @@ export const getTitleMethod = (elem) => {
|
|||||||
* @todo Combine this with `setDocumentTitle`
|
* @todo Combine this with `setDocumentTitle`
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setGroupTitleMethod = (val) => {
|
const setGroupTitleMethod = (val) => {
|
||||||
const {
|
const {
|
||||||
InsertElementCommand, RemoveElementCommand,
|
InsertElementCommand, RemoveElementCommand,
|
||||||
ChangeElementCommand, BatchCommand
|
ChangeElementCommand, BatchCommand
|
||||||
@@ -119,7 +159,7 @@ export const setGroupTitleMethod = (val) => {
|
|||||||
* @param {string} newTitle - String with the new title
|
* @param {string} newTitle - String with the new title
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setDocumentTitleMethod = (newTitle) => {
|
const setDocumentTitleMethod = (newTitle) => {
|
||||||
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
||||||
const childs = svgCanvas.getSvgContent().childNodes
|
const childs = svgCanvas.getSvgContent().childNodes
|
||||||
let docTitle = false; let oldTitle = ''
|
let docTitle = false; let oldTitle = ''
|
||||||
@@ -159,7 +199,7 @@ export const setDocumentTitleMethod = (newTitle) => {
|
|||||||
* @returns {boolean} Indicates if resolution change was successful.
|
* @returns {boolean} Indicates if resolution change was successful.
|
||||||
* It will fail on "fit to content" option with no content to fit to.
|
* It will fail on "fit to content" option with no content to fit to.
|
||||||
*/
|
*/
|
||||||
export const setResolutionMethod = (x, y) => {
|
const setResolutionMethod = (x, y) => {
|
||||||
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
||||||
const zoom = svgCanvas.getZoom()
|
const zoom = svgCanvas.getZoom()
|
||||||
const res = svgCanvas.getResolution()
|
const res = svgCanvas.getResolution()
|
||||||
@@ -220,7 +260,7 @@ export const setResolutionMethod = (x, y) => {
|
|||||||
* @param {boolean} [add] - Indicates whether or not to add the namespace value
|
* @param {boolean} [add] - Indicates whether or not to add the namespace value
|
||||||
* @returns {string} The editor's namespace URL
|
* @returns {string} The editor's namespace URL
|
||||||
*/
|
*/
|
||||||
export const getEditorNSMethod = (add) => {
|
const getEditorNSMethod = (add) => {
|
||||||
if (add) {
|
if (add) {
|
||||||
svgCanvas.getSvgContent().setAttribute('xmlns:se', NS.SE)
|
svgCanvas.getSvgContent().setAttribute('xmlns:se', NS.SE)
|
||||||
}
|
}
|
||||||
@@ -240,7 +280,7 @@ export const getEditorNSMethod = (add) => {
|
|||||||
* @param {Integer} editorH - The editor's workarea box's height
|
* @param {Integer} editorH - The editor's workarea box's height
|
||||||
* @returns {module:elem-get-set.ZoomAndBBox|void}
|
* @returns {module:elem-get-set.ZoomAndBBox|void}
|
||||||
*/
|
*/
|
||||||
export const setBBoxZoomMethod = (val, editorW, editorH) => {
|
const setBBoxZoomMethod = (val, editorW, editorH) => {
|
||||||
const zoom = svgCanvas.getZoom()
|
const zoom = svgCanvas.getZoom()
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
let spacer = 0.85
|
let spacer = 0.85
|
||||||
@@ -299,7 +339,7 @@ export const setBBoxZoomMethod = (val, editorW, editorH) => {
|
|||||||
* @fires module:elem-get-set.SvgCanvas#event:ext_zoomChanged
|
* @fires module:elem-get-set.SvgCanvas#event:ext_zoomChanged
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setZoomMethod = (zoomLevel) => {
|
const setZoomMethod = (zoomLevel) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const res = svgCanvas.getResolution()
|
const res = svgCanvas.getResolution()
|
||||||
svgCanvas.getSvgContent().setAttribute('viewBox', '0 0 ' + res.w / zoomLevel + ' ' + res.h / zoomLevel)
|
svgCanvas.getSvgContent().setAttribute('viewBox', '0 0 ' + res.w / zoomLevel + ' ' + res.h / zoomLevel)
|
||||||
@@ -317,11 +357,11 @@ export const setZoomMethod = (zoomLevel) => {
|
|||||||
* @function module:elem-get-set.SvgCanvas#setColor
|
* @function module:elem-get-set.SvgCanvas#setColor
|
||||||
* @param {string} type - String indicating fill or stroke
|
* @param {string} type - String indicating fill or stroke
|
||||||
* @param {string} val - The value to set the stroke attribute to
|
* @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
|
* @param {boolean} preventUndo - Boolean indicating whether or not svgCanvas should be an undoable option
|
||||||
* @fires module:elem-get-set.SvgCanvas#event:changed
|
* @fires module:elem-get-set.SvgCanvas#event:changed
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setColorMethod = (type, val, preventUndo) => {
|
const setColorMethod = (type, val, preventUndo) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
svgCanvas.setCurShape(type, val)
|
svgCanvas.setCurShape(type, val)
|
||||||
svgCanvas.setCurProperties(type + '_paint', { type: 'solidColor' })
|
svgCanvas.setCurProperties(type + '_paint', { type: 'solidColor' })
|
||||||
@@ -367,7 +407,7 @@ export const setColorMethod = (type, val, preventUndo) => {
|
|||||||
* @param {"fill"|"stroke"} type - String indicating "fill" or "stroke" to apply to an element
|
* @param {"fill"|"stroke"} type - String indicating "fill" or "stroke" to apply to an element
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setGradientMethod = (type) => {
|
const setGradientMethod = (type) => {
|
||||||
if (!svgCanvas.getCurProperties(type + '_paint') ||
|
if (!svgCanvas.getCurProperties(type + '_paint') ||
|
||||||
svgCanvas.getCurProperties(type + '_paint').type === 'solidColor') { return }
|
svgCanvas.getCurProperties(type + '_paint').type === 'solidColor') { return }
|
||||||
const canvas = svgCanvas
|
const canvas = svgCanvas
|
||||||
@@ -394,7 +434,7 @@ export const setGradientMethod = (type) => {
|
|||||||
* @param {SVGGradientElement} grad - The gradient DOM element to compare to others
|
* @param {SVGGradientElement} grad - The gradient DOM element to compare to others
|
||||||
* @returns {SVGGradientElement} The existing gradient if found, `null` if not
|
* @returns {SVGGradientElement} The existing gradient if found, `null` if not
|
||||||
*/
|
*/
|
||||||
export const findDuplicateGradient = (grad) => {
|
const findDuplicateGradient = (grad) => {
|
||||||
const defs = findDefs()
|
const defs = findDefs()
|
||||||
const existingGrads = defs.querySelectorAll('linearGradient, radialGradient')
|
const existingGrads = defs.querySelectorAll('linearGradient, radialGradient')
|
||||||
let i = existingGrads.length
|
let i = existingGrads.length
|
||||||
@@ -468,7 +508,7 @@ export const findDuplicateGradient = (grad) => {
|
|||||||
* @param {module:jGraduate.jGraduatePaintOptions} paint - The jGraduate paint object to apply
|
* @param {module:jGraduate.jGraduatePaintOptions} paint - The jGraduate paint object to apply
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setPaintMethod = (type, paint) => {
|
const setPaintMethod = (type, paint) => {
|
||||||
// make a copy
|
// make a copy
|
||||||
const p = new jGraduate.Paint(paint)
|
const p = new jGraduate.Paint(paint)
|
||||||
svgCanvas.setPaintOpacity(type, p.alpha / 100, true)
|
svgCanvas.setPaintOpacity(type, p.alpha / 100, true)
|
||||||
@@ -494,7 +534,7 @@ export const setPaintMethod = (type, paint) => {
|
|||||||
* @fires module:elem-get-set.SvgCanvas#event:changed
|
* @fires module:elem-get-set.SvgCanvas#event:changed
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setStrokeWidthMethod = (val) => {
|
const setStrokeWidthMethod = (val) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
if (val === 0 && ['line', 'path'].includes(svgCanvas.getMode())) {
|
if (val === 0 && ['line', 'path'].includes(svgCanvas.getMode())) {
|
||||||
svgCanvas.setStrokeWidth(1)
|
svgCanvas.setStrokeWidth(1)
|
||||||
@@ -538,7 +578,7 @@ export const setStrokeWidthMethod = (val) => {
|
|||||||
* @fires module:elem-get-set.SvgCanvas#event:changed
|
* @fires module:elem-get-set.SvgCanvas#event:changed
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setStrokeAttrMethod = (attr, val) => {
|
const setStrokeAttrMethod = (attr, val) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
svgCanvas.setCurShape(attr.replace('-', '_'), val)
|
svgCanvas.setCurShape(attr.replace('-', '_'), val)
|
||||||
const elems = []
|
const elems = []
|
||||||
@@ -564,7 +604,7 @@ export const setStrokeAttrMethod = (attr, val) => {
|
|||||||
* @function module:svgcanvas.SvgCanvas#getBold
|
* @function module:svgcanvas.SvgCanvas#getBold
|
||||||
* @returns {boolean} Indicates whether or not element is bold
|
* @returns {boolean} Indicates whether or not element is bold
|
||||||
*/
|
*/
|
||||||
export const getBoldMethod = () => {
|
const getBoldMethod = () => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
// should only have one element selected
|
// should only have one element selected
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
@@ -581,7 +621,7 @@ export const getBoldMethod = () => {
|
|||||||
* @param {boolean} b - Indicates bold (`true`) or normal (`false`)
|
* @param {boolean} b - Indicates bold (`true`) or normal (`false`)
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setBoldMethod = (b) => {
|
const setBoldMethod = (b) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
if (selected?.tagName === 'text' &&
|
if (selected?.tagName === 'text' &&
|
||||||
@@ -597,7 +637,7 @@ export const setBoldMethod = (b) => {
|
|||||||
* Check whether selected element has the given text decoration value or not.
|
* Check whether selected element has the given text decoration value or not.
|
||||||
* @returns {boolean} Indicates whether or not element has the text decoration value
|
* @returns {boolean} Indicates whether or not element has the text decoration value
|
||||||
*/
|
*/
|
||||||
export const hasTextDecorationMethod = (value) => {
|
const hasTextDecorationMethod = (value) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
|
|
||||||
@@ -614,7 +654,7 @@ export const hasTextDecorationMethod = (value) => {
|
|||||||
* @param value The text decoration value
|
* @param value The text decoration value
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const addTextDecorationMethod = (value) => {
|
const addTextDecorationMethod = (value) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
||||||
@@ -631,7 +671,7 @@ export const addTextDecorationMethod = (value) => {
|
|||||||
* @param value The text decoration value
|
* @param value The text decoration value
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const removeTextDecorationMethod = (value) => {
|
const removeTextDecorationMethod = (value) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
||||||
@@ -648,7 +688,7 @@ export const removeTextDecorationMethod = (value) => {
|
|||||||
* @function module:svgcanvas.SvgCanvas#getItalic
|
* @function module:svgcanvas.SvgCanvas#getItalic
|
||||||
* @returns {boolean} Indicates whether or not element is italic
|
* @returns {boolean} Indicates whether or not element is italic
|
||||||
*/
|
*/
|
||||||
export const getItalicMethod = () => {
|
const getItalicMethod = () => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
||||||
@@ -663,7 +703,7 @@ export const getItalicMethod = () => {
|
|||||||
* @param {boolean} i - Indicates italic (`true`) or normal (`false`)
|
* @param {boolean} i - Indicates italic (`true`) or normal (`false`)
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setItalicMethod = (i) => {
|
const setItalicMethod = (i) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
||||||
@@ -679,7 +719,7 @@ export const setItalicMethod = (i) => {
|
|||||||
* @param {string} value - The text anchor value (start, middle or end)
|
* @param {string} value - The text anchor value (start, middle or end)
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setTextAnchorMethod = (value) => {
|
const setTextAnchorMethod = (value) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
||||||
@@ -695,7 +735,7 @@ export const setTextAnchorMethod = (value) => {
|
|||||||
* @param {string} value - The letter spacing value
|
* @param {string} value - The letter spacing value
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setLetterSpacingMethod = (value) => {
|
const setLetterSpacingMethod = (value) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
||||||
@@ -711,7 +751,7 @@ export const setLetterSpacingMethod = (value) => {
|
|||||||
* @param {string} value - The word spacing value
|
* @param {string} value - The word spacing value
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setWordSpacingMethod = (value) => {
|
const setWordSpacingMethod = (value) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
||||||
@@ -727,7 +767,7 @@ export const setWordSpacingMethod = (value) => {
|
|||||||
* @param {string} value - The text length value
|
* @param {string} value - The text length value
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setTextLengthMethod = (value) => {
|
const setTextLengthMethod = (value) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
||||||
@@ -743,7 +783,7 @@ export const setTextLengthMethod = (value) => {
|
|||||||
* @param {string} value - The length adjust value
|
* @param {string} value - The length adjust value
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setLengthAdjustMethod = (value) => {
|
const setLengthAdjustMethod = (value) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
||||||
@@ -758,7 +798,7 @@ export const setLengthAdjustMethod = (value) => {
|
|||||||
* @function module:svgcanvas.SvgCanvas#getFontFamily
|
* @function module:svgcanvas.SvgCanvas#getFontFamily
|
||||||
* @returns {string} The current font family
|
* @returns {string} The current font family
|
||||||
*/
|
*/
|
||||||
export const getFontFamilyMethod = () => {
|
const getFontFamilyMethod = () => {
|
||||||
return svgCanvas.getCurText('font_family')
|
return svgCanvas.getCurText('font_family')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -768,7 +808,7 @@ export const getFontFamilyMethod = () => {
|
|||||||
* @param {string} val - String with the new font family
|
* @param {string} val - String with the new font family
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setFontFamilyMethod = (val) => {
|
const setFontFamilyMethod = (val) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
svgCanvas.setCurText('font_family', val)
|
svgCanvas.setCurText('font_family', val)
|
||||||
svgCanvas.changeSelectedAttribute('font-family', val)
|
svgCanvas.changeSelectedAttribute('font-family', val)
|
||||||
@@ -783,7 +823,7 @@ export const setFontFamilyMethod = (val) => {
|
|||||||
* @param {string} val - String with the new font color
|
* @param {string} val - String with the new font color
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setFontColorMethod = (val) => {
|
const setFontColorMethod = (val) => {
|
||||||
svgCanvas.setCurText('fill', val)
|
svgCanvas.setCurText('fill', val)
|
||||||
svgCanvas.changeSelectedAttribute('fill', val)
|
svgCanvas.changeSelectedAttribute('fill', val)
|
||||||
}
|
}
|
||||||
@@ -792,7 +832,7 @@ export const setFontColorMethod = (val) => {
|
|||||||
* @function module:svgcanvas.SvgCanvas#getFontColor
|
* @function module:svgcanvas.SvgCanvas#getFontColor
|
||||||
* @returns {string} The current font color
|
* @returns {string} The current font color
|
||||||
*/
|
*/
|
||||||
export const getFontColorMethod = () => {
|
const getFontColorMethod = () => {
|
||||||
return svgCanvas.getCurText('fill')
|
return svgCanvas.getCurText('fill')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,7 +840,7 @@ export const getFontColorMethod = () => {
|
|||||||
* @function module:svgcanvas.SvgCanvas#getFontSize
|
* @function module:svgcanvas.SvgCanvas#getFontSize
|
||||||
* @returns {Float} The current font size
|
* @returns {Float} The current font size
|
||||||
*/
|
*/
|
||||||
export const getFontSizeMethod = () => {
|
const getFontSizeMethod = () => {
|
||||||
return svgCanvas.getCurText('font_size')
|
return svgCanvas.getCurText('font_size')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -810,7 +850,7 @@ export const getFontSizeMethod = () => {
|
|||||||
* @param {Float} val - Float with the new font size
|
* @param {Float} val - Float with the new font size
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setFontSizeMethod = (val) => {
|
const setFontSizeMethod = (val) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
svgCanvas.setCurText('font_size', val)
|
svgCanvas.setCurText('font_size', val)
|
||||||
svgCanvas.changeSelectedAttribute('font-size', val)
|
svgCanvas.changeSelectedAttribute('font-size', val)
|
||||||
@@ -823,7 +863,7 @@ export const setFontSizeMethod = (val) => {
|
|||||||
* @function module:svgcanvas.SvgCanvas#getText
|
* @function module:svgcanvas.SvgCanvas#getText
|
||||||
* @returns {string} The current text (`textContent`) of the selected element
|
* @returns {string} The current text (`textContent`) of the selected element
|
||||||
*/
|
*/
|
||||||
export const getTextMethod = () => {
|
const getTextMethod = () => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
return (selected) ? selected.textContent : ''
|
return (selected) ? selected.textContent : ''
|
||||||
@@ -835,7 +875,7 @@ export const getTextMethod = () => {
|
|||||||
* @param {string} val - String with the new text
|
* @param {string} val - String with the new text
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setTextContentMethod = (val) => {
|
const setTextContentMethod = (val) => {
|
||||||
svgCanvas.changeSelectedAttribute('#text', val)
|
svgCanvas.changeSelectedAttribute('#text', val)
|
||||||
svgCanvas.textActions.init(val)
|
svgCanvas.textActions.init(val)
|
||||||
svgCanvas.textActions.setCursor()
|
svgCanvas.textActions.setCursor()
|
||||||
@@ -849,7 +889,7 @@ export const setTextContentMethod = (val) => {
|
|||||||
* @fires module:svgcanvas.SvgCanvas#event:changed
|
* @fires module:svgcanvas.SvgCanvas#event:changed
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setImageURLMethod = (val) => {
|
const setImageURLMethod = (val) => {
|
||||||
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const elem = selectedElements[0]
|
const elem = selectedElements[0]
|
||||||
@@ -898,7 +938,7 @@ export const setImageURLMethod = (val) => {
|
|||||||
* @param {string} val - String with the link URL/path
|
* @param {string} val - String with the link URL/path
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setLinkURLMethod = (val) => {
|
const setLinkURLMethod = (val) => {
|
||||||
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
let elem = selectedElements[0]
|
let elem = selectedElements[0]
|
||||||
@@ -935,7 +975,7 @@ export const setLinkURLMethod = (val) => {
|
|||||||
* @fires module:svgcanvas.SvgCanvas#event:changed
|
* @fires module:svgcanvas.SvgCanvas#event:changed
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setRectRadiusMethod = (val) => {
|
const setRectRadiusMethod = (val) => {
|
||||||
const { ChangeElementCommand } = svgCanvas.history
|
const { ChangeElementCommand } = svgCanvas.history
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
@@ -956,7 +996,7 @@ export const setRectRadiusMethod = (val) => {
|
|||||||
* @param {string} url
|
* @param {string} url
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const makeHyperlinkMethod = (url) => {
|
const makeHyperlinkMethod = (url) => {
|
||||||
svgCanvas.groupSelectedElements('a', url)
|
svgCanvas.groupSelectedElements('a', url)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -964,7 +1004,7 @@ export const makeHyperlinkMethod = (url) => {
|
|||||||
* @function module:svgcanvas.SvgCanvas#removeHyperlink
|
* @function module:svgcanvas.SvgCanvas#removeHyperlink
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const removeHyperlinkMethod = () => {
|
const removeHyperlinkMethod = () => {
|
||||||
svgCanvas.ungroupSelectedElement()
|
svgCanvas.ungroupSelectedElement()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -978,7 +1018,7 @@ export const removeHyperlinkMethod = () => {
|
|||||||
* @param {Integer} newType - New segment type. See {@link https://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg} for list
|
* @param {Integer} newType - New segment type. See {@link https://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg} for list
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setSegTypeMethod = (newType) => {
|
const setSegTypeMethod = (newType) => {
|
||||||
svgCanvas.pathActions.setSegType(newType)
|
svgCanvas.pathActions.setSegType(newType)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -989,7 +1029,7 @@ export const setSegTypeMethod = (newType) => {
|
|||||||
* @param {string} url - URL or path to image to use
|
* @param {string} url - URL or path to image to use
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setBackgroundMethod = (color, url) => {
|
const setBackgroundMethod = (color, url) => {
|
||||||
const bg = getElement('canvasBackground')
|
const bg = getElement('canvasBackground')
|
||||||
const border = bg.querySelector('rect')
|
const border = bg.querySelector('rect')
|
||||||
let bgImg = getElement('background_image')
|
let bgImg = getElement('background_image')
|
||||||
|
|||||||
@@ -10,22 +10,34 @@ import { NS } from './namespaces.js'
|
|||||||
import * as hstry from './history.js'
|
import * as hstry from './history.js'
|
||||||
import * as pathModule from './path.js'
|
import * as pathModule from './path.js'
|
||||||
import {
|
import {
|
||||||
getStrokedBBoxDefaultVisible, setHref, getElement, getHref, getVisibleElements,
|
getStrokedBBoxDefaultVisible,
|
||||||
findDefs, getRotationAngle, getRefElem, getBBox as utilsGetBBox, walkTreePost, assignAttributes, getFeGaussianBlur
|
setHref,
|
||||||
|
getElement,
|
||||||
|
getHref,
|
||||||
|
getVisibleElements,
|
||||||
|
findDefs,
|
||||||
|
getRotationAngle,
|
||||||
|
getRefElem,
|
||||||
|
getBBox as utilsGetBBox,
|
||||||
|
walkTreePost,
|
||||||
|
assignAttributes,
|
||||||
|
getFeGaussianBlur
|
||||||
} from './utilities.js'
|
} from './utilities.js'
|
||||||
import {
|
import {
|
||||||
transformPoint, matrixMultiply, transformListToTransform
|
transformPoint,
|
||||||
|
matrixMultiply,
|
||||||
|
transformListToTransform
|
||||||
} from './math.js'
|
} from './math.js'
|
||||||
import {
|
import { recalculateDimensions } from './recalculate.js'
|
||||||
recalculateDimensions
|
import { isGecko } from '../common/browser.js' // , supportsEditableText
|
||||||
} from './recalculate.js'
|
|
||||||
import {
|
|
||||||
isGecko
|
|
||||||
} from '../common/browser.js' // , supportsEditableText
|
|
||||||
import { getParents } from '../editor/components/jgraduate/Util.js'
|
import { getParents } from '../editor/components/jgraduate/Util.js'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
MoveElementCommand, BatchCommand, InsertElementCommand, RemoveElementCommand, ChangeElementCommand
|
MoveElementCommand,
|
||||||
|
BatchCommand,
|
||||||
|
InsertElementCommand,
|
||||||
|
RemoveElementCommand,
|
||||||
|
ChangeElementCommand
|
||||||
} = hstry
|
} = hstry
|
||||||
|
|
||||||
let svgCanvas = null
|
let svgCanvas = null
|
||||||
@@ -35,7 +47,7 @@ let svgCanvas = null
|
|||||||
* @param {module:selected-elem.elementContext} elementContext
|
* @param {module:selected-elem.elementContext} elementContext
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const init = (canvas) => {
|
export const init = canvas => {
|
||||||
svgCanvas = canvas
|
svgCanvas = canvas
|
||||||
svgCanvas.copySelectedElements = copySelectedElements
|
svgCanvas.copySelectedElements = copySelectedElements
|
||||||
svgCanvas.groupSelectedElements = groupSelectedElements // Wraps all the selected elements in a group (`g`) element.
|
svgCanvas.groupSelectedElements = groupSelectedElements // Wraps all the selected elements in a group (`g`) element.
|
||||||
@@ -69,7 +81,9 @@ const moveToTopSelectedElem = () => {
|
|||||||
// If the element actually moved position, add the command and fire the changed
|
// If the element actually moved position, add the command and fire the changed
|
||||||
// event handler.
|
// event handler.
|
||||||
if (oldNextSibling !== t.nextSibling) {
|
if (oldNextSibling !== t.nextSibling) {
|
||||||
svgCanvas.addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, 'top'))
|
svgCanvas.addCommandToHistory(
|
||||||
|
new MoveElementCommand(t, oldNextSibling, oldParent, 'top')
|
||||||
|
)
|
||||||
svgCanvas.call('changed', [t])
|
svgCanvas.call('changed', [t])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,7 +115,9 @@ const moveToBottomSelectedElem = () => {
|
|||||||
// If the element actually moved position, add the command and fire the changed
|
// If the element actually moved position, add the command and fire the changed
|
||||||
// event handler.
|
// event handler.
|
||||||
if (oldNextSibling !== t.nextSibling) {
|
if (oldNextSibling !== t.nextSibling) {
|
||||||
svgCanvas.addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, 'bottom'))
|
svgCanvas.addCommandToHistory(
|
||||||
|
new MoveElementCommand(t, oldNextSibling, oldParent, 'bottom')
|
||||||
|
)
|
||||||
svgCanvas.call('changed', [t])
|
svgCanvas.call('changed', [t])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,18 +131,25 @@ const moveToBottomSelectedElem = () => {
|
|||||||
* @fires module:selected-elem.SvgCanvas#event:changed
|
* @fires module:selected-elem.SvgCanvas#event:changed
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
const moveUpDownSelected = (dir) => {
|
const moveUpDownSelected = dir => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const selected = selectedElements[0]
|
const selected = selectedElements[0]
|
||||||
if (!selected) { return }
|
if (!selected) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
svgCanvas.setCurBBoxes([])
|
svgCanvas.setCurBBoxes([])
|
||||||
let closest; let foundCur
|
let closest
|
||||||
|
let foundCur
|
||||||
// jQuery sorts this list
|
// jQuery sorts this list
|
||||||
const list = svgCanvas.getIntersectionList(getStrokedBBoxDefaultVisible([selected]))
|
const list = svgCanvas.getIntersectionList(
|
||||||
if (dir === 'Down') { list.reverse() }
|
getStrokedBBoxDefaultVisible([selected])
|
||||||
|
)
|
||||||
|
if (dir === 'Down') {
|
||||||
|
list.reverse()
|
||||||
|
}
|
||||||
|
|
||||||
Array.prototype.forEach.call(list, (el) => {
|
Array.prototype.forEach.call(list, el => {
|
||||||
if (!foundCur) {
|
if (!foundCur) {
|
||||||
if (el === selected) {
|
if (el === selected) {
|
||||||
foundCur = true
|
foundCur = true
|
||||||
@@ -136,7 +159,9 @@ const moveUpDownSelected = (dir) => {
|
|||||||
closest = el
|
closest = el
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
if (!closest) { return }
|
if (!closest) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const t = selected
|
const t = selected
|
||||||
const oldParent = t.parentNode
|
const oldParent = t.parentNode
|
||||||
@@ -149,7 +174,9 @@ const moveUpDownSelected = (dir) => {
|
|||||||
// If the element actually moved position, add the command and fire the changed
|
// If the element actually moved position, add the command and fire the changed
|
||||||
// event handler.
|
// event handler.
|
||||||
if (oldNextSibling !== t.nextSibling) {
|
if (oldNextSibling !== t.nextSibling) {
|
||||||
svgCanvas.addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, 'Move ' + dir))
|
svgCanvas.addCommandToHistory(
|
||||||
|
new MoveElementCommand(t, oldNextSibling, oldParent, 'Move ' + dir)
|
||||||
|
)
|
||||||
svgCanvas.call('changed', [t])
|
svgCanvas.call('changed', [t])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,7 +225,10 @@ const moveSelectedElements = (dx, dy, undoable = true) => {
|
|||||||
batchCmd.addSubCommand(cmd)
|
batchCmd.addSubCommand(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
svgCanvas.gettingSelectorManager().requestSelector(selected).resize()
|
svgCanvas
|
||||||
|
.gettingSelectorManager()
|
||||||
|
.requestSelector(selected)
|
||||||
|
.resize()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (!batchCmd.isEmpty()) {
|
if (!batchCmd.isEmpty()) {
|
||||||
@@ -222,12 +252,13 @@ const moveSelectedElements = (dx, dy, undoable = true) => {
|
|||||||
const cloneSelectedElements = (x, y) => {
|
const cloneSelectedElements = (x, y) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const currentGroup = svgCanvas.getCurrentGroup()
|
const currentGroup = svgCanvas.getCurrentGroup()
|
||||||
let i; let elem
|
let i
|
||||||
|
let elem
|
||||||
const batchCmd = new BatchCommand('Clone Elements')
|
const batchCmd = new BatchCommand('Clone Elements')
|
||||||
// find all the elements selected (stop at first null)
|
// find all the elements selected (stop at first null)
|
||||||
const len = selectedElements.length
|
const len = selectedElements.length
|
||||||
|
|
||||||
const index = (el) => {
|
const index = el => {
|
||||||
if (!el) return -1
|
if (!el) return -1
|
||||||
let i = 0
|
let i = 0
|
||||||
do {
|
do {
|
||||||
@@ -243,12 +274,14 @@ const cloneSelectedElements = (x, y) => {
|
|||||||
* @returns {Integer}
|
* @returns {Integer}
|
||||||
*/
|
*/
|
||||||
const sortfunction = (a, b) => {
|
const sortfunction = (a, b) => {
|
||||||
return (index(b) - index(a))
|
return index(b) - index(a)
|
||||||
}
|
}
|
||||||
selectedElements.sort(sortfunction)
|
selectedElements.sort(sortfunction)
|
||||||
for (i = 0; i < len; ++i) {
|
for (i = 0; i < len; ++i) {
|
||||||
elem = selectedElements[i]
|
elem = selectedElements[i]
|
||||||
if (!elem) { break }
|
if (!elem) {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// use slice to quickly get the subset of elements we need
|
// use slice to quickly get the subset of elements we need
|
||||||
const copiedElements = selectedElements.slice(0, i)
|
const copiedElements = selectedElements.slice(0, i)
|
||||||
@@ -259,8 +292,8 @@ const cloneSelectedElements = (x, y) => {
|
|||||||
i = copiedElements.length
|
i = copiedElements.length
|
||||||
while (i--) {
|
while (i--) {
|
||||||
// clone each element and replace it within copiedElements
|
// clone each element and replace it within copiedElements
|
||||||
elem = copiedElements[i] = drawing.copyElem(copiedElements[i]);
|
elem = copiedElements[i] = drawing.copyElem(copiedElements[i])
|
||||||
(currentGroup || drawing.getCurrentLayer()).append(elem)
|
;(currentGroup || drawing.getCurrentLayer()).append(elem)
|
||||||
batchCmd.addSubCommand(new InsertElementCommand(elem))
|
batchCmd.addSubCommand(new InsertElementCommand(elem))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,21 +314,39 @@ const alignSelectedElements = (type, relativeTo) => {
|
|||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const bboxes = [] // angles = [];
|
const bboxes = [] // angles = [];
|
||||||
const len = selectedElements.length
|
const len = selectedElements.length
|
||||||
if (!len) { return }
|
if (!len) {
|
||||||
let minx = Number.MAX_VALUE; let maxx = Number.MIN_VALUE
|
return
|
||||||
let miny = Number.MAX_VALUE; let maxy = Number.MIN_VALUE
|
}
|
||||||
let curwidth = Number.MIN_VALUE; let curheight = Number.MIN_VALUE
|
let minx = Number.MAX_VALUE
|
||||||
|
let maxx = Number.MIN_VALUE
|
||||||
|
let miny = Number.MAX_VALUE
|
||||||
|
let maxy = Number.MIN_VALUE
|
||||||
|
let curwidth = Number.MIN_VALUE
|
||||||
|
let curheight = Number.MIN_VALUE
|
||||||
for (let i = 0; i < len; ++i) {
|
for (let i = 0; i < len; ++i) {
|
||||||
if (!selectedElements[i]) { break }
|
if (!selectedElements[i]) {
|
||||||
|
break
|
||||||
|
}
|
||||||
const elem = selectedElements[i]
|
const elem = selectedElements[i]
|
||||||
bboxes[i] = getStrokedBBoxDefaultVisible([elem])
|
bboxes[i] = getStrokedBBoxDefaultVisible([elem])
|
||||||
|
|
||||||
// now bbox is axis-aligned and handles rotation
|
// now bbox is axis-aligned and handles rotation
|
||||||
switch (relativeTo) {
|
switch (relativeTo) {
|
||||||
case 'smallest':
|
case 'smallest':
|
||||||
if (((type === 'l' || type === 'c' || type === 'r' || type === 'left' || type === 'center' || type === 'right') &&
|
if (
|
||||||
|
((type === 'l' ||
|
||||||
|
type === 'c' ||
|
||||||
|
type === 'r' ||
|
||||||
|
type === 'left' ||
|
||||||
|
type === 'center' ||
|
||||||
|
type === 'right') &&
|
||||||
(curwidth === Number.MIN_VALUE || curwidth > bboxes[i].width)) ||
|
(curwidth === Number.MIN_VALUE || curwidth > bboxes[i].width)) ||
|
||||||
((type === 't' || type === 'm' || type === 'b' || type === 'top' || type === 'middle' || type === 'bottom') &&
|
((type === 't' ||
|
||||||
|
type === 'm' ||
|
||||||
|
type === 'b' ||
|
||||||
|
type === 'top' ||
|
||||||
|
type === 'middle' ||
|
||||||
|
type === 'bottom') &&
|
||||||
(curheight === Number.MIN_VALUE || curheight > bboxes[i].height))
|
(curheight === Number.MIN_VALUE || curheight > bboxes[i].height))
|
||||||
) {
|
) {
|
||||||
minx = bboxes[i].x
|
minx = bboxes[i].x
|
||||||
@@ -307,9 +358,20 @@ const alignSelectedElements = (type, relativeTo) => {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'largest':
|
case 'largest':
|
||||||
if (((type === 'l' || type === 'c' || type === 'r' || type === 'left' || type === 'center' || type === 'right') &&
|
if (
|
||||||
|
((type === 'l' ||
|
||||||
|
type === 'c' ||
|
||||||
|
type === 'r' ||
|
||||||
|
type === 'left' ||
|
||||||
|
type === 'center' ||
|
||||||
|
type === 'right') &&
|
||||||
(curwidth === Number.MIN_VALUE || curwidth < bboxes[i].width)) ||
|
(curwidth === Number.MIN_VALUE || curwidth < bboxes[i].width)) ||
|
||||||
((type === 't' || type === 'm' || type === 'b' || type === 'top' || type === 'middle' || type === 'bottom') &&
|
((type === 't' ||
|
||||||
|
type === 'm' ||
|
||||||
|
type === 'b' ||
|
||||||
|
type === 'top' ||
|
||||||
|
type === 'middle' ||
|
||||||
|
type === 'bottom') &&
|
||||||
(curheight === Number.MIN_VALUE || curheight < bboxes[i].height))
|
(curheight === Number.MIN_VALUE || curheight < bboxes[i].height))
|
||||||
) {
|
) {
|
||||||
minx = bboxes[i].x
|
minx = bboxes[i].x
|
||||||
@@ -320,11 +382,20 @@ const alignSelectedElements = (type, relativeTo) => {
|
|||||||
curheight = bboxes[i].height
|
curheight = bboxes[i].height
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
default: // 'selected'
|
default:
|
||||||
if (bboxes[i].x < minx) { minx = bboxes[i].x }
|
// 'selected'
|
||||||
if (bboxes[i].y < miny) { miny = bboxes[i].y }
|
if (bboxes[i].x < minx) {
|
||||||
if (bboxes[i].x + bboxes[i].width > maxx) { maxx = bboxes[i].x + bboxes[i].width }
|
minx = bboxes[i].x
|
||||||
if (bboxes[i].y + bboxes[i].height > maxy) { maxy = bboxes[i].y + bboxes[i].height }
|
}
|
||||||
|
if (bboxes[i].y < miny) {
|
||||||
|
miny = bboxes[i].y
|
||||||
|
}
|
||||||
|
if (bboxes[i].x + bboxes[i].width > maxx) {
|
||||||
|
maxx = bboxes[i].x + bboxes[i].width
|
||||||
|
}
|
||||||
|
if (bboxes[i].y + bboxes[i].height > maxy) {
|
||||||
|
maxy = bboxes[i].y + bboxes[i].height
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} // loop for each element to find the bbox and adjust min/max
|
} // loop for each element to find the bbox and adjust min/max
|
||||||
@@ -339,7 +410,9 @@ const alignSelectedElements = (type, relativeTo) => {
|
|||||||
const dx = new Array(len)
|
const dx = new Array(len)
|
||||||
const dy = new Array(len)
|
const dy = new Array(len)
|
||||||
for (let i = 0; i < len; ++i) {
|
for (let i = 0; i < len; ++i) {
|
||||||
if (!selectedElements[i]) { break }
|
if (!selectedElements[i]) {
|
||||||
|
break
|
||||||
|
}
|
||||||
// const elem = selectedElements[i];
|
// const elem = selectedElements[i];
|
||||||
const bbox = bboxes[i]
|
const bbox = bboxes[i]
|
||||||
dx[i] = 0
|
dx[i] = 0
|
||||||
@@ -389,7 +462,9 @@ const deleteSelectedElements = () => {
|
|||||||
|
|
||||||
for (let i = 0; i < len; ++i) {
|
for (let i = 0; i < len; ++i) {
|
||||||
const selected = selectedElements[i]
|
const selected = selectedElements[i]
|
||||||
if (!selected) { break }
|
if (!selected) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
let parent = selected.parentNode
|
let parent = selected.parentNode
|
||||||
let t = selected
|
let t = selected
|
||||||
@@ -414,7 +489,9 @@ const deleteSelectedElements = () => {
|
|||||||
}
|
}
|
||||||
svgCanvas.setEmptySelectedElements()
|
svgCanvas.setEmptySelectedElements()
|
||||||
|
|
||||||
if (!batchCmd.isEmpty()) { svgCanvas.addCommandToHistory(batchCmd) }
|
if (!batchCmd.isEmpty()) {
|
||||||
|
svgCanvas.addCommandToHistory(batchCmd)
|
||||||
|
}
|
||||||
svgCanvas.call('changed', selectedCopy)
|
svgCanvas.call('changed', selectedCopy)
|
||||||
svgCanvas.clearSelection()
|
svgCanvas.clearSelection()
|
||||||
}
|
}
|
||||||
@@ -426,8 +503,9 @@ const deleteSelectedElements = () => {
|
|||||||
*/
|
*/
|
||||||
const copySelectedElements = () => {
|
const copySelectedElements = () => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const data =
|
const data = JSON.stringify(
|
||||||
JSON.stringify(selectedElements.map((x) => svgCanvas.getJsonFromSvgElements(x)))
|
selectedElements.map(x => svgCanvas.getJsonFromSvgElements(x))
|
||||||
|
)
|
||||||
// Use sessionStorage for the clipboard data.
|
// Use sessionStorage for the clipboard data.
|
||||||
sessionStorage.setItem(svgCanvas.getClipboardID(), data)
|
sessionStorage.setItem(svgCanvas.getClipboardID(), data)
|
||||||
svgCanvas.flashStorage()
|
svgCanvas.flashStorage()
|
||||||
@@ -446,7 +524,9 @@ const copySelectedElements = () => {
|
|||||||
*/
|
*/
|
||||||
const groupSelectedElements = (type, urlArg) => {
|
const groupSelectedElements = (type, urlArg) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
if (!type) { type = 'g' }
|
if (!type) {
|
||||||
|
type = 'g'
|
||||||
|
}
|
||||||
let cmdStr = ''
|
let cmdStr = ''
|
||||||
let url
|
let url
|
||||||
|
|
||||||
@@ -455,7 +535,8 @@ const groupSelectedElements = (type, urlArg) => {
|
|||||||
cmdStr = 'Make hyperlink'
|
cmdStr = 'Make hyperlink'
|
||||||
url = urlArg || ''
|
url = urlArg || ''
|
||||||
break
|
break
|
||||||
} default: {
|
}
|
||||||
|
default: {
|
||||||
type = 'g'
|
type = 'g'
|
||||||
cmdStr = 'Group Elements'
|
cmdStr = 'Group Elements'
|
||||||
break
|
break
|
||||||
@@ -480,18 +561,27 @@ const groupSelectedElements = (type, urlArg) => {
|
|||||||
let i = selectedElements.length
|
let i = selectedElements.length
|
||||||
while (i--) {
|
while (i--) {
|
||||||
let elem = selectedElements[i]
|
let elem = selectedElements[i]
|
||||||
if (!elem) { continue }
|
if (!elem) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if (elem.parentNode.tagName === 'a' && elem.parentNode.childNodes.length === 1) {
|
if (
|
||||||
|
elem.parentNode.tagName === 'a' &&
|
||||||
|
elem.parentNode.childNodes.length === 1
|
||||||
|
) {
|
||||||
elem = elem.parentNode
|
elem = elem.parentNode
|
||||||
}
|
}
|
||||||
|
|
||||||
const oldNextSibling = elem.nextSibling
|
const oldNextSibling = elem.nextSibling
|
||||||
const oldParent = elem.parentNode
|
const oldParent = elem.parentNode
|
||||||
g.append(elem)
|
g.append(elem)
|
||||||
batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent))
|
batchCmd.addSubCommand(
|
||||||
|
new MoveElementCommand(elem, oldNextSibling, oldParent)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (!batchCmd.isEmpty()) {
|
||||||
|
svgCanvas.addCommandToHistory(batchCmd)
|
||||||
}
|
}
|
||||||
if (!batchCmd.isEmpty()) { svgCanvas.addCommandToHistory(batchCmd) }
|
|
||||||
|
|
||||||
// update selection
|
// update selection
|
||||||
svgCanvas.selectOnly([g], true)
|
svgCanvas.selectOnly([g], true)
|
||||||
@@ -528,24 +618,32 @@ const pushGroupProperty = (g, undoable) => {
|
|||||||
filter: g.getAttribute('filter'),
|
filter: g.getAttribute('filter'),
|
||||||
opacity: g.getAttribute('opacity')
|
opacity: g.getAttribute('opacity')
|
||||||
}
|
}
|
||||||
let gfilter; let gblur; let changes
|
let gfilter
|
||||||
|
let gblur
|
||||||
|
let changes
|
||||||
const drawing = svgCanvas.getDrawing()
|
const drawing = svgCanvas.getDrawing()
|
||||||
|
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
const elem = children[i]
|
const elem = children[i]
|
||||||
|
|
||||||
if (elem.nodeType !== 1) { continue }
|
if (elem.nodeType !== 1) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if (gattrs.opacity !== null && gattrs.opacity !== 1) {
|
if (gattrs.opacity !== null && gattrs.opacity !== 1) {
|
||||||
// const c_opac = elem.getAttribute('opacity') || 1;
|
// const c_opac = elem.getAttribute('opacity') || 1;
|
||||||
const newOpac = Math.round((elem.getAttribute('opacity') || 1) * gattrs.opacity * 100) / 100
|
const newOpac =
|
||||||
|
Math.round((elem.getAttribute('opacity') || 1) * gattrs.opacity * 100) /
|
||||||
|
100
|
||||||
svgCanvas.changeSelectedAttribute('opacity', newOpac, [elem])
|
svgCanvas.changeSelectedAttribute('opacity', newOpac, [elem])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gattrs.filter) {
|
if (gattrs.filter) {
|
||||||
let cblur = svgCanvas.getBlur(elem)
|
let cblur = svgCanvas.getBlur(elem)
|
||||||
const origCblur = cblur
|
const origCblur = cblur
|
||||||
if (!gblur) { gblur = svgCanvas.getBlur(g) }
|
if (!gblur) {
|
||||||
|
gblur = svgCanvas.getBlur(g)
|
||||||
|
}
|
||||||
if (cblur) {
|
if (cblur) {
|
||||||
// Is this formula correct?
|
// Is this formula correct?
|
||||||
cblur = Number(gblur) + Number(cblur)
|
cblur = Number(gblur) + Number(cblur)
|
||||||
@@ -566,9 +664,14 @@ const pushGroupProperty = (g, undoable) => {
|
|||||||
// const filterElem = getRefElem(gfilter);
|
// const filterElem = getRefElem(gfilter);
|
||||||
const blurElem = getFeGaussianBlur(gfilter)
|
const blurElem = getFeGaussianBlur(gfilter)
|
||||||
// Change this in future for different filters
|
// Change this in future for different filters
|
||||||
const suffix = (blurElem?.tagName === 'feGaussianBlur') ? 'blur' : 'filter'
|
const suffix =
|
||||||
|
blurElem?.tagName === 'feGaussianBlur' ? 'blur' : 'filter'
|
||||||
gfilter.id = elem.id + '_' + suffix
|
gfilter.id = elem.id + '_' + suffix
|
||||||
svgCanvas.changeSelectedAttribute('filter', 'url(#' + gfilter.id + ')', [elem])
|
svgCanvas.changeSelectedAttribute(
|
||||||
|
'filter',
|
||||||
|
'url(#' + gfilter.id + ')',
|
||||||
|
[elem]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gfilter = getRefElem(elem.getAttribute('filter'))
|
gfilter = getRefElem(elem.getAttribute('filter'))
|
||||||
@@ -586,13 +689,19 @@ const pushGroupProperty = (g, undoable) => {
|
|||||||
let chtlist = elem.transform?.baseVal
|
let chtlist = elem.transform?.baseVal
|
||||||
|
|
||||||
// Don't process gradient transforms
|
// Don't process gradient transforms
|
||||||
if (elem.tagName.includes('Gradient')) { chtlist = null }
|
if (elem.tagName.includes('Gradient')) {
|
||||||
|
chtlist = null
|
||||||
|
}
|
||||||
|
|
||||||
// Hopefully not a problem to add this. Necessary for elements like <desc/>
|
// Hopefully not a problem to add this. Necessary for elements like <desc/>
|
||||||
if (!chtlist) { continue }
|
if (!chtlist) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Apparently <defs> can get get a transformlist, but we don't want it to have one!
|
// Apparently <defs> can get get a transformlist, but we don't want it to have one!
|
||||||
if (elem.tagName === 'defs') { continue }
|
if (elem.tagName === 'defs') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if (glist.numberOfItems) {
|
if (glist.numberOfItems) {
|
||||||
// TODO: if the group's transform is just a rotate, we can always transfer the
|
// TODO: if the group's transform is just a rotate, we can always transfer the
|
||||||
@@ -621,7 +730,11 @@ const pushGroupProperty = (g, undoable) => {
|
|||||||
// get child's old center of rotation
|
// get child's old center of rotation
|
||||||
const cbox = utilsGetBBox(elem)
|
const cbox = utilsGetBBox(elem)
|
||||||
const ceqm = transformListToTransform(chtlist).matrix
|
const ceqm = transformListToTransform(chtlist).matrix
|
||||||
const coldc = transformPoint(cbox.x + cbox.width / 2, cbox.y + cbox.height / 2, ceqm)
|
const coldc = transformPoint(
|
||||||
|
cbox.x + cbox.width / 2,
|
||||||
|
cbox.y + cbox.height / 2,
|
||||||
|
ceqm
|
||||||
|
)
|
||||||
|
|
||||||
// sum group and child's angles
|
// sum group and child's angles
|
||||||
const sangle = gangle + cangle
|
const sangle = gangle + cangle
|
||||||
@@ -655,7 +768,8 @@ const pushGroupProperty = (g, undoable) => {
|
|||||||
chtlist.appendItem(tr)
|
chtlist.appendItem(tr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // more complicated than just a rotate
|
} else {
|
||||||
|
// more complicated than just a rotate
|
||||||
// transfer the group's transform down to each child and then
|
// transfer the group's transform down to each child and then
|
||||||
// call recalculateDimensions()
|
// call recalculateDimensions()
|
||||||
const oldxform = elem.getAttribute('transform')
|
const oldxform = elem.getAttribute('transform')
|
||||||
@@ -673,7 +787,9 @@ const pushGroupProperty = (g, undoable) => {
|
|||||||
chtlist.appendItem(newxform)
|
chtlist.appendItem(newxform)
|
||||||
}
|
}
|
||||||
const cmd = recalculateDimensions(elem)
|
const cmd = recalculateDimensions(elem)
|
||||||
if (cmd) { batchCmd.addSubCommand(cmd) }
|
if (cmd) {
|
||||||
|
batchCmd.addSubCommand(cmd)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,7 +815,7 @@ const pushGroupProperty = (g, undoable) => {
|
|||||||
* @fires module:selected-elem.SvgCanvas#event:selected
|
* @fires module:selected-elem.SvgCanvas#event:selected
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
const convertToGroup = (elem) => {
|
const convertToGroup = elem => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
if (!elem) {
|
if (!elem) {
|
||||||
elem = selectedElements[0]
|
elem = selectedElements[0]
|
||||||
@@ -752,7 +868,13 @@ const convertToGroup = (elem) => {
|
|||||||
const prev = $elem.previousElementSibling
|
const prev = $elem.previousElementSibling
|
||||||
|
|
||||||
// Remove <use> element
|
// Remove <use> element
|
||||||
batchCmd.addSubCommand(new RemoveElementCommand($elem, $elem.nextElementSibling, $elem.parentNode))
|
batchCmd.addSubCommand(
|
||||||
|
new RemoveElementCommand(
|
||||||
|
$elem,
|
||||||
|
$elem.nextElementSibling,
|
||||||
|
$elem.parentNode
|
||||||
|
)
|
||||||
|
)
|
||||||
$elem.remove()
|
$elem.remove()
|
||||||
|
|
||||||
// See if other elements reference this symbol
|
// See if other elements reference this symbol
|
||||||
@@ -772,7 +894,9 @@ const convertToGroup = (elem) => {
|
|||||||
// Duplicate the gradients for Gecko, since they weren't included in the <symbol>
|
// Duplicate the gradients for Gecko, since they weren't included in the <symbol>
|
||||||
if (isGecko()) {
|
if (isGecko()) {
|
||||||
const svgElement = findDefs()
|
const svgElement = findDefs()
|
||||||
const gradients = svgElement.querySelectorAll('linearGradient,radialGradient,pattern')
|
const gradients = svgElement.querySelectorAll(
|
||||||
|
'linearGradient,radialGradient,pattern'
|
||||||
|
)
|
||||||
for (let i = 0, im = gradients.length; im > i; i++) {
|
for (let i = 0, im = gradients.length; im > i; i++) {
|
||||||
g.appendChild(gradients[i].cloneNode(true))
|
g.appendChild(gradients[i].cloneNode(true))
|
||||||
}
|
}
|
||||||
@@ -789,7 +913,9 @@ const convertToGroup = (elem) => {
|
|||||||
// Put the dupe gradients back into <defs> (after uniquifying them)
|
// Put the dupe gradients back into <defs> (after uniquifying them)
|
||||||
if (isGecko()) {
|
if (isGecko()) {
|
||||||
const svgElement = findDefs()
|
const svgElement = findDefs()
|
||||||
const elements = g.querySelectorAll('linearGradient,radialGradient,pattern')
|
const elements = g.querySelectorAll(
|
||||||
|
'linearGradient,radialGradient,pattern'
|
||||||
|
)
|
||||||
for (let i = 0, im = elements.length; im > i; i++) {
|
for (let i = 0, im = elements.length; im > i; i++) {
|
||||||
svgElement.appendChild(elements[i])
|
svgElement.appendChild(elements[i])
|
||||||
}
|
}
|
||||||
@@ -805,7 +931,9 @@ const convertToGroup = (elem) => {
|
|||||||
// remove symbol/svg element
|
// remove symbol/svg element
|
||||||
const { nextSibling } = elem
|
const { nextSibling } = elem
|
||||||
elem.remove()
|
elem.remove()
|
||||||
batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent))
|
batchCmd.addSubCommand(
|
||||||
|
new RemoveElementCommand(elem, nextSibling, parent)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
batchCmd.addSubCommand(new InsertElementCommand(g))
|
batchCmd.addSubCommand(new InsertElementCommand(g))
|
||||||
}
|
}
|
||||||
@@ -820,7 +948,7 @@ const convertToGroup = (elem) => {
|
|||||||
|
|
||||||
// recalculate dimensions on the top-level children so that unnecessary transforms
|
// recalculate dimensions on the top-level children so that unnecessary transforms
|
||||||
// are removed
|
// are removed
|
||||||
walkTreePost(g, (n) => {
|
walkTreePost(g, n => {
|
||||||
try {
|
try {
|
||||||
recalculateDimensions(n)
|
recalculateDimensions(n)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -830,8 +958,10 @@ const convertToGroup = (elem) => {
|
|||||||
|
|
||||||
// Give ID for any visible element missing one
|
// Give ID for any visible element missing one
|
||||||
const visElems = g.querySelectorAll(svgCanvas.getVisElems())
|
const visElems = g.querySelectorAll(svgCanvas.getVisElems())
|
||||||
Array.prototype.forEach.call(visElems, (el) => {
|
Array.prototype.forEach.call(visElems, el => {
|
||||||
if (!el.id) { el.id = svgCanvas.getNextId() }
|
if (!el.id) {
|
||||||
|
el.id = svgCanvas.getNextId()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
svgCanvas.selectOnly([g])
|
svgCanvas.selectOnly([g])
|
||||||
@@ -882,7 +1012,9 @@ const ungroupSelectedElement = () => {
|
|||||||
if (g.tagName === 'g' || g.tagName === 'a') {
|
if (g.tagName === 'g' || g.tagName === 'a') {
|
||||||
const batchCmd = new BatchCommand('Ungroup Elements')
|
const batchCmd = new BatchCommand('Ungroup Elements')
|
||||||
const cmd = pushGroupProperty(g, true)
|
const cmd = pushGroupProperty(g, true)
|
||||||
if (cmd) { batchCmd.addSubCommand(cmd) }
|
if (cmd) {
|
||||||
|
batchCmd.addSubCommand(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
const parent = g.parentNode
|
const parent = g.parentNode
|
||||||
const anchor = g.nextSibling
|
const anchor = g.nextSibling
|
||||||
@@ -897,13 +1029,17 @@ const ungroupSelectedElement = () => {
|
|||||||
// Remove child title elements
|
// Remove child title elements
|
||||||
if (elem.tagName === 'title') {
|
if (elem.tagName === 'title') {
|
||||||
const { nextSibling } = elem
|
const { nextSibling } = elem
|
||||||
batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, oldParent))
|
batchCmd.addSubCommand(
|
||||||
|
new RemoveElementCommand(elem, nextSibling, oldParent)
|
||||||
|
)
|
||||||
elem.remove()
|
elem.remove()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
children[i++] = parent.insertBefore(elem, anchor)
|
children[i++] = parent.insertBefore(elem, anchor)
|
||||||
batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent))
|
batchCmd.addSubCommand(
|
||||||
|
new MoveElementCommand(elem, oldNextSibling, oldParent)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the group from the selection
|
// remove the group from the selection
|
||||||
@@ -914,7 +1050,9 @@ const ungroupSelectedElement = () => {
|
|||||||
g.remove()
|
g.remove()
|
||||||
batchCmd.addSubCommand(new RemoveElementCommand(g, gNextSibling, parent))
|
batchCmd.addSubCommand(new RemoveElementCommand(g, gNextSibling, parent))
|
||||||
|
|
||||||
if (!batchCmd.isEmpty()) { svgCanvas.addCommandToHistory(batchCmd) }
|
if (!batchCmd.isEmpty()) {
|
||||||
|
svgCanvas.addCommandToHistory(batchCmd)
|
||||||
|
}
|
||||||
|
|
||||||
// update selection
|
// update selection
|
||||||
svgCanvas.addToSelection(children)
|
svgCanvas.addToSelection(children)
|
||||||
@@ -935,8 +1073,8 @@ const updateCanvas = (w, h) => {
|
|||||||
const bg = document.getElementById('canvasBackground')
|
const bg = document.getElementById('canvasBackground')
|
||||||
const oldX = Number(svgCanvas.getSvgContent().getAttribute('x'))
|
const oldX = Number(svgCanvas.getSvgContent().getAttribute('x'))
|
||||||
const oldY = Number(svgCanvas.getSvgContent().getAttribute('y'))
|
const oldY = Number(svgCanvas.getSvgContent().getAttribute('y'))
|
||||||
const x = ((w - svgCanvas.contentW * zoom) / 2)
|
const x = (w - svgCanvas.contentW * zoom) / 2
|
||||||
const y = ((h - svgCanvas.contentH * zoom) / 2)
|
const y = (h - svgCanvas.contentH * zoom) / 2
|
||||||
|
|
||||||
assignAttributes(svgCanvas.getSvgContent(), {
|
assignAttributes(svgCanvas.getSvgContent(), {
|
||||||
width: svgCanvas.contentW * zoom,
|
width: svgCanvas.contentW * zoom,
|
||||||
@@ -961,7 +1099,10 @@ const updateCanvas = (w, h) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
svgCanvas.selectorManager.selectorParentGroup.setAttribute('transform', 'translate(' + x + ',' + y + ')')
|
svgCanvas.selectorManager.selectorParentGroup.setAttribute(
|
||||||
|
'transform',
|
||||||
|
'translate(' + x + ',' + y + ')'
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked upon updates to the canvas.
|
* Invoked upon updates to the canvas.
|
||||||
@@ -979,7 +1120,14 @@ const updateCanvas = (w, h) => {
|
|||||||
/**
|
/**
|
||||||
* @type {module:svgcanvas.SvgCanvas#event:ext_canvasUpdated}
|
* @type {module:svgcanvas.SvgCanvas#event:ext_canvasUpdated}
|
||||||
*/
|
*/
|
||||||
{ new_x: x, new_y: y, old_x: oldX, old_y: oldY, d_x: x - oldX, d_y: y - oldY }
|
{
|
||||||
|
new_x: x,
|
||||||
|
new_y: y,
|
||||||
|
old_x: oldX,
|
||||||
|
old_y: oldY,
|
||||||
|
d_x: x - oldX,
|
||||||
|
d_y: y - oldY
|
||||||
|
}
|
||||||
)
|
)
|
||||||
return { x, y, old_x: oldX, old_y: oldY, d_x: x - oldX, d_y: y - oldY }
|
return { x, y, old_x: oldX, old_y: oldY, d_x: x - oldX, d_y: y - oldY }
|
||||||
}
|
}
|
||||||
@@ -990,14 +1138,18 @@ const updateCanvas = (w, h) => {
|
|||||||
* @fires module:svgcanvas.SvgCanvas#event:selected
|
* @fires module:svgcanvas.SvgCanvas#event:selected
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
const cycleElement = (next) => {
|
const cycleElement = next => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
const currentGroup = svgCanvas.getCurrentGroup()
|
const currentGroup = svgCanvas.getCurrentGroup()
|
||||||
let num
|
let num
|
||||||
const curElem = selectedElements[0]
|
const curElem = selectedElements[0]
|
||||||
let elem = false
|
let elem = false
|
||||||
const allElems = getVisibleElements(currentGroup || svgCanvas.getCurrentDrawing().getCurrentLayer())
|
const allElems = getVisibleElements(
|
||||||
if (!allElems.length) { return }
|
currentGroup || svgCanvas.getCurrentDrawing().getCurrentLayer()
|
||||||
|
)
|
||||||
|
if (!allElems.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (!curElem) {
|
if (!curElem) {
|
||||||
num = next ? allElems.length - 1 : 0
|
num = next ? allElems.length - 1 : 0
|
||||||
elem = allElems[num]
|
elem = allElems[num]
|
||||||
|
|||||||
@@ -28,6 +28,15 @@ let svgCanvas = null
|
|||||||
*/
|
*/
|
||||||
export const init = (canvas) => {
|
export const init = (canvas) => {
|
||||||
svgCanvas = canvas
|
svgCanvas = canvas
|
||||||
|
svgCanvas.getMouseTarget = getMouseTargetMethod
|
||||||
|
svgCanvas.clearSelection = clearSelectionMethod
|
||||||
|
svgCanvas.addToSelection = addToSelectionMethod
|
||||||
|
svgCanvas.getIntersectionList = getIntersectionListMethod
|
||||||
|
svgCanvas.runExtensions = runExtensionsMethod
|
||||||
|
svgCanvas.groupSvgElem = groupSvgElem
|
||||||
|
svgCanvas.prepareSvg = prepareSvg
|
||||||
|
svgCanvas.recalculateAllSelectedDimensions = recalculateAllSelectedDimensions
|
||||||
|
svgCanvas.setRotationAngle = setRotationAngle
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,7 +46,7 @@ export const init = (canvas) => {
|
|||||||
* @type {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection}
|
* @type {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection}
|
||||||
* @fires module:selection.SvgCanvas#event:selected
|
* @fires module:selection.SvgCanvas#event:selected
|
||||||
*/
|
*/
|
||||||
export const clearSelectionMethod = (noCall) => {
|
const clearSelectionMethod = (noCall) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
selectedElements.forEach((elem) => {
|
selectedElements.forEach((elem) => {
|
||||||
if (!elem) {
|
if (!elem) {
|
||||||
@@ -59,7 +68,7 @@ export const clearSelectionMethod = (noCall) => {
|
|||||||
* @type {module:path.EditorContext#addToSelection}
|
* @type {module:path.EditorContext#addToSelection}
|
||||||
* @fires module:selection.SvgCanvas#event:selected
|
* @fires module:selection.SvgCanvas#event:selected
|
||||||
*/
|
*/
|
||||||
export const addToSelectionMethod = (elemsToAdd, showGrips) => {
|
const addToSelectionMethod = (elemsToAdd, showGrips) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
if (!elemsToAdd.length) {
|
if (!elemsToAdd.length) {
|
||||||
return
|
return
|
||||||
@@ -134,7 +143,7 @@ export const addToSelectionMethod = (elemsToAdd, showGrips) => {
|
|||||||
* @name module:svgcanvas.SvgCanvas#getMouseTarget
|
* @name module:svgcanvas.SvgCanvas#getMouseTarget
|
||||||
* @type {module:path.EditorContext#getMouseTarget}
|
* @type {module:path.EditorContext#getMouseTarget}
|
||||||
*/
|
*/
|
||||||
export const getMouseTargetMethod = (evt) => {
|
const getMouseTargetMethod = (evt) => {
|
||||||
if (!evt) {
|
if (!evt) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -211,7 +220,7 @@ export const getMouseTargetMethod = (evt) => {
|
|||||||
* @returns {GenericArray<module:svgcanvas.ExtensionStatus>|module:svgcanvas.ExtensionStatus|false} See {@tutorial ExtensionDocs} on the ExtensionStatus.
|
* @returns {GenericArray<module:svgcanvas.ExtensionStatus>|module:svgcanvas.ExtensionStatus|false} See {@tutorial ExtensionDocs} on the ExtensionStatus.
|
||||||
*/
|
*/
|
||||||
/* eslint-enable max-len */
|
/* eslint-enable max-len */
|
||||||
export const runExtensionsMethod = (
|
const runExtensionsMethod = (
|
||||||
action,
|
action,
|
||||||
vars,
|
vars,
|
||||||
returnArray
|
returnArray
|
||||||
@@ -248,7 +257,7 @@ export const runExtensionsMethod = (
|
|||||||
* @param {Element} parent - The parent DOM element to search within
|
* @param {Element} parent - The parent DOM element to search within
|
||||||
* @returns {ElementAndBBox[]} An array with objects that include:
|
* @returns {ElementAndBBox[]} An array with objects that include:
|
||||||
*/
|
*/
|
||||||
export const getVisibleElementsAndBBoxes = (parent) => {
|
const getVisibleElementsAndBBoxes = (parent) => {
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
const svgContent = svgCanvas.getSvgContent()
|
const svgContent = svgCanvas.getSvgContent()
|
||||||
parent = svgContent.children // Prevent layers from being included
|
parent = svgContent.children // Prevent layers from being included
|
||||||
@@ -275,7 +284,7 @@ export const getVisibleElementsAndBBoxes = (parent) => {
|
|||||||
* @param {SVGRect} rect
|
* @param {SVGRect} rect
|
||||||
* @returns {Element[]|NodeList} Bbox elements
|
* @returns {Element[]|NodeList} Bbox elements
|
||||||
*/
|
*/
|
||||||
export const getIntersectionListMethod = (rect) => {
|
const getIntersectionListMethod = (rect) => {
|
||||||
const zoom = svgCanvas.getZoom()
|
const zoom = svgCanvas.getZoom()
|
||||||
if (!svgCanvas.getRubberBox()) {
|
if (!svgCanvas.getRubberBox()) {
|
||||||
return null
|
return null
|
||||||
@@ -338,7 +347,7 @@ export const getIntersectionListMethod = (rect) => {
|
|||||||
* @param {Element} elem - SVG element to wrap
|
* @param {Element} elem - SVG element to wrap
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const groupSvgElem = (elem) => {
|
const groupSvgElem = (elem) => {
|
||||||
const dataStorage = svgCanvas.getDataStorage()
|
const dataStorage = svgCanvas.getDataStorage()
|
||||||
const g = document.createElementNS(NS.SVG, 'g')
|
const g = document.createElementNS(NS.SVG, 'g')
|
||||||
elem.replaceWith(g)
|
elem.replaceWith(g)
|
||||||
@@ -353,7 +362,7 @@ export const groupSvgElem = (elem) => {
|
|||||||
* @param {XMLDocument} newDoc - The SVG DOM document
|
* @param {XMLDocument} newDoc - The SVG DOM document
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const prepareSvg = (newDoc) => {
|
const prepareSvg = (newDoc) => {
|
||||||
svgCanvas.sanitizeSvg(newDoc.documentElement)
|
svgCanvas.sanitizeSvg(newDoc.documentElement)
|
||||||
|
|
||||||
// convert paths into absolute commands
|
// convert paths into absolute commands
|
||||||
@@ -374,7 +383,7 @@ export const prepareSvg = (newDoc) => {
|
|||||||
* @fires module:svgcanvas.SvgCanvas#event:changed
|
* @fires module:svgcanvas.SvgCanvas#event:changed
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setRotationAngle = (val, preventUndo) => {
|
const setRotationAngle = (val, preventUndo) => {
|
||||||
const selectedElements = svgCanvas.getSelectedElements()
|
const selectedElements = svgCanvas.getSelectedElements()
|
||||||
// ensure val is the proper type
|
// ensure val is the proper type
|
||||||
val = Number.parseFloat(val)
|
val = Number.parseFloat(val)
|
||||||
@@ -444,7 +453,7 @@ export const setRotationAngle = (val, preventUndo) => {
|
|||||||
* @fires module:svgcanvas.SvgCanvas#event:changed
|
* @fires module:svgcanvas.SvgCanvas#event:changed
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const recalculateAllSelectedDimensions = () => {
|
const recalculateAllSelectedDimensions = () => {
|
||||||
const text =
|
const text =
|
||||||
svgCanvas.getCurrentResizeMode() === 'none' ? 'position' : 'size'
|
svgCanvas.getCurrentResizeMode() === 'none' ? 'position' : 'size'
|
||||||
const batchCmd = new BatchCommand(text)
|
const batchCmd = new BatchCommand(text)
|
||||||
|
|||||||
@@ -10,28 +10,33 @@ import 'svg2pdf.js/dist/svg2pdf.es.js'
|
|||||||
import html2canvas from 'html2canvas'
|
import html2canvas from 'html2canvas'
|
||||||
import * as hstry from './history.js'
|
import * as hstry from './history.js'
|
||||||
import {
|
import {
|
||||||
text2xml, cleanupElement, findDefs, getHref, preventClickDefault,
|
text2xml,
|
||||||
toXml, getStrokedBBoxDefaultVisible, encode64, createObjectURL,
|
cleanupElement,
|
||||||
dataURLToObjectURL, walkTree, getBBox as utilsGetBBox
|
findDefs,
|
||||||
|
getHref,
|
||||||
|
preventClickDefault,
|
||||||
|
toXml,
|
||||||
|
getStrokedBBoxDefaultVisible,
|
||||||
|
encode64,
|
||||||
|
createObjectURL,
|
||||||
|
dataURLToObjectURL,
|
||||||
|
walkTree,
|
||||||
|
getBBox as utilsGetBBox
|
||||||
} from './utilities.js'
|
} from './utilities.js'
|
||||||
import {
|
import { transformPoint, transformListToTransform } from './math.js'
|
||||||
transformPoint, transformListToTransform
|
import { convertUnit, shortFloat, convertToNum } from '../common/units.js'
|
||||||
} from './math.js'
|
|
||||||
import {
|
|
||||||
convertUnit, shortFloat, convertToNum
|
|
||||||
} from '../common/units.js'
|
|
||||||
import { isGecko, isChrome, isWebkit } from '../common/browser.js'
|
import { isGecko, isChrome, isWebkit } from '../common/browser.js'
|
||||||
import * as pathModule from './path.js'
|
import * as pathModule from './path.js'
|
||||||
import { NS } from './namespaces.js'
|
import { NS } from './namespaces.js'
|
||||||
import * as draw from './draw.js'
|
import * as draw from './draw.js'
|
||||||
import {
|
import { recalculateDimensions } from './recalculate.js'
|
||||||
recalculateDimensions
|
|
||||||
} from './recalculate.js'
|
|
||||||
import { getParents, getClosest } from '../editor/components/jgraduate/Util.js'
|
import { getParents, getClosest } from '../editor/components/jgraduate/Util.js'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
InsertElementCommand, RemoveElementCommand,
|
InsertElementCommand,
|
||||||
ChangeElementCommand, BatchCommand
|
RemoveElementCommand,
|
||||||
|
ChangeElementCommand,
|
||||||
|
BatchCommand
|
||||||
} = hstry
|
} = hstry
|
||||||
|
|
||||||
let svgCanvas = null
|
let svgCanvas = null
|
||||||
@@ -41,8 +46,19 @@ let svgCanvas = null
|
|||||||
* @param {module:svg-exec.SvgCanvas#init} svgContext
|
* @param {module:svg-exec.SvgCanvas#init} svgContext
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const init = (canvas) => {
|
export const init = canvas => {
|
||||||
svgCanvas = canvas
|
svgCanvas = canvas
|
||||||
|
svgCanvas.setSvgString = setSvgString
|
||||||
|
svgCanvas.importSvgString = importSvgString
|
||||||
|
svgCanvas.uniquifyElems = uniquifyElemsMethod
|
||||||
|
svgCanvas.setUseData = setUseDataMethod
|
||||||
|
svgCanvas.convertGradients = convertGradientsMethod
|
||||||
|
svgCanvas.removeUnusedDefElems = removeUnusedDefElemsMethod // remove DOM elements inside the `<defs>` if they are notreferred to,
|
||||||
|
svgCanvas.svgCanvasToString = svgCanvasToString // Main function to set up the SVG content for output.
|
||||||
|
svgCanvas.svgToString = svgToString // Sub function ran on each SVG element to convert it to a string as desired.
|
||||||
|
svgCanvas.embedImage = embedImage // Converts a given image file to a data URL when possibl
|
||||||
|
svgCanvas.rasterExport = rasterExport // Generates a PNG (or JPG, BMP, WEBP) Data URL based on the current image
|
||||||
|
svgCanvas.exportPDF = exportPDF // Generates a PDF based on the current image, then calls "exportedPDF"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,7 +66,7 @@ export const init = (canvas) => {
|
|||||||
* @function module:svgcanvas.SvgCanvas#svgCanvasToString
|
* @function module:svgcanvas.SvgCanvas#svgCanvasToString
|
||||||
* @returns {string} The SVG image for output
|
* @returns {string} The SVG image for output
|
||||||
*/
|
*/
|
||||||
export const svgCanvasToString = () => {
|
const svgCanvasToString = () => {
|
||||||
// keep calling it until there are none to remove
|
// keep calling it until there are none to remove
|
||||||
while (svgCanvas.removeUnusedDefElems() > 0) {} // eslint-disable-line no-empty
|
while (svgCanvas.removeUnusedDefElems() > 0) {} // eslint-disable-line no-empty
|
||||||
|
|
||||||
@@ -58,7 +74,7 @@ export const svgCanvasToString = () => {
|
|||||||
|
|
||||||
// Keep SVG-Edit comment on top
|
// Keep SVG-Edit comment on top
|
||||||
const childNodesElems = svgCanvas.getSvgContent().childNodes
|
const childNodesElems = svgCanvas.getSvgContent().childNodes
|
||||||
childNodesElems.forEach(function (node, i) {
|
childNodesElems.forEach((node, i) => {
|
||||||
if (i && node.nodeType === 8 && node.data.includes('Created with')) {
|
if (i && node.nodeType === 8 && node.data.includes('Created with')) {
|
||||||
svgCanvas.getSvgContent().firstChild.before(node)
|
svgCanvas.getSvgContent().firstChild.before(node)
|
||||||
}
|
}
|
||||||
@@ -74,7 +90,7 @@ export const svgCanvasToString = () => {
|
|||||||
|
|
||||||
// Unwrap gsvg if it has no special attributes (only id and style)
|
// Unwrap gsvg if it has no special attributes (only id and style)
|
||||||
const gsvgElems = svgCanvas.getSvgContent().querySelectorAll('g[data-gsvg]')
|
const gsvgElems = svgCanvas.getSvgContent().querySelectorAll('g[data-gsvg]')
|
||||||
Array.prototype.forEach.call(gsvgElems, function (element) {
|
Array.prototype.forEach.call(gsvgElems, (element) => {
|
||||||
const attrs = element.attributes
|
const attrs = element.attributes
|
||||||
let len = attrs.length
|
let len = attrs.length
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
@@ -93,7 +109,7 @@ export const svgCanvasToString = () => {
|
|||||||
|
|
||||||
// Rewrap gsvg
|
// Rewrap gsvg
|
||||||
if (nakedSvgs.length) {
|
if (nakedSvgs.length) {
|
||||||
Array.prototype.forEach.call(nakedSvgs, function (el) {
|
Array.prototype.forEach.call(nakedSvgs, (el) => {
|
||||||
svgCanvas.groupSvgElem(el)
|
svgCanvas.groupSvgElem(el)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -108,7 +124,7 @@ export const svgCanvasToString = () => {
|
|||||||
* @param {Integer} indent - Number of spaces to indent this tag
|
* @param {Integer} indent - Number of spaces to indent this tag
|
||||||
* @returns {string} The given element as an SVG tag
|
* @returns {string} The given element as an SVG tag
|
||||||
*/
|
*/
|
||||||
export const svgToString = function (elem, indent) {
|
const svgToString = (elem, indent) => {
|
||||||
const curConfig = svgCanvas.getCurConfig()
|
const curConfig = svgCanvas.getCurConfig()
|
||||||
const nsMap = svgCanvas.getNsMap()
|
const nsMap = svgCanvas.getNsMap()
|
||||||
const out = []
|
const out = []
|
||||||
@@ -123,8 +139,11 @@ export const svgToString = function (elem, indent) {
|
|||||||
return a.name > b.name ? -1 : 1
|
return a.name > b.name ? -1 : 1
|
||||||
})
|
})
|
||||||
|
|
||||||
for (let i = 0; i < indent; i++) { out.push(' ') }
|
for (let i = 0; i < indent; i++) {
|
||||||
out.push('<'); out.push(elem.nodeName)
|
out.push(' ')
|
||||||
|
}
|
||||||
|
out.push('<')
|
||||||
|
out.push(elem.nodeName)
|
||||||
if (elem.id === 'svgcontent') {
|
if (elem.id === 'svgcontent') {
|
||||||
// Process root element separately
|
// Process root element separately
|
||||||
const res = svgCanvas.getResolution()
|
const res = svgCanvas.getResolution()
|
||||||
@@ -147,7 +166,17 @@ export const svgToString = function (elem, indent) {
|
|||||||
res.h = convertUnit(res.h, unit) + unit
|
res.h = convertUnit(res.h, unit) + unit
|
||||||
}
|
}
|
||||||
|
|
||||||
out.push(' width="' + res.w + '" height="' + res.h + '"' + vb + ' xmlns="' + NS.SVG + '"')
|
out.push(
|
||||||
|
' width="' +
|
||||||
|
res.w +
|
||||||
|
'" height="' +
|
||||||
|
res.h +
|
||||||
|
'"' +
|
||||||
|
vb +
|
||||||
|
' xmlns="' +
|
||||||
|
NS.SVG +
|
||||||
|
'"'
|
||||||
|
)
|
||||||
|
|
||||||
const nsuris = {}
|
const nsuris = {}
|
||||||
|
|
||||||
@@ -155,11 +184,17 @@ export const svgToString = function (elem, indent) {
|
|||||||
const csElements = elem.querySelectorAll('*')
|
const csElements = elem.querySelectorAll('*')
|
||||||
const cElements = Array.prototype.slice.call(csElements)
|
const cElements = Array.prototype.slice.call(csElements)
|
||||||
cElements.push(elem)
|
cElements.push(elem)
|
||||||
Array.prototype.forEach.call(cElements, function (el) {
|
Array.prototype.forEach.call(cElements, (el) => {
|
||||||
// const el = this;
|
// const el = this;
|
||||||
// for some elements have no attribute
|
// for some elements have no attribute
|
||||||
const uri = el.namespaceURI
|
const uri = el.namespaceURI
|
||||||
if (uri && !nsuris[uri] && nsMap[uri] && nsMap[uri] !== 'xmlns' && nsMap[uri] !== 'xml') {
|
if (
|
||||||
|
uri &&
|
||||||
|
!nsuris[uri] &&
|
||||||
|
nsMap[uri] &&
|
||||||
|
nsMap[uri] !== 'xmlns' &&
|
||||||
|
nsMap[uri] !== 'xml'
|
||||||
|
) {
|
||||||
nsuris[uri] = true
|
nsuris[uri] = true
|
||||||
out.push(' xmlns:' + nsMap[uri] + '="' + uri + '"')
|
out.push(' xmlns:' + nsMap[uri] + '="' + uri + '"')
|
||||||
}
|
}
|
||||||
@@ -175,40 +210,71 @@ export const svgToString = function (elem, indent) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
let i = attrs.length
|
let i = attrs.length
|
||||||
const attrNames = ['width', 'height', 'xmlns', 'x', 'y', 'viewBox', 'id', 'overflow']
|
const attrNames = [
|
||||||
|
'width',
|
||||||
|
'height',
|
||||||
|
'xmlns',
|
||||||
|
'x',
|
||||||
|
'y',
|
||||||
|
'viewBox',
|
||||||
|
'id',
|
||||||
|
'overflow'
|
||||||
|
]
|
||||||
while (i--) {
|
while (i--) {
|
||||||
const attr = attrs[i]
|
const attr = attrs[i]
|
||||||
const attrVal = toXml(attr.value)
|
const attrVal = toXml(attr.value)
|
||||||
|
|
||||||
// Namespaces have already been dealt with, so skip
|
// Namespaces have already been dealt with, so skip
|
||||||
if (attr.nodeName.startsWith('xmlns:')) { continue }
|
if (attr.nodeName.startsWith('xmlns:')) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// only serialize attributes we don't use internally
|
// only serialize attributes we don't use internally
|
||||||
if (attrVal !== '' && !attrNames.includes(attr.localName) && (!attr.namespaceURI || nsMap[attr.namespaceURI])) {
|
if (
|
||||||
|
attrVal !== '' &&
|
||||||
|
!attrNames.includes(attr.localName) &&
|
||||||
|
(!attr.namespaceURI || nsMap[attr.namespaceURI])
|
||||||
|
) {
|
||||||
out.push(' ')
|
out.push(' ')
|
||||||
out.push(attr.nodeName); out.push('="')
|
out.push(attr.nodeName)
|
||||||
out.push(attrVal); out.push('"')
|
out.push('="')
|
||||||
|
out.push(attrVal)
|
||||||
|
out.push('"')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Skip empty defs
|
// Skip empty defs
|
||||||
if (elem.nodeName === 'defs' && !elem.firstChild) { return '' }
|
if (elem.nodeName === 'defs' && !elem.firstChild) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
const mozAttrs = ['-moz-math-font-style', '_moz-math-font-style']
|
const mozAttrs = ['-moz-math-font-style', '_moz-math-font-style']
|
||||||
for (let i = attrs.length - 1; i >= 0; i--) {
|
for (let i = attrs.length - 1; i >= 0; i--) {
|
||||||
const attr = attrs[i]
|
const attr = attrs[i]
|
||||||
let attrVal = toXml(attr.value)
|
let attrVal = toXml(attr.value)
|
||||||
// remove bogus attributes added by Gecko
|
// remove bogus attributes added by Gecko
|
||||||
if (mozAttrs.includes(attr.localName)) { continue }
|
if (mozAttrs.includes(attr.localName)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if (attrVal === 'null') {
|
if (attrVal === 'null') {
|
||||||
const styleName = attr.localName.replace(/-[a-z]/g, (s) => s[1].toUpperCase())
|
const styleName = attr.localName.replace(/-[a-z]/g, s =>
|
||||||
if (Object.prototype.hasOwnProperty.call(elem.style, styleName)) { continue }
|
s[1].toUpperCase()
|
||||||
|
)
|
||||||
|
if (Object.prototype.hasOwnProperty.call(elem.style, styleName)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (attrVal !== '') {
|
if (attrVal !== '') {
|
||||||
if (attrVal.startsWith('pointer-events')) { continue }
|
if (attrVal.startsWith('pointer-events')) {
|
||||||
if (attr.localName === 'class' && attrVal.startsWith('se_')) { continue }
|
continue
|
||||||
|
}
|
||||||
|
if (attr.localName === 'class' && attrVal.startsWith('se_')) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
out.push(' ')
|
out.push(' ')
|
||||||
if (attr.localName === 'd') { attrVal = svgCanvas.pathActions.convertPath(elem, true) }
|
if (attr.localName === 'd') {
|
||||||
|
attrVal = svgCanvas.pathActions.convertPath(elem, true)
|
||||||
|
}
|
||||||
if (!isNaN(attrVal)) {
|
if (!isNaN(attrVal)) {
|
||||||
attrVal = shortFloat(attrVal)
|
attrVal = shortFloat(attrVal)
|
||||||
} else if (unitRe.test(attrVal)) {
|
} else if (unitRe.test(attrVal)) {
|
||||||
@@ -216,21 +282,30 @@ export const svgToString = function (elem, indent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Embed images when saving
|
// Embed images when saving
|
||||||
if (svgCanvas.getSvgOptionApply() &&
|
if (
|
||||||
|
svgCanvas.getSvgOptionApply() &&
|
||||||
elem.nodeName === 'image' &&
|
elem.nodeName === 'image' &&
|
||||||
attr.localName === 'href' &&
|
attr.localName === 'href' &&
|
||||||
svgCanvas.getSvgOptionImages() &&
|
svgCanvas.getSvgOptionImages() &&
|
||||||
svgCanvas.getSvgOptionImages() === 'embed'
|
svgCanvas.getSvgOptionImages() === 'embed'
|
||||||
) {
|
) {
|
||||||
const img = svgCanvas.getEncodableImages(attrVal)
|
const img = svgCanvas.getEncodableImages(attrVal)
|
||||||
if (img) { attrVal = img }
|
if (img) {
|
||||||
|
attrVal = img
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// map various namespaces to our fixed namespace prefixes
|
// map various namespaces to our fixed namespace prefixes
|
||||||
// (the default xmlns attribute itself does not get a prefix)
|
// (the default xmlns attribute itself does not get a prefix)
|
||||||
if (!attr.namespaceURI || attr.namespaceURI === NS.SVG || nsMap[attr.namespaceURI]) {
|
if (
|
||||||
out.push(attr.nodeName); out.push('="')
|
!attr.namespaceURI ||
|
||||||
out.push(attrVal); out.push('"')
|
attr.namespaceURI === NS.SVG ||
|
||||||
|
nsMap[attr.namespaceURI]
|
||||||
|
) {
|
||||||
|
out.push(attr.nodeName)
|
||||||
|
out.push('="')
|
||||||
|
out.push(attrVal)
|
||||||
|
out.push('"')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -248,14 +323,16 @@ export const svgToString = function (elem, indent) {
|
|||||||
out.push('\n')
|
out.push('\n')
|
||||||
out.push(svgCanvas.svgToString(child, indent))
|
out.push(svgCanvas.svgToString(child, indent))
|
||||||
break
|
break
|
||||||
case 3: { // text node
|
case 3: {
|
||||||
|
// text node
|
||||||
const str = child.nodeValue.replace(/^\s+|\s+$/g, '')
|
const str = child.nodeValue.replace(/^\s+|\s+$/g, '')
|
||||||
if (str !== '') {
|
if (str !== '') {
|
||||||
bOneLine = true
|
bOneLine = true
|
||||||
out.push(String(toXml(str)))
|
out.push(String(toXml(str)))
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
} case 4: // cdata node
|
}
|
||||||
|
case 4: // cdata node
|
||||||
out.push('\n')
|
out.push('\n')
|
||||||
out.push(new Array(indent + 1).join(' '))
|
out.push(new Array(indent + 1).join(' '))
|
||||||
out.push('<![CDATA[')
|
out.push('<![CDATA[')
|
||||||
@@ -274,9 +351,13 @@ export const svgToString = function (elem, indent) {
|
|||||||
indent--
|
indent--
|
||||||
if (!bOneLine) {
|
if (!bOneLine) {
|
||||||
out.push('\n')
|
out.push('\n')
|
||||||
for (let i = 0; i < indent; i++) { out.push(' ') }
|
for (let i = 0; i < indent; i++) {
|
||||||
|
out.push(' ')
|
||||||
}
|
}
|
||||||
out.push('</'); out.push(elem.nodeName); out.push('>')
|
}
|
||||||
|
out.push('</')
|
||||||
|
out.push(elem.nodeName)
|
||||||
|
out.push('>')
|
||||||
} else {
|
} else {
|
||||||
out.push('/>')
|
out.push('/>')
|
||||||
}
|
}
|
||||||
@@ -297,14 +378,16 @@ export const svgToString = function (elem, indent) {
|
|||||||
* @returns {boolean} This function returns `false` if the set was
|
* @returns {boolean} This function returns `false` if the set was
|
||||||
* unsuccessful, `true` otherwise.
|
* unsuccessful, `true` otherwise.
|
||||||
*/
|
*/
|
||||||
export const setSvgString = function (xmlString, preventUndo) {
|
const setSvgString = (xmlString, preventUndo) => {
|
||||||
const curConfig = svgCanvas.getCurConfig()
|
const curConfig = svgCanvas.getCurConfig()
|
||||||
const dataStorage = svgCanvas.getDataStorage()
|
const dataStorage = svgCanvas.getDataStorage()
|
||||||
try {
|
try {
|
||||||
// convert string into XML document
|
// convert string into XML document
|
||||||
const newDoc = text2xml(xmlString)
|
const newDoc = text2xml(xmlString)
|
||||||
if (newDoc.firstElementChild &&
|
if (
|
||||||
newDoc.firstElementChild.namespaceURI !== NS.SVG) {
|
newDoc.firstElementChild &&
|
||||||
|
newDoc.firstElementChild.namespaceURI !== NS.SVG
|
||||||
|
) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,20 +400,29 @@ export const setSvgString = function (xmlString, preventUndo) {
|
|||||||
|
|
||||||
svgCanvas.getSvgContent().remove()
|
svgCanvas.getSvgContent().remove()
|
||||||
const oldzoom = svgCanvas.getSvgContent()
|
const oldzoom = svgCanvas.getSvgContent()
|
||||||
batchCmd.addSubCommand(new RemoveElementCommand(oldzoom, nextSibling, svgCanvas.getSvgRoot()))
|
batchCmd.addSubCommand(
|
||||||
|
new RemoveElementCommand(oldzoom, nextSibling, svgCanvas.getSvgRoot())
|
||||||
|
)
|
||||||
|
|
||||||
// set new svg document
|
// set new svg document
|
||||||
// If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode()
|
// If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode()
|
||||||
if (svgCanvas.getDOMDocument().adoptNode) {
|
if (svgCanvas.getDOMDocument().adoptNode) {
|
||||||
svgCanvas.setSvgContent(svgCanvas.getDOMDocument().adoptNode(newDoc.documentElement))
|
svgCanvas.setSvgContent(
|
||||||
|
svgCanvas.getDOMDocument().adoptNode(newDoc.documentElement)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
svgCanvas.setSvgContent(svgCanvas.getDOMDocument().importNode(newDoc.documentElement, true))
|
svgCanvas.setSvgContent(
|
||||||
|
svgCanvas.getDOMDocument().importNode(newDoc.documentElement, true)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
svgCanvas.getSvgRoot().append(svgCanvas.getSvgContent())
|
svgCanvas.getSvgRoot().append(svgCanvas.getSvgContent())
|
||||||
const content = svgCanvas.getSvgContent()
|
const content = svgCanvas.getSvgContent()
|
||||||
|
|
||||||
svgCanvas.current_drawing_ = new draw.Drawing(svgCanvas.getSvgContent(), svgCanvas.getIdPrefix())
|
svgCanvas.current_drawing_ = new draw.Drawing(
|
||||||
|
svgCanvas.getSvgContent(),
|
||||||
|
svgCanvas.getIdPrefix()
|
||||||
|
)
|
||||||
|
|
||||||
// retrieve or set the nonce
|
// retrieve or set the nonce
|
||||||
const nonce = svgCanvas.getCurrentDrawing().getNonce()
|
const nonce = svgCanvas.getCurrentDrawing().getNonce()
|
||||||
@@ -342,7 +434,7 @@ export const setSvgString = function (xmlString, preventUndo) {
|
|||||||
|
|
||||||
// change image href vals if possible
|
// change image href vals if possible
|
||||||
const elements = content.querySelectorAll('image')
|
const elements = content.querySelectorAll('image')
|
||||||
Array.prototype.forEach.call(elements, function (image) {
|
Array.prototype.forEach.call(elements, (image) => {
|
||||||
preventClickDefault(image)
|
preventClickDefault(image)
|
||||||
const val = svgCanvas.getHref(image)
|
const val = svgCanvas.getHref(image)
|
||||||
if (val) {
|
if (val) {
|
||||||
@@ -388,9 +480,11 @@ export const setSvgString = function (xmlString, preventUndo) {
|
|||||||
|
|
||||||
// Wrap child SVGs in group elements
|
// Wrap child SVGs in group elements
|
||||||
const svgElements = content.querySelectorAll('svg')
|
const svgElements = content.querySelectorAll('svg')
|
||||||
Array.prototype.forEach.call(svgElements, function (element) {
|
Array.prototype.forEach.call(svgElements, (element) => {
|
||||||
// Skip if it's in a <defs>
|
// Skip if it's in a <defs>
|
||||||
if (getClosest(element.parentNode, 'defs')) { return }
|
if (getClosest(element.parentNode, 'defs')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
svgCanvas.uniquifyElems(element)
|
svgCanvas.uniquifyElems(element)
|
||||||
|
|
||||||
@@ -407,8 +501,10 @@ export const setSvgString = function (xmlString, preventUndo) {
|
|||||||
// For Firefox: Put all paint elems in defs
|
// For Firefox: Put all paint elems in defs
|
||||||
if (isGecko()) {
|
if (isGecko()) {
|
||||||
const svgDefs = findDefs()
|
const svgDefs = findDefs()
|
||||||
const findElems = content.querySelectorAll('linearGradient, radialGradient, pattern')
|
const findElems = content.querySelectorAll(
|
||||||
Array.prototype.forEach.call(findElems, function (ele) {
|
'linearGradient, radialGradient, pattern'
|
||||||
|
)
|
||||||
|
Array.prototype.forEach.call(findElems, (ele) => {
|
||||||
svgDefs.appendChild(ele)
|
svgDefs.appendChild(ele)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -435,7 +531,7 @@ export const setSvgString = function (xmlString, preventUndo) {
|
|||||||
attrs.height = vb[3]
|
attrs.height = vb[3]
|
||||||
// handle content that doesn't have a viewBox
|
// handle content that doesn't have a viewBox
|
||||||
} else {
|
} else {
|
||||||
['width', 'height'].forEach(function (dim) {
|
;['width', 'height'].forEach((dim) => {
|
||||||
// Set to 100 if not given
|
// Set to 100 if not given
|
||||||
const val = content.getAttribute(dim) || '100%'
|
const val = content.getAttribute(dim) || '100%'
|
||||||
if (String(val).substr(-1) === '%') {
|
if (String(val).substr(-1) === '%') {
|
||||||
@@ -452,10 +548,12 @@ export const setSvgString = function (xmlString, preventUndo) {
|
|||||||
|
|
||||||
// Give ID for any visible layer children missing one
|
// Give ID for any visible layer children missing one
|
||||||
const chiElems = content.children
|
const chiElems = content.children
|
||||||
Array.prototype.forEach.call(chiElems, function (chiElem) {
|
Array.prototype.forEach.call(chiElems, (chiElem) => {
|
||||||
const visElems = chiElem.querySelectorAll(svgCanvas.getVisElems())
|
const visElems = chiElem.querySelectorAll(svgCanvas.getVisElems())
|
||||||
Array.prototype.forEach.call(visElems, function (elem) {
|
Array.prototype.forEach.call(visElems, (elem) => {
|
||||||
if (!elem.id) { elem.id = svgCanvas.getNextId() }
|
if (!elem.id) {
|
||||||
|
elem.id = svgCanvas.getNextId()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -468,8 +566,12 @@ export const setSvgString = function (xmlString, preventUndo) {
|
|||||||
|
|
||||||
// Just in case negative numbers are given or
|
// Just in case negative numbers are given or
|
||||||
// result from the percs calculation
|
// result from the percs calculation
|
||||||
if (attrs.width <= 0) { attrs.width = 100 }
|
if (attrs.width <= 0) {
|
||||||
if (attrs.height <= 0) { attrs.height = 100 }
|
attrs.width = 100
|
||||||
|
}
|
||||||
|
if (attrs.height <= 0) {
|
||||||
|
attrs.height = 100
|
||||||
|
}
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(attrs)) {
|
for (const [key, value] of Object.entries(attrs)) {
|
||||||
content.setAttribute(key, value)
|
content.setAttribute(key, value)
|
||||||
@@ -482,7 +584,9 @@ export const setSvgString = function (xmlString, preventUndo) {
|
|||||||
const width = content.getAttribute('width')
|
const width = content.getAttribute('width')
|
||||||
const height = content.getAttribute('height')
|
const height = content.getAttribute('height')
|
||||||
const changes = { width: width, height: height }
|
const changes = { width: width, height: height }
|
||||||
batchCmd.addSubCommand(new ChangeElementCommand(svgCanvas.getSvgRoot(), changes))
|
batchCmd.addSubCommand(
|
||||||
|
new ChangeElementCommand(svgCanvas.getSvgRoot(), changes)
|
||||||
|
)
|
||||||
|
|
||||||
// reset zoom
|
// reset zoom
|
||||||
svgCanvas.setZoom(1)
|
svgCanvas.setZoom(1)
|
||||||
@@ -515,9 +619,11 @@ export const setSvgString = function (xmlString, preventUndo) {
|
|||||||
* arbitrary transform lists, but makes some assumptions about how the transform list
|
* arbitrary transform lists, but makes some assumptions about how the transform list
|
||||||
* was obtained
|
* was obtained
|
||||||
*/
|
*/
|
||||||
export const importSvgString = function (xmlString) {
|
const importSvgString = (xmlString) => {
|
||||||
const dataStorage = svgCanvas.getDataStorage()
|
const dataStorage = svgCanvas.getDataStorage()
|
||||||
let j; let ts; let useEl
|
let j
|
||||||
|
let ts
|
||||||
|
let useEl
|
||||||
try {
|
try {
|
||||||
// Get unique ID
|
// Get unique ID
|
||||||
const uid = encode64(xmlString.length + xmlString).substr(0, 32)
|
const uid = encode64(xmlString.length + xmlString).substr(0, 32)
|
||||||
@@ -564,7 +670,10 @@ export const importSvgString = function (xmlString) {
|
|||||||
canvash = Number(svgCanvas.getSvgContent().getAttribute('height'))
|
canvash = Number(svgCanvas.getSvgContent().getAttribute('height'))
|
||||||
// imported content should be 1/3 of the canvas on its largest dimension
|
// imported content should be 1/3 of the canvas on its largest dimension
|
||||||
|
|
||||||
ts = innerh > innerw ? 'scale(' + (canvash / 3) / vb[3] + ')' : 'scale(' + (canvash / 3) / vb[2] + ')'
|
ts =
|
||||||
|
innerh > innerw
|
||||||
|
? 'scale(' + canvash / 3 / vb[3] + ')'
|
||||||
|
: 'scale(' + canvash / 3 / vb[2] + ')'
|
||||||
|
|
||||||
// Hack to make recalculateDimensions understand how to scale
|
// Hack to make recalculateDimensions understand how to scale
|
||||||
ts = 'translate(0) ' + ts + ' translate(0)'
|
ts = 'translate(0) ' + ts + ' translate(0)'
|
||||||
@@ -576,8 +685,10 @@ export const importSvgString = function (xmlString) {
|
|||||||
// Move all gradients into root for Firefox, workaround for this bug:
|
// Move all gradients into root for Firefox, workaround for this bug:
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=353575
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=353575
|
||||||
// TODO: Make this properly undo-able.
|
// TODO: Make this properly undo-able.
|
||||||
const elements = svg.querySelectorAll('linearGradient, radialGradient, pattern')
|
const elements = svg.querySelectorAll(
|
||||||
Array.prototype.forEach.call(elements, function (el) {
|
'linearGradient, radialGradient, pattern'
|
||||||
|
)
|
||||||
|
Array.prototype.forEach.call(elements, (el) => {
|
||||||
defs.appendChild(el)
|
defs.appendChild(el)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -587,7 +698,8 @@ export const importSvgString = function (xmlString) {
|
|||||||
symbol.append(first)
|
symbol.append(first)
|
||||||
}
|
}
|
||||||
const attrs = svg.attributes
|
const attrs = svg.attributes
|
||||||
for (const attr of attrs) { // Ok for `NamedNodeMap`
|
for (const attr of attrs) {
|
||||||
|
// Ok for `NamedNodeMap`
|
||||||
symbol.setAttribute(attr.nodeName, attr.value)
|
symbol.setAttribute(attr.nodeName, attr.value)
|
||||||
}
|
}
|
||||||
symbol.id = svgCanvas.getNextId()
|
symbol.id = svgCanvas.getNextId()
|
||||||
@@ -604,9 +716,11 @@ export const importSvgString = function (xmlString) {
|
|||||||
|
|
||||||
useEl = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'use')
|
useEl = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'use')
|
||||||
useEl.id = svgCanvas.getNextId()
|
useEl.id = svgCanvas.getNextId()
|
||||||
svgCanvas.setHref(useEl, '#' + symbol.id);
|
svgCanvas.setHref(useEl, '#' + symbol.id)
|
||||||
|
;(
|
||||||
(svgCanvas.getCurrentGroup() || svgCanvas.getCurrentDrawing().getCurrentLayer()).append(useEl)
|
svgCanvas.getCurrentGroup() ||
|
||||||
|
svgCanvas.getCurrentDrawing().getCurrentLayer()
|
||||||
|
).append(useEl)
|
||||||
batchCmd.addSubCommand(new InsertElementCommand(useEl))
|
batchCmd.addSubCommand(new InsertElementCommand(useEl))
|
||||||
svgCanvas.clearSelection()
|
svgCanvas.clearSelection()
|
||||||
|
|
||||||
@@ -642,12 +756,12 @@ export const importSvgString = function (xmlString) {
|
|||||||
* @param {string} src - The path/URL of the image
|
* @param {string} src - The path/URL of the image
|
||||||
* @returns {Promise<string|false>} Resolves to a Data URL (string|false)
|
* @returns {Promise<string|false>} Resolves to a Data URL (string|false)
|
||||||
*/
|
*/
|
||||||
export const embedImage = function (src) {
|
const embedImage = (src) => {
|
||||||
// Todo: Remove this Promise in favor of making an async/await `Image.load` utility
|
// Todo: Remove this Promise in favor of making an async/await `Image.load` utility
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise((resolve, reject) => {
|
||||||
// load in the image and once it's loaded, get the dimensions
|
// load in the image and once it's loaded, get the dimensions
|
||||||
const imgI = new Image()
|
const imgI = new Image()
|
||||||
imgI.addEventListener('load', (e) => {
|
imgI.addEventListener('load', e => {
|
||||||
// create a canvas the same size as the raster image
|
// create a canvas the same size as the raster image
|
||||||
const cvs = document.createElement('canvas')
|
const cvs = document.createElement('canvas')
|
||||||
cvs.width = e.currentTarget.width
|
cvs.width = e.currentTarget.width
|
||||||
@@ -665,8 +779,12 @@ export const embedImage = function (src) {
|
|||||||
svgCanvas.setGoodImage(src)
|
svgCanvas.setGoodImage(src)
|
||||||
resolve(svgCanvas.getEncodableImages(src))
|
resolve(svgCanvas.getEncodableImages(src))
|
||||||
})
|
})
|
||||||
imgI.addEventListener('error', (e) => {
|
imgI.addEventListener('error', e => {
|
||||||
reject(new Error(`error loading image: ${e.currentTarget.attributes.src.value}`))
|
reject(
|
||||||
|
new Error(
|
||||||
|
`error loading image: ${e.currentTarget.attributes.src.value}`
|
||||||
|
)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
imgI.setAttribute('src', src)
|
imgI.setAttribute('src', src)
|
||||||
})
|
})
|
||||||
@@ -682,7 +800,7 @@ export const embedImage = function (src) {
|
|||||||
* Codes only is useful for locale-independent detection.
|
* Codes only is useful for locale-independent detection.
|
||||||
* @returns {module:svgcanvas.IssuesAndCodes}
|
* @returns {module:svgcanvas.IssuesAndCodes}
|
||||||
*/
|
*/
|
||||||
function getIssues () {
|
const getIssues = () => {
|
||||||
const uiStrings = svgCanvas.getUIStrings()
|
const uiStrings = svgCanvas.getUIStrings()
|
||||||
// remove the selected outline before serializing
|
// remove the selected outline before serializing
|
||||||
svgCanvas.clearSelection()
|
svgCanvas.clearSelection()
|
||||||
@@ -693,15 +811,15 @@ function getIssues () {
|
|||||||
|
|
||||||
// Selector and notice
|
// Selector and notice
|
||||||
const issueList = {
|
const issueList = {
|
||||||
feGaussianBlur: uiStrings.exportNoBlur,
|
feGaussianBlur: uiStrings.NoBlur,
|
||||||
foreignObject: uiStrings.exportNoforeignObject,
|
foreignObject: uiStrings.NoforeignObject,
|
||||||
'[stroke-dasharray]': uiStrings.exportNoDashArray
|
'[stroke-dasharray]': uiStrings.NoDashArray
|
||||||
}
|
}
|
||||||
const content = svgCanvas.getSvgContent()
|
const content = svgCanvas.getSvgContent()
|
||||||
|
|
||||||
// Add font/text check if Canvas Text API is not implemented
|
// Add font/text check if Canvas Text API is not implemented
|
||||||
if (!('font' in document.querySelector('CANVAS').getContext('2d'))) {
|
if (!('font' in document.querySelector('CANVAS').getContext('2d'))) {
|
||||||
issueList.text = uiStrings.exportNoText
|
issueList.text = uiStrings.NoText
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [sel, descr] of Object.entries(issueList)) {
|
for (const [sel, descr] of Object.entries(issueList)) {
|
||||||
@@ -713,7 +831,7 @@ function getIssues () {
|
|||||||
return { issues, issueCodes }
|
return { issues, issueCodes }
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @typedef {PlainObject} module:svgcanvas.ImageExportedResults
|
* @typedef {PlainObject} module:svgcanvas.ImageedResults
|
||||||
* @property {string} datauri Contents as a Data URL
|
* @property {string} datauri Contents as a Data URL
|
||||||
* @property {string} bloburl May be the empty string
|
* @property {string} bloburl May be the empty string
|
||||||
* @property {string} svg The SVG contents as a string
|
* @property {string} svg The SVG contents as a string
|
||||||
@@ -722,39 +840,40 @@ function getIssues () {
|
|||||||
* @property {"PNG"|"JPEG"|"BMP"|"WEBP"|"ICO"} type The chosen image type
|
* @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 {"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 {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
|
* @property {string} WindowName A convenience for passing along a `window.name` to target a window on which the could be added
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a PNG (or JPG, BMP, WEBP) Data URL based on the current image,
|
* Generates a PNG (or JPG, BMP, WEBP) Data URL based on the current image,
|
||||||
* then calls "exported" with an object including the string, image
|
* then calls "ed" with an object including the string, image
|
||||||
* information, and any issues found.
|
* information, and any issues found.
|
||||||
* @function module:svgcanvas.SvgCanvas#rasterExport
|
* @function module:svgcanvas.SvgCanvas#raster
|
||||||
* @param {"PNG"|"JPEG"|"BMP"|"WEBP"|"ICO"} [imgType="PNG"]
|
* @param {"PNG"|"JPEG"|"BMP"|"WEBP"|"ICO"} [imgType="PNG"]
|
||||||
* @param {Float} [quality] Between 0 and 1
|
* @param {Float} [quality] Between 0 and 1
|
||||||
* @param {string} [exportWindowName]
|
* @param {string} [WindowName]
|
||||||
* @param {PlainObject} [opts]
|
* @param {PlainObject} [opts]
|
||||||
* @param {boolean} [opts.avoidEvent]
|
* @param {boolean} [opts.avoidEvent]
|
||||||
* @fires module:svgcanvas.SvgCanvas#event:exported
|
* @fires module:svgcanvas.SvgCanvas#event:ed
|
||||||
* @todo Confirm/fix ICO type
|
* @todo Confirm/fix ICO type
|
||||||
* @returns {Promise<module:svgcanvas.ImageExportedResults>} Resolves to {@link module:svgcanvas.ImageExportedResults}
|
* @returns {Promise<module:svgcanvas.ImageedResults>} Resolves to {@link module:svgcanvas.ImageedResults}
|
||||||
*/
|
*/
|
||||||
export const rasterExport = async function (imgType, quality, exportWindowName, opts = {}) {
|
const rasterExport = async (imgType, quality, WindowName, opts = {}) => {
|
||||||
const type = imgType === 'ICO' ? 'BMP' : (imgType || 'PNG')
|
const type = imgType === 'ICO' ? 'BMP' : imgType || 'PNG'
|
||||||
const mimeType = 'image/' + type.toLowerCase()
|
const mimeType = 'image/' + type.toLowerCase()
|
||||||
const { issues, issueCodes } = getIssues()
|
const { issues, issueCodes } = getIssues()
|
||||||
const svg = svgCanvas.svgCanvasToString()
|
const svg = svgCanvas.svgCanvasToString()
|
||||||
|
|
||||||
const iframe = document.createElement('iframe')
|
const iframe = document.createElement('iframe')
|
||||||
iframe.onload = function () {
|
iframe.onload = () => {
|
||||||
const iframedoc = iframe.contentDocument || iframe.contentWindow.document
|
const iframedoc = iframe.contentDocument || iframe.contentWindow.document
|
||||||
const ele = svgCanvas.getSvgContent()
|
const ele = svgCanvas.getSvgContent()
|
||||||
const cln = ele.cloneNode(true)
|
const cln = ele.cloneNode(true)
|
||||||
iframedoc.body.appendChild(cln)
|
iframedoc.body.appendChild(cln)
|
||||||
setTimeout(function () {
|
setTimeout(() => {
|
||||||
// eslint-disable-next-line promise/catch-or-return
|
// eslint-disable-next-line promise/catch-or-return
|
||||||
html2canvas(iframedoc.body, { useCORS: true, allowTaint: true }).then((canvas) => {
|
html2canvas(iframedoc.body, { useCORS: true, allowTaint: true }).then(
|
||||||
return new Promise((resolve) => {
|
canvas => {
|
||||||
|
return new Promise(resolve => {
|
||||||
const dataURLType = type.toLowerCase()
|
const dataURLType = type.toLowerCase()
|
||||||
const datauri = quality
|
const datauri = quality
|
||||||
? canvas.toDataURL('image/' + dataURLType, quality)
|
? canvas.toDataURL('image/' + dataURLType, quality)
|
||||||
@@ -762,7 +881,7 @@ export const rasterExport = async function (imgType, quality, exportWindowName,
|
|||||||
iframe.parentNode.removeChild(iframe)
|
iframe.parentNode.removeChild(iframe)
|
||||||
let bloburl
|
let bloburl
|
||||||
|
|
||||||
function done () {
|
const done = () => {
|
||||||
const obj = {
|
const obj = {
|
||||||
datauri,
|
datauri,
|
||||||
bloburl,
|
bloburl,
|
||||||
@@ -772,24 +891,29 @@ export const rasterExport = async function (imgType, quality, exportWindowName,
|
|||||||
type: imgType,
|
type: imgType,
|
||||||
mimeType,
|
mimeType,
|
||||||
quality,
|
quality,
|
||||||
exportWindowName
|
WindowName
|
||||||
}
|
}
|
||||||
if (!opts.avoidEvent) {
|
if (!opts.avoidEvent) {
|
||||||
svgCanvas.call('exported', obj)
|
svgCanvas.call('ed', obj)
|
||||||
}
|
}
|
||||||
resolve(obj)
|
resolve(obj)
|
||||||
}
|
}
|
||||||
if (canvas.toBlob) {
|
if (canvas.toBlob) {
|
||||||
canvas.toBlob((blob) => {
|
canvas.toBlob(
|
||||||
|
blob => {
|
||||||
bloburl = createObjectURL(blob)
|
bloburl = createObjectURL(blob)
|
||||||
done()
|
done()
|
||||||
}, mimeType, quality)
|
},
|
||||||
|
mimeType,
|
||||||
|
quality
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bloburl = dataURLToObjectURL(datauri)
|
bloburl = dataURLToObjectURL(datauri)
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
document.body.appendChild(iframe)
|
document.body.appendChild(iframe)
|
||||||
@@ -797,10 +921,10 @@ export const rasterExport = async function (imgType, quality, exportWindowName,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {void|"save"|"arraybuffer"|"blob"|"datauristring"|"dataurlstring"|"dataurlnewwindow"|"datauri"|"dataurl"} external:jsPDF.OutputType
|
* @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
|
* @todo Newer version to add also allows these `outputType` values "bloburi"|"bloburl" which return strings, so document here and for `outputType` of `module:svgcanvas.PDFedResults` below if added
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @typedef {PlainObject} module:svgcanvas.PDFExportedResults
|
* @typedef {PlainObject} module:svgcanvas.PDFedResults
|
||||||
* @property {string} svg The SVG PDF output
|
* @property {string} svg The SVG PDF output
|
||||||
* @property {string|ArrayBuffer|Blob|window} output The output based on the `outputType`;
|
* @property {string|ArrayBuffer|Blob|window} output The output based on the `outputType`;
|
||||||
* if `undefined`, "datauristring", "dataurlstring", "datauri",
|
* if `undefined`, "datauristring", "dataurlstring", "datauri",
|
||||||
@@ -815,34 +939,35 @@ export const rasterExport = async function (imgType, quality, exportWindowName,
|
|||||||
* @property {external:jsPDF.OutputType} outputType
|
* @property {external:jsPDF.OutputType} outputType
|
||||||
* @property {string[]} issues The human-readable localization messages of corresponding `issueCodes`
|
* @property {string[]} issues The human-readable localization messages of corresponding `issueCodes`
|
||||||
* @property {module:svgcanvas.IssueCode[]} issueCodes
|
* @property {module:svgcanvas.IssueCode[]} issueCodes
|
||||||
* @property {string} exportWindowName
|
* @property {string} WindowName
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a PDF based on the current image, then calls "exportedPDF" with
|
* Generates a PDF based on the current image, then calls "edPDF" with
|
||||||
* an object including the string, the data URL, and any issues found.
|
* an object including the string, the data URL, and any issues found.
|
||||||
* @function module:svgcanvas.SvgCanvas#exportPDF
|
* @function module:svgcanvas.SvgCanvas#PDF
|
||||||
* @param {string} [exportWindowName] Will also be used for the download file name here
|
* @param {string} [WindowName] Will also be used for the download file name here
|
||||||
* @param {external:jsPDF.OutputType} [outputType="dataurlstring"]
|
* @param {external:jsPDF.OutputType} [outputType="dataurlstring"]
|
||||||
* @fires module:svgcanvas.SvgCanvas#event:exportedPDF
|
* @fires module:svgcanvas.SvgCanvas#event:edPDF
|
||||||
* @returns {Promise<module:svgcanvas.PDFExportedResults>} Resolves to {@link module:svgcanvas.PDFExportedResults}
|
* @returns {Promise<module:svgcanvas.PDFedResults>} Resolves to {@link module:svgcanvas.PDFedResults}
|
||||||
*/
|
*/
|
||||||
export const exportPDF = async (
|
const exportPDF = async (
|
||||||
exportWindowName,
|
WindowName,
|
||||||
outputType = isChrome() ? 'save' : undefined
|
outputType = isChrome() ? 'save' : undefined
|
||||||
) => {
|
) => {
|
||||||
const res = svgCanvas.getResolution()
|
const res = svgCanvas.getResolution()
|
||||||
const orientation = res.w > res.h ? 'landscape' : 'portrait'
|
const orientation = res.w > res.h ? 'landscape' : 'portrait'
|
||||||
const unit = 'pt' // curConfig.baseUnit; // We could use baseUnit, but that is presumably not intended for export purposes
|
const unit = 'pt' // curConfig.baseUnit; // We could use baseUnit, but that is presumably not intended for purposes
|
||||||
const iframe = document.createElement('iframe')
|
const iframe = document.createElement('iframe')
|
||||||
iframe.onload = function () {
|
iframe.onload = () => {
|
||||||
const iframedoc = iframe.contentDocument || iframe.contentWindow.document
|
const iframedoc = iframe.contentDocument || iframe.contentWindow.document
|
||||||
const ele = svgCanvas.getSvgContent()
|
const ele = svgCanvas.getSvgContent()
|
||||||
const cln = ele.cloneNode(true)
|
const cln = ele.cloneNode(true)
|
||||||
iframedoc.body.appendChild(cln)
|
iframedoc.body.appendChild(cln)
|
||||||
setTimeout(function () {
|
setTimeout(() => {
|
||||||
// eslint-disable-next-line promise/catch-or-return
|
// eslint-disable-next-line promise/catch-or-return
|
||||||
html2canvas(iframedoc.body, { useCORS: true, allowTaint: true }).then((canvas) => {
|
html2canvas(iframedoc.body, { useCORS: true, allowTaint: true }).then(
|
||||||
|
canvas => {
|
||||||
const imgData = canvas.toDataURL('image/png')
|
const imgData = canvas.toDataURL('image/png')
|
||||||
const doc = new JsPDF({
|
const doc = new JsPDF({
|
||||||
orientation: orientation,
|
orientation: orientation,
|
||||||
@@ -857,11 +982,15 @@ export const exportPDF = async (
|
|||||||
iframe.parentNode.removeChild(iframe)
|
iframe.parentNode.removeChild(iframe)
|
||||||
const { issues, issueCodes } = getIssues()
|
const { issues, issueCodes } = getIssues()
|
||||||
outputType = outputType || 'dataurlstring'
|
outputType = outputType || 'dataurlstring'
|
||||||
const obj = { issues, issueCodes, exportWindowName, outputType }
|
const obj = { issues, issueCodes, WindowName, outputType }
|
||||||
obj.output = doc.output(outputType, outputType === 'save' ? (exportWindowName || 'svg.pdf') : undefined)
|
obj.output = doc.output(
|
||||||
svgCanvas.call('exportedPDF', obj)
|
outputType,
|
||||||
|
outputType === 'save' ? WindowName || 'svg.pdf' : undefined
|
||||||
|
)
|
||||||
|
svgCanvas.call('edPDF', obj)
|
||||||
return obj
|
return obj
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
document.body.appendChild(iframe)
|
document.body.appendChild(iframe)
|
||||||
@@ -872,7 +1001,7 @@ export const exportPDF = async (
|
|||||||
* @param {Element} g - The parent element of the tree to give unique IDs
|
* @param {Element} g - The parent element of the tree to give unique IDs
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const uniquifyElemsMethod = function (g) {
|
const uniquifyElemsMethod = (g) => {
|
||||||
const ids = {}
|
const ids = {}
|
||||||
// TODO: Handle markers and connectors. These are not yet re-identified properly
|
// TODO: Handle markers and connectors. These are not yet re-identified properly
|
||||||
// as their referring elements do not get remapped.
|
// as their referring elements do not get remapped.
|
||||||
@@ -882,9 +1011,17 @@ export const uniquifyElemsMethod = function (g) {
|
|||||||
//
|
//
|
||||||
// Problem #1: if svg_1 gets renamed, we do not update the polyline's se:connector attribute
|
// Problem #1: if svg_1 gets renamed, we do not update the polyline's se:connector attribute
|
||||||
// Problem #2: if the polyline svg_7 gets renamed, we do not update the marker id nor the polyline's marker-end attribute
|
// Problem #2: if the polyline svg_7 gets renamed, we do not update the marker id nor the polyline's marker-end attribute
|
||||||
const refElems = ['filter', 'linearGradient', 'pattern', 'radialGradient', 'symbol', 'textPath', 'use']
|
const refElems = [
|
||||||
|
'filter',
|
||||||
|
'linearGradient',
|
||||||
|
'pattern',
|
||||||
|
'radialGradient',
|
||||||
|
'symbol',
|
||||||
|
'textPath',
|
||||||
|
'use'
|
||||||
|
]
|
||||||
|
|
||||||
walkTree(g, function (n) {
|
walkTree(g, (n) => {
|
||||||
// if it's an element node
|
// if it's an element node
|
||||||
if (n.nodeType === 1) {
|
if (n.nodeType === 1) {
|
||||||
// and the element has an ID
|
// and the element has an ID
|
||||||
@@ -899,7 +1036,7 @@ export const uniquifyElemsMethod = function (g) {
|
|||||||
|
|
||||||
// now search for all attributes on this element that might refer
|
// now search for all attributes on this element that might refer
|
||||||
// to other elements
|
// to other elements
|
||||||
svgCanvas.getrefAttrs().forEach(function (attr) {
|
svgCanvas.getrefAttrs().forEach((attr) => {
|
||||||
const attrnode = n.getAttributeNode(attr)
|
const attrnode = n.getAttributeNode(attr)
|
||||||
if (attrnode) {
|
if (attrnode) {
|
||||||
// the incoming file has been sanitized, so we should be able to safely just strip off the leading #
|
// the incoming file has been sanitized, so we should be able to safely just strip off the leading #
|
||||||
@@ -933,7 +1070,9 @@ export const uniquifyElemsMethod = function (g) {
|
|||||||
|
|
||||||
// in ids, we now have a map of ids, elements and attributes, let's re-identify
|
// in ids, we now have a map of ids, elements and attributes, let's re-identify
|
||||||
for (const oldid in ids) {
|
for (const oldid in ids) {
|
||||||
if (!oldid) { continue }
|
if (!oldid) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
const { elem } = ids[oldid]
|
const { elem } = ids[oldid]
|
||||||
if (elem) {
|
if (elem) {
|
||||||
const newid = svgCanvas.getNextId()
|
const newid = svgCanvas.getNextId()
|
||||||
@@ -966,7 +1105,7 @@ export const uniquifyElemsMethod = function (g) {
|
|||||||
* @param {Element} parent
|
* @param {Element} parent
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const setUseDataMethod = function (parent) {
|
const setUseDataMethod = (parent) => {
|
||||||
let elems = parent
|
let elems = parent
|
||||||
|
|
||||||
if (parent.tagName !== 'use') {
|
if (parent.tagName !== 'use') {
|
||||||
@@ -974,11 +1113,13 @@ export const setUseDataMethod = function (parent) {
|
|||||||
elems = elems.querySelectorAll('use')
|
elems = elems.querySelectorAll('use')
|
||||||
}
|
}
|
||||||
|
|
||||||
Array.prototype.forEach.call(elems, function (el, _) {
|
Array.prototype.forEach.call(elems, (el, _) => {
|
||||||
const dataStorage = svgCanvas.getDataStorage()
|
const dataStorage = svgCanvas.getDataStorage()
|
||||||
const id = svgCanvas.getHref(el).substr(1)
|
const id = svgCanvas.getHref(el).substr(1)
|
||||||
const refElem = svgCanvas.getElement(id)
|
const refElem = svgCanvas.getElement(id)
|
||||||
if (!refElem) { return }
|
if (!refElem) {
|
||||||
|
return
|
||||||
|
}
|
||||||
dataStorage.put(el, 'ref', refElem)
|
dataStorage.put(el, 'ref', refElem)
|
||||||
if (refElem.tagName === 'symbol' || refElem.tagName === 'svg') {
|
if (refElem.tagName === 'symbol' || refElem.tagName === 'svg') {
|
||||||
dataStorage.put(el, 'symbol', refElem)
|
dataStorage.put(el, 'symbol', refElem)
|
||||||
@@ -993,21 +1134,31 @@ export const setUseDataMethod = function (parent) {
|
|||||||
* @function module:svgcanvas.SvgCanvas#removeUnusedDefElems
|
* @function module:svgcanvas.SvgCanvas#removeUnusedDefElems
|
||||||
* @returns {Integer} The number of elements that were removed
|
* @returns {Integer} The number of elements that were removed
|
||||||
*/
|
*/
|
||||||
export const removeUnusedDefElemsMethod = function () {
|
const removeUnusedDefElemsMethod = () => {
|
||||||
const defs = svgCanvas.getSvgContent().getElementsByTagNameNS(NS.SVG, 'defs')
|
const defs = svgCanvas.getSvgContent().getElementsByTagNameNS(NS.SVG, 'defs')
|
||||||
if (!defs || !defs.length) { return 0 }
|
if (!defs || !defs.length) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// if (!defs.firstChild) { return; }
|
// if (!defs.firstChild) { return; }
|
||||||
|
|
||||||
const defelemUses = []
|
const defelemUses = []
|
||||||
let numRemoved = 0
|
let numRemoved = 0
|
||||||
const attrs = ['fill', 'stroke', 'filter', 'marker-start', 'marker-mid', 'marker-end']
|
const attrs = [
|
||||||
|
'fill',
|
||||||
|
'stroke',
|
||||||
|
'filter',
|
||||||
|
'marker-start',
|
||||||
|
'marker-mid',
|
||||||
|
'marker-end'
|
||||||
|
]
|
||||||
const alen = attrs.length
|
const alen = attrs.length
|
||||||
|
|
||||||
const allEls = svgCanvas.getSvgContent().getElementsByTagNameNS(NS.SVG, '*')
|
const allEls = svgCanvas.getSvgContent().getElementsByTagNameNS(NS.SVG, '*')
|
||||||
const allLen = allEls.length
|
const allLen = allEls.length
|
||||||
|
|
||||||
let i; let j
|
let i
|
||||||
|
let j
|
||||||
for (i = 0; i < allLen; i++) {
|
for (i = 0; i < allLen; i++) {
|
||||||
const el = allEls[i]
|
const el = allEls[i]
|
||||||
for (j = 0; j < alen; j++) {
|
for (j = 0; j < alen; j++) {
|
||||||
@@ -1024,8 +1175,10 @@ export const removeUnusedDefElemsMethod = function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Array.prototype.forEach.call(defs, function (def, i) {
|
Array.prototype.forEach.call(defs, (def, i) => {
|
||||||
const defelems = def.querySelectorAll('linearGradient, radialGradient, filter, marker, svg, symbol')
|
const defelems = def.querySelectorAll(
|
||||||
|
'linearGradient, radialGradient, filter, marker, svg, symbol'
|
||||||
|
)
|
||||||
i = defelems.length
|
i = defelems.length
|
||||||
while (i--) {
|
while (i--) {
|
||||||
const defelem = defelems[i]
|
const defelem = defelems[i]
|
||||||
@@ -1047,26 +1200,43 @@ export const removeUnusedDefElemsMethod = function () {
|
|||||||
* @param {Element} elem
|
* @param {Element} elem
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const convertGradientsMethod = function (elem) {
|
const convertGradientsMethod = (elem) => {
|
||||||
let elems = elem.querySelectorAll('linearGradient, radialGradient')
|
let elems = elem.querySelectorAll('linearGradient, radialGradient')
|
||||||
if (!elems.length && isWebkit()) {
|
if (!elems.length && isWebkit()) {
|
||||||
// Bug in webkit prevents regular *Gradient selector search
|
// Bug in webkit prevents regular *Gradient selector search
|
||||||
elems = Array.prototype.filter.call(elem.querySelectorAll('*'), function (curThis) {
|
elems = Array.prototype.filter.call(elem.querySelectorAll('*'), (
|
||||||
return (curThis.tagName.includes('Gradient'))
|
curThis
|
||||||
|
) => {
|
||||||
|
return curThis.tagName.includes('Gradient')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Array.prototype.forEach.call(elems, function (grad) {
|
Array.prototype.forEach.call(elems, (grad) => {
|
||||||
if (grad.getAttribute('gradientUnits') === 'userSpaceOnUse') {
|
if (grad.getAttribute('gradientUnits') === 'userSpaceOnUse') {
|
||||||
const svgContent = svgCanvas.getSvgContent()
|
const svgContent = svgCanvas.getSvgContent()
|
||||||
// TODO: Support more than one element with this ref by duplicating parent grad
|
// TODO: Support more than one element with this ref by duplicating parent grad
|
||||||
let fillStrokeElems = svgContent.querySelectorAll('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]')
|
let fillStrokeElems = svgContent.querySelectorAll(
|
||||||
|
'[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]'
|
||||||
|
)
|
||||||
if (!fillStrokeElems.length) {
|
if (!fillStrokeElems.length) {
|
||||||
const tmpFillStrokeElems = svgContent.querySelectorAll('[*|href="#' + grad.id + '"]')
|
const tmpFillStrokeElems = svgContent.querySelectorAll(
|
||||||
|
'[*|href="#' + grad.id + '"]'
|
||||||
|
)
|
||||||
if (!tmpFillStrokeElems.length) {
|
if (!tmpFillStrokeElems.length) {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
if ((tmpFillStrokeElems[0].tagName === 'linearGradient' || tmpFillStrokeElems[0].tagName === 'radialGradient') && tmpFillStrokeElems[0].getAttribute('gradientUnits') === 'userSpaceOnUse') {
|
if (
|
||||||
fillStrokeElems = svgContent.querySelectorAll('[fill="url(#' + tmpFillStrokeElems[0].id + ')"],[stroke="url(#' + tmpFillStrokeElems[0].id + ')"]')
|
(tmpFillStrokeElems[0].tagName === 'linearGradient' ||
|
||||||
|
tmpFillStrokeElems[0].tagName === 'radialGradient') &&
|
||||||
|
tmpFillStrokeElems[0].getAttribute('gradientUnits') ===
|
||||||
|
'userSpaceOnUse'
|
||||||
|
) {
|
||||||
|
fillStrokeElems = svgContent.querySelectorAll(
|
||||||
|
'[fill="url(#' +
|
||||||
|
tmpFillStrokeElems[0].id +
|
||||||
|
')"],[stroke="url(#' +
|
||||||
|
tmpFillStrokeElems[0].id +
|
||||||
|
')"]'
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1077,7 +1247,9 @@ export const convertGradientsMethod = function (elem) {
|
|||||||
|
|
||||||
// This will occur if the element is inside a <defs> or a <symbol>,
|
// This will occur if the element is inside a <defs> or a <symbol>,
|
||||||
// in which we shouldn't need to convert anyway.
|
// in which we shouldn't need to convert anyway.
|
||||||
if (!bb) { return }
|
if (!bb) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if (grad.tagName === 'linearGradient') {
|
if (grad.tagName === 'linearGradient') {
|
||||||
const gCoords = {
|
const gCoords = {
|
||||||
x1: grad.getAttribute('x1'),
|
x1: grad.getAttribute('x1'),
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user