* feat(svgcanvas): Trigger 'changed' event on text attribute modifications This update adds a call to the 'changed' event for various text attribute methods, ensuring that changes to text elements are properly tracked and reflected in the SVG canvas. The methods updated include setBold, setItalic, setTextAnchor, setLetterSpacing, setWordSpacing, setTextLength, setLengthAdjust, setFontFamily, setFontColor, and setFontSize. * refactor(svgcanvas): Simplify text attribute methods and optimize 'changed' event emission This update introduces helper functions to streamline the handling of selected text elements and their attribute changes. The methods setBold, setItalic, setTextAnchor, setLetterSpacing, setWordSpacing, and setTextLength now utilize these helpers to filter and notify only modified text elements, improving performance and clarity in event emissions.
1200 lines
39 KiB
JavaScript
1200 lines
39 KiB
JavaScript
/**
|
|
* @module elem-get-set get and set methods.
|
|
* @license MIT
|
|
* @copyright 2011 Jeff Schiller
|
|
*/
|
|
|
|
import Paint from './paint.js'
|
|
import { NS } from './namespaces.js'
|
|
import {
|
|
getVisibleElements, getStrokedBBoxDefaultVisible, findDefs,
|
|
walkTree, getHref, setHref, getElement
|
|
} from './utilities.js'
|
|
import {
|
|
convertToNum
|
|
} from './units.js'
|
|
import { getParents } from '../common/util.js'
|
|
|
|
let svgCanvas = null
|
|
|
|
/**
|
|
* @function module:elem-get-set.init
|
|
* @param {module:elem-get-set.elemContext} elemContext
|
|
* @returns {void}
|
|
*/
|
|
export const init = (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
|
|
* @returns {DimensionsAndZoom} The current dimensions and zoom level in an object
|
|
*/
|
|
const getResolutionMethod = () => {
|
|
const zoom = svgCanvas.getZoom()
|
|
const w = svgCanvas.getSvgContent().getAttribute('width') / zoom
|
|
const h = svgCanvas.getSvgContent().getAttribute('height') / zoom
|
|
|
|
return {
|
|
w,
|
|
h,
|
|
zoom
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @function module:elem-get-set.SvgCanvas#getTitle
|
|
* @param {Element} [elem]
|
|
* @returns {string|void} the current group/SVG's title contents or
|
|
* `undefined` if no element is passed nd there are no selected elements.
|
|
*/
|
|
const getTitleMethod = (elem) => {
|
|
const selectedElements = svgCanvas.getSelectedElements()
|
|
const dataStorage = svgCanvas.getDataStorage()
|
|
elem = elem || selectedElements[0]
|
|
if (!elem) { return undefined }
|
|
if (dataStorage.has(elem, 'gsvg')) {
|
|
elem = dataStorage.get(elem, 'gsvg')
|
|
} else if (dataStorage.has(elem, 'symbol')) {
|
|
elem = dataStorage.get(elem, 'symbol')
|
|
}
|
|
const childs = elem.childNodes
|
|
for (const child of childs) {
|
|
if (child.nodeName === 'title') {
|
|
return child.textContent
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
/**
|
|
* Sets the group/SVG's title content.
|
|
* @function module:elem-get-set.SvgCanvas#setGroupTitle
|
|
* @param {string} val
|
|
* @todo Combine this with `setDocumentTitle`
|
|
* @returns {void}
|
|
*/
|
|
const setGroupTitleMethod = (val) => {
|
|
const {
|
|
InsertElementCommand, RemoveElementCommand,
|
|
ChangeElementCommand, BatchCommand
|
|
} = svgCanvas.history
|
|
const selectedElements = svgCanvas.getSelectedElements()
|
|
const dataStorage = svgCanvas.getDataStorage()
|
|
let elem = selectedElements[0]
|
|
if (!elem) { return }
|
|
if (dataStorage.has(elem, 'gsvg')) {
|
|
elem = dataStorage.get(elem, 'gsvg')
|
|
} else if (dataStorage.has(elem, 'symbol')) {
|
|
elem = dataStorage.get(elem, 'symbol')
|
|
}
|
|
if (!elem) { return }
|
|
|
|
const batchCmd = new BatchCommand('Set Label')
|
|
|
|
let title = null
|
|
for (const child of elem.childNodes) {
|
|
if (child.nodeName === 'title') {
|
|
title = child
|
|
break
|
|
}
|
|
}
|
|
|
|
if (val.length === 0) {
|
|
if (!title) { return }
|
|
// Remove title element
|
|
const { nextSibling } = title
|
|
title.remove()
|
|
batchCmd.addSubCommand(new RemoveElementCommand(title, nextSibling, elem))
|
|
} else if (title) {
|
|
// Change title contents
|
|
const oldText = title.textContent
|
|
if (oldText === val) { return }
|
|
title.textContent = val
|
|
batchCmd.addSubCommand(new ChangeElementCommand(title, { '#text': oldText }))
|
|
} else {
|
|
// Add title element
|
|
title = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'title')
|
|
title.textContent = val
|
|
elem.insertBefore(title, elem.firstChild)
|
|
batchCmd.addSubCommand(new InsertElementCommand(title))
|
|
}
|
|
|
|
if (!batchCmd.isEmpty()) {
|
|
svgCanvas.addCommandToHistory(batchCmd)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds/updates a title element for the document with the given name.
|
|
* This is an undoable action.
|
|
* @function module:elem-get-set.SvgCanvas#setDocumentTitle
|
|
* @param {string} newTitle - String with the new title
|
|
* @returns {void}
|
|
*/
|
|
const setDocumentTitleMethod = (newTitle) => {
|
|
const {
|
|
InsertElementCommand, RemoveElementCommand,
|
|
ChangeElementCommand, BatchCommand
|
|
} = svgCanvas.history
|
|
const svgContent = svgCanvas.getSvgContent()
|
|
|
|
const batchCmd = new BatchCommand('Change Image Title')
|
|
|
|
/** @type {Element|null} */
|
|
let docTitle = null
|
|
for (const child of svgContent.childNodes) {
|
|
if (child.nodeName === 'title') {
|
|
docTitle = child
|
|
break
|
|
}
|
|
}
|
|
|
|
if (!docTitle) {
|
|
if (!newTitle.length) { return }
|
|
docTitle = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'title')
|
|
docTitle.textContent = newTitle
|
|
svgContent.insertBefore(docTitle, svgContent.firstChild)
|
|
batchCmd.addSubCommand(new InsertElementCommand(docTitle))
|
|
} else if (newTitle.length) {
|
|
const oldTitle = docTitle.textContent
|
|
if (oldTitle === newTitle) { return }
|
|
docTitle.textContent = newTitle
|
|
batchCmd.addSubCommand(new ChangeElementCommand(docTitle, { '#text': oldTitle }))
|
|
} else {
|
|
// No title given, so element is not necessary
|
|
const { nextSibling } = docTitle
|
|
docTitle.remove()
|
|
batchCmd.addSubCommand(new RemoveElementCommand(docTitle, nextSibling, svgContent))
|
|
}
|
|
|
|
if (!batchCmd.isEmpty()) {
|
|
svgCanvas.addCommandToHistory(batchCmd)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Changes the document's dimensions to the given size.
|
|
* @function module:elem-get-set.SvgCanvas#setResolution
|
|
* @param {Float|"fit"} x - Number with the width of the new dimensions in user units.
|
|
* Can also be the string "fit" to indicate "fit to content".
|
|
* @param {Float} y - Number with the height of the new dimensions in user units.
|
|
* @fires module:elem-get-set.SvgCanvas#event:changed
|
|
* @returns {boolean} Indicates if resolution change was successful.
|
|
* It will fail on "fit to content" option with no content to fit to.
|
|
*/
|
|
const setResolutionMethod = (x, y) => {
|
|
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
|
const res = svgCanvas.getResolution()
|
|
const { w, h } = res
|
|
let batchCmd
|
|
|
|
if (x === 'fit') {
|
|
// Get bounding box
|
|
const bbox = getStrokedBBoxDefaultVisible()
|
|
|
|
if (bbox) {
|
|
batchCmd = new BatchCommand('Fit Canvas to Content')
|
|
const visEls = getVisibleElements()
|
|
svgCanvas.addToSelection(visEls)
|
|
const dx = []; const dy = []
|
|
visEls.forEach((_item, _i) => {
|
|
dx.push(bbox.x * -1)
|
|
dy.push(bbox.y * -1)
|
|
})
|
|
|
|
const cmd = svgCanvas.moveSelectedElements(dx, dy, false)
|
|
if (cmd) {
|
|
batchCmd.addSubCommand(cmd)
|
|
}
|
|
svgCanvas.clearSelection()
|
|
|
|
x = Math.round(bbox.width)
|
|
y = Math.round(bbox.height)
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
const newW = convertToNum('width', x)
|
|
const newH = convertToNum('height', y)
|
|
if (newW !== w || newH !== h) {
|
|
if (!batchCmd) {
|
|
batchCmd = new BatchCommand('Change Image Dimensions')
|
|
}
|
|
const svgContent = svgCanvas.getSvgContent()
|
|
const oldViewBox = svgContent.getAttribute('viewBox')
|
|
|
|
svgContent.setAttribute('width', newW)
|
|
svgContent.setAttribute('height', newH)
|
|
|
|
svgCanvas.contentW = newW
|
|
svgCanvas.contentH = newH
|
|
svgContent.setAttribute('viewBox', [0, 0, newW, newH].join(' '))
|
|
batchCmd.addSubCommand(new ChangeElementCommand(svgContent, { width: w, height: h, viewBox: oldViewBox }))
|
|
|
|
svgCanvas.addCommandToHistory(batchCmd)
|
|
svgCanvas.call('changed', [svgContent])
|
|
}
|
|
return true
|
|
}
|
|
|
|
/**
|
|
* Returns the editor's namespace URL, optionally adding it to the root element.
|
|
* @function module:elem-get-set.SvgCanvas#getEditorNS
|
|
* @param {boolean} [add] - Indicates whether or not to add the namespace value
|
|
* @returns {string} The editor's namespace URL
|
|
*/
|
|
const getEditorNSMethod = (add) => {
|
|
if (add) {
|
|
svgCanvas.getSvgContent().setAttribute('xmlns:se', NS.SE)
|
|
}
|
|
return NS.SE
|
|
}
|
|
|
|
/**
|
|
* @typedef {PlainObject} module:elem-get-set.ZoomAndBBox
|
|
* @property {Float} zoom
|
|
* @property {module:utilities.BBoxObject} bbox
|
|
*/
|
|
/**
|
|
* Sets the zoom level on the canvas-side based on the given value.
|
|
* @function module:elem-get-set.SvgCanvas#setBBoxZoom
|
|
* @param {"selection"|"canvas"|"content"|"layer"|module:SVGEditor.BBoxObjectWithFactor} val - Bounding box object to zoom to or string indicating zoom option. Note: the object value type is defined in `svg-editor.js`
|
|
* @param {Integer} editorW - The editor's workarea box's width
|
|
* @param {Integer} editorH - The editor's workarea box's height
|
|
* @returns {module:elem-get-set.ZoomAndBBox|void}
|
|
*/
|
|
const setBBoxZoomMethod = (val, editorW, editorH) => {
|
|
const zoom = svgCanvas.getZoom()
|
|
const selectedElements = svgCanvas.getSelectedElements()
|
|
let spacer = 0.85
|
|
let bb
|
|
const calcZoom = (bb) => {
|
|
if (!bb) { return undefined }
|
|
if (!Number.isFinite(editorW) || !Number.isFinite(editorH) || editorW <= 0 || editorH <= 0) {
|
|
return undefined
|
|
}
|
|
if (!Number.isFinite(bb.width) || !Number.isFinite(bb.height) || bb.width <= 0 || bb.height <= 0) {
|
|
return undefined
|
|
}
|
|
const wZoom = Math.round((editorW / bb.width) * 100 * spacer) / 100
|
|
const hZoom = Math.round((editorH / bb.height) * 100 * spacer) / 100
|
|
const zoom = Math.min(wZoom, hZoom)
|
|
if (!Number.isFinite(zoom) || zoom <= 0) {
|
|
return undefined
|
|
}
|
|
svgCanvas.setZoom(zoom)
|
|
return { zoom, bbox: bb }
|
|
}
|
|
|
|
if (val && typeof val === 'object') {
|
|
bb = val
|
|
if (bb.width === 0 || bb.height === 0) {
|
|
let newzoom = zoom
|
|
if (Number.isFinite(bb.zoom) && bb.zoom > 0) {
|
|
newzoom = bb.zoom
|
|
} else if (Number.isFinite(bb.factor) && bb.factor > 0) {
|
|
newzoom = zoom * bb.factor
|
|
}
|
|
if (Number.isFinite(newzoom) && newzoom > 0) {
|
|
svgCanvas.setZoom(newzoom)
|
|
}
|
|
return { zoom: newzoom, bbox: bb }
|
|
}
|
|
return calcZoom(bb)
|
|
}
|
|
|
|
switch (val) {
|
|
case 'selection': {
|
|
if (!selectedElements[0]) { return undefined }
|
|
const selectedElems = selectedElements.filter(Boolean)
|
|
bb = getStrokedBBoxDefaultVisible(selectedElems)
|
|
break
|
|
} case 'canvas': {
|
|
const res = svgCanvas.getResolution()
|
|
spacer = 0.95
|
|
bb = { width: res.w, height: res.h, x: 0, y: 0 }
|
|
break
|
|
} case 'content':
|
|
bb = getStrokedBBoxDefaultVisible()
|
|
break
|
|
case 'layer':
|
|
bb = getStrokedBBoxDefaultVisible(getVisibleElements(svgCanvas.getCurrentDrawing().getCurrentLayer()))
|
|
break
|
|
default:
|
|
return undefined
|
|
}
|
|
return calcZoom(bb)
|
|
}
|
|
|
|
/**
|
|
* Sets the zoom to the given level.
|
|
* @function module:elem-get-set.SvgCanvas#setZoom
|
|
* @param {Float} zoomLevel - Float indicating the zoom level to change to
|
|
* @fires module:elem-get-set.SvgCanvas#event:ext_zoomChanged
|
|
* @returns {void}
|
|
*/
|
|
const setZoomMethod = (zoomLevel) => {
|
|
if (!Number.isFinite(zoomLevel) || zoomLevel <= 0) {
|
|
return
|
|
}
|
|
const selectedElements = svgCanvas.getSelectedElements()
|
|
const res = svgCanvas.getResolution()
|
|
const w = res.w / zoomLevel
|
|
const h = res.h / zoomLevel
|
|
if (!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) {
|
|
return
|
|
}
|
|
svgCanvas.getSvgContent().setAttribute('viewBox', `0 0 ${w} ${h}`)
|
|
svgCanvas.setZoom(zoomLevel)
|
|
selectedElements.forEach((elem) => {
|
|
if (!elem) { return }
|
|
const selector = svgCanvas.selectorManager.requestSelector(elem)
|
|
selector && selector.resize()
|
|
})
|
|
svgCanvas.pathActions.zoomChange()
|
|
svgCanvas.runExtensions('zoomChanged', zoomLevel)
|
|
}
|
|
|
|
/**
|
|
* Change the current stroke/fill color/gradient value.
|
|
* @function module:elem-get-set.SvgCanvas#setColor
|
|
* @param {string} type - String indicating fill or stroke
|
|
* @param {string} val - The value to set the stroke attribute to
|
|
* @param {boolean} preventUndo - Boolean indicating whether or not svgCanvas should be an undoable option
|
|
* @fires module:elem-get-set.SvgCanvas#event:changed
|
|
* @returns {void}
|
|
*/
|
|
const setColorMethod = (type, val, preventUndo) => {
|
|
const selectedElements = svgCanvas.getSelectedElements()
|
|
svgCanvas.setCurShape(type, val)
|
|
svgCanvas.setCurProperties(`${type}_paint`, { type: 'solidColor' })
|
|
const elems = []
|
|
/**
|
|
*
|
|
* @param {Element} e
|
|
* @returns {void}
|
|
*/
|
|
const addNonG = (e) => {
|
|
if (e.nodeName !== 'g') {
|
|
elems.push(e)
|
|
}
|
|
}
|
|
let i = selectedElements.length
|
|
while (i--) {
|
|
const elem = selectedElements[i]
|
|
if (elem) {
|
|
if (elem.tagName === 'g') {
|
|
walkTree(elem, addNonG)
|
|
} else if (type === 'fill') {
|
|
if (elem.tagName !== 'polyline' && elem.tagName !== 'line') {
|
|
elems.push(elem)
|
|
}
|
|
} else {
|
|
elems.push(elem)
|
|
}
|
|
}
|
|
}
|
|
if (elems.length > 0) {
|
|
if (!preventUndo) {
|
|
svgCanvas.changeSelectedAttribute(type, val, elems)
|
|
svgCanvas.call('changed', elems)
|
|
} else {
|
|
svgCanvas.changeSelectedAttributeNoUndo(type, val, elems)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Apply the current gradient to selected element's fill or stroke.
|
|
* @function module:elem-get-set.SvgCanvas#setGradient
|
|
* @param {"fill"|"stroke"} type - String indicating "fill" or "stroke" to apply to an element
|
|
* @returns {void}
|
|
*/
|
|
const setGradientMethod = (type) => {
|
|
if (!svgCanvas.getCurProperties(`${type}_paint`) ||
|
|
svgCanvas.getCurProperties(`${type}_paint`).type === 'solidColor') { return }
|
|
const canvas = svgCanvas
|
|
let grad = canvas[type + 'Grad']
|
|
if (!grad) { return }
|
|
// find out if there is a duplicate gradient already in the defs
|
|
const duplicateGrad = findDuplicateGradient(grad)
|
|
const defs = findDefs()
|
|
// no duplicate found, so import gradient into defs
|
|
if (!duplicateGrad) {
|
|
// const origGrad = grad;
|
|
grad = svgCanvas.getDOMDocument().importNode(grad, true)
|
|
defs.append(grad)
|
|
// get next id and set it on the grad
|
|
grad.id = svgCanvas.getNextId()
|
|
} else { // use existing gradient
|
|
grad = duplicateGrad
|
|
}
|
|
svgCanvas.setColor(type, `url(#${grad.id})`)
|
|
}
|
|
|
|
/**
|
|
* Check if exact gradient already exists.
|
|
* @function module:svgcanvas~findDuplicateGradient
|
|
* @param {SVGGradientElement} grad - The gradient DOM element to compare to others
|
|
* @returns {SVGGradientElement} The existing gradient if found, `null` if not
|
|
*/
|
|
const findDuplicateGradient = (grad) => {
|
|
if (!grad) {
|
|
return null
|
|
}
|
|
if (!['linearGradient', 'radialGradient'].includes(grad.tagName)) {
|
|
return null
|
|
}
|
|
const defs = findDefs()
|
|
const existingGrads = defs.querySelectorAll('linearGradient, radialGradient')
|
|
let i = existingGrads.length
|
|
const radAttrs = ['r', 'cx', 'cy', 'fx', 'fy']
|
|
while (i--) {
|
|
const og = existingGrads[i]
|
|
if (og.tagName !== grad.tagName) {
|
|
continue
|
|
}
|
|
if (grad.tagName === 'linearGradient') {
|
|
if (grad.getAttribute('x1') !== og.getAttribute('x1') ||
|
|
grad.getAttribute('y1') !== og.getAttribute('y1') ||
|
|
grad.getAttribute('x2') !== og.getAttribute('x2') ||
|
|
grad.getAttribute('y2') !== og.getAttribute('y2')
|
|
) {
|
|
continue
|
|
}
|
|
} else {
|
|
const gradAttrs = {
|
|
r: Number(grad.getAttribute('r')),
|
|
cx: Number(grad.getAttribute('cx')),
|
|
cy: Number(grad.getAttribute('cy')),
|
|
fx: Number(grad.getAttribute('fx')),
|
|
fy: Number(grad.getAttribute('fy'))
|
|
}
|
|
const ogAttrs = {
|
|
r: Number(og.getAttribute('r')),
|
|
cx: Number(og.getAttribute('cx')),
|
|
cy: Number(og.getAttribute('cy')),
|
|
fx: Number(og.getAttribute('fx')),
|
|
fy: Number(og.getAttribute('fy'))
|
|
}
|
|
|
|
let diff = false
|
|
radAttrs.forEach((attr) => {
|
|
if (gradAttrs[attr] !== ogAttrs[attr]) { diff = true }
|
|
})
|
|
|
|
if (diff) { continue }
|
|
}
|
|
|
|
// else could be a duplicate, iterate through stops
|
|
const stops = grad.getElementsByTagNameNS(NS.SVG, 'stop')
|
|
const ostops = og.getElementsByTagNameNS(NS.SVG, 'stop')
|
|
|
|
if (stops.length !== ostops.length) {
|
|
continue
|
|
}
|
|
|
|
let j = stops.length
|
|
while (j--) {
|
|
const stop = stops[j]
|
|
const ostop = ostops[j]
|
|
|
|
if (stop.getAttribute('offset') !== ostop.getAttribute('offset') ||
|
|
stop.getAttribute('stop-opacity') !== ostop.getAttribute('stop-opacity') ||
|
|
stop.getAttribute('stop-color') !== ostop.getAttribute('stop-color')) {
|
|
break
|
|
}
|
|
}
|
|
|
|
if (j === -1) {
|
|
return og
|
|
}
|
|
} // for each gradient in defs
|
|
|
|
return null
|
|
}
|
|
|
|
/**
|
|
* Set a color/gradient to a fill/stroke.
|
|
* @function module:elem-get-set.SvgCanvas#setPaint
|
|
* @param {"fill"|"stroke"} type - String with "fill" or "stroke"
|
|
* @param {} paint - The paint object to apply
|
|
* @returns {void}
|
|
*/
|
|
const setPaintMethod = (type, paint) => {
|
|
// make a copy
|
|
const p = new Paint(paint)
|
|
svgCanvas.setPaintOpacity(type, p.alpha / 100, true)
|
|
|
|
// now set the current paint object
|
|
svgCanvas.setCurProperties(`${type}_paint`, p)
|
|
switch (p.type) {
|
|
case 'solidColor':
|
|
svgCanvas.setColor(type, p.solidColor !== 'none' ? `#${p.solidColor}` : 'none')
|
|
break
|
|
case 'linearGradient':
|
|
case 'radialGradient':
|
|
svgCanvas.setCanvas(type + 'Grad', p[p.type])
|
|
svgCanvas.setGradient(type)
|
|
break
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the stroke width for the current selected elements.
|
|
* When attempting to set a line's width to 0, this changes it to 1 instead.
|
|
* @function module:elem-get-set.SvgCanvas#setStrokeWidth
|
|
* @param {Float} val - A Float indicating the new stroke width value
|
|
* @fires module:elem-get-set.SvgCanvas#event:changed
|
|
* @returns {void}
|
|
*/
|
|
const setStrokeWidthMethod = (val) => {
|
|
const selectedElements = svgCanvas.getSelectedElements()
|
|
if (val === 0 && ['line', 'path'].includes(svgCanvas.getMode())) {
|
|
svgCanvas.setStrokeWidth(1)
|
|
return
|
|
}
|
|
svgCanvas.setCurProperties('stroke_width', val)
|
|
|
|
const elems = []
|
|
/**
|
|
*
|
|
* @param {Element} e
|
|
* @returns {void}
|
|
*/
|
|
const addNonG = (e) => {
|
|
if (e.nodeName !== 'g') {
|
|
elems.push(e)
|
|
}
|
|
}
|
|
let i = selectedElements.length
|
|
while (i--) {
|
|
const elem = selectedElements[i]
|
|
if (elem) {
|
|
if (elem.tagName === 'g') {
|
|
walkTree(elem, addNonG)
|
|
} else {
|
|
elems.push(elem)
|
|
}
|
|
}
|
|
}
|
|
if (elems.length > 0) {
|
|
svgCanvas.changeSelectedAttribute('stroke-width', val, elems)
|
|
svgCanvas.call('changed', selectedElements)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the given stroke-related attribute the given value for selected elements.
|
|
* @function module:elem-get-set.SvgCanvas#setStrokeAttr
|
|
* @param {string} attr - String with the attribute name
|
|
* @param {string|Float} val - String or number with the attribute value
|
|
* @fires module:elem-get-set.SvgCanvas#event:changed
|
|
* @returns {void}
|
|
*/
|
|
const setStrokeAttrMethod = (attr, val) => {
|
|
const selectedElements = svgCanvas.getSelectedElements()
|
|
svgCanvas.setCurShape(attr.replace('-', '_'), val)
|
|
const elems = []
|
|
|
|
let i = selectedElements.length
|
|
while (i--) {
|
|
const elem = selectedElements[i]
|
|
if (elem) {
|
|
if (elem.tagName === 'g') {
|
|
walkTree(elem, (e) => { if (e.nodeName !== 'g') { elems.push(e) } })
|
|
} else {
|
|
elems.push(elem)
|
|
}
|
|
}
|
|
}
|
|
if (elems.length > 0) {
|
|
svgCanvas.changeSelectedAttribute(attr, val, elems)
|
|
svgCanvas.call('changed', selectedElements)
|
|
}
|
|
}
|
|
|
|
const getSelectedTextElements = () => {
|
|
return svgCanvas.getSelectedElements().filter(el => el?.tagName === 'text')
|
|
}
|
|
|
|
const getChangedTextElements = (textElements, attr, newValue) => {
|
|
const normalizedValue = String(newValue)
|
|
return textElements.filter((elem) => {
|
|
const oldValue = attr === '#text' ? elem.textContent : elem.getAttribute(attr)
|
|
return (oldValue || '') !== normalizedValue
|
|
})
|
|
}
|
|
|
|
const notifyTextChange = (textElements) => {
|
|
if (textElements.length > 0) {
|
|
svgCanvas.call('changed', textElements)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if all selected text elements are in bold.
|
|
* @function module:svgcanvas.SvgCanvas#getBold
|
|
* @returns {boolean} `true` if all selected elements are bold, `false` otherwise.
|
|
*/
|
|
const getBoldMethod = () => {
|
|
const textElements = getSelectedTextElements()
|
|
return textElements.every(el => el.getAttribute('font-weight') === 'bold')
|
|
}
|
|
|
|
/**
|
|
* Make the selected element(s) bold or normal.
|
|
* @function module:svgcanvas.SvgCanvas#setBold
|
|
* @param {boolean} b - Indicates bold (`true`) or normal (`false`)
|
|
* @returns {void}
|
|
*/
|
|
const setBoldMethod = (b) => {
|
|
const textElements = getSelectedTextElements()
|
|
const value = b ? 'bold' : 'normal'
|
|
const changedTextElements = getChangedTextElements(textElements, 'font-weight', value)
|
|
if (changedTextElements.length > 0) {
|
|
svgCanvas.changeSelectedAttribute('font-weight', value, changedTextElements)
|
|
}
|
|
if (!textElements.some(el => el.textContent)) {
|
|
svgCanvas.textActions.setCursor()
|
|
}
|
|
notifyTextChange(changedTextElements)
|
|
}
|
|
|
|
/**
|
|
* Check if all selected text elements have the given text decoration value or not.
|
|
* @returns {boolean} Indicates whether or not elements have the text decoration value
|
|
*/
|
|
const hasTextDecorationMethod = (value) => {
|
|
const textElements = getSelectedTextElements()
|
|
return textElements.every(el => (el.getAttribute('text-decoration') || '').includes(value))
|
|
}
|
|
|
|
/**
|
|
* Adds the given text decoration value
|
|
* @param value The text decoration value
|
|
* @returns {void}
|
|
*/
|
|
const addTextDecorationMethod = (value) => {
|
|
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
|
const textElements = getSelectedTextElements()
|
|
|
|
const batchCmd = new BatchCommand()
|
|
textElements.forEach(elem => {
|
|
const oldValue = elem.getAttribute('text-decoration') || ''
|
|
// Add the new text decoration value if it did not exist
|
|
if (!oldValue.includes(value)) {
|
|
batchCmd.addSubCommand(new ChangeElementCommand(elem, { 'text-decoration': oldValue }))
|
|
svgCanvas.changeSelectedAttributeNoUndo('text-decoration', `${oldValue} ${value}`.trim(), [elem])
|
|
}
|
|
})
|
|
if (!batchCmd.isEmpty()) {
|
|
svgCanvas.undoMgr.addCommandToHistory(batchCmd)
|
|
}
|
|
|
|
if (!textElements.some(el => el.textContent)) {
|
|
svgCanvas.textActions.setCursor()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes the given text decoration value
|
|
* @param value The text decoration value
|
|
* @returns {void}
|
|
*/
|
|
const removeTextDecorationMethod = (value) => {
|
|
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
|
const textElements = getSelectedTextElements()
|
|
|
|
const batchCmd = new BatchCommand()
|
|
textElements.forEach(elem => {
|
|
const actualValues = elem.getAttribute('text-decoration') || ''
|
|
batchCmd.addSubCommand(new ChangeElementCommand(elem, { 'text-decoration': actualValues }))
|
|
svgCanvas.changeSelectedAttributeNoUndo('text-decoration', actualValues.replace(value, '').trim(), [elem])
|
|
})
|
|
if (!batchCmd.isEmpty()) {
|
|
svgCanvas.undoMgr.addCommandToHistory(batchCmd)
|
|
}
|
|
|
|
if (!textElements.some(el => el.textContent)) {
|
|
svgCanvas.textActions.setCursor()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if all selected elements have an italic font style.
|
|
* @function module:svgcanvas.SvgCanvas#getItalic
|
|
* @returns {boolean} `true` if all selected elements are in italics, `false` otherwise.
|
|
*/
|
|
const getItalicMethod = () => {
|
|
const textElements = getSelectedTextElements()
|
|
return textElements.every(el => el.getAttribute('font-style') === 'italic')
|
|
}
|
|
|
|
/**
|
|
* Make the selected element(s) italic or normal.
|
|
* @function module:svgcanvas.SvgCanvas#setItalic
|
|
* @param {boolean} i - Indicates italic (`true`) or normal (`false`)
|
|
* @returns {void}
|
|
*/
|
|
const setItalicMethod = (i) => {
|
|
const textElements = getSelectedTextElements()
|
|
const value = i ? 'italic' : 'normal'
|
|
const changedTextElements = getChangedTextElements(textElements, 'font-style', value)
|
|
if (changedTextElements.length > 0) {
|
|
svgCanvas.changeSelectedAttribute('font-style', value, changedTextElements)
|
|
}
|
|
if (!textElements.some(el => el.textContent)) {
|
|
svgCanvas.textActions.setCursor()
|
|
}
|
|
notifyTextChange(changedTextElements)
|
|
}
|
|
|
|
/**
|
|
* @function module:svgcanvas.SvgCanvas#setTextAnchorMethod Set the new text anchor
|
|
* @param {string} value - The text anchor value (start, middle or end)
|
|
* @returns {void}
|
|
*/
|
|
const setTextAnchorMethod = (value) => {
|
|
const textElements = getSelectedTextElements()
|
|
const changedTextElements = getChangedTextElements(textElements, 'text-anchor', value)
|
|
if (changedTextElements.length > 0) {
|
|
svgCanvas.changeSelectedAttribute('text-anchor', value, changedTextElements)
|
|
}
|
|
notifyTextChange(changedTextElements)
|
|
}
|
|
|
|
/**
|
|
* @function module:svgcanvas.SvgCanvas#setLetterSpacingMethod Set the new letter spacing
|
|
* @param {string} value - The letter spacing value
|
|
* @returns {void}
|
|
*/
|
|
const setLetterSpacingMethod = (value) => {
|
|
const textElements = getSelectedTextElements()
|
|
const changedTextElements = getChangedTextElements(textElements, 'letter-spacing', value)
|
|
if (changedTextElements.length > 0) {
|
|
svgCanvas.changeSelectedAttribute('letter-spacing', value, changedTextElements)
|
|
}
|
|
if (!textElements.some(el => el.textContent)) {
|
|
svgCanvas.textActions.setCursor()
|
|
}
|
|
notifyTextChange(changedTextElements)
|
|
}
|
|
|
|
/**
|
|
* @function module:svgcanvas.SvgCanvas#setWordSpacingMethod Set the new word spacing
|
|
* @param {string} value - The word spacing value
|
|
* @returns {void}
|
|
*/
|
|
const setWordSpacingMethod = (value) => {
|
|
const textElements = getSelectedTextElements()
|
|
const changedTextElements = getChangedTextElements(textElements, 'word-spacing', value)
|
|
if (changedTextElements.length > 0) {
|
|
svgCanvas.changeSelectedAttribute('word-spacing', value, changedTextElements)
|
|
}
|
|
if (!textElements.some(el => el.textContent)) {
|
|
svgCanvas.textActions.setCursor()
|
|
}
|
|
notifyTextChange(changedTextElements)
|
|
}
|
|
|
|
/**
|
|
* @function module:svgcanvas.SvgCanvas#setTextLengthMethod Set the new text length
|
|
* @param {string} value - The text length value
|
|
* @returns {void}
|
|
*/
|
|
const setTextLengthMethod = (value) => {
|
|
const textElements = getSelectedTextElements()
|
|
const changedTextElements = getChangedTextElements(textElements, 'textLength', value)
|
|
if (changedTextElements.length > 0) {
|
|
svgCanvas.changeSelectedAttribute('textLength', value, changedTextElements)
|
|
}
|
|
if (!textElements.some(el => el.textContent)) {
|
|
svgCanvas.textActions.setCursor()
|
|
}
|
|
notifyTextChange(changedTextElements)
|
|
}
|
|
|
|
/**
|
|
* @function module:svgcanvas.SvgCanvas#setLengthAdjustMethod Set the new length adjust
|
|
* @param {string} value - The length adjust value
|
|
* @returns {void}
|
|
*/
|
|
const setLengthAdjustMethod = (value) => {
|
|
const textElements = getSelectedTextElements()
|
|
const changedTextElements = getChangedTextElements(textElements, 'lengthAdjust', value)
|
|
if (changedTextElements.length > 0) {
|
|
svgCanvas.changeSelectedAttribute('lengthAdjust', value, changedTextElements)
|
|
}
|
|
if (!textElements.some(el => el.textContent)) {
|
|
svgCanvas.textActions.setCursor()
|
|
}
|
|
notifyTextChange(changedTextElements)
|
|
}
|
|
|
|
/**
|
|
* @function module:svgcanvas.SvgCanvas#getFontFamily
|
|
* @returns {string} The current font family
|
|
*/
|
|
const getFontFamilyMethod = () => {
|
|
return svgCanvas.getCurText('font_family')
|
|
}
|
|
|
|
/**
|
|
* Set the new font family.
|
|
* @function module:svgcanvas.SvgCanvas#setFontFamily
|
|
* @param {string} val - String with the new font family
|
|
* @returns {void}
|
|
*/
|
|
const setFontFamilyMethod = (val) => {
|
|
const textElements = getSelectedTextElements()
|
|
const changedTextElements = getChangedTextElements(textElements, 'font-family', val)
|
|
svgCanvas.setCurText('font_family', val)
|
|
if (changedTextElements.length > 0) {
|
|
svgCanvas.changeSelectedAttribute('font-family', val, changedTextElements)
|
|
}
|
|
if (!textElements.some(el => el.textContent)) {
|
|
svgCanvas.textActions.setCursor()
|
|
}
|
|
notifyTextChange(changedTextElements)
|
|
}
|
|
|
|
/**
|
|
* Set the new font color.
|
|
* @function module:svgcanvas.SvgCanvas#setFontColor
|
|
* @param {string} val - String with the new font color
|
|
* @returns {void}
|
|
*/
|
|
const setFontColorMethod = (val) => {
|
|
const textElements = getSelectedTextElements()
|
|
const changedTextElements = getChangedTextElements(textElements, 'fill', val)
|
|
svgCanvas.setCurText('fill', val)
|
|
if (changedTextElements.length > 0) {
|
|
svgCanvas.changeSelectedAttribute('fill', val, changedTextElements)
|
|
}
|
|
notifyTextChange(changedTextElements)
|
|
}
|
|
|
|
/**
|
|
* @function module:svgcanvas.SvgCanvas#getFontColor
|
|
* @returns {string} The current font color
|
|
*/
|
|
const getFontColorMethod = () => {
|
|
return svgCanvas.getCurText('fill')
|
|
}
|
|
|
|
/**
|
|
* @function module:svgcanvas.SvgCanvas#getFontSize
|
|
* @returns {Float} The current font size
|
|
*/
|
|
const getFontSizeMethod = () => {
|
|
return svgCanvas.getCurText('font_size')
|
|
}
|
|
|
|
/**
|
|
* Applies the given font size to the selected element.
|
|
* @function module:svgcanvas.SvgCanvas#setFontSize
|
|
* @param {Float} val - Float with the new font size
|
|
* @returns {void}
|
|
*/
|
|
const setFontSizeMethod = (val) => {
|
|
const textElements = getSelectedTextElements()
|
|
const changedTextElements = getChangedTextElements(textElements, 'font-size', val)
|
|
svgCanvas.setCurText('font_size', val)
|
|
if (changedTextElements.length > 0) {
|
|
svgCanvas.changeSelectedAttribute('font-size', val, changedTextElements)
|
|
}
|
|
if (!textElements.some(el => el.textContent)) {
|
|
svgCanvas.textActions.setCursor()
|
|
}
|
|
notifyTextChange(changedTextElements)
|
|
}
|
|
|
|
/**
|
|
* @function module:svgcanvas.SvgCanvas#getText
|
|
* @returns {string} The current text (`textContent`) of the selected element
|
|
*/
|
|
const getTextMethod = () => {
|
|
const selectedElements = svgCanvas.getSelectedElements()
|
|
const selected = selectedElements[0]
|
|
return (selected) ? selected.textContent : ''
|
|
}
|
|
|
|
/**
|
|
* Updates the text element with the given string.
|
|
* @function module:svgcanvas.SvgCanvas#setTextContent
|
|
* @param {string} val - String with the new text
|
|
* @returns {void}
|
|
*/
|
|
const setTextContentMethod = (val) => {
|
|
svgCanvas.changeSelectedAttribute('#text', val)
|
|
svgCanvas.textActions.init(val)
|
|
svgCanvas.textActions.setCursor()
|
|
}
|
|
|
|
/**
|
|
* Sets the new image URL for the selected image element. Updates its size if
|
|
* a new URL is given.
|
|
* @function module:svgcanvas.SvgCanvas#setImageURL
|
|
* @param {string} val - String with the image URL/path
|
|
* @fires module:svgcanvas.SvgCanvas#event:changed
|
|
* @returns {void}
|
|
*/
|
|
const setImageURLMethod = (val) => {
|
|
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
|
const selectedElements = svgCanvas.getSelectedElements()
|
|
const elem = selectedElements[0]
|
|
if (!elem) { return }
|
|
|
|
const attrs = {
|
|
width: elem.getAttribute('width'),
|
|
height: elem.getAttribute('height')
|
|
}
|
|
const setsize = (!attrs.width || !attrs.height)
|
|
|
|
const curHref = getHref(elem)
|
|
const hrefChanged = curHref !== val
|
|
|
|
// Do nothing if no URL change or size change
|
|
if (!hrefChanged && !setsize) {
|
|
return
|
|
}
|
|
|
|
const batchCmd = new BatchCommand('Change Image URL')
|
|
|
|
if (hrefChanged) {
|
|
setHref(elem, val)
|
|
batchCmd.addSubCommand(new ChangeElementCommand(elem, {
|
|
'#href': curHref
|
|
}))
|
|
}
|
|
|
|
let finalized = false
|
|
const finalize = () => {
|
|
if (finalized) { return }
|
|
finalized = true
|
|
if (batchCmd.isEmpty()) { return }
|
|
svgCanvas.addCommandToHistory(batchCmd)
|
|
svgCanvas.call('changed', [elem])
|
|
}
|
|
|
|
const img = new Image()
|
|
img.onload = () => {
|
|
const changes = {
|
|
width: elem.getAttribute('width'),
|
|
height: elem.getAttribute('height')
|
|
}
|
|
elem.setAttribute('width', img.width)
|
|
elem.setAttribute('height', img.height)
|
|
|
|
const selector = svgCanvas.selectorManager.requestSelector(elem)
|
|
selector && selector.resize()
|
|
|
|
batchCmd.addSubCommand(new ChangeElementCommand(elem, changes))
|
|
finalize()
|
|
}
|
|
img.onerror = () => {
|
|
finalize()
|
|
}
|
|
img.src = val
|
|
}
|
|
|
|
/**
|
|
* Sets the new link URL for the selected anchor element.
|
|
* @function module:svgcanvas.SvgCanvas#setLinkURL
|
|
* @param {string} val - String with the link URL/path
|
|
* @returns {void}
|
|
*/
|
|
const setLinkURLMethod = (val) => {
|
|
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
|
const selectedElements = svgCanvas.getSelectedElements()
|
|
let elem = selectedElements[0]
|
|
if (!elem) { return }
|
|
if (elem.tagName !== 'a') {
|
|
// See if parent is an anchor
|
|
const parentsA = getParents(elem.parentNode, 'a')
|
|
if (parentsA?.length) {
|
|
elem = parentsA[0]
|
|
} else {
|
|
return
|
|
}
|
|
}
|
|
|
|
const curHref = getHref(elem)
|
|
|
|
if (curHref === val) { return }
|
|
|
|
const batchCmd = new BatchCommand('Change Link URL')
|
|
|
|
setHref(elem, val)
|
|
batchCmd.addSubCommand(new ChangeElementCommand(elem, {
|
|
'#href': curHref
|
|
}))
|
|
|
|
svgCanvas.addCommandToHistory(batchCmd)
|
|
}
|
|
|
|
/**
|
|
* Sets the `rx` and `ry` values to the selected `rect` element
|
|
* to change its corner radius.
|
|
* @function module:svgcanvas.SvgCanvas#setRectRadius
|
|
* @param {string|Float} val - The new radius
|
|
* @fires module:svgcanvas.SvgCanvas#event:changed
|
|
* @returns {void}
|
|
*/
|
|
const setRectRadiusMethod = (val) => {
|
|
const { ChangeElementCommand } = svgCanvas.history
|
|
const selectedElements = svgCanvas.getSelectedElements()
|
|
const selected = selectedElements[0]
|
|
if (selected?.tagName !== 'rect') { return }
|
|
|
|
const radius = Number(val)
|
|
if (!Number.isFinite(radius) || radius < 0) {
|
|
return
|
|
}
|
|
|
|
const oldRx = selected.getAttribute('rx')
|
|
const oldRy = selected.getAttribute('ry')
|
|
const currentRx = Number(oldRx)
|
|
const currentRy = Number(oldRy)
|
|
const hasCurrentRx = oldRx !== null && Number.isFinite(currentRx)
|
|
const hasCurrentRy = oldRy !== null && Number.isFinite(currentRy)
|
|
const already = (radius === 0 && oldRx === null && oldRy === null) ||
|
|
(hasCurrentRx && hasCurrentRy && currentRx === radius && currentRy === radius)
|
|
if (already) { return }
|
|
|
|
selected.setAttribute('rx', radius)
|
|
selected.setAttribute('ry', radius)
|
|
svgCanvas.addCommandToHistory(new ChangeElementCommand(selected, { rx: oldRx, ry: oldRy }, 'Radius'))
|
|
svgCanvas.call('changed', [selected])
|
|
}
|
|
|
|
/**
|
|
* Wraps the selected element(s) in an anchor element or converts group to one.
|
|
* @function module:svgcanvas.SvgCanvas#makeHyperlink
|
|
* @param {string} url
|
|
* @returns {void}
|
|
*/
|
|
const makeHyperlinkMethod = (url) => {
|
|
svgCanvas.groupSelectedElements('a', url)
|
|
}
|
|
|
|
/**
|
|
* @function module:svgcanvas.SvgCanvas#removeHyperlink
|
|
* @returns {void}
|
|
*/
|
|
const removeHyperlinkMethod = () => {
|
|
svgCanvas.ungroupSelectedElement()
|
|
}
|
|
|
|
/**
|
|
* Group: Element manipulation.
|
|
*/
|
|
|
|
/**
|
|
* Sets the new segment type to the selected segment(s).
|
|
* @function module:svgcanvas.SvgCanvas#setSegType
|
|
* @param {Integer} newType - New segment type. See {@link https://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg} for list
|
|
* @returns {void}
|
|
*/
|
|
const setSegTypeMethod = (newType) => {
|
|
svgCanvas.pathActions.setSegType(newType)
|
|
}
|
|
|
|
/**
|
|
* Set the background of the editor (NOT the actual document).
|
|
* @function module:svgcanvas.SvgCanvas#setBackground
|
|
* @param {string} color - String with fill color to apply
|
|
* @param {string} url - URL or path to image to use
|
|
* @returns {void}
|
|
*/
|
|
const setBackgroundMethod = (color, url) => {
|
|
const bg = getElement('canvasBackground')
|
|
if (!bg) { return }
|
|
const border = bg.querySelector('rect')
|
|
if (!border) { return }
|
|
let bgImg = getElement('background_image')
|
|
let bgPattern = getElement('background_pattern')
|
|
border.setAttribute('fill', color === 'chessboard' ? '#fff' : color)
|
|
if (color === 'chessboard') {
|
|
if (!bgPattern) {
|
|
bgPattern = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'foreignObject')
|
|
svgCanvas.assignAttributes(bgPattern, {
|
|
id: 'background_pattern',
|
|
width: '100%',
|
|
height: '100%',
|
|
preserveAspectRatio: 'xMinYMin',
|
|
style: 'pointer-events:none'
|
|
})
|
|
const div = document.createElement('div')
|
|
svgCanvas.assignAttributes(div, {
|
|
style: 'pointer-events:none;width:100%;height:100%;' +
|
|
'background-image:url(data:image/gif;base64,' +
|
|
'R0lGODlhEAAQAIAAAP///9bW1iH5BAAAAAAALAAAAAAQABAAAAIfjG+' +
|
|
'gq4jM3IFLJgpswNly/XkcBpIiVaInlLJr9FZWAQA7);'
|
|
})
|
|
bgPattern.append(div)
|
|
bg.append(bgPattern)
|
|
}
|
|
} else if (bgPattern) {
|
|
bgPattern.remove()
|
|
}
|
|
if (url) {
|
|
if (!bgImg) {
|
|
bgImg = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'image')
|
|
svgCanvas.assignAttributes(bgImg, {
|
|
id: 'background_image',
|
|
width: '100%',
|
|
height: '100%',
|
|
preserveAspectRatio: 'xMinYMin',
|
|
style: 'pointer-events:none'
|
|
})
|
|
}
|
|
setHref(bgImg, url)
|
|
bg.append(bgImg)
|
|
} else if (bgImg) {
|
|
bgImg.remove()
|
|
}
|
|
}
|