UNPKG

apexcharts

Version:

A JavaScript Chart Library

1,720 lines (1,548 loc) 1.35 MB
/*! * ApexCharts v5.3.1 * (c) 2018-2025 ApexCharts */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ApexCharts = factory()); })(this, (function () { 'use strict'; function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var n = 0, F = function () {}; return { s: F, n: function () { return n >= r.length ? { done: !0 } : { done: !1, value: r[n++] }; }, e: function (r) { throw r; }, f: F }; } 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 o, a = !0, u = !1; return { s: function () { t = t.call(r); }, n: function () { var r = t.next(); return a = r.done, r; }, e: function (r) { u = !0, o = r; }, f: function () { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; } function _createSuper(t) { var r = _isNativeReflectConstruct(); return function () { var e, o = _getPrototypeOf(t); if (r) { var s = _getPrototypeOf(this).constructor; e = Reflect.construct(o, arguments, s); } else e = o.apply(this, arguments); return _possibleConstructorReturn(this, e); }; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function () { return !!t; })(); } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _possibleConstructorReturn(t, e) { if (e && ("object" == typeof e || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } /* ** Generic functions which are not dependent on ApexCharts */ var Utils$1 = /*#__PURE__*/function () { function Utils() { _classCallCheck(this, Utils); } _createClass(Utils, [{ key: "shadeRGBColor", value: function shadeRGBColor(percent, color) { var f = color.split(','), t = percent < 0 ? 0 : 255, p = percent < 0 ? percent * -1 : percent, R = parseInt(f[0].slice(4), 10), G = parseInt(f[1], 10), B = parseInt(f[2], 10); return 'rgb(' + (Math.round((t - R) * p) + R) + ',' + (Math.round((t - G) * p) + G) + ',' + (Math.round((t - B) * p) + B) + ')'; } }, { key: "shadeHexColor", value: function shadeHexColor(percent, color) { var f = parseInt(color.slice(1), 16), t = percent < 0 ? 0 : 255, p = percent < 0 ? percent * -1 : percent, R = f >> 16, G = f >> 8 & 0x00ff, B = f & 0x0000ff; return '#' + (0x1000000 + (Math.round((t - R) * p) + R) * 0x10000 + (Math.round((t - G) * p) + G) * 0x100 + (Math.round((t - B) * p) + B)).toString(16).slice(1); } // beautiful color shading blending code // http://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors }, { key: "shadeColor", value: function shadeColor(p, color) { if (Utils.isColorHex(color)) { return this.shadeHexColor(p, color); } else { return this.shadeRGBColor(p, color); } } }], [{ key: "bind", value: function bind(fn, me) { return function () { return fn.apply(me, arguments); }; } }, { key: "isObject", value: function isObject(item) { return item && _typeof(item) === 'object' && !Array.isArray(item) && item != null; } // Type checking that works across different window objects }, { key: "is", value: function is(type, val) { return Object.prototype.toString.call(val) === '[object ' + type + ']'; } }, { key: "isSafari", value: function isSafari() { return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); } }, { key: "listToArray", value: function listToArray(list) { var i, array = []; for (i = 0; i < list.length; i++) { array[i] = list[i]; } return array; } // to extend defaults with user options // credit: http://stackoverflow.com/questions/27936772/deep-object-merging-in-es6-es7#answer-34749873 }, { key: "extend", value: function extend(target, source) { var _this = this; if (typeof Object.assign !== 'function') { (function () { Object.assign = function (target) { // We must check against these specific cases. if (target === undefined || target === null) { throw new TypeError('Cannot convert undefined or null to object'); } var output = Object(target); for (var index = 1; index < arguments.length; index++) { var _source = arguments[index]; if (_source !== undefined && _source !== null) { for (var nextKey in _source) { if (_source.hasOwnProperty(nextKey)) { output[nextKey] = _source[nextKey]; } } } } return output; }; })(); } var output = Object.assign({}, target); if (this.isObject(target) && this.isObject(source)) { Object.keys(source).forEach(function (key) { if (_this.isObject(source[key])) { if (!(key in target)) { Object.assign(output, _defineProperty({}, key, source[key])); } else { output[key] = _this.extend(target[key], source[key]); } } else { Object.assign(output, _defineProperty({}, key, source[key])); } }); } return output; } }, { key: "extendArray", value: function extendArray(arrToExtend, resultArr) { var extendedArr = []; arrToExtend.map(function (item) { extendedArr.push(Utils.extend(resultArr, item)); }); arrToExtend = extendedArr; return arrToExtend; } // If month counter exceeds 12, it starts again from 1 }, { key: "monthMod", value: function monthMod(month) { return month % 12; } }, { key: "clone", value: function clone(source) { var visited = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new WeakMap(); if (source === null || _typeof(source) !== 'object') { return source; } if (visited.has(source)) { return visited.get(source); } var cloneResult; if (Array.isArray(source)) { cloneResult = []; visited.set(source, cloneResult); for (var i = 0; i < source.length; i++) { cloneResult[i] = this.clone(source[i], visited); } } else if (source instanceof Date) { cloneResult = new Date(source.getTime()); } else { cloneResult = {}; visited.set(source, cloneResult); for (var prop in source) { if (source.hasOwnProperty(prop)) { cloneResult[prop] = this.clone(source[prop], visited); } } } return cloneResult; } }, { key: "log10", value: function log10(x) { return Math.log(x) / Math.LN10; } }, { key: "roundToBase10", value: function roundToBase10(x) { return Math.pow(10, Math.floor(Math.log10(x))); } }, { key: "roundToBase", value: function roundToBase(x, base) { return Math.pow(base, Math.floor(Math.log(x) / Math.log(base))); } }, { key: "parseNumber", value: function parseNumber(val) { if (typeof val === 'number' || val === null) return val; return parseFloat(val); } }, { key: "stripNumber", value: function stripNumber(num) { var precision = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2; return Number.isInteger(num) ? num : parseFloat(num.toPrecision(precision)); } }, { key: "randomId", value: function randomId() { return (Math.random() + 1).toString(36).substring(4); } }, { key: "noExponents", value: function noExponents(num) { // Check if the number contains 'e' (exponential notation) if (num.toString().includes('e')) { return Math.round(num); // Round the number } return num; // Return as-is if no exponential notation } }, { key: "elementExists", value: function elementExists(element) { if (!element || !element.isConnected) { return false; } return true; } }, { key: "getDimensions", value: function getDimensions(el) { var computedStyle = getComputedStyle(el, null); var elementHeight = el.clientHeight; var elementWidth = el.clientWidth; elementHeight -= parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom); elementWidth -= parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight); return [elementWidth, elementHeight]; } }, { key: "getBoundingClientRect", value: function getBoundingClientRect(element) { var rect = element.getBoundingClientRect(); return { top: rect.top, right: rect.right, bottom: rect.bottom, left: rect.left, width: element.clientWidth, height: element.clientHeight, x: rect.left, y: rect.top }; } }, { key: "getLargestStringFromArr", value: function getLargestStringFromArr(arr) { return arr.reduce(function (a, b) { if (Array.isArray(b)) { b = b.reduce(function (aa, bb) { return aa.length > bb.length ? aa : bb; }); } return a.length > b.length ? a : b; }, 0); } // http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb#answer-12342275 }, { key: "hexToRgba", value: function hexToRgba() { var hex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '#999999'; var opacity = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.6; if (hex.substring(0, 1) !== '#') { hex = '#999999'; } var h = hex.replace('#', ''); h = h.match(new RegExp('(.{' + h.length / 3 + '})', 'g')); for (var i = 0; i < h.length; i++) { h[i] = parseInt(h[i].length === 1 ? h[i] + h[i] : h[i], 16); } if (typeof opacity !== 'undefined') h.push(opacity); return 'rgba(' + h.join(',') + ')'; } }, { key: "getOpacityFromRGBA", value: function getOpacityFromRGBA(rgba) { return parseFloat(rgba.replace(/^.*,(.+)\)/, '$1')); } }, { key: "rgb2hex", value: function rgb2hex(rgb) { rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i); return rgb && rgb.length === 4 ? '#' + ('0' + parseInt(rgb[1], 10).toString(16)).slice(-2) + ('0' + parseInt(rgb[2], 10).toString(16)).slice(-2) + ('0' + parseInt(rgb[3], 10).toString(16)).slice(-2) : ''; } }, { key: "isColorHex", value: function isColorHex(color) { return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)|(^#[0-9A-F]{8}$)/i.test(color); } }, { key: "getPolygonPos", value: function getPolygonPos(size, dataPointsLen) { var dotsArray = []; var angle = Math.PI * 2 / dataPointsLen; for (var i = 0; i < dataPointsLen; i++) { var curPos = {}; curPos.x = size * Math.sin(i * angle); curPos.y = -size * Math.cos(i * angle); dotsArray.push(curPos); } return dotsArray; } }, { key: "polarToCartesian", value: function polarToCartesian(centerX, centerY, radius, angleInDegrees) { var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; return { x: centerX + radius * Math.cos(angleInRadians), y: centerY + radius * Math.sin(angleInRadians) }; } }, { key: "escapeString", value: function escapeString(str) { var escapeWith = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'x'; var newStr = str.toString().slice(); newStr = newStr.replace(/[` ~!@#$%^&*()|+\=?;:'",.<>{}[\]\\/]/gi, escapeWith); return newStr; } }, { key: "negToZero", value: function negToZero(val) { return val < 0 ? 0 : val; } }, { key: "moveIndexInArray", value: function moveIndexInArray(arr, old_index, new_index) { if (new_index >= arr.length) { var k = new_index - arr.length + 1; while (k--) { arr.push(undefined); } } arr.splice(new_index, 0, arr.splice(old_index, 1)[0]); return arr; } }, { key: "extractNumber", value: function extractNumber(s) { return parseFloat(s.replace(/[^\d.]*/g, '')); } }, { key: "findAncestor", value: function findAncestor(el, cls) { while ((el = el.parentElement) && !el.classList.contains(cls)) { } return el; } }, { key: "setELstyles", value: function setELstyles(el, styles) { for (var key in styles) { if (styles.hasOwnProperty(key)) { el.style.key = styles[key]; } } } // prevents JS prevision errors when adding }, { key: "preciseAddition", value: function preciseAddition(a, b) { var aDecimals = (String(a).split('.')[1] || '').length; var bDecimals = (String(b).split('.')[1] || '').length; var factor = Math.pow(10, Math.max(aDecimals, bDecimals)); return (Math.round(a * factor) + Math.round(b * factor)) / factor; } }, { key: "isNumber", value: function isNumber(value) { return !isNaN(value) && parseFloat(Number(value)) === value && !isNaN(parseInt(value, 10)); } }, { key: "isFloat", value: function isFloat(n) { return Number(n) === n && n % 1 !== 0; } }, { key: "isMsEdge", value: function isMsEdge() { var ua = window.navigator.userAgent; var edge = ua.indexOf('Edge/'); if (edge > 0) { // Edge (IE 12+) => return version number return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); } // other browser return false; } // // Find the Greatest Common Divisor of two numbers // }, { key: "getGCD", value: function getGCD(a, b) { var p = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 7; var big = Math.pow(10, p - Math.floor(Math.log10(Math.max(a, b)))); a = Math.round(Math.abs(a) * big); b = Math.round(Math.abs(b) * big); while (b) { var t = b; b = a % b; a = t; } return a / big; } }, { key: "getPrimeFactors", value: function getPrimeFactors(n) { var factors = []; var divisor = 2; while (n >= 2) { if (n % divisor == 0) { factors.push(divisor); n = n / divisor; } else { divisor++; } } return factors; } }, { key: "mod", value: function mod(a, b) { var p = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 7; var big = Math.pow(10, p - Math.floor(Math.log10(Math.max(a, b)))); a = Math.round(Math.abs(a) * big); b = Math.round(Math.abs(b) * big); return a % b / big; } }]); return Utils; }(); /** * ApexCharts Animation Class. * * @module Animations **/ var Animations = /*#__PURE__*/function () { function Animations(ctx) { _classCallCheck(this, Animations); this.ctx = ctx; this.w = ctx.w; } _createClass(Animations, [{ key: "animateLine", value: function animateLine(el, from, to, speed) { el.attr(from).animate(speed).attr(to); } /* ** Animate radius of a circle element */ }, { key: "animateMarker", value: function animateMarker(el, speed, easing, cb) { el.attr({ opacity: 0 }).animate(speed).attr({ opacity: 1 }).after(function () { cb(); }); } /* ** Animate rect properties */ }, { key: "animateRect", value: function animateRect(el, from, to, speed, fn) { el.attr(from).animate(speed).attr(to).after(function () { return fn(); }); } }, { key: "animatePathsGradually", value: function animatePathsGradually(params) { var el = params.el, realIndex = params.realIndex, j = params.j, fill = params.fill, pathFrom = params.pathFrom, pathTo = params.pathTo, speed = params.speed, delay = params.delay; var me = this; var w = this.w; var delayFactor = 0; if (w.config.chart.animations.animateGradually.enabled) { delayFactor = w.config.chart.animations.animateGradually.delay; } if (w.config.chart.animations.dynamicAnimation.enabled && w.globals.dataChanged && w.config.chart.type !== 'bar') { // disabled due to this bug - https://github.com/apexcharts/vue-apexcharts/issues/75 delayFactor = 0; } me.morphSVG(el, realIndex, j, w.config.chart.type === 'line' && !w.globals.comboCharts ? 'stroke' : fill, pathFrom, pathTo, speed, delay * delayFactor); } }, { key: "showDelayedElements", value: function showDelayedElements() { this.w.globals.delayedElements.forEach(function (d) { var ele = d.el; ele.classList.remove('apexcharts-element-hidden'); ele.classList.add('apexcharts-hidden-element-shown'); }); } }, { key: "animationCompleted", value: function animationCompleted(el) { var w = this.w; if (w.globals.animationEnded) return; w.globals.animationEnded = true; this.showDelayedElements(); if (typeof w.config.chart.events.animationEnd === 'function') { w.config.chart.events.animationEnd(this.ctx, { el: el, w: w }); } } // SVG.js animation for morphing one path to another }, { key: "morphSVG", value: function morphSVG(el, realIndex, j, fill, pathFrom, pathTo, speed, delay) { var _this = this; var w = this.w; if (!pathFrom) { pathFrom = el.attr('pathFrom'); } if (!pathTo) { pathTo = el.attr('pathTo'); } var disableAnimationForCorrupPath = function disableAnimationForCorrupPath(path) { if (w.config.chart.type === 'radar') { // radar chart drops the path to bottom and hence a corrup path looks ugly // therefore, disable animation for such a case speed = 1; } return "M 0 ".concat(w.globals.gridHeight); }; if (!pathFrom || pathFrom.indexOf('undefined') > -1 || pathFrom.indexOf('NaN') > -1) { pathFrom = disableAnimationForCorrupPath(); } if (!pathTo.trim() || pathTo.indexOf('undefined') > -1 || pathTo.indexOf('NaN') > -1) { pathTo = disableAnimationForCorrupPath(); } if (!w.globals.shouldAnimate) { speed = 1; } el.plot(pathFrom).animate(1, delay).plot(pathFrom).animate(speed, delay).plot(pathTo).after(function () { // a flag to indicate that the original mount function can return true now as animation finished here if (Utils$1.isNumber(j)) { if (j === w.globals.series[w.globals.maxValsInArrayIndex].length - 2 && w.globals.shouldAnimate) { _this.animationCompleted(el); } } else if (fill !== 'none' && w.globals.shouldAnimate) { if (!w.globals.comboCharts && realIndex === w.globals.series.length - 1 || w.globals.comboCharts) { _this.animationCompleted(el); } } _this.showDelayedElements(); }); } }]); return Animations; }(); const methods$1 = {}; const names = []; function registerMethods(name, m) { if (Array.isArray(name)) { for (const _name of name) { registerMethods(_name, m); } return } if (typeof name === 'object') { for (const _name in name) { registerMethods(_name, name[_name]); } return } addMethodNames(Object.getOwnPropertyNames(m)); methods$1[name] = Object.assign(methods$1[name] || {}, m); } function getMethodsFor(name) { return methods$1[name] || {} } function getMethodNames() { return [...new Set(names)] } function addMethodNames(_names) { names.push(..._names); } // Map function function map(array, block) { let i; const il = array.length; const result = []; for (i = 0; i < il; i++) { result.push(block(array[i])); } return result } // Filter function function filter(array, block) { let i; const il = array.length; const result = []; for (i = 0; i < il; i++) { if (block(array[i])) { result.push(array[i]); } } return result } // Degrees to radians function radians(d) { return ((d % 360) * Math.PI) / 180 } // Convert camel cased string to dash separated function unCamelCase(s) { return s.replace(/([A-Z])/g, function (m, g) { return '-' + g.toLowerCase() }) } // Capitalize first letter of a string function capitalize(s) { return s.charAt(0).toUpperCase() + s.slice(1) } // Calculate proportional width and height values when necessary function proportionalSize(element, width, height, box) { if (width == null || height == null) { box = box || element.bbox(); if (width == null) { width = (box.width / box.height) * height; } else if (height == null) { height = (box.height / box.width) * width; } } return { width: width, height: height } } /** * This function adds support for string origins. * It searches for an origin in o.origin o.ox and o.originX. * This way, origin: {x: 'center', y: 50} can be passed as well as ox: 'center', oy: 50 **/ function getOrigin(o, element) { const origin = o.origin; // First check if origin is in ox or originX let ox = o.ox != null ? o.ox : o.originX != null ? o.originX : 'center'; let oy = o.oy != null ? o.oy : o.originY != null ? o.originY : 'center'; // Then check if origin was used and overwrite in that case if (origin != null) { [ox, oy] = Array.isArray(origin) ? origin : typeof origin === 'object' ? [origin.x, origin.y] : [origin, origin]; } // Make sure to only call bbox when actually needed const condX = typeof ox === 'string'; const condY = typeof oy === 'string'; if (condX || condY) { const { height, width, x, y } = element.bbox(); // And only overwrite if string was passed for this specific axis if (condX) { ox = ox.includes('left') ? x : ox.includes('right') ? x + width : x + width / 2; } if (condY) { oy = oy.includes('top') ? y : oy.includes('bottom') ? y + height : y + height / 2; } } // Return the origin as it is if it wasn't a string return [ox, oy] } const descriptiveElements = new Set(['desc', 'metadata', 'title']); const isDescriptive = (element) => descriptiveElements.has(element.nodeName); const writeDataToDom = (element, data, defaults = {}) => { const cloned = { ...data }; for (const key in cloned) { if (cloned[key].valueOf() === defaults[key]) { delete cloned[key]; } } if (Object.keys(cloned).length) { element.node.setAttribute('data-svgjs', JSON.stringify(cloned)); // see #428 } else { element.node.removeAttribute('data-svgjs'); element.node.removeAttribute('svgjs:data'); } }; // Default namespaces const svg = 'http://www.w3.org/2000/svg'; const html = 'http://www.w3.org/1999/xhtml'; const xmlns = 'http://www.w3.org/2000/xmlns/'; const xlink = 'http://www.w3.org/1999/xlink'; const globals = { window: typeof window === 'undefined' ? null : window, document: typeof document === 'undefined' ? null : document }; function getWindow() { return globals.window } let Base$1 = class Base { // constructor (node/*, {extensions = []} */) { // // this.tags = [] // // // // for (let extension of extensions) { // // extension.setup.call(this, node) // // this.tags.push(extension.name) // // } // } }; const elements = {}; const root = '___SYMBOL___ROOT___'; // Method for element creation function create(name, ns = svg) { // create element return globals.document.createElementNS(ns, name) } function makeInstance(element, isHTML = false) { if (element instanceof Base$1) return element if (typeof element === 'object') { return adopter(element) } if (element == null) { return new elements[root]() } if (typeof element === 'string' && element.charAt(0) !== '<') { return adopter(globals.document.querySelector(element)) } // Make sure, that HTML elements are created with the correct namespace const wrapper = isHTML ? globals.document.createElement('div') : create('svg'); wrapper.innerHTML = element; // We can use firstChild here because we know, // that the first char is < and thus an element element = adopter(wrapper.firstChild); // make sure, that element doesn't have its wrapper attached wrapper.removeChild(wrapper.firstChild); return element } function nodeOrNew(name, node) { return node && (node instanceof globals.window.Node || (node.ownerDocument && node instanceof node.ownerDocument.defaultView.Node)) ? node : create(name) } // Adopt existing svg elements function adopt(node) { // check for presence of node if (!node) return null // make sure a node isn't already adopted if (node.instance instanceof Base$1) return node.instance if (node.nodeName === '#document-fragment') { return new elements.Fragment(node) } // initialize variables let className = capitalize(node.nodeName || 'Dom'); // Make sure that gradients are adopted correctly if (className === 'LinearGradient' || className === 'RadialGradient') { className = 'Gradient'; // Fallback to Dom if element is not known } else if (!elements[className]) { className = 'Dom'; } return new elements[className](node) } let adopter = adopt; function register(element, name = element.name, asRoot = false) { elements[name] = element; if (asRoot) elements[root] = element; addMethodNames(Object.getOwnPropertyNames(element.prototype)); return element } function getClass(name) { return elements[name] } // Element id sequence let did = 1000; // Get next named element id function eid(name) { return 'Svgjs' + capitalize(name) + did++ } // Deep new id assignment function assignNewId(node) { // do the same for SVG child nodes as well for (let i = node.children.length - 1; i >= 0; i--) { assignNewId(node.children[i]); } if (node.id) { node.id = eid(node.nodeName); return node } return node } // Method for extending objects function extend(modules, methods) { let key, i; modules = Array.isArray(modules) ? modules : [modules]; for (i = modules.length - 1; i >= 0; i--) { for (key in methods) { modules[i].prototype[key] = methods[key]; } } } function wrapWithAttrCheck(fn) { return function (...args) { const o = args[args.length - 1]; if (o && o.constructor === Object && !(o instanceof Array)) { return fn.apply(this, args.slice(0, -1)).attr(o) } else { return fn.apply(this, args) } } } // Get all siblings, including myself function siblings() { return this.parent().children() } // Get the current position siblings function position() { return this.parent().index(this) } // Get the next element (will return null if there is none) function next() { return this.siblings()[this.position() + 1] } // Get the next element (will return null if there is none) function prev() { return this.siblings()[this.position() - 1] } // Send given element one step forward function forward() { const i = this.position(); const p = this.parent(); // move node one step forward p.add(this.remove(), i + 1); return this } // Send given element one step backward function backward() { const i = this.position(); const p = this.parent(); p.add(this.remove(), i ? i - 1 : 0); return this } // Send given element all the way to the front function front() { const p = this.parent(); // Move node forward p.add(this.remove()); return this } // Send given element all the way to the back function back() { const p = this.parent(); // Move node back p.add(this.remove(), 0); return this } // Inserts a given element before the targeted element function before(element) { element = makeInstance(element); element.remove(); const i = this.position(); this.parent().add(element, i); return this } // Inserts a given element after the targeted element function after(element) { element = makeInstance(element); element.remove(); const i = this.position(); this.parent().add(element, i + 1); return this } function insertBefore(element) { element = makeInstance(element); element.before(this); return this } function insertAfter(element) { element = makeInstance(element); element.after(this); return this } registerMethods('Dom', { siblings, position, next, prev, forward, backward, front, back, before, after, insertBefore, insertAfter }); // Parse unit value const numberAndUnit = /^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i; // Parse hex value const hex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i; // Parse rgb value const rgb = /rgb\((\d+),(\d+),(\d+)\)/; // Parse reference id const reference = /(#[a-z_][a-z0-9\-_]*)/i; // splits a transformation chain const transforms = /\)\s*,?\s*/; // Whitespace const whitespace = /\s/g; // Test hex value const isHex = /^#[a-f0-9]{3}$|^#[a-f0-9]{6}$/i; // Test rgb value const isRgb = /^rgb\(/; // Test for blank string const isBlank = /^(\s+)?$/; // Test for numeric string const isNumber = /^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i; // Test for image url const isImage = /\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i; // split at whitespace and comma const delimiter = /[\s,]+/; // Test for path letter const isPathLetter = /[MLHVCSQTAZ]/i; // Return array of classes on the node function classes() { const attr = this.attr('class'); return attr == null ? [] : attr.trim().split(delimiter) } // Return true if class exists on the node, false otherwise function hasClass(name) { return this.classes().indexOf(name) !== -1 } // Add class to the node function addClass(name) { if (!this.hasClass(name)) { const array = this.classes(); array.push(name); this.attr('class', array.join(' ')); } return this } // Remove class from the node function removeClass(name) { if (this.hasClass(name)) { this.attr( 'class', this.classes() .filter(function (c) { return c !== name }) .join(' ') ); } return this } // Toggle the presence of a class on the node function toggleClass(name) { return this.hasClass(name) ? this.removeClass(name) : this.addClass(name) } registerMethods('Dom', { classes, hasClass, addClass, removeClass, toggleClass }); // Dynamic style generator function css(style, val) { const ret = {}; if (arguments.length === 0) { // get full style as object this.node.style.cssText .split(/\s*;\s*/) .filter(function (el) { return !!el.length }) .forEach(function (el) { const t = el.split(/\s*:\s*/); ret[t[0]] = t[1]; }); return ret } if (arguments.length < 2) { // get style properties as array if (Array.isArray(style)) { for (const name of style) { const cased = name; ret[name] = this.node.style.getPropertyValue(cased); } return ret } // get style for property if (typeof style === 'string') { return this.node.style.getPropertyValue(style) } // set styles in object if (typeof style === 'object') { for (const name in style) { // set empty string if null/undefined/'' was given this.node.style.setProperty( name, style[name] == null || isBlank.test(style[name]) ? '' : style[name] ); } } } // set style for property if (arguments.length === 2) { this.node.style.setProperty( style, val == null || isBlank.test(val) ? '' : val ); } return this } // Show element function show() { return this.css('display', '') } // Hide element function hide() { return this.css('display', 'none') } // Is element visible? function visible() { return this.css('display') !== 'none' } registerMethods('Dom', { css, show, hide, visible }); // Store data values on svg nodes function data(a, v, r) { if (a == null) { // get an object of attributes return this.data( map( filter( this.node.attributes, (el) => el.nodeName.indexOf('data-') === 0 ), (el) => el.nodeName.slice(5) ) ) } else if (a instanceof Array) { const data = {}; for (const key of a) { data[key] = this.data(key); } return data } else if (typeof a === 'object') { for (v in a) { this.data(v, a[v]); } } else if (arguments.length < 2) { try { return JSON.parse(this.attr('data-' + a)) } catch (e) { return this.attr('data-' + a) } } else { this.attr( 'data-' + a, v === null ? null : r === true || typeof v === 'string' || typeof v === 'number' ? v : JSON.stringify(v) ); } return this } registerMethods('Dom', { data }); // Remember arbitrary data function remember(k, v) { // remember every item in an object individually if (typeof arguments[0] === 'object') { for (const key in k) { this.remember(key, k[key]); } } else if (arguments.length === 1) { // retrieve memory return this.memory()[k] } else { // store memory this.memory()[k] = v; } return this } // Erase a given memory function forget() { if (arguments.length === 0) { this._memory = {}; } else { for (let i = arguments.length - 1; i >= 0; i--) { delete this.memory()[arguments[i]]; } } return this } // This triggers creation of a new hidden class which is not performant // However, this function is not rarely used so it will not happen frequently // Return local memory object function memory() { return (this._memory = this._memory || {}) } registerMethods('Dom', { remember, forget, memory }); function sixDigitHex(hex) { return hex.length === 4 ? [ '#', hex.substring(1, 2), hex.substring(1, 2), hex.substring(2, 3), hex.substring(2, 3), hex.substring(3, 4), hex.substring(3, 4) ].join('') : hex } function componentHex(component) { const integer = Math.round(component); const bounded = Math.max(0, Math.min(255, integer)); const hex = bounded.toString(16); return hex.length === 1 ? '0' + hex : hex } function is(object, space) { for (let i = space.length; i--; ) { if (object[space[i]] == null) { return false } } return true } function getParameters(a, b) { const params = is(a, 'rgb') ? { _a: a.r, _b: a.g, _c: a.b, _d: 0, space: 'rgb' } : is(a, 'xyz') ? { _a: a.x, _b: a.y, _c: a.z, _d: 0, space: 'xyz' } : is(a, 'hsl') ? { _a: a.h, _b: a.s, _c: a.l, _d: 0, space: 'hsl' } : is(a, 'lab') ? { _a: a.l, _b: a.a, _c: a.b, _d: 0, space: 'lab' } : is(a, 'lch') ? { _a: a.l, _b: a.c, _c: a.h, _d: 0, space: 'lch' } : is(a, 'cmyk') ? { _a: a.c, _b: a.m, _c: a.y, _d: a.k, space: 'cmyk' } : { _a: 0, _b: 0, _c: 0, space: 'rgb' }; params.space = b || params.space; return params } function cieSpace(space) { if (space === 'lab' || space === 'xyz' || space === 'lch') { return true } else { return false } } function hueToRgb(p, q, t) { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t if (t < 1 / 2) return q if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6 return p } class Color { constructor(...inputs) { this.init(...inputs); } // Test if given value is a color static isColor(color) { return ( color && (color instanceof Color || this.isRgb(color) || this.test(color)) ) } // Test if given value is an rgb object static isRgb(color) { return ( color && typeof color.r === 'number' && typeof color.g === 'number' && typeof color.b === 'number' ) } /* Generating random colors */ static random(mode = 'vibrant', t) { // Get the math modules const { random, round, sin, PI: pi } = Math; // Run the correct generator if (mode === 'vibrant') { const l = (81 - 57) * random() + 57; const c = (83 - 45) * random() + 45; const h = 360 * random(); const color = new Color(l, c, h, 'lch'); return color } else if (mode === 'sine') { t = t == null ? random() : t; const r = round(80 * sin((2 * pi * t) / 0.5 + 0.01) + 150); const g = round(50 * sin((2 * pi * t) / 0.5 + 4.6) + 200); const b = round(100 * sin((2 * pi * t) / 0.5 + 2.3) + 150); const color = new Color(r, g, b); return color } else if (mode === 'pastel') { const l = (94 - 86) * random() + 86; const c = (26 - 9) * random() + 9; const h = 360 * random(); const color = new Color(l, c, h, 'lch'); return color } else if (mode === 'dark') { const l = 10 + 10 * random(); const c = (125 - 75) * random() + 86; const h = 360 * random(); const color = new Color(l, c, h, 'lch'); return color } else if (mode === 'rgb') { const r = 255 * random(); const g = 255 * random(); const b = 255 * random(); const color = new Color(r, g, b); return color } else if (mode === 'lab') { const l = 100 * random(); const a = 256 * random() - 128; const b = 256 * random() - 128; const color = new Color(l, a, b, 'lab'); return color } else if (mode === 'grey') { const grey = 255 * random(); const color = new Color(grey, grey, grey); return color } else { throw new Error('Unsupported random color mode') } } // Test if given value is a color string static test(color) { return typeof color === 'string' && (isHex.test(color) || isRgb.test(color)) } cmyk() { // Get the rgb values for the current color const { _a, _b, _c } = this.rgb(); const [r, g, b] = [_a, _b, _c].map((v) => v / 255); // Get the cmyk values in an unbounded format const k = Math.min(1 - r, 1 - g, 1 - b); if (k === 1) { // Catch the black case return new Color(0, 0, 0, 1, 'cmyk') } const c = (1 - r - k) / (1 - k); const m = (1 - g - k) / (1 - k); const y = (1 - b - k) / (1 - k); // Construct the new color const color = new Color(c, m, y, k, 'cmyk'); return color } hsl() { // Get the rgb values const { _a, _b, _c } = this.rgb(); const [r, g, b] = [_a, _b, _c].map((v) => v / 255); // Find the maximum and minimum values to get the lightness const max = Math.max(r, g, b); const min = Math.min(r, g, b); const l = (max + min) / 2; // If the r, g, v values are identical then we are grey const isGrey = max === min; // Calculate the hue and saturation const delta = max - min; const s = isGrey ? 0 : l > 0.5 ? delta / (2 - max - min) : delta / (max + min); const h = isGrey ? 0 : max === r ? ((g - b) / delta + (g < b ? 6 : 0)) / 6 : max === g ? ((b - r) / delta + 2) / 6 : max === b ? ((r - g) / delta + 4) / 6 : 0; // Construct and return the new color const color = new Color(360 * h, 100 * s, 100 * l, 'hsl'); return color } init(a = 0, b = 0, c = 0, d = 0, space = 'rgb') { // This catches the case when a falsy value is passed like '' a = !a ? 0 : a; // Reset all values in case the init function is rerun with new color space if (this.space) { for (const component in this.space) { delete this[this.space[component]]; } } if (typeof a === 'number') { // Allow for the case that we don't need d... space = typeof d === 'string' ? d : space; d = typeof d === 'string' ? 0 : d; // Assign the values straight to the color Object.assign(this, { _a: a, _b: b, _c: c, _d: d, space }); // If the user gav