@svgedit/svgcanvas 7.2.7 → 7.4.2
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/common/browser.js +104 -37
- package/common/logger.js +151 -0
- package/common/util.js +96 -155
- package/core/blur-event.js +106 -42
- package/core/clear.js +13 -3
- package/core/coords.js +214 -90
- package/core/copy-elem.js +27 -13
- package/core/dataStorage.js +84 -21
- package/core/draw.js +80 -40
- package/core/elem-get-set.js +247 -115
- package/core/event.js +171 -29
- package/core/history.js +105 -50
- package/core/historyrecording.js +4 -2
- package/core/json.js +54 -12
- package/core/layer.js +11 -17
- package/core/math.js +102 -23
- package/core/namespaces.js +5 -5
- package/core/paint.js +95 -24
- package/core/paste-elem.js +58 -19
- package/core/path-actions.js +812 -791
- package/core/path-method.js +236 -37
- package/core/path.js +45 -10
- package/core/recalculate.js +410 -15
- package/core/sanitize.js +51 -18
- package/core/select.js +44 -20
- package/core/selected-elem.js +159 -38
- package/core/selection.js +16 -6
- package/core/svg-exec.js +99 -27
- package/core/svgroot.js +1 -1
- package/core/text-actions.js +363 -307
- package/core/undo.js +47 -15
- package/core/units.js +8 -6
- package/core/utilities.js +282 -170
- package/dist/svgcanvas.js +40021 -55172
- package/dist/svgcanvas.js.map +1 -1
- package/package.json +55 -54
- package/publish.md +1 -6
- package/svgcanvas.d.ts +225 -0
- package/svgcanvas.js +11 -9
- package/vite.config.mjs +20 -0
- package/rollup.config.mjs +0 -38
package/core/undo.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as draw from './draw.js'
|
|
8
8
|
import * as hstry from './history.js'
|
|
9
|
+
import { BBOX_AFFECTING_ATTRS } from './history.js'
|
|
9
10
|
import {
|
|
10
11
|
getRotationAngle, getBBox as utilsGetBBox, setHref, getStrokedBBoxDefaultVisible
|
|
11
12
|
} from './utilities.js'
|
|
@@ -46,11 +47,26 @@ export const getUndoManager = () => {
|
|
|
46
47
|
if (eventType === EventTypes.BEFORE_UNAPPLY || eventType === EventTypes.BEFORE_APPLY) {
|
|
47
48
|
svgCanvas.clearSelection()
|
|
48
49
|
} else if (eventType === EventTypes.AFTER_APPLY || eventType === EventTypes.AFTER_UNAPPLY) {
|
|
50
|
+
const cmdType = cmd.type()
|
|
51
|
+
const isApply = (eventType === EventTypes.AFTER_APPLY)
|
|
52
|
+
if (cmdType === 'ChangeElementCommand' && cmd.elem === svgCanvas.getSvgContent()) {
|
|
53
|
+
const values = isApply ? cmd.newValues : cmd.oldValues
|
|
54
|
+
if (values.width !== null && values.width !== undefined && values.width !== '') {
|
|
55
|
+
const newContentW = Number(values.width)
|
|
56
|
+
if (Number.isFinite(newContentW) && newContentW > 0) {
|
|
57
|
+
svgCanvas.contentW = newContentW
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (values.height !== null && values.height !== undefined && values.height !== '') {
|
|
61
|
+
const newContentH = Number(values.height)
|
|
62
|
+
if (Number.isFinite(newContentH) && newContentH > 0) {
|
|
63
|
+
svgCanvas.contentH = newContentH
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
49
67
|
const elems = cmd.elements()
|
|
50
68
|
svgCanvas.pathActions.clear()
|
|
51
69
|
svgCanvas.call('changed', elems)
|
|
52
|
-
const cmdType = cmd.type()
|
|
53
|
-
const isApply = (eventType === EventTypes.AFTER_APPLY)
|
|
54
70
|
if (cmdType === 'MoveElementCommand') {
|
|
55
71
|
const parent = isApply ? cmd.newParent : cmd.oldParent
|
|
56
72
|
if (parent === svgCanvas.getSvgContent()) {
|
|
@@ -116,7 +132,7 @@ export const getUndoManager = () => {
|
|
|
116
132
|
* @param {Element} elem - The (text) DOM element to clone
|
|
117
133
|
* @returns {Element} Cloned element
|
|
118
134
|
*/
|
|
119
|
-
export const ffClone =
|
|
135
|
+
export const ffClone = (elem) => {
|
|
120
136
|
if (!isGecko()) { return elem }
|
|
121
137
|
const clone = elem.cloneNode(true)
|
|
122
138
|
elem.before(clone)
|
|
@@ -189,7 +205,10 @@ export const changeSelectedAttributeNoUndoMethod = (attr, newValue, elems) => {
|
|
|
189
205
|
} else if (attr === '#href') {
|
|
190
206
|
setHref(elem, newValue)
|
|
191
207
|
} else if (newValue) {
|
|
192
|
-
|
|
208
|
+
// Number(), unlike parseFloat(), rejects a value with a trailing unit suffix
|
|
209
|
+
// (e.g. "10pt", "2px") instead of silently truncating it to a bare number.
|
|
210
|
+
const asNumber = Number(newValue)
|
|
211
|
+
elem.setAttribute(attr, Number.isNaN(asNumber) ? newValue : asNumber)
|
|
193
212
|
} else if (typeof newValue === 'number') {
|
|
194
213
|
elem.setAttribute(attr, newValue)
|
|
195
214
|
} else {
|
|
@@ -213,7 +232,7 @@ export const changeSelectedAttributeNoUndoMethod = (attr, newValue, elems) => {
|
|
|
213
232
|
elem = ffClone(elem)
|
|
214
233
|
}
|
|
215
234
|
// Timeout needed for Opera & Firefox
|
|
216
|
-
// codedread: it is now possible for this
|
|
235
|
+
// codedread: it is now possible for this to be called with elements
|
|
217
236
|
// that are not in the selectedElements array, we need to only request a
|
|
218
237
|
// selector if the element is in that array
|
|
219
238
|
if (selectedElements.includes(elem)) {
|
|
@@ -224,26 +243,39 @@ export const changeSelectedAttributeNoUndoMethod = (attr, newValue, elems) => {
|
|
|
224
243
|
svgCanvas.selectorManager.requestSelector(elem).resize()
|
|
225
244
|
}, 0)
|
|
226
245
|
}
|
|
227
|
-
//
|
|
228
|
-
//
|
|
246
|
+
// Only recalculate rotation center for attributes that change element geometry.
|
|
247
|
+
// Non-geometric attributes (stroke-width, fill, opacity, etc.) don't affect
|
|
248
|
+
// the bbox center, so the rotation is already correct and must not be touched.
|
|
249
|
+
// BBOX_AFFECTING_ATTRS is imported from history.js to keep the list in one place.
|
|
229
250
|
const angle = getRotationAngle(elem)
|
|
230
|
-
if (angle !== 0 && attr !== 'transform') {
|
|
251
|
+
if (angle !== 0 && attr !== 'transform' && BBOX_AFFECTING_ATTRS.has(attr)) {
|
|
231
252
|
const tlist = getTransformList(elem)
|
|
232
253
|
let n = tlist.numberOfItems
|
|
233
254
|
while (n--) {
|
|
234
255
|
const xform = tlist.getItem(n)
|
|
235
256
|
if (xform.type === 4) {
|
|
236
|
-
//
|
|
257
|
+
// Compute bbox BEFORE removing the rotation so we can bail out
|
|
258
|
+
// safely if getBBox returns nothing (avoids losing the rotation).
|
|
259
|
+
const box = utilsGetBBox(elem)
|
|
260
|
+
if (!box) break
|
|
261
|
+
|
|
237
262
|
tlist.removeItem(n)
|
|
238
263
|
|
|
239
|
-
|
|
264
|
+
// Transform bbox center through only the transforms that come
|
|
265
|
+
// AFTER the rotation in the list (not the pre-rotation transforms).
|
|
266
|
+
// After removeItem(n), what was at n+1 is now at n.
|
|
267
|
+
let centerMatrix
|
|
268
|
+
if (n < tlist.numberOfItems) {
|
|
269
|
+
centerMatrix = transformListToTransform(tlist, n, tlist.numberOfItems - 1).matrix
|
|
270
|
+
} else {
|
|
271
|
+
centerMatrix = svgCanvas.getSvgRoot().createSVGMatrix() // identity
|
|
272
|
+
}
|
|
240
273
|
const center = transformPoint(
|
|
241
|
-
box.x + box.width / 2, box.y + box.height / 2,
|
|
274
|
+
box.x + box.width / 2, box.y + box.height / 2, centerMatrix
|
|
242
275
|
)
|
|
243
|
-
|
|
244
|
-
const cy = center.y
|
|
276
|
+
|
|
245
277
|
const newrot = svgCanvas.getSvgRoot().createSVGTransform()
|
|
246
|
-
newrot.setRotate(angle,
|
|
278
|
+
newrot.setRotate(angle, center.x, center.y)
|
|
247
279
|
tlist.insertItemBefore(newrot, n)
|
|
248
280
|
break
|
|
249
281
|
}
|
|
@@ -264,7 +296,7 @@ export const changeSelectedAttributeNoUndoMethod = (attr, newValue, elems) => {
|
|
|
264
296
|
* @param {Element[]} elems - The DOM elements to apply the change to
|
|
265
297
|
* @returns {void}
|
|
266
298
|
*/
|
|
267
|
-
export const changeSelectedAttributeMethod =
|
|
299
|
+
export const changeSelectedAttributeMethod = (attr, val, elems) => {
|
|
268
300
|
const selectedElements = svgCanvas.getSelectedElements()
|
|
269
301
|
elems = elems || selectedElements
|
|
270
302
|
svgCanvas.undoMgr.beginUndoableChange(attr, elems)
|
package/core/units.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* @copyright 2010 Alexis Deveria, 2010 Jeff Schiller
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { error } from '../common/logger.js'
|
|
10
|
+
|
|
9
11
|
const NSSVG = 'http://www.w3.org/2000/svg'
|
|
10
12
|
|
|
11
13
|
const wAttrs = ['x', 'x1', 'cx', 'rx', 'width']
|
|
@@ -62,7 +64,7 @@ let typeMap_ = {}
|
|
|
62
64
|
* @param {module:units.ElementContainer} elementContainer - An object implementing the ElementContainer interface.
|
|
63
65
|
* @returns {void}
|
|
64
66
|
*/
|
|
65
|
-
export const init =
|
|
67
|
+
export const init = (elementContainer) => {
|
|
66
68
|
elementContainer_ = elementContainer
|
|
67
69
|
|
|
68
70
|
// Get correct em/ex values by creating a temporary SVG.
|
|
@@ -124,7 +126,7 @@ export const shortFloat = (val) => {
|
|
|
124
126
|
return Number(Number(val).toFixed(digits))
|
|
125
127
|
}
|
|
126
128
|
if (Array.isArray(val)) {
|
|
127
|
-
return shortFloat(val[0])
|
|
129
|
+
return `${shortFloat(val[0])},${shortFloat(val[1])}`
|
|
128
130
|
}
|
|
129
131
|
return Number.parseFloat(val).toFixed(digits) - 0
|
|
130
132
|
}
|
|
@@ -214,8 +216,8 @@ export const convertToNum = (attr, val) => {
|
|
|
214
216
|
}
|
|
215
217
|
return num * Math.sqrt((width * width) + (height * height)) / Math.sqrt(2)
|
|
216
218
|
}
|
|
217
|
-
const unit = val.
|
|
218
|
-
const num = val.
|
|
219
|
+
const unit = val.slice(-2)
|
|
220
|
+
const num = val.slice(0, -2)
|
|
219
221
|
// Note that this multiplication turns the string into a number
|
|
220
222
|
return num * typeMap_[unit]
|
|
221
223
|
}
|
|
@@ -237,7 +239,7 @@ export const isValidUnit = (attr, val, selectedElement) => {
|
|
|
237
239
|
// Not a number, check if it has a valid unit
|
|
238
240
|
val = val.toLowerCase()
|
|
239
241
|
return Object.keys(typeMap_).some((unit) => {
|
|
240
|
-
const re = new RegExp(
|
|
242
|
+
const re = new RegExp(`^-?[\\d\\.]+${unit}$`)
|
|
241
243
|
return re.test(val)
|
|
242
244
|
})
|
|
243
245
|
}
|
|
@@ -253,7 +255,7 @@ export const isValidUnit = (attr, val, selectedElement) => {
|
|
|
253
255
|
try {
|
|
254
256
|
const elem = elementContainer_.getElement(val)
|
|
255
257
|
result = (!elem || elem === selectedElement)
|
|
256
|
-
} catch (e) {
|
|
258
|
+
} catch (e) { error('Error getting element by ID', e, 'units') }
|
|
257
259
|
return result
|
|
258
260
|
}
|
|
259
261
|
return true
|