* create and use getTransformList
* update dependencies
This commit is contained in:
JFH
2023-03-31 01:57:06 +02:00
committed by GitHub
parent 8619a17333
commit 13cdaedc63
20 changed files with 5166 additions and 3512 deletions

View File

@@ -7,17 +7,17 @@
*/
/**
* @typedef {PlainObject} module:math.AngleCoord45
* @property {Float} x - The angle-snapped x value
* @property {Float} y - The angle-snapped y value
* @property {Integer} a - The angle at which to snap
*/
* @typedef {PlainObject} module:math.AngleCoord45
* @property {Float} x - The angle-snapped x value
* @property {Float} y - The angle-snapped y value
* @property {Integer} a - The angle at which to snap
*/
/**
* @typedef {PlainObject} module:math.XYObject
* @property {Float} x
* @property {Float} y
*/
* @typedef {PlainObject} module:math.XYObject
* @property {Float} x
* @property {Float} y
*/
import { NS } from './namespaces.js'
@@ -35,20 +35,35 @@ const svg = document.createElementNS(NS.SVG, 'svg')
* @param {Float} y - Float representing the y coordinate
* @param {SVGMatrix} m - Matrix object to transform the point with
* @returns {module:math.XYObject} An x, y object representing the transformed point
*/
*/
export const transformPoint = function (x, y, m) {
return { x: m.a * x + m.c * y + m.e, y: m.b * x + m.d * y + m.f }
}
export const getTransformList = (elem) => {
if (elem.transform) {
return elem.transform?.baseVal
}
if (elem.gradientTransform) {
return elem.gradientTransform?.baseVal
}
if (elem.patternTransform) {
return elem.patternTransform?.baseVal
}
console.warn('no transform list found - check browser version', elem)
}
/**
* Helper function to check if the matrix performs no actual transform
* (i.e. exists for identity purposes).
* @function module:math.isIdentity
* @param {SVGMatrix} m - The matrix object to check
* @returns {boolean} Indicates whether or not the matrix is 1,0,0,1,0,0
*/
*/
export const isIdentity = function (m) {
return (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0)
return (
m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0
)
}
/**
@@ -57,18 +72,30 @@ export const isIdentity = function (m) {
* @function module:math.matrixMultiply
* @param {...SVGMatrix} args - Matrix objects to multiply
* @returns {SVGMatrix} The matrix object resulting from the calculation
*/
*/
export const matrixMultiply = function (...args) {
const m = args.reduceRight((prev, m1) => {
return m1.multiply(prev)
})
if (Math.abs(m.a) < NEAR_ZERO) { m.a = 0 }
if (Math.abs(m.b) < NEAR_ZERO) { m.b = 0 }
if (Math.abs(m.c) < NEAR_ZERO) { m.c = 0 }
if (Math.abs(m.d) < NEAR_ZERO) { m.d = 0 }
if (Math.abs(m.e) < NEAR_ZERO) { m.e = 0 }
if (Math.abs(m.f) < NEAR_ZERO) { m.f = 0 }
if (Math.abs(m.a) < NEAR_ZERO) {
m.a = 0
}
if (Math.abs(m.b) < NEAR_ZERO) {
m.b = 0
}
if (Math.abs(m.c) < NEAR_ZERO) {
m.c = 0
}
if (Math.abs(m.d) < NEAR_ZERO) {
m.d = 0
}
if (Math.abs(m.e) < NEAR_ZERO) {
m.e = 0
}
if (Math.abs(m.f) < NEAR_ZERO) {
m.f = 0
}
return m
}
@@ -78,29 +105,33 @@ export const matrixMultiply = function (...args) {
* @function module:math.hasMatrixTransform
* @param {SVGTransformList} [tlist] - The transformlist to check
* @returns {boolean} Whether or not a matrix transform was found
*/
*/
export const hasMatrixTransform = function (tlist) {
if (!tlist) { return false }
if (!tlist) {
return false
}
let num = tlist.numberOfItems
while (num--) {
const xform = tlist.getItem(num)
if (xform.type === 1 && !isIdentity(xform.matrix)) { return true }
if (xform.type === 1 && !isIdentity(xform.matrix)) {
return true
}
}
return false
}
/**
* @typedef {PlainObject} module:math.TransformedBox An object with the following values
* @property {module:math.XYObject} tl - The top left coordinate
* @property {module:math.XYObject} tr - The top right coordinate
* @property {module:math.XYObject} bl - The bottom left coordinate
* @property {module:math.XYObject} br - The bottom right coordinate
* @property {PlainObject} aabox - Object with the following values:
* @property {Float} aabox.x - Float with the axis-aligned x coordinate
* @property {Float} aabox.y - Float with the axis-aligned y coordinate
* @property {Float} aabox.width - Float with the axis-aligned width coordinate
* @property {Float} aabox.height - Float with the axis-aligned height coordinate
*/
* @typedef {PlainObject} module:math.TransformedBox An object with the following values
* @property {module:math.XYObject} tl - The top left coordinate
* @property {module:math.XYObject} tr - The top right coordinate
* @property {module:math.XYObject} bl - The bottom left coordinate
* @property {module:math.XYObject} br - The bottom right coordinate
* @property {PlainObject} aabox - Object with the following values:
* @property {Float} aabox.x - Float with the axis-aligned x coordinate
* @property {Float} aabox.y - Float with the axis-aligned y coordinate
* @property {Float} aabox.width - Float with the axis-aligned width coordinate
* @property {Float} aabox.height - Float with the axis-aligned height coordinate
*/
/**
* Transforms a rectangle based on the given matrix.
@@ -111,12 +142,12 @@ export const hasMatrixTransform = function (tlist) {
* @param {Float} h - Float with the box height
* @param {SVGMatrix} m - Matrix object to transform the box by
* @returns {module:math.TransformedBox}
*/
*/
export const transformBox = function (l, t, w, h, m) {
const tl = transformPoint(l, t, m)
const tr = transformPoint((l + w), t, m)
const bl = transformPoint(l, (t + h), m)
const br = transformPoint((l + w), (t + h), m)
const tr = transformPoint(l + w, t, m)
const bl = transformPoint(l, t + h, m)
const br = transformPoint(l + w, t + h, m)
const minx = Math.min(tl.x, tr.x, bl.x, br.x)
const maxx = Math.max(tl.x, tr.x, bl.x, br.x)
@@ -131,8 +162,8 @@ export const transformBox = function (l, t, w, h, m) {
aabox: {
x: minx,
y: miny,
width: (maxx - minx),
height: (maxy - miny)
width: maxx - minx,
height: maxy - miny
}
}
}
@@ -148,23 +179,28 @@ export const transformBox = function (l, t, w, h, m) {
* @param {Integer} [max] - Optional integer indicating end transform position;
* defaults to one less than the tlist's `numberOfItems`
* @returns {SVGTransform} A single matrix transform object
*/
*/
export const transformListToTransform = function (tlist, min, max) {
if (!tlist) {
// Or should tlist = null have been prevented before this?
return svg.createSVGTransformFromMatrix(svg.createSVGMatrix())
}
min = min || 0
max = max || (tlist.numberOfItems - 1)
max = max || tlist.numberOfItems - 1
min = Number.parseInt(min)
max = Number.parseInt(max)
if (min > max) { const temp = max; max = min; min = temp }
if (min > max) {
const temp = max
max = min
min = temp
}
let m = svg.createSVGMatrix()
for (let i = min; i <= max; ++i) {
// if our indices are out of range, just use a harmless identity matrix
const mtom = (i >= 0 && i < tlist.numberOfItems
? tlist.getItem(i).matrix
: svg.createSVGMatrix())
const mtom =
i >= 0 && i < tlist.numberOfItems
? tlist.getItem(i).matrix
: svg.createSVGMatrix()
m = matrixMultiply(m, mtom)
}
return svg.createSVGTransformFromMatrix(m)
@@ -175,9 +211,9 @@ export const transformListToTransform = function (tlist, min, max) {
* @function module:math.getMatrix
* @param {Element} elem - The DOM element to check
* @returns {SVGMatrix} The matrix object associated with the element's transformlist
*/
*/
export const getMatrix = (elem) => {
const tlist = elem.transform.baseVal
const tlist = getTransformList(elem)
return transformListToTransform(tlist).matrix
}
@@ -190,7 +226,7 @@ export const getMatrix = (elem) => {
* @param {Integer} x2 - Second coordinate's x value
* @param {Integer} y2 - Second coordinate's y value
* @returns {module:math.AngleCoord45}
*/
*/
export const snapToAngle = (x1, y1, x2, y2) => {
const snap = Math.PI / 4 // 45 degrees
const dx = x2 - x1
@@ -214,8 +250,10 @@ export const snapToAngle = (x1, y1, x2, y2) => {
* @returns {boolean} True if rectangles intersect
*/
export const rectsIntersect = (r1, r2) => {
return r2.x < (r1.x + r1.width) &&
(r2.x + r2.width) > r1.x &&
r2.y < (r1.y + r1.height) &&
(r2.y + r2.height) > r1.y
return (
r2.x < r1.x + r1.width &&
r2.x + r2.width > r1.x &&
r2.y < r1.y + r1.height &&
r2.y + r2.height > r1.y
)
}