(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@antv/g-lite')) : typeof define === 'function' && define.amd ? define(['exports', '@antv/g-lite'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.G = global.G || {}, global.G.Canvas2D = {}), global.window.G)); }(this, (function (exports, gLite) { 'use strict'; function _regeneratorRuntime() { _regeneratorRuntime = function () { return exports; }; var exports = {}, Op = Object.prototype, hasOwn = Op.hasOwnProperty, defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; }, $Symbol = "function" == typeof Symbol ? Symbol : {}, iteratorSymbol = $Symbol.iterator || "@@iterator", asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator", toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; function define(obj, key, value) { return Object.defineProperty(obj, key, { value: value, enumerable: !0, configurable: !0, writable: !0 }), obj[key]; } try { define({}, ""); } catch (err) { define = function (obj, key, value) { return obj[key] = value; }; } function wrap(innerFn, outerFn, self, tryLocsList) { var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator, generator = Object.create(protoGenerator.prototype), context = new Context(tryLocsList || []); return defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) }), generator; } function tryCatch(fn, obj, arg) { try { return { type: "normal", arg: fn.call(obj, arg) }; } catch (err) { return { type: "throw", arg: err }; } } exports.wrap = wrap; var ContinueSentinel = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var IteratorPrototype = {}; define(IteratorPrototype, iteratorSymbol, function () { return this; }); var getProto = Object.getPrototypeOf, NativeIteratorPrototype = getProto && getProto(getProto(values([]))); NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype); var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype); function defineIteratorMethods(prototype) { ["next", "throw", "return"].forEach(function (method) { define(prototype, method, function (arg) { return this._invoke(method, arg); }); }); } function AsyncIterator(generator, PromiseImpl) { function invoke(method, arg, resolve, reject) { var record = tryCatch(generator[method], generator, arg); if ("throw" !== record.type) { var result = record.arg, value = result.value; return value && "object" == typeof value && hasOwn.call(value, "__await") ? PromiseImpl.resolve(value.__await).then(function (value) { invoke("next", value, resolve, reject); }, function (err) { invoke("throw", err, resolve, reject); }) : PromiseImpl.resolve(value).then(function (unwrapped) { result.value = unwrapped, resolve(result); }, function (error) { return invoke("throw", error, resolve, reject); }); } reject(record.arg); } var previousPromise; defineProperty(this, "_invoke", { value: function (method, arg) { function callInvokeWithMethodAndArg() { return new PromiseImpl(function (resolve, reject) { invoke(method, arg, resolve, reject); }); } return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(innerFn, self, context) { var state = "suspendedStart"; return function (method, arg) { if ("executing" === state) throw new Error("Generator is already running"); if ("completed" === state) { if ("throw" === method) throw arg; return doneResult(); } for (context.method = method, context.arg = arg;;) { var delegate = context.delegate; if (delegate) { var delegateResult = maybeInvokeDelegate(delegate, context); if (delegateResult) { if (delegateResult === ContinueSentinel) continue; return delegateResult; } } if ("next" === context.method) context.sent = context._sent = context.arg;else if ("throw" === context.method) { if ("suspendedStart" === state) throw state = "completed", context.arg; context.dispatchException(context.arg); } else "return" === context.method && context.abrupt("return", context.arg); state = "executing"; var record = tryCatch(innerFn, self, context); if ("normal" === record.type) { if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue; return { value: record.arg, done: context.done }; } "throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg); } }; } function maybeInvokeDelegate(delegate, context) { var methodName = context.method, method = delegate.iterator[methodName]; if (undefined === method) return context.delegate = null, "throw" === methodName && delegate.iterator.return && (context.method = "return", context.arg = undefined, maybeInvokeDelegate(delegate, context), "throw" === context.method) || "return" !== methodName && (context.method = "throw", context.arg = new TypeError("The iterator does not provide a '" + methodName + "' method")), ContinueSentinel; var record = tryCatch(method, delegate.iterator, context.arg); if ("throw" === record.type) return context.method = "throw", context.arg = record.arg, context.delegate = null, ContinueSentinel; var info = record.arg; return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, "return" !== context.method && (context.method = "next", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = "throw", context.arg = new TypeError("iterator result is not an object"), context.delegate = null, ContinueSentinel); } function pushTryEntry(locs) { var entry = { tryLoc: locs[0] }; 1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry); } function resetTryEntry(entry) { var record = entry.completion || {}; record.type = "normal", delete record.arg, entry.completion = record; } function Context(tryLocsList) { this.tryEntries = [{ tryLoc: "root" }], tryLocsList.forEach(pushTryEntry, this), this.reset(!0); } function values(iterable) { if (iterable) { var iteratorMethod = iterable[iteratorSymbol]; if (iteratorMethod) return iteratorMethod.call(iterable); if ("function" == typeof iterable.next) return iterable; if (!isNaN(iterable.length)) { var i = -1, next = function next() { for (; ++i < iterable.length;) if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next; return next.value = undefined, next.done = !0, next; }; return next.next = next; } } return { next: doneResult }; } function doneResult() { return { value: undefined, done: !0 }; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), defineProperty(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) { var ctor = "function" == typeof genFun && genFun.constructor; return !!ctor && (ctor === GeneratorFunction || "GeneratorFunction" === (ctor.displayName || ctor.name)); }, exports.mark = function (genFun) { return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, "GeneratorFunction")), genFun.prototype = Object.create(Gp), genFun; }, exports.awrap = function (arg) { return { __await: arg }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () { return this; }), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) { void 0 === PromiseImpl && (PromiseImpl = Promise); var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl); return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) { return result.done ? result.value : iter.next(); }); }, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, "Generator"), define(Gp, iteratorSymbol, function () { return this; }), define(Gp, "toString", function () { return "[object Generator]"; }), exports.keys = function (val) { var object = Object(val), keys = []; for (var key in object) keys.push(key); return keys.reverse(), function next() { for (; keys.length;) { var key = keys.pop(); if (key in object) return next.value = key, next.done = !1, next; } return next.done = !0, next; }; }, exports.values = values, Context.prototype = { constructor: Context, reset: function (skipTempReset) { if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = "next", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) "t" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined); }, stop: function () { this.done = !0; var rootRecord = this.tryEntries[0].completion; if ("throw" === rootRecord.type) throw rootRecord.arg; return this.rval; }, dispatchException: function (exception) { if (this.done) throw exception; var context = this; function handle(loc, caught) { return record.type = "throw", record.arg = exception, context.next = loc, caught && (context.method = "next", context.arg = undefined), !!caught; } for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i], record = entry.completion; if ("root" === entry.tryLoc) return handle("end"); if (entry.tryLoc <= this.prev) { var hasCatch = hasOwn.call(entry, "catchLoc"), hasFinally = hasOwn.call(entry, "finallyLoc"); if (hasCatch && hasFinally) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } else if (hasCatch) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); } else { if (!hasFinally) throw new Error("try statement without catch or finally"); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } } } }, abrupt: function (type, arg) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) { var finallyEntry = entry; break; } } finallyEntry && ("break" === type || "continue" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null); var record = finallyEntry ? finallyEntry.completion : {}; return record.type = type, record.arg = arg, finallyEntry ? (this.method = "next", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record); }, complete: function (record, afterLoc) { if ("throw" === record.type) throw record.arg; return "break" === record.type || "continue" === record.type ? this.next = record.arg : "return" === record.type ? (this.rval = this.arg = record.arg, this.method = "return", this.next = "end") : "normal" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel; }, finish: function (finallyLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel; } }, catch: function (tryLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc === tryLoc) { var record = entry.completion; if ("throw" === record.type) { var thrown = record.arg; resetTryEntry(entry); } return thrown; } } throw new Error("illegal catch attempt"); }, delegateYield: function (iterable, resultName, nextLoc) { return this.delegate = { iterator: values(iterable), resultName: resultName, nextLoc: nextLoc }, "next" === this.method && (this.arg = undefined), ContinueSentinel; } }, exports; } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } /** * Common utilities * @module glMatrix */ var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array; if (!Math.hypot) Math.hypot = function () { var y = 0, i = arguments.length; while (i--) { y += arguments[i] * arguments[i]; } return Math.sqrt(y); }; /** * 4x4 Matrix
Format: column-major, when typed out it looks like row-major
The matrices are being post multiplied. * @module mat4 */ /** * Creates a new identity mat4 * * @returns {mat4} a new 4x4 matrix */ function create() { var out = new ARRAY_TYPE(16); if (ARRAY_TYPE != Float32Array) { out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; } out[0] = 1; out[5] = 1; out[10] = 1; out[15] = 1; return out; } /** * Copy the values from one mat4 to another * * @param {mat4} out the receiving matrix * @param {ReadonlyMat4} a the source matrix * @returns {mat4} out */ function copy(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7]; out[8] = a[8]; out[9] = a[9]; out[10] = a[10]; out[11] = a[11]; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; return out; } /** * Inverts a mat4 * * @param {mat4} out the receiving matrix * @param {ReadonlyMat4} a the source matrix * @returns {mat4} out */ function invert(out, a) { var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; var b00 = a00 * a11 - a01 * a10; var b01 = a00 * a12 - a02 * a10; var b02 = a00 * a13 - a03 * a10; var b03 = a01 * a12 - a02 * a11; var b04 = a01 * a13 - a03 * a11; var b05 = a02 * a13 - a03 * a12; var b06 = a20 * a31 - a21 * a30; var b07 = a20 * a32 - a22 * a30; var b08 = a20 * a33 - a23 * a30; var b09 = a21 * a32 - a22 * a31; var b10 = a21 * a33 - a23 * a31; var b11 = a22 * a33 - a23 * a32; // Calculate the determinant var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; if (!det) { return null; } det = 1.0 / det; out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; return out; } /** * Multiplies two mat4s * * @param {mat4} out the receiving matrix * @param {ReadonlyMat4} a the first operand * @param {ReadonlyMat4} b the second operand * @returns {mat4} out */ function multiply(out, a, b) { var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; // Cache only the current line of the second matrix var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; return out; } /** * Translate a mat4 by the given vector * * @param {mat4} out the receiving matrix * @param {ReadonlyMat4} a the matrix to translate * @param {ReadonlyVec3} v vector to translate by * @returns {mat4} out */ function translate(out, a, v) { var x = v[0], y = v[1], z = v[2]; var a00, a01, a02, a03; var a10, a11, a12, a13; var a20, a21, a22, a23; if (a === out) { out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; } else { a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03; out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13; out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23; out[12] = a00 * x + a10 * y + a20 * z + a[12]; out[13] = a01 * x + a11 * y + a21 * z + a[13]; out[14] = a02 * x + a12 * y + a22 * z + a[14]; out[15] = a03 * x + a13 * y + a23 * z + a[15]; } return out; } /** * Creates a matrix from a vector scaling * This is equivalent to (but much faster than): * * mat4.identity(dest); * mat4.scale(dest, dest, vec); * * @param {mat4} out mat4 receiving operation result * @param {ReadonlyVec3} v Scaling vector * @returns {mat4} out */ function fromScaling(out, v) { out[0] = v[0]; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = v[1]; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[10] = v[2]; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1; return out; } /** * 3 Dimensional Vector * @module vec3 */ /** * Creates a new, empty vec3 * * @returns {vec3} a new 3D vector */ function create$1() { var out = new ARRAY_TYPE(3); if (ARRAY_TYPE != Float32Array) { out[0] = 0; out[1] = 0; out[2] = 0; } return out; } /** * Set the components of a vec3 to the given values * * @param {vec3} out the receiving vector * @param {Number} x X component * @param {Number} y Y component * @param {Number} z Z component * @returns {vec3} out */ function set(out, x, y, z) { out[0] = x; out[1] = y; out[2] = z; return out; } /** * Transforms the vec3 with a mat4. * 4th vector component is implicitly '1' * * @param {vec3} out the receiving vector * @param {ReadonlyVec3} a the vector to transform * @param {ReadonlyMat4} m matrix to transform with * @returns {vec3} out */ function transformMat4(out, a, m) { var x = a[0], y = a[1], z = a[2]; var w = m[3] * x + m[7] * y + m[11] * z + m[15]; w = w || 1.0; out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; return out; } /** * Perform some operation over an array of vec3s. * * @param {Array} a the array of vectors to iterate over * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed * @param {Number} offset Number of elements to skip at the beginning of the array * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array * @param {Function} fn Function to call for each vector in the array * @param {Object} [arg] additional argument to pass to fn * @returns {Array} a * @function */ var forEach = function () { var vec = create$1(); return function (a, stride, offset, count, fn, arg) { var i, l; if (!stride) { stride = 3; } if (!offset) { offset = 0; } if (count) { l = Math.min(count * stride + offset, a.length); } else { l = a.length; } for (i = offset; i < l; i += stride) { vec[0] = a[i]; vec[1] = a[i + 1]; vec[2] = a[i + 2]; fn(vec, vec, arg); a[i] = vec[0]; a[i + 1] = vec[1]; a[i + 2] = vec[2]; } return a; }; }(); /** * 2 Dimensional Vector * @module vec2 */ /** * Creates a new, empty vec2 * * @returns {vec2} a new 2D vector */ function create$2() { var out = new ARRAY_TYPE(2); if (ARRAY_TYPE != Float32Array) { out[0] = 0; out[1] = 0; } return out; } /** * Normalize a vec2 * * @param {vec2} out the receiving vector * @param {ReadonlyVec2} a vector to normalize * @returns {vec2} out */ function normalize(out, a) { var x = a[0], y = a[1]; var len = x * x + y * y; if (len > 0) { //TODO: evaluate use of glm_invsqrt here? len = 1 / Math.sqrt(len); } out[0] = a[0] * len; out[1] = a[1] * len; return out; } /** * Calculates the dot product of two vec2's * * @param {ReadonlyVec2} a the first operand * @param {ReadonlyVec2} b the second operand * @returns {Number} dot product of a and b */ function dot(a, b) { return a[0] * b[0] + a[1] * b[1]; } /** * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===) * * @param {ReadonlyVec2} a The first vector. * @param {ReadonlyVec2} b The second vector. * @returns {Boolean} True if the vectors are equal, false otherwise. */ function exactEquals(a, b) { return a[0] === b[0] && a[1] === b[1]; } /** * Perform some operation over an array of vec2s. * * @param {Array} a the array of vectors to iterate over * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed * @param {Number} offset Number of elements to skip at the beginning of the array * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array * @param {Function} fn Function to call for each vector in the array * @param {Object} [arg] additional argument to pass to fn * @returns {Array} a * @function */ var forEach$1 = function () { var vec = create$2(); return function (a, stride, offset, count, fn, arg) { var i, l; if (!stride) { stride = 2; } if (!offset) { offset = 0; } if (count) { l = Math.min(count * stride + offset, a.length); } else { l = a.length; } for (i = offset; i < l; i += stride) { vec[0] = a[i]; vec[1] = a[i + 1]; fn(vec, vec, arg); a[i] = vec[0]; a[i + 1] = vec[1]; } return a; }; }(); function rotateVector(x, y, rad) { var X = x * Math.cos(rad) - y * Math.sin(rad); var Y = x * Math.sin(rad) + y * Math.cos(rad); return { x: X, y: Y }; } /** * Converts A (arc-to) segments to C (cubic-bezier-to). * * For more information of where this math came from visit: * http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes */ function arcToCubic(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, recursive) { var x1 = X1; var y1 = Y1; var rx = RX; var ry = RY; var x2 = X2; var y2 = Y2; // for more information of where this Math came from visit: // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes var d120 = (Math.PI * 120) / 180; var rad = (Math.PI / 180) * (+angle || 0); /** @type {number[]} */ var res = []; var xy; var f1; var f2; var cx; var cy; if (!recursive) { xy = rotateVector(x1, y1, -rad); x1 = xy.x; y1 = xy.y; xy = rotateVector(x2, y2, -rad); x2 = xy.x; y2 = xy.y; var x = (x1 - x2) / 2; var y = (y1 - y2) / 2; var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); if (h > 1) { h = Math.sqrt(h); rx *= h; ry *= h; } var rx2 = rx * rx; var ry2 = ry * ry; var k = (LAF === SF ? -1 : 1) * Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))); cx = (k * rx * y) / ry + (x1 + x2) / 2; cy = (k * -ry * x) / rx + (y1 + y2) / 2; // eslint-disable-next-line no-bitwise -- Impossible to satisfy no-bitwise f1 = Math.asin(((((y1 - cy) / ry) * Math.pow(10, 9)) >> 0) / Math.pow(10, 9)); // eslint-disable-next-line no-bitwise -- Impossible to satisfy no-bitwise f2 = Math.asin(((((y2 - cy) / ry) * Math.pow(10, 9)) >> 0) / Math.pow(10, 9)); f1 = x1 < cx ? Math.PI - f1 : f1; f2 = x2 < cx ? Math.PI - f2 : f2; if (f1 < 0) f1 = Math.PI * 2 + f1; if (f2 < 0) f2 = Math.PI * 2 + f2; if (SF && f1 > f2) { f1 -= Math.PI * 2; } if (!SF && f2 > f1) { f2 -= Math.PI * 2; } } else { f1 = recursive[0], f2 = recursive[1], cx = recursive[2], cy = recursive[3]; } var df = f2 - f1; if (Math.abs(df) > d120) { var f2old = f2; var x2old = x2; var y2old = y2; f2 = f1 + d120 * (SF && f2 > f1 ? 1 : -1); x2 = cx + rx * Math.cos(f2); y2 = cy + ry * Math.sin(f2); res = arcToCubic(x2, y2, rx, ry, angle, 0, SF, x2old, y2old, [f2, f2old, cx, cy]); } df = f2 - f1; var c1 = Math.cos(f1); var s1 = Math.sin(f1); var c2 = Math.cos(f2); var s2 = Math.sin(f2); var t = Math.tan(df / 4); var hx = (4 / 3) * rx * t; var hy = (4 / 3) * ry * t; var m1 = [x1, y1]; var m2 = [x1 + hx * s1, y1 - hy * c1]; var m3 = [x2 + hx * s2, y2 - hy * c2]; var m4 = [x2, y2]; m2[0] = 2 * m1[0] - m2[0]; m2[1] = 2 * m1[1] - m2[1]; if (recursive) { return m2.concat(m3, m4, res); // return [...m2, ...m3, ...m4, ...res]; } res = m2.concat(m3, m4, res); // res = [...m2, ...m3, ...m4, ...res]; var newres = []; for (var i = 0, ii = res.length; i < ii; i += 1) { newres[i] = i % 2 ? rotateVector(res[i - 1], res[i], rad).y : rotateVector(res[i], res[i + 1], rad).x; } return newres; } // const TAU = Math.PI * 2; // const mapToEllipse = ( // { x, y }: { x: number; y: number }, // rx: number, // ry: number, // cosphi: number, // sinphi: number, // centerx: number, // centery: number, // ) => { // x *= rx; // y *= ry; // const xp = cosphi * x - sinphi * y; // const yp = sinphi * x + cosphi * y; // return { // x: xp + centerx, // y: yp + centery, // }; // }; // const approxUnitArc = (ang1: number, ang2: number) => { // // If 90 degree circular arc, use a constant // // as derived from http://spencermortensen.com/articles/bezier-circle // const a = // ang2 === 1.5707963267948966 // ? 0.551915024494 // : ang2 === -1.5707963267948966 // ? -0.551915024494 // : (4 / 3) * Math.tan(ang2 / 4); // const x1 = Math.cos(ang1); // const y1 = Math.sin(ang1); // const x2 = Math.cos(ang1 + ang2); // const y2 = Math.sin(ang1 + ang2); // return [ // { // x: x1 - y1 * a, // y: y1 + x1 * a, // }, // { // x: x2 + y2 * a, // y: y2 - x2 * a, // }, // { // x: x2, // y: y2, // }, // ]; // }; // const vectorAngle = (ux: number, uy: number, vx: number, vy: number) => { // const sign = ux * vy - uy * vx < 0 ? -1 : 1; // let dot = ux * vx + uy * vy; // if (dot > 1) { // dot = 1; // } // if (dot < -1) { // dot = -1; // } // return sign * Math.acos(dot); // }; // const getArcCenter = ( // px: any, // py: any, // cx: any, // cy: any, // rx: number, // ry: number, // largeArcFlag: number, // sweepFlag: number, // sinphi: number, // cosphi: number, // pxp: number, // pyp: number, // ) => { // const rxsq = Math.pow(rx, 2); // const rysq = Math.pow(ry, 2); // const pxpsq = Math.pow(pxp, 2); // const pypsq = Math.pow(pyp, 2); // let radicant = rxsq * rysq - rxsq * pypsq - rysq * pxpsq; // if (radicant < 0) { // radicant = 0; // } // radicant /= rxsq * pypsq + rysq * pxpsq; // radicant = Math.sqrt(radicant) * (largeArcFlag === sweepFlag ? -1 : 1); // const centerxp = ((radicant * rx) / ry) * pyp; // const centeryp = ((radicant * -ry) / rx) * pxp; // const centerx = cosphi * centerxp - sinphi * centeryp + (px + cx) / 2; // const centery = sinphi * centerxp + cosphi * centeryp + (py + cy) / 2; // const vx1 = (pxp - centerxp) / rx; // const vy1 = (pyp - centeryp) / ry; // const vx2 = (-pxp - centerxp) / rx; // const vy2 = (-pyp - centeryp) / ry; // const ang1 = vectorAngle(1, 0, vx1, vy1); // let ang2 = vectorAngle(vx1, vy1, vx2, vy2); // if (sweepFlag === 0 && ang2 > 0) { // ang2 -= TAU; // } // if (sweepFlag === 1 && ang2 < 0) { // ang2 += TAU; // } // return [centerx, centery, ang1, ang2]; // }; // const arcToBezier = ({ px, py, cx, cy, rx, ry, xAxisRotation = 0, largeArcFlag = 0, sweepFlag = 0 }) => { // const curves = []; // if (rx === 0 || ry === 0) { // return [{ x1: 0, y1: 0, x2: 0, y2: 0, x: cx, y: cy }]; // } // const sinphi = Math.sin((xAxisRotation * TAU) / 360); // const cosphi = Math.cos((xAxisRotation * TAU) / 360); // const pxp = (cosphi * (px - cx)) / 2 + (sinphi * (py - cy)) / 2; // const pyp = (-sinphi * (px - cx)) / 2 + (cosphi * (py - cy)) / 2; // if (pxp === 0 && pyp === 0) { // return [{ x1: 0, y1: 0, x2: 0, y2: 0, x: cx, y: cy }]; // } // rx = Math.abs(rx); // ry = Math.abs(ry); // const lambda = Math.pow(pxp, 2) / Math.pow(rx, 2) + Math.pow(pyp, 2) / Math.pow(ry, 2); // if (lambda > 1) { // rx *= Math.sqrt(lambda); // ry *= Math.sqrt(lambda); // } // let [centerx, centery, ang1, ang2] = getArcCenter( // px, // py, // cx, // cy, // rx, // ry, // largeArcFlag, // sweepFlag, // sinphi, // cosphi, // pxp, // pyp, // ); // // If 'ang2' == 90.0000000001, then `ratio` will evaluate to // // 1.0000000001. This causes `segments` to be greater than one, which is an // // unecessary split, and adds extra points to the bezier curve. To alleviate // // this issue, we round to 1.0 when the ratio is close to 1.0. // let ratio = Math.abs(ang2) / (TAU / 4); // if (Math.abs(1.0 - ratio) < 0.0000001) { // ratio = 1.0; // } // const segments = Math.max(Math.ceil(ratio), 1); // ang2 /= segments; // for (let i = 0; i < segments; i++) { // curves.push(approxUnitArc(ang1, ang2)); // ang1 += ang2; // } // return curves.map((curve) => { // const { x: x1, y: y1 } = mapToEllipse(curve[0], rx, ry, cosphi, sinphi, centerx, centery); // const { x: x2, y: y2 } = mapToEllipse(curve[1], rx, ry, cosphi, sinphi, centerx, centery); // const { x, y } = mapToEllipse(curve[2], rx, ry, cosphi, sinphi, centerx, centery); // return { x1, y1, x2, y2, x, y }; // }); // }; // export function arcToCubic( // x1: number, // y1: number, // rx: number, // ry: number, // angle: number, // LAF: number, // SF: number, // x2: number, // y2: number, // ) { // const curves = arcToBezier({ // px: x1, // py: y1, // cx: x2, // cy: y2, // rx, // ry, // xAxisRotation: angle, // largeArcFlag: LAF, // sweepFlag: SF, // }); // return curves.reduce((prev, cur) => { // const { x1, y1, x2, y2, x, y } = cur; // prev.push(x1, y1, x2, y2, x, y); // return prev; // }, [] as number[]); // } // isFinite, var isNil = function (value) { /** * isNil(null) => true * isNil() => true */ return value === null || value === undefined; }; var toString = {}.toString; var isType = function (value, type) { return toString.call(value) === '[object ' + type + ']'; }; var isString = (function (str) { return isType(str, 'String'); }); var clamp = function (a, min, max) { if (a < min) { return min; } else if (a > max) { return max; } return a; }; /** * 判断是否数字 * @return {Boolean} 是否数字 */ var isNumber = function (value) { return isType(value, 'Number'); }; function _inheritsLoose$1(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf$1(subClass, superClass); } function _setPrototypeOf$1(o, p) { _setPrototypeOf$1 = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf$1(o, p); } function generatePath(context, parsedStyle) { var r = parsedStyle.r; context.arc(r, r, r, 0, Math.PI * 2, false); } function generatePath$1(context, parsedStyle) { var rxInPixels = parsedStyle.rx, ryInPixels = parsedStyle.ry; var rx = rxInPixels; var ry = ryInPixels; // @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/ellipse if (context.ellipse) { context.ellipse(rx, ry, rx, ry, 0, 0, Math.PI * 2, false); } else { // 如果不支持,则使用圆来绘制,进行变形 var r = rx > ry ? rx : ry; var scaleX = rx > ry ? 1 : rx / ry; var scaleY = rx > ry ? ry / rx : 1; context.save(); context.scale(scaleX, scaleY); context.arc(0, 0, r, 0, Math.PI * 2); } } function generatePath$2(context, parsedStyle) { var x1 = parsedStyle.x1, y1 = parsedStyle.y1, x2 = parsedStyle.x2, y2 = parsedStyle.y2, _parsedStyle$defX = parsedStyle.defX, defX = _parsedStyle$defX === void 0 ? 0 : _parsedStyle$defX, _parsedStyle$defY = parsedStyle.defY, defY = _parsedStyle$defY === void 0 ? 0 : _parsedStyle$defY, markerStart = parsedStyle.markerStart, markerEnd = parsedStyle.markerEnd, markerStartOffset = parsedStyle.markerStartOffset, markerEndOffset = parsedStyle.markerEndOffset; var startOffsetX = 0; var startOffsetY = 0; var endOffsetX = 0; var endOffsetY = 0; var rad = 0; var x; var y; if (markerStart && gLite.isDisplayObject(markerStart) && markerStartOffset) { x = x2 - x1; y = y2 - y1; rad = Math.atan2(y, x); startOffsetX = Math.cos(rad) * (markerStartOffset || 0); startOffsetY = Math.sin(rad) * (markerStartOffset || 0); } if (markerEnd && gLite.isDisplayObject(markerEnd) && markerEndOffset) { x = x1 - x2; y = y1 - y2; rad = Math.atan2(y, x); endOffsetX = Math.cos(rad) * (markerEndOffset || 0); endOffsetY = Math.sin(rad) * (markerEndOffset || 0); } context.moveTo(x1 - defX + startOffsetX, y1 - defY + startOffsetY); context.lineTo(x2 - defX + endOffsetX, y2 - defY + endOffsetY); } function generatePath$3(context, parsedStyle) { var _parsedStyle$defX = parsedStyle.defX, defX = _parsedStyle$defX === void 0 ? 0 : _parsedStyle$defX, _parsedStyle$defY = parsedStyle.defY, defY = _parsedStyle$defY === void 0 ? 0 : _parsedStyle$defY, markerStart = parsedStyle.markerStart, markerEnd = parsedStyle.markerEnd, markerStartOffset = parsedStyle.markerStartOffset, markerEndOffset = parsedStyle.markerEndOffset; var _parsedStyle$path = parsedStyle.path, absolutePath = _parsedStyle$path.absolutePath, segments = _parsedStyle$path.segments; var startOffsetX = 0; var startOffsetY = 0; var endOffsetX = 0; var endOffsetY = 0; var rad = 0; var x; var y; if (markerStart && gLite.isDisplayObject(markerStart) && markerStartOffset) { var _markerStart$parentNo = markerStart.parentNode.getStartTangent(), p1 = _markerStart$parentNo[0], p2 = _markerStart$parentNo[1]; x = p1[0] - p2[0]; y = p1[1] - p2[1]; rad = Math.atan2(y, x); startOffsetX = Math.cos(rad) * (markerStartOffset || 0); startOffsetY = Math.sin(rad) * (markerStartOffset || 0); } if (markerEnd && gLite.isDisplayObject(markerEnd) && markerEndOffset) { var _markerEnd$parentNode = markerEnd.parentNode.getEndTangent(), _p = _markerEnd$parentNode[0], _p2 = _markerEnd$parentNode[1]; x = _p[0] - _p2[0]; y = _p[1] - _p2[1]; rad = Math.atan2(y, x); endOffsetX = Math.cos(rad) * (markerEndOffset || 0); endOffsetY = Math.sin(rad) * (markerEndOffset || 0); } for (var i = 0; i < absolutePath.length; i++) { var params = absolutePath[i]; var command = params[0]; var nextSegment = absolutePath[i + 1]; var useStartOffset = i === 0 && (startOffsetX !== 0 || startOffsetY !== 0); var useEndOffset = (i === absolutePath.length - 1 || nextSegment && (nextSegment[0] === 'M' || nextSegment[0] === 'Z')) && endOffsetX !== 0 && endOffsetY !== 0; switch (command) { case 'M': // Use start marker offset if (useStartOffset) { context.moveTo(params[1] - defX + startOffsetX, params[2] - defY + startOffsetY); context.lineTo(params[1] - defX, params[2] - defY); } else { context.moveTo(params[1] - defX, params[2] - defY); } break; case 'L': if (useEndOffset) { context.lineTo(params[1] - defX + endOffsetX, params[2] - defY + endOffsetY); } else { context.lineTo(params[1] - defX, params[2] - defY); } break; case 'Q': context.quadraticCurveTo(params[1] - defX, params[2] - defY, params[3] - defX, params[4] - defY); if (useEndOffset) { context.lineTo(params[3] - defX + endOffsetX, params[4] - defY + endOffsetY); } break; case 'C': context.bezierCurveTo(params[1] - defX, params[2] - defY, params[3] - defX, params[4] - defY, params[5] - defX, params[6] - defY); if (useEndOffset) { context.lineTo(params[5] - defX + endOffsetX, params[6] - defY + endOffsetY); } break; case 'A': { var arcParams = segments[i].arcParams; var cx = arcParams.cx, cy = arcParams.cy, rx = arcParams.rx, ry = arcParams.ry, startAngle = arcParams.startAngle, endAngle = arcParams.endAngle, xRotation = arcParams.xRotation, sweepFlag = arcParams.sweepFlag; // @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/ellipse if (context.ellipse) { context.ellipse(cx - defX, cy - defY, rx, ry, xRotation, startAngle, endAngle, !!(1 - sweepFlag)); } else { // @see https://stackoverflow.com/a/47494351 var r = rx > ry ? rx : ry; var scaleX = rx > ry ? 1 : rx / ry; var scaleY = rx > ry ? ry / rx : 1; context.translate(cx - defX, cy - defY); context.rotate(xRotation); context.scale(scaleX, scaleY); context.arc(0, 0, r, startAngle, endAngle, !!(1 - sweepFlag)); context.scale(1 / scaleX, 1 / scaleY); context.rotate(-xRotation); context.translate(-(cx - defX), -(cy - defY)); } if (useEndOffset) { context.lineTo(params[6] - defX + endOffsetX, params[7] - defY + endOffsetY); } break; } case 'Z': context.closePath(); break; } } } function generatePath$4(context, parsedStyle) { var _parsedStyle$defX = parsedStyle.defX, defX = _parsedStyle$defX === void 0 ? 0 : _parsedStyle$defX, _parsedStyle$defY = parsedStyle.defY, defY = _parsedStyle$defY === void 0 ? 0 : _parsedStyle$defY, markerStart = parsedStyle.markerStart, markerEnd = parsedStyle.markerEnd, markerStartOffset = parsedStyle.markerStartOffset, markerEndOffset = parsedStyle.markerEndOffset; var points = parsedStyle.points.points; var length = points.length; var x1 = points[0][0] - defX; var y1 = points[0][1] - defY; var x2 = points[length - 1][0] - defX; var y2 = points[length - 1][1] - defY; var startOffsetX = 0; var startOffsetY = 0; var endOffsetX = 0; var endOffsetY = 0; var rad = 0; var x; var y; if (markerStart && gLite.isDisplayObject(markerStart) && markerStartOffset) { x = points[1][0] - points[0][0]; y = points[1][1] - points[0][1]; rad = Math.atan2(y, x); startOffsetX = Math.cos(rad) * (markerStartOffset || 0); startOffsetY = Math.sin(rad) * (markerStartOffset || 0); } if (markerEnd && gLite.isDisplayObject(markerEnd) && markerEndOffset) { x = points[length - 1][0] - points[0][0]; y = points[length - 1][1] - points[0][1]; rad = Math.atan2(y, x); endOffsetX = Math.cos(rad) * (markerEndOffset || 0); endOffsetY = Math.sin(rad) * (markerEndOffset || 0); } context.moveTo(x1 + (startOffsetX || endOffsetX), y1 + (startOffsetY || endOffsetY)); for (var i = 1; i < length - 1; i++) { var point = points[i]; context.lineTo(point[0] - defX, point[1] - defY); } context.lineTo(x2, y2); } function generatePath$5(context, parsedStyle) { var _parsedStyle$defX = parsedStyle.defX, defX = _parsedStyle$defX === void 0 ? 0 : _parsedStyle$defX, _parsedStyle$defY = parsedStyle.defY, defY = _parsedStyle$defY === void 0 ? 0 : _parsedStyle$defY, markerStart = parsedStyle.markerStart, markerEnd = parsedStyle.markerEnd, markerStartOffset = parsedStyle.markerStartOffset, markerEndOffset = parsedStyle.markerEndOffset; var points = parsedStyle.points.points; var length = points.length; var x1 = points[0][0] - defX; var y1 = points[0][1] - defY; var x2 = points[length - 1][0] - defX; var y2 = points[length - 1][1] - defY; var startOffsetX = 0; var startOffsetY = 0; var endOffsetX = 0; var endOffsetY = 0; var rad = 0; var x; var y; if (markerStart && gLite.isDisplayObject(markerStart) && markerStartOffset) { x = points[1][0] - points[0][0]; y = points[1][1] - points[0][1]; rad = Math.atan2(y, x); startOffsetX = Math.cos(rad) * (markerStartOffset || 0); startOffsetY = Math.sin(rad) * (markerStartOffset || 0); } if (markerEnd && gLite.isDisplayObject(markerEnd) && markerEndOffset) { x = points[length - 2][0] - points[length - 1][0]; y = points[length - 2][1] - points[length - 1][1]; rad = Math.atan2(y, x); endOffsetX = Math.cos(rad) * (markerEndOffset || 0); endOffsetY = Math.sin(rad) * (markerEndOffset || 0); } context.moveTo(x1 + startOffsetX, y1 + startOffsetY); for (var i = 1; i < length - 1; i++) { var point = points[i]; context.lineTo(point[0] - defX, point[1] - defY); } context.lineTo(x2 + endOffsetX, y2 + endOffsetY); } function generatePath$6(context, parsedStyle) { var radius = parsedStyle.radius, width = parsedStyle.width, height = parsedStyle.height; var w = width; var h = height; var hasRadius = radius && radius.some(function (r) { return r !== 0; }); if (!hasRadius) { // Canvas support negative width/height of rect context.rect(0, 0, w, h); } else { var signX = width > 0 ? 1 : -1; var signY = height > 0 ? 1 : -1; var sweepFlag = signX + signY === 0; var _radius$map = radius.map(function (r) { return clamp(r, 0, Math.min(Math.abs(w) / 2, Math.abs(h) / 2)); }), tlr = _radius$map[0], trr = _radius$map[1], brr = _radius$map[2], blr = _radius$map[3]; context.moveTo(signX * tlr, 0); context.lineTo(w - signX * trr, 0); if (trr !== 0) { context.arc(w - signX * trr, signY * trr, trr, -signY * Math.PI / 2, signX > 0 ? 0 : Math.PI, sweepFlag); } context.lineTo(w, h - signY * brr); if (brr !== 0) { context.arc(w - signX * brr, h - signY * brr, brr, signX > 0 ? 0 : Math.PI, signY > 0 ? Math.PI / 2 : 1.5 * Math.PI, sweepFlag); } context.lineTo(signX * blr, h); if (blr !== 0) { context.arc(signX * blr, h - signY * blr, blr, signY > 0 ? Math.PI / 2 : -Math.PI / 2, signX > 0 ? Math.PI : 0, sweepFlag); } context.lineTo(0, signY * tlr); if (tlr !== 0) { context.arc(signX * tlr, signY * tlr, tlr, signX > 0 ? Math.PI : 0, signY > 0 ? Math.PI * 1.5 : Math.PI / 2, sweepFlag); } } } var Plugin = /*#__PURE__*/function (_AbstractRendererPlug) { _inheritsLoose$1(Plugin, _AbstractRendererPlug); function Plugin() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _AbstractRendererPlug.call.apply(_AbstractRendererPlug, [this].concat(args)) || this; _this.name = 'canvas-path-generator'; return _this; } var _proto = Plugin.prototype; _proto.init = function init() { var _pathGeneratorFactory; var pathGeneratorFactory = (_pathGeneratorFactory = {}, _pathGeneratorFactory[gLite.Shape.CIRCLE] = generatePath, _pathGeneratorFactory[gLite.Shape.ELLIPSE] = generatePath$1, _pathGeneratorFactory[gLite.Shape.RECT] = generatePath$6, _pathGeneratorFactory[gLite.Shape.LINE] = generatePath$2, _pathGeneratorFactory[gLite.Shape.POLYLINE] = generatePath$5, _pathGeneratorFactory[gLite.Shape.POLYGON] = generatePath$4, _pathGeneratorFactory[gLite.Shape.PATH] = generatePath$3, _pathGeneratorFactory[gLite.Shape.TEXT] = undefined, _pathGeneratorFactory[gLite.Shape.GROUP] = undefined, _pathGeneratorFactory[gLite.Shape.IMAGE] = undefined, _pathGeneratorFactory[gLite.Shape.HTML] = undefined, _pathGeneratorFactory[gLite.Shape.MESH] = undefined, _pathGeneratorFactory); // @ts-ignore this.context.pathGeneratorFactory = pathGeneratorFactory; }; _proto.destroy = function destroy() { // @ts-ignore delete this.context.pathGeneratorFactory; }; return Plugin; }(gLite.AbstractRendererPlugin); var index_esm = /*#__PURE__*/Object.freeze({ __proto__: null, Plugin: Plugin }); function _regeneratorRuntime$1() { _regeneratorRuntime$1 = function _regeneratorRuntime() { return exports; }; var exports = {}, Op = Object.prototype, hasOwn = Op.hasOwnProperty, defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; }, $Symbol = "function" == typeof Symbol ? Symbol : {}, iteratorSymbol = $Symbol.iterator || "@@iterator", asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator", toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; function define(obj, key, value) { return Object.defineProperty(obj, key, { value: value, enumerable: !0, configurable: !0, writable: !0 }), obj[key]; } try { define({}, ""); } catch (err) { define = function define(obj, key, value) { return obj[key] = value; }; } function wrap(innerFn, outerFn, self, tryLocsList) { var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator, generator = Object.create(protoGenerator.prototype), context = new Context(tryLocsList || []); return defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) }), generator; } function tryCatch(fn, obj, arg) { try { return { type: "normal", arg: fn.call(obj, arg) }; } catch (err) { return { type: "throw", arg: err }; } } exports.wrap = wrap; var ContinueSentinel = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var IteratorPrototype = {}; define(IteratorPrototype, iteratorSymbol, function () { return this; }); var getProto = Object.getPrototypeOf, NativeIteratorPrototype = getProto && getProto(getProto(values([]))); NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype); var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype); function defineIteratorMethods(prototype) { ["next", "throw", "return"].forEach(function (method) { define(prototype, method, function (arg) { return this._invoke(method, arg); }); }); } function AsyncIterator(generator, PromiseImpl) { function invoke(method, arg, resolve, reject) { var record = tryCatch(generator[method], generator, arg); if ("throw" !== record.type) { var result = record.arg, value = result.value; return value && "object" == typeof value && hasOwn.call(value, "__await") ? PromiseImpl.resolve(value.__await).then(function (value) { invoke("next", value, resolve, reject); }, function (err) { invoke("throw", err, resolve, reject); }) : PromiseImpl.resolve(value).then(function (unwrapped) { result.value = unwrapped, resolve(result); }, function (error) { return invoke("throw", error, resolve, reject); }); } reject(record.arg); } var previousPromise; defineProperty(this, "_invoke", { value: function value(method, arg) { function callInvokeWithMethodAndArg() { return new PromiseImpl(function (resolve, reject) { invoke(method, arg, resolve, reject); }); } return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(innerFn, self, context) { var state = "suspendedStart"; return function (method, arg) { if ("executing" === state) throw new Error("Generator is already running"); if ("completed" === state) { if ("throw" === method) throw arg; return doneResult(); } for (context.method = method, context.arg = arg;;) { var delegate = context.delegate; if (delegate) { var delegateResult = maybeInvokeDelegate(delegate, context); if (delegateResult) { if (delegateResult === ContinueSentinel) continue; return delegateResult; } } if ("next" === context.method) context.sent = context._sent = context.arg;else if ("throw" === context.method) { if ("suspendedStart" === state) throw state = "completed", context.arg; context.dispatchException(context.arg); } else "return" === context.method && context.abrupt("return", context.arg); state = "executing"; var record = tryCatch(innerFn, self, context); if ("normal" === record.type) { if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue; return { value: record.arg, done: context.done }; } "throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg); } }; } function maybeInvokeDelegate(delegate, context) { var methodName = context.method, method = delegate.iterator[methodName]; if (undefined === method) return context.delegate = null, "throw" === methodName && delegate.iterator.return && (context.method = "return", context.arg = undefined, maybeInvokeDelegate(delegate, context), "throw" === context.method) || "return" !== methodName && (context.method = "throw", context.arg = new TypeError("The iterator does not provide a '" + methodName + "' method")), ContinueSentinel; var record = tryCatch(method, delegate.iterator, context.arg); if ("throw" === record.type) return context.method = "throw", context.arg = record.arg, context.delegate = null, ContinueSentinel; var info = record.arg; return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, "return" !== context.method && (context.method = "next", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = "throw", context.arg = new TypeError("iterator result is not an object"), context.delegate = null, ContinueSentinel); } function pushTryEntry(locs) { var entry = { tryLoc: locs[0] }; 1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry); } function resetTryEntry(entry) { var record = entry.completion || {}; record.type = "normal", delete record.arg, entry.completion = record; } function Context(tryLocsList) { this.tryEntries = [{ tryLoc: "root" }], tryLocsList.forEach(pushTryEntry, this), this.reset(!0); } function values(iterable) { if (iterable) { var iteratorMethod = iterable[iteratorSymbol]; if (iteratorMethod) return iteratorMethod.call(iterable); if ("function" == typeof iterable.next) return iterable; if (!isNaN(iterable.length)) { var i = -1, next = function next() { for (; ++i < iterable.length;) if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next; return next.value = undefined, next.done = !0, next; }; return next.next = next; } } return { next: doneResult }; } function doneResult() { return { value: undefined, done: !0 }; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), defineProperty(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) { var ctor = "function" == typeof genFun && genFun.constructor; return !!ctor && (ctor === GeneratorFunction || "GeneratorFunction" === (ctor.displayName || ctor.name)); }, exports.mark = function (genFun) { return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, "GeneratorFunction")), genFun.prototype = Object.create(Gp), genFun; }, exports.awrap = function (arg) { return { __await: arg }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () { return this; }), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) { void 0 === PromiseImpl && (PromiseImpl = Promise); var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl); return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) { return result.done ? result.value : iter.next(); }); }, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, "Generator"), define(Gp, iteratorSymbol, function () { return this; }), define(Gp, "toString", function () { return "[object Generator]"; }), exports.keys = function (val) { var object = Object(val), keys = []; for (var key in object) keys.push(key); return keys.reverse(), function next() { for (; keys.length;) { var key = keys.pop(); if (key in object) return next.value = key, next.done = !1, next; } return next.done = !0, next; }; }, exports.values = values, Context.prototype = { constructor: Context, reset: function reset(skipTempReset) { if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = "next", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) "t" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined); }, stop: function stop() { this.done = !0; var rootRecord = this.tryEntries[0].completion; if ("throw" === rootRecord.type) throw rootRecord.arg; return this.rval; }, dispatchException: function dispatchException(exception) { if (this.done) throw exception; var context = this; function handle(loc, caught) { return record.type = "throw", record.arg = exception, context.next = loc, caught && (context.method = "next", context.arg = undefined), !!caught; } for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i], record = entry.completion; if ("root" === entry.tryLoc) return handle("end"); if (entry.tryLoc <= this.prev) { var hasCatch = hasOwn.call(entry, "catchLoc"), hasFinally = hasOwn.call(entry, "finallyLoc"); if (hasCatch && hasFinally) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } else if (hasCatch) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); } else { if (!hasFinally) throw new Error("try statement without catch or finally"); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } } } }, abrupt: function abrupt(type, arg) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) { var finallyEntry = entry; break; } } finallyEntry && ("break" === type || "continue" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null); var record = finallyEntry ? finallyEntry.completion : {}; return record.type = type, record.arg = arg, finallyEntry ? (this.method = "next", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record); }, complete: function complete(record, afterLoc) { if ("throw" === record.type) throw record.arg; return "break" === record.type || "continue" === record.type ? this.next = record.arg : "return" === record.type ? (this.rval = this.arg = record.arg, this.method = "return", this.next = "end") : "normal" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel; }, finish: function finish(finallyLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel; } }, catch: function _catch(tryLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc === tryLoc) { var record = entry.completion; if ("throw" === record.type) { var thrown = record.arg; resetTryEntry(entry); } return thrown; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(iterable, resultName, nextLoc) { return this.delegate = { iterator: values(iterable), resultName: resultName, nextLoc: nextLoc }, "next" === this.method && (this.arg = undefined), ContinueSentinel; } }, exports; } function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator$1(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _inheritsLoose$2(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf$2(subClass, superClass); } function _setPrototypeOf$2(o, p) { _setPrototypeOf$2 = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf$2(o, p); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var tmpVec3a = create$1(); var tmpVec3b = create$1(); var tmpVec3c = create$1(); var tmpMat4 = create(); /** * pick shape(s) with Mouse/Touch event * * 1. find AABB with r-tree * 2. do math calculation with geometry in an accurate way */ var CanvasPickerPlugin = /*#__PURE__*/function () { function CanvasPickerPlugin() { var _this = this; this.context = void 0; this.runtime = void 0; this.isHit = function (displayObject, position, worldTransform, isClipPath) { // use picker for current shape's type var pick = _this.context.pointInPathPickerFactory[displayObject.nodeName]; if (pick) { // invert with world matrix var invertWorldMat = invert(tmpMat4, worldTransform); // transform client position to local space, do picking in local space var localPosition = transformMat4(tmpVec3b, set(tmpVec3c, position[0], position[1], 0), invertWorldMat); // account for anchor var _displayObject$getGeo = displayObject.getGeometryBounds(), halfExtents = _displayObject$getGeo.halfExtents; var anchor = displayObject.parsedStyle.anchor; localPosition[0] += (anchor && anchor[0] || 0) * halfExtents[0] * 2; localPosition[1] += (anchor && anchor[1] || 0) * halfExtents[1] * 2; if (pick(displayObject, new gLite.Point(localPosition[0], localPosition[1]), isClipPath, _this.isPointInPath, _this.context, _this.runtime)) { return true; } } return false; }; /** * use native picking method * @see https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/isPointInPath */ this.isPointInPath = function (displayObject, position) { var context = _this.runtime.offscreenCanvas.getOrCreateContext(_this.context.config.offscreenCanvas); var generatePath = _this.context.pathGeneratorFactory[displayObject.nodeName]; if (generatePath) { context.beginPath(); generatePath(context, displayObject.parsedStyle); context.closePath(); } return context.isPointInPath(position.x, position.y); }; } var _proto = CanvasPickerPlugin.prototype; _proto.apply = function apply(context, runtime) { var _renderingContext$roo, _this2 = this; var renderingService = context.renderingService, renderingContext = context.renderingContext; this.context = context; this.runtime = runtime; var document = (_renderingContext$roo = renderingContext.root) === null || _renderingContext$roo === void 0 ? void 0 : _renderingContext$roo.ownerDocument; renderingService.hooks.pick.tapPromise(CanvasPickerPlugin.tag, /*#__PURE__*/function () { var _ref = _asyncToGenerator$1( /*#__PURE__*/_regeneratorRuntime$1().mark(function _callee(result) { return _regeneratorRuntime$1().wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: return _context.abrupt("return", _this2.pick(document, result)); case 1: case "end": return _context.stop(); } }, _callee); })); return function (_x) { return _ref.apply(this, arguments); }; }()); renderingService.hooks.pickSync.tap(CanvasPickerPlugin.tag, function (result) { return _this2.pick(document, result); }); }; _proto.pick = function pick(document, result) { var topmost = result.topmost, _result$position = result.position, x = _result$position.x, y = _result$position.y; // position in world space var position = set(tmpVec3a, x, y, 0); // query by AABB first with spatial index(r-tree) var hitTestList = document.elementsFromBBox(position[0], position[1], position[0], position[1]); // test with clip path & origin shape // @see https://github.com/antvis/g/issues/1064 var pickedDisplayObjects = []; for (var _iterator = _createForOfIteratorHelperLoose(hitTestList), _step; !(_step = _iterator()).done;) { var displayObject = _step.value; var worldTransform = displayObject.getWorldTransform(); var isHitOriginShape = this.isHit(displayObject, position, worldTransform, false); if (isHitOriginShape) { // should look up in the ancestor node var clipped = gLite.findClosestClipPathTarget(displayObject); if (clipped) { var clipPath = clipped.parsedStyle.clipPath; var isHitClipPath = this.isHit(clipPath, position, clipPath.getWorldTransform(), true); if (isHitClipPath) { if (topmost) { result.picked = [displayObject]; return result; } else { pickedDisplayObjects.push(displayObject); } } } else { if (topmost) { result.picked = [displayObject]; return result; } else { pickedDisplayObjects.push(displayObject); } } } } result.picked = pickedDisplayObjects; return result; }; return CanvasPickerPlugin; }(); CanvasPickerPlugin.tag = 'CanvasPicker'; /** * 两点之间的距离 * @param {number} x1 起始点 x * @param {number} y1 起始点 y * @param {number} x2 结束点 x * @param {number} y2 结束点 y * @return {number} 距离 */ function distance(x1, y1, x2, y2) { var dx = x1 - x2; var dy = y1 - y2; return Math.sqrt(dx * dx + dy * dy); } function isNumberEqual(v1, v2) { return Math.abs(v1 - v2) < 0.001; } function getBBoxByArray(xArr, yArr) { var minX = Math.min.apply(Math, xArr); var minY = Math.min.apply(Math, yArr); var maxX = Math.max.apply(Math, xArr); var maxY = Math.max.apply(Math, yArr); return { x: minX, y: minY, width: maxX - minX, height: maxY - minY }; } function piMod(angle) { return (angle + Math.PI * 2) % (Math.PI * 2); } var line = { /** * 计算线段的包围盒 * @param {number} x1 起始点 x * @param {number} y1 起始点 y * @param {number} x2 结束点 x * @param {number} y2 结束点 y * @return {object} 包围盒对象 */ box: function box(x1, y1, x2, y2) { return getBBoxByArray([x1, x2], [y1, y2]); }, /** * 线段的长度 * @param {number} x1 起始点 x * @param {number} y1 起始点 y * @param {number} x2 结束点 x * @param {number} y2 结束点 y * @return {number} 距离 */ length: function length(x1, y1, x2, y2) { return distance(x1, y1, x2, y2); }, /** * 根据比例获取点 * @param {number} x1 起始点 x * @param {number} y1 起始点 y * @param {number} x2 结束点 x * @param {number} y2 结束点 y * @param {number} t 指定比例 * @return {object} 包含 x, y 的点 */ pointAt: function pointAt(x1, y1, x2, y2, t) { return { x: (1 - t) * x1 + t * x2, y: (1 - t) * y1 + t * y2 }; }, /** * 点到线段的距离 * @param {number} x1 起始点 x * @param {number} y1 起始点 y * @param {number} x2 结束点 x * @param {number} y2 结束点 y * @param {number} x 测试点 x * @param {number} y 测试点 y * @return {number} 距离 */ pointDistance: function pointDistance(x1, y1, x2, y2, x, y) { // 投影距离 x1, y1 的向量,假设 p, p1, p2 三个点,投影点为 a // p1a = p1p.p1p2/|p1p2| * (p1p 的单位向量) var cross = (x2 - x1) * (x - x1) + (y2 - y1) * (y - y1); if (cross < 0) { return distance(x1, y1, x, y); } var lengthSquare = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); if (cross > lengthSquare) { return distance(x2, y2, x, y); } return this.pointToLine(x1, y1, x2, y2, x, y); }, /** * 点到直线的距离,而不是点到线段的距离 * @param {number} x1 起始点 x * @param {number} y1 起始点 y * @param {number} x2 结束点 x * @param {number} y2 结束点 y * @param {number} x 测试点 x * @param {number} y 测试点 y * @return {number} 距离 */ pointToLine: function pointToLine(x1, y1, x2, y2, x, y) { var d = [x2 - x1, y2 - y1]; // 如果端点相等,则判定点到点的距离 if (exactEquals(d, [0, 0])) { return Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1)); } var u = [-d[1], d[0]]; normalize(u, u); var a = [x - x1, y - y1]; return Math.abs(dot(a, u)); }, /** * 线段的角度 * @param {number} x1 起始点 x * @param {number} y1 起始点 y * @param {number} x2 结束点 x * @param {number} y2 结束点 y * @return {number} 导数 */ tangentAngle: function tangentAngle(x1, y1, x2, y2) { return Math.atan2(y2 - y1, x2 - x1); } }; var EPSILON = 0.0001; /** * 使用牛顿切割法求最近的点 * @param {number[]} xArr 点的 x 数组 * @param {number[]} yArr 点的 y 数组 * @param {number} x 指定的点 x * @param {number} y 指定的点 y * @param {Function} tCallback 差值函数 */ function nearestPoint(xArr, yArr, x, y, tCallback, length) { var t = -1; var d = Infinity; var v0 = [x, y]; var segNum = 20; if (length && length > 200) { segNum = length / 10; } var increaseRate = 1 / segNum; var interval = increaseRate / 10; for (var i = 0; i <= segNum; i++) { var _t = i * increaseRate; var v1 = [tCallback.apply(void 0, xArr.concat([_t])), tCallback.apply(void 0, yArr.concat([_t]))]; var d1 = distance(v0[0], v0[1], v1[0], v1[1]); if (d1 < d) { t = _t; d = d1; } } // 提前终止 if (t === 0) { return { x: xArr[0], y: yArr[0] }; } if (t === 1) { var count = xArr.length; return { x: xArr[count - 1], y: yArr[count - 1] }; } d = Infinity; for (var _i = 0; _i < 32; _i++) { if (interval < EPSILON) { break; } var prev = t - interval; var next = t + interval; var _v = [tCallback.apply(void 0, xArr.concat([prev])), tCallback.apply(void 0, yArr.concat([prev]))]; var _d = distance(v0[0], v0[1], _v[0], _v[1]); if (prev >= 0 && _d < d) { t = prev; d = _d; } else { var v2 = [tCallback.apply(void 0, xArr.concat([next])), tCallback.apply(void 0, yArr.concat([next]))]; var d2 = distance(v0[0], v0[1], v2[0], v2[1]); if (next <= 1 && d2 < d) { t = next; d = d2; } else { interval *= 0.5; } } } return { x: tCallback.apply(void 0, xArr.concat([t])), y: tCallback.apply(void 0, yArr.concat([t])) }; } // 近似求解 https://community.khronos.org/t/3d-cubic-bezier-segment-length/62363/2 function snapLength(xArr, yArr) { var totalLength = 0; var count = xArr.length; for (var i = 0; i < count; i++) { var x = xArr[i]; var y = yArr[i]; var nextX = xArr[(i + 1) % count]; var nextY = yArr[(i + 1) % count]; totalLength += distance(x, y, nextX, nextY); } return totalLength / 2; } // 差值公式 function quadraticAt(p0, p1, p2, t) { var onet = 1 - t; return onet * onet * p0 + 2 * t * onet * p1 + t * t * p2; } // 求极值 function extrema(p0, p1, p2) { var a = p0 + p2 - 2 * p1; if (isNumberEqual(a, 0)) { return [0.5]; } var rst = (p0 - p1) / a; if (rst <= 1 && rst >= 0) { return [rst]; } return []; } function derivativeAt(p0, p1, p2, t) { return 2 * (1 - t) * (p1 - p0) + 2 * t * (p2 - p1); } // 分割贝塞尔曲线 function divideQuadratic(x1, y1, x2, y2, x3, y3, t) { // 划分点 var xt = quadraticAt(x1, x2, x3, t); var yt = quadraticAt(y1, y2, y3, t); // 分割的第一条曲线的控制点 var controlPoint1 = line.pointAt(x1, y1, x2, y2, t); // 分割的第二条曲线的控制点 var controlPoint2 = line.pointAt(x2, y2, x3, y3, t); return [[x1, y1, controlPoint1.x, controlPoint1.y, xt, yt], [xt, yt, controlPoint2.x, controlPoint2.y, x3, y3]]; } // 使用迭代法取贝塞尔曲线的长度 function quadraticLength(x1, y1, x2, y2, x3, y3, iterationCount) { if (iterationCount === 0) { return (distance(x1, y1, x2, y2) + distance(x2, y2, x3, y3) + distance(x1, y1, x3, y3)) / 2; } var quadratics = divideQuadratic(x1, y1, x2, y2, x3, y3, 0.5); var left = quadratics[0]; var right = quadratics[1]; left.push(iterationCount - 1); right.push(iterationCount - 1); return quadraticLength.apply(void 0, left) + quadraticLength.apply(void 0, right); } var quadratic = { box: function box(x1, y1, x2, y2, x3, y3) { var xExtrema = extrema(x1, x2, x3)[0]; var yExtrema = extrema(y1, y2, y3)[0]; // 控制点不加入 box 的计算 var xArr = [x1, x3]; var yArr = [y1, y3]; if (xExtrema !== undefined) { xArr.push(quadraticAt(x1, x2, x3, xExtrema)); } if (yExtrema !== undefined) { yArr.push(quadraticAt(y1, y2, y3, yExtrema)); } return getBBoxByArray(xArr, yArr); }, length: function length(x1, y1, x2, y2, x3, y3) { return quadraticLength(x1, y1, x2, y2, x3, y3, 3); }, nearestPoint: function nearestPoint$1(x1, y1, x2, y2, x3, y3, x0, y0) { return nearestPoint([x1, x2, x3], [y1, y2, y3], x0, y0, quadraticAt); }, pointDistance: function pointDistance(x1, y1, x2, y2, x3, y3, x0, y0) { var point = this.nearestPoint(x1, y1, x2, y2, x3, y3, x0, y0); return distance(point.x, point.y, x0, y0); }, interpolationAt: quadraticAt, pointAt: function pointAt(x1, y1, x2, y2, x3, y3, t) { return { x: quadraticAt(x1, x2, x3, t), y: quadraticAt(y1, y2, y3, t) }; }, divide: function divide(x1, y1, x2, y2, x3, y3, t) { return divideQuadratic(x1, y1, x2, y2, x3, y3, t); }, tangentAngle: function tangentAngle(x1, y1, x2, y2, x3, y3, t) { var dx = derivativeAt(x1, x2, x3, t); var dy = derivativeAt(y1, y2, y3, t); var angle = Math.atan2(dy, dx); return piMod(angle); } }; function cubicAt(p0, p1, p2, p3, t) { var onet = 1 - t; // t * t * t 的性能大概是 Math.pow(t, 3) 的三倍 return onet * onet * onet * p0 + 3 * p1 * t * onet * onet + 3 * p2 * t * t * onet + p3 * t * t * t; } function derivativeAt$1(p0, p1, p2, p3, t) { var onet = 1 - t; return 3 * (onet * onet * (p1 - p0) + 2 * onet * t * (p2 - p1) + t * t * (p3 - p2)); } function extrema$1(p0, p1, p2, p3) { var a = -3 * p0 + 9 * p1 - 9 * p2 + 3 * p3; var b = 6 * p0 - 12 * p1 + 6 * p2; var c = 3 * p1 - 3 * p0; var extremas = []; var t1; var t2; var discSqrt; if (isNumberEqual(a, 0)) { if (!isNumberEqual(b, 0)) { t1 = -c / b; if (t1 >= 0 && t1 <= 1) { extremas.push(t1); } } } else { var disc = b * b - 4 * a * c; if (isNumberEqual(disc, 0)) { extremas.push(-b / (2 * a)); } else if (disc > 0) { discSqrt = Math.sqrt(disc); t1 = (-b + discSqrt) / (2 * a); t2 = (-b - discSqrt) / (2 * a); if (t1 >= 0 && t1 <= 1) { extremas.push(t1); } if (t2 >= 0 && t2 <= 1) { extremas.push(t2); } } } return extremas; } // 分割贝塞尔曲线 function divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, t) { // 划分点 var xt = cubicAt(x1, x2, x3, x4, t); var yt = cubicAt(y1, y2, y3, y4, t); // 计算两点之间的差值点 var c1 = line.pointAt(x1, y1, x2, y2, t); var c2 = line.pointAt(x2, y2, x3, y3, t); var c3 = line.pointAt(x3, y3, x4, y4, t); var c12 = line.pointAt(c1.x, c1.y, c2.x, c2.y, t); var c23 = line.pointAt(c2.x, c2.y, c3.x, c3.y, t); return [[x1, y1, c1.x, c1.y, c12.x, c12.y, xt, yt], [xt, yt, c23.x, c23.y, c3.x, c3.y, x4, y4]]; } // 使用迭代法取贝塞尔曲线的长度,二阶和三阶分开写,更清晰和便于调试 function cubicLength(x1, y1, x2, y2, x3, y3, x4, y4, iterationCount) { if (iterationCount === 0) { return snapLength([x1, x2, x3, x4], [y1, y2, y3, y4]); } var cubics = divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, 0.5); var left = [].concat(cubics[0], [iterationCount - 1]); var right = [].concat(cubics[1], [iterationCount - 1]); return cubicLength.apply(void 0, left) + cubicLength.apply(void 0, right); } var cubic = { extrema: extrema$1, box: function box(x1, y1, x2, y2, x3, y3, x4, y4) { var xArr = [x1, x4]; var yArr = [y1, y4]; var xExtrema = extrema$1(x1, x2, x3, x4); var yExtrema = extrema$1(y1, y2, y3, y4); for (var i = 0; i < xExtrema.length; i++) { xArr.push(cubicAt(x1, x2, x3, x4, xExtrema[i])); } for (var _i = 0; _i < yExtrema.length; _i++) { yArr.push(cubicAt(y1, y2, y3, y4, yExtrema[_i])); } return getBBoxByArray(xArr, yArr); }, length: function length(x1, y1, x2, y2, x3, y3, x4, y4) { // 迭代三次,划分成 8 段求长度 return cubicLength(x1, y1, x2, y2, x3, y3, x4, y4, 3); }, nearestPoint: function nearestPoint$1(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length) { return nearestPoint([x1, x2, x3, x4], [y1, y2, y3, y4], x0, y0, cubicAt, length); }, pointDistance: function pointDistance(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length) { var point = this.nearestPoint(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length); return distance(point.x, point.y, x0, y0); }, interpolationAt: cubicAt, pointAt: function pointAt(x1, y1, x2, y2, x3, y3, x4, y4, t) { return { x: cubicAt(x1, x2, x3, x4, t), y: cubicAt(y1, y2, y3, y4, t) }; }, divide: function divide(x1, y1, x2, y2, x3, y3, x4, y4, t) { return divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, t); }, tangentAngle: function tangentAngle(x1, y1, x2, y2, x3, y3, x4, y4, t) { var dx = derivativeAt$1(x1, x2, x3, x4, t); var dy = derivativeAt$1(y1, y2, y3, y4, t); return piMod(Math.atan2(dy, dx)); } }; function distance$1(x1, y1, x2, y2) { var dx = x1 - x2; var dy = y1 - y2; return Math.sqrt(dx * dx + dy * dy); } function inBox(minX, minY, width, height, x, y) { return x >= minX && x <= minX + width && y >= minY && y <= minY + height; } function inRect(minX, minY, width, height, lineWidth, x, y) { var halfWidth = lineWidth / 2; // 将四个边看做矩形来检测,比边的检测算法要快 return inBox(minX - halfWidth, minY - halfWidth, width, lineWidth, x, y) || // 上边 inBox(minX + width - halfWidth, minY - halfWidth, lineWidth, height, x, y) || // 右边 inBox(minX + halfWidth, minY + height - halfWidth, width, lineWidth, x, y) || // 下边 inBox(minX - halfWidth, minY + halfWidth, lineWidth, height, x, y); // 左边 } function inArc(cx, cy, r, startAngle, endAngle, lineWidth, x, y) { var angle = (Math.atan2(y - cy, x - cx) + Math.PI * 2) % (Math.PI * 2); // 转换到 0 - 2 * Math.PI 之间 // if (angle < startAngle || angle > endAngle) { // return false; // } var point = { x: cx + r * Math.cos(angle), y: cy + r * Math.sin(angle) }; return distance$1(point.x, point.y, x, y) <= lineWidth / 2; } function inLine(x1, y1, x2, y2, lineWidth, x, y) { var minX = Math.min(x1, x2); var maxX = Math.max(x1, x2); var minY = Math.min(y1, y2); var maxY = Math.max(y1, y2); var halfWidth = lineWidth / 2; // 因为目前的方案是计算点到直线的距离,而有可能会在延长线上,所以要先判断是否在包围盒内 // 这种方案会在水平或者竖直的情况下载线的延长线上有半 lineWidth 的误差 if (!(x >= minX - halfWidth && x <= maxX + halfWidth && y >= minY - halfWidth && y <= maxY + halfWidth)) { return false; } // 因为已经计算了包围盒,所以仅需要计算到直线的距离即可,可以显著提升性能 return line.pointToLine(x1, y1, x2, y2, x, y) <= lineWidth / 2; } function inPolyline(points, lineWidth, x, y, isClose) { var count = points.length; if (count < 2) { return false; } for (var i = 0; i < count - 1; i++) { var x1 = points[i][0]; var y1 = points[i][1]; var x2 = points[i + 1][0]; var y2 = points[i + 1][1]; if (inLine(x1, y1, x2, y2, lineWidth, x, y)) { return true; } } // 如果封闭,则计算起始点和结束点的边 if (isClose) { var first = points[0]; var last = points[count - 1]; if (inLine(first[0], first[1], last[0], last[1], lineWidth, x, y)) { return true; } } return false; } // 多边形的射线检测,参考:https://blog.csdn.net/WilliamSun0122/article/details/77994526 var tolerance = 1e-6; // 三态函数,判断两个double在eps精度下的大小关系 function dcmp(x) { if (Math.abs(x) < tolerance) { return 0; } return x < 0 ? -1 : 1; } // 判断点Q是否在p1和p2的线段上 function onSegment(p1, p2, q) { if ((q[0] - p1[0]) * (p2[1] - p1[1]) === (p2[0] - p1[0]) * (q[1] - p1[1]) && Math.min(p1[0], p2[0]) <= q[0] && q[0] <= Math.max(p1[0], p2[0]) && Math.min(p1[1], p2[1]) <= q[1] && q[1] <= Math.max(p1[1], p2[1])) { return true; } return false; } // 判断点P在多边形内-射线法 function inPolygon(points, x, y) { var isHit = false; var n = points.length; if (n <= 2) { // svg 中点小于 3 个时,不显示,也无法被拾取 return false; } for (var i = 0; i < n; i++) { var p1 = points[i]; var p2 = points[(i + 1) % n]; if (onSegment(p1, p2, [x, y])) { // 点在多边形一条边上 return true; } // 前一个判断min(p1[1],p2[1]) 0 !== dcmp(p2[1] - y) > 0 && dcmp(x - (y - p1[1]) * (p1[0] - p2[0]) / (p1[1] - p2[1]) - p1[0]) < 0) { isHit = !isHit; } } return isHit; } function inPolygons(polygons, x, y) { var isHit = false; for (var i = 0; i < polygons.length; i++) { var points = polygons[i]; isHit = inPolygon(points, x, y); if (isHit) { break; } } return isHit; } function isPointInPath(displayObject, position, isClipPath) { var _displayObject$parsed = displayObject.parsedStyle, r = _displayObject$parsed.r, fill = _displayObject$parsed.fill, stroke = _displayObject$parsed.stroke, lineWidth = _displayObject$parsed.lineWidth, increasedLineWidthForHitTesting = _displayObject$parsed.increasedLineWidthForHitTesting, pointerEvents = _displayObject$parsed.pointerEvents; var halfLineWidth = ((lineWidth || 0) + (increasedLineWidthForHitTesting || 0)) / 2; var absDistance = distance$1(r, r, position.x, position.y); var _isFillOrStrokeAffect = gLite.isFillOrStrokeAffected(pointerEvents, fill, stroke), hasFill = _isFillOrStrokeAffect[0], hasStroke = _isFillOrStrokeAffect[1]; if (hasFill && hasStroke || isClipPath) { return absDistance <= r + halfLineWidth; } if (hasFill) { return absDistance <= r; } if (hasStroke) { return absDistance >= r - halfLineWidth && absDistance <= r + halfLineWidth; } return false; } function ellipseDistance(squareX, squareY, rx, ry) { return squareX / (rx * rx) + squareY / (ry * ry); } function isPointInPath$1(displayObject, position, isClipPath) { var _displayObject$parsed = displayObject.parsedStyle, rx = _displayObject$parsed.rx, ry = _displayObject$parsed.ry, fill = _displayObject$parsed.fill, stroke = _displayObject$parsed.stroke, lineWidth = _displayObject$parsed.lineWidth, increasedLineWidthForHitTesting = _displayObject$parsed.increasedLineWidthForHitTesting, pointerEvents = _displayObject$parsed.pointerEvents; var x = position.x, y = position.y; var _isFillOrStrokeAffect = gLite.isFillOrStrokeAffected(pointerEvents, fill, stroke), hasFill = _isFillOrStrokeAffect[0], hasStroke = _isFillOrStrokeAffect[1]; var halfLineWith = ((lineWidth || 0) + (increasedLineWidthForHitTesting || 0)) / 2; var squareX = (x - rx) * (x - rx); var squareY = (y - ry) * (y - ry); // 使用椭圆的公式: x*x/rx*rx + y*y/ry*ry = 1; if (hasFill && hasStroke || isClipPath) { return ellipseDistance(squareX, squareY, rx + halfLineWith, ry + halfLineWith) <= 1; } if (hasFill) { return ellipseDistance(squareX, squareY, rx, ry) <= 1; } if (hasStroke) { return ellipseDistance(squareX, squareY, rx - halfLineWith, ry - halfLineWith) >= 1 && ellipseDistance(squareX, squareY, rx + halfLineWith, ry + halfLineWith) <= 1; } return false; } function isPointInPath$2(displayObject, position, isClipPath) { var _displayObject$parsed = displayObject.parsedStyle, x1 = _displayObject$parsed.x1, y1 = _displayObject$parsed.y1, x2 = _displayObject$parsed.x2, y2 = _displayObject$parsed.y2, lineWidth = _displayObject$parsed.lineWidth, increasedLineWidthForHitTesting = _displayObject$parsed.increasedLineWidthForHitTesting, _displayObject$parsed2 = _displayObject$parsed.defX, x = _displayObject$parsed2 === void 0 ? 0 : _displayObject$parsed2, _displayObject$parsed3 = _displayObject$parsed.defY, y = _displayObject$parsed3 === void 0 ? 0 : _displayObject$parsed3, pointerEvents = _displayObject$parsed.pointerEvents, fill = _displayObject$parsed.fill, stroke = _displayObject$parsed.stroke; var _isFillOrStrokeAffect = gLite.isFillOrStrokeAffected(pointerEvents, fill, stroke), hasStroke = _isFillOrStrokeAffect[1]; if (!hasStroke && !isClipPath || !lineWidth) { return false; } return inLine(x1, y1, x2, y2, (lineWidth || 0) + (increasedLineWidthForHitTesting || 0), position.x + x, position.y + y); } // TODO: replace it with method in @antv/util function isPointInStroke(segments, lineWidth, px, py, length) { var isHit = false; var halfWidth = lineWidth / 2; for (var i = 0; i < segments.length; i++) { var segment = segments[i]; var currentPoint = segment.currentPoint, params = segment.params, prePoint = segment.prePoint, box = segment.box; // 如果在前面已经生成过包围盒,直接按照包围盒计算 if (box && !inBox(box.x - halfWidth, box.y - halfWidth, box.width + lineWidth, box.height + lineWidth, px, py)) { continue; } switch (segment.command) { // L 和 Z 都是直线, M 不进行拾取 case 'L': case 'Z': isHit = inLine(prePoint[0], prePoint[1], currentPoint[0], currentPoint[1], lineWidth, px, py); if (isHit) { return true; } break; case 'Q': var qDistance = quadratic.pointDistance(prePoint[0], prePoint[1], params[1], params[2], params[3], params[4], px, py); isHit = qDistance <= lineWidth / 2; if (isHit) { return true; } break; case 'C': var cDistance = cubic.pointDistance(prePoint[0], // 上一段结束位置, 即 C 的起始点 prePoint[1], params[1], // 'C' 的参数,1、2 为第一个控制点,3、4 为第二个控制点,5、6 为结束点 params[2], params[3], params[4], params[5], params[6], px, py, length); isHit = cDistance <= lineWidth / 2; if (isHit) { return true; } break; case 'A': // cache conversion result if (!segment.cubicParams) { segment.cubicParams = arcToCubic(prePoint[0], prePoint[1], params[1], params[2], params[3], params[4], params[5], params[6], params[7], undefined); } var args = segment.cubicParams; // fixArc var prePointInCubic = prePoint; for (var _i = 0; _i < args.length; _i += 6) { var _cDistance = cubic.pointDistance(prePointInCubic[0], // 上一段结束位置, 即 C 的起始点 prePointInCubic[1], args[_i], args[_i + 1], args[_i + 2], args[_i + 3], args[_i + 4], args[_i + 5], px, py, length); prePointInCubic = [args[_i + 4], args[_i + 5]]; isHit = _cDistance <= lineWidth / 2; if (isHit) { return true; } } break; } } return isHit; } function isPointInPath$3(displayObject, position, isClipPath, isPointInPath, renderingPluginContext, runtime) { var _displayObject$parsed = displayObject.parsedStyle, lineWidth = _displayObject$parsed.lineWidth, increasedLineWidthForHitTesting = _displayObject$parsed.increasedLineWidthForHitTesting, stroke = _displayObject$parsed.stroke, fill = _displayObject$parsed.fill, _displayObject$parsed2 = _displayObject$parsed.defX, x = _displayObject$parsed2 === void 0 ? 0 : _displayObject$parsed2, _displayObject$parsed3 = _displayObject$parsed.defY, y = _displayObject$parsed3 === void 0 ? 0 : _displayObject$parsed3, path = _displayObject$parsed.path, pointerEvents = _displayObject$parsed.pointerEvents; var segments = path.segments, hasArc = path.hasArc, polylines = path.polylines, polygons = path.polygons; var _isFillOrStrokeAffect = gLite.isFillOrStrokeAffected(pointerEvents, // Only a closed path can be filled. (polygons === null || polygons === void 0 ? void 0 : polygons.length) && fill, stroke), hasFill = _isFillOrStrokeAffect[0], hasStroke = _isFillOrStrokeAffect[1]; var totalLength = gLite.getOrCalculatePathTotalLength(displayObject); var isHit = false; if (hasFill || isClipPath) { if (hasArc) { // 存在曲线时,暂时使用 canvas 的 api 计算,后续可以进行多边形切割 isHit = isPointInPath(displayObject, position); } else { // 提取出来的多边形包含闭合的和非闭合的,在这里统一按照多边形处理 isHit = inPolygons(polygons, position.x + x, position.y + y) || inPolygons(polylines, position.x + x, position.y + y); } return isHit; } else if (hasStroke || isClipPath) { isHit = isPointInStroke(segments, (lineWidth || 0) + (increasedLineWidthForHitTesting || 0), position.x + x, position.y + y, totalLength); } return isHit; } function isPointInPath$4(displayObject, position, isClipPath) { var _displayObject$parsed = displayObject.parsedStyle, stroke = _displayObject$parsed.stroke, fill = _displayObject$parsed.fill, lineWidth = _displayObject$parsed.lineWidth, increasedLineWidthForHitTesting = _displayObject$parsed.increasedLineWidthForHitTesting, points = _displayObject$parsed.points, _displayObject$parsed2 = _displayObject$parsed.defX, x = _displayObject$parsed2 === void 0 ? 0 : _displayObject$parsed2, _displayObject$parsed3 = _displayObject$parsed.defY, y = _displayObject$parsed3 === void 0 ? 0 : _displayObject$parsed3, pointerEvents = _displayObject$parsed.pointerEvents; var _isFillOrStrokeAffect = gLite.isFillOrStrokeAffected(pointerEvents, fill, stroke), hasFill = _isFillOrStrokeAffect[0], hasStroke = _isFillOrStrokeAffect[1]; var isHit = false; if (hasStroke || isClipPath) { isHit = inPolyline(points.points, (lineWidth || 0) + (increasedLineWidthForHitTesting || 0), position.x + x, position.y + y, true); } if (!isHit && (hasFill || isClipPath)) { isHit = inPolygon(points.points, position.x + x, position.y + y); } return isHit; } function isPointInPath$5(displayObject, position, isClipPath) { var _displayObject$parsed = displayObject.parsedStyle, lineWidth = _displayObject$parsed.lineWidth, increasedLineWidthForHitTesting = _displayObject$parsed.increasedLineWidthForHitTesting, points = _displayObject$parsed.points, _displayObject$parsed2 = _displayObject$parsed.defX, x = _displayObject$parsed2 === void 0 ? 0 : _displayObject$parsed2, _displayObject$parsed3 = _displayObject$parsed.defY, y = _displayObject$parsed3 === void 0 ? 0 : _displayObject$parsed3, pointerEvents = _displayObject$parsed.pointerEvents, fill = _displayObject$parsed.fill, stroke = _displayObject$parsed.stroke; var _isFillOrStrokeAffect = gLite.isFillOrStrokeAffected(pointerEvents, fill, stroke), hasStroke = _isFillOrStrokeAffect[1]; if (!hasStroke && !isClipPath || !lineWidth) { return false; } return inPolyline(points.points, (lineWidth || 0) + (increasedLineWidthForHitTesting || 0), position.x + x, position.y + y, false); } function isPointInPath$6(displayObject, position, isClipPath, isPointInPath, runtime) { var _displayObject$parsed = displayObject.parsedStyle, radius = _displayObject$parsed.radius, fill = _displayObject$parsed.fill, stroke = _displayObject$parsed.stroke, lineWidth = _displayObject$parsed.lineWidth, increasedLineWidthForHitTesting = _displayObject$parsed.increasedLineWidthForHitTesting, width = _displayObject$parsed.width, height = _displayObject$parsed.height, pointerEvents = _displayObject$parsed.pointerEvents; var _isFillOrStrokeAffect = gLite.isFillOrStrokeAffected(pointerEvents, fill, stroke), hasFill = _isFillOrStrokeAffect[0], hasStroke = _isFillOrStrokeAffect[1]; var hasRadius = radius && radius.some(function (r) { return r !== 0; }); var lineWidthForHitTesting = (lineWidth || 0) + (increasedLineWidthForHitTesting || 0); // 无圆角时的策略 if (!hasRadius) { var halfWidth = lineWidthForHitTesting / 2; // 同时填充和带有边框 if (hasFill && hasStroke || isClipPath) { return inBox(0 - halfWidth, 0 - halfWidth, width + halfWidth, height + halfWidth, position.x, position.y); } // 仅填充 if (hasFill) { return inBox(0, 0, width, height, position.x, position.y); } if (hasStroke) { return inRect(0, 0, width, height, lineWidthForHitTesting, position.x, position.y); } } else { var isHit = false; if (hasStroke || isClipPath) { isHit = inRectWithRadius(0, 0, width, height, radius.map(function (r) { return clamp(r, 0, Math.min(Math.abs(width) / 2, Math.abs(height) / 2)); }), lineWidthForHitTesting, position.x, position.y); } // 仅填充时带有圆角的矩形直接通过图形拾取 // 以后可以改成纯数学的近似拾取,将圆弧切割成多边形 if (!isHit && (hasFill || isClipPath)) { isHit = isPointInPath(displayObject, position); } return isHit; } return false; } function inRectWithRadius(minX, minY, width, height, radiusArray, lineWidth, x, y) { var tlr = radiusArray[0], trr = radiusArray[1], brr = radiusArray[2], blr = radiusArray[3]; return inLine(minX + tlr, minY, minX + width - trr, minY, lineWidth, x, y) || inLine(minX + width, minY + trr, minX + width, minY + height - brr, lineWidth, x, y) || inLine(minX + width - brr, minY + height, minX + blr, minY + height, lineWidth, x, y) || inLine(minX, minY + height - blr, minX, minY + tlr, lineWidth, x, y) || inArc(minX + width - trr, minY + trr, trr, 1.5 * Math.PI, 2 * Math.PI, lineWidth, x, y) || inArc(minX + width - brr, minY + height - brr, brr, 0, 0.5 * Math.PI, lineWidth, x, y) || inArc(minX + blr, minY + height - blr, blr, 0.5 * Math.PI, Math.PI, lineWidth, x, y) || inArc(minX + tlr, minY + tlr, tlr, Math.PI, 1.5 * Math.PI, lineWidth, x, y); } function isPointInPath$7(displayObject, position, isClipPath, isPointInPath, renderingPluginContext, runtime) { var _displayObject$parsed = displayObject.parsedStyle, pointerEvents = _displayObject$parsed.pointerEvents, width = _displayObject$parsed.width, height = _displayObject$parsed.height; if (pointerEvents === 'non-transparent-pixel') { var offscreenCanvas = renderingPluginContext.config.offscreenCanvas; var canvas = runtime.offscreenCanvas.getOrCreateCanvas(offscreenCanvas); var context = runtime.offscreenCanvas.getOrCreateContext(offscreenCanvas, { willReadFrequently: true }); canvas.width = width; canvas.height = height; renderingPluginContext.defaultStyleRendererFactory[gLite.Shape.IMAGE].render(context, displayObject.parsedStyle, displayObject, undefined, undefined, undefined); var imagedata = context.getImageData(position.x, position.y, 1, 1).data; return imagedata.every(function (component) { return component !== 0; }); } return true; } var Plugin$1 = /*#__PURE__*/function (_AbstractRendererPlug) { _inheritsLoose$2(Plugin, _AbstractRendererPlug); function Plugin() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _AbstractRendererPlug.call.apply(_AbstractRendererPlug, [this].concat(args)) || this; _this.name = 'canvas-picker'; return _this; } var _proto = Plugin.prototype; _proto.init = function init() { var _pointInPathPickerFac; var trueFunc = function trueFunc() { return true; }; var pointInPathPickerFactory = (_pointInPathPickerFac = {}, _pointInPathPickerFac[gLite.Shape.CIRCLE] = isPointInPath, _pointInPathPickerFac[gLite.Shape.ELLIPSE] = isPointInPath$1, _pointInPathPickerFac[gLite.Shape.RECT] = isPointInPath$6, _pointInPathPickerFac[gLite.Shape.LINE] = isPointInPath$2, _pointInPathPickerFac[gLite.Shape.POLYLINE] = isPointInPath$5, _pointInPathPickerFac[gLite.Shape.POLYGON] = isPointInPath$4, _pointInPathPickerFac[gLite.Shape.PATH] = isPointInPath$3, _pointInPathPickerFac[gLite.Shape.TEXT] = trueFunc, _pointInPathPickerFac[gLite.Shape.GROUP] = null, _pointInPathPickerFac[gLite.Shape.IMAGE] = isPointInPath$7, _pointInPathPickerFac[gLite.Shape.HTML] = null, _pointInPathPickerFac[gLite.Shape.MESH] = null, _pointInPathPickerFac); // @ts-ignore this.context.pointInPathPickerFactory = pointInPathPickerFactory; this.addRenderingPlugin(new CanvasPickerPlugin()); }; _proto.destroy = function destroy() { // @ts-ignore delete this.context.pointInPathPickerFactory; this.removeAllRenderingPlugins(); }; return Plugin; }(gLite.AbstractRendererPlugin); var index_esm$1 = /*#__PURE__*/Object.freeze({ __proto__: null, Plugin: Plugin$1 }); function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _inheritsLoose$3(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf$3(subClass, superClass); } function _setPrototypeOf$3(o, p) { _setPrototypeOf$3 = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf$3(o, p); } /** * support 2 modes in rendering: * * immediate * * delayed: render at the end of frame with dirty-rectangle */ var CanvasRendererPlugin = /*#__PURE__*/function () { function CanvasRendererPlugin(canvasRendererPluginOptions) { this.canvasRendererPluginOptions = void 0; this.context = void 0; this.pathGeneratorFactory = void 0; /** * RBush used in dirty rectangle rendering */ this.rBush = void 0; this.removedRBushNodeAABBs = []; this.renderQueue = []; /** * This stack is only used by clipPath for now. */ this.restoreStack = []; this.clearFullScreen = false; /** * view projection matrix */ this.vpMatrix = create(); this.dprMatrix = create(); this.tmpMat4 = create(); this.vec3a = create$1(); this.vec3b = create$1(); this.vec3c = create$1(); this.vec3d = create$1(); this.canvasRendererPluginOptions = canvasRendererPluginOptions; } var _proto = CanvasRendererPlugin.prototype; _proto.apply = function apply(context, runtime) { var _this = this; this.context = context; var config = context.config, camera = context.camera, renderingService = context.renderingService, renderingContext = context.renderingContext, rBushRoot = context.rBushRoot, pathGeneratorFactory = context.pathGeneratorFactory; this.rBush = rBushRoot; this.pathGeneratorFactory = pathGeneratorFactory; var contextService = context.contextService; var canvas = renderingContext.root.ownerDocument.defaultView; var handleUnmounted = function handleUnmounted(e) { var object = e.target; // remove r-bush node // @ts-ignore var rBushNode = object.rBushNode; if (rBushNode.aabb) { // save removed aabbs for dirty-rectangle rendering later _this.removedRBushNodeAABBs.push(rBushNode.aabb); } }; var handleCulled = function handleCulled(e) { var object = e.target; // @ts-ignore var rBushNode = object.rBushNode; if (rBushNode.aabb) { // save removed aabbs for dirty-rectangle rendering later _this.removedRBushNodeAABBs.push(rBushNode.aabb); } }; renderingService.hooks.init.tap(CanvasRendererPlugin.tag, function () { canvas.addEventListener(gLite.ElementEvent.UNMOUNTED, handleUnmounted); canvas.addEventListener(gLite.ElementEvent.CULLED, handleCulled); // clear fullscreen var dpr = contextService.getDPR(); var width = config.width, height = config.height; var context = contextService.getContext(); _this.clearRect(context, 0, 0, width * dpr, height * dpr, config.background); }); renderingService.hooks.destroy.tap(CanvasRendererPlugin.tag, function () { canvas.removeEventListener(gLite.ElementEvent.UNMOUNTED, handleUnmounted); canvas.removeEventListener(gLite.ElementEvent.CULLED, handleCulled); // this.renderQueue = []; // this.removedRBushNodeAABBs = []; // this.restoreStack = []; }); renderingService.hooks.beginFrame.tap(CanvasRendererPlugin.tag, function () { var context = contextService.getContext(); var dpr = contextService.getDPR(); var width = config.width, height = config.height; var _this$canvasRendererP = _this.canvasRendererPluginOptions, dirtyObjectNumThreshold = _this$canvasRendererP.dirtyObjectNumThreshold, dirtyObjectRatioThreshold = _this$canvasRendererP.dirtyObjectRatioThreshold; // some heuristic conditions such as 80% object changed var _renderingService$get = renderingService.getStats(), total = _renderingService$get.total, rendered = _renderingService$get.rendered; var ratio = rendered / total; _this.clearFullScreen = renderingService.disableDirtyRectangleRendering() || rendered > dirtyObjectNumThreshold && ratio > dirtyObjectRatioThreshold; if (context) { context.resetTransform ? context.resetTransform() : context.setTransform(1, 0, 0, 1, 0, 0); if (_this.clearFullScreen) { _this.clearRect(context, 0, 0, width * dpr, height * dpr, config.background); } } }); var renderByZIndex = function renderByZIndex(object, context) { if (object.isVisible() && !object.isCulled()) { _this.renderDisplayObject(object, context, _this.context, _this.restoreStack, runtime); // if (object.renderable.) { // if we did a full screen rendering last frame _this.saveDirtyAABB(object); // } } var sorted = object.sortable.sorted || object.childNodes; // should account for z-index sorted.forEach(function (child) { renderByZIndex(child, context); }); }; // render at the end of frame renderingService.hooks.endFrame.tap(CanvasRendererPlugin.tag, function () { var context = contextService.getContext(); // clear & clip dirty rectangle var dpr = contextService.getDPR(); fromScaling(_this.dprMatrix, [dpr, dpr, 1]); multiply(_this.vpMatrix, _this.dprMatrix, camera.getOrthoMatrix()); // if (this.clearFullScreen) { if (_this.clearFullScreen) { // console.log('canvas renderer fcp...'); renderByZIndex(renderingContext.root, context); } else { // console.log('canvas renderer next...'); // merge removed AABB var dirtyRenderBounds = _this.safeMergeAABB.apply(_this, [_this.mergeDirtyAABBs(_this.renderQueue)].concat(_this.removedRBushNodeAABBs.map(function (_ref) { var minX = _ref.minX, minY = _ref.minY, maxX = _ref.maxX, maxY = _ref.maxY; var aabb = new gLite.AABB(); aabb.setMinMax( // vec3.fromValues(minX, minY, 0), // vec3.fromValues(maxX, maxY, 0), [minX, minY, 0], [maxX, maxY, 0]); return aabb; }))); _this.removedRBushNodeAABBs = []; if (gLite.AABB.isEmpty(dirtyRenderBounds)) { _this.renderQueue = []; return; } var dirtyRect = _this.convertAABB2Rect(dirtyRenderBounds); var x = dirtyRect.x, y = dirtyRect.y, width = dirtyRect.width, height = dirtyRect.height; var tl = transformMat4(_this.vec3a, [x, y, 0], _this.vpMatrix); var tr = transformMat4(_this.vec3b, [x + width, y, 0], _this.vpMatrix); var bl = transformMat4(_this.vec3c, [x, y + height, 0], _this.vpMatrix); var br = transformMat4(_this.vec3d, [x + width, y + height, 0], _this.vpMatrix); var minx = Math.min(tl[0], tr[0], br[0], bl[0]); var miny = Math.min(tl[1], tr[1], br[1], bl[1]); var maxx = Math.max(tl[0], tr[0], br[0], bl[0]); var maxy = Math.max(tl[1], tr[1], br[1], bl[1]); var ix = Math.floor(minx); var iy = Math.floor(miny); var iwidth = Math.ceil(maxx - minx); var iheight = Math.ceil(maxy - miny); context.save(); _this.clearRect(context, ix, iy, iwidth, iheight, config.background); context.beginPath(); context.rect(ix, iy, iwidth, iheight); context.clip(); // @see https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Transformations context.setTransform(_this.vpMatrix[0], _this.vpMatrix[1], _this.vpMatrix[4], _this.vpMatrix[5], _this.vpMatrix[12], _this.vpMatrix[13]); // draw dirty rectangle var _config$renderer$getC = config.renderer.getConfig(), enableDirtyRectangleRenderingDebug = _config$renderer$getC.enableDirtyRectangleRenderingDebug; if (enableDirtyRectangleRenderingDebug) { canvas.dispatchEvent(new gLite.CustomEvent(gLite.CanvasEvent.DIRTY_RECTANGLE, { dirtyRect: { x: ix, y: iy, width: iwidth, height: iheight } })); } // search objects intersect with dirty rectangle var dirtyObjects = _this.searchDirtyObjects(dirtyRenderBounds); // do rendering dirtyObjects // sort by z-index .sort(function (a, b) { return a.sortable.renderOrder - b.sortable.renderOrder; }).forEach(function (object) { // culled object should not be rendered if (object && object.isVisible() && !object.isCulled()) { _this.renderDisplayObject(object, context, _this.context, _this.restoreStack, runtime); } }); context.restore(); // save dirty AABBs in last frame _this.renderQueue.forEach(function (object) { _this.saveDirtyAABB(object); }); // clear queue _this.renderQueue = []; } // pop restore stack, eg. root -> parent -> child _this.restoreStack.forEach(function () { context.restore(); }); // clear restore stack _this.restoreStack = []; }); renderingService.hooks.render.tap(CanvasRendererPlugin.tag, function (object) { if (!_this.clearFullScreen) { // render at the end of frame _this.renderQueue.push(object); } }); }; _proto.clearRect = function clearRect(context, x, y, width, height, background) { // clearRect is faster than fillRect @see https://stackoverflow.com/a/30830253 context.clearRect(x, y, width, height); if (background) { context.fillStyle = background; context.fillRect(x, y, width, height); } }; _proto.renderDisplayObject = function renderDisplayObject(object, context, canvasContext, restoreStack, runtime) { var nodeName = object.nodeName; // console.log('canvas render:', object); // restore to its ancestor var parent = restoreStack[restoreStack.length - 1]; if (parent && !(object.compareDocumentPosition(parent) & Node.DOCUMENT_POSITION_CONTAINS)) { context.restore(); restoreStack.pop(); } // @ts-ignore var styleRenderer = this.context.styleRendererFactory[nodeName]; var generatePath = this.pathGeneratorFactory[nodeName]; // clip path var clipPath = object.parsedStyle.clipPath; if (clipPath) { this.applyWorldTransform(context, clipPath); // generate path in local space var _generatePath = this.pathGeneratorFactory[clipPath.nodeName]; if (_generatePath) { context.save(); // save clip restoreStack.push(object); context.beginPath(); _generatePath(context, clipPath.parsedStyle); context.closePath(); context.clip(); } } // fill & stroke if (styleRenderer) { this.applyWorldTransform(context, object); context.save(); // apply attributes to context this.applyAttributesToContext(context, object); } if (generatePath) { context.beginPath(); generatePath(context, object.parsedStyle); if (object.nodeName !== gLite.Shape.LINE && object.nodeName !== gLite.Shape.PATH && object.nodeName !== gLite.Shape.POLYLINE) { context.closePath(); } } // fill & stroke if (styleRenderer) { styleRenderer.render(context, object.parsedStyle, object, canvasContext, this, runtime); // restore applied attributes, eg. shadowBlur shadowColor... context.restore(); } // finish rendering, clear dirty flag object.renderable.dirty = false; }; _proto.convertAABB2Rect = function convertAABB2Rect(aabb) { var min = aabb.getMin(); var max = aabb.getMax(); // expand the rectangle a bit to avoid artifacts // @see https://www.yuque.com/antv/ou292n/bi8nix#ExvCu var minX = Math.floor(min[0]); var minY = Math.floor(min[1]); var maxX = Math.ceil(max[0]); var maxY = Math.ceil(max[1]); var width = maxX - minX; var height = maxY - minY; return { x: minX, y: minY, width: width, height: height }; } /** * TODO: merge dirty rectangles with some strategies. * For now, we just simply merge all the rectangles into one. * @see https://idom.me/articles/841.html */; _proto.mergeDirtyAABBs = function mergeDirtyAABBs(dirtyObjects) { // merge into a big AABB // TODO: skip descendant if ancestor is caculated, but compareNodePosition is really slow var aabb = new gLite.AABB(); dirtyObjects.forEach(function (object) { var renderBounds = object.getRenderBounds(); aabb.add(renderBounds); var dirtyRenderBounds = object.renderable.dirtyRenderBounds; if (dirtyRenderBounds) { aabb.add(dirtyRenderBounds); } }); return aabb; }; _proto.searchDirtyObjects = function searchDirtyObjects(dirtyRectangle) { // search in r-tree, get all affected nodes var _dirtyRectangle$getMi = dirtyRectangle.getMin(), minX = _dirtyRectangle$getMi[0], minY = _dirtyRectangle$getMi[1]; var _dirtyRectangle$getMa = dirtyRectangle.getMax(), maxX = _dirtyRectangle$getMa[0], maxY = _dirtyRectangle$getMa[1]; var rBushNodes = this.rBush.search({ minX: minX, minY: minY, maxX: maxX, maxY: maxY }); return rBushNodes.map(function (_ref2) { var displayObject = _ref2.displayObject; return displayObject; }); }; _proto.saveDirtyAABB = function saveDirtyAABB(object) { var renderable = object.renderable; if (!renderable.dirtyRenderBounds) { renderable.dirtyRenderBounds = new gLite.AABB(); } var renderBounds = object.getRenderBounds(); if (renderBounds) { // save last dirty aabb renderable.dirtyRenderBounds.update(renderBounds.center, renderBounds.halfExtents); } } /** * TODO: batch the same global attributes */; _proto.applyAttributesToContext = function applyAttributesToContext(context, object) { var _object$parsedStyle = object.parsedStyle, stroke = _object$parsedStyle.stroke, fill = _object$parsedStyle.fill, opacity = _object$parsedStyle.opacity, lineDash = _object$parsedStyle.lineDash, lineDashOffset = _object$parsedStyle.lineDashOffset; // @see https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/setLineDash if (lineDash) { context.setLineDash(lineDash); } // @see https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/lineDashOffset if (!isNil(lineDashOffset)) { context.lineDashOffset = lineDashOffset; } if (!isNil(opacity)) { context.globalAlpha *= opacity; } if (!isNil(stroke) && !Array.isArray(stroke) && !stroke.isNone) { context.strokeStyle = object.attributes.stroke; } if (!isNil(fill) && !Array.isArray(fill) && !fill.isNone) { context.fillStyle = object.attributes.fill; } }; _proto.applyWorldTransform = function applyWorldTransform(context, object, matrix) { var tx = 0; var ty = 0; var _ref3 = object.parsedStyle || {}, anchor = _ref3.anchor; var anchorX = anchor && anchor[0] || 0; var anchorY = anchor && anchor[1] || 0; if (anchorX !== 0 || anchorY !== 0) { // const bounds = object.getGeometryBounds(); var bounds = object.geometry.contentBounds; var width = bounds && bounds.halfExtents[0] * 2 || 0; var height = bounds && bounds.halfExtents[1] * 2 || 0; tx = -(anchorX * width); ty = -(anchorY * height); } // apply clip shape's RTS if (matrix) { copy(this.tmpMat4, object.getLocalTransform()); this.vec3a[0] = tx; this.vec3a[1] = ty; this.vec3a[2] = 0; translate(this.tmpMat4, this.tmpMat4, this.vec3a); multiply(this.tmpMat4, matrix, this.tmpMat4); multiply(this.tmpMat4, this.vpMatrix, this.tmpMat4); } else { // apply RTS transformation in world space copy(this.tmpMat4, object.getWorldTransform()); this.vec3a[0] = tx; this.vec3a[1] = ty; this.vec3a[2] = 0; translate(this.tmpMat4, this.tmpMat4, this.vec3a); multiply(this.tmpMat4, this.vpMatrix, this.tmpMat4); } // @see https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Transformations context.setTransform(this.tmpMat4[0], this.tmpMat4[1], this.tmpMat4[4], this.tmpMat4[5], this.tmpMat4[12], this.tmpMat4[13]); }; _proto.safeMergeAABB = function safeMergeAABB() { var merged = new gLite.AABB(); for (var _len = arguments.length, aabbs = new Array(_len), _key = 0; _key < _len; _key++) { aabbs[_key] = arguments[_key]; } aabbs.forEach(function (aabb) { merged.add(aabb); }); return merged; }; return CanvasRendererPlugin; }(); CanvasRendererPlugin.tag = 'CanvasRenderer'; var DefaultRenderer = /*#__PURE__*/function () { function DefaultRenderer(imagePool) { this.imagePool = void 0; this.imagePool = imagePool; } var _proto = DefaultRenderer.prototype; _proto.render = function render(context, parsedStyle, object, canvasContext, plugin, runtime) { var fill = parsedStyle.fill, fillRule = parsedStyle.fillRule, opacity = parsedStyle.opacity, fillOpacity = parsedStyle.fillOpacity, stroke = parsedStyle.stroke, strokeOpacity = parsedStyle.strokeOpacity, lineWidth = parsedStyle.lineWidth, lineCap = parsedStyle.lineCap, lineJoin = parsedStyle.lineJoin, shadowType = parsedStyle.shadowType, shadowColor = parsedStyle.shadowColor, shadowBlur = parsedStyle.shadowBlur, filter = parsedStyle.filter, miterLimit = parsedStyle.miterLimit; var hasFill = !isNil(fill) && !fill.isNone; var hasStroke = !isNil(stroke) && !stroke.isNone && lineWidth > 0; var isFillTransparent = fill.alpha === 0; var hasFilter = !!(filter && filter.length); var hasShadow = !isNil(shadowColor) && shadowBlur > 0; var nodeName = object.nodeName; var isInnerShadow = shadowType === 'inner'; var shouldDrawShadowWithStroke = hasStroke && hasShadow && (nodeName === gLite.Shape.PATH || nodeName === gLite.Shape.LINE || nodeName === gLite.Shape.POLYLINE || isFillTransparent || isInnerShadow); if (hasFill) { context.globalAlpha = opacity * fillOpacity; if (!shouldDrawShadowWithStroke) { setShadowAndFilter(object, context, hasShadow); } this.fill(context, object, fill, fillRule, canvasContext, plugin, runtime); if (!shouldDrawShadowWithStroke) { this.clearShadowAndFilter(context, hasFilter, hasShadow); } } if (hasStroke) { context.globalAlpha = opacity * strokeOpacity; context.lineWidth = lineWidth; if (!isNil(miterLimit)) { context.miterLimit = miterLimit; } if (!isNil(lineCap)) { context.lineCap = lineCap; } if (!isNil(lineJoin)) { context.lineJoin = lineJoin; } if (shouldDrawShadowWithStroke) { if (isInnerShadow) { context.globalCompositeOperation = 'source-atop'; } setShadowAndFilter(object, context, true); if (isInnerShadow) { this.stroke(context, object, stroke, canvasContext, plugin, runtime); context.globalCompositeOperation = 'source-over'; this.clearShadowAndFilter(context, hasFilter, true); } } this.stroke(context, object, stroke, canvasContext, plugin, runtime); } }; _proto.clearShadowAndFilter = function clearShadowAndFilter(context, hasFilter, hasShadow) { if (hasShadow) { context.shadowColor = 'transparent'; context.shadowBlur = 0; } if (hasFilter) { // save drop-shadow filter var oldFilter = context.filter; if (!isNil(oldFilter) && oldFilter.indexOf('drop-shadow') > -1) { context.filter = oldFilter.replace(/drop-shadow\([^)]*\)/, '').trim() || 'none'; } } }; _proto.fill = function fill(context, object, _fill, fillRule, canvasContext, plugin, runtime) { var _this = this; if (Array.isArray(_fill)) { _fill.forEach(function (gradient) { context.fillStyle = _this.getColor(gradient, object, context); fillRule ? context.fill(fillRule) : context.fill(); }); } else { if (gLite.isPattern(_fill)) { context.fillStyle = this.getPattern(_fill, object, context, canvasContext, plugin, runtime); } fillRule ? context.fill(fillRule) : context.fill(); } }; _proto.stroke = function stroke(context, object, _stroke, canvasContext, plugin, runtime) { var _this2 = this; if (Array.isArray(_stroke)) { _stroke.forEach(function (gradient) { context.strokeStyle = _this2.getColor(gradient, object, context); context.stroke(); }); } else { if (gLite.isPattern(_stroke)) { context.strokeStyle = this.getPattern(_stroke, object, context, canvasContext, plugin, runtime); } context.stroke(); } }; _proto.getPattern = function getPattern(pattern, object, context, canvasContext, plugin, runtime) { var $offscreenCanvas; var dpr; if (pattern.image.nodeName === 'rect') { var _pattern$image$parsed = pattern.image.parsedStyle, width = _pattern$image$parsed.width, height = _pattern$image$parsed.height; dpr = canvasContext.contextService.getDPR(); var offscreenCanvas = canvasContext.config.offscreenCanvas; $offscreenCanvas = runtime.offscreenCanvas.getOrCreateCanvas(offscreenCanvas); $offscreenCanvas.width = width * dpr; $offscreenCanvas.height = height * dpr; var offscreenCanvasContext = runtime.offscreenCanvas.getOrCreateContext(offscreenCanvas); var restoreStack = []; // offscreenCanvasContext.scale(1 / dpr, 1 / dpr); pattern.image.forEach(function (object) { plugin.renderDisplayObject(object, offscreenCanvasContext, canvasContext, restoreStack, runtime); }); restoreStack.forEach(function () { offscreenCanvasContext.restore(); }); } var canvasPattern = this.imagePool.getOrCreatePatternSync(pattern, context, $offscreenCanvas, dpr, function () { // set dirty rectangle flag object.renderable.dirty = true; canvasContext.renderingService.dirtify(); }); return canvasPattern; }; _proto.getColor = function getColor(parsedColor, object, context) { var color; if (parsedColor.type === gLite.GradientType.LinearGradient || parsedColor.type === gLite.GradientType.RadialGradient) { var bounds = object.getGeometryBounds(); var width = bounds && bounds.halfExtents[0] * 2 || 1; var height = bounds && bounds.halfExtents[1] * 2 || 1; color = this.imagePool.getOrCreateGradient(_extends({ type: parsedColor.type }, parsedColor.value, { width: width, height: height }), context); } return color; }; return DefaultRenderer; }(); /** * apply before fill and stroke but only once */ function setShadowAndFilter(object, context, hasShadow) { var _object$parsedStyle = object.parsedStyle, filter = _object$parsedStyle.filter, shadowColor = _object$parsedStyle.shadowColor, shadowBlur = _object$parsedStyle.shadowBlur, shadowOffsetX = _object$parsedStyle.shadowOffsetX, shadowOffsetY = _object$parsedStyle.shadowOffsetY; if (filter && filter.length) { // use raw filter string context.filter = object.style.filter; } if (hasShadow) { context.shadowColor = shadowColor.toString(); context.shadowBlur = shadowBlur || 0; context.shadowOffsetX = shadowOffsetX || 0; context.shadowOffsetY = shadowOffsetY || 0; } } var ImageRenderer = /*#__PURE__*/function () { function ImageRenderer(imagePool) { this.imagePool = void 0; this.imagePool = imagePool; } var _proto = ImageRenderer.prototype; _proto.render = function render(context, parsedStyle, object) { var width = parsedStyle.width, height = parsedStyle.height, img = parsedStyle.img, shadowColor = parsedStyle.shadowColor, shadowBlur = parsedStyle.shadowBlur; var image; var iw = width; var ih = height; if (isString(img)) { // image has been loaded in `mounted` hook image = this.imagePool.getImageSync(img); } else { iw || (iw = img.width); ih || (ih = img.height); image = img; } if (image) { var hasShadow = !isNil(shadowColor) && shadowBlur > 0; setShadowAndFilter(object, context, hasShadow); // node-canvas will throw the following err: // Error: Image given has not completed loading try { context.drawImage(image, 0, 0, iw, ih); } catch (e) {} } }; return ImageRenderer; }(); var TextRenderer = /*#__PURE__*/function () { function TextRenderer() {} var _proto = TextRenderer.prototype; _proto.render = function render(context, parsedStyle, object) { var lineWidth = parsedStyle.lineWidth, textAlign = parsedStyle.textAlign, textBaseline = parsedStyle.textBaseline, lineJoin = parsedStyle.lineJoin, miterLimit = parsedStyle.miterLimit, letterSpacing = parsedStyle.letterSpacing, stroke = parsedStyle.stroke, fill = parsedStyle.fill, fillOpacity = parsedStyle.fillOpacity, strokeOpacity = parsedStyle.strokeOpacity, opacity = parsedStyle.opacity, metrics = parsedStyle.metrics, dx = parsedStyle.dx, dy = parsedStyle.dy, shadowColor = parsedStyle.shadowColor, shadowBlur = parsedStyle.shadowBlur; var font = metrics.font, lines = metrics.lines, height = metrics.height, lineHeight = metrics.lineHeight, lineMetrics = metrics.lineMetrics; context.font = font; context.lineWidth = lineWidth; context.textAlign = textAlign === 'middle' ? 'center' : textAlign; var formattedTextBaseline = textBaseline; if ( // formattedTextBaseline === 'bottom' || !gLite.runtime.enableCSSParsing && formattedTextBaseline === 'alphabetic') { formattedTextBaseline = 'bottom'; } context.lineJoin = lineJoin; if (!isNil(miterLimit)) { context.miterLimit = miterLimit; } var linePositionY = 0; // handle vertical text baseline if (textBaseline === 'middle') { linePositionY = -height / 2 - lineHeight / 2; } else if (textBaseline === 'bottom' || textBaseline === 'alphabetic' || textBaseline === 'ideographic') { linePositionY = -height; } else if (textBaseline === 'top' || textBaseline === 'hanging') { linePositionY = -lineHeight; } // account for dx & dy var offsetX = dx || 0; linePositionY += dy || 0; if (lines.length === 1) { if (formattedTextBaseline === 'bottom') { formattedTextBaseline = 'middle'; linePositionY -= 0.5 * height; } else if (formattedTextBaseline === 'top') { formattedTextBaseline = 'middle'; linePositionY += 0.5 * height; } } context.textBaseline = formattedTextBaseline; var hasShadow = !isNil(shadowColor) && shadowBlur > 0; setShadowAndFilter(object, context, hasShadow); // draw lines line by line for (var i = 0; i < lines.length; i++) { var linePositionX = lineWidth / 2 + offsetX; linePositionY += lineHeight; // no need to re-position X, cause we already set text align // @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign if (!isNil(stroke) && !stroke.isNone && lineWidth) { this.drawLetterSpacing(context, lines[i], lineMetrics[i], textAlign, linePositionX, linePositionY, letterSpacing, fillOpacity, strokeOpacity, opacity, true); } if (!isNil(fill)) { this.drawLetterSpacing(context, lines[i], lineMetrics[i], textAlign, linePositionX, linePositionY, letterSpacing, fillOpacity, strokeOpacity, opacity); } } }; _proto.drawLetterSpacing = function drawLetterSpacing(context, text, lineMetrics, textAlign, x, y, letterSpacing, fillOpacity, strokeOpacity, opacity, isStroke) { if (isStroke === void 0) { isStroke = false; } // letterSpacing of 0 means normal, render all texts directly if (letterSpacing === 0) { if (isStroke) { this.strokeText(context, text, x, y, strokeOpacity); } else { this.fillText(context, text, x, y, fillOpacity, opacity); } return; } // draw text using left align var currentTextAlign = context.textAlign; context.textAlign = 'left'; var currentPosition = x; if (textAlign === 'center' || textAlign === 'middle') { currentPosition = x - lineMetrics.width / 2; } else if (textAlign === 'right' || textAlign === 'end') { currentPosition = x - lineMetrics.width; } var stringArray = Array.from(text); var previousWidth = context.measureText(text).width; var currentWidth = 0; for (var i = 0; i < stringArray.length; ++i) { var currentChar = stringArray[i]; if (isStroke) { this.strokeText(context, currentChar, currentPosition, y, strokeOpacity); } else { this.fillText(context, currentChar, currentPosition, y, fillOpacity, opacity); } currentWidth = context.measureText(text.substring(i + 1)).width; currentPosition += previousWidth - currentWidth + letterSpacing; previousWidth = currentWidth; } context.textAlign = currentTextAlign; }; _proto.fillText = function fillText(context, text, x, y, fillOpacity, opacity) { var currentGlobalAlpha; var applyOpacity = !isNil(fillOpacity) && fillOpacity !== 1; if (applyOpacity) { currentGlobalAlpha = context.globalAlpha; context.globalAlpha = fillOpacity * opacity; } context.fillText(text, x, y); if (applyOpacity) { context.globalAlpha = currentGlobalAlpha; } }; _proto.strokeText = function strokeText(context, text, x, y, strokeOpacity) { var currentGlobalAlpha; var applyOpacity = !isNil(strokeOpacity) && strokeOpacity !== 1; if (applyOpacity) { currentGlobalAlpha = context.globalAlpha; context.globalAlpha = strokeOpacity; } context.strokeText(text, x, y); if (applyOpacity) { context.globalAlpha = currentGlobalAlpha; } }; return TextRenderer; }(); var RectRenderer = /*#__PURE__*/function (_DefaultRenderer) { _inheritsLoose$3(RectRenderer, _DefaultRenderer); function RectRenderer() { return _DefaultRenderer.apply(this, arguments) || this; } return RectRenderer; }(DefaultRenderer); var CircleRenderer = /*#__PURE__*/function (_DefaultRenderer) { _inheritsLoose$3(CircleRenderer, _DefaultRenderer); function CircleRenderer() { return _DefaultRenderer.apply(this, arguments) || this; } return CircleRenderer; }(DefaultRenderer); var EllipseRenderer = /*#__PURE__*/function (_DefaultRenderer) { _inheritsLoose$3(EllipseRenderer, _DefaultRenderer); function EllipseRenderer() { return _DefaultRenderer.apply(this, arguments) || this; } return EllipseRenderer; }(DefaultRenderer); var LineRenderer = /*#__PURE__*/function (_DefaultRenderer) { _inheritsLoose$3(LineRenderer, _DefaultRenderer); function LineRenderer() { return _DefaultRenderer.apply(this, arguments) || this; } return LineRenderer; }(DefaultRenderer); var PolylineRenderer = /*#__PURE__*/function (_DefaultRenderer) { _inheritsLoose$3(PolylineRenderer, _DefaultRenderer); function PolylineRenderer() { return _DefaultRenderer.apply(this, arguments) || this; } return PolylineRenderer; }(DefaultRenderer); var PolygonRenderer = /*#__PURE__*/function (_DefaultRenderer) { _inheritsLoose$3(PolygonRenderer, _DefaultRenderer); function PolygonRenderer() { return _DefaultRenderer.apply(this, arguments) || this; } return PolygonRenderer; }(DefaultRenderer); var PathRenderer = /*#__PURE__*/function (_DefaultRenderer) { _inheritsLoose$3(PathRenderer, _DefaultRenderer); function PathRenderer() { return _DefaultRenderer.apply(this, arguments) || this; } return PathRenderer; }(DefaultRenderer); var Plugin$2 = /*#__PURE__*/function (_AbstractRendererPlug) { _inheritsLoose$3(Plugin, _AbstractRendererPlug); function Plugin(options) { var _this; if (options === void 0) { options = {}; } _this = _AbstractRendererPlug.call(this) || this; _this.options = void 0; _this.name = 'canvas-renderer'; _this.options = options; return _this; } var _proto = Plugin.prototype; _proto.init = function init() { var _defaultStyleRenderer; var canvasRendererPluginOptions = _extends({ dirtyObjectNumThreshold: 500, dirtyObjectRatioThreshold: 0.8 }, this.options); // @ts-ignore var imagePool = this.context.imagePool; var defaultRenderer = new DefaultRenderer(imagePool); var defaultStyleRendererFactory = (_defaultStyleRenderer = {}, _defaultStyleRenderer[gLite.Shape.CIRCLE] = defaultRenderer, _defaultStyleRenderer[gLite.Shape.ELLIPSE] = defaultRenderer, _defaultStyleRenderer[gLite.Shape.RECT] = defaultRenderer, _defaultStyleRenderer[gLite.Shape.IMAGE] = new ImageRenderer(imagePool), _defaultStyleRenderer[gLite.Shape.TEXT] = new TextRenderer(), _defaultStyleRenderer[gLite.Shape.LINE] = defaultRenderer, _defaultStyleRenderer[gLite.Shape.POLYLINE] = defaultRenderer, _defaultStyleRenderer[gLite.Shape.POLYGON] = defaultRenderer, _defaultStyleRenderer[gLite.Shape.PATH] = defaultRenderer, _defaultStyleRenderer[gLite.Shape.GROUP] = undefined, _defaultStyleRenderer[gLite.Shape.HTML] = undefined, _defaultStyleRenderer[gLite.Shape.MESH] = undefined, _defaultStyleRenderer); this.context.defaultStyleRendererFactory = defaultStyleRendererFactory; this.context.styleRendererFactory = defaultStyleRendererFactory; this.addRenderingPlugin(new CanvasRendererPlugin(canvasRendererPluginOptions)); }; _proto.destroy = function destroy() { this.removeAllRenderingPlugins(); delete this.context.defaultStyleRendererFactory; delete this.context.styleRendererFactory; }; return Plugin; }(gLite.AbstractRendererPlugin); var index_esm$2 = /*#__PURE__*/Object.freeze({ __proto__: null, CircleRenderer: CircleRenderer, EllipseRenderer: EllipseRenderer, ImageRenderer: ImageRenderer, LineRenderer: LineRenderer, PathRenderer: PathRenderer, Plugin: Plugin$2, PolygonRenderer: PolygonRenderer, PolylineRenderer: PolylineRenderer, RectRenderer: RectRenderer, TextRenderer: TextRenderer }); function _inheritsLoose$4(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf$4(subClass, superClass); } function _setPrototypeOf$4(o, p) { _setPrototypeOf$4 = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf$4(o, p); } // const MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; /** * listen to mouse/touch/pointer events on DOM wrapper, trigger pointer events */ var DOMInteractionPlugin = /*#__PURE__*/function () { function DOMInteractionPlugin() { this.context = void 0; } var _proto = DOMInteractionPlugin.prototype; _proto.apply = function apply(context, runtime) { var _this = this; var renderingService = context.renderingService, renderingContext = context.renderingContext, config = context.config; this.context = context; var canvas = renderingContext.root.ownerDocument.defaultView; // const SUPPORT_ONLY_TOUCH = canvas.supportsTouchEvents && MOBILE_REGEX.test(navigator.userAgent); var onPointerMove = function onPointerMove(ev) { renderingService.hooks.pointerMove.call(ev); }; var onPointerUp = function onPointerUp(ev) { renderingService.hooks.pointerUp.call(ev); }; var onPointerDown = function onPointerDown(ev) { renderingService.hooks.pointerDown.call(ev); }; var onPointerOver = function onPointerOver(ev) { renderingService.hooks.pointerOver.call(ev); }; var onPointerOut = function onPointerOut(ev) { renderingService.hooks.pointerOut.call(ev); }; var onPointerCancel = function onPointerCancel(ev) { renderingService.hooks.pointerCancel.call(ev); }; var onPointerWheel = function onPointerWheel(ev) { renderingService.hooks.pointerWheel.call(ev); }; var onClick = function onClick(ev) { renderingService.hooks.click.call(ev); }; var addPointerEventListener = function addPointerEventListener($el) { runtime.globalThis.document.addEventListener('pointermove', onPointerMove, true); $el.addEventListener('pointerdown', onPointerDown, true); $el.addEventListener('pointerleave', onPointerOut, true); $el.addEventListener('pointerover', onPointerOver, true); runtime.globalThis.addEventListener('pointerup', onPointerUp, true); runtime.globalThis.addEventListener('pointercancel', onPointerCancel, true); }; var addTouchEventListener = function addTouchEventListener($el) { $el.addEventListener('touchstart', onPointerDown, true); $el.addEventListener('touchend', onPointerUp, true); $el.addEventListener('touchmove', onPointerMove, true); $el.addEventListener('touchcancel', onPointerCancel, true); }; var addMouseEventListener = function addMouseEventListener($el) { runtime.globalThis.document.addEventListener('mousemove', onPointerMove, true); $el.addEventListener('mousedown', onPointerDown, true); $el.addEventListener('mouseout', onPointerOut, true); $el.addEventListener('mouseover', onPointerOver, true); runtime.globalThis.addEventListener('mouseup', onPointerUp, true); }; var removePointerEventListener = function removePointerEventListener($el) { runtime.globalThis.document.removeEventListener('pointermove', onPointerMove, true); $el.removeEventListener('pointerdown', onPointerDown, true); $el.removeEventListener('pointerleave', onPointerOut, true); $el.removeEventListener('pointerover', onPointerOver, true); runtime.globalThis.removeEventListener('pointerup', onPointerUp, true); }; var removeTouchEventListener = function removeTouchEventListener($el) { $el.removeEventListener('touchstart', onPointerDown, true); $el.removeEventListener('touchend', onPointerUp, true); $el.removeEventListener('touchmove', onPointerMove, true); $el.removeEventListener('touchcancel', onPointerCancel, true); }; var removeMouseEventListener = function removeMouseEventListener($el) { runtime.globalThis.document.removeEventListener('mousemove', onPointerMove, true); $el.removeEventListener('mousedown', onPointerDown, true); $el.removeEventListener('mouseout', onPointerOut, true); $el.removeEventListener('mouseover', onPointerOver, true); runtime.globalThis.removeEventListener('mouseup', onPointerUp, true); }; renderingService.hooks.init.tap(DOMInteractionPlugin.tag, function () { var $el = _this.context.contextService.getDomElement(); // @ts-ignore if (runtime.globalThis.navigator.msPointerEnabled) { // @ts-ignore $el.style.msContentZooming = 'none'; // @ts-ignore $el.style.msTouchAction = 'none'; } else if (canvas.supportsPointerEvents) { $el.style.touchAction = 'none'; } if (canvas.supportsPointerEvents) { addPointerEventListener($el); } else { addMouseEventListener($el); } if (canvas.supportsTouchEvents) { addTouchEventListener($el); } if (config.useNativeClickEvent) { $el.addEventListener('click', onClick, true); } // use passive event listeners // @see https://zhuanlan.zhihu.com/p/24555031 $el.addEventListener('wheel', onPointerWheel, { passive: true, capture: true }); }); renderingService.hooks.destroy.tap(DOMInteractionPlugin.tag, function () { var $el = _this.context.contextService.getDomElement(); // @ts-ignore if (runtime.globalThis.navigator.msPointerEnabled) { // @ts-ignore $el.style.msContentZooming = ''; // @ts-ignore $el.style.msTouchAction = ''; } else if (canvas.supportsPointerEvents) { $el.style.touchAction = ''; } if (canvas.supportsPointerEvents) { removePointerEventListener($el); } else { removeMouseEventListener($el); } if (canvas.supportsTouchEvents) { removeTouchEventListener($el); } if (config.useNativeClickEvent) { $el.removeEventListener('click', onClick, true); } $el.removeEventListener('wheel', onPointerWheel, true); }); }; return DOMInteractionPlugin; }(); DOMInteractionPlugin.tag = 'DOMInteraction'; var Plugin$3 = /*#__PURE__*/function (_AbstractRendererPlug) { _inheritsLoose$4(Plugin, _AbstractRendererPlug); function Plugin() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _AbstractRendererPlug.call.apply(_AbstractRendererPlug, [this].concat(args)) || this; _this.name = 'dom-interaction'; return _this; } var _proto = Plugin.prototype; _proto.init = function init() { this.addRenderingPlugin(new DOMInteractionPlugin()); }; _proto.destroy = function destroy() { this.removeAllRenderingPlugins(); }; return Plugin; }(gLite.AbstractRendererPlugin); var index_esm$3 = /*#__PURE__*/Object.freeze({ __proto__: null, Plugin: Plugin$3 }); function _inheritsLoose$5(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf$5(subClass, superClass); } function _setPrototypeOf$5(o, p) { _setPrototypeOf$5 = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf$5(o, p); } var HTML_PREFIX = 'g-html-'; var CANVAS_CAMERA_ID = 'g-canvas-camera'; var HTMLRenderingPlugin = /*#__PURE__*/function () { function HTMLRenderingPlugin() { this.context = void 0; /** * wrapper for camera */ this.$camera = void 0; } var _proto = HTMLRenderingPlugin.prototype; _proto.joinTransformMatrix = function joinTransformMatrix(matrix) { return "matrix(" + [matrix[0], matrix[1], matrix[4], matrix[5], matrix[12], matrix[13]].join(',') + ")"; }; _proto.apply = function apply(context) { var _this = this; var camera = context.camera, renderingContext = context.renderingContext, renderingService = context.renderingService; this.context = context; var canvas = renderingContext.root.ownerDocument.defaultView; var setTransform = function setTransform(object, $el) { $el.style.transform = _this.joinTransformMatrix(object.getWorldTransform()); }; var handleMounted = function handleMounted(e) { var object = e.target; if (object.nodeName === gLite.Shape.HTML) { if (!_this.$camera) { _this.$camera = _this.createCamera(camera); } // create DOM element var $el = _this.getOrCreateEl(object); _this.$camera.appendChild($el); // apply documentElement's style var attributes = object.ownerDocument.documentElement.attributes; Object.keys(attributes).forEach(function (name) { $el.style[name] = attributes[name]; }); Object.keys(object.attributes).forEach(function (name) { _this.updateAttribute(name, object); }); setTransform(object, $el); gLite.runtime.nativeHTMLMap.set($el, object); } }; var handleUnmounted = function handleUnmounted(e) { var object = e.target; if (object.nodeName === gLite.Shape.HTML && _this.$camera) { var $el = _this.getOrCreateEl(object); if ($el) { $el.remove(); gLite.runtime.nativeHTMLMap.delete($el); } // const existedId = this.getId(object); // const $existedElement: HTMLElement | null = this.$camera.querySelector('#' + existedId); // if ($existedElement) { // this.$camera.removeChild($existedElement); // } } }; var handleAttributeChanged = function handleAttributeChanged(e) { var object = e.target; if (object.nodeName === gLite.Shape.HTML) { var attrName = e.attrName; _this.updateAttribute(attrName, object); } }; var handleBoundsChanged = function handleBoundsChanged(e) { var object = e.target; if (object.nodeName === gLite.Shape.HTML) { var $el = _this.getOrCreateEl(object); setTransform(object, $el); } }; var handleCanvasResize = function handleCanvasResize() { if (_this.$camera) { var _this$context$config = _this.context.config, width = _this$context$config.width, height = _this$context$config.height; _this.$camera.style.width = (width || 0) + "px"; _this.$camera.style.height = (height || 0) + "px"; } }; renderingService.hooks.init.tap(HTMLRenderingPlugin.tag, function () { canvas.addEventListener(gLite.CanvasEvent.RESIZE, handleCanvasResize); canvas.addEventListener(gLite.ElementEvent.MOUNTED, handleMounted); canvas.addEventListener(gLite.ElementEvent.UNMOUNTED, handleUnmounted); canvas.addEventListener(gLite.ElementEvent.ATTR_MODIFIED, handleAttributeChanged); canvas.addEventListener(gLite.ElementEvent.BOUNDS_CHANGED, handleBoundsChanged); }); renderingService.hooks.endFrame.tap(HTMLRenderingPlugin.tag, function () { if (_this.$camera && renderingContext.renderReasons.has(gLite.RenderReason.CAMERA_CHANGED)) { _this.$camera.style.transform = _this.joinTransformMatrix(camera.getOrthoMatrix()); } }); renderingService.hooks.destroy.tap(HTMLRenderingPlugin.tag, function () { // remove camera if (_this.$camera) { _this.$camera.remove(); } canvas.removeEventListener(gLite.CanvasEvent.RESIZE, handleCanvasResize); canvas.removeEventListener(gLite.ElementEvent.MOUNTED, handleMounted); canvas.removeEventListener(gLite.ElementEvent.UNMOUNTED, handleUnmounted); canvas.removeEventListener(gLite.ElementEvent.ATTR_MODIFIED, handleAttributeChanged); canvas.removeEventListener(gLite.ElementEvent.BOUNDS_CHANGED, handleBoundsChanged); }); }; _proto.getId = function getId(object) { return object.id || HTML_PREFIX + object.entity; }; _proto.createCamera = function createCamera(camera) { var _this$context$config2 = this.context.config, doc = _this$context$config2.document, width = _this$context$config2.width, height = _this$context$config2.height; var $canvas = this.context.contextService.getDomElement(); var $container = $canvas.parentNode; if ($container) { var cameraId = CANVAS_CAMERA_ID; var $existedCamera = $container.querySelector('#' + cameraId); if (!$existedCamera) { var $camera = (doc || document).createElement('div'); $existedCamera = $camera; $camera.id = cameraId; // use absolute position $camera.style.position = 'absolute'; // account for DOM element's offset @see https://github.com/antvis/G/issues/1150 $camera.style.left = ($canvas.offsetLeft || 0) + "px"; $camera.style.top = ($canvas.offsetTop || 0) + "px"; $camera.style.transformOrigin = 'left top'; $camera.style.transform = this.joinTransformMatrix(camera.getOrthoMatrix()); // HTML elements should not overflow with canvas @see https://github.com/antvis/G/issues/1163 $camera.style.overflow = 'hidden'; $camera.style.pointerEvents = 'none'; $camera.style.width = (width || 0) + "px"; $camera.style.height = (height || 0) + "px"; $container.appendChild($camera); } return $existedCamera; } return null; }; _proto.getOrCreateEl = function getOrCreateEl(object) { var doc = this.context.config.document; var existedId = this.getId(object); var $existedElement = this.$camera.querySelector('#' + existedId); if (!$existedElement) { $existedElement = (doc || document).createElement('div'); object.parsedStyle.$el = $existedElement; $existedElement.id = existedId; if (object.name) { $existedElement.setAttribute('name', object.name); } if (object.className) { $existedElement.className = object.className; } // use absolute position $existedElement.style.position = 'absolute'; // @see https://github.com/antvis/G/issues/1150 $existedElement.style.left = "0px"; $existedElement.style.top = "0px"; $existedElement.style['will-change'] = 'transform'; $existedElement.style.transform = this.joinTransformMatrix(object.getWorldTransform()); } return $existedElement; }; _proto.updateAttribute = function updateAttribute(name, object) { var $el = this.getOrCreateEl(object); switch (name) { case 'innerHTML': var innerHTML = object.parsedStyle.innerHTML; if (isString(innerHTML)) { $el.innerHTML = innerHTML; } else { $el.innerHTML = ''; $el.appendChild(innerHTML); } break; case 'transformOrigin': var transformOrigin = object.parsedStyle.transformOrigin; $el.style['transform-origin'] = transformOrigin[0].value + " " + transformOrigin[1].value; break; case 'width': if (gLite.runtime.enableCSSParsing) { var width = object.computedStyleMap().get('width'); $el.style.width = width.toString(); } else { var _width = object.parsedStyle.width; $el.style.width = isNumber(_width) ? _width + "px" : _width.toString(); } break; case 'height': if (gLite.runtime.enableCSSParsing) { var height = object.computedStyleMap().get('height'); $el.style.height = height.toString(); } else { var _height = object.parsedStyle.height; $el.style.height = isNumber(_height) ? _height + "px" : _height.toString(); } break; case 'zIndex': var zIndex = object.parsedStyle.zIndex; $el.style['z-index'] = "" + zIndex; break; case 'visibility': var visibility = object.parsedStyle.visibility; $el.style.visibility = visibility; break; case 'pointerEvents': var pointerEvents = object.parsedStyle.pointerEvents; $el.style.pointerEvents = pointerEvents; break; case 'opacity': var opacity = object.parsedStyle.opacity; $el.style.opacity = "" + opacity; break; case 'fill': var fill = object.parsedStyle.fill; var color = ''; if (gLite.isCSSRGB(fill)) { if (fill.isNone) { color = 'transparent'; } else { color = object.getAttribute('fill'); } } else if (Array.isArray(fill)) { color = object.getAttribute('fill'); } else if (gLite.isPattern(fill)) ; $el.style.background = color; break; case 'stroke': var stroke = object.parsedStyle.stroke; var borderColor = ''; if (gLite.isCSSRGB(stroke)) { if (stroke.isNone) { borderColor = 'transparent'; } else { borderColor = object.getAttribute('stroke'); } } else if (Array.isArray(stroke)) { borderColor = object.getAttribute('stroke'); } else if (gLite.isPattern(stroke)) ; $el.style['border-color'] = borderColor; $el.style['border-style'] = 'solid'; break; case 'lineWidth': var lineWidth = object.parsedStyle.lineWidth; $el.style['border-width'] = (lineWidth || 0) + "px"; break; case 'lineDash': $el.style['border-style'] = 'dashed'; break; case 'filter': var filter = object.style.filter; $el.style.filter = filter; break; } }; return HTMLRenderingPlugin; }(); HTMLRenderingPlugin.tag = 'HTMLRendering'; var Plugin$4 = /*#__PURE__*/function (_AbstractRendererPlug) { _inheritsLoose$5(Plugin, _AbstractRendererPlug); function Plugin() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _AbstractRendererPlug.call.apply(_AbstractRendererPlug, [this].concat(args)) || this; _this.name = 'html-renderer'; return _this; } var _proto = Plugin.prototype; _proto.init = function init() { this.addRenderingPlugin(new HTMLRenderingPlugin()); }; _proto.destroy = function destroy() { this.removeAllRenderingPlugins(); }; return Plugin; }(gLite.AbstractRendererPlugin); var index_esm$4 = /*#__PURE__*/Object.freeze({ __proto__: null, Plugin: Plugin$4 }); function _inheritsLoose$6(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf$6(subClass, superClass); } function _setPrototypeOf$6(o, p) { _setPrototypeOf$6 = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf$6(o, p); } /** * Common utilities * @module glMatrix */ var ARRAY_TYPE$1 = typeof Float32Array !== 'undefined' ? Float32Array : Array; if (!Math.hypot) Math.hypot = function () { var y = 0, i = arguments.length; while (i--) { y += arguments[i] * arguments[i]; } return Math.sqrt(y); }; /** * 4x4 Matrix
Format: column-major, when typed out it looks like row-major
The matrices are being post multiplied. * @module mat4 */ /** * Creates a new identity mat4 * * @returns {mat4} a new 4x4 matrix */ function create$3() { var out = new ARRAY_TYPE$1(16); if (ARRAY_TYPE$1 != Float32Array) { out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; } out[0] = 1; out[5] = 1; out[10] = 1; out[15] = 1; return out; } /** * Set a mat4 to the identity matrix * * @param {mat4} out the receiving matrix * @returns {mat4} out */ function identity(out) { out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = 1; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[10] = 1; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1; return out; } /** * Scales the mat4 by the dimensions in the given vec3 not using vectorization * * @param {mat4} out the receiving matrix * @param {ReadonlyMat4} a the matrix to scale * @param {ReadonlyVec3} v the vec3 to scale the matrix by * @returns {mat4} out **/ function scale(out, a, v) { var x = v[0], y = v[1], z = v[2]; out[0] = a[0] * x; out[1] = a[1] * x; out[2] = a[2] * x; out[3] = a[3] * x; out[4] = a[4] * y; out[5] = a[5] * y; out[6] = a[6] * y; out[7] = a[7] * y; out[8] = a[8] * z; out[9] = a[9] * z; out[10] = a[10] * z; out[11] = a[11] * z; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; return out; } var ImagePool = /*#__PURE__*/function () { function ImagePool(canvasConfig) { this.canvasConfig = void 0; this.imageCache = {}; this.gradientCache = {}; this.patternCache = {}; this.canvasConfig = canvasConfig; } var _proto = ImagePool.prototype; _proto.getImageSync = function getImageSync(src, callback) { if (!this.imageCache[src]) { this.getOrCreateImage(src).then(function () { if (callback) { callback(); } }); } else { if (callback) { callback(); } } return this.imageCache[src]; }; _proto.getOrCreateImage = function getOrCreateImage(src) { var _this = this; if (this.imageCache[src]) { return Promise.resolve(this.imageCache[src]); } // @see https://github.com/antvis/g/issues/938 var createImage = this.canvasConfig.createImage; return new Promise(function (resolve, reject) { var image; if (createImage) { image = createImage(src); } else if (gLite.isBrowser) { image = new window.Image(); } if (image) { image.onload = function () { _this.imageCache[src] = image; resolve(image); }; image.onerror = function (ev) { reject(ev); }; image.crossOrigin = 'Anonymous'; image.src = src; } }); }; _proto.getOrCreatePatternSync = function getOrCreatePatternSync(pattern, context, $offscreenCanvas, dpr, callback) { var patternKey = this.generatePatternKey(pattern); if (patternKey && this.patternCache[patternKey]) { return this.patternCache[patternKey]; } var image = pattern.image, repetition = pattern.repetition, transform = pattern.transform; var src; var needScaleWithDPR = false; // Image URL if (isString(image)) { src = this.getImageSync(image, callback); } else if ($offscreenCanvas) { src = $offscreenCanvas; needScaleWithDPR = true; } else { src = image; } // @see https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/createPattern var canvasPattern = src && context.createPattern(src, repetition); if (canvasPattern) { var mat; // @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern/setTransform if (transform) { mat = gLite.parsedTransformToMat4(gLite.parseTransform(transform)); } else { mat = identity(create$3()); } if (needScaleWithDPR) { scale(mat, mat, [1 / dpr, 1 / dpr, 1]); } canvasPattern.setTransform({ a: mat[0], b: mat[1], c: mat[4], d: mat[5], e: mat[12], f: mat[13] }); } if (patternKey && canvasPattern) { this.patternCache[patternKey] = canvasPattern; } return canvasPattern; }; _proto.getOrCreateGradient = function getOrCreateGradient(params, context) { var key = this.generateGradientKey(params); var type = params.type, steps = params.steps, width = params.width, height = params.height, angle = params.angle, cx = params.cx, cy = params.cy, size = params.size; if (this.gradientCache[key]) { return this.gradientCache[key]; } var gradient = null; if (type === gLite.GradientType.LinearGradient) { var _computeLinearGradien = gLite.computeLinearGradient(width, height, angle), x1 = _computeLinearGradien.x1, y1 = _computeLinearGradien.y1, x2 = _computeLinearGradien.x2, y2 = _computeLinearGradien.y2; // @see https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/createLinearGradient gradient = context.createLinearGradient(x1, y1, x2, y2); } else if (type === gLite.GradientType.RadialGradient) { var _computeRadialGradien = gLite.computeRadialGradient(width, height, cx, cy, size), x = _computeRadialGradien.x, y = _computeRadialGradien.y, r = _computeRadialGradien.r; // @see https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/createRadialGradient gradient = context.createRadialGradient(x, y, 0, x, y, r); } if (gradient) { steps.forEach(function (_ref) { var offset = _ref.offset, color = _ref.color; if (offset.unit === gLite.UnitType.kPercentage) { var _gradient; (_gradient = gradient) === null || _gradient === void 0 ? void 0 : _gradient.addColorStop(offset.value / 100, color.toString()); } }); this.gradientCache[key] = gradient; } return this.gradientCache[key]; }; _proto.generateGradientKey = function generateGradientKey(params) { var type = params.type, width = params.width, height = params.height, steps = params.steps, angle = params.angle, cx = params.cx, cy = params.cy, size = params.size; return "gradient-" + type + "-" + ((angle === null || angle === void 0 ? void 0 : angle.toString()) || 0) + "-" + ((cx === null || cx === void 0 ? void 0 : cx.toString()) || 0) + "-" + ((cy === null || cy === void 0 ? void 0 : cy.toString()) || 0) + "-" + ((size === null || size === void 0 ? void 0 : size.toString()) || 0) + "-" + width + "-" + height + "-" + steps.map(function (_ref2) { var offset = _ref2.offset, color = _ref2.color; return "" + offset + color; }).join('-'); }; _proto.generatePatternKey = function generatePatternKey(pattern) { var image = pattern.image, repetition = pattern.repetition; // only generate cache for Image if (isString(image)) { return "pattern-" + image + "-" + repetition; } else if (image.nodeName === 'rect') { return "pattern-" + image.entity + "-" + repetition; } }; return ImagePool; }(); var LoadImagePlugin = /*#__PURE__*/function () { function LoadImagePlugin() {} var _proto = LoadImagePlugin.prototype; _proto.apply = function apply(context) { // @ts-ignore var renderingService = context.renderingService, renderingContext = context.renderingContext, imagePool = context.imagePool; var canvas = renderingContext.root.ownerDocument.defaultView; var handleMounted = function handleMounted(e) { var object = e.target; var nodeName = object.nodeName, attributes = object.attributes; if (nodeName === gLite.Shape.IMAGE) { var img = attributes.img; if (isString(img)) { imagePool.getImageSync(img, function () { // set dirty rectangle flag object.renderable.dirty = true; renderingService.dirtify(); }); } } }; var handleAttributeChanged = function handleAttributeChanged(e) { var object = e.target; var attrName = e.attrName, newValue = e.newValue; if (object.nodeName === gLite.Shape.IMAGE) { if (attrName === 'img') { if (isString(newValue)) { imagePool.getOrCreateImage(newValue).then(function () { // set dirty rectangle flag object.renderable.dirty = true; renderingService.dirtify(); }); } } } }; renderingService.hooks.init.tap(LoadImagePlugin.tag, function () { canvas.addEventListener(gLite.ElementEvent.MOUNTED, handleMounted); canvas.addEventListener(gLite.ElementEvent.ATTR_MODIFIED, handleAttributeChanged); }); renderingService.hooks.destroy.tap(LoadImagePlugin.tag, function () { canvas.removeEventListener(gLite.ElementEvent.MOUNTED, handleMounted); canvas.removeEventListener(gLite.ElementEvent.ATTR_MODIFIED, handleAttributeChanged); }); }; return LoadImagePlugin; }(); LoadImagePlugin.tag = 'LoadImage'; var Plugin$5 = /*#__PURE__*/function (_AbstractRendererPlug) { _inheritsLoose$6(Plugin, _AbstractRendererPlug); function Plugin() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _AbstractRendererPlug.call.apply(_AbstractRendererPlug, [this].concat(args)) || this; _this.name = 'image-loader'; return _this; } var _proto = Plugin.prototype; _proto.init = function init() { // @ts-ignore this.context.imagePool = new ImagePool(this.context.config); this.addRenderingPlugin(new LoadImagePlugin()); }; _proto.destroy = function destroy() { this.removeAllRenderingPlugins(); }; return Plugin; }(gLite.AbstractRendererPlugin); var index_esm$5 = /*#__PURE__*/Object.freeze({ __proto__: null, ImagePool: ImagePool, Plugin: Plugin$5 }); var Canvas2DContextService = /*#__PURE__*/function () { function Canvas2DContextService(context) { this.$container = void 0; this.$canvas = void 0; this.dpr = void 0; this.context = void 0; this.canvasConfig = void 0; this.renderingContext = void 0; this.renderingContext = context.renderingContext; this.canvasConfig = context.config; } var _proto = Canvas2DContextService.prototype; _proto.init = function init() { var _this$canvasConfig = this.canvasConfig, container = _this$canvasConfig.container, canvas = _this$canvasConfig.canvas; if (canvas) { this.$canvas = canvas; if (container && canvas.parentElement !== container) { container.appendChild(canvas); } this.$container = canvas.parentElement; this.canvasConfig.container = this.$container; } else if (container) { // create container this.$container = isString(container) ? document.getElementById(container) : container; if (this.$container) { // create canvas var $canvas = document.createElement('canvas'); this.$container.appendChild($canvas); if (!this.$container.style.position) { this.$container.style.position = 'relative'; } this.$canvas = $canvas; } } this.context = this.$canvas.getContext('2d'); this.resize(this.canvasConfig.width, this.canvasConfig.height); }; _proto.getContext = function getContext() { return this.context; }; _proto.getDomElement = function getDomElement() { return this.$canvas; }; _proto.getDPR = function getDPR() { return this.dpr; }; _proto.getBoundingClientRect = function getBoundingClientRect() { if (this.$canvas.getBoundingClientRect) { return this.$canvas.getBoundingClientRect(); } }; _proto.destroy = function destroy() { // @ts-ignore if (this.$container && this.$canvas && this.$canvas.parentNode) { // destroy context // @ts-ignore this.$container.removeChild(this.$canvas); } }; _proto.resize = function resize(width, height) { var devicePixelRatio = this.canvasConfig.devicePixelRatio; // use user-defined dpr first var dpr = devicePixelRatio || gLite.isBrowser && window.devicePixelRatio || 1; dpr = dpr >= 1 ? Math.ceil(dpr) : 1; this.dpr = dpr; if (this.$canvas) { // set canvas width & height this.$canvas.width = this.dpr * width; this.$canvas.height = this.dpr * height; // set CSS style width & height gLite.setDOMSize(this.$canvas, width, height); // const dpr = this.getDPR(); // scale all drawing operations by the dpr // @see https://www.html5rocks.com/en/tutorials/canvas/hidpi/ // this.context.scale(dpr, dpr); } this.renderingContext.renderReasons.add(gLite.RenderReason.CAMERA_CHANGED); }; _proto.applyCursorStyle = function applyCursorStyle(cursor) { if (this.$container && this.$container.style) { this.$container.style.cursor = cursor; } }; _proto.toDataURL = /*#__PURE__*/function () { var _toDataURL = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(options) { var _options, type, encoderOptions; return _regeneratorRuntime().wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: if (options === void 0) { options = {}; } _options = options, type = _options.type, encoderOptions = _options.encoderOptions; return _context.abrupt("return", this.context.canvas.toDataURL(type, encoderOptions)); case 3: case "end": return _context.stop(); } }, _callee, this); })); function toDataURL(_x) { return _toDataURL.apply(this, arguments); } return toDataURL; }(); return Canvas2DContextService; }(); var ContextRegisterPlugin = /*#__PURE__*/function (_AbstractRendererPlug) { _inheritsLoose(ContextRegisterPlugin, _AbstractRendererPlug); function ContextRegisterPlugin() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _AbstractRendererPlug.call.apply(_AbstractRendererPlug, [this].concat(args)) || this; _this.name = 'canvas-context-register'; return _this; } var _proto = ContextRegisterPlugin.prototype; _proto.init = function init() { this.context.ContextService = Canvas2DContextService; }; _proto.destroy = function destroy() { delete this.context.ContextService; }; return ContextRegisterPlugin; }(gLite.AbstractRendererPlugin); var Renderer = /*#__PURE__*/function (_AbstractRenderer) { _inheritsLoose(Renderer, _AbstractRenderer); function Renderer(config) { var _this; _this = _AbstractRenderer.call(this, config) || this; // register Canvas2DContext _this.registerPlugin(new ContextRegisterPlugin()); _this.registerPlugin(new Plugin$5()); _this.registerPlugin(new Plugin()); // enable rendering with Canvas2D API _this.registerPlugin(new Plugin$2()); _this.registerPlugin(new Plugin$3()); // enable picking with Canvas2D API _this.registerPlugin(new Plugin$1()); // render HTML component _this.registerPlugin(new Plugin$4()); return _this; } return Renderer; }(gLite.AbstractRenderer); exports.CanvasPathGenerator = index_esm; exports.CanvasPicker = index_esm$1; exports.CanvasRenderer = index_esm$2; exports.DomInteraction = index_esm$3; exports.HTMLRenderer = index_esm$4; exports.ImageLoader = index_esm$5; exports.Renderer = Renderer; Object.defineProperty(exports, '__esModule', { value: true }); })));