// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import eve from './eve.js' import { Snap } from './svg.js' import { is } from './utils.js' import { SEPARATOR } from './lib/constants.js' import { parseColor } from './lib/color.js' import { Matrix } from './matrix.js' let names = {}, reUnit = /[%a-z]+$/i, Str = String names.stroke = names.fill = 'colour' function getEmpty(item) { let l = item[0] switch (l.toLowerCase()) { case 't': return [l, 0, 0] case 'm': return [l, 1, 0, 0, 1, 0, 0] case 'r': if (item.length == 4) { return [l, 0, item[2], item[3]] } else { return [l, 0] } case 's': if (item.length == 5) { return [l, 1, 1, item[3], item[4]] } else if (item.length == 3) { return [l, 1, 1] } else { return [l, 1] } } } function equaliseTransform(t1, t2, getBBox) { t1 = t1 || new Matrix() t2 = t2 || new Matrix() t1 = Snap.parseTransformString(t1.toTransformString()) || [] t2 = Snap.parseTransformString(t2.toTransformString()) || [] let maxlength = Math.max(t1.length, t2.length), from = [], to = [], i = 0, j, jj, tt1, tt2 for (; i < maxlength; i++) { tt1 = t1[i] || getEmpty(t2[i]) tt2 = t2[i] || getEmpty(tt1) if ( tt1[0] != tt2[0] || (tt1[0].toLowerCase() == 'r' && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || (tt1[0].toLowerCase() == 's' && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) ) { t1 = Snap._.transform2matrix(t1, getBBox()) t2 = Snap._.transform2matrix(t2, getBBox()) from = [['m', t1.a, t1.b, t1.c, t1.d, t1.e, t1.f]] to = [['m', t2.a, t2.b, t2.c, t2.d, t2.e, t2.f]] break } from[i] = [] to[i] = [] for (j = 0, jj = Math.max(tt1.length, tt2.length); j < jj; j++) { j in tt1 && (from[i][j] = tt1[j]) j in tt2 && (to[i][j] = tt2[j]) } } return { from: path2array(from), to: path2array(to), f: getPath(from) } } function getNumber(val) { return val } function getUnit(unit) { return function (val) { return +val.toFixed(3) + unit } } function getViewBox(val) { return val.join(' ') } function getColour(clr) { return Snap.rgb(clr[0], clr[1], clr[2], clr[3]) } function getPath(path) { let k = 0, i, ii, j, jj, out, a, b = [] for (i = 0, ii = path.length; i < ii; i++) { out = '[' a = ['"' + path[i][0] + '"'] for (j = 1, jj = path[i].length; j < jj; j++) { a[j] = 'val[' + k++ + ']' } out += a + ']' b[i] = out } return Function('val', 'return Snap.path.toString.call([' + b + '])') } function path2array(path) { let out = [] for (let i = 0, ii = path.length; i < ii; i++) { for (let j = 1, jj = path[i].length; j < jj; j++) { out.push(path[i][j]) } } return out } function isNumeric(obj) { return isFinite(obj) } function arrayEqual(arr1, arr2) { if (!is(arr1, 'array') || !is(arr2, 'array')) { return false } return arr1.toString() == arr2.toString() } eve.on('snap.util.equal', function (name, b) { let A, B, a = Str(this.attr(name) || ''), el = this if (names[name] == 'colour') { A = parseColor(a) B = parseColor(b) return { from: [A.r, A.g, A.b, A.opacity], to: [B.r, B.g, B.b, B.opacity], f: getColour } } if (name == 'viewBox') { A = this.attr(name).vb.split(' ').map(Number) B = b.split(' ').map(Number) return { from: A, to: B, f: getViewBox } } if ( name == 'transform' || name == 'gradientTransform' || name == 'patternTransform' ) { if (typeof b == 'string') { b = Str(b).replace(/\.{3}|\u2026/g, a) } a = this.matrix if (!Snap._.rgTransform.test(b)) { b = Snap._.transform2matrix(Snap._.svgTransform2string(b), this.getBBox()) } else { b = Snap._.transform2matrix(b, this.getBBox()) } return equaliseTransform(a, b, function () { return el.getBBox(1) }) } if (name == 'd' || name == 'path') { A = Snap.path.toCubic(a, b) return { from: path2array(A[0]), to: path2array(A[1]), f: getPath(A[0]) } } if (name == 'points') { A = Str(a).split(SEPARATOR) B = Str(b).split(SEPARATOR) return { from: A, to: B, f: function (val) { return val } } } if (isNumeric(a) && isNumeric(b)) { return { from: parseFloat(a), to: parseFloat(b), f: getNumber } } let aUnit = a.match(reUnit), bUnit = Str(b).match(reUnit) if (aUnit && arrayEqual(aUnit, bUnit)) { return { from: parseFloat(a), to: parseFloat(b), f: getUnit(aUnit) } } else { return { from: this.asPX(name), to: this.asPX(name, b), f: getNumber } } })