@svgedit/svgcanvas 7.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/blur-event.js +156 -0
- package/clear.js +43 -0
- package/coords.js +298 -0
- package/copy-elem.js +45 -0
- package/dataStorage.js +28 -0
- package/dist/svgcanvas.js +515 -0
- package/dist/svgcanvas.js.map +1 -0
- package/draw.js +1064 -0
- package/elem-get-set.js +1077 -0
- package/event.js +1388 -0
- package/history.js +619 -0
- package/historyrecording.js +161 -0
- package/json.js +110 -0
- package/layer.js +228 -0
- package/math.js +221 -0
- package/namespaces.js +40 -0
- package/package.json +54 -0
- package/paint.js +88 -0
- package/paste-elem.js +127 -0
- package/path-actions.js +1237 -0
- package/path-method.js +1012 -0
- package/path.js +781 -0
- package/recalculate.js +794 -0
- package/rollup.config.js +40 -0
- package/sanitize.js +252 -0
- package/select.js +543 -0
- package/selected-elem.js +1297 -0
- package/selection.js +482 -0
- package/svg-exec.js +1289 -0
- package/svgcanvas.js +1347 -0
- package/svgroot.js +36 -0
- package/text-actions.js +530 -0
- package/touch.js +51 -0
- package/undo.js +279 -0
- package/utilities.js +1214 -0
package/elem-get-set.js
ADDED
|
@@ -0,0 +1,1077 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module elem-get-set get and set methods.
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @copyright 2011 Jeff Schiller
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import Paint from './paint.js'
|
|
8
|
+
import { NS } from './namespaces.js'
|
|
9
|
+
import {
|
|
10
|
+
getVisibleElements, getStrokedBBoxDefaultVisible, findDefs,
|
|
11
|
+
walkTree, getHref, setHref, getElement
|
|
12
|
+
} from './utilities.js'
|
|
13
|
+
import {
|
|
14
|
+
convertToNum
|
|
15
|
+
} from '../../src/common/units.js'
|
|
16
|
+
import { getParents } from '../../src/common/util.js'
|
|
17
|
+
|
|
18
|
+
let svgCanvas = null
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @function module:elem-get-set.init
|
|
22
|
+
* @param {module:elem-get-set.elemContext} elemContext
|
|
23
|
+
* @returns {void}
|
|
24
|
+
*/
|
|
25
|
+
export const init = (canvas) => {
|
|
26
|
+
svgCanvas = canvas
|
|
27
|
+
svgCanvas.getBold = getBoldMethod // Check whether selected element is bold or not.
|
|
28
|
+
svgCanvas.setBold = setBoldMethod // Make the selected element bold or normal.
|
|
29
|
+
svgCanvas.getItalic = getItalicMethod // Check whether selected element is in italics or not.
|
|
30
|
+
svgCanvas.setItalic = setItalicMethod // Make the selected element italic or normal.
|
|
31
|
+
svgCanvas.hasTextDecoration = hasTextDecorationMethod // Check whether the selected element has the given text decoration or not.
|
|
32
|
+
svgCanvas.addTextDecoration = addTextDecorationMethod // Adds the given value to the text decoration
|
|
33
|
+
svgCanvas.removeTextDecoration = removeTextDecorationMethod // Removes the given value from the text decoration
|
|
34
|
+
svgCanvas.setTextAnchor = setTextAnchorMethod // Set the new text anchor.
|
|
35
|
+
svgCanvas.setLetterSpacing = setLetterSpacingMethod // Set the new letter spacing.
|
|
36
|
+
svgCanvas.setWordSpacing = setWordSpacingMethod // Set the new word spacing.
|
|
37
|
+
svgCanvas.setTextLength = setTextLengthMethod // Set the new text length.
|
|
38
|
+
svgCanvas.setLengthAdjust = setLengthAdjustMethod // Set the new length adjust.
|
|
39
|
+
svgCanvas.getFontFamily = getFontFamilyMethod // The current font family
|
|
40
|
+
svgCanvas.setFontFamily = setFontFamilyMethod // Set the new font family.
|
|
41
|
+
svgCanvas.setFontColor = setFontColorMethod // Set the new font color.
|
|
42
|
+
svgCanvas.getFontColor = getFontColorMethod // The current font color
|
|
43
|
+
svgCanvas.getFontSize = getFontSizeMethod // The current font size
|
|
44
|
+
svgCanvas.setFontSize = setFontSizeMethod // Applies the given font size to the selected element.
|
|
45
|
+
svgCanvas.getText = getTextMethod // current text (`textContent`) of the selected element
|
|
46
|
+
svgCanvas.setTextContent = setTextContentMethod // Updates the text element with the given string.
|
|
47
|
+
svgCanvas.setImageURL = setImageURLMethod // Sets the new image URL for the selected image element
|
|
48
|
+
svgCanvas.setLinkURL = setLinkURLMethod // Sets the new link URL for the selected anchor element.
|
|
49
|
+
svgCanvas.setRectRadius = setRectRadiusMethod // Sets the `rx` and `ry` values to the selected `rect` element
|
|
50
|
+
svgCanvas.makeHyperlink = makeHyperlinkMethod // Wraps the selected element(s) in an anchor element or converts group to one.
|
|
51
|
+
svgCanvas.removeHyperlink = removeHyperlinkMethod
|
|
52
|
+
svgCanvas.setSegType = setSegTypeMethod // Sets the new segment type to the selected segment(s).
|
|
53
|
+
svgCanvas.setStrokeWidth = setStrokeWidthMethod // Sets the stroke width for the current selected elements.
|
|
54
|
+
svgCanvas.getResolution = getResolutionMethod // The current dimensions and zoom level in an object
|
|
55
|
+
svgCanvas.getTitle = getTitleMethod // the current group/SVG's title contents or `undefined` if no element
|
|
56
|
+
svgCanvas.setGroupTitle = setGroupTitleMethod // Sets the group/SVG's title content.
|
|
57
|
+
svgCanvas.setStrokeAttr = setStrokeAttrMethod // Set the given stroke-related attribute the given value for selected elements.
|
|
58
|
+
svgCanvas.setBackground = setBackgroundMethod // Set the background of the editor (NOT the actual document).
|
|
59
|
+
svgCanvas.setDocumentTitle = setDocumentTitleMethod // Adds/updates a title element for the document with the given name.
|
|
60
|
+
svgCanvas.getEditorNS = getEditorNSMethod // Returns the editor's namespace URL, optionally adding it to the root element.
|
|
61
|
+
svgCanvas.setResolution = setResolutionMethod // Changes the document's dimensions to the given size.
|
|
62
|
+
svgCanvas.setBBoxZoom = setBBoxZoomMethod // Sets the zoom level on the canvas-side based on the given value.
|
|
63
|
+
svgCanvas.setCurrentZoom = setZoomMethod // Sets the zoom to the given level.
|
|
64
|
+
svgCanvas.setColor = setColorMethod // Change the current stroke/fill color/gradien
|
|
65
|
+
svgCanvas.setGradient = setGradientMethod // Apply the current gradient to selected element's fill or stroke.
|
|
66
|
+
svgCanvas.setPaint = setPaintMethod // Set a color/gradient to a fill/stroke.
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @function module:elem-get-set.SvgCanvas#getResolution
|
|
71
|
+
* @returns {DimensionsAndZoom} The current dimensions and zoom level in an object
|
|
72
|
+
*/
|
|
73
|
+
const getResolutionMethod = () => {
|
|
74
|
+
const zoom = svgCanvas.getZoom()
|
|
75
|
+
const w = svgCanvas.getSvgContent().getAttribute('width') / zoom
|
|
76
|
+
const h = svgCanvas.getSvgContent().getAttribute('height') / zoom
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
w,
|
|
80
|
+
h,
|
|
81
|
+
zoom
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @function module:elem-get-set.SvgCanvas#getTitle
|
|
87
|
+
* @param {Element} [elem]
|
|
88
|
+
* @returns {string|void} the current group/SVG's title contents or
|
|
89
|
+
* `undefined` if no element is passed nd there are no selected elements.
|
|
90
|
+
*/
|
|
91
|
+
const getTitleMethod = (elem) => {
|
|
92
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
93
|
+
const dataStorage = svgCanvas.getDataStorage()
|
|
94
|
+
elem = elem || selectedElements[0]
|
|
95
|
+
if (!elem) { return undefined }
|
|
96
|
+
if (dataStorage.has(elem, 'gsvg')) {
|
|
97
|
+
elem = dataStorage.get(elem, 'gsvg')
|
|
98
|
+
} else if (dataStorage.has(elem, 'symbol')) {
|
|
99
|
+
elem = dataStorage.get(elem, 'symbol')
|
|
100
|
+
}
|
|
101
|
+
const childs = elem.childNodes
|
|
102
|
+
for (const child of childs) {
|
|
103
|
+
if (child.nodeName === 'title') {
|
|
104
|
+
return child.textContent
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return ''
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Sets the group/SVG's title content.
|
|
112
|
+
* @function module:elem-get-set.SvgCanvas#setGroupTitle
|
|
113
|
+
* @param {string} val
|
|
114
|
+
* @todo Combine this with `setDocumentTitle`
|
|
115
|
+
* @returns {void}
|
|
116
|
+
*/
|
|
117
|
+
const setGroupTitleMethod = (val) => {
|
|
118
|
+
const {
|
|
119
|
+
InsertElementCommand, RemoveElementCommand,
|
|
120
|
+
ChangeElementCommand, BatchCommand
|
|
121
|
+
} = svgCanvas.history
|
|
122
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
123
|
+
const dataStorage = svgCanvas.getDataStorage()
|
|
124
|
+
let elem = selectedElements[0]
|
|
125
|
+
if (dataStorage.has(elem, 'gsvg')) {
|
|
126
|
+
elem = dataStorage.get(elem, 'gsvg')
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const ts = elem.querySelectorAll('title')
|
|
130
|
+
|
|
131
|
+
const batchCmd = new BatchCommand('Set Label')
|
|
132
|
+
|
|
133
|
+
let title
|
|
134
|
+
if (val.length === 0) {
|
|
135
|
+
// Remove title element
|
|
136
|
+
const tsNextSibling = ts.nextSibling
|
|
137
|
+
batchCmd.addSubCommand(new RemoveElementCommand(ts[0], tsNextSibling, elem))
|
|
138
|
+
ts.remove()
|
|
139
|
+
} else if (ts.length) {
|
|
140
|
+
// Change title contents
|
|
141
|
+
title = ts[0]
|
|
142
|
+
batchCmd.addSubCommand(new ChangeElementCommand(title, { '#text': title.textContent }))
|
|
143
|
+
title.textContent = val
|
|
144
|
+
} else {
|
|
145
|
+
// Add title element
|
|
146
|
+
title = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'title')
|
|
147
|
+
title.textContent = val
|
|
148
|
+
elem.insertBefore(title, elem.firstChild)
|
|
149
|
+
batchCmd.addSubCommand(new InsertElementCommand(title))
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
svgCanvas.addCommandToHistory(batchCmd)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Adds/updates a title element for the document with the given name.
|
|
157
|
+
* This is an undoable action.
|
|
158
|
+
* @function module:elem-get-set.SvgCanvas#setDocumentTitle
|
|
159
|
+
* @param {string} newTitle - String with the new title
|
|
160
|
+
* @returns {void}
|
|
161
|
+
*/
|
|
162
|
+
const setDocumentTitleMethod = (newTitle) => {
|
|
163
|
+
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
|
164
|
+
const childs = svgCanvas.getSvgContent().childNodes
|
|
165
|
+
let docTitle = false; let oldTitle = ''
|
|
166
|
+
|
|
167
|
+
const batchCmd = new BatchCommand('Change Image Title')
|
|
168
|
+
|
|
169
|
+
for (const child of childs) {
|
|
170
|
+
if (child.nodeName === 'title') {
|
|
171
|
+
docTitle = child
|
|
172
|
+
oldTitle = docTitle.textContent
|
|
173
|
+
break
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (!docTitle) {
|
|
177
|
+
docTitle = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'title')
|
|
178
|
+
svgCanvas.getSvgContent().insertBefore(docTitle, svgCanvas.getSvgContent().firstChild)
|
|
179
|
+
// svgContent.firstChild.before(docTitle); // Ok to replace above with this?
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (newTitle.length) {
|
|
183
|
+
docTitle.textContent = newTitle
|
|
184
|
+
} else {
|
|
185
|
+
// No title given, so element is not necessary
|
|
186
|
+
docTitle.remove()
|
|
187
|
+
}
|
|
188
|
+
batchCmd.addSubCommand(new ChangeElementCommand(docTitle, { '#text': oldTitle }))
|
|
189
|
+
svgCanvas.addCommandToHistory(batchCmd)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Changes the document's dimensions to the given size.
|
|
194
|
+
* @function module:elem-get-set.SvgCanvas#setResolution
|
|
195
|
+
* @param {Float|"fit"} x - Number with the width of the new dimensions in user units.
|
|
196
|
+
* Can also be the string "fit" to indicate "fit to content".
|
|
197
|
+
* @param {Float} y - Number with the height of the new dimensions in user units.
|
|
198
|
+
* @fires module:elem-get-set.SvgCanvas#event:changed
|
|
199
|
+
* @returns {boolean} Indicates if resolution change was successful.
|
|
200
|
+
* It will fail on "fit to content" option with no content to fit to.
|
|
201
|
+
*/
|
|
202
|
+
const setResolutionMethod = (x, y) => {
|
|
203
|
+
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
|
204
|
+
const zoom = svgCanvas.getZoom()
|
|
205
|
+
const res = svgCanvas.getResolution()
|
|
206
|
+
const { w, h } = res
|
|
207
|
+
let batchCmd
|
|
208
|
+
|
|
209
|
+
if (x === 'fit') {
|
|
210
|
+
// Get bounding box
|
|
211
|
+
const bbox = getStrokedBBoxDefaultVisible()
|
|
212
|
+
|
|
213
|
+
if (bbox) {
|
|
214
|
+
batchCmd = new BatchCommand('Fit Canvas to Content')
|
|
215
|
+
const visEls = getVisibleElements()
|
|
216
|
+
svgCanvas.addToSelection(visEls)
|
|
217
|
+
const dx = []; const dy = []
|
|
218
|
+
visEls.forEach((_item, _i) => {
|
|
219
|
+
dx.push(bbox.x * -1)
|
|
220
|
+
dy.push(bbox.y * -1)
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
const cmd = svgCanvas.moveSelectedElements(dx, dy, true)
|
|
224
|
+
batchCmd.addSubCommand(cmd)
|
|
225
|
+
svgCanvas.clearSelection()
|
|
226
|
+
|
|
227
|
+
x = Math.round(bbox.width)
|
|
228
|
+
y = Math.round(bbox.height)
|
|
229
|
+
} else {
|
|
230
|
+
return false
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (x !== w || y !== h) {
|
|
234
|
+
if (!batchCmd) {
|
|
235
|
+
batchCmd = new BatchCommand('Change Image Dimensions')
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
x = convertToNum('width', x)
|
|
239
|
+
y = convertToNum('height', y)
|
|
240
|
+
|
|
241
|
+
svgCanvas.getSvgContent().setAttribute('width', x)
|
|
242
|
+
svgCanvas.getSvgContent().setAttribute('height', y)
|
|
243
|
+
|
|
244
|
+
svgCanvas.contentW = x
|
|
245
|
+
svgCanvas.contentH = y
|
|
246
|
+
batchCmd.addSubCommand(new ChangeElementCommand(svgCanvas.getSvgContent(), { width: w, height: h }))
|
|
247
|
+
|
|
248
|
+
svgCanvas.getSvgContent().setAttribute('viewBox', [0, 0, x / zoom, y / zoom].join(' '))
|
|
249
|
+
batchCmd.addSubCommand(new ChangeElementCommand(svgCanvas.getSvgContent(), { viewBox: ['0 0', w, h].join(' ') }))
|
|
250
|
+
|
|
251
|
+
svgCanvas.addCommandToHistory(batchCmd)
|
|
252
|
+
svgCanvas.call('changed', [svgCanvas.getSvgContent()])
|
|
253
|
+
}
|
|
254
|
+
return true
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Returns the editor's namespace URL, optionally adding it to the root element.
|
|
259
|
+
* @function module:elem-get-set.SvgCanvas#getEditorNS
|
|
260
|
+
* @param {boolean} [add] - Indicates whether or not to add the namespace value
|
|
261
|
+
* @returns {string} The editor's namespace URL
|
|
262
|
+
*/
|
|
263
|
+
const getEditorNSMethod = (add) => {
|
|
264
|
+
if (add) {
|
|
265
|
+
svgCanvas.getSvgContent().setAttribute('xmlns:se', NS.SE)
|
|
266
|
+
}
|
|
267
|
+
return NS.SE
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* @typedef {PlainObject} module:elem-get-set.ZoomAndBBox
|
|
272
|
+
* @property {Float} zoom
|
|
273
|
+
* @property {module:utilities.BBoxObject} bbox
|
|
274
|
+
*/
|
|
275
|
+
/**
|
|
276
|
+
* Sets the zoom level on the canvas-side based on the given value.
|
|
277
|
+
* @function module:elem-get-set.SvgCanvas#setBBoxZoom
|
|
278
|
+
* @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`
|
|
279
|
+
* @param {Integer} editorW - The editor's workarea box's width
|
|
280
|
+
* @param {Integer} editorH - The editor's workarea box's height
|
|
281
|
+
* @returns {module:elem-get-set.ZoomAndBBox|void}
|
|
282
|
+
*/
|
|
283
|
+
const setBBoxZoomMethod = (val, editorW, editorH) => {
|
|
284
|
+
const zoom = svgCanvas.getZoom()
|
|
285
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
286
|
+
let spacer = 0.85
|
|
287
|
+
let bb
|
|
288
|
+
const calcZoom = (bb) => {
|
|
289
|
+
if (!bb) { return false }
|
|
290
|
+
const wZoom = Math.round((editorW / bb.width) * 100 * spacer) / 100
|
|
291
|
+
const hZoom = Math.round((editorH / bb.height) * 100 * spacer) / 100
|
|
292
|
+
const zoom = Math.min(wZoom, hZoom)
|
|
293
|
+
svgCanvas.setZoom(zoom)
|
|
294
|
+
return { zoom, bbox: bb }
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (typeof val === 'object') {
|
|
298
|
+
bb = val
|
|
299
|
+
if (bb.width === 0 || bb.height === 0) {
|
|
300
|
+
const newzoom = bb.zoom ? bb.zoom : zoom * bb.factor
|
|
301
|
+
svgCanvas.setZoom(newzoom)
|
|
302
|
+
return { zoom, bbox: bb }
|
|
303
|
+
}
|
|
304
|
+
return calcZoom(bb)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
switch (val) {
|
|
308
|
+
case 'selection': {
|
|
309
|
+
if (!selectedElements[0]) { return undefined }
|
|
310
|
+
const selectedElems = selectedElements.map((n, _) => {
|
|
311
|
+
if (n) {
|
|
312
|
+
return n
|
|
313
|
+
}
|
|
314
|
+
return undefined
|
|
315
|
+
})
|
|
316
|
+
bb = getStrokedBBoxDefaultVisible(selectedElems)
|
|
317
|
+
break
|
|
318
|
+
} case 'canvas': {
|
|
319
|
+
const res = svgCanvas.getResolution()
|
|
320
|
+
spacer = 0.95
|
|
321
|
+
bb = { width: res.w, height: res.h, x: 0, y: 0 }
|
|
322
|
+
break
|
|
323
|
+
} case 'content':
|
|
324
|
+
bb = getStrokedBBoxDefaultVisible()
|
|
325
|
+
break
|
|
326
|
+
case 'layer':
|
|
327
|
+
bb = getStrokedBBoxDefaultVisible(getVisibleElements(svgCanvas.getCurrentDrawing().getCurrentLayer()))
|
|
328
|
+
break
|
|
329
|
+
default:
|
|
330
|
+
return undefined
|
|
331
|
+
}
|
|
332
|
+
return calcZoom(bb)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Sets the zoom to the given level.
|
|
337
|
+
* @function module:elem-get-set.SvgCanvas#setZoom
|
|
338
|
+
* @param {Float} zoomLevel - Float indicating the zoom level to change to
|
|
339
|
+
* @fires module:elem-get-set.SvgCanvas#event:ext_zoomChanged
|
|
340
|
+
* @returns {void}
|
|
341
|
+
*/
|
|
342
|
+
const setZoomMethod = (zoomLevel) => {
|
|
343
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
344
|
+
const res = svgCanvas.getResolution()
|
|
345
|
+
svgCanvas.getSvgContent().setAttribute('viewBox', '0 0 ' + res.w / zoomLevel + ' ' + res.h / zoomLevel)
|
|
346
|
+
svgCanvas.setZoom(zoomLevel)
|
|
347
|
+
selectedElements.forEach((elem) => {
|
|
348
|
+
if (!elem) { return }
|
|
349
|
+
svgCanvas.selectorManager.requestSelector(elem).resize()
|
|
350
|
+
})
|
|
351
|
+
svgCanvas.pathActions.zoomChange()
|
|
352
|
+
svgCanvas.runExtensions('zoomChanged', zoomLevel)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Change the current stroke/fill color/gradient value.
|
|
357
|
+
* @function module:elem-get-set.SvgCanvas#setColor
|
|
358
|
+
* @param {string} type - String indicating fill or stroke
|
|
359
|
+
* @param {string} val - The value to set the stroke attribute to
|
|
360
|
+
* @param {boolean} preventUndo - Boolean indicating whether or not svgCanvas should be an undoable option
|
|
361
|
+
* @fires module:elem-get-set.SvgCanvas#event:changed
|
|
362
|
+
* @returns {void}
|
|
363
|
+
*/
|
|
364
|
+
const setColorMethod = (type, val, preventUndo) => {
|
|
365
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
366
|
+
svgCanvas.setCurShape(type, val)
|
|
367
|
+
svgCanvas.setCurProperties(type + '_paint', { type: 'solidColor' })
|
|
368
|
+
const elems = []
|
|
369
|
+
/**
|
|
370
|
+
*
|
|
371
|
+
* @param {Element} e
|
|
372
|
+
* @returns {void}
|
|
373
|
+
*/
|
|
374
|
+
const addNonG = (e) => {
|
|
375
|
+
if (e.nodeName !== 'g') {
|
|
376
|
+
elems.push(e)
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
let i = selectedElements.length
|
|
380
|
+
while (i--) {
|
|
381
|
+
const elem = selectedElements[i]
|
|
382
|
+
if (elem) {
|
|
383
|
+
if (elem.tagName === 'g') {
|
|
384
|
+
walkTree(elem, addNonG)
|
|
385
|
+
} else if (type === 'fill') {
|
|
386
|
+
if (elem.tagName !== 'polyline' && elem.tagName !== 'line') {
|
|
387
|
+
elems.push(elem)
|
|
388
|
+
}
|
|
389
|
+
} else {
|
|
390
|
+
elems.push(elem)
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (elems.length > 0) {
|
|
395
|
+
if (!preventUndo) {
|
|
396
|
+
svgCanvas.changeSelectedAttribute(type, val, elems)
|
|
397
|
+
svgCanvas.call('changed', elems)
|
|
398
|
+
} else {
|
|
399
|
+
svgCanvas.changeSelectedAttributeNoUndo(type, val, elems)
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Apply the current gradient to selected element's fill or stroke.
|
|
406
|
+
* @function module:elem-get-set.SvgCanvas#setGradient
|
|
407
|
+
* @param {"fill"|"stroke"} type - String indicating "fill" or "stroke" to apply to an element
|
|
408
|
+
* @returns {void}
|
|
409
|
+
*/
|
|
410
|
+
const setGradientMethod = (type) => {
|
|
411
|
+
if (!svgCanvas.getCurProperties(type + '_paint') ||
|
|
412
|
+
svgCanvas.getCurProperties(type + '_paint').type === 'solidColor') { return }
|
|
413
|
+
const canvas = svgCanvas
|
|
414
|
+
let grad = canvas[type + 'Grad']
|
|
415
|
+
// find out if there is a duplicate gradient already in the defs
|
|
416
|
+
const duplicateGrad = findDuplicateGradient(grad)
|
|
417
|
+
const defs = findDefs()
|
|
418
|
+
// no duplicate found, so import gradient into defs
|
|
419
|
+
if (!duplicateGrad) {
|
|
420
|
+
// const origGrad = grad;
|
|
421
|
+
grad = svgCanvas.getDOMDocument().importNode(grad, true)
|
|
422
|
+
defs.append(grad)
|
|
423
|
+
// get next id and set it on the grad
|
|
424
|
+
grad.id = svgCanvas.getNextId()
|
|
425
|
+
} else { // use existing gradient
|
|
426
|
+
grad = duplicateGrad
|
|
427
|
+
}
|
|
428
|
+
svgCanvas.setColor(type, 'url(#' + grad.id + ')')
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Check if exact gradient already exists.
|
|
433
|
+
* @function module:svgcanvas~findDuplicateGradient
|
|
434
|
+
* @param {SVGGradientElement} grad - The gradient DOM element to compare to others
|
|
435
|
+
* @returns {SVGGradientElement} The existing gradient if found, `null` if not
|
|
436
|
+
*/
|
|
437
|
+
const findDuplicateGradient = (grad) => {
|
|
438
|
+
const defs = findDefs()
|
|
439
|
+
const existingGrads = defs.querySelectorAll('linearGradient, radialGradient')
|
|
440
|
+
let i = existingGrads.length
|
|
441
|
+
const radAttrs = ['r', 'cx', 'cy', 'fx', 'fy']
|
|
442
|
+
while (i--) {
|
|
443
|
+
const og = existingGrads[i]
|
|
444
|
+
if (grad.tagName === 'linearGradient') {
|
|
445
|
+
if (grad.getAttribute('x1') !== og.getAttribute('x1') ||
|
|
446
|
+
grad.getAttribute('y1') !== og.getAttribute('y1') ||
|
|
447
|
+
grad.getAttribute('x2') !== og.getAttribute('x2') ||
|
|
448
|
+
grad.getAttribute('y2') !== og.getAttribute('y2')
|
|
449
|
+
) {
|
|
450
|
+
continue
|
|
451
|
+
}
|
|
452
|
+
} else {
|
|
453
|
+
const gradAttrs = {
|
|
454
|
+
r: Number(grad.getAttribute('r')),
|
|
455
|
+
cx: Number(grad.getAttribute('cx')),
|
|
456
|
+
cy: Number(grad.getAttribute('cy')),
|
|
457
|
+
fx: Number(grad.getAttribute('fx')),
|
|
458
|
+
fy: Number(grad.getAttribute('fy'))
|
|
459
|
+
}
|
|
460
|
+
const ogAttrs = {
|
|
461
|
+
r: Number(og.getAttribute('r')),
|
|
462
|
+
cx: Number(og.getAttribute('cx')),
|
|
463
|
+
cy: Number(og.getAttribute('cy')),
|
|
464
|
+
fx: Number(og.getAttribute('fx')),
|
|
465
|
+
fy: Number(og.getAttribute('fy'))
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
let diff = false
|
|
469
|
+
radAttrs.forEach((attr) => {
|
|
470
|
+
if (gradAttrs[attr] !== ogAttrs[attr]) { diff = true }
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
if (diff) { continue }
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// else could be a duplicate, iterate through stops
|
|
477
|
+
const stops = grad.getElementsByTagNameNS(NS.SVG, 'stop')
|
|
478
|
+
const ostops = og.getElementsByTagNameNS(NS.SVG, 'stop')
|
|
479
|
+
|
|
480
|
+
if (stops.length !== ostops.length) {
|
|
481
|
+
continue
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
let j = stops.length
|
|
485
|
+
while (j--) {
|
|
486
|
+
const stop = stops[j]
|
|
487
|
+
const ostop = ostops[j]
|
|
488
|
+
|
|
489
|
+
if (stop.getAttribute('offset') !== ostop.getAttribute('offset') ||
|
|
490
|
+
stop.getAttribute('stop-opacity') !== ostop.getAttribute('stop-opacity') ||
|
|
491
|
+
stop.getAttribute('stop-color') !== ostop.getAttribute('stop-color')) {
|
|
492
|
+
break
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (j === -1) {
|
|
497
|
+
return og
|
|
498
|
+
}
|
|
499
|
+
} // for each gradient in defs
|
|
500
|
+
|
|
501
|
+
return null
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Set a color/gradient to a fill/stroke.
|
|
506
|
+
* @function module:elem-get-set.SvgCanvas#setPaint
|
|
507
|
+
* @param {"fill"|"stroke"} type - String with "fill" or "stroke"
|
|
508
|
+
* @param {} paint - The paint object to apply
|
|
509
|
+
* @returns {void}
|
|
510
|
+
*/
|
|
511
|
+
const setPaintMethod = (type, paint) => {
|
|
512
|
+
// make a copy
|
|
513
|
+
const p = new Paint(paint)
|
|
514
|
+
svgCanvas.setPaintOpacity(type, p.alpha / 100, true)
|
|
515
|
+
|
|
516
|
+
// now set the current paint object
|
|
517
|
+
svgCanvas.setCurProperties(type + '_paint', p)
|
|
518
|
+
switch (p.type) {
|
|
519
|
+
case 'solidColor':
|
|
520
|
+
svgCanvas.setColor(type, p.solidColor !== 'none' ? '#' + p.solidColor : 'none')
|
|
521
|
+
break
|
|
522
|
+
case 'linearGradient':
|
|
523
|
+
case 'radialGradient':
|
|
524
|
+
svgCanvas.setCanvas(type + 'Grad', p[p.type])
|
|
525
|
+
svgCanvas.setGradient(type)
|
|
526
|
+
break
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Sets the stroke width for the current selected elements.
|
|
531
|
+
* When attempting to set a line's width to 0, this changes it to 1 instead.
|
|
532
|
+
* @function module:elem-get-set.SvgCanvas#setStrokeWidth
|
|
533
|
+
* @param {Float} val - A Float indicating the new stroke width value
|
|
534
|
+
* @fires module:elem-get-set.SvgCanvas#event:changed
|
|
535
|
+
* @returns {void}
|
|
536
|
+
*/
|
|
537
|
+
const setStrokeWidthMethod = (val) => {
|
|
538
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
539
|
+
if (val === 0 && ['line', 'path'].includes(svgCanvas.getMode())) {
|
|
540
|
+
svgCanvas.setStrokeWidth(1)
|
|
541
|
+
return
|
|
542
|
+
}
|
|
543
|
+
svgCanvas.setCurProperties('stroke_width', val)
|
|
544
|
+
|
|
545
|
+
const elems = []
|
|
546
|
+
/**
|
|
547
|
+
*
|
|
548
|
+
* @param {Element} e
|
|
549
|
+
* @returns {void}
|
|
550
|
+
*/
|
|
551
|
+
const addNonG = (e) => {
|
|
552
|
+
if (e.nodeName !== 'g') {
|
|
553
|
+
elems.push(e)
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
let i = selectedElements.length
|
|
557
|
+
while (i--) {
|
|
558
|
+
const elem = selectedElements[i]
|
|
559
|
+
if (elem) {
|
|
560
|
+
if (elem.tagName === 'g') {
|
|
561
|
+
walkTree(elem, addNonG)
|
|
562
|
+
} else {
|
|
563
|
+
elems.push(elem)
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (elems.length > 0) {
|
|
568
|
+
svgCanvas.changeSelectedAttribute('stroke-width', val, elems)
|
|
569
|
+
svgCanvas.call('changed', selectedElements)
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Set the given stroke-related attribute the given value for selected elements.
|
|
575
|
+
* @function module:elem-get-set.SvgCanvas#setStrokeAttr
|
|
576
|
+
* @param {string} attr - String with the attribute name
|
|
577
|
+
* @param {string|Float} val - String or number with the attribute value
|
|
578
|
+
* @fires module:elem-get-set.SvgCanvas#event:changed
|
|
579
|
+
* @returns {void}
|
|
580
|
+
*/
|
|
581
|
+
const setStrokeAttrMethod = (attr, val) => {
|
|
582
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
583
|
+
svgCanvas.setCurShape(attr.replace('-', '_'), val)
|
|
584
|
+
const elems = []
|
|
585
|
+
|
|
586
|
+
let i = selectedElements.length
|
|
587
|
+
while (i--) {
|
|
588
|
+
const elem = selectedElements[i]
|
|
589
|
+
if (elem) {
|
|
590
|
+
if (elem.tagName === 'g') {
|
|
591
|
+
walkTree(elem, (e) => { if (e.nodeName !== 'g') { elems.push(e) } })
|
|
592
|
+
} else {
|
|
593
|
+
elems.push(elem)
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
if (elems.length > 0) {
|
|
598
|
+
svgCanvas.changeSelectedAttribute(attr, val, elems)
|
|
599
|
+
svgCanvas.call('changed', selectedElements)
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Check whether selected element is bold or not.
|
|
604
|
+
* @function module:svgcanvas.SvgCanvas#getBold
|
|
605
|
+
* @returns {boolean} Indicates whether or not element is bold
|
|
606
|
+
*/
|
|
607
|
+
const getBoldMethod = () => {
|
|
608
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
609
|
+
// should only have one element selected
|
|
610
|
+
const selected = selectedElements[0]
|
|
611
|
+
if (selected?.tagName === 'text' &&
|
|
612
|
+
!selectedElements[1]) {
|
|
613
|
+
return (selected.getAttribute('font-weight') === 'bold')
|
|
614
|
+
}
|
|
615
|
+
return false
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Make the selected element bold or normal.
|
|
620
|
+
* @function module:svgcanvas.SvgCanvas#setBold
|
|
621
|
+
* @param {boolean} b - Indicates bold (`true`) or normal (`false`)
|
|
622
|
+
* @returns {void}
|
|
623
|
+
*/
|
|
624
|
+
const setBoldMethod = (b) => {
|
|
625
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
626
|
+
const selected = selectedElements[0]
|
|
627
|
+
if (selected?.tagName === 'text' &&
|
|
628
|
+
!selectedElements[1]) {
|
|
629
|
+
svgCanvas.changeSelectedAttribute('font-weight', b ? 'bold' : 'normal')
|
|
630
|
+
}
|
|
631
|
+
if (!selectedElements[0].textContent) {
|
|
632
|
+
svgCanvas.textActions.setCursor()
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Check whether selected element has the given text decoration value or not.
|
|
638
|
+
* @returns {boolean} Indicates whether or not element has the text decoration value
|
|
639
|
+
*/
|
|
640
|
+
const hasTextDecorationMethod = (value) => {
|
|
641
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
642
|
+
const selected = selectedElements[0]
|
|
643
|
+
|
|
644
|
+
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
|
645
|
+
const attribute = selected.getAttribute('text-decoration') || ''
|
|
646
|
+
return attribute.includes(value)
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
return false
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Adds the given text decoration value
|
|
654
|
+
* @param value The text decoration value
|
|
655
|
+
* @returns {void}
|
|
656
|
+
*/
|
|
657
|
+
const addTextDecorationMethod = (value) => {
|
|
658
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
659
|
+
const selected = selectedElements[0]
|
|
660
|
+
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
|
661
|
+
const oldValue = selected.getAttribute('text-decoration') || ''
|
|
662
|
+
svgCanvas.changeSelectedAttribute('text-decoration', (oldValue + ' ' + value).trim())
|
|
663
|
+
}
|
|
664
|
+
if (selectedElements.length > 0 && !selectedElements[0].textContent) {
|
|
665
|
+
svgCanvas.textActions.setCursor()
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Removes the given text decoration value
|
|
671
|
+
* @param value The text decoration value
|
|
672
|
+
* @returns {void}
|
|
673
|
+
*/
|
|
674
|
+
const removeTextDecorationMethod = (value) => {
|
|
675
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
676
|
+
const selected = selectedElements[0]
|
|
677
|
+
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
|
678
|
+
const actualValues = selected.getAttribute('text-decoration') || ''
|
|
679
|
+
svgCanvas.changeSelectedAttribute('text-decoration', actualValues.replace(value, '').trim())
|
|
680
|
+
}
|
|
681
|
+
if (selectedElements.length > 0 && !selectedElements[0].textContent) {
|
|
682
|
+
svgCanvas.textActions.setCursor()
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Check whether selected element is in italics or not.
|
|
688
|
+
* @function module:svgcanvas.SvgCanvas#getItalic
|
|
689
|
+
* @returns {boolean} Indicates whether or not element is italic
|
|
690
|
+
*/
|
|
691
|
+
const getItalicMethod = () => {
|
|
692
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
693
|
+
const selected = selectedElements[0]
|
|
694
|
+
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
|
695
|
+
return (selected.getAttribute('font-style') === 'italic')
|
|
696
|
+
}
|
|
697
|
+
return false
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Make the selected element italic or normal.
|
|
702
|
+
* @function module:svgcanvas.SvgCanvas#setItalic
|
|
703
|
+
* @param {boolean} i - Indicates italic (`true`) or normal (`false`)
|
|
704
|
+
* @returns {void}
|
|
705
|
+
*/
|
|
706
|
+
const setItalicMethod = (i) => {
|
|
707
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
708
|
+
const selected = selectedElements[0]
|
|
709
|
+
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
|
710
|
+
svgCanvas.changeSelectedAttribute('font-style', i ? 'italic' : 'normal')
|
|
711
|
+
}
|
|
712
|
+
if (!selectedElements[0].textContent) {
|
|
713
|
+
svgCanvas.textActions.setCursor()
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* @function module:svgcanvas.SvgCanvas#setTextAnchorMethod Set the new text anchor
|
|
719
|
+
* @param {string} value - The text anchor value (start, middle or end)
|
|
720
|
+
* @returns {void}
|
|
721
|
+
*/
|
|
722
|
+
const setTextAnchorMethod = (value) => {
|
|
723
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
724
|
+
const selected = selectedElements[0]
|
|
725
|
+
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
|
726
|
+
svgCanvas.changeSelectedAttribute('text-anchor', value)
|
|
727
|
+
}
|
|
728
|
+
if (selectedElements.length > 0 && !selectedElements[0].textContent) {
|
|
729
|
+
svgCanvas.textActions.setCursor()
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* @function module:svgcanvas.SvgCanvas#setLetterSpacingMethod Set the new letter spacing
|
|
735
|
+
* @param {string} value - The letter spacing value
|
|
736
|
+
* @returns {void}
|
|
737
|
+
*/
|
|
738
|
+
const setLetterSpacingMethod = (value) => {
|
|
739
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
740
|
+
const selected = selectedElements[0]
|
|
741
|
+
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
|
742
|
+
svgCanvas.changeSelectedAttribute('letter-spacing', value)
|
|
743
|
+
}
|
|
744
|
+
if (selectedElements.length > 0 && !selectedElements[0].textContent) {
|
|
745
|
+
svgCanvas.textActions.setCursor()
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* @function module:svgcanvas.SvgCanvas#setWordSpacingMethod Set the new word spacing
|
|
751
|
+
* @param {string} value - The word spacing value
|
|
752
|
+
* @returns {void}
|
|
753
|
+
*/
|
|
754
|
+
const setWordSpacingMethod = (value) => {
|
|
755
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
756
|
+
const selected = selectedElements[0]
|
|
757
|
+
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
|
758
|
+
svgCanvas.changeSelectedAttribute('word-spacing', value)
|
|
759
|
+
}
|
|
760
|
+
if (selectedElements.length > 0 && !selectedElements[0].textContent) {
|
|
761
|
+
svgCanvas.textActions.setCursor()
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* @function module:svgcanvas.SvgCanvas#setTextLengthMethod Set the new text length
|
|
767
|
+
* @param {string} value - The text length value
|
|
768
|
+
* @returns {void}
|
|
769
|
+
*/
|
|
770
|
+
const setTextLengthMethod = (value) => {
|
|
771
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
772
|
+
const selected = selectedElements[0]
|
|
773
|
+
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
|
774
|
+
svgCanvas.changeSelectedAttribute('textLength', value)
|
|
775
|
+
}
|
|
776
|
+
if (selectedElements.length > 0 && !selectedElements[0].textContent) {
|
|
777
|
+
svgCanvas.textActions.setCursor()
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* @function module:svgcanvas.SvgCanvas#setLengthAdjustMethod Set the new length adjust
|
|
783
|
+
* @param {string} value - The length adjust value
|
|
784
|
+
* @returns {void}
|
|
785
|
+
*/
|
|
786
|
+
const setLengthAdjustMethod = (value) => {
|
|
787
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
788
|
+
const selected = selectedElements[0]
|
|
789
|
+
if (selected?.tagName === 'text' && !selectedElements[1]) {
|
|
790
|
+
svgCanvas.changeSelectedAttribute('lengthAdjust', value)
|
|
791
|
+
}
|
|
792
|
+
if (selectedElements.length > 0 && !selectedElements[0].textContent) {
|
|
793
|
+
svgCanvas.textActions.setCursor()
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* @function module:svgcanvas.SvgCanvas#getFontFamily
|
|
799
|
+
* @returns {string} The current font family
|
|
800
|
+
*/
|
|
801
|
+
const getFontFamilyMethod = () => {
|
|
802
|
+
return svgCanvas.getCurText('font_family')
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Set the new font family.
|
|
807
|
+
* @function module:svgcanvas.SvgCanvas#setFontFamily
|
|
808
|
+
* @param {string} val - String with the new font family
|
|
809
|
+
* @returns {void}
|
|
810
|
+
*/
|
|
811
|
+
const setFontFamilyMethod = (val) => {
|
|
812
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
813
|
+
svgCanvas.setCurText('font_family', val)
|
|
814
|
+
svgCanvas.changeSelectedAttribute('font-family', val)
|
|
815
|
+
if (!selectedElements[0]?.textContent) {
|
|
816
|
+
svgCanvas.textActions.setCursor()
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Set the new font color.
|
|
822
|
+
* @function module:svgcanvas.SvgCanvas#setFontColor
|
|
823
|
+
* @param {string} val - String with the new font color
|
|
824
|
+
* @returns {void}
|
|
825
|
+
*/
|
|
826
|
+
const setFontColorMethod = (val) => {
|
|
827
|
+
svgCanvas.setCurText('fill', val)
|
|
828
|
+
svgCanvas.changeSelectedAttribute('fill', val)
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* @function module:svgcanvas.SvgCanvas#getFontColor
|
|
833
|
+
* @returns {string} The current font color
|
|
834
|
+
*/
|
|
835
|
+
const getFontColorMethod = () => {
|
|
836
|
+
return svgCanvas.getCurText('fill')
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* @function module:svgcanvas.SvgCanvas#getFontSize
|
|
841
|
+
* @returns {Float} The current font size
|
|
842
|
+
*/
|
|
843
|
+
const getFontSizeMethod = () => {
|
|
844
|
+
return svgCanvas.getCurText('font_size')
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Applies the given font size to the selected element.
|
|
849
|
+
* @function module:svgcanvas.SvgCanvas#setFontSize
|
|
850
|
+
* @param {Float} val - Float with the new font size
|
|
851
|
+
* @returns {void}
|
|
852
|
+
*/
|
|
853
|
+
const setFontSizeMethod = (val) => {
|
|
854
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
855
|
+
svgCanvas.setCurText('font_size', val)
|
|
856
|
+
svgCanvas.changeSelectedAttribute('font-size', val)
|
|
857
|
+
if (!selectedElements[0]?.textContent) {
|
|
858
|
+
svgCanvas.textActions.setCursor()
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* @function module:svgcanvas.SvgCanvas#getText
|
|
864
|
+
* @returns {string} The current text (`textContent`) of the selected element
|
|
865
|
+
*/
|
|
866
|
+
const getTextMethod = () => {
|
|
867
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
868
|
+
const selected = selectedElements[0]
|
|
869
|
+
return (selected) ? selected.textContent : ''
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* Updates the text element with the given string.
|
|
874
|
+
* @function module:svgcanvas.SvgCanvas#setTextContent
|
|
875
|
+
* @param {string} val - String with the new text
|
|
876
|
+
* @returns {void}
|
|
877
|
+
*/
|
|
878
|
+
const setTextContentMethod = (val) => {
|
|
879
|
+
svgCanvas.changeSelectedAttribute('#text', val)
|
|
880
|
+
svgCanvas.textActions.init(val)
|
|
881
|
+
svgCanvas.textActions.setCursor()
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* Sets the new image URL for the selected image element. Updates its size if
|
|
886
|
+
* a new URL is given.
|
|
887
|
+
* @function module:svgcanvas.SvgCanvas#setImageURL
|
|
888
|
+
* @param {string} val - String with the image URL/path
|
|
889
|
+
* @fires module:svgcanvas.SvgCanvas#event:changed
|
|
890
|
+
* @returns {void}
|
|
891
|
+
*/
|
|
892
|
+
const setImageURLMethod = (val) => {
|
|
893
|
+
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
|
894
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
895
|
+
const elem = selectedElements[0]
|
|
896
|
+
if (!elem) { return }
|
|
897
|
+
|
|
898
|
+
const attrs = {
|
|
899
|
+
width: elem.getAttribute('width'),
|
|
900
|
+
height: elem.getAttribute('height')
|
|
901
|
+
}
|
|
902
|
+
const setsize = (!attrs.width || !attrs.height)
|
|
903
|
+
|
|
904
|
+
const curHref = getHref(elem)
|
|
905
|
+
|
|
906
|
+
// Do nothing if no URL change or size change
|
|
907
|
+
if (curHref === val && !setsize) {
|
|
908
|
+
return
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
const batchCmd = new BatchCommand('Change Image URL')
|
|
912
|
+
|
|
913
|
+
setHref(elem, val)
|
|
914
|
+
batchCmd.addSubCommand(new ChangeElementCommand(elem, {
|
|
915
|
+
'#href': curHref
|
|
916
|
+
}))
|
|
917
|
+
const img = new Image()
|
|
918
|
+
img.onload = function () {
|
|
919
|
+
const changes = {
|
|
920
|
+
width: elem.getAttribute('width'),
|
|
921
|
+
height: elem.getAttribute('height')
|
|
922
|
+
}
|
|
923
|
+
elem.setAttribute('width', this.width)
|
|
924
|
+
elem.setAttribute('height', this.height)
|
|
925
|
+
|
|
926
|
+
svgCanvas.selectorManager.requestSelector(elem).resize()
|
|
927
|
+
|
|
928
|
+
batchCmd.addSubCommand(new ChangeElementCommand(elem, changes))
|
|
929
|
+
svgCanvas.addCommandToHistory(batchCmd)
|
|
930
|
+
svgCanvas.call('changed', [elem])
|
|
931
|
+
}
|
|
932
|
+
img.src = val
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* Sets the new link URL for the selected anchor element.
|
|
937
|
+
* @function module:svgcanvas.SvgCanvas#setLinkURL
|
|
938
|
+
* @param {string} val - String with the link URL/path
|
|
939
|
+
* @returns {void}
|
|
940
|
+
*/
|
|
941
|
+
const setLinkURLMethod = (val) => {
|
|
942
|
+
const { ChangeElementCommand, BatchCommand } = svgCanvas.history
|
|
943
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
944
|
+
let elem = selectedElements[0]
|
|
945
|
+
if (!elem) { return }
|
|
946
|
+
if (elem.tagName !== 'a') {
|
|
947
|
+
// See if parent is an anchor
|
|
948
|
+
const parentsA = getParents(elem.parentNode, 'a')
|
|
949
|
+
if (parentsA?.length) {
|
|
950
|
+
elem = parentsA[0]
|
|
951
|
+
} else {
|
|
952
|
+
return
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
const curHref = getHref(elem)
|
|
957
|
+
|
|
958
|
+
if (curHref === val) { return }
|
|
959
|
+
|
|
960
|
+
const batchCmd = new BatchCommand('Change Link URL')
|
|
961
|
+
|
|
962
|
+
setHref(elem, val)
|
|
963
|
+
batchCmd.addSubCommand(new ChangeElementCommand(elem, {
|
|
964
|
+
'#href': curHref
|
|
965
|
+
}))
|
|
966
|
+
|
|
967
|
+
svgCanvas.addCommandToHistory(batchCmd)
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* Sets the `rx` and `ry` values to the selected `rect` element
|
|
972
|
+
* to change its corner radius.
|
|
973
|
+
* @function module:svgcanvas.SvgCanvas#setRectRadius
|
|
974
|
+
* @param {string|Float} val - The new radius
|
|
975
|
+
* @fires module:svgcanvas.SvgCanvas#event:changed
|
|
976
|
+
* @returns {void}
|
|
977
|
+
*/
|
|
978
|
+
const setRectRadiusMethod = (val) => {
|
|
979
|
+
const { ChangeElementCommand } = svgCanvas.history
|
|
980
|
+
const selectedElements = svgCanvas.getSelectedElements()
|
|
981
|
+
const selected = selectedElements[0]
|
|
982
|
+
if (selected?.tagName === 'rect') {
|
|
983
|
+
const r = Number(selected.getAttribute('rx'))
|
|
984
|
+
if (r !== val) {
|
|
985
|
+
selected.setAttribute('rx', val)
|
|
986
|
+
selected.setAttribute('ry', val)
|
|
987
|
+
svgCanvas.addCommandToHistory(new ChangeElementCommand(selected, { rx: r, ry: r }, 'Radius'))
|
|
988
|
+
svgCanvas.call('changed', [selected])
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
/**
|
|
994
|
+
* Wraps the selected element(s) in an anchor element or converts group to one.
|
|
995
|
+
* @function module:svgcanvas.SvgCanvas#makeHyperlink
|
|
996
|
+
* @param {string} url
|
|
997
|
+
* @returns {void}
|
|
998
|
+
*/
|
|
999
|
+
const makeHyperlinkMethod = (url) => {
|
|
1000
|
+
svgCanvas.groupSelectedElements('a', url)
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* @function module:svgcanvas.SvgCanvas#removeHyperlink
|
|
1005
|
+
* @returns {void}
|
|
1006
|
+
*/
|
|
1007
|
+
const removeHyperlinkMethod = () => {
|
|
1008
|
+
svgCanvas.ungroupSelectedElement()
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
/**
|
|
1012
|
+
* Group: Element manipulation.
|
|
1013
|
+
*/
|
|
1014
|
+
|
|
1015
|
+
/**
|
|
1016
|
+
* Sets the new segment type to the selected segment(s).
|
|
1017
|
+
* @function module:svgcanvas.SvgCanvas#setSegType
|
|
1018
|
+
* @param {Integer} newType - New segment type. See {@link https://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg} for list
|
|
1019
|
+
* @returns {void}
|
|
1020
|
+
*/
|
|
1021
|
+
const setSegTypeMethod = (newType) => {
|
|
1022
|
+
svgCanvas.pathActions.setSegType(newType)
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Set the background of the editor (NOT the actual document).
|
|
1027
|
+
* @function module:svgcanvas.SvgCanvas#setBackground
|
|
1028
|
+
* @param {string} color - String with fill color to apply
|
|
1029
|
+
* @param {string} url - URL or path to image to use
|
|
1030
|
+
* @returns {void}
|
|
1031
|
+
*/
|
|
1032
|
+
const setBackgroundMethod = (color, url) => {
|
|
1033
|
+
const bg = getElement('canvasBackground')
|
|
1034
|
+
const border = bg.querySelector('rect')
|
|
1035
|
+
let bgImg = getElement('background_image')
|
|
1036
|
+
let bgPattern = getElement('background_pattern')
|
|
1037
|
+
border.setAttribute('fill', color === 'chessboard' ? '#fff' : color)
|
|
1038
|
+
if (color === 'chessboard') {
|
|
1039
|
+
if (!bgPattern) {
|
|
1040
|
+
bgPattern = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'foreignObject')
|
|
1041
|
+
svgCanvas.assignAttributes(bgPattern, {
|
|
1042
|
+
id: 'background_pattern',
|
|
1043
|
+
width: '100%',
|
|
1044
|
+
height: '100%',
|
|
1045
|
+
preserveAspectRatio: 'xMinYMin',
|
|
1046
|
+
style: 'pointer-events:none'
|
|
1047
|
+
})
|
|
1048
|
+
const div = document.createElement('div')
|
|
1049
|
+
svgCanvas.assignAttributes(div, {
|
|
1050
|
+
style: 'pointer-events:none;width:100%;height:100%;' +
|
|
1051
|
+
'background-image:url(data:image/gif;base64,' +
|
|
1052
|
+
'R0lGODlhEAAQAIAAAP///9bW1iH5BAAAAAAALAAAAAAQABAAAAIfjG+' +
|
|
1053
|
+
'gq4jM3IFLJgpswNly/XkcBpIiVaInlLJr9FZWAQA7);'
|
|
1054
|
+
})
|
|
1055
|
+
bgPattern.append(div)
|
|
1056
|
+
bg.append(bgPattern)
|
|
1057
|
+
}
|
|
1058
|
+
} else if (bgPattern) {
|
|
1059
|
+
bgPattern.remove()
|
|
1060
|
+
}
|
|
1061
|
+
if (url) {
|
|
1062
|
+
if (!bgImg) {
|
|
1063
|
+
bgImg = svgCanvas.getDOMDocument().createElementNS(NS.SVG, 'image')
|
|
1064
|
+
svgCanvas.assignAttributes(bgImg, {
|
|
1065
|
+
id: 'background_image',
|
|
1066
|
+
width: '100%',
|
|
1067
|
+
height: '100%',
|
|
1068
|
+
preserveAspectRatio: 'xMinYMin',
|
|
1069
|
+
style: 'pointer-events:none'
|
|
1070
|
+
})
|
|
1071
|
+
}
|
|
1072
|
+
setHref(bgImg, url)
|
|
1073
|
+
bg.append(bgImg)
|
|
1074
|
+
} else if (bgImg) {
|
|
1075
|
+
bgImg.remove()
|
|
1076
|
+
}
|
|
1077
|
+
}
|