remove svgtransform polyfill now widely supported

master
JFH 2021-08-29 14:16:03 +02:00
parent e2d91ea248
commit 0d2c344fee
22 changed files with 35 additions and 845 deletions

View File

@ -1,14 +1,10 @@
import { NS } from '../../../instrumented/common/namespaces.js';
import * as transformlist from '../../../instrumented/svgcanvas/svgtransformlist.js';
import * as utilities from '../../../instrumented/svgcanvas/utilities.js';
import * as hstory from '../../../instrumented/svgcanvas/history.js';
describe('history', function () {
// TODO(codedread): Write tests for handling history events.
// Mocked out methods.
transformlist.changeRemoveElementFromListMap(() => { /* empty fn */ });
utilities.mock({
getHref () { return '#foo'; },
setHref () { /* empty fn */ },

View File

@ -1,330 +0,0 @@
import { NS } from '../../../instrumented/common/namespaces.js';
import * as transformlist from '../../../instrumented/svgcanvas/svgtransformlist.js';
import { disableSupportsNativeTransformLists } from '../../../instrumented/common/browser.js';
import almostEqualsPlugin from '../../support/assert-almostEquals.js';
import expectOutOfBoundsExceptionPlugin from '../../support/assert-expectOutOfBoundsException.js';
chai.use(almostEqualsPlugin);
chai.use(expectOutOfBoundsExceptionPlugin);
describe('svgtransformlist', function () {
disableSupportsNativeTransformLists();
let svgroot; let svgcontent; let rect; let circle;
/**
* Set up tests, adding elements.
* @returns {void}
*/
beforeEach(() => {
document.body.textContent = '';
svgroot = document.createElement('div');
svgroot.id = 'svgroot';
svgroot.style.visibility = 'hidden';
document.body.append(svgroot);
svgcontent = document.createElementNS(NS.SVG, 'svg');
svgroot.append(svgcontent);
rect = document.createElementNS(NS.SVG, 'rect');
svgcontent.append(rect);
rect.id = 'r';
circle = document.createElementNS(NS.SVG, 'circle');
svgcontent.append(circle);
circle.id = 'c';
});
/**
* Tear down tests, emptying SVG root, and resetting list map.
* @returns {void}
*/
afterEach(() => {
transformlist.resetListMap();
while (svgroot.hasChildNodes()) {
svgroot.firstChild.remove();
}
});
it('Test svgedit.transformlist package', function () {
assert.ok(transformlist);
assert.ok(transformlist.getTransformList);
});
it('Test svgedit.transformlist.getTransformList() function', function () {
const rxform = transformlist.getTransformList(rect);
const cxform = transformlist.getTransformList(circle);
assert.ok(rxform);
assert.ok(cxform);
assert.equal(typeof rxform, typeof {});
assert.equal(typeof cxform, typeof {});
});
it('Test SVGTransformList.numberOfItems property', function () {
const rxform = transformlist.getTransformList(rect);
assert.equal(typeof rxform.numberOfItems, typeof 0);
assert.equal(rxform.numberOfItems, 0);
});
it('Test SVGTransformList.initialize()', function () {
const rxform = transformlist.getTransformList(rect);
const cxform = transformlist.getTransformList(circle);
const t = svgcontent.createSVGTransform();
assert.ok(t);
assert.ok(rxform.initialize);
assert.equal(typeof rxform.initialize, typeof function () { /* empty fn */ });
rxform.initialize(t);
assert.equal(rxform.numberOfItems, 1);
assert.equal(cxform.numberOfItems, 0);
// If a transform was already in a transform list, this should
// remove it from its old list and add it to this list.
cxform.initialize(t);
// This also fails in Firefox native.
// assert.equal(rxform.numberOfItems, 0, 'Did not remove transform from list before initializing another transformlist');
assert.equal(cxform.numberOfItems, 1);
});
it('Test SVGTransformList.appendItem() and getItem()', function () {
const rxform = transformlist.getTransformList(rect);
const cxform = transformlist.getTransformList(circle);
const t1 = svgcontent.createSVGTransform();
const t2 = svgcontent.createSVGTransform();
const t3 = svgcontent.createSVGTransform();
assert.ok(rxform.appendItem);
assert.ok(rxform.getItem);
assert.equal(typeof rxform.appendItem, typeof function () { /* empty fn */ });
assert.equal(typeof rxform.getItem, typeof function () { /* empty fn */ });
rxform.appendItem(t1);
rxform.appendItem(t2);
rxform.appendItem(t3);
assert.equal(rxform.numberOfItems, 3);
const rxf = rxform.getItem(0);
assert.equal(rxf, t1);
assert.equal(rxform.getItem(1), t2);
assert.equal(rxform.getItem(2), t3);
assert.expectOutOfBoundsException(rxform, 'getItem', -1);
assert.expectOutOfBoundsException(rxform, 'getItem', 3);
cxform.appendItem(t1);
// These also fail in Firefox native.
// assert.equal(rxform.numberOfItems, 2, 'Did not remove a transform from a list before appending it to a new transformlist');
// assert.equal(rxform.getItem(0), t2, 'Found the wrong transform in a transformlist');
// assert.equal(rxform.getItem(1), t3, 'Found the wrong transform in a transformlist');
assert.equal(cxform.numberOfItems, 1);
assert.equal(cxform.getItem(0), t1);
});
it('Test SVGTransformList.removeItem()', function () {
const rxform = transformlist.getTransformList(rect);
const t1 = svgcontent.createSVGTransform();
const t2 = svgcontent.createSVGTransform();
assert.ok(rxform.removeItem);
assert.equal(typeof rxform.removeItem, typeof function () { /* empty fn */ });
rxform.appendItem(t1);
rxform.appendItem(t2);
const removedTransform = rxform.removeItem(0);
assert.equal(rxform.numberOfItems, 1);
assert.equal(removedTransform, t1);
assert.equal(rxform.getItem(0), t2);
assert.expectOutOfBoundsException(rxform, 'removeItem', -1);
assert.expectOutOfBoundsException(rxform, 'removeItem', 1);
});
it('Test SVGTransformList.replaceItem()', function () {
const rxform = transformlist.getTransformList(rect);
const cxform = transformlist.getTransformList(circle);
assert.ok(rxform.replaceItem);
assert.equal(typeof rxform.replaceItem, typeof function () { /* empty fn */ });
const t1 = svgcontent.createSVGTransform();
const t2 = svgcontent.createSVGTransform();
const t3 = svgcontent.createSVGTransform();
rxform.appendItem(t1);
rxform.appendItem(t2);
cxform.appendItem(t3);
const newItem = rxform.replaceItem(t3, 0);
assert.equal(rxform.numberOfItems, 2);
assert.equal(newItem, t3);
assert.equal(rxform.getItem(0), t3);
assert.equal(rxform.getItem(1), t2);
// Fails in Firefox native
// assert.equal(cxform.numberOfItems, 0);
// test replaceItem within a list
rxform.appendItem(t1);
rxform.replaceItem(t1, 0);
// Fails in Firefox native
// assert.equal(rxform.numberOfItems, 2);
assert.equal(rxform.getItem(0), t1);
assert.equal(rxform.getItem(1), t2);
});
it('Test SVGTransformList.insertItemBefore()', function () {
const rxform = transformlist.getTransformList(rect);
const cxform = transformlist.getTransformList(circle);
assert.ok(rxform.insertItemBefore);
assert.equal(typeof rxform.insertItemBefore, typeof function () { /* empty fn */ });
const t1 = svgcontent.createSVGTransform();
const t2 = svgcontent.createSVGTransform();
const t3 = svgcontent.createSVGTransform();
rxform.appendItem(t1);
rxform.appendItem(t2);
cxform.appendItem(t3);
const newItem = rxform.insertItemBefore(t3, 0);
assert.equal(rxform.numberOfItems, 3);
assert.equal(newItem, t3);
assert.equal(rxform.getItem(0), t3);
assert.equal(rxform.getItem(1), t1);
assert.equal(rxform.getItem(2), t2);
// Fails in Firefox native
// assert.equal(cxform.numberOfItems, 0);
rxform.insertItemBefore(t2, 1);
// Fails in Firefox native (they make copies of the transforms)
// assert.equal(rxform.numberOfItems, 3);
assert.equal(rxform.getItem(0), t3);
assert.equal(rxform.getItem(1), t2);
assert.equal(rxform.getItem(2), t1);
});
it('Test SVGTransformList.init() for translate(200,100)', function () {
rect.setAttribute('transform', 'translate(200,100)');
const rxform = transformlist.getTransformList(rect);
assert.equal(rxform.numberOfItems, 1);
const translate = rxform.getItem(0);
assert.equal(translate.type, 2);
const m = translate.matrix;
assert.equal(m.a, 1);
assert.equal(m.b, 0);
assert.equal(m.c, 0);
assert.equal(m.d, 1);
assert.equal(m.e, 200);
assert.equal(m.f, 100);
});
it('Test SVGTransformList.init() for scale(4)', function () {
rect.setAttribute('transform', 'scale(4)');
const rxform = transformlist.getTransformList(rect);
assert.equal(rxform.numberOfItems, 1);
const scale = rxform.getItem(0);
assert.equal(scale.type, 3);
const m = scale.matrix;
assert.equal(m.a, 4);
assert.equal(m.b, 0);
assert.equal(m.c, 0);
assert.equal(m.d, 4);
assert.equal(m.e, 0);
assert.equal(m.f, 0);
});
it('Test SVGTransformList.init() for scale(4,3)', function () {
rect.setAttribute('transform', 'scale(4,3)');
const rxform = transformlist.getTransformList(rect);
assert.equal(rxform.numberOfItems, 1);
const scale = rxform.getItem(0);
assert.equal(scale.type, 3);
const m = scale.matrix;
assert.equal(m.a, 4);
assert.equal(m.b, 0);
assert.equal(m.c, 0);
assert.equal(m.d, 3);
assert.equal(m.e, 0);
assert.equal(m.f, 0);
});
it('Test SVGTransformList.init() for rotate(45)', function () {
rect.setAttribute('transform', 'rotate(45)');
const rxform = transformlist.getTransformList(rect);
assert.equal(rxform.numberOfItems, 1);
const rotate = rxform.getItem(0);
assert.equal(rotate.type, 4);
assert.equal(rotate.angle, 45);
const m = rotate.matrix;
assert.almostEquals(1 / Math.sqrt(2), m.a);
assert.almostEquals(1 / Math.sqrt(2), m.b);
assert.almostEquals(-1 / Math.sqrt(2), m.c);
assert.almostEquals(1 / Math.sqrt(2), m.d);
assert.equal(m.e, 0);
assert.equal(m.f, 0);
});
it('Test SVGTransformList.init() for rotate(45, 100, 200)', function () {
rect.setAttribute('transform', 'rotate(45, 100, 200)');
const rxform = transformlist.getTransformList(rect);
assert.equal(rxform.numberOfItems, 1);
const rotate = rxform.getItem(0);
assert.equal(rotate.type, 4);
assert.equal(rotate.angle, 45);
const m = rotate.matrix;
assert.almostEquals(m.a, 1 / Math.sqrt(2));
assert.almostEquals(m.b, 1 / Math.sqrt(2));
assert.almostEquals(m.c, -1 / Math.sqrt(2));
assert.almostEquals(m.d, 1 / Math.sqrt(2));
const r = svgcontent.createSVGMatrix();
r.a = 1 / Math.sqrt(2); r.b = 1 / Math.sqrt(2);
r.c = -1 / Math.sqrt(2); r.d = 1 / Math.sqrt(2);
const t = svgcontent.createSVGMatrix();
t.e = -100; t.f = -200;
const t_ = svgcontent.createSVGMatrix();
t_.e = 100; t_.f = 200;
const result = t_.multiply(r).multiply(t);
assert.almostEquals(m.e, result.e);
assert.almostEquals(m.f, result.f);
});
it('Test SVGTransformList.init() for matrix(1, 2, 3, 4, 5, 6)', function () {
rect.setAttribute('transform', 'matrix(1,2,3,4,5,6)');
const rxform = transformlist.getTransformList(rect);
assert.equal(rxform.numberOfItems, 1);
const mt = rxform.getItem(0);
assert.equal(mt.type, 1);
const m = mt.matrix;
assert.equal(m.a, 1);
assert.equal(m.b, 2);
assert.equal(m.c, 3);
assert.equal(m.d, 4);
assert.equal(m.e, 5);
assert.equal(m.f, 6);
});
});

View File

@ -3,7 +3,6 @@ import 'pathseg';
import { NS } from '../../../instrumented/common/namespaces.js';
import * as utilities from '../../../instrumented/svgcanvas/utilities.js';
import * as transformlist from '../../../instrumented/svgcanvas/svgtransformlist.js';
import * as math from '../../../instrumented/svgcanvas/math.js';
import * as path from '../../../instrumented/svgcanvas/path.js';
import setAssertionMethods from '../../support/assert-close.js';
@ -39,7 +38,7 @@ describe('utilities bbox', function () {
const mockPathActions = {
resetOrientation (pth) {
if (utilities.isNullish(pth) || pth.nodeName !== 'path') { return false; }
const tlist = transformlist.getTransformList(pth);
const tlist = pth.transform.baseVal;
const m = math.transformListToTransform(tlist).matrix;
tlist.clear();
pth.removeAttribute('transform');
@ -84,8 +83,6 @@ describe('utilities bbox', function () {
});
sandbox.append(svgroot);
// We're reusing ID's so we need to do this for transforms.
transformlist.resetListMap();
path.init(null);
mockaddSVGElementFromJsonCallCount = 0;
});

View File

@ -3,7 +3,6 @@ import 'pathseg';
import { NS } from '../../../instrumented/common/namespaces.js';
import * as utilities from '../../../instrumented/svgcanvas/utilities.js';
import * as transformlist from '../../../instrumented/svgcanvas/svgtransformlist.js';
import * as math from '../../../instrumented/svgcanvas/math.js';
describe('utilities performance', function () {
@ -118,7 +117,7 @@ describe('utilities performance', function () {
const mockPathActions = {
resetOrientation (path) {
if (utilities.isNullish(path) || path.nodeName !== 'path') { return false; }
const tlist = transformlist.getTransformList(path);
const tlist = path.transform.baseVal;
const m = math.transformListToTransform(tlist).matrix;
tlist.clear();
path.removeAttribute('transform');

View File

@ -11,7 +11,6 @@ import 'pathseg';
import { NS } from './namespaces.js';
const { userAgent } = navigator;
const svg = document.createElementNS(NS.SVG, 'svg');
// Note: Browser sniffing should only be used if no other detection method is possible
const isWebkit_ = userAgent.includes('AppleWebKit');
@ -99,26 +98,6 @@ const supportsNonScalingStroke_ = (function () {
return rect.style.vectorEffect === 'non-scaling-stroke';
}());
let supportsNativeSVGTransformLists_ = (function () {
const rect = document.createElementNS(NS.SVG, 'rect');
const rxform = rect.transform.baseVal;
const t1 = svg.createSVGTransform();
rxform.appendItem(t1);
const r1 = rxform.getItem(0);
const isSVGTransform = (o) => {
// https://developer.mozilla.org/en-US/docs/Web/API/SVGTransform
return o && typeof o === 'object' && typeof o.setMatrix === 'function' && 'angle' in o;
};
return isSVGTransform(r1) && isSVGTransform(t1) &&
r1.type === t1.type && r1.angle === t1.angle &&
r1.matrix.a === t1.matrix.a &&
r1.matrix.b === t1.matrix.b &&
r1.matrix.c === t1.matrix.c &&
r1.matrix.d === t1.matrix.d &&
r1.matrix.e === t1.matrix.e &&
r1.matrix.f === t1.matrix.f;
}());
// Public API
/**
@ -184,17 +163,3 @@ export const supportsGoodTextCharPos = () => supportsGoodTextCharPos_;
*/
export const supportsNonScalingStroke = () => supportsNonScalingStroke_;
/**
* @function module:browser.supportsNativeTransformLists
* @returns {boolean}
*/
export const supportsNativeTransformLists = () => supportsNativeSVGTransformLists_;
/**
* Set `supportsNativeSVGTransformLists_` to `false` (for unit testing).
* @function module:browser.disableSupportsNativeTransformLists
* @returns {void}
*/
export const disableSupportsNativeTransformLists = () => {
supportsNativeSVGTransformLists_ = false;
};

View File

@ -456,7 +456,7 @@ export default {
if (elem && dataStorage.has(elem, 'c_start')) {
// Remove the "translate" transform given to move
svgCanvas.removeFromSelection([ elem ]);
svgCanvas.getTransformList(elem).clear();
elem.transform.baseVal.clear();
}
}
if (connections.length) {

View File

@ -94,8 +94,6 @@ export default {
canv.recalculateDimensions(curShape);
canv.getTransformList(curShape);
lastBBox = curShape.getBBox();
return {
@ -112,7 +110,7 @@ export default {
const x = opts.mouse_x / zoom;
const y = opts.mouse_y / zoom;
const tlist = canv.getTransformList(curShape);
const tlist = curShape.transform.baseVal;
const box = curShape.getBBox();
const left = box.x; const top = box.y;

View File

@ -10,7 +10,6 @@ import {
import {
transformPoint, transformListToTransform, matrixMultiply, transformBox
} from './math.js';
import { getTransformList } from './svgtransformlist.js';
// this is how we map paths to our preferred relative segment types
const pathMap = [
@ -103,7 +102,7 @@ export const remapElement = function (selected, changes, m) {
changes.y = Number.parseFloat(changes.y) + tNew.f;
} else {
// we just absorb all matrices into the element and don't do any remapping
const chlist = getTransformList(selected);
const chlist = selected.transform.baseVal;
const mt = editorContext_.getSVGRoot().createSVGTransform();
mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix, m));
chlist.clear();
@ -120,7 +119,7 @@ export const remapElement = function (selected, changes, m) {
// Allow images to be inverted (give them matrix when flipped)
if (elName === 'image' && (m.a < 0 || m.d < 0)) {
// Convert to matrix
const chlist = getTransformList(selected);
const chlist = selected.transform.baseVal;
const mt = editorContext_.getSVGRoot().createSVGTransform();
mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix, m));
chlist.clear();

View File

@ -14,9 +14,6 @@ import {
import {
transformPoint, hasMatrixTransform, getMatrix, snapToAngle
} from './math.js';
import {
getTransformList
} from './svgtransformlist.js';
import { supportsNonScalingStroke } from '../common/browser.js';
import * as draw from './draw.js';
import * as pathModule from './path.js';
@ -144,7 +141,7 @@ export const mouseMoveEvent = function (evt) {
// update the dummy transform in our transform list
// to be a translate
const xform = svgRoot.createSVGTransform();
tlist = getTransformList(selected);
tlist = selected.transform.baseVal;
// Note that if Webkit and there's no ID for this
// element, the dummy transform may have gotten lost.
// This results in unexpected behaviour
@ -209,7 +206,7 @@ export const mouseMoveEvent = function (evt) {
// we track the resize bounding box and translate/scale the selected element
// while the mouse is down, when mouse goes up, we use this to recalculate
// the shape's coordinates
tlist = getTransformList(selected);
tlist = selected.transform.baseVal;
const hasMatrix = hasMatrixTransform(tlist);
box = hasMatrix ? eventContext_.getInitBbox() : utilsGetBBox(selected);
let left = box.x;
@ -1019,7 +1016,7 @@ export const mouseDownEvent = function (evt) {
eventContext_.setStartTransform(mouseTarget.getAttribute('transform'));
const tlist = getTransformList(mouseTarget);
const tlist = mouseTarget.transform.baseVal;
switch (eventContext_.getCurrentMode()) {
case 'select':
eventContext_.setStarted(true);
@ -1046,7 +1043,7 @@ export const mouseDownEvent = function (evt) {
// a transform to use for its translate
for (const selectedElement of selectedElements()) {
if (isNullish(selectedElement)) { continue; }
const slist = getTransformList(selectedElement);
const slist = selectedElement.transform.baseVal;
if (slist.numberOfItems) {
slist.insertItemBefore(svgRoot.createSVGTransform(), 0);
} else {

View File

@ -7,7 +7,6 @@
*/
import { getHref, setHref, getRotationAngle, isNullish } from './utilities.js';
import { removeElementFromListMap } from './svgtransformlist.js';
/**
* Group: Undo/Redo history management.
@ -215,6 +214,7 @@ export class InsertElementCommand extends Command {
}
}
/**
* History command for an element removed from the DOM.
* @implements {module:history.HistoryCommand}
@ -232,9 +232,6 @@ export class RemoveElementCommand extends Command {
this.text = text || ('Delete ' + elem.tagName);
this.nextSibling = oldNextSibling;
this.parent = oldParent;
// special hack for webkit: remove this element's entry in the svgTransformLists map
removeElementFromListMap(elem);
}
/**
@ -245,7 +242,7 @@ export class RemoveElementCommand extends Command {
*/
apply (handler) {
super.apply(handler, () => {
removeElementFromListMap(this.elem);
this.removeElementFromListMap();
this.parent = this.elem.parentNode;
this.elem.remove();
});
@ -259,7 +256,6 @@ export class RemoveElementCommand extends Command {
*/
unapply (handler) {
super.unapply(handler, () => {
removeElementFromListMap(this.elem);
if (isNullish(this.nextSibling) && window.console) {
console.error('Reference element was lost');
}
@ -385,8 +381,6 @@ export class ChangeElementCommand extends Command {
}
}
}
// Remove transformlist to prevent confusion that causes bugs like 575.
removeElementFromListMap(this.elem);
});
}
}

View File

@ -20,7 +20,6 @@
*/
import { NS } from '../common/namespaces.js';
import { getTransformList } from './svgtransformlist.js';
// Constants
const NEAR_ZERO = 1e-14;
@ -178,7 +177,7 @@ export const transformListToTransform = function (tlist, min, max) {
* @returns {SVGMatrix} The matrix object associated with the element's transformlist
*/
export const getMatrix = function (elem) {
const tlist = getTransformList(elem);
const tlist = elem.transform.baseVal;
return transformListToTransform(tlist).matrix;
};

View File

@ -8,7 +8,6 @@
import { NS } from '../common/namespaces.js';
import { shortFloat } from '../common/units.js';
import { getTransformList } from './svgtransformlist.js';
import { ChangeElementCommand, BatchCommand } from './history.js';
import {
transformPoint, snapToAngle, rectsIntersect,
@ -879,7 +878,7 @@ export const pathActionsMethod = (function () {
*/
resetOrientation (pth) {
if (isNullish(pth) || pth.nodeName !== 'path') { return false; }
const tlist = getTransformList(pth);
const tlist = pth.transform.baseVal;
const m = transformListToTransform(tlist).matrix;
tlist.clear();
pth.removeAttribute('transform');

View File

@ -6,7 +6,6 @@
* @copyright 2011 Alexis Deveria, 2011 Jeff Schiller
*/
import { getTransformList } from './svgtransformlist.js';
import { shortFloat } from '../common/units.js';
import { transformPoint } from './math.js';
import {
@ -526,7 +525,7 @@ export const recalcRotatedPath = function () {
// now we must set the new transform to be rotated around the new center
const Rnc = editorContext_.getSVGRoot().createSVGTransform();
const tlist = getTransformList(currentPath);
const tlist = currentPath.transform.baseVal;
Rnc.setRotate((angle * 180.0 / Math.PI), newcx, newcy);
tlist.replaceItem(Rnc, 0);
};

View File

@ -7,7 +7,6 @@
import { NS } from '../common/namespaces.js';
import { convertToNum } from '../common/units.js';
import { isWebkit } from '../common/browser.js';
import { getTransformList } from './svgtransformlist.js';
import { getRotationAngle, getHref, getBBox, getRefElem, isNullish } from './utilities.js';
import { BatchCommand, ChangeElementCommand } from './history.js';
import { remapElement } from './coords.js';
@ -57,7 +56,7 @@ export const init = function (editorContext) {
*/
export const updateClipPath = function (attr, tx, ty) {
const path = getRefElem(attr).firstChild;
const cpXform = getTransformList(path);
const cpXform = path.transform.baseVal;
const newxlate = context_.getSVGRoot().createSVGTransform();
newxlate.setTranslate(tx, ty);
@ -74,17 +73,10 @@ export const updateClipPath = function (attr, tx, ty) {
* @returns {Command} Undo command object with the resulting change
*/
export const recalculateDimensions = function (selected) {
if (isNullish(selected)) { return null; }
// Firefox Issue - 1081
if (selected.nodeName === 'svg' && navigator.userAgent.includes('Firefox/20')) {
return null;
}
if (!selected) return null;
const svgroot = context_.getSVGRoot();
const dataStorage = context_.getDataStorage();
const tlist = getTransformList(selected);
const tlist = selected.transform.baseVal;
// remove any unnecessary transforms
if (tlist && tlist.numberOfItems > 0) {
let k = tlist.numberOfItems;
@ -307,7 +299,7 @@ export const recalculateDimensions = function (selected) {
tx = 0;
ty = 0;
if (child.nodeType === 1) {
const childTlist = getTransformList(child);
const childTlist = child.transform.baseVal;
// some children might not have a transform (<metadata>, <defs>, etc)
if (!childTlist) { continue; }
@ -387,7 +379,7 @@ export const recalculateDimensions = function (selected) {
// if (href == getHref(useElem)) {
// const usexlate = svgroot.createSVGTransform();
// usexlate.setTranslate(-tx,-ty);
// getTransformList(useElem).insertItemBefore(usexlate,0);
// useElem.transform.baseVal.insertItemBefore(usexlate,0);
// batchCmd.addSubCommand( recalculateDimensions(useElem) );
// }
// }
@ -441,7 +433,7 @@ export const recalculateDimensions = function (selected) {
oldStartTransform = context_.getStartTransform();
context_.setStartTransform(child.getAttribute('transform'));
const childTlist = getTransformList(child);
const childTlist = child.transform?.baseVal;
// some children might not have a transform (<metadata>, <defs>, etc)
if (childTlist) {
const newxlate = svgroot.createSVGTransform();
@ -463,7 +455,7 @@ export const recalculateDimensions = function (selected) {
if (href === getHref(useElem)) {
const usexlate = svgroot.createSVGTransform();
usexlate.setTranslate(-tx, -ty);
getTransformList(useElem).insertItemBefore(usexlate, 0);
useElem.transform.baseVal.insertItemBefore(usexlate, 0);
batchCmd.addSubCommand(recalculateDimensions(useElem));
}
}
@ -485,7 +477,7 @@ export const recalculateDimensions = function (selected) {
if (child.nodeType === 1) {
oldStartTransform = context_.getStartTransform();
context_.setStartTransform(child.getAttribute('transform'));
const childTlist = getTransformList(child);
const childTlist = child.transform.baseVal;
if (!childTlist) { continue; }
@ -566,7 +558,7 @@ export const recalculateDimensions = function (selected) {
if (child.nodeType === 1) {
oldStartTransform = context_.getStartTransform();
context_.setStartTransform(child.getAttribute('transform'));
const childTlist = getTransformList(child);
const childTlist = child.transform.baseVal;
const newxlate = svgroot.createSVGTransform();
newxlate.setTranslate(tx, ty);
if (childTlist.numberOfItems) {
@ -649,7 +641,7 @@ export const recalculateDimensions = function (selected) {
if (attrVal === 'userSpaceOnUse') {
// Update the userSpaceOnUse element
m = transformListToTransform(tlist).matrix;
const gtlist = getTransformList(paint);
const gtlist = paint.transform.baseVal;
const gmatrix = transformListToTransform(gtlist).matrix;
m = matrixMultiply(m, gmatrix);
const mStr = 'matrix(' + [ m.a, m.b, m.c, m.d, m.e, m.f ].join(',') + ')';

View File

@ -9,7 +9,6 @@
import { isTouch, isWebkit } from '../common/browser.js'; // , isOpera
import { getRotationAngle, getBBox, getStrokedBBox, isNullish } from './utilities.js';
import { transformListToTransform, transformBox, transformPoint } from './math.js';
import { getTransformList } from './svgtransformlist.js';
let svgFactory_;
let config_;
@ -124,7 +123,7 @@ export class Selector {
}
// loop and transform our bounding box until we reach our first rotation
const tlist = getTransformList(selected);
const tlist = selected.transform.baseVal;
const m = transformListToTransform(tlist).matrix;
// This should probably be handled somewhere else, but for now

View File

@ -16,9 +16,6 @@ import {
import {
transformPoint, matrixMultiply, transformListToTransform
} from './math.js';
import {
getTransformList
} from './svgtransformlist.js';
import {
recalculateDimensions
} from './recalculate.js';
@ -171,7 +168,7 @@ export const moveSelectedElements = function (dx, dy, undoable = true) {
const selected = selectedElements[i];
if (!isNullish(selected)) {
const xform = elementContext_.getSVGRoot().createSVGTransform();
const tlist = getTransformList(selected);
const tlist = selected.transform.baseVal;
// dx and dy could be arrays
if (Array.isArray(dx)) {
@ -503,7 +500,7 @@ export const pushGroupProperty = function (g, undoable) {
const len = children.length;
const xform = g.getAttribute('transform');
const glist = getTransformList(g);
const glist = g.transform.baseVal;
const m = transformListToTransform(glist).matrix;
const batchCmd = new BatchCommand('Push group properties');
@ -576,7 +573,7 @@ export const pushGroupProperty = function (g, undoable) {
}
}
let chtlist = getTransformList(elem);
let chtlist = elem.transform?.baseVal;
// Don't process gradient transforms
if (elem.tagName.includes('Gradient')) { chtlist = null; }
@ -717,7 +714,7 @@ export const convertToGroup = function (elem) {
}
dataStorage.remove(elem, 'gsvg');
const tlist = getTransformList(elem);
const tlist = elem.transform.baseVal;
const xform = elementContext_.getSVGRoot().createSVGTransform();
xform.setTranslate(pt.x, pt.y);
tlist.appendItem(xform);

View File

@ -10,9 +10,6 @@ import {
isNullish, getBBox as utilsGetBBox, getStrokedBBoxDefaultVisible
} from './utilities.js';
import { transformPoint, transformListToTransform, rectsIntersect } from './math.js';
import {
getTransformList
} from './svgtransformlist.js';
import * as hstry from './history.js';
import { getClosest } from '../editor/components/jgraduate/Util.js';
@ -353,7 +350,7 @@ export const setRotationAngle = function (val, preventUndo) {
const oldTransform = elem.getAttribute('transform');
const bbox = utilsGetBBox(elem);
const cx = bbox.x + bbox.width / 2; const cy = bbox.y + bbox.height / 2;
const tlist = getTransformList(elem);
const tlist = elem.transform.baseVal;
// only remove the real rotational transform if present (i.e. at index=0)
if (tlist.numberOfItems > 0) {
@ -411,7 +408,6 @@ export const recalculateAllSelectedDimensions = function () {
let i = selectedElements().length;
while (i--) {
const elem = selectedElements()[i];
// if (getRotationAngle(elem) && !hasMatrixTransform(getTransformList(elem))) { continue; }
const cmd = svgCanvas.recalculateDimensions(elem);
if (cmd) {
batchCmd.addSubCommand(cmd);

View File

@ -17,7 +17,6 @@ import {
import {
transformPoint, transformListToTransform
} from './math.js';
import { resetListMap } from './svgtransformlist.js';
import {
convertUnit, shortFloat, convertToNum
} from '../common/units.js';
@ -491,8 +490,6 @@ export const setSvgString = function (xmlString, preventUndo) {
// reset zoom
svgContext_.setCurrentZoom(1);
// reset transform lists
resetListMap();
svgCanvas.clearSelection();
pathModule.clearData();
svgContext_.getSVGRoot().append(svgCanvas.selectorManager.selectorParentGroup);

View File

@ -87,9 +87,6 @@ import {
import {
isChrome, isWebkit
} from '../common/browser.js'; // , supportsEditableText
import {
getTransformList, SVGTransformList as SVGEditTransformList
} from './svgtransformlist.js';
import {
remapElement,
init as coordsInit
@ -151,7 +148,6 @@ if (window.opera) {
* @borrows module:utilities.getRefElem as #getRefElem
* @borrows module:utilities.assignAttributes as #assignAttributes
*
* @borrows module:SVGTransformList.getTransformList as #getTransformList
* @borrows module:math.matrixMultiply as #matrixMultiply
* @borrows module:math.hasMatrixTransform as #hasMatrixTransform
* @borrows module:math.transformListToTransform as #transformListToTransform
@ -372,7 +368,6 @@ class SvgCanvas {
*/
const addSVGElementFromJson = this.addSVGElementFromJson = addSVGElementsFromJson;
canvas.getTransformList = getTransformList;
canvas.matrixMultiply = matrixMultiply;
canvas.hasMatrixTransform = hasMatrixTransform;
canvas.transformListToTransform = transformListToTransform;
@ -2756,7 +2751,6 @@ class SvgCanvas {
NS,
preventClickDefault,
RemoveElementCommand,
SVGEditTransformList,
text2xml,
transformBox,
transformPoint,

View File

@ -1,393 +0,0 @@
/**
* Partial polyfill of `SVGTransformList`
* @module SVGTransformList
*
* @license MIT
*
* @copyright 2010 Alexis Deveria, 2010 Jeff Schiller
*/
import { NS } from '../common/namespaces.js';
import { supportsNativeTransformLists } from '../common/browser.js';
const svgroot = document.createElementNS(NS.SVG, 'svg');
/**
* Helper function to convert `SVGTransform` to a string.
* @param {SVGTransform} xform
* @returns {string}
*/
function transformToString (xform) {
const m = xform.matrix;
let text = '';
switch (xform.type) {
case 1: // MATRIX
text = 'matrix(' + [ m.a, m.b, m.c, m.d, m.e, m.f ].join(',') + ')';
break;
case 2: // TRANSLATE
text = 'translate(' + m.e + ',' + m.f + ')';
break;
case 3: // SCALE
text = (m.a === m.d) ? `scale(${m.a})` : `scale(${m.a},${m.d})`;
break;
case 4: { // ROTATE
let cx = 0;
let cy = 0;
// this prevents divide by zero
if (xform.angle !== 0) {
const K = 1 - m.a;
cy = (K * m.f + m.b * m.e) / (K * K + m.b * m.b);
cx = (m.e - m.b * cy) / K;
}
text = 'rotate(' + xform.angle + ' ' + cx + ',' + cy + ')';
break;
}
}
return text;
}
/**
* Map of SVGTransformList objects.
*/
let listMap_ = {};
/**
* @interface module:SVGTransformList.SVGEditTransformList
* @property {Integer} numberOfItems unsigned long
*/
/**
* @function module:SVGTransformList.SVGEditTransformList#clear
* @returns {void}
*/
/**
* @function module:SVGTransformList.SVGEditTransformList#initialize
* @param {SVGTransform} newItem
* @returns {SVGTransform}
*/
/**
* DOES NOT THROW DOMException, INDEX_SIZE_ERR.
* @function module:SVGTransformList.SVGEditTransformList#getItem
* @param {Integer} index unsigned long
* @returns {SVGTransform}
*/
/**
* DOES NOT THROW DOMException, INDEX_SIZE_ERR.
* @function module:SVGTransformList.SVGEditTransformList#insertItemBefore
* @param {SVGTransform} newItem
* @param {Integer} index unsigned long
* @returns {SVGTransform}
*/
/**
* DOES NOT THROW DOMException, INDEX_SIZE_ERR.
* @function module:SVGTransformList.SVGEditTransformList#replaceItem
* @param {SVGTransform} newItem
* @param {Integer} index unsigned long
* @returns {SVGTransform}
*/
/**
* DOES NOT THROW DOMException, INDEX_SIZE_ERR.
* @function module:SVGTransformList.SVGEditTransformList#removeItem
* @param {Integer} index unsigned long
* @returns {SVGTransform}
*/
/**
* @function module:SVGTransformList.SVGEditTransformList#appendItem
* @param {SVGTransform} newItem
* @returns {SVGTransform}
*/
/**
* NOT IMPLEMENTED.
* @ignore
* @function module:SVGTransformList.SVGEditTransformList#createSVGTransformFromMatrix
* @param {SVGMatrix} matrix
* @returns {SVGTransform}
*/
/**
* NOT IMPLEMENTED.
* @ignore
* @function module:SVGTransformList.SVGEditTransformList#consolidate
* @returns {SVGTransform}
*/
/**
* SVGTransformList implementation for Webkit.
* These methods do not currently raise any exceptions.
* These methods also do not check that transforms are being inserted. This is basically
* implementing as much of SVGTransformList that we need to get the job done.
* @implements {module:SVGTransformList.SVGEditTransformList}
*/
export class SVGTransformList {
/**
* @param {Element} elem
* @returns {SVGTransformList}
*/
constructor (elem) {
this._elem = elem || null;
this._xforms = [];
// TODO: how do we capture the undo-ability in the changed transform list?
this._update = function () {
let tstr = '';
// /* const concatMatrix = */ svgroot.createSVGMatrix();
for (let i = 0; i < this.numberOfItems; ++i) {
const xform = this._list.getItem(i);
tstr += transformToString(xform) + ' ';
}
this._elem.setAttribute('transform', tstr);
};
this._list = this;
this._init = function () {
// Transform attribute parser
let str = this._elem.getAttribute('transform');
if (!str) { return; }
// TODO: Add skew support in future
const re = /\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/;
// const re = /\s*(?<xform>(?:scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/;
let m = true;
while (m) {
m = str.match(re);
str = str.replace(re, '');
if (m && m[1]) {
const x = m[1];
const bits = x.split(/\s*\(/);
const name = bits[0];
const valBits = bits[1].match(/\s*(.*?)\s*\)/);
valBits[1] = valBits[1].replace(/(\d)-/g, '$1 -');
const valArr = valBits[1].split(/[, ]+/);
const letters = 'abcdef'.split('');
/*
if (m && m.groups.xform) {
const x = m.groups.xform;
const [name, bits] = x.split(/\s*\(/);
const valBits = bits.match(/\s*(?<nonWhitespace>.*?)\s*\)/);
valBits.groups.nonWhitespace = valBits.groups.nonWhitespace.replace(
/(?<digit>\d)-/g, '$<digit> -'
);
const valArr = valBits.groups.nonWhitespace.split(/[, ]+/);
const letters = [...'abcdef'];
*/
const mtx = svgroot.createSVGMatrix();
Object.values(valArr).forEach(function (item, i) {
valArr[i] = Number.parseFloat(item);
if (name === 'matrix') {
mtx[letters[i]] = valArr[i];
}
});
const xform = svgroot.createSVGTransform();
const fname = 'set' + name.charAt(0).toUpperCase() + name.slice(1);
const values = name === 'matrix' ? [ mtx ] : valArr;
if (name === 'scale' && values.length === 1) {
values.push(values[0]);
} else if (name === 'translate' && values.length === 1) {
values.push(0);
} else if (name === 'rotate' && values.length === 1) {
values.push(0, 0);
}
xform[fname](...values);
this._list.appendItem(xform);
}
}
};
this._removeFromOtherLists = function (item) {
if (item) {
// Check if this transform is already in a transformlist, and
// remove it if so.
Object.values(listMap_).some((tl) => {
for (let i = 0, len = tl._xforms.length; i < len; ++i) {
if (tl._xforms[i] === item) {
tl.removeItem(i);
return true;
}
}
return false;
});
}
};
this.numberOfItems = 0;
}
/**
* @returns {void}
*/
clear () {
this.numberOfItems = 0;
this._xforms = [];
}
/**
* @param {SVGTransform} newItem
* @returns {void}
*/
initialize (newItem) {
this.numberOfItems = 1;
this._removeFromOtherLists(newItem);
this._xforms = [ newItem ];
}
/**
* @param {Integer} index unsigned long
* @throws {Error}
* @returns {SVGTransform}
*/
getItem (index) {
if (index < this.numberOfItems && index >= 0) {
return this._xforms[index];
}
const err = new Error('DOMException with code=INDEX_SIZE_ERR');
err.code = 1;
throw err;
}
/**
* @param {SVGTransform} newItem
* @param {Integer} index unsigned long
* @returns {SVGTransform}
*/
insertItemBefore (newItem, index) {
let retValue = null;
if (index >= 0) {
if (index < this.numberOfItems) {
this._removeFromOtherLists(newItem);
const newxforms = new Array(this.numberOfItems + 1);
// TODO: use array copying and slicing
let i;
for (i = 0; i < index; ++i) {
newxforms[i] = this._xforms[i];
}
newxforms[i] = newItem;
for (let j = i + 1; i < this.numberOfItems; ++j, ++i) {
newxforms[j] = this._xforms[i];
}
this.numberOfItems++;
this._xforms = newxforms;
retValue = newItem;
this._list._update();
} else {
retValue = this._list.appendItem(newItem);
}
}
return retValue;
}
/**
* @param {SVGTransform} newItem
* @param {Integer} index unsigned long
* @returns {SVGTransform}
*/
replaceItem (newItem, index) {
let retValue = null;
if (index < this.numberOfItems && index >= 0) {
this._removeFromOtherLists(newItem);
this._xforms[index] = newItem;
retValue = newItem;
this._list._update();
}
return retValue;
}
/**
* @param {Integer} index unsigned long
* @throws {Error}
* @returns {SVGTransform}
*/
removeItem (index) {
if (index < this.numberOfItems && index >= 0) {
const retValue = this._xforms[index];
const newxforms = new Array(this.numberOfItems - 1);
let i;
for (i = 0; i < index; ++i) {
newxforms[i] = this._xforms[i];
}
for (let j = i; j < this.numberOfItems - 1; ++j, ++i) {
newxforms[j] = this._xforms[i + 1];
}
this.numberOfItems--;
this._xforms = newxforms;
this._list._update();
return retValue;
}
const err = new Error('DOMException with code=INDEX_SIZE_ERR');
err.code = 1;
throw err;
}
/**
* @param {SVGTransform} newItem
* @returns {SVGTransform}
*/
appendItem (newItem) {
this._removeFromOtherLists(newItem);
this._xforms.push(newItem);
this.numberOfItems++;
this._list._update();
return newItem;
}
}
/**
* @function module:SVGTransformList.resetListMap
* @returns {void}
*/
export const resetListMap = function () {
listMap_ = {};
};
/**
* Removes transforms of the given element from the map.
* @function module:SVGTransformList.removeElementFromListMap
* @param {Element} elem - a DOM Element
* @returns {void}
*/
export let removeElementFromListMap = function (elem) {
if (elem.id && listMap_[elem.id]) {
delete listMap_[elem.id];
}
};
/**
* Returns an object that behaves like a `SVGTransformList` for the given DOM element.
* @function module:SVGTransformList.getTransformList
* @param {Element} elem - DOM element to get a transformlist from
* @todo The polyfill should have `SVGAnimatedTransformList` and this should use it
* @returns {SVGAnimatedTransformList|SVGTransformList}
*/
export const getTransformList = function (elem) {
if (!supportsNativeTransformLists()) {
const id = elem.id || 'temp';
let t = listMap_[id];
if (!t || id === 'temp') {
listMap_[id] = new SVGTransformList(elem);
listMap_[id]._init();
t = listMap_[id];
}
return t;
}
if (elem.transform) {
return elem.transform.baseVal;
}
if (elem.gradientTransform) {
return elem.gradientTransform.baseVal;
}
if (elem.patternTransform) {
return elem.patternTransform.baseVal;
}
return null;
};
/**
* @callback module:SVGTransformList.removeElementFromListMap
* @param {Element} elem
* @returns {void}
*/
/**
* Replace `removeElementFromListMap` for unit-testing.
* @function module:SVGTransformList.changeRemoveElementFromListMap
* @param {module:SVGTransformList.removeElementFromListMap} cb Passed a single argument `elem`
* @returns {void}
*/
export const changeRemoveElementFromListMap = function (cb) {
removeElementFromListMap = cb;
};

View File

@ -15,9 +15,6 @@ import {
import {
transformPoint, transformListToTransform
} from './math.js';
import {
getTransformList
} from './svgtransformlist.js';
const {
UndoManager, HistoryEventTypes
@ -251,7 +248,7 @@ export const changeSelectedAttributeNoUndoMethod = function (attr, newValue, ele
// we need to update the rotational transform attribute
const angle = getRotationAngle(elem);
if (angle !== 0 && attr !== 'transform') {
const tlist = getTransformList(elem);
const tlist = elem.transform.baseVal;
let n = tlist.numberOfItems;
while (n--) {
const xform = tlist.getItem(n);

View File

@ -7,7 +7,6 @@
*/
import { NS } from '../common/namespaces.js';
import { getTransformList } from './svgtransformlist.js';
import { setUnitAttr, getTypeMap } from '../common/units.js';
import {
hasMatrixTransform, transformListToTransform, transformBox
@ -907,7 +906,7 @@ export const convertToPath = function (
// Reorient if it has a matrix
if (eltrans) {
const tlist = getTransformList(path);
const tlist = path.transform.baseVal;
if (hasMatrixTransform(tlist)) {
pathActions.resetOrientation(path);
}
@ -978,7 +977,7 @@ export const getBBoxWithTransform = function (elem, addSVGElementFromJson, pathA
return null;
}
const tlist = getTransformList(elem);
const tlist = elem.transform.baseVal;
const angle = getRotationAngleFromTransformList(tlist);
const hasMatrixXForm = hasMatrixTransform(tlist);
@ -1170,7 +1169,7 @@ export const getRotationAngleFromTransformList = function (tlist, toRad) {
export let getRotationAngle = function (elem, toRad) {
const selected = elem || editorContext_.getSelectedElements()[0];
// find the rotation transform (if any) and set it
const tlist = getTransformList(selected);
const tlist = selected.transform.baseVal;
return getRotationAngleFromTransformList(tlist, toRad);
};