From 670c71104e6f60c0e08b4f9f30db325939069a48 Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Wed, 26 Nov 2025 22:28:05 +1100 Subject: [PATCH 1/6] Add a chart to the web-site performance data --- src/site/CMakeLists.txt | 9 + src/site/echarts.js | 57475 +++++++++++++++++ src/site/generate_appending_a_log_message.js | 119 + src/site/markdown/performance.md | 19 +- src/site/test_echarts.html | 15 + src/site/test_echarts.js | 36 + 6 files changed, 57668 insertions(+), 5 deletions(-) create mode 100644 src/site/echarts.js create mode 100644 src/site/generate_appending_a_log_message.js create mode 100644 src/site/test_echarts.html create mode 100644 src/site/test_echarts.js diff --git a/src/site/CMakeLists.txt b/src/site/CMakeLists.txt index 25aef6bbd..07888695f 100644 --- a/src/site/CMakeLists.txt +++ b/src/site/CMakeLists.txt @@ -54,6 +54,15 @@ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/markdown/download.md.in configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/markdown/development/build-cmake.md.in ${CMAKE_CURRENT_BINARY_DIR}/markdown/development/build-cmake.md ) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/echarts.js + ${CMAKE_CURRENT_BINARY_DIR}/html/echarts.js + COPYONLY +) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/generate_appending_a_log_message.js + ${CMAKE_CURRENT_BINARY_DIR}/html/generate_appending_a_log_message.js + COPYONLY +) + add_custom_target( doc_doxygen ALL COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${LOG4CXX_SOURCE_DIR} diff --git a/src/site/echarts.js b/src/site/echarts.js new file mode 100644 index 000000000..24f0ba3b8 --- /dev/null +++ b/src/site/echarts.js @@ -0,0 +1,57475 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.echarts = {})); +})(this, function (exports) { + 'use strict'; + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + ***************************************************************************** */ + + /* global Reflect, Promise */ + + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || { + __proto__: [] + } instanceof Array && function (d, b) { + d.__proto__ = b; + } || function (d, b) { + for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; + }; + + return extendStatics(d, b); + }; + + function __extends(d, b) { + if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + + function __() { + this.constructor = d; + } + + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + } + + var Browser = function () { + function Browser() { + this.firefox = false; + this.ie = false; + this.edge = false; + this.newEdge = false; + this.weChat = false; + } + + return Browser; + }(); + + var Env = function () { + function Env() { + this.browser = new Browser(); + this.node = false; + this.wxa = false; + this.worker = false; + this.svgSupported = false; + this.touchEventsSupported = false; + this.pointerEventsSupported = false; + this.domSupported = false; + this.transformSupported = false; + this.transform3dSupported = false; + this.hasGlobalWindow = typeof window !== 'undefined'; + } + + return Env; + }(); + + var env = new Env(); + + if (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') { + env.wxa = true; + env.touchEventsSupported = true; + } else if (typeof document === 'undefined' && typeof self !== 'undefined') { + env.worker = true; + } else if (!env.hasGlobalWindow || 'Deno' in window || typeof navigator !== 'undefined' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Node.js') > -1) { + env.node = true; + env.svgSupported = true; + } else { + detect(navigator.userAgent, env); + } + + function detect(ua, env) { + var browser = env.browser; + var firefox = ua.match(/Firefox\/([\d.]+)/); + var ie = ua.match(/MSIE\s([\d.]+)/) || ua.match(/Trident\/.+?rv:(([\d.]+))/); + var edge = ua.match(/Edge?\/([\d.]+)/); + var weChat = /micromessenger/i.test(ua); + + if (firefox) { + browser.firefox = true; + browser.version = firefox[1]; + } + + if (ie) { + browser.ie = true; + browser.version = ie[1]; + } + + if (edge) { + browser.edge = true; + browser.version = edge[1]; + browser.newEdge = +edge[1].split('.')[0] > 18; + } + + if (weChat) { + browser.weChat = true; + } + + env.svgSupported = typeof SVGRect !== 'undefined'; + env.touchEventsSupported = 'ontouchstart' in window && !browser.ie && !browser.edge; + env.pointerEventsSupported = 'onpointerdown' in window && (browser.edge || browser.ie && +browser.version >= 11); + var domSupported = env.domSupported = typeof document !== 'undefined'; + + if (domSupported) { + var style = document.documentElement.style; + env.transform3dSupported = (browser.ie && 'transition' in style || browser.edge || 'WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix() || 'MozPerspective' in style) && !('OTransition' in style); + env.transformSupported = env.transform3dSupported || browser.ie && +browser.version >= 9; + } + } + + var DEFAULT_FONT_SIZE = 12; + var DEFAULT_FONT_FAMILY = 'sans-serif'; + var DEFAULT_FONT = DEFAULT_FONT_SIZE + "px " + DEFAULT_FONT_FAMILY; + var OFFSET = 20; + var SCALE = 100; + var defaultWidthMapStr = "007LLmW'55;N0500LLLLLLLLLL00NNNLzWW\\\\WQb\\0FWLg\\bWb\\WQ\\WrWWQ000CL5LLFLL0LL**F*gLLLL5F0LF\\FFF5.5N"; + + function getTextWidthMap(mapStr) { + var map = {}; + + if (typeof JSON === 'undefined') { + return map; + } + + for (var i = 0; i < mapStr.length; i++) { + var char = String.fromCharCode(i + 32); + var size = (mapStr.charCodeAt(i) - OFFSET) / SCALE; + map[char] = size; + } + + return map; + } + + var DEFAULT_TEXT_WIDTH_MAP = getTextWidthMap(defaultWidthMapStr); + var platformApi = { + createCanvas: function () { + return typeof document !== 'undefined' && document.createElement('canvas'); + }, + measureText: function () { + var _ctx; + + var _cachedFont; + + return function (text, font) { + if (!_ctx) { + var canvas = platformApi.createCanvas(); + _ctx = canvas && canvas.getContext('2d'); + } + + if (_ctx) { + if (_cachedFont !== font) { + _cachedFont = _ctx.font = font || DEFAULT_FONT; + } + + return _ctx.measureText(text); + } else { + text = text || ''; + font = font || DEFAULT_FONT; + var res = /((?:\d+)?\.?\d*)px/.exec(font); + var fontSize = res && +res[1] || DEFAULT_FONT_SIZE; + var width = 0; + + if (font.indexOf('mono') >= 0) { + width = fontSize * text.length; + } else { + for (var i = 0; i < text.length; i++) { + var preCalcWidth = DEFAULT_TEXT_WIDTH_MAP[text[i]]; + width += preCalcWidth == null ? fontSize : preCalcWidth * fontSize; + } + } + + return { + width: width + }; + } + }; + }(), + loadImage: function (src, onload, onerror) { + var image = new Image(); + image.onload = onload; + image.onerror = onerror; + image.src = src; + return image; + } + }; + + function setPlatformAPI(newPlatformApis) { + for (var key in platformApi) { + if (newPlatformApis[key]) { + platformApi[key] = newPlatformApis[key]; + } + } + } + + var BUILTIN_OBJECT = reduce(['Function', 'RegExp', 'Date', 'Error', 'CanvasGradient', 'CanvasPattern', 'Image', 'Canvas'], function (obj, val) { + obj['[object ' + val + ']'] = true; + return obj; + }, {}); + var TYPED_ARRAY = reduce(['Int8', 'Uint8', 'Uint8Clamped', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Float32', 'Float64'], function (obj, val) { + obj['[object ' + val + 'Array]'] = true; + return obj; + }, {}); + var objToString = Object.prototype.toString; + var arrayProto = Array.prototype; + var nativeForEach = arrayProto.forEach; + var nativeFilter = arrayProto.filter; + var nativeSlice = arrayProto.slice; + var nativeMap = arrayProto.map; + + var ctorFunction = function () {}.constructor; + + var protoFunction = ctorFunction ? ctorFunction.prototype : null; + var protoKey = '__proto__'; + var idStart = 0x0907; + + function guid() { + return idStart++; + } + + function logError() { + var args = []; + + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + + if (typeof console !== 'undefined') { + console.error.apply(console, args); + } + } + + function clone$3(source) { + if (source == null || typeof source !== 'object') { + return source; + } + + var result = source; + var typeStr = objToString.call(source); + + if (typeStr === '[object Array]') { + if (!isPrimitive(source)) { + result = []; + + for (var i = 0, len = source.length; i < len; i++) { + result[i] = clone$3(source[i]); + } + } + } else if (TYPED_ARRAY[typeStr]) { + if (!isPrimitive(source)) { + var Ctor = source.constructor; + + if (Ctor.from) { + result = Ctor.from(source); + } else { + result = new Ctor(source.length); + + for (var i = 0, len = source.length; i < len; i++) { + result[i] = source[i]; + } + } + } + } else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) { + result = {}; + + for (var key in source) { + if (source.hasOwnProperty(key) && key !== protoKey) { + result[key] = clone$3(source[key]); + } + } + } + + return result; + } + + function merge(target, source, overwrite) { + if (!isObject$2(source) || !isObject$2(target)) { + return overwrite ? clone$3(source) : target; + } + + for (var key in source) { + if (source.hasOwnProperty(key) && key !== protoKey) { + var targetProp = target[key]; + var sourceProp = source[key]; + + if (isObject$2(sourceProp) && isObject$2(targetProp) && !isArray(sourceProp) && !isArray(targetProp) && !isDom(sourceProp) && !isDom(targetProp) && !isBuiltInObject(sourceProp) && !isBuiltInObject(targetProp) && !isPrimitive(sourceProp) && !isPrimitive(targetProp)) { + merge(targetProp, sourceProp, overwrite); + } else if (overwrite || !(key in target)) { + target[key] = clone$3(source[key]); + } + } + } + + return target; + } + + function mergeAll(targetAndSources, overwrite) { + var result = targetAndSources[0]; + + for (var i = 1, len = targetAndSources.length; i < len; i++) { + result = merge(result, targetAndSources[i], overwrite); + } + + return result; + } + + function extend(target, source) { + if (Object.assign) { + Object.assign(target, source); + } else { + for (var key in source) { + if (source.hasOwnProperty(key) && key !== protoKey) { + target[key] = source[key]; + } + } + } + + return target; + } + + function defaults(target, source, overlay) { + var keysArr = keys(source); + + for (var i = 0, len = keysArr.length; i < len; i++) { + var key = keysArr[i]; + + if (overlay ? source[key] != null : target[key] == null) { + target[key] = source[key]; + } + } + + return target; + } + + var createCanvas = platformApi.createCanvas; + + function indexOf(array, value) { + if (array) { + if (array.indexOf) { + return array.indexOf(value); + } + + for (var i = 0, len = array.length; i < len; i++) { + if (array[i] === value) { + return i; + } + } + } + + return -1; + } + + function inherits(clazz, baseClazz) { + var clazzPrototype = clazz.prototype; + + function F() {} + + F.prototype = baseClazz.prototype; + clazz.prototype = new F(); + + for (var prop in clazzPrototype) { + if (clazzPrototype.hasOwnProperty(prop)) { + clazz.prototype[prop] = clazzPrototype[prop]; + } + } + + clazz.prototype.constructor = clazz; + clazz.superClass = baseClazz; + } + + function mixin(target, source, override) { + target = 'prototype' in target ? target.prototype : target; + source = 'prototype' in source ? source.prototype : source; + + if (Object.getOwnPropertyNames) { + var keyList = Object.getOwnPropertyNames(source); + + for (var i = 0; i < keyList.length; i++) { + var key = keyList[i]; + + if (key !== 'constructor') { + if (override ? source[key] != null : target[key] == null) { + target[key] = source[key]; + } + } + } + } else { + defaults(target, source, override); + } + } + + function isArrayLike(data) { + if (!data) { + return false; + } + + if (typeof data === 'string') { + return false; + } + + return typeof data.length === 'number'; + } + + function each$4(arr, cb, context) { + if (!(arr && cb)) { + return; + } + + if (arr.forEach && arr.forEach === nativeForEach) { + arr.forEach(cb, context); + } else if (arr.length === +arr.length) { + for (var i = 0, len = arr.length; i < len; i++) { + cb.call(context, arr[i], i, arr); + } + } else { + for (var key in arr) { + if (arr.hasOwnProperty(key)) { + cb.call(context, arr[key], key, arr); + } + } + } + } + + function map$1(arr, cb, context) { + if (!arr) { + return []; + } + + if (!cb) { + return slice(arr); + } + + if (arr.map && arr.map === nativeMap) { + return arr.map(cb, context); + } else { + var result = []; + + for (var i = 0, len = arr.length; i < len; i++) { + result.push(cb.call(context, arr[i], i, arr)); + } + + return result; + } + } + + function reduce(arr, cb, memo, context) { + if (!(arr && cb)) { + return; + } + + for (var i = 0, len = arr.length; i < len; i++) { + memo = cb.call(context, memo, arr[i], i, arr); + } + + return memo; + } + + function filter(arr, cb, context) { + if (!arr) { + return []; + } + + if (!cb) { + return slice(arr); + } + + if (arr.filter && arr.filter === nativeFilter) { + return arr.filter(cb, context); + } else { + var result = []; + + for (var i = 0, len = arr.length; i < len; i++) { + if (cb.call(context, arr[i], i, arr)) { + result.push(arr[i]); + } + } + + return result; + } + } + + function find(arr, cb, context) { + if (!(arr && cb)) { + return; + } + + for (var i = 0, len = arr.length; i < len; i++) { + if (cb.call(context, arr[i], i, arr)) { + return arr[i]; + } + } + } + + function keys(obj) { + if (!obj) { + return []; + } + + if (Object.keys) { + return Object.keys(obj); + } + + var keyList = []; + + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + keyList.push(key); + } + } + + return keyList; + } + + function bindPolyfill(func, context) { + var args = []; + + for (var _i = 2; _i < arguments.length; _i++) { + args[_i - 2] = arguments[_i]; + } + + return function () { + return func.apply(context, args.concat(nativeSlice.call(arguments))); + }; + } + + var bind$1 = protoFunction && isFunction(protoFunction.bind) ? protoFunction.call.bind(protoFunction.bind) : bindPolyfill; + + function curry$1(func) { + var args = []; + + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + + return function () { + return func.apply(this, args.concat(nativeSlice.call(arguments))); + }; + } + + function isArray(value) { + if (Array.isArray) { + return Array.isArray(value); + } + + return objToString.call(value) === '[object Array]'; + } + + function isFunction(value) { + return typeof value === 'function'; + } + + function isString(value) { + return typeof value === 'string'; + } + + function isStringSafe(value) { + return objToString.call(value) === '[object String]'; + } + + function isNumber(value) { + return typeof value === 'number'; + } + + function isObject$2(value) { + var type = typeof value; + return type === 'function' || !!value && type === 'object'; + } + + function isBuiltInObject(value) { + return !!BUILTIN_OBJECT[objToString.call(value)]; + } + + function isTypedArray(value) { + return !!TYPED_ARRAY[objToString.call(value)]; + } + + function isDom(value) { + return typeof value === 'object' && typeof value.nodeType === 'number' && typeof value.ownerDocument === 'object'; + } + + function isGradientObject(value) { + return value.colorStops != null; + } + + function isImagePatternObject(value) { + return value.image != null; + } + + function isRegExp(value) { + return objToString.call(value) === '[object RegExp]'; + } + + function eqNaN(value) { + return value !== value; + } + + function retrieve() { + var args = []; + + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + + for (var i = 0, len = args.length; i < len; i++) { + if (args[i] != null) { + return args[i]; + } + } + } + + function retrieve2(value0, value1) { + return value0 != null ? value0 : value1; + } + + function retrieve3(value0, value1, value2) { + return value0 != null ? value0 : value1 != null ? value1 : value2; + } + + function slice(arr) { + var args = []; + + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + + return nativeSlice.apply(arr, args); + } + + function normalizeCssArray$1(val) { + if (typeof val === 'number') { + return [val, val, val, val]; + } + + var len = val.length; + + if (len === 2) { + return [val[0], val[1], val[0], val[1]]; + } else if (len === 3) { + return [val[0], val[1], val[2], val[1]]; + } + + return val; + } + + function assert(condition, message) { + if (!condition) { + throw new Error(message); + } + } + + function trim(str) { + if (str == null) { + return null; + } else if (typeof str.trim === 'function') { + return str.trim(); + } else { + return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); + } + } + + var primitiveKey = '__ec_primitive__'; + + function setAsPrimitive(obj) { + obj[primitiveKey] = true; + } + + function isPrimitive(obj) { + return obj[primitiveKey]; + } + + var MapPolyfill = function () { + function MapPolyfill() { + this.data = {}; + } + + MapPolyfill.prototype["delete"] = function (key) { + var existed = this.has(key); + + if (existed) { + delete this.data[key]; + } + + return existed; + }; + + MapPolyfill.prototype.has = function (key) { + return this.data.hasOwnProperty(key); + }; + + MapPolyfill.prototype.get = function (key) { + return this.data[key]; + }; + + MapPolyfill.prototype.set = function (key, value) { + this.data[key] = value; + return this; + }; + + MapPolyfill.prototype.keys = function () { + return keys(this.data); + }; + + MapPolyfill.prototype.forEach = function (callback) { + var data = this.data; + + for (var key in data) { + if (data.hasOwnProperty(key)) { + callback(data[key], key); + } + } + }; + + return MapPolyfill; + }(); + + var isNativeMapSupported = typeof Map === 'function'; + + function maybeNativeMap() { + return isNativeMapSupported ? new Map() : new MapPolyfill(); + } + + var HashMap = function () { + function HashMap(obj) { + var isArr = isArray(obj); + this.data = maybeNativeMap(); + var thisMap = this; + obj instanceof HashMap ? obj.each(visit) : obj && each$4(obj, visit); + + function visit(value, key) { + isArr ? thisMap.set(value, key) : thisMap.set(key, value); + } + } + + HashMap.prototype.hasKey = function (key) { + return this.data.has(key); + }; + + HashMap.prototype.get = function (key) { + return this.data.get(key); + }; + + HashMap.prototype.set = function (key, value) { + this.data.set(key, value); + return value; + }; + + HashMap.prototype.each = function (cb, context) { + this.data.forEach(function (value, key) { + cb.call(context, value, key); + }); + }; + + HashMap.prototype.keys = function () { + var keys = this.data.keys(); + return isNativeMapSupported ? Array.from(keys) : keys; + }; + + HashMap.prototype.removeKey = function (key) { + this.data["delete"](key); + }; + + return HashMap; + }(); + + function createHashMap(obj) { + return new HashMap(obj); + } + + function concatArray(a, b) { + var newArray = new a.constructor(a.length + b.length); + + for (var i = 0; i < a.length; i++) { + newArray[i] = a[i]; + } + + var offset = a.length; + + for (var i = 0; i < b.length; i++) { + newArray[i + offset] = b[i]; + } + + return newArray; + } + + function createObject(proto, properties) { + var obj; + + if (Object.create) { + obj = Object.create(proto); + } else { + var StyleCtor = function () {}; + + StyleCtor.prototype = proto; + obj = new StyleCtor(); + } + + if (properties) { + extend(obj, properties); + } + + return obj; + } + + function disableUserSelect(dom) { + var domStyle = dom.style; + domStyle.webkitUserSelect = 'none'; + domStyle.userSelect = 'none'; + domStyle.webkitTapHighlightColor = 'rgba(0,0,0,0)'; + domStyle['-webkit-touch-callout'] = 'none'; + } + + function hasOwn(own, prop) { + return own.hasOwnProperty(prop); + } + + function noop() {} + + var RADIAN_TO_DEGREE = 180 / Math.PI; + var EPSILON$4 = Number.EPSILON || Math.pow(2, -52); + var util$1 = /*#__PURE__*/Object.freeze({ + __proto__: null, + EPSILON: EPSILON$4, + HashMap: HashMap, + RADIAN_TO_DEGREE: RADIAN_TO_DEGREE, + assert: assert, + bind: bind$1, + clone: clone$3, + concatArray: concatArray, + createCanvas: createCanvas, + createHashMap: createHashMap, + createObject: createObject, + curry: curry$1, + defaults: defaults, + disableUserSelect: disableUserSelect, + each: each$4, + eqNaN: eqNaN, + extend: extend, + filter: filter, + find: find, + guid: guid, + hasOwn: hasOwn, + indexOf: indexOf, + inherits: inherits, + isArray: isArray, + isArrayLike: isArrayLike, + isBuiltInObject: isBuiltInObject, + isDom: isDom, + isFunction: isFunction, + isGradientObject: isGradientObject, + isImagePatternObject: isImagePatternObject, + isNumber: isNumber, + isObject: isObject$2, + isPrimitive: isPrimitive, + isRegExp: isRegExp, + isString: isString, + isStringSafe: isStringSafe, + isTypedArray: isTypedArray, + keys: keys, + logError: logError, + map: map$1, + merge: merge, + mergeAll: mergeAll, + mixin: mixin, + noop: noop, + normalizeCssArray: normalizeCssArray$1, + reduce: reduce, + retrieve: retrieve, + retrieve2: retrieve2, + retrieve3: retrieve3, + setAsPrimitive: setAsPrimitive, + slice: slice, + trim: trim + }); + + function create$1(x, y) { + if (x == null) { + x = 0; + } + + if (y == null) { + y = 0; + } + + return [x, y]; + } + + function copy$1(out, v) { + out[0] = v[0]; + out[1] = v[1]; + return out; + } + + function clone$2(v) { + return [v[0], v[1]]; + } + + function set$1(out, a, b) { + out[0] = a; + out[1] = b; + return out; + } + + function add(out, v1, v2) { + out[0] = v1[0] + v2[0]; + out[1] = v1[1] + v2[1]; + return out; + } + + function scaleAndAdd(out, v1, v2, a) { + out[0] = v1[0] + v2[0] * a; + out[1] = v1[1] + v2[1] * a; + return out; + } + + function sub(out, v1, v2) { + out[0] = v1[0] - v2[0]; + out[1] = v1[1] - v2[1]; + return out; + } + + function len(v) { + return Math.sqrt(lenSquare(v)); + } + + var length = len; + + function lenSquare(v) { + return v[0] * v[0] + v[1] * v[1]; + } + + var lengthSquare = lenSquare; + + function mul$1(out, v1, v2) { + out[0] = v1[0] * v2[0]; + out[1] = v1[1] * v2[1]; + return out; + } + + function div(out, v1, v2) { + out[0] = v1[0] / v2[0]; + out[1] = v1[1] / v2[1]; + return out; + } + + function dot(v1, v2) { + return v1[0] * v2[0] + v1[1] * v2[1]; + } + + function scale$2(out, v, s) { + out[0] = v[0] * s; + out[1] = v[1] * s; + return out; + } + + function normalize$1(out, v) { + var d = len(v); + + if (d === 0) { + out[0] = 0; + out[1] = 0; + } else { + out[0] = v[0] / d; + out[1] = v[1] / d; + } + + return out; + } + + function distance(v1, v2) { + return Math.sqrt((v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1])); + } + + var dist$1 = distance; + + function distanceSquare(v1, v2) { + return (v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1]); + } + + var distSquare = distanceSquare; + + function negate(out, v) { + out[0] = -v[0]; + out[1] = -v[1]; + return out; + } + + function lerp$1(out, v1, v2, t) { + out[0] = v1[0] + t * (v2[0] - v1[0]); + out[1] = v1[1] + t * (v2[1] - v1[1]); + return out; + } + + function applyTransform$1(out, v, m) { + var x = v[0]; + var y = v[1]; + out[0] = m[0] * x + m[2] * y + m[4]; + out[1] = m[1] * x + m[3] * y + m[5]; + return out; + } + + function min$1(out, v1, v2) { + out[0] = Math.min(v1[0], v2[0]); + out[1] = Math.min(v1[1], v2[1]); + return out; + } + + function max$1(out, v1, v2) { + out[0] = Math.max(v1[0], v2[0]); + out[1] = Math.max(v1[1], v2[1]); + return out; + } + + var vector = /*#__PURE__*/Object.freeze({ + __proto__: null, + add: add, + applyTransform: applyTransform$1, + clone: clone$2, + copy: copy$1, + create: create$1, + dist: dist$1, + distSquare: distSquare, + distance: distance, + distanceSquare: distanceSquare, + div: div, + dot: dot, + len: len, + lenSquare: lenSquare, + length: length, + lengthSquare: lengthSquare, + lerp: lerp$1, + max: max$1, + min: min$1, + mul: mul$1, + negate: negate, + normalize: normalize$1, + scale: scale$2, + scaleAndAdd: scaleAndAdd, + set: set$1, + sub: sub + }); + + var Param = function () { + function Param(target, e) { + this.target = target; + this.topTarget = e && e.topTarget; + } + + return Param; + }(); + + var Draggable = function () { + function Draggable(handler) { + this.handler = handler; + handler.on('mousedown', this._dragStart, this); + handler.on('mousemove', this._drag, this); + handler.on('mouseup', this._dragEnd, this); + } + + Draggable.prototype._dragStart = function (e) { + var draggingTarget = e.target; + + while (draggingTarget && !draggingTarget.draggable) { + draggingTarget = draggingTarget.parent || draggingTarget.__hostTarget; + } + + if (draggingTarget) { + this._draggingTarget = draggingTarget; + draggingTarget.dragging = true; + this._x = e.offsetX; + this._y = e.offsetY; + this.handler.dispatchToElement(new Param(draggingTarget, e), 'dragstart', e.event); + } + }; + + Draggable.prototype._drag = function (e) { + var draggingTarget = this._draggingTarget; + + if (draggingTarget) { + var x = e.offsetX; + var y = e.offsetY; + var dx = x - this._x; + var dy = y - this._y; + this._x = x; + this._y = y; + draggingTarget.drift(dx, dy, e); + this.handler.dispatchToElement(new Param(draggingTarget, e), 'drag', e.event); + var dropTarget = this.handler.findHover(x, y, draggingTarget).target; + var lastDropTarget = this._dropTarget; + this._dropTarget = dropTarget; + + if (draggingTarget !== dropTarget) { + if (lastDropTarget && dropTarget !== lastDropTarget) { + this.handler.dispatchToElement(new Param(lastDropTarget, e), 'dragleave', e.event); + } + + if (dropTarget && dropTarget !== lastDropTarget) { + this.handler.dispatchToElement(new Param(dropTarget, e), 'dragenter', e.event); + } + } + } + }; + + Draggable.prototype._dragEnd = function (e) { + var draggingTarget = this._draggingTarget; + + if (draggingTarget) { + draggingTarget.dragging = false; + } + + this.handler.dispatchToElement(new Param(draggingTarget, e), 'dragend', e.event); + + if (this._dropTarget) { + this.handler.dispatchToElement(new Param(this._dropTarget, e), 'drop', e.event); + } + + this._draggingTarget = null; + this._dropTarget = null; + }; + + return Draggable; + }(); + + var Eventful = function () { + function Eventful(eventProcessors) { + if (eventProcessors) { + this._$eventProcessor = eventProcessors; + } + } + + Eventful.prototype.on = function (event, query, handler, context) { + if (!this._$handlers) { + this._$handlers = {}; + } + + var _h = this._$handlers; + + if (typeof query === 'function') { + context = handler; + handler = query; + query = null; + } + + if (!handler || !event) { + return this; + } + + var eventProcessor = this._$eventProcessor; + + if (query != null && eventProcessor && eventProcessor.normalizeQuery) { + query = eventProcessor.normalizeQuery(query); + } + + if (!_h[event]) { + _h[event] = []; + } + + for (var i = 0; i < _h[event].length; i++) { + if (_h[event][i].h === handler) { + return this; + } + } + + var wrap = { + h: handler, + query: query, + ctx: context || this, + callAtLast: handler.zrEventfulCallAtLast + }; + var lastIndex = _h[event].length - 1; + var lastWrap = _h[event][lastIndex]; + lastWrap && lastWrap.callAtLast ? _h[event].splice(lastIndex, 0, wrap) : _h[event].push(wrap); + return this; + }; + + Eventful.prototype.isSilent = function (eventName) { + var _h = this._$handlers; + return !_h || !_h[eventName] || !_h[eventName].length; + }; + + Eventful.prototype.off = function (eventType, handler) { + var _h = this._$handlers; + + if (!_h) { + return this; + } + + if (!eventType) { + this._$handlers = {}; + return this; + } + + if (handler) { + if (_h[eventType]) { + var newList = []; + + for (var i = 0, l = _h[eventType].length; i < l; i++) { + if (_h[eventType][i].h !== handler) { + newList.push(_h[eventType][i]); + } + } + + _h[eventType] = newList; + } + + if (_h[eventType] && _h[eventType].length === 0) { + delete _h[eventType]; + } + } else { + delete _h[eventType]; + } + + return this; + }; + + Eventful.prototype.trigger = function (eventType) { + var args = []; + + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + + if (!this._$handlers) { + return this; + } + + var _h = this._$handlers[eventType]; + var eventProcessor = this._$eventProcessor; + + if (_h) { + var argLen = args.length; + var len = _h.length; + + for (var i = 0; i < len; i++) { + var hItem = _h[i]; + + if (eventProcessor && eventProcessor.filter && hItem.query != null && !eventProcessor.filter(eventType, hItem.query)) { + continue; + } + + switch (argLen) { + case 0: + hItem.h.call(hItem.ctx); + break; + + case 1: + hItem.h.call(hItem.ctx, args[0]); + break; + + case 2: + hItem.h.call(hItem.ctx, args[0], args[1]); + break; + + default: + hItem.h.apply(hItem.ctx, args); + break; + } + } + } + + eventProcessor && eventProcessor.afterTrigger && eventProcessor.afterTrigger(eventType); + return this; + }; + + Eventful.prototype.triggerWithContext = function (type) { + var args = []; + + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + + if (!this._$handlers) { + return this; + } + + var _h = this._$handlers[type]; + var eventProcessor = this._$eventProcessor; + + if (_h) { + var argLen = args.length; + var ctx = args[argLen - 1]; + var len = _h.length; + + for (var i = 0; i < len; i++) { + var hItem = _h[i]; + + if (eventProcessor && eventProcessor.filter && hItem.query != null && !eventProcessor.filter(type, hItem.query)) { + continue; + } + + switch (argLen) { + case 0: + hItem.h.call(ctx); + break; + + case 1: + hItem.h.call(ctx, args[0]); + break; + + case 2: + hItem.h.call(ctx, args[0], args[1]); + break; + + default: + hItem.h.apply(ctx, args.slice(1, argLen - 1)); + break; + } + } + } + + eventProcessor && eventProcessor.afterTrigger && eventProcessor.afterTrigger(type); + return this; + }; + + return Eventful; + }(); + + var LN2 = Math.log(2); + + function determinant(rows, rank, rowStart, rowMask, colMask, detCache) { + var cacheKey = rowMask + '-' + colMask; + var fullRank = rows.length; + + if (detCache.hasOwnProperty(cacheKey)) { + return detCache[cacheKey]; + } + + if (rank === 1) { + var colStart = Math.round(Math.log((1 << fullRank) - 1 & ~colMask) / LN2); + return rows[rowStart][colStart]; + } + + var subRowMask = rowMask | 1 << rowStart; + var subRowStart = rowStart + 1; + + while (rowMask & 1 << subRowStart) { + subRowStart++; + } + + var sum = 0; + + for (var j = 0, colLocalIdx = 0; j < fullRank; j++) { + var colTag = 1 << j; + + if (!(colTag & colMask)) { + sum += (colLocalIdx % 2 ? -1 : 1) * rows[rowStart][j] * determinant(rows, rank - 1, subRowStart, subRowMask, colMask | colTag, detCache); + colLocalIdx++; + } + } + + detCache[cacheKey] = sum; + return sum; + } + + function buildTransformer(src, dest) { + var mA = [[src[0], src[1], 1, 0, 0, 0, -dest[0] * src[0], -dest[0] * src[1]], [0, 0, 0, src[0], src[1], 1, -dest[1] * src[0], -dest[1] * src[1]], [src[2], src[3], 1, 0, 0, 0, -dest[2] * src[2], -dest[2] * src[3]], [0, 0, 0, src[2], src[3], 1, -dest[3] * src[2], -dest[3] * src[3]], [src[4], src[5], 1, 0, 0, 0, -dest[4] * src[4], -dest[4] * src[5]], [0, 0, 0, src[4], src[5], 1, -dest[5] * src[4], -dest[5] * src[5]], [src[6], src[7], 1, 0, 0, 0, -dest[6] * src[6], -dest[6] * src[7]], [0, 0, 0, src[6], src[7], 1, -dest[7] * src[6], -dest[7] * src[7]]]; + var detCache = {}; + var det = determinant(mA, 8, 0, 0, 0, detCache); + + if (det === 0) { + return; + } + + var vh = []; + + for (var i = 0; i < 8; i++) { + for (var j = 0; j < 8; j++) { + vh[j] == null && (vh[j] = 0); + vh[j] += ((i + j) % 2 ? -1 : 1) * determinant(mA, 7, i === 0 ? 1 : 0, 1 << i, 1 << j, detCache) / det * dest[i]; + } + } + + return function (out, srcPointX, srcPointY) { + var pk = srcPointX * vh[6] + srcPointY * vh[7] + 1; + out[0] = (srcPointX * vh[0] + srcPointY * vh[1] + vh[2]) / pk; + out[1] = (srcPointX * vh[3] + srcPointY * vh[4] + vh[5]) / pk; + }; + } + + var EVENT_SAVED_PROP = '___zrEVENTSAVED'; + var _calcOut$1 = []; + + function transformLocalCoord(out, elFrom, elTarget, inX, inY) { + return transformCoordWithViewport(_calcOut$1, elFrom, inX, inY, true) && transformCoordWithViewport(out, elTarget, _calcOut$1[0], _calcOut$1[1]); + } + + function transformLocalCoordClear(elFrom, elTarget) { + elFrom && dealClear(elFrom); + elTarget && dealClear(elTarget); + + function dealClear(el) { + var saved = el[EVENT_SAVED_PROP]; + + if (saved) { + saved.clearMarkers && saved.clearMarkers(); + delete el[EVENT_SAVED_PROP]; + } + } + } + + function transformCoordWithViewport(out, el, inX, inY, inverse) { + if (el.getBoundingClientRect && env.domSupported && !isCanvasEl(el)) { + var saved = el[EVENT_SAVED_PROP] || (el[EVENT_SAVED_PROP] = {}); + var markers = prepareCoordMarkers(el, saved); + var transformer = preparePointerTransformer(markers, saved, inverse); + + if (transformer) { + transformer(out, inX, inY); + return true; + } + } + + return false; + } + + function prepareCoordMarkers(el, saved) { + var markers = saved.markers; + + if (markers) { + return markers; + } + + markers = saved.markers = []; + var propLR = ['left', 'right']; + var propTB = ['top', 'bottom']; + + for (var i = 0; i < 4; i++) { + var marker = document.createElement('div'); + var stl = marker.style; + var idxLR = i % 2; + var idxTB = (i >> 1) % 2; + stl.cssText = ['position: absolute', 'visibility: hidden', 'padding: 0', 'margin: 0', 'border-width: 0', 'user-select: none', 'width:0', 'height:0', propLR[idxLR] + ':0', propTB[idxTB] + ':0', propLR[1 - idxLR] + ':auto', propTB[1 - idxTB] + ':auto', ''].join('!important;'); + el.appendChild(marker); + markers.push(marker); + } + + saved.clearMarkers = function () { + each$4(markers, function (marker) { + marker.parentNode && marker.parentNode.removeChild(marker); + }); + }; + + return markers; + } + + function preparePointerTransformer(markers, saved, inverse) { + var transformerName = inverse ? 'invTrans' : 'trans'; + var transformer = saved[transformerName]; + var oldSrcCoords = saved.srcCoords; + var srcCoords = []; + var destCoords = []; + var oldCoordTheSame = true; + + for (var i = 0; i < 4; i++) { + var rect = markers[i].getBoundingClientRect(); + var ii = 2 * i; + var x = rect.left; + var y = rect.top; + srcCoords.push(x, y); + oldCoordTheSame = oldCoordTheSame && oldSrcCoords && x === oldSrcCoords[ii] && y === oldSrcCoords[ii + 1]; + destCoords.push(markers[i].offsetLeft, markers[i].offsetTop); + } + + return oldCoordTheSame && transformer ? transformer : (saved.srcCoords = srcCoords, saved[transformerName] = inverse ? buildTransformer(destCoords, srcCoords) : buildTransformer(srcCoords, destCoords)); + } + + function isCanvasEl(el) { + return el.nodeName.toUpperCase() === 'CANVAS'; + } + + var replaceReg = /([&<>"'])/g; + var replaceMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''' + }; + + function encodeHTML(source) { + return source == null ? '' : (source + '').replace(replaceReg, function (str, c) { + return replaceMap[c]; + }); + } + + var MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/; + var _calcOut = []; + var firefoxNotSupportOffsetXY = env.browser.firefox && +env.browser.version.split('.')[0] < 39; + + function clientToLocal(el, e, out, calculate) { + out = out || {}; + + if (calculate) { + calculateZrXY(el, e, out); + } else if (firefoxNotSupportOffsetXY && e.layerX != null && e.layerX !== e.offsetX) { + out.zrX = e.layerX; + out.zrY = e.layerY; + } else if (e.offsetX != null) { + out.zrX = e.offsetX; + out.zrY = e.offsetY; + } else { + calculateZrXY(el, e, out); + } + + return out; + } + + function calculateZrXY(el, e, out) { + if (env.domSupported && el.getBoundingClientRect) { + var ex = e.clientX; + var ey = e.clientY; + + if (isCanvasEl(el)) { + var box = el.getBoundingClientRect(); + out.zrX = ex - box.left; + out.zrY = ey - box.top; + return; + } else { + if (transformCoordWithViewport(_calcOut, el, ex, ey)) { + out.zrX = _calcOut[0]; + out.zrY = _calcOut[1]; + return; + } + } + } + + out.zrX = out.zrY = 0; + } + + function getNativeEvent(e) { + return e || window.event; + } + + function normalizeEvent(el, e, calculate) { + e = getNativeEvent(e); + + if (e.zrX != null) { + return e; + } + + var eventType = e.type; + var isTouch = eventType && eventType.indexOf('touch') >= 0; + + if (!isTouch) { + clientToLocal(el, e, e, calculate); + var wheelDelta = getWheelDeltaMayPolyfill(e); + e.zrDelta = wheelDelta ? wheelDelta / 120 : -(e.detail || 0) / 3; + } else { + var touch = eventType !== 'touchend' ? e.targetTouches[0] : e.changedTouches[0]; + touch && clientToLocal(el, touch, e, calculate); + } + + var button = e.button; + + if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) { + e.which = button & 1 ? 1 : button & 2 ? 3 : button & 4 ? 2 : 0; + } + + return e; + } + + function getWheelDeltaMayPolyfill(e) { + var rawWheelDelta = e.wheelDelta; + + if (rawWheelDelta) { + return rawWheelDelta; + } + + var deltaX = e.deltaX; + var deltaY = e.deltaY; + + if (deltaX == null || deltaY == null) { + return rawWheelDelta; + } + + var delta = deltaY !== 0 ? Math.abs(deltaY) : Math.abs(deltaX); + var sign = deltaY > 0 ? -1 : deltaY < 0 ? 1 : deltaX > 0 ? -1 : 1; + return 3 * delta * sign; + } + + function addEventListener(el, name, handler, opt) { + el.addEventListener(name, handler, opt); + } + + function removeEventListener(el, name, handler, opt) { + el.removeEventListener(name, handler, opt); + } + + var stop = function (e) { + e.preventDefault(); + e.stopPropagation(); + e.cancelBubble = true; + }; + + var GestureMgr = function () { + function GestureMgr() { + this._track = []; + } + + GestureMgr.prototype.recognize = function (event, target, root) { + this._doTrack(event, target, root); + + return this._recognize(event); + }; + + GestureMgr.prototype.clear = function () { + this._track.length = 0; + return this; + }; + + GestureMgr.prototype._doTrack = function (event, target, root) { + var touches = event.touches; + + if (!touches) { + return; + } + + var trackItem = { + points: [], + touches: [], + target: target, + event: event + }; + + for (var i = 0, len = touches.length; i < len; i++) { + var touch = touches[i]; + var pos = clientToLocal(root, touch, {}); + trackItem.points.push([pos.zrX, pos.zrY]); + trackItem.touches.push(touch); + } + + this._track.push(trackItem); + }; + + GestureMgr.prototype._recognize = function (event) { + for (var eventName in recognizers) { + if (recognizers.hasOwnProperty(eventName)) { + var gestureInfo = recognizers[eventName](this._track, event); + + if (gestureInfo) { + return gestureInfo; + } + } + } + }; + + return GestureMgr; + }(); + + function dist(pointPair) { + var dx = pointPair[1][0] - pointPair[0][0]; + var dy = pointPair[1][1] - pointPair[0][1]; + return Math.sqrt(dx * dx + dy * dy); + } + + function center(pointPair) { + return [(pointPair[0][0] + pointPair[1][0]) / 2, (pointPair[0][1] + pointPair[1][1]) / 2]; + } + + var recognizers = { + pinch: function (tracks, event) { + var trackLen = tracks.length; + + if (!trackLen) { + return; + } + + var pinchEnd = (tracks[trackLen - 1] || {}).points; + var pinchPre = (tracks[trackLen - 2] || {}).points || pinchEnd; + + if (pinchPre && pinchPre.length > 1 && pinchEnd && pinchEnd.length > 1) { + var pinchScale = dist(pinchEnd) / dist(pinchPre); + !isFinite(pinchScale) && (pinchScale = 1); + event.pinchScale = pinchScale; + var pinchCenter = center(pinchEnd); + event.pinchX = pinchCenter[0]; + event.pinchY = pinchCenter[1]; + return { + type: 'pinch', + target: tracks[0].target, + event: event + }; + } + } + }; + + function create() { + return [1, 0, 0, 1, 0, 0]; + } + + function identity(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; + } + + function copy(out, m) { + out[0] = m[0]; + out[1] = m[1]; + out[2] = m[2]; + out[3] = m[3]; + out[4] = m[4]; + out[5] = m[5]; + return out; + } + + function mul(out, m1, m2) { + var out0 = m1[0] * m2[0] + m1[2] * m2[1]; + var out1 = m1[1] * m2[0] + m1[3] * m2[1]; + var out2 = m1[0] * m2[2] + m1[2] * m2[3]; + var out3 = m1[1] * m2[2] + m1[3] * m2[3]; + var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4]; + var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5]; + out[0] = out0; + out[1] = out1; + out[2] = out2; + out[3] = out3; + out[4] = out4; + out[5] = out5; + return out; + } + + function translate(out, a, v) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4] + v[0]; + out[5] = a[5] + v[1]; + return out; + } + + function rotate(out, a, rad, pivot) { + if (pivot === void 0) { + pivot = [0, 0]; + } + + var aa = a[0]; + var ac = a[2]; + var atx = a[4]; + var ab = a[1]; + var ad = a[3]; + var aty = a[5]; + var st = Math.sin(rad); + var ct = Math.cos(rad); + out[0] = aa * ct + ab * st; + out[1] = -aa * st + ab * ct; + out[2] = ac * ct + ad * st; + out[3] = -ac * st + ct * ad; + out[4] = ct * (atx - pivot[0]) + st * (aty - pivot[1]) + pivot[0]; + out[5] = ct * (aty - pivot[1]) - st * (atx - pivot[0]) + pivot[1]; + return out; + } + + function scale$1(out, a, v) { + var vx = v[0]; + var vy = v[1]; + out[0] = a[0] * vx; + out[1] = a[1] * vy; + out[2] = a[2] * vx; + out[3] = a[3] * vy; + out[4] = a[4] * vx; + out[5] = a[5] * vy; + return out; + } + + function invert(out, a) { + var aa = a[0]; + var ac = a[2]; + var atx = a[4]; + var ab = a[1]; + var ad = a[3]; + var aty = a[5]; + var det = aa * ad - ab * ac; + + if (!det) { + return null; + } + + det = 1.0 / det; + out[0] = ad * det; + out[1] = -ab * det; + out[2] = -ac * det; + out[3] = aa * det; + out[4] = (ac * aty - ad * atx) * det; + out[5] = (ab * atx - aa * aty) * det; + return out; + } + + function clone$1(a) { + var b = create(); + copy(b, a); + return b; + } + + var matrix = /*#__PURE__*/Object.freeze({ + __proto__: null, + clone: clone$1, + copy: copy, + create: create, + identity: identity, + invert: invert, + mul: mul, + rotate: rotate, + scale: scale$1, + translate: translate + }); + + var Point = function () { + function Point(x, y) { + this.x = x || 0; + this.y = y || 0; + } + + Point.prototype.copy = function (other) { + this.x = other.x; + this.y = other.y; + return this; + }; + + Point.prototype.clone = function () { + return new Point(this.x, this.y); + }; + + Point.prototype.set = function (x, y) { + this.x = x; + this.y = y; + return this; + }; + + Point.prototype.equal = function (other) { + return other.x === this.x && other.y === this.y; + }; + + Point.prototype.add = function (other) { + this.x += other.x; + this.y += other.y; + return this; + }; + + Point.prototype.scale = function (scalar) { + this.x *= scalar; + this.y *= scalar; + }; + + Point.prototype.scaleAndAdd = function (other, scalar) { + this.x += other.x * scalar; + this.y += other.y * scalar; + }; + + Point.prototype.sub = function (other) { + this.x -= other.x; + this.y -= other.y; + return this; + }; + + Point.prototype.dot = function (other) { + return this.x * other.x + this.y * other.y; + }; + + Point.prototype.len = function () { + return Math.sqrt(this.x * this.x + this.y * this.y); + }; + + Point.prototype.lenSquare = function () { + return this.x * this.x + this.y * this.y; + }; + + Point.prototype.normalize = function () { + var len = this.len(); + this.x /= len; + this.y /= len; + return this; + }; + + Point.prototype.distance = function (other) { + var dx = this.x - other.x; + var dy = this.y - other.y; + return Math.sqrt(dx * dx + dy * dy); + }; + + Point.prototype.distanceSquare = function (other) { + var dx = this.x - other.x; + var dy = this.y - other.y; + return dx * dx + dy * dy; + }; + + Point.prototype.negate = function () { + this.x = -this.x; + this.y = -this.y; + return this; + }; + + Point.prototype.transform = function (m) { + if (!m) { + return; + } + + var x = this.x; + var y = this.y; + this.x = m[0] * x + m[2] * y + m[4]; + this.y = m[1] * x + m[3] * y + m[5]; + return this; + }; + + Point.prototype.toArray = function (out) { + out[0] = this.x; + out[1] = this.y; + return out; + }; + + Point.prototype.fromArray = function (input) { + this.x = input[0]; + this.y = input[1]; + }; + + Point.set = function (p, x, y) { + p.x = x; + p.y = y; + }; + + Point.copy = function (p, p2) { + p.x = p2.x; + p.y = p2.y; + }; + + Point.len = function (p) { + return Math.sqrt(p.x * p.x + p.y * p.y); + }; + + Point.lenSquare = function (p) { + return p.x * p.x + p.y * p.y; + }; + + Point.dot = function (p0, p1) { + return p0.x * p1.x + p0.y * p1.y; + }; + + Point.add = function (out, p0, p1) { + out.x = p0.x + p1.x; + out.y = p0.y + p1.y; + }; + + Point.sub = function (out, p0, p1) { + out.x = p0.x - p1.x; + out.y = p0.y - p1.y; + }; + + Point.scale = function (out, p0, scalar) { + out.x = p0.x * scalar; + out.y = p0.y * scalar; + }; + + Point.scaleAndAdd = function (out, p0, p1, scalar) { + out.x = p0.x + p1.x * scalar; + out.y = p0.y + p1.y * scalar; + }; + + Point.lerp = function (out, p0, p1, t) { + var onet = 1 - t; + out.x = onet * p0.x + t * p1.x; + out.y = onet * p0.y + t * p1.y; + }; + + return Point; + }(); + + var mathMin$7 = Math.min; + var mathMax$7 = Math.max; + var mathAbs$4 = Math.abs; + var XY$2 = ['x', 'y']; + var WH$2 = ['width', 'height']; + var lt = new Point(); + var rb = new Point(); + var lb = new Point(); + var rt = new Point(); + + var _intersectCtx$1 = createIntersectContext(); + + var _minTv$1 = _intersectCtx$1.minTv; + var _maxTv$1 = _intersectCtx$1.maxTv; + var _lenMinMax = [0, 0]; + + var BoundingRect = function () { + function BoundingRect(x, y, width, height) { + BoundingRect.set(this, x, y, width, height); + } + + BoundingRect.set = function (target, x, y, width, height) { + if (width < 0) { + x = x + width; + width = -width; + } + + if (height < 0) { + y = y + height; + height = -height; + } + + target.x = x; + target.y = y; + target.width = width; + target.height = height; + return target; + }; + + BoundingRect.prototype.union = function (other) { + var x = mathMin$7(other.x, this.x); + var y = mathMin$7(other.y, this.y); + + if (isFinite(this.x) && isFinite(this.width)) { + this.width = mathMax$7(other.x + other.width, this.x + this.width) - x; + } else { + this.width = other.width; + } + + if (isFinite(this.y) && isFinite(this.height)) { + this.height = mathMax$7(other.y + other.height, this.y + this.height) - y; + } else { + this.height = other.height; + } + + this.x = x; + this.y = y; + }; + + BoundingRect.prototype.applyTransform = function (m) { + BoundingRect.applyTransform(this, this, m); + }; + + BoundingRect.prototype.calculateTransform = function (b) { + var a = this; + var sx = b.width / a.width; + var sy = b.height / a.height; + var m = create(); + translate(m, m, [-a.x, -a.y]); + scale$1(m, m, [sx, sy]); + translate(m, m, [b.x, b.y]); + return m; + }; + + BoundingRect.prototype.intersect = function (b, mtv, opt) { + return BoundingRect.intersect(this, b, mtv, opt); + }; + + BoundingRect.intersect = function (a, b, mtv, opt) { + if (mtv) { + Point.set(mtv, 0, 0); + } + + var outIntersectRect = opt && opt.outIntersectRect || null; + var clamp = opt && opt.clamp; + + if (outIntersectRect) { + outIntersectRect.x = outIntersectRect.y = outIntersectRect.width = outIntersectRect.height = NaN; + } + + if (!a || !b) { + return false; + } + + if (!(a instanceof BoundingRect)) { + a = BoundingRect.set(_tmpIntersectA, a.x, a.y, a.width, a.height); + } + + if (!(b instanceof BoundingRect)) { + b = BoundingRect.set(_tmpIntersectB, b.x, b.y, b.width, b.height); + } + + var useMTV = !!mtv; + + _intersectCtx$1.reset(opt, useMTV); + + var touchThreshold = _intersectCtx$1.touchThreshold; + var ax0 = a.x + touchThreshold; + var ax1 = a.x + a.width - touchThreshold; + var ay0 = a.y + touchThreshold; + var ay1 = a.y + a.height - touchThreshold; + var bx0 = b.x + touchThreshold; + var bx1 = b.x + b.width - touchThreshold; + var by0 = b.y + touchThreshold; + var by1 = b.y + b.height - touchThreshold; + + if (ax0 > ax1 || ay0 > ay1 || bx0 > bx1 || by0 > by1) { + return false; + } + + var overlap = !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0); + + if (useMTV || outIntersectRect) { + _lenMinMax[0] = Infinity; + _lenMinMax[1] = 0; + intersectOneDim(ax0, ax1, bx0, bx1, 0, useMTV, outIntersectRect, clamp); + intersectOneDim(ay0, ay1, by0, by1, 1, useMTV, outIntersectRect, clamp); + + if (useMTV) { + Point.copy(mtv, overlap ? _intersectCtx$1.useDir ? _intersectCtx$1.dirMinTv : _minTv$1 : _maxTv$1); + } + } + + return overlap; + }; + + BoundingRect.contain = function (rect, x, y) { + return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height; + }; + + BoundingRect.prototype.contain = function (x, y) { + return BoundingRect.contain(this, x, y); + }; + + BoundingRect.prototype.clone = function () { + return new BoundingRect(this.x, this.y, this.width, this.height); + }; + + BoundingRect.prototype.copy = function (other) { + BoundingRect.copy(this, other); + }; + + BoundingRect.prototype.plain = function () { + return { + x: this.x, + y: this.y, + width: this.width, + height: this.height + }; + }; + + BoundingRect.prototype.isFinite = function () { + return isFinite(this.x) && isFinite(this.y) && isFinite(this.width) && isFinite(this.height); + }; + + BoundingRect.prototype.isZero = function () { + return this.width === 0 || this.height === 0; + }; + + BoundingRect.create = function (rect) { + return new BoundingRect(rect.x, rect.y, rect.width, rect.height); + }; + + BoundingRect.copy = function (target, source) { + target.x = source.x; + target.y = source.y; + target.width = source.width; + target.height = source.height; + return target; + }; + + BoundingRect.applyTransform = function (target, source, m) { + if (!m) { + if (target !== source) { + BoundingRect.copy(target, source); + } + + return; + } + + if (m[1] < 1e-5 && m[1] > -1e-5 && m[2] < 1e-5 && m[2] > -1e-5) { + var sx = m[0]; + var sy = m[3]; + var tx = m[4]; + var ty = m[5]; + target.x = source.x * sx + tx; + target.y = source.y * sy + ty; + target.width = source.width * sx; + target.height = source.height * sy; + + if (target.width < 0) { + target.x += target.width; + target.width = -target.width; + } + + if (target.height < 0) { + target.y += target.height; + target.height = -target.height; + } + + return; + } + + lt.x = lb.x = source.x; + lt.y = rt.y = source.y; + rb.x = rt.x = source.x + source.width; + rb.y = lb.y = source.y + source.height; + lt.transform(m); + rt.transform(m); + rb.transform(m); + lb.transform(m); + target.x = mathMin$7(lt.x, rb.x, lb.x, rt.x); + target.y = mathMin$7(lt.y, rb.y, lb.y, rt.y); + var maxX = mathMax$7(lt.x, rb.x, lb.x, rt.x); + var maxY = mathMax$7(lt.y, rb.y, lb.y, rt.y); + target.width = maxX - target.x; + target.height = maxY - target.y; + }; + + return BoundingRect; + }(); + + var _tmpIntersectA = new BoundingRect(0, 0, 0, 0); + + var _tmpIntersectB = new BoundingRect(0, 0, 0, 0); + + function intersectOneDim(a0, a1, b0, b1, updateDimIdx, useMTV, outIntersectRect, clamp) { + var d0 = mathAbs$4(a1 - b0); + var d1 = mathAbs$4(b1 - a0); + var d01min = mathMin$7(d0, d1); + var updateDim = XY$2[updateDimIdx]; + var zeroDim = XY$2[1 - updateDimIdx]; + var wh = WH$2[updateDimIdx]; + + if (a1 < b0 || b1 < a0) { + if (d0 < d1) { + if (useMTV) { + _maxTv$1[updateDim] = -d0; + } + + if (clamp) { + outIntersectRect[updateDim] = a1; + outIntersectRect[wh] = 0; + } + } else { + if (useMTV) { + _maxTv$1[updateDim] = d1; + } + + if (clamp) { + outIntersectRect[updateDim] = a0; + outIntersectRect[wh] = 0; + } + } + } else { + if (outIntersectRect) { + outIntersectRect[updateDim] = mathMax$7(a0, b0); + outIntersectRect[wh] = mathMin$7(a1, b1) - outIntersectRect[updateDim]; + } + + if (useMTV) { + if (d01min < _lenMinMax[0] || _intersectCtx$1.useDir) { + _lenMinMax[0] = mathMin$7(d01min, _lenMinMax[0]); + + if (d0 < d1 || !_intersectCtx$1.bidirectional) { + _minTv$1[updateDim] = d0; + _minTv$1[zeroDim] = 0; + + if (_intersectCtx$1.useDir) { + _intersectCtx$1.calcDirMTV(); + } + } + + if (d0 >= d1 || !_intersectCtx$1.bidirectional) { + _minTv$1[updateDim] = -d1; + _minTv$1[zeroDim] = 0; + + if (_intersectCtx$1.useDir) { + _intersectCtx$1.calcDirMTV(); + } + } + } + } + } + } + + function createIntersectContext() { + var _direction = 0; + + var _dirCheckVec = new Point(); + + var _dirTmp = new Point(); + + var _ctx = { + minTv: new Point(), + maxTv: new Point(), + useDir: false, + dirMinTv: new Point(), + touchThreshold: 0, + bidirectional: true, + negativeSize: false, + reset: function (opt, useMTV) { + _ctx.touchThreshold = 0; + + if (opt && opt.touchThreshold != null) { + _ctx.touchThreshold = mathMax$7(0, opt.touchThreshold); + } + + _ctx.negativeSize = false; + + if (!useMTV) { + return; + } + + _ctx.minTv.set(Infinity, Infinity); + + _ctx.maxTv.set(0, 0); + + _ctx.useDir = false; + + if (opt && opt.direction != null) { + _ctx.useDir = true; + + _ctx.dirMinTv.copy(_ctx.minTv); + + _dirTmp.copy(_ctx.minTv); + + _direction = opt.direction; + _ctx.bidirectional = opt.bidirectional == null || !!opt.bidirectional; + + if (!_ctx.bidirectional) { + _dirCheckVec.set(Math.cos(_direction), Math.sin(_direction)); + } + } + }, + calcDirMTV: function () { + var minTv = _ctx.minTv; + var dirMinTv = _ctx.dirMinTv; + var squareMag = minTv.y * minTv.y + minTv.x * minTv.x; + var dirSin = Math.sin(_direction); + var dirCos = Math.cos(_direction); + var dotProd = dirSin * minTv.y + dirCos * minTv.x; + + if (nearZero(dotProd)) { + if (nearZero(minTv.x) && nearZero(minTv.y)) { + dirMinTv.set(0, 0); + } + + return; + } + + _dirTmp.x = squareMag * dirCos / dotProd; + _dirTmp.y = squareMag * dirSin / dotProd; + + if (nearZero(_dirTmp.x) && nearZero(_dirTmp.y)) { + dirMinTv.set(0, 0); + return; + } + + if ((_ctx.bidirectional || _dirCheckVec.dot(_dirTmp) > 0) && _dirTmp.len() < dirMinTv.len()) { + dirMinTv.copy(_dirTmp); + } + } + }; + + function nearZero(val) { + return mathAbs$4(val) < 1e-10; + } + + return _ctx; + } + + var SILENT = 'silent'; + + function makeEventPacket(eveType, targetInfo, event) { + return { + type: eveType, + event: event, + target: targetInfo.target, + topTarget: targetInfo.topTarget, + cancelBubble: false, + offsetX: event.zrX, + offsetY: event.zrY, + gestureEvent: event.gestureEvent, + pinchX: event.pinchX, + pinchY: event.pinchY, + pinchScale: event.pinchScale, + wheelDelta: event.zrDelta, + zrByTouch: event.zrByTouch, + which: event.which, + stop: stopEvent + }; + } + + function stopEvent() { + stop(this.event); + } + + var EmptyProxy = function (_super) { + __extends(EmptyProxy, _super); + + function EmptyProxy() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.handler = null; + return _this; + } + + EmptyProxy.prototype.dispose = function () {}; + + EmptyProxy.prototype.setCursor = function () {}; + + return EmptyProxy; + }(Eventful); + + var HoveredResult = function () { + function HoveredResult(x, y) { + this.x = x; + this.y = y; + } + + return HoveredResult; + }(); + + var handlerNames = ['click', 'dblclick', 'mousewheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu']; + var tmpRect$1 = new BoundingRect(0, 0, 0, 0); + + var Handler = function (_super) { + __extends(Handler, _super); + + function Handler(storage, painter, proxy, painterRoot, pointerSize) { + var _this = _super.call(this) || this; + + _this._hovered = new HoveredResult(0, 0); + _this.storage = storage; + _this.painter = painter; + _this.painterRoot = painterRoot; + _this._pointerSize = pointerSize; + proxy = proxy || new EmptyProxy(); + _this.proxy = null; + + _this.setHandlerProxy(proxy); + + _this._draggingMgr = new Draggable(_this); + return _this; + } + + Handler.prototype.setHandlerProxy = function (proxy) { + if (this.proxy) { + this.proxy.dispose(); + } + + if (proxy) { + each$4(handlerNames, function (name) { + proxy.on && proxy.on(name, this[name], this); + }, this); + proxy.handler = this; + } + + this.proxy = proxy; + }; + + Handler.prototype.mousemove = function (event) { + var x = event.zrX; + var y = event.zrY; + var isOutside = isOutsideBoundary(this, x, y); + var lastHovered = this._hovered; + var lastHoveredTarget = lastHovered.target; + + if (lastHoveredTarget && !lastHoveredTarget.__zr) { + lastHovered = this.findHover(lastHovered.x, lastHovered.y); + lastHoveredTarget = lastHovered.target; + } + + var hovered = this._hovered = isOutside ? new HoveredResult(x, y) : this.findHover(x, y); + var hoveredTarget = hovered.target; + var proxy = this.proxy; + proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default'); + + if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) { + this.dispatchToElement(lastHovered, 'mouseout', event); + } + + this.dispatchToElement(hovered, 'mousemove', event); + + if (hoveredTarget && hoveredTarget !== lastHoveredTarget) { + this.dispatchToElement(hovered, 'mouseover', event); + } + }; + + Handler.prototype.mouseout = function (event) { + var eventControl = event.zrEventControl; + + if (eventControl !== 'only_globalout') { + this.dispatchToElement(this._hovered, 'mouseout', event); + } + + if (eventControl !== 'no_globalout') { + this.trigger('globalout', { + type: 'globalout', + event: event + }); + } + }; + + Handler.prototype.resize = function () { + this._hovered = new HoveredResult(0, 0); + }; + + Handler.prototype.dispatch = function (eventName, eventArgs) { + var handler = this[eventName]; + handler && handler.call(this, eventArgs); + }; + + Handler.prototype.dispose = function () { + this.proxy.dispose(); + this.storage = null; + this.proxy = null; + this.painter = null; + }; + + Handler.prototype.setCursorStyle = function (cursorStyle) { + var proxy = this.proxy; + proxy.setCursor && proxy.setCursor(cursorStyle); + }; + + Handler.prototype.dispatchToElement = function (targetInfo, eventName, event) { + targetInfo = targetInfo || {}; + var el = targetInfo.target; + + if (el && el.silent) { + return; + } + + var eventKey = 'on' + eventName; + var eventPacket = makeEventPacket(eventName, targetInfo, event); + + while (el) { + el[eventKey] && (eventPacket.cancelBubble = !!el[eventKey].call(el, eventPacket)); + el.trigger(eventName, eventPacket); + el = el.__hostTarget ? el.__hostTarget : el.parent; + + if (eventPacket.cancelBubble) { + break; + } + } + + if (!eventPacket.cancelBubble) { + this.trigger(eventName, eventPacket); + + if (this.painter && this.painter.eachOtherLayer) { + this.painter.eachOtherLayer(function (layer) { + if (typeof layer[eventKey] === 'function') { + layer[eventKey].call(layer, eventPacket); + } + + if (layer.trigger) { + layer.trigger(eventName, eventPacket); + } + }); + } + } + }; + + Handler.prototype.findHover = function (x, y, exclude) { + var list = this.storage.getDisplayList(); + var out = new HoveredResult(x, y); + setHoverTarget(list, out, x, y, exclude); + + if (this._pointerSize && !out.target) { + var candidates = []; + var pointerSize = this._pointerSize; + var targetSizeHalf = pointerSize / 2; + var pointerRect = new BoundingRect(x - targetSizeHalf, y - targetSizeHalf, pointerSize, pointerSize); + + for (var i = list.length - 1; i >= 0; i--) { + var el = list[i]; + + if (el !== exclude && !el.ignore && !el.ignoreCoarsePointer && (!el.parent || !el.parent.ignoreCoarsePointer)) { + tmpRect$1.copy(el.getBoundingRect()); + + if (el.transform) { + tmpRect$1.applyTransform(el.transform); + } + + if (tmpRect$1.intersect(pointerRect)) { + candidates.push(el); + } + } + } + + if (candidates.length) { + var rStep = 4; + var thetaStep = Math.PI / 12; + var PI2 = Math.PI * 2; + + for (var r = 0; r < targetSizeHalf; r += rStep) { + for (var theta = 0; theta < PI2; theta += thetaStep) { + var x1 = x + r * Math.cos(theta); + var y1 = y + r * Math.sin(theta); + setHoverTarget(candidates, out, x1, y1, exclude); + + if (out.target) { + return out; + } + } + } + } + } + + return out; + }; + + Handler.prototype.processGesture = function (event, stage) { + if (!this._gestureMgr) { + this._gestureMgr = new GestureMgr(); + } + + var gestureMgr = this._gestureMgr; + stage === 'start' && gestureMgr.clear(); + var gestureInfo = gestureMgr.recognize(event, this.findHover(event.zrX, event.zrY, null).target, this.proxy.dom); + stage === 'end' && gestureMgr.clear(); + + if (gestureInfo) { + var type = gestureInfo.type; + event.gestureEvent = type; + var res = new HoveredResult(); + res.target = gestureInfo.target; + this.dispatchToElement(res, type, gestureInfo.event); + } + }; + + return Handler; + }(Eventful); + + each$4(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) { + Handler.prototype[name] = function (event) { + var x = event.zrX; + var y = event.zrY; + var isOutside = isOutsideBoundary(this, x, y); + var hovered; + var hoveredTarget; + + if (name !== 'mouseup' || !isOutside) { + hovered = this.findHover(x, y); + hoveredTarget = hovered.target; + } + + if (name === 'mousedown') { + this._downEl = hoveredTarget; + this._downPoint = [event.zrX, event.zrY]; + this._upEl = hoveredTarget; + } else if (name === 'mouseup') { + this._upEl = hoveredTarget; + } else if (name === 'click') { + if (this._downEl !== this._upEl || !this._downPoint || dist$1(this._downPoint, [event.zrX, event.zrY]) > 4) { + return; + } + + this._downPoint = null; + } + + this.dispatchToElement(hovered, name, event); + }; + }); + + function isHover(displayable, x, y) { + if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) { + var el = displayable; + var isSilent = void 0; + var ignoreClip = false; + + while (el) { + if (el.ignoreClip) { + ignoreClip = true; + } + + if (!ignoreClip) { + var clipPath = el.getClipPath(); + + if (clipPath && !clipPath.contain(x, y)) { + return false; + } + } + + if (el.silent) { + isSilent = true; + } + + var hostEl = el.__hostTarget; + el = hostEl ? el.ignoreHostSilent ? null : hostEl : el.parent; + } + + return isSilent ? SILENT : true; + } + + return false; + } + + function setHoverTarget(list, out, x, y, exclude) { + for (var i = list.length - 1; i >= 0; i--) { + var el = list[i]; + var hoverCheckResult = void 0; + + if (el !== exclude && !el.ignore && (hoverCheckResult = isHover(el, x, y))) { + !out.topTarget && (out.topTarget = el); + + if (hoverCheckResult !== SILENT) { + out.target = el; + break; + } + } + } + } + + function isOutsideBoundary(handlerInstance, x, y) { + var painter = handlerInstance.painter; + return x < 0 || x > painter.getWidth() || y < 0 || y > painter.getHeight(); + } + + var DEFAULT_MIN_MERGE = 32; + var DEFAULT_MIN_GALLOPING = 7; + + function minRunLength(n) { + var r = 0; + + while (n >= DEFAULT_MIN_MERGE) { + r |= n & 1; + n >>= 1; + } + + return n + r; + } + + function makeAscendingRun(array, lo, hi, compare) { + var runHi = lo + 1; + + if (runHi === hi) { + return 1; + } + + if (compare(array[runHi++], array[lo]) < 0) { + while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) { + runHi++; + } + + reverseRun(array, lo, runHi); + } else { + while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) { + runHi++; + } + } + + return runHi - lo; + } + + function reverseRun(array, lo, hi) { + hi--; + + while (lo < hi) { + var t = array[lo]; + array[lo++] = array[hi]; + array[hi--] = t; + } + } + + function binaryInsertionSort(array, lo, hi, start, compare) { + if (start === lo) { + start++; + } + + for (; start < hi; start++) { + var pivot = array[start]; + var left = lo; + var right = start; + var mid; + + while (left < right) { + mid = left + right >>> 1; + + if (compare(pivot, array[mid]) < 0) { + right = mid; + } else { + left = mid + 1; + } + } + + var n = start - left; + + switch (n) { + case 3: + array[left + 3] = array[left + 2]; + + case 2: + array[left + 2] = array[left + 1]; + + case 1: + array[left + 1] = array[left]; + break; + + default: + while (n > 0) { + array[left + n] = array[left + n - 1]; + n--; + } + + } + + array[left] = pivot; + } + } + + function gallopLeft(value, array, start, length, hint, compare) { + var lastOffset = 0; + var maxOffset = 0; + var offset = 1; + + if (compare(value, array[start + hint]) > 0) { + maxOffset = length - hint; + + while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) { + lastOffset = offset; + offset = (offset << 1) + 1; + + if (offset <= 0) { + offset = maxOffset; + } + } + + if (offset > maxOffset) { + offset = maxOffset; + } + + lastOffset += hint; + offset += hint; + } else { + maxOffset = hint + 1; + + while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) { + lastOffset = offset; + offset = (offset << 1) + 1; + + if (offset <= 0) { + offset = maxOffset; + } + } + + if (offset > maxOffset) { + offset = maxOffset; + } + + var tmp = lastOffset; + lastOffset = hint - offset; + offset = hint - tmp; + } + + lastOffset++; + + while (lastOffset < offset) { + var m = lastOffset + (offset - lastOffset >>> 1); + + if (compare(value, array[start + m]) > 0) { + lastOffset = m + 1; + } else { + offset = m; + } + } + + return offset; + } + + function gallopRight(value, array, start, length, hint, compare) { + var lastOffset = 0; + var maxOffset = 0; + var offset = 1; + + if (compare(value, array[start + hint]) < 0) { + maxOffset = hint + 1; + + while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) { + lastOffset = offset; + offset = (offset << 1) + 1; + + if (offset <= 0) { + offset = maxOffset; + } + } + + if (offset > maxOffset) { + offset = maxOffset; + } + + var tmp = lastOffset; + lastOffset = hint - offset; + offset = hint - tmp; + } else { + maxOffset = length - hint; + + while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) { + lastOffset = offset; + offset = (offset << 1) + 1; + + if (offset <= 0) { + offset = maxOffset; + } + } + + if (offset > maxOffset) { + offset = maxOffset; + } + + lastOffset += hint; + offset += hint; + } + + lastOffset++; + + while (lastOffset < offset) { + var m = lastOffset + (offset - lastOffset >>> 1); + + if (compare(value, array[start + m]) < 0) { + offset = m; + } else { + lastOffset = m + 1; + } + } + + return offset; + } + + function TimSort(array, compare) { + var minGallop = DEFAULT_MIN_GALLOPING; + var runStart; + var runLength; + var stackSize = 0; + var tmp = []; + runStart = []; + runLength = []; + + function pushRun(_runStart, _runLength) { + runStart[stackSize] = _runStart; + runLength[stackSize] = _runLength; + stackSize += 1; + } + + function mergeRuns() { + while (stackSize > 1) { + var n = stackSize - 2; + + if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) { + if (runLength[n - 1] < runLength[n + 1]) { + n--; + } + } else if (runLength[n] > runLength[n + 1]) { + break; + } + + mergeAt(n); + } + } + + function forceMergeRuns() { + while (stackSize > 1) { + var n = stackSize - 2; + + if (n > 0 && runLength[n - 1] < runLength[n + 1]) { + n--; + } + + mergeAt(n); + } + } + + function mergeAt(i) { + var start1 = runStart[i]; + var length1 = runLength[i]; + var start2 = runStart[i + 1]; + var length2 = runLength[i + 1]; + runLength[i] = length1 + length2; + + if (i === stackSize - 3) { + runStart[i + 1] = runStart[i + 2]; + runLength[i + 1] = runLength[i + 2]; + } + + stackSize--; + var k = gallopRight(array[start2], array, start1, length1, 0, compare); + start1 += k; + length1 -= k; + + if (length1 === 0) { + return; + } + + length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare); + + if (length2 === 0) { + return; + } + + if (length1 <= length2) { + mergeLow(start1, length1, start2, length2); + } else { + mergeHigh(start1, length1, start2, length2); + } + } + + function mergeLow(start1, length1, start2, length2) { + var i = 0; + + for (i = 0; i < length1; i++) { + tmp[i] = array[start1 + i]; + } + + var cursor1 = 0; + var cursor2 = start2; + var dest = start1; + array[dest++] = array[cursor2++]; + + if (--length2 === 0) { + for (i = 0; i < length1; i++) { + array[dest + i] = tmp[cursor1 + i]; + } + + return; + } + + if (length1 === 1) { + for (i = 0; i < length2; i++) { + array[dest + i] = array[cursor2 + i]; + } + + array[dest + length2] = tmp[cursor1]; + return; + } + + var _minGallop = minGallop; + var count1; + var count2; + var exit; + + while (1) { + count1 = 0; + count2 = 0; + exit = false; + + do { + if (compare(array[cursor2], tmp[cursor1]) < 0) { + array[dest++] = array[cursor2++]; + count2++; + count1 = 0; + + if (--length2 === 0) { + exit = true; + break; + } + } else { + array[dest++] = tmp[cursor1++]; + count1++; + count2 = 0; + + if (--length1 === 1) { + exit = true; + break; + } + } + } while ((count1 | count2) < _minGallop); + + if (exit) { + break; + } + + do { + count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare); + + if (count1 !== 0) { + for (i = 0; i < count1; i++) { + array[dest + i] = tmp[cursor1 + i]; + } + + dest += count1; + cursor1 += count1; + length1 -= count1; + + if (length1 <= 1) { + exit = true; + break; + } + } + + array[dest++] = array[cursor2++]; + + if (--length2 === 0) { + exit = true; + break; + } + + count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare); + + if (count2 !== 0) { + for (i = 0; i < count2; i++) { + array[dest + i] = array[cursor2 + i]; + } + + dest += count2; + cursor2 += count2; + length2 -= count2; + + if (length2 === 0) { + exit = true; + break; + } + } + + array[dest++] = tmp[cursor1++]; + + if (--length1 === 1) { + exit = true; + break; + } + + _minGallop--; + } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING); + + if (exit) { + break; + } + + if (_minGallop < 0) { + _minGallop = 0; + } + + _minGallop += 2; + } + + minGallop = _minGallop; + minGallop < 1 && (minGallop = 1); + + if (length1 === 1) { + for (i = 0; i < length2; i++) { + array[dest + i] = array[cursor2 + i]; + } + + array[dest + length2] = tmp[cursor1]; + } else if (length1 === 0) { + throw new Error(); + } else { + for (i = 0; i < length1; i++) { + array[dest + i] = tmp[cursor1 + i]; + } + } + } + + function mergeHigh(start1, length1, start2, length2) { + var i = 0; + + for (i = 0; i < length2; i++) { + tmp[i] = array[start2 + i]; + } + + var cursor1 = start1 + length1 - 1; + var cursor2 = length2 - 1; + var dest = start2 + length2 - 1; + var customCursor = 0; + var customDest = 0; + array[dest--] = array[cursor1--]; + + if (--length1 === 0) { + customCursor = dest - (length2 - 1); + + for (i = 0; i < length2; i++) { + array[customCursor + i] = tmp[i]; + } + + return; + } + + if (length2 === 1) { + dest -= length1; + cursor1 -= length1; + customDest = dest + 1; + customCursor = cursor1 + 1; + + for (i = length1 - 1; i >= 0; i--) { + array[customDest + i] = array[customCursor + i]; + } + + array[dest] = tmp[cursor2]; + return; + } + + var _minGallop = minGallop; + + while (true) { + var count1 = 0; + var count2 = 0; + var exit = false; + + do { + if (compare(tmp[cursor2], array[cursor1]) < 0) { + array[dest--] = array[cursor1--]; + count1++; + count2 = 0; + + if (--length1 === 0) { + exit = true; + break; + } + } else { + array[dest--] = tmp[cursor2--]; + count2++; + count1 = 0; + + if (--length2 === 1) { + exit = true; + break; + } + } + } while ((count1 | count2) < _minGallop); + + if (exit) { + break; + } + + do { + count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare); + + if (count1 !== 0) { + dest -= count1; + cursor1 -= count1; + length1 -= count1; + customDest = dest + 1; + customCursor = cursor1 + 1; + + for (i = count1 - 1; i >= 0; i--) { + array[customDest + i] = array[customCursor + i]; + } + + if (length1 === 0) { + exit = true; + break; + } + } + + array[dest--] = tmp[cursor2--]; + + if (--length2 === 1) { + exit = true; + break; + } + + count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare); + + if (count2 !== 0) { + dest -= count2; + cursor2 -= count2; + length2 -= count2; + customDest = dest + 1; + customCursor = cursor2 + 1; + + for (i = 0; i < count2; i++) { + array[customDest + i] = tmp[customCursor + i]; + } + + if (length2 <= 1) { + exit = true; + break; + } + } + + array[dest--] = array[cursor1--]; + + if (--length1 === 0) { + exit = true; + break; + } + + _minGallop--; + } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING); + + if (exit) { + break; + } + + if (_minGallop < 0) { + _minGallop = 0; + } + + _minGallop += 2; + } + + minGallop = _minGallop; + + if (minGallop < 1) { + minGallop = 1; + } + + if (length2 === 1) { + dest -= length1; + cursor1 -= length1; + customDest = dest + 1; + customCursor = cursor1 + 1; + + for (i = length1 - 1; i >= 0; i--) { + array[customDest + i] = array[customCursor + i]; + } + + array[dest] = tmp[cursor2]; + } else if (length2 === 0) { + throw new Error(); + } else { + customCursor = dest - (length2 - 1); + + for (i = 0; i < length2; i++) { + array[customCursor + i] = tmp[i]; + } + } + } + + return { + mergeRuns: mergeRuns, + forceMergeRuns: forceMergeRuns, + pushRun: pushRun + }; + } + + function sort(array, compare, lo, hi) { + if (!lo) { + lo = 0; + } + + if (!hi) { + hi = array.length; + } + + var remaining = hi - lo; + + if (remaining < 2) { + return; + } + + var runLength = 0; + + if (remaining < DEFAULT_MIN_MERGE) { + runLength = makeAscendingRun(array, lo, hi, compare); + binaryInsertionSort(array, lo, hi, lo + runLength, compare); + return; + } + + var ts = TimSort(array, compare); + var minRun = minRunLength(remaining); + + do { + runLength = makeAscendingRun(array, lo, hi, compare); + + if (runLength < minRun) { + var force = remaining; + + if (force > minRun) { + force = minRun; + } + + binaryInsertionSort(array, lo, lo + force, lo + runLength, compare); + runLength = force; + } + + ts.pushRun(lo, runLength); + ts.mergeRuns(); + remaining -= runLength; + lo += runLength; + } while (remaining !== 0); + + ts.forceMergeRuns(); + } + + var REDRAW_BIT = 1; + var STYLE_CHANGED_BIT = 2; + var SHAPE_CHANGED_BIT = 4; + var invalidZErrorLogged = false; + + function logInvalidZError() { + if (invalidZErrorLogged) { + return; + } + + invalidZErrorLogged = true; + console.warn('z / z2 / zlevel of displayable is invalid, which may cause unexpected errors'); + } + + function shapeCompareFunc(a, b) { + if (a.zlevel === b.zlevel) { + if (a.z === b.z) { + return a.z2 - b.z2; + } + + return a.z - b.z; + } + + return a.zlevel - b.zlevel; + } + + var Storage = function () { + function Storage() { + this._roots = []; + this._displayList = []; + this._displayListLen = 0; + this.displayableSortFunc = shapeCompareFunc; + } + + Storage.prototype.traverse = function (cb, context) { + for (var i = 0; i < this._roots.length; i++) { + this._roots[i].traverse(cb, context); + } + }; + + Storage.prototype.getDisplayList = function (update, includeIgnore) { + includeIgnore = includeIgnore || false; + var displayList = this._displayList; + + if (update || !displayList.length) { + this.updateDisplayList(includeIgnore); + } + + return displayList; + }; + + Storage.prototype.updateDisplayList = function (includeIgnore) { + this._displayListLen = 0; + var roots = this._roots; + var displayList = this._displayList; + + for (var i = 0, len = roots.length; i < len; i++) { + this._updateAndAddDisplayable(roots[i], null, includeIgnore); + } + + displayList.length = this._displayListLen; + sort(displayList, shapeCompareFunc); + }; + + Storage.prototype._updateAndAddDisplayable = function (el, parentClipPaths, includeIgnore) { + if (el.ignore && !includeIgnore) { + return; + } + + el.beforeUpdate(); + el.update(); + el.afterUpdate(); + var userSetClipPath = el.getClipPath(); + var parentHasClipPaths = parentClipPaths && parentClipPaths.length; + var clipPathIdx = 0; + var thisClipPaths = el.__clipPaths; + + if (!el.ignoreClip && (parentHasClipPaths || userSetClipPath)) { + if (!thisClipPaths) { + thisClipPaths = el.__clipPaths = []; + } + + if (parentHasClipPaths) { + for (var idx = 0; idx < parentClipPaths.length; idx++) { + thisClipPaths[clipPathIdx++] = parentClipPaths[idx]; + } + } + + var currentClipPath = userSetClipPath; + var parentClipPath = el; + + while (currentClipPath) { + currentClipPath.parent = parentClipPath; + currentClipPath.updateTransform(); + thisClipPaths[clipPathIdx++] = currentClipPath; + parentClipPath = currentClipPath; + currentClipPath = currentClipPath.getClipPath(); + } + } + + if (thisClipPaths) { + thisClipPaths.length = clipPathIdx; + } + + if (el.childrenRef) { + var children = el.childrenRef(); + + for (var i = 0; i < children.length; i++) { + var child = children[i]; + + if (el.__dirty) { + child.__dirty |= REDRAW_BIT; + } + + this._updateAndAddDisplayable(child, thisClipPaths, includeIgnore); + } + + el.__dirty = 0; + } else { + var disp = el; + + if (isNaN(disp.z)) { + logInvalidZError(); + disp.z = 0; + } + + if (isNaN(disp.z2)) { + logInvalidZError(); + disp.z2 = 0; + } + + if (isNaN(disp.zlevel)) { + logInvalidZError(); + disp.zlevel = 0; + } + + this._displayList[this._displayListLen++] = disp; + } + + var decalEl = el.getDecalElement && el.getDecalElement(); + + if (decalEl) { + this._updateAndAddDisplayable(decalEl, thisClipPaths, includeIgnore); + } + + var textGuide = el.getTextGuideLine(); + + if (textGuide) { + this._updateAndAddDisplayable(textGuide, thisClipPaths, includeIgnore); + } + + var textEl = el.getTextContent(); + + if (textEl) { + this._updateAndAddDisplayable(textEl, thisClipPaths, includeIgnore); + } + }; + + Storage.prototype.addRoot = function (el) { + if (el.__zr && el.__zr.storage === this) { + return; + } + + this._roots.push(el); + }; + + Storage.prototype.delRoot = function (el) { + if (el instanceof Array) { + for (var i = 0, l = el.length; i < l; i++) { + this.delRoot(el[i]); + } + + return; + } + + var idx = indexOf(this._roots, el); + + if (idx >= 0) { + this._roots.splice(idx, 1); + } + }; + + Storage.prototype.delAllRoots = function () { + this._roots = []; + this._displayList = []; + this._displayListLen = 0; + return; + }; + + Storage.prototype.getRoots = function () { + return this._roots; + }; + + Storage.prototype.dispose = function () { + this._displayList = null; + this._roots = null; + }; + + return Storage; + }(); + + var requestAnimationFrame; + + requestAnimationFrame = env.hasGlobalWindow && (window.requestAnimationFrame && window.requestAnimationFrame.bind(window) || window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window) || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame) || function (func) { + return setTimeout(func, 16); + }; + + var requestAnimationFrame$1 = requestAnimationFrame; + var easingFuncs = { + linear: function (k) { + return k; + }, + quadraticIn: function (k) { + return k * k; + }, + quadraticOut: function (k) { + return k * (2 - k); + }, + quadraticInOut: function (k) { + if ((k *= 2) < 1) { + return 0.5 * k * k; + } + + return -0.5 * (--k * (k - 2) - 1); + }, + cubicIn: function (k) { + return k * k * k; + }, + cubicOut: function (k) { + return --k * k * k + 1; + }, + cubicInOut: function (k) { + if ((k *= 2) < 1) { + return 0.5 * k * k * k; + } + + return 0.5 * ((k -= 2) * k * k + 2); + }, + quarticIn: function (k) { + return k * k * k * k; + }, + quarticOut: function (k) { + return 1 - --k * k * k * k; + }, + quarticInOut: function (k) { + if ((k *= 2) < 1) { + return 0.5 * k * k * k * k; + } + + return -0.5 * ((k -= 2) * k * k * k - 2); + }, + quinticIn: function (k) { + return k * k * k * k * k; + }, + quinticOut: function (k) { + return --k * k * k * k * k + 1; + }, + quinticInOut: function (k) { + if ((k *= 2) < 1) { + return 0.5 * k * k * k * k * k; + } + + return 0.5 * ((k -= 2) * k * k * k * k + 2); + }, + sinusoidalIn: function (k) { + return 1 - Math.cos(k * Math.PI / 2); + }, + sinusoidalOut: function (k) { + return Math.sin(k * Math.PI / 2); + }, + sinusoidalInOut: function (k) { + return 0.5 * (1 - Math.cos(Math.PI * k)); + }, + exponentialIn: function (k) { + return k === 0 ? 0 : Math.pow(1024, k - 1); + }, + exponentialOut: function (k) { + return k === 1 ? 1 : 1 - Math.pow(2, -10 * k); + }, + exponentialInOut: function (k) { + if (k === 0) { + return 0; + } + + if (k === 1) { + return 1; + } + + if ((k *= 2) < 1) { + return 0.5 * Math.pow(1024, k - 1); + } + + return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2); + }, + circularIn: function (k) { + return 1 - Math.sqrt(1 - k * k); + }, + circularOut: function (k) { + return Math.sqrt(1 - --k * k); + }, + circularInOut: function (k) { + if ((k *= 2) < 1) { + return -0.5 * (Math.sqrt(1 - k * k) - 1); + } + + return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1); + }, + elasticIn: function (k) { + var s; + var a = 0.1; + var p = 0.4; + + if (k === 0) { + return 0; + } + + if (k === 1) { + return 1; + } + + if (!a || a < 1) { + a = 1; + s = p / 4; + } else { + s = p * Math.asin(1 / a) / (2 * Math.PI); + } + + return -(a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p)); + }, + elasticOut: function (k) { + var s; + var a = 0.1; + var p = 0.4; + + if (k === 0) { + return 0; + } + + if (k === 1) { + return 1; + } + + if (!a || a < 1) { + a = 1; + s = p / 4; + } else { + s = p * Math.asin(1 / a) / (2 * Math.PI); + } + + return a * Math.pow(2, -10 * k) * Math.sin((k - s) * (2 * Math.PI) / p) + 1; + }, + elasticInOut: function (k) { + var s; + var a = 0.1; + var p = 0.4; + + if (k === 0) { + return 0; + } + + if (k === 1) { + return 1; + } + + if (!a || a < 1) { + a = 1; + s = p / 4; + } else { + s = p * Math.asin(1 / a) / (2 * Math.PI); + } + + if ((k *= 2) < 1) { + return -0.5 * (a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p)); + } + + return a * Math.pow(2, -10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1; + }, + backIn: function (k) { + var s = 1.70158; + return k * k * ((s + 1) * k - s); + }, + backOut: function (k) { + var s = 1.70158; + return --k * k * ((s + 1) * k + s) + 1; + }, + backInOut: function (k) { + var s = 1.70158 * 1.525; + + if ((k *= 2) < 1) { + return 0.5 * (k * k * ((s + 1) * k - s)); + } + + return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2); + }, + bounceIn: function (k) { + return 1 - easingFuncs.bounceOut(1 - k); + }, + bounceOut: function (k) { + if (k < 1 / 2.75) { + return 7.5625 * k * k; + } else if (k < 2 / 2.75) { + return 7.5625 * (k -= 1.5 / 2.75) * k + 0.75; + } else if (k < 2.5 / 2.75) { + return 7.5625 * (k -= 2.25 / 2.75) * k + 0.9375; + } else { + return 7.5625 * (k -= 2.625 / 2.75) * k + 0.984375; + } + }, + bounceInOut: function (k) { + if (k < 0.5) { + return easingFuncs.bounceIn(k * 2) * 0.5; + } + + return easingFuncs.bounceOut(k * 2 - 1) * 0.5 + 0.5; + } + }; + var mathPow$1 = Math.pow; + var mathSqrt$3 = Math.sqrt; + var EPSILON$3 = 1e-8; + var EPSILON_NUMERIC = 1e-4; + var THREE_SQRT = mathSqrt$3(3); + var ONE_THIRD = 1 / 3; + + var _v0 = create$1(); + + var _v1 = create$1(); + + var _v2 = create$1(); + + function isAroundZero(val) { + return val > -EPSILON$3 && val < EPSILON$3; + } + + function isNotAroundZero$1(val) { + return val > EPSILON$3 || val < -EPSILON$3; + } + + function cubicAt(p0, p1, p2, p3, t) { + var onet = 1 - t; + return onet * onet * (onet * p0 + 3 * t * p1) + t * t * (t * p3 + 3 * onet * p2); + } + + function cubicDerivativeAt(p0, p1, p2, p3, t) { + var onet = 1 - t; + return 3 * (((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet + (p3 - p2) * t * t); + } + + function cubicRootAt(p0, p1, p2, p3, val, roots) { + var a = p3 + 3 * (p1 - p2) - p0; + var b = 3 * (p2 - p1 * 2 + p0); + var c = 3 * (p1 - p0); + var d = p0 - val; + var A = b * b - 3 * a * c; + var B = b * c - 9 * a * d; + var C = c * c - 3 * b * d; + var n = 0; + + if (isAroundZero(A) && isAroundZero(B)) { + if (isAroundZero(b)) { + roots[0] = 0; + } else { + var t1 = -c / b; + + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + } + } else { + var disc = B * B - 4 * A * C; + + if (isAroundZero(disc)) { + var K = B / A; + var t1 = -b / a + K; + var t2 = -K / 2; + + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + + if (t2 >= 0 && t2 <= 1) { + roots[n++] = t2; + } + } else if (disc > 0) { + var discSqrt = mathSqrt$3(disc); + var Y1 = A * b + 1.5 * a * (-B + discSqrt); + var Y2 = A * b + 1.5 * a * (-B - discSqrt); + + if (Y1 < 0) { + Y1 = -mathPow$1(-Y1, ONE_THIRD); + } else { + Y1 = mathPow$1(Y1, ONE_THIRD); + } + + if (Y2 < 0) { + Y2 = -mathPow$1(-Y2, ONE_THIRD); + } else { + Y2 = mathPow$1(Y2, ONE_THIRD); + } + + var t1 = (-b - (Y1 + Y2)) / (3 * a); + + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + } else { + var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt$3(A * A * A)); + var theta = Math.acos(T) / 3; + var ASqrt = mathSqrt$3(A); + var tmp = Math.cos(theta); + var t1 = (-b - 2 * ASqrt * tmp) / (3 * a); + var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a); + var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a); + + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + + if (t2 >= 0 && t2 <= 1) { + roots[n++] = t2; + } + + if (t3 >= 0 && t3 <= 1) { + roots[n++] = t3; + } + } + } + + return n; + } + + function cubicExtrema(p0, p1, p2, p3, extrema) { + var b = 6 * p2 - 12 * p1 + 6 * p0; + var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2; + var c = 3 * p1 - 3 * p0; + var n = 0; + + if (isAroundZero(a)) { + if (isNotAroundZero$1(b)) { + var t1 = -c / b; + + if (t1 >= 0 && t1 <= 1) { + extrema[n++] = t1; + } + } + } else { + var disc = b * b - 4 * a * c; + + if (isAroundZero(disc)) { + extrema[0] = -b / (2 * a); + } else if (disc > 0) { + var discSqrt = mathSqrt$3(disc); + var t1 = (-b + discSqrt) / (2 * a); + var t2 = (-b - discSqrt) / (2 * a); + + if (t1 >= 0 && t1 <= 1) { + extrema[n++] = t1; + } + + if (t2 >= 0 && t2 <= 1) { + extrema[n++] = t2; + } + } + } + + return n; + } + + function cubicSubdivide(p0, p1, p2, p3, t, out) { + var p01 = (p1 - p0) * t + p0; + var p12 = (p2 - p1) * t + p1; + var p23 = (p3 - p2) * t + p2; + var p012 = (p12 - p01) * t + p01; + var p123 = (p23 - p12) * t + p12; + var p0123 = (p123 - p012) * t + p012; + out[0] = p0; + out[1] = p01; + out[2] = p012; + out[3] = p0123; + out[4] = p0123; + out[5] = p123; + out[6] = p23; + out[7] = p3; + } + + function cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, out) { + var t; + var interval = 0.005; + var d = Infinity; + var prev; + var next; + var d1; + var d2; + _v0[0] = x; + _v0[1] = y; + + for (var _t = 0; _t < 1; _t += 0.05) { + _v1[0] = cubicAt(x0, x1, x2, x3, _t); + _v1[1] = cubicAt(y0, y1, y2, y3, _t); + d1 = distSquare(_v0, _v1); + + if (d1 < d) { + t = _t; + d = d1; + } + } + + d = Infinity; + + for (var i = 0; i < 32; i++) { + if (interval < EPSILON_NUMERIC) { + break; + } + + prev = t - interval; + next = t + interval; + _v1[0] = cubicAt(x0, x1, x2, x3, prev); + _v1[1] = cubicAt(y0, y1, y2, y3, prev); + d1 = distSquare(_v1, _v0); + + if (prev >= 0 && d1 < d) { + t = prev; + d = d1; + } else { + _v2[0] = cubicAt(x0, x1, x2, x3, next); + _v2[1] = cubicAt(y0, y1, y2, y3, next); + d2 = distSquare(_v2, _v0); + + if (next <= 1 && d2 < d) { + t = next; + d = d2; + } else { + interval *= 0.5; + } + } + } + + if (out) { + out[0] = cubicAt(x0, x1, x2, x3, t); + out[1] = cubicAt(y0, y1, y2, y3, t); + } + + return mathSqrt$3(d); + } + + function cubicLength(x0, y0, x1, y1, x2, y2, x3, y3, iteration) { + var px = x0; + var py = y0; + var d = 0; + var step = 1 / iteration; + + for (var i = 1; i <= iteration; i++) { + var t = i * step; + var x = cubicAt(x0, x1, x2, x3, t); + var y = cubicAt(y0, y1, y2, y3, t); + var dx = x - px; + var dy = y - py; + d += Math.sqrt(dx * dx + dy * dy); + px = x; + py = y; + } + + return d; + } + + function quadraticAt(p0, p1, p2, t) { + var onet = 1 - t; + return onet * (onet * p0 + 2 * t * p1) + t * t * p2; + } + + function quadraticDerivativeAt(p0, p1, p2, t) { + return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1)); + } + + function quadraticRootAt(p0, p1, p2, val, roots) { + var a = p0 - 2 * p1 + p2; + var b = 2 * (p1 - p0); + var c = p0 - val; + var n = 0; + + if (isAroundZero(a)) { + if (isNotAroundZero$1(b)) { + var t1 = -c / b; + + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + } + } else { + var disc = b * b - 4 * a * c; + + if (isAroundZero(disc)) { + var t1 = -b / (2 * a); + + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + } else if (disc > 0) { + var discSqrt = mathSqrt$3(disc); + var t1 = (-b + discSqrt) / (2 * a); + var t2 = (-b - discSqrt) / (2 * a); + + if (t1 >= 0 && t1 <= 1) { + roots[n++] = t1; + } + + if (t2 >= 0 && t2 <= 1) { + roots[n++] = t2; + } + } + } + + return n; + } + + function quadraticExtremum(p0, p1, p2) { + var divider = p0 + p2 - 2 * p1; + + if (divider === 0) { + return 0.5; + } else { + return (p0 - p1) / divider; + } + } + + function quadraticSubdivide(p0, p1, p2, t, out) { + var p01 = (p1 - p0) * t + p0; + var p12 = (p2 - p1) * t + p1; + var p012 = (p12 - p01) * t + p01; + out[0] = p0; + out[1] = p01; + out[2] = p012; + out[3] = p012; + out[4] = p12; + out[5] = p2; + } + + function quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, out) { + var t; + var interval = 0.005; + var d = Infinity; + _v0[0] = x; + _v0[1] = y; + + for (var _t = 0; _t < 1; _t += 0.05) { + _v1[0] = quadraticAt(x0, x1, x2, _t); + _v1[1] = quadraticAt(y0, y1, y2, _t); + var d1 = distSquare(_v0, _v1); + + if (d1 < d) { + t = _t; + d = d1; + } + } + + d = Infinity; + + for (var i = 0; i < 32; i++) { + if (interval < EPSILON_NUMERIC) { + break; + } + + var prev = t - interval; + var next = t + interval; + _v1[0] = quadraticAt(x0, x1, x2, prev); + _v1[1] = quadraticAt(y0, y1, y2, prev); + var d1 = distSquare(_v1, _v0); + + if (prev >= 0 && d1 < d) { + t = prev; + d = d1; + } else { + _v2[0] = quadraticAt(x0, x1, x2, next); + _v2[1] = quadraticAt(y0, y1, y2, next); + var d2 = distSquare(_v2, _v0); + + if (next <= 1 && d2 < d) { + t = next; + d = d2; + } else { + interval *= 0.5; + } + } + } + + if (out) { + out[0] = quadraticAt(x0, x1, x2, t); + out[1] = quadraticAt(y0, y1, y2, t); + } + + return mathSqrt$3(d); + } + + function quadraticLength(x0, y0, x1, y1, x2, y2, iteration) { + var px = x0; + var py = y0; + var d = 0; + var step = 1 / iteration; + + for (var i = 1; i <= iteration; i++) { + var t = i * step; + var x = quadraticAt(x0, x1, x2, t); + var y = quadraticAt(y0, y1, y2, t); + var dx = x - px; + var dy = y - py; + d += Math.sqrt(dx * dx + dy * dy); + px = x; + py = y; + } + + return d; + } + + var regexp = /cubic-bezier\(([0-9,\.e ]+)\)/; + + function createCubicEasingFunc(cubicEasingStr) { + var cubic = cubicEasingStr && regexp.exec(cubicEasingStr); + + if (cubic) { + var points = cubic[1].split(','); + var a_1 = +trim(points[0]); + var b_1 = +trim(points[1]); + var c_1 = +trim(points[2]); + var d_1 = +trim(points[3]); + + if (isNaN(a_1 + b_1 + c_1 + d_1)) { + return; + } + + var roots_1 = []; + return function (p) { + return p <= 0 ? 0 : p >= 1 ? 1 : cubicRootAt(0, a_1, c_1, 1, p, roots_1) && cubicAt(0, b_1, d_1, 1, roots_1[0]); + }; + } + } + + var Clip = function () { + function Clip(opts) { + this._inited = false; + this._startTime = 0; + this._pausedTime = 0; + this._paused = false; + this._life = opts.life || 1000; + this._delay = opts.delay || 0; + this.loop = opts.loop || false; + this.onframe = opts.onframe || noop; + this.ondestroy = opts.ondestroy || noop; + this.onrestart = opts.onrestart || noop; + opts.easing && this.setEasing(opts.easing); + } + + Clip.prototype.step = function (globalTime, deltaTime) { + if (!this._inited) { + this._startTime = globalTime + this._delay; + this._inited = true; + } + + if (this._paused) { + this._pausedTime += deltaTime; + return; + } + + var life = this._life; + var elapsedTime = globalTime - this._startTime - this._pausedTime; + var percent = elapsedTime / life; + + if (percent < 0) { + percent = 0; + } + + percent = Math.min(percent, 1); + var easingFunc = this.easingFunc; + var schedule = easingFunc ? easingFunc(percent) : percent; + this.onframe(schedule); + + if (percent === 1) { + if (this.loop) { + var remainder = elapsedTime % life; + this._startTime = globalTime - remainder; + this._pausedTime = 0; + this.onrestart(); + } else { + return true; + } + } + + return false; + }; + + Clip.prototype.pause = function () { + this._paused = true; + }; + + Clip.prototype.resume = function () { + this._paused = false; + }; + + Clip.prototype.setEasing = function (easing) { + this.easing = easing; + this.easingFunc = isFunction(easing) ? easing : easingFuncs[easing] || createCubicEasingFunc(easing); + }; + + return Clip; + }(); + + var Entry = function () { + function Entry(val) { + this.value = val; + } + + return Entry; + }(); + + var LinkedList = function () { + function LinkedList() { + this._len = 0; + } + + LinkedList.prototype.insert = function (val) { + var entry = new Entry(val); + this.insertEntry(entry); + return entry; + }; + + LinkedList.prototype.insertEntry = function (entry) { + if (!this.head) { + this.head = this.tail = entry; + } else { + this.tail.next = entry; + entry.prev = this.tail; + entry.next = null; + this.tail = entry; + } + + this._len++; + }; + + LinkedList.prototype.remove = function (entry) { + var prev = entry.prev; + var next = entry.next; + + if (prev) { + prev.next = next; + } else { + this.head = next; + } + + if (next) { + next.prev = prev; + } else { + this.tail = prev; + } + + entry.next = entry.prev = null; + this._len--; + }; + + LinkedList.prototype.len = function () { + return this._len; + }; + + LinkedList.prototype.clear = function () { + this.head = this.tail = null; + this._len = 0; + }; + + return LinkedList; + }(); + + var LRU = function () { + function LRU(maxSize) { + this._list = new LinkedList(); + this._maxSize = 10; + this._map = {}; + this._maxSize = maxSize; + } + + LRU.prototype.put = function (key, value) { + var list = this._list; + var map = this._map; + var removed = null; + + if (map[key] == null) { + var len = list.len(); + var entry = this._lastRemovedEntry; + + if (len >= this._maxSize && len > 0) { + var leastUsedEntry = list.head; + list.remove(leastUsedEntry); + delete map[leastUsedEntry.key]; + removed = leastUsedEntry.value; + this._lastRemovedEntry = leastUsedEntry; + } + + if (entry) { + entry.value = value; + } else { + entry = new Entry(value); + } + + entry.key = key; + list.insertEntry(entry); + map[key] = entry; + } + + return removed; + }; + + LRU.prototype.get = function (key) { + var entry = this._map[key]; + var list = this._list; + + if (entry != null) { + if (entry !== list.tail) { + list.remove(entry); + list.insertEntry(entry); + } + + return entry.value; + } + }; + + LRU.prototype.clear = function () { + this._list.clear(); + + this._map = {}; + }; + + LRU.prototype.len = function () { + return this._list.len(); + }; + + return LRU; + }(); + + var kCSSColorTable = { + 'transparent': [0, 0, 0, 0], + 'aliceblue': [240, 248, 255, 1], + 'antiquewhite': [250, 235, 215, 1], + 'aqua': [0, 255, 255, 1], + 'aquamarine': [127, 255, 212, 1], + 'azure': [240, 255, 255, 1], + 'beige': [245, 245, 220, 1], + 'bisque': [255, 228, 196, 1], + 'black': [0, 0, 0, 1], + 'blanchedalmond': [255, 235, 205, 1], + 'blue': [0, 0, 255, 1], + 'blueviolet': [138, 43, 226, 1], + 'brown': [165, 42, 42, 1], + 'burlywood': [222, 184, 135, 1], + 'cadetblue': [95, 158, 160, 1], + 'chartreuse': [127, 255, 0, 1], + 'chocolate': [210, 105, 30, 1], + 'coral': [255, 127, 80, 1], + 'cornflowerblue': [100, 149, 237, 1], + 'cornsilk': [255, 248, 220, 1], + 'crimson': [220, 20, 60, 1], + 'cyan': [0, 255, 255, 1], + 'darkblue': [0, 0, 139, 1], + 'darkcyan': [0, 139, 139, 1], + 'darkgoldenrod': [184, 134, 11, 1], + 'darkgray': [169, 169, 169, 1], + 'darkgreen': [0, 100, 0, 1], + 'darkgrey': [169, 169, 169, 1], + 'darkkhaki': [189, 183, 107, 1], + 'darkmagenta': [139, 0, 139, 1], + 'darkolivegreen': [85, 107, 47, 1], + 'darkorange': [255, 140, 0, 1], + 'darkorchid': [153, 50, 204, 1], + 'darkred': [139, 0, 0, 1], + 'darksalmon': [233, 150, 122, 1], + 'darkseagreen': [143, 188, 143, 1], + 'darkslateblue': [72, 61, 139, 1], + 'darkslategray': [47, 79, 79, 1], + 'darkslategrey': [47, 79, 79, 1], + 'darkturquoise': [0, 206, 209, 1], + 'darkviolet': [148, 0, 211, 1], + 'deeppink': [255, 20, 147, 1], + 'deepskyblue': [0, 191, 255, 1], + 'dimgray': [105, 105, 105, 1], + 'dimgrey': [105, 105, 105, 1], + 'dodgerblue': [30, 144, 255, 1], + 'firebrick': [178, 34, 34, 1], + 'floralwhite': [255, 250, 240, 1], + 'forestgreen': [34, 139, 34, 1], + 'fuchsia': [255, 0, 255, 1], + 'gainsboro': [220, 220, 220, 1], + 'ghostwhite': [248, 248, 255, 1], + 'gold': [255, 215, 0, 1], + 'goldenrod': [218, 165, 32, 1], + 'gray': [128, 128, 128, 1], + 'green': [0, 128, 0, 1], + 'greenyellow': [173, 255, 47, 1], + 'grey': [128, 128, 128, 1], + 'honeydew': [240, 255, 240, 1], + 'hotpink': [255, 105, 180, 1], + 'indianred': [205, 92, 92, 1], + 'indigo': [75, 0, 130, 1], + 'ivory': [255, 255, 240, 1], + 'khaki': [240, 230, 140, 1], + 'lavender': [230, 230, 250, 1], + 'lavenderblush': [255, 240, 245, 1], + 'lawngreen': [124, 252, 0, 1], + 'lemonchiffon': [255, 250, 205, 1], + 'lightblue': [173, 216, 230, 1], + 'lightcoral': [240, 128, 128, 1], + 'lightcyan': [224, 255, 255, 1], + 'lightgoldenrodyellow': [250, 250, 210, 1], + 'lightgray': [211, 211, 211, 1], + 'lightgreen': [144, 238, 144, 1], + 'lightgrey': [211, 211, 211, 1], + 'lightpink': [255, 182, 193, 1], + 'lightsalmon': [255, 160, 122, 1], + 'lightseagreen': [32, 178, 170, 1], + 'lightskyblue': [135, 206, 250, 1], + 'lightslategray': [119, 136, 153, 1], + 'lightslategrey': [119, 136, 153, 1], + 'lightsteelblue': [176, 196, 222, 1], + 'lightyellow': [255, 255, 224, 1], + 'lime': [0, 255, 0, 1], + 'limegreen': [50, 205, 50, 1], + 'linen': [250, 240, 230, 1], + 'magenta': [255, 0, 255, 1], + 'maroon': [128, 0, 0, 1], + 'mediumaquamarine': [102, 205, 170, 1], + 'mediumblue': [0, 0, 205, 1], + 'mediumorchid': [186, 85, 211, 1], + 'mediumpurple': [147, 112, 219, 1], + 'mediumseagreen': [60, 179, 113, 1], + 'mediumslateblue': [123, 104, 238, 1], + 'mediumspringgreen': [0, 250, 154, 1], + 'mediumturquoise': [72, 209, 204, 1], + 'mediumvioletred': [199, 21, 133, 1], + 'midnightblue': [25, 25, 112, 1], + 'mintcream': [245, 255, 250, 1], + 'mistyrose': [255, 228, 225, 1], + 'moccasin': [255, 228, 181, 1], + 'navajowhite': [255, 222, 173, 1], + 'navy': [0, 0, 128, 1], + 'oldlace': [253, 245, 230, 1], + 'olive': [128, 128, 0, 1], + 'olivedrab': [107, 142, 35, 1], + 'orange': [255, 165, 0, 1], + 'orangered': [255, 69, 0, 1], + 'orchid': [218, 112, 214, 1], + 'palegoldenrod': [238, 232, 170, 1], + 'palegreen': [152, 251, 152, 1], + 'paleturquoise': [175, 238, 238, 1], + 'palevioletred': [219, 112, 147, 1], + 'papayawhip': [255, 239, 213, 1], + 'peachpuff': [255, 218, 185, 1], + 'peru': [205, 133, 63, 1], + 'pink': [255, 192, 203, 1], + 'plum': [221, 160, 221, 1], + 'powderblue': [176, 224, 230, 1], + 'purple': [128, 0, 128, 1], + 'red': [255, 0, 0, 1], + 'rosybrown': [188, 143, 143, 1], + 'royalblue': [65, 105, 225, 1], + 'saddlebrown': [139, 69, 19, 1], + 'salmon': [250, 128, 114, 1], + 'sandybrown': [244, 164, 96, 1], + 'seagreen': [46, 139, 87, 1], + 'seashell': [255, 245, 238, 1], + 'sienna': [160, 82, 45, 1], + 'silver': [192, 192, 192, 1], + 'skyblue': [135, 206, 235, 1], + 'slateblue': [106, 90, 205, 1], + 'slategray': [112, 128, 144, 1], + 'slategrey': [112, 128, 144, 1], + 'snow': [255, 250, 250, 1], + 'springgreen': [0, 255, 127, 1], + 'steelblue': [70, 130, 180, 1], + 'tan': [210, 180, 140, 1], + 'teal': [0, 128, 128, 1], + 'thistle': [216, 191, 216, 1], + 'tomato': [255, 99, 71, 1], + 'turquoise': [64, 224, 208, 1], + 'violet': [238, 130, 238, 1], + 'wheat': [245, 222, 179, 1], + 'white': [255, 255, 255, 1], + 'whitesmoke': [245, 245, 245, 1], + 'yellow': [255, 255, 0, 1], + 'yellowgreen': [154, 205, 50, 1] + }; + + function clampCssByte(i) { + i = Math.round(i); + return i < 0 ? 0 : i > 255 ? 255 : i; + } + + function clampCssAngle(i) { + i = Math.round(i); + return i < 0 ? 0 : i > 360 ? 360 : i; + } + + function clampCssFloat(f) { + return f < 0 ? 0 : f > 1 ? 1 : f; + } + + function parseCssInt(val) { + var str = val; + + if (str.length && str.charAt(str.length - 1) === '%') { + return clampCssByte(parseFloat(str) / 100 * 255); + } + + return clampCssByte(parseInt(str, 10)); + } + + function parseCssFloat(val) { + var str = val; + + if (str.length && str.charAt(str.length - 1) === '%') { + return clampCssFloat(parseFloat(str) / 100); + } + + return clampCssFloat(parseFloat(str)); + } + + function cssHueToRgb(m1, m2, h) { + if (h < 0) { + h += 1; + } else if (h > 1) { + h -= 1; + } + + if (h * 6 < 1) { + return m1 + (m2 - m1) * h * 6; + } + + if (h * 2 < 1) { + return m2; + } + + if (h * 3 < 2) { + return m1 + (m2 - m1) * (2 / 3 - h) * 6; + } + + return m1; + } + + function lerpNumber(a, b, p) { + return a + (b - a) * p; + } + + function setRgba(out, r, g, b, a) { + out[0] = r; + out[1] = g; + out[2] = b; + out[3] = a; + return out; + } + + function copyRgba(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; + } + + var colorCache = new LRU(20); + var lastRemovedArr = null; + + function putToCache(colorStr, rgbaArr) { + if (lastRemovedArr) { + copyRgba(lastRemovedArr, rgbaArr); + } + + lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || rgbaArr.slice()); + } + + function parse(colorStr, rgbaArr) { + if (!colorStr) { + return; + } + + rgbaArr = rgbaArr || []; + var cached = colorCache.get(colorStr); + + if (cached) { + return copyRgba(rgbaArr, cached); + } + + colorStr = colorStr + ''; + var str = colorStr.replace(/ /g, '').toLowerCase(); + + if (str in kCSSColorTable) { + copyRgba(rgbaArr, kCSSColorTable[str]); + putToCache(colorStr, rgbaArr); + return rgbaArr; + } + + var strLen = str.length; + + if (str.charAt(0) === '#') { + if (strLen === 4 || strLen === 5) { + var iv = parseInt(str.slice(1, 4), 16); + + if (!(iv >= 0 && iv <= 0xfff)) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + + setRgba(rgbaArr, (iv & 0xf00) >> 4 | (iv & 0xf00) >> 8, iv & 0xf0 | (iv & 0xf0) >> 4, iv & 0xf | (iv & 0xf) << 4, strLen === 5 ? parseInt(str.slice(4), 16) / 0xf : 1); + putToCache(colorStr, rgbaArr); + return rgbaArr; + } else if (strLen === 7 || strLen === 9) { + var iv = parseInt(str.slice(1, 7), 16); + + if (!(iv >= 0 && iv <= 0xffffff)) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + + setRgba(rgbaArr, (iv & 0xff0000) >> 16, (iv & 0xff00) >> 8, iv & 0xff, strLen === 9 ? parseInt(str.slice(7), 16) / 0xff : 1); + putToCache(colorStr, rgbaArr); + return rgbaArr; + } + + return; + } + + var op = str.indexOf('('); + var ep = str.indexOf(')'); + + if (op !== -1 && ep + 1 === strLen) { + var fname = str.substr(0, op); + var params = str.substr(op + 1, ep - (op + 1)).split(','); + var alpha = 1; + + switch (fname) { + case 'rgba': + if (params.length !== 4) { + return params.length === 3 ? setRgba(rgbaArr, +params[0], +params[1], +params[2], 1) : setRgba(rgbaArr, 0, 0, 0, 1); + } + + alpha = parseCssFloat(params.pop()); + + case 'rgb': + if (params.length >= 3) { + setRgba(rgbaArr, parseCssInt(params[0]), parseCssInt(params[1]), parseCssInt(params[2]), params.length === 3 ? alpha : parseCssFloat(params[3])); + putToCache(colorStr, rgbaArr); + return rgbaArr; + } else { + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + + case 'hsla': + if (params.length !== 4) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + + params[3] = parseCssFloat(params[3]); + hsla2rgba(params, rgbaArr); + putToCache(colorStr, rgbaArr); + return rgbaArr; + + case 'hsl': + if (params.length !== 3) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + + hsla2rgba(params, rgbaArr); + putToCache(colorStr, rgbaArr); + return rgbaArr; + + default: + return; + } + } + + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + + function hsla2rgba(hsla, rgba) { + var h = (parseFloat(hsla[0]) % 360 + 360) % 360 / 360; + var s = parseCssFloat(hsla[1]); + var l = parseCssFloat(hsla[2]); + var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; + var m1 = l * 2 - m2; + rgba = rgba || []; + setRgba(rgba, clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255), clampCssByte(cssHueToRgb(m1, m2, h) * 255), clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255), 1); + + if (hsla.length === 4) { + rgba[3] = hsla[3]; + } + + return rgba; + } + + function rgba2hsla(rgba) { + if (!rgba) { + return; + } + + var R = rgba[0] / 255; + var G = rgba[1] / 255; + var B = rgba[2] / 255; + var vMin = Math.min(R, G, B); + var vMax = Math.max(R, G, B); + var delta = vMax - vMin; + var L = (vMax + vMin) / 2; + var H; + var S; + + if (delta === 0) { + H = 0; + S = 0; + } else { + if (L < 0.5) { + S = delta / (vMax + vMin); + } else { + S = delta / (2 - vMax - vMin); + } + + var deltaR = ((vMax - R) / 6 + delta / 2) / delta; + var deltaG = ((vMax - G) / 6 + delta / 2) / delta; + var deltaB = ((vMax - B) / 6 + delta / 2) / delta; + + if (R === vMax) { + H = deltaB - deltaG; + } else if (G === vMax) { + H = 1 / 3 + deltaR - deltaB; + } else if (B === vMax) { + H = 2 / 3 + deltaG - deltaR; + } + + if (H < 0) { + H += 1; + } + + if (H > 1) { + H -= 1; + } + } + + var hsla = [H * 360, S, L]; + + if (rgba[3] != null) { + hsla.push(rgba[3]); + } + + return hsla; + } + + function lift(color, level) { + var colorArr = parse(color); + + if (colorArr) { + for (var i = 0; i < 3; i++) { + if (level < 0) { + colorArr[i] = colorArr[i] * (1 - level) | 0; + } else { + colorArr[i] = (255 - colorArr[i]) * level + colorArr[i] | 0; + } + + if (colorArr[i] > 255) { + colorArr[i] = 255; + } else if (colorArr[i] < 0) { + colorArr[i] = 0; + } + } + + return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb'); + } + } + + function toHex(color) { + var colorArr = parse(color); + + if (colorArr) { + return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + +colorArr[2]).toString(16).slice(1); + } + } + + function fastLerp(normalizedValue, colors, out) { + if (!(colors && colors.length) || !(normalizedValue >= 0 && normalizedValue <= 1)) { + return; + } + + out = out || []; + var value = normalizedValue * (colors.length - 1); + var leftIndex = Math.floor(value); + var rightIndex = Math.ceil(value); + var leftColor = colors[leftIndex]; + var rightColor = colors[rightIndex]; + var dv = value - leftIndex; + out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)); + out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)); + out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)); + out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv)); + return out; + } + + var fastMapToColor = fastLerp; + + function lerp(normalizedValue, colors, fullOutput) { + if (!(colors && colors.length) || !(normalizedValue >= 0 && normalizedValue <= 1)) { + return; + } + + var value = normalizedValue * (colors.length - 1); + var leftIndex = Math.floor(value); + var rightIndex = Math.ceil(value); + var leftColor = parse(colors[leftIndex]); + var rightColor = parse(colors[rightIndex]); + var dv = value - leftIndex; + var color = stringify([clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)), clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)), clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)), clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv))], 'rgba'); + return fullOutput ? { + color: color, + leftIndex: leftIndex, + rightIndex: rightIndex, + value: value + } : color; + } + + var mapToColor = lerp; + + function modifyHSL(color, h, s, l) { + var colorArr = parse(color); + + if (color) { + colorArr = rgba2hsla(colorArr); + h != null && (colorArr[0] = clampCssAngle(isFunction(h) ? h(colorArr[0]) : h)); + s != null && (colorArr[1] = parseCssFloat(isFunction(s) ? s(colorArr[1]) : s)); + l != null && (colorArr[2] = parseCssFloat(isFunction(l) ? l(colorArr[2]) : l)); + return stringify(hsla2rgba(colorArr), 'rgba'); + } + } + + function modifyAlpha(color, alpha) { + var colorArr = parse(color); + + if (colorArr && alpha != null) { + colorArr[3] = clampCssFloat(alpha); + return stringify(colorArr, 'rgba'); + } + } + + function stringify(arrColor, type) { + if (!arrColor || !arrColor.length) { + return; + } + + var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2]; + + if (type === 'rgba' || type === 'hsva' || type === 'hsla') { + colorStr += ',' + arrColor[3]; + } + + return type + '(' + colorStr + ')'; + } + + function lum(color, backgroundLum) { + var arr = parse(color); + return arr ? (0.299 * arr[0] + 0.587 * arr[1] + 0.114 * arr[2]) * arr[3] / 255 + (1 - arr[3]) * backgroundLum : 0; + } + + function random() { + return stringify([Math.round(Math.random() * 255), Math.round(Math.random() * 255), Math.round(Math.random() * 255)], 'rgb'); + } + + var liftedColorCache = new LRU(100); + + function liftColor(color) { + if (isString(color)) { + var liftedColor = liftedColorCache.get(color); + + if (!liftedColor) { + liftedColor = lift(color, -0.1); + liftedColorCache.put(color, liftedColor); + } + + return liftedColor; + } else if (isGradientObject(color)) { + var ret = extend({}, color); + ret.colorStops = map$1(color.colorStops, function (stop) { + return { + offset: stop.offset, + color: lift(stop.color, -0.1) + }; + }); + return ret; + } + + return color; + } + + var color$2 = /*#__PURE__*/Object.freeze({ + __proto__: null, + fastLerp: fastLerp, + fastMapToColor: fastMapToColor, + lerp: lerp, + lift: lift, + liftColor: liftColor, + lum: lum, + mapToColor: mapToColor, + modifyAlpha: modifyAlpha, + modifyHSL: modifyHSL, + parse: parse, + parseCssFloat: parseCssFloat, + parseCssInt: parseCssInt, + random: random, + stringify: stringify, + toHex: toHex + }); + + function isLinearGradient(val) { + return val.type === 'linear'; + } + + function isRadialGradient(val) { + return val.type === 'radial'; + } + + (function () { + if (env.hasGlobalWindow && isFunction(window.btoa)) { + return function (str) { + return window.btoa(unescape(encodeURIComponent(str))); + }; + } + + if (typeof Buffer !== 'undefined') { + return function (str) { + return Buffer.from(str).toString('base64'); + }; + } + + return function (str) { + { + logError('Base64 isn\'t natively supported in the current environment.'); + } + return null; + }; + })(); + + var arraySlice = Array.prototype.slice; + + function interpolateNumber$1(p0, p1, percent) { + return (p1 - p0) * percent + p0; + } + + function interpolate1DArray(out, p0, p1, percent) { + var len = p0.length; + + for (var i = 0; i < len; i++) { + out[i] = interpolateNumber$1(p0[i], p1[i], percent); + } + + return out; + } + + function interpolate2DArray(out, p0, p1, percent) { + var len = p0.length; + var len2 = len && p0[0].length; + + for (var i = 0; i < len; i++) { + if (!out[i]) { + out[i] = []; + } + + for (var j = 0; j < len2; j++) { + out[i][j] = interpolateNumber$1(p0[i][j], p1[i][j], percent); + } + } + + return out; + } + + function add1DArray(out, p0, p1, sign) { + var len = p0.length; + + for (var i = 0; i < len; i++) { + out[i] = p0[i] + p1[i] * sign; + } + + return out; + } + + function add2DArray(out, p0, p1, sign) { + var len = p0.length; + var len2 = len && p0[0].length; + + for (var i = 0; i < len; i++) { + if (!out[i]) { + out[i] = []; + } + + for (var j = 0; j < len2; j++) { + out[i][j] = p0[i][j] + p1[i][j] * sign; + } + } + + return out; + } + + function fillColorStops(val0, val1) { + var len0 = val0.length; + var len1 = val1.length; + var shorterArr = len0 > len1 ? val1 : val0; + var shorterLen = Math.min(len0, len1); + var last = shorterArr[shorterLen - 1] || { + color: [0, 0, 0, 0], + offset: 0 + }; + + for (var i = shorterLen; i < Math.max(len0, len1); i++) { + shorterArr.push({ + offset: last.offset, + color: last.color.slice() + }); + } + } + + function fillArray(val0, val1, arrDim) { + var arr0 = val0; + var arr1 = val1; + + if (!arr0.push || !arr1.push) { + return; + } + + var arr0Len = arr0.length; + var arr1Len = arr1.length; + + if (arr0Len !== arr1Len) { + var isPreviousLarger = arr0Len > arr1Len; + + if (isPreviousLarger) { + arr0.length = arr1Len; + } else { + for (var i = arr0Len; i < arr1Len; i++) { + arr0.push(arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])); + } + } + } + + var len2 = arr0[0] && arr0[0].length; + + for (var i = 0; i < arr0.length; i++) { + if (arrDim === 1) { + if (isNaN(arr0[i])) { + arr0[i] = arr1[i]; + } + } else { + for (var j = 0; j < len2; j++) { + if (isNaN(arr0[i][j])) { + arr0[i][j] = arr1[i][j]; + } + } + } + } + } + + function cloneValue(value) { + if (isArrayLike(value)) { + var len = value.length; + + if (isArrayLike(value[0])) { + var ret = []; + + for (var i = 0; i < len; i++) { + ret.push(arraySlice.call(value[i])); + } + + return ret; + } + + return arraySlice.call(value); + } + + return value; + } + + function rgba2String(rgba) { + rgba[0] = Math.floor(rgba[0]) || 0; + rgba[1] = Math.floor(rgba[1]) || 0; + rgba[2] = Math.floor(rgba[2]) || 0; + rgba[3] = rgba[3] == null ? 1 : rgba[3]; + return 'rgba(' + rgba.join(',') + ')'; + } + + function guessArrayDim(value) { + return isArrayLike(value && value[0]) ? 2 : 1; + } + + var VALUE_TYPE_NUMBER = 0; + var VALUE_TYPE_1D_ARRAY = 1; + var VALUE_TYPE_2D_ARRAY = 2; + var VALUE_TYPE_COLOR = 3; + var VALUE_TYPE_LINEAR_GRADIENT = 4; + var VALUE_TYPE_RADIAL_GRADIENT = 5; + var VALUE_TYPE_UNKOWN = 6; + + function isGradientValueType(valType) { + return valType === VALUE_TYPE_LINEAR_GRADIENT || valType === VALUE_TYPE_RADIAL_GRADIENT; + } + + function isArrayValueType(valType) { + return valType === VALUE_TYPE_1D_ARRAY || valType === VALUE_TYPE_2D_ARRAY; + } + + var tmpRgba = [0, 0, 0, 0]; + + var Track = function () { + function Track(propName) { + this.keyframes = []; + this.discrete = false; + this._invalid = false; + this._needsSort = false; + this._lastFr = 0; + this._lastFrP = 0; + this.propName = propName; + } + + Track.prototype.isFinished = function () { + return this._finished; + }; + + Track.prototype.setFinished = function () { + this._finished = true; + + if (this._additiveTrack) { + this._additiveTrack.setFinished(); + } + }; + + Track.prototype.needsAnimate = function () { + return this.keyframes.length >= 1; + }; + + Track.prototype.getAdditiveTrack = function () { + return this._additiveTrack; + }; + + Track.prototype.addKeyframe = function (time, rawValue, easing) { + this._needsSort = true; + var keyframes = this.keyframes; + var len = keyframes.length; + var discrete = false; + var valType = VALUE_TYPE_UNKOWN; + var value = rawValue; + + if (isArrayLike(rawValue)) { + var arrayDim = guessArrayDim(rawValue); + valType = arrayDim; + + if (arrayDim === 1 && !isNumber(rawValue[0]) || arrayDim === 2 && !isNumber(rawValue[0][0])) { + discrete = true; + } + } else { + if (isNumber(rawValue) && !eqNaN(rawValue)) { + valType = VALUE_TYPE_NUMBER; + } else if (isString(rawValue)) { + if (!isNaN(+rawValue)) { + valType = VALUE_TYPE_NUMBER; + } else { + var colorArray = parse(rawValue); + + if (colorArray) { + value = colorArray; + valType = VALUE_TYPE_COLOR; + } + } + } else if (isGradientObject(rawValue)) { + var parsedGradient = extend({}, value); + parsedGradient.colorStops = map$1(rawValue.colorStops, function (colorStop) { + return { + offset: colorStop.offset, + color: parse(colorStop.color) + }; + }); + + if (isLinearGradient(rawValue)) { + valType = VALUE_TYPE_LINEAR_GRADIENT; + } else if (isRadialGradient(rawValue)) { + valType = VALUE_TYPE_RADIAL_GRADIENT; + } + + value = parsedGradient; + } + } + + if (len === 0) { + this.valType = valType; + } else if (valType !== this.valType || valType === VALUE_TYPE_UNKOWN) { + discrete = true; + } + + this.discrete = this.discrete || discrete; + var kf = { + time: time, + value: value, + rawValue: rawValue, + percent: 0 + }; + + if (easing) { + kf.easing = easing; + kf.easingFunc = isFunction(easing) ? easing : easingFuncs[easing] || createCubicEasingFunc(easing); + } + + keyframes.push(kf); + return kf; + }; + + Track.prototype.prepare = function (maxTime, additiveTrack) { + var kfs = this.keyframes; + + if (this._needsSort) { + kfs.sort(function (a, b) { + return a.time - b.time; + }); + } + + var valType = this.valType; + var kfsLen = kfs.length; + var lastKf = kfs[kfsLen - 1]; + var isDiscrete = this.discrete; + var isArr = isArrayValueType(valType); + var isGradient = isGradientValueType(valType); + + for (var i = 0; i < kfsLen; i++) { + var kf = kfs[i]; + var value = kf.value; + var lastValue = lastKf.value; + kf.percent = kf.time / maxTime; + + if (!isDiscrete) { + if (isArr && i !== kfsLen - 1) { + fillArray(value, lastValue, valType); + } else if (isGradient) { + fillColorStops(value.colorStops, lastValue.colorStops); + } + } + } + + if (!isDiscrete && valType !== VALUE_TYPE_RADIAL_GRADIENT && additiveTrack && this.needsAnimate() && additiveTrack.needsAnimate() && valType === additiveTrack.valType && !additiveTrack._finished) { + this._additiveTrack = additiveTrack; + var startValue = kfs[0].value; + + for (var i = 0; i < kfsLen; i++) { + if (valType === VALUE_TYPE_NUMBER) { + kfs[i].additiveValue = kfs[i].value - startValue; + } else if (valType === VALUE_TYPE_COLOR) { + kfs[i].additiveValue = add1DArray([], kfs[i].value, startValue, -1); + } else if (isArrayValueType(valType)) { + kfs[i].additiveValue = valType === VALUE_TYPE_1D_ARRAY ? add1DArray([], kfs[i].value, startValue, -1) : add2DArray([], kfs[i].value, startValue, -1); + } + } + } + }; + + Track.prototype.step = function (target, percent) { + if (this._finished) { + return; + } + + if (this._additiveTrack && this._additiveTrack._finished) { + this._additiveTrack = null; + } + + var isAdditive = this._additiveTrack != null; + var valueKey = isAdditive ? 'additiveValue' : 'value'; + var valType = this.valType; + var keyframes = this.keyframes; + var kfsNum = keyframes.length; + var propName = this.propName; + var isValueColor = valType === VALUE_TYPE_COLOR; + var frameIdx; + var lastFrame = this._lastFr; + var mathMin = Math.min; + var frame; + var nextFrame; + + if (kfsNum === 1) { + frame = nextFrame = keyframes[0]; + } else { + if (percent < 0) { + frameIdx = 0; + } else if (percent < this._lastFrP) { + var start = mathMin(lastFrame + 1, kfsNum - 1); + + for (frameIdx = start; frameIdx >= 0; frameIdx--) { + if (keyframes[frameIdx].percent <= percent) { + break; + } + } + + frameIdx = mathMin(frameIdx, kfsNum - 2); + } else { + for (frameIdx = lastFrame; frameIdx < kfsNum; frameIdx++) { + if (keyframes[frameIdx].percent > percent) { + break; + } + } + + frameIdx = mathMin(frameIdx - 1, kfsNum - 2); + } + + nextFrame = keyframes[frameIdx + 1]; + frame = keyframes[frameIdx]; + } + + if (!(frame && nextFrame)) { + return; + } + + this._lastFr = frameIdx; + this._lastFrP = percent; + var interval = nextFrame.percent - frame.percent; + var w = interval === 0 ? 1 : mathMin((percent - frame.percent) / interval, 1); + + if (nextFrame.easingFunc) { + w = nextFrame.easingFunc(w); + } + + var targetArr = isAdditive ? this._additiveValue : isValueColor ? tmpRgba : target[propName]; + + if ((isArrayValueType(valType) || isValueColor) && !targetArr) { + targetArr = this._additiveValue = []; + } + + if (this.discrete) { + target[propName] = w < 1 ? frame.rawValue : nextFrame.rawValue; + } else if (isArrayValueType(valType)) { + valType === VALUE_TYPE_1D_ARRAY ? interpolate1DArray(targetArr, frame[valueKey], nextFrame[valueKey], w) : interpolate2DArray(targetArr, frame[valueKey], nextFrame[valueKey], w); + } else if (isGradientValueType(valType)) { + var val = frame[valueKey]; + var nextVal_1 = nextFrame[valueKey]; + var isLinearGradient_1 = valType === VALUE_TYPE_LINEAR_GRADIENT; + target[propName] = { + type: isLinearGradient_1 ? 'linear' : 'radial', + x: interpolateNumber$1(val.x, nextVal_1.x, w), + y: interpolateNumber$1(val.y, nextVal_1.y, w), + colorStops: map$1(val.colorStops, function (colorStop, idx) { + var nextColorStop = nextVal_1.colorStops[idx]; + return { + offset: interpolateNumber$1(colorStop.offset, nextColorStop.offset, w), + color: rgba2String(interpolate1DArray([], colorStop.color, nextColorStop.color, w)) + }; + }), + global: nextVal_1.global + }; + + if (isLinearGradient_1) { + target[propName].x2 = interpolateNumber$1(val.x2, nextVal_1.x2, w); + target[propName].y2 = interpolateNumber$1(val.y2, nextVal_1.y2, w); + } else { + target[propName].r = interpolateNumber$1(val.r, nextVal_1.r, w); + } + } else if (isValueColor) { + interpolate1DArray(targetArr, frame[valueKey], nextFrame[valueKey], w); + + if (!isAdditive) { + target[propName] = rgba2String(targetArr); + } + } else { + var value = interpolateNumber$1(frame[valueKey], nextFrame[valueKey], w); + + if (isAdditive) { + this._additiveValue = value; + } else { + target[propName] = value; + } + } + + if (isAdditive) { + this._addToTarget(target); + } + }; + + Track.prototype._addToTarget = function (target) { + var valType = this.valType; + var propName = this.propName; + var additiveValue = this._additiveValue; + + if (valType === VALUE_TYPE_NUMBER) { + target[propName] = target[propName] + additiveValue; + } else if (valType === VALUE_TYPE_COLOR) { + parse(target[propName], tmpRgba); + add1DArray(tmpRgba, tmpRgba, additiveValue, 1); + target[propName] = rgba2String(tmpRgba); + } else if (valType === VALUE_TYPE_1D_ARRAY) { + add1DArray(target[propName], target[propName], additiveValue, 1); + } else if (valType === VALUE_TYPE_2D_ARRAY) { + add2DArray(target[propName], target[propName], additiveValue, 1); + } + }; + + return Track; + }(); + + var Animator = function () { + function Animator(target, loop, allowDiscreteAnimation, additiveTo) { + this._tracks = {}; + this._trackKeys = []; + this._maxTime = 0; + this._started = 0; + this._clip = null; + this._target = target; + this._loop = loop; + + if (loop && additiveTo) { + logError('Can\' use additive animation on looped animation.'); + return; + } + + this._additiveAnimators = additiveTo; + this._allowDiscrete = allowDiscreteAnimation; + } + + Animator.prototype.getMaxTime = function () { + return this._maxTime; + }; + + Animator.prototype.getDelay = function () { + return this._delay; + }; + + Animator.prototype.getLoop = function () { + return this._loop; + }; + + Animator.prototype.getTarget = function () { + return this._target; + }; + + Animator.prototype.changeTarget = function (target) { + this._target = target; + }; + + Animator.prototype.when = function (time, props, easing) { + return this.whenWithKeys(time, props, keys(props), easing); + }; + + Animator.prototype.whenWithKeys = function (time, props, propNames, easing) { + var tracks = this._tracks; + + for (var i = 0; i < propNames.length; i++) { + var propName = propNames[i]; + var track = tracks[propName]; + + if (!track) { + track = tracks[propName] = new Track(propName); + var initialValue = void 0; + + var additiveTrack = this._getAdditiveTrack(propName); + + if (additiveTrack) { + var addtiveTrackKfs = additiveTrack.keyframes; + var lastFinalKf = addtiveTrackKfs[addtiveTrackKfs.length - 1]; + initialValue = lastFinalKf && lastFinalKf.value; + + if (additiveTrack.valType === VALUE_TYPE_COLOR && initialValue) { + initialValue = rgba2String(initialValue); + } + } else { + initialValue = this._target[propName]; + } + + if (initialValue == null) { + continue; + } + + if (time > 0) { + track.addKeyframe(0, cloneValue(initialValue), easing); + } + + this._trackKeys.push(propName); + } + + track.addKeyframe(time, cloneValue(props[propName]), easing); + } + + this._maxTime = Math.max(this._maxTime, time); + return this; + }; + + Animator.prototype.pause = function () { + this._clip.pause(); + + this._paused = true; + }; + + Animator.prototype.resume = function () { + this._clip.resume(); + + this._paused = false; + }; + + Animator.prototype.isPaused = function () { + return !!this._paused; + }; + + Animator.prototype.duration = function (duration) { + this._maxTime = duration; + this._force = true; + return this; + }; + + Animator.prototype._doneCallback = function () { + this._setTracksFinished(); + + this._clip = null; + var doneList = this._doneCbs; + + if (doneList) { + var len = doneList.length; + + for (var i = 0; i < len; i++) { + doneList[i].call(this); + } + } + }; + + Animator.prototype._abortedCallback = function () { + this._setTracksFinished(); + + var animation = this.animation; + var abortedList = this._abortedCbs; + + if (animation) { + animation.removeClip(this._clip); + } + + this._clip = null; + + if (abortedList) { + for (var i = 0; i < abortedList.length; i++) { + abortedList[i].call(this); + } + } + }; + + Animator.prototype._setTracksFinished = function () { + var tracks = this._tracks; + var tracksKeys = this._trackKeys; + + for (var i = 0; i < tracksKeys.length; i++) { + tracks[tracksKeys[i]].setFinished(); + } + }; + + Animator.prototype._getAdditiveTrack = function (trackName) { + var additiveTrack; + var additiveAnimators = this._additiveAnimators; + + if (additiveAnimators) { + for (var i = 0; i < additiveAnimators.length; i++) { + var track = additiveAnimators[i].getTrack(trackName); + + if (track) { + additiveTrack = track; + } + } + } + + return additiveTrack; + }; + + Animator.prototype.start = function (easing) { + if (this._started > 0) { + return; + } + + this._started = 1; + var self = this; + var tracks = []; + var maxTime = this._maxTime || 0; + + for (var i = 0; i < this._trackKeys.length; i++) { + var propName = this._trackKeys[i]; + var track = this._tracks[propName]; + + var additiveTrack = this._getAdditiveTrack(propName); + + var kfs = track.keyframes; + var kfsNum = kfs.length; + track.prepare(maxTime, additiveTrack); + + if (track.needsAnimate()) { + if (!this._allowDiscrete && track.discrete) { + var lastKf = kfs[kfsNum - 1]; + + if (lastKf) { + self._target[track.propName] = lastKf.rawValue; + } + + track.setFinished(); + } else { + tracks.push(track); + } + } + } + + if (tracks.length || this._force) { + var clip = new Clip({ + life: maxTime, + loop: this._loop, + delay: this._delay || 0, + onframe: function (percent) { + self._started = 2; + var additiveAnimators = self._additiveAnimators; + + if (additiveAnimators) { + var stillHasAdditiveAnimator = false; + + for (var i = 0; i < additiveAnimators.length; i++) { + if (additiveAnimators[i]._clip) { + stillHasAdditiveAnimator = true; + break; + } + } + + if (!stillHasAdditiveAnimator) { + self._additiveAnimators = null; + } + } + + for (var i = 0; i < tracks.length; i++) { + tracks[i].step(self._target, percent); + } + + var onframeList = self._onframeCbs; + + if (onframeList) { + for (var i = 0; i < onframeList.length; i++) { + onframeList[i](self._target, percent); + } + } + }, + ondestroy: function () { + self._doneCallback(); + } + }); + this._clip = clip; + + if (this.animation) { + this.animation.addClip(clip); + } + + if (easing) { + clip.setEasing(easing); + } + } else { + this._doneCallback(); + } + + return this; + }; + + Animator.prototype.stop = function (forwardToLast) { + if (!this._clip) { + return; + } + + var clip = this._clip; + + if (forwardToLast) { + clip.onframe(1); + } + + this._abortedCallback(); + }; + + Animator.prototype.delay = function (time) { + this._delay = time; + return this; + }; + + Animator.prototype.during = function (cb) { + if (cb) { + if (!this._onframeCbs) { + this._onframeCbs = []; + } + + this._onframeCbs.push(cb); + } + + return this; + }; + + Animator.prototype.done = function (cb) { + if (cb) { + if (!this._doneCbs) { + this._doneCbs = []; + } + + this._doneCbs.push(cb); + } + + return this; + }; + + Animator.prototype.aborted = function (cb) { + if (cb) { + if (!this._abortedCbs) { + this._abortedCbs = []; + } + + this._abortedCbs.push(cb); + } + + return this; + }; + + Animator.prototype.getClip = function () { + return this._clip; + }; + + Animator.prototype.getTrack = function (propName) { + return this._tracks[propName]; + }; + + Animator.prototype.getTracks = function () { + var _this = this; + + return map$1(this._trackKeys, function (key) { + return _this._tracks[key]; + }); + }; + + Animator.prototype.stopTracks = function (propNames, forwardToLast) { + if (!propNames.length || !this._clip) { + return true; + } + + var tracks = this._tracks; + var tracksKeys = this._trackKeys; + + for (var i = 0; i < propNames.length; i++) { + var track = tracks[propNames[i]]; + + if (track && !track.isFinished()) { + if (forwardToLast) { + track.step(this._target, 1); + } else if (this._started === 1) { + track.step(this._target, 0); + } + + track.setFinished(); + } + } + + var allAborted = true; + + for (var i = 0; i < tracksKeys.length; i++) { + if (!tracks[tracksKeys[i]].isFinished()) { + allAborted = false; + break; + } + } + + if (allAborted) { + this._abortedCallback(); + } + + return allAborted; + }; + + Animator.prototype.saveTo = function (target, trackKeys, firstOrLast) { + if (!target) { + return; + } + + trackKeys = trackKeys || this._trackKeys; + + for (var i = 0; i < trackKeys.length; i++) { + var propName = trackKeys[i]; + var track = this._tracks[propName]; + + if (!track || track.isFinished()) { + continue; + } + + var kfs = track.keyframes; + var kf = kfs[firstOrLast ? 0 : kfs.length - 1]; + + if (kf) { + target[propName] = cloneValue(kf.rawValue); + } + } + }; + + Animator.prototype.__changeFinalValue = function (finalProps, trackKeys) { + trackKeys = trackKeys || keys(finalProps); + + for (var i = 0; i < trackKeys.length; i++) { + var propName = trackKeys[i]; + var track = this._tracks[propName]; + + if (!track) { + continue; + } + + var kfs = track.keyframes; + + if (kfs.length > 1) { + var lastKf = kfs.pop(); + track.addKeyframe(lastKf.time, finalProps[propName]); + track.prepare(this._maxTime, track.getAdditiveTrack()); + } + } + }; + + return Animator; + }(); + + function getTime() { + return new Date().getTime(); + } + + var Animation = function (_super) { + __extends(Animation, _super); + + function Animation(opts) { + var _this = _super.call(this) || this; + + _this._running = false; + _this._time = 0; + _this._pausedTime = 0; + _this._pauseStart = 0; + _this._paused = false; + opts = opts || {}; + _this.stage = opts.stage || {}; + return _this; + } + + Animation.prototype.addClip = function (clip) { + if (clip.animation) { + this.removeClip(clip); + } + + if (!this._head) { + this._head = this._tail = clip; + } else { + this._tail.next = clip; + clip.prev = this._tail; + clip.next = null; + this._tail = clip; + } + + clip.animation = this; + }; + + Animation.prototype.addAnimator = function (animator) { + animator.animation = this; + var clip = animator.getClip(); + + if (clip) { + this.addClip(clip); + } + }; + + Animation.prototype.removeClip = function (clip) { + if (!clip.animation) { + return; + } + + var prev = clip.prev; + var next = clip.next; + + if (prev) { + prev.next = next; + } else { + this._head = next; + } + + if (next) { + next.prev = prev; + } else { + this._tail = prev; + } + + clip.next = clip.prev = clip.animation = null; + }; + + Animation.prototype.removeAnimator = function (animator) { + var clip = animator.getClip(); + + if (clip) { + this.removeClip(clip); + } + + animator.animation = null; + }; + + Animation.prototype.update = function (notTriggerFrameAndStageUpdate) { + var time = getTime() - this._pausedTime; + + var delta = time - this._time; + var clip = this._head; + + while (clip) { + var nextClip = clip.next; + var finished = clip.step(time, delta); + + if (finished) { + clip.ondestroy(); + this.removeClip(clip); + clip = nextClip; + } else { + clip = nextClip; + } + } + + this._time = time; + + if (!notTriggerFrameAndStageUpdate) { + this.trigger('frame', delta); + this.stage.update && this.stage.update(); + } + }; + + Animation.prototype._startLoop = function () { + var self = this; + this._running = true; + + function step() { + if (self._running) { + requestAnimationFrame$1(step); + !self._paused && self.update(); + } + } + + requestAnimationFrame$1(step); + }; + + Animation.prototype.start = function () { + if (this._running) { + return; + } + + this._time = getTime(); + this._pausedTime = 0; + + this._startLoop(); + }; + + Animation.prototype.stop = function () { + this._running = false; + }; + + Animation.prototype.pause = function () { + if (!this._paused) { + this._pauseStart = getTime(); + this._paused = true; + } + }; + + Animation.prototype.resume = function () { + if (this._paused) { + this._pausedTime += getTime() - this._pauseStart; + this._paused = false; + } + }; + + Animation.prototype.clear = function () { + var clip = this._head; + + while (clip) { + var nextClip = clip.next; + clip.prev = clip.next = clip.animation = null; + clip = nextClip; + } + + this._head = this._tail = null; + }; + + Animation.prototype.isFinished = function () { + return this._head == null; + }; + + Animation.prototype.animate = function (target, options) { + options = options || {}; + this.start(); + var animator = new Animator(target, options.loop); + this.addAnimator(animator); + return animator; + }; + + return Animation; + }(Eventful); + + var TOUCH_CLICK_DELAY = 300; + var globalEventSupported = env.domSupported; + + var localNativeListenerNames = function () { + var mouseHandlerNames = ['click', 'dblclick', 'mousewheel', 'wheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu']; + var touchHandlerNames = ['touchstart', 'touchend', 'touchmove']; + var pointerEventNameMap = { + pointerdown: 1, + pointerup: 1, + pointermove: 1, + pointerout: 1 + }; + var pointerHandlerNames = map$1(mouseHandlerNames, function (name) { + var nm = name.replace('mouse', 'pointer'); + return pointerEventNameMap.hasOwnProperty(nm) ? nm : name; + }); + return { + mouse: mouseHandlerNames, + touch: touchHandlerNames, + pointer: pointerHandlerNames + }; + }(); + + var globalNativeListenerNames = { + mouse: ['mousemove', 'mouseup'], + pointer: ['pointermove', 'pointerup'] + }; + var wheelEventSupported = false; + + function isPointerFromTouch(event) { + var pointerType = event.pointerType; + return pointerType === 'pen' || pointerType === 'touch'; + } + + function setTouchTimer(scope) { + scope.touching = true; + + if (scope.touchTimer != null) { + clearTimeout(scope.touchTimer); + scope.touchTimer = null; + } + + scope.touchTimer = setTimeout(function () { + scope.touching = false; + scope.touchTimer = null; + }, 700); + } + + function markTouch(event) { + event && (event.zrByTouch = true); + } + + function normalizeGlobalEvent(instance, event) { + return normalizeEvent(instance.dom, new FakeGlobalEvent(instance, event), true); + } + + function isLocalEl(instance, el) { + var elTmp = el; + var isLocal = false; + + while (elTmp && elTmp.nodeType !== 9 && !(isLocal = elTmp.domBelongToZr || elTmp !== el && elTmp === instance.painterRoot)) { + elTmp = elTmp.parentNode; + } + + return isLocal; + } + + var FakeGlobalEvent = function () { + function FakeGlobalEvent(instance, event) { + this.stopPropagation = noop; + this.stopImmediatePropagation = noop; + this.preventDefault = noop; + this.type = event.type; + this.target = this.currentTarget = instance.dom; + this.pointerType = event.pointerType; + this.clientX = event.clientX; + this.clientY = event.clientY; + } + + return FakeGlobalEvent; + }(); + + var localDOMHandlers = { + mousedown: function (event) { + event = normalizeEvent(this.dom, event); + this.__mayPointerCapture = [event.zrX, event.zrY]; + this.trigger('mousedown', event); + }, + mousemove: function (event) { + event = normalizeEvent(this.dom, event); + var downPoint = this.__mayPointerCapture; + + if (downPoint && (event.zrX !== downPoint[0] || event.zrY !== downPoint[1])) { + this.__togglePointerCapture(true); + } + + this.trigger('mousemove', event); + }, + mouseup: function (event) { + event = normalizeEvent(this.dom, event); + + this.__togglePointerCapture(false); + + this.trigger('mouseup', event); + }, + mouseout: function (event) { + event = normalizeEvent(this.dom, event); + var element = event.toElement || event.relatedTarget; + + if (!isLocalEl(this, element)) { + if (this.__pointerCapturing) { + event.zrEventControl = 'no_globalout'; + } + + this.trigger('mouseout', event); + } + }, + wheel: function (event) { + wheelEventSupported = true; + event = normalizeEvent(this.dom, event); + this.trigger('mousewheel', event); + }, + mousewheel: function (event) { + if (wheelEventSupported) { + return; + } + + event = normalizeEvent(this.dom, event); + this.trigger('mousewheel', event); + }, + touchstart: function (event) { + event = normalizeEvent(this.dom, event); + markTouch(event); + this.__lastTouchMoment = new Date(); + this.handler.processGesture(event, 'start'); + localDOMHandlers.mousemove.call(this, event); + localDOMHandlers.mousedown.call(this, event); + }, + touchmove: function (event) { + event = normalizeEvent(this.dom, event); + markTouch(event); + this.handler.processGesture(event, 'change'); + localDOMHandlers.mousemove.call(this, event); + }, + touchend: function (event) { + event = normalizeEvent(this.dom, event); + markTouch(event); + this.handler.processGesture(event, 'end'); + localDOMHandlers.mouseup.call(this, event); + + if (+new Date() - +this.__lastTouchMoment < TOUCH_CLICK_DELAY) { + localDOMHandlers.click.call(this, event); + } + }, + pointerdown: function (event) { + localDOMHandlers.mousedown.call(this, event); + }, + pointermove: function (event) { + if (!isPointerFromTouch(event)) { + localDOMHandlers.mousemove.call(this, event); + } + }, + pointerup: function (event) { + localDOMHandlers.mouseup.call(this, event); + }, + pointerout: function (event) { + if (!isPointerFromTouch(event)) { + localDOMHandlers.mouseout.call(this, event); + } + } + }; + each$4(['click', 'dblclick', 'contextmenu'], function (name) { + localDOMHandlers[name] = function (event) { + event = normalizeEvent(this.dom, event); + this.trigger(name, event); + }; + }); + var globalDOMHandlers = { + pointermove: function (event) { + if (!isPointerFromTouch(event)) { + globalDOMHandlers.mousemove.call(this, event); + } + }, + pointerup: function (event) { + globalDOMHandlers.mouseup.call(this, event); + }, + mousemove: function (event) { + this.trigger('mousemove', event); + }, + mouseup: function (event) { + var pointerCaptureReleasing = this.__pointerCapturing; + + this.__togglePointerCapture(false); + + this.trigger('mouseup', event); + + if (pointerCaptureReleasing) { + event.zrEventControl = 'only_globalout'; + this.trigger('mouseout', event); + } + } + }; + + function mountLocalDOMEventListeners(instance, scope) { + var domHandlers = scope.domHandlers; + + if (env.pointerEventsSupported) { + each$4(localNativeListenerNames.pointer, function (nativeEventName) { + mountSingleDOMEventListener(scope, nativeEventName, function (event) { + domHandlers[nativeEventName].call(instance, event); + }); + }); + } else { + if (env.touchEventsSupported) { + each$4(localNativeListenerNames.touch, function (nativeEventName) { + mountSingleDOMEventListener(scope, nativeEventName, function (event) { + domHandlers[nativeEventName].call(instance, event); + setTouchTimer(scope); + }); + }); + } + + each$4(localNativeListenerNames.mouse, function (nativeEventName) { + mountSingleDOMEventListener(scope, nativeEventName, function (event) { + event = getNativeEvent(event); + + if (!scope.touching) { + domHandlers[nativeEventName].call(instance, event); + } + }); + }); + } + } + + function mountGlobalDOMEventListeners(instance, scope) { + if (env.pointerEventsSupported) { + each$4(globalNativeListenerNames.pointer, mount); + } else if (!env.touchEventsSupported) { + each$4(globalNativeListenerNames.mouse, mount); + } + + function mount(nativeEventName) { + function nativeEventListener(event) { + event = getNativeEvent(event); + + if (!isLocalEl(instance, event.target)) { + event = normalizeGlobalEvent(instance, event); + scope.domHandlers[nativeEventName].call(instance, event); + } + } + + mountSingleDOMEventListener(scope, nativeEventName, nativeEventListener, { + capture: true + }); + } + } + + function mountSingleDOMEventListener(scope, nativeEventName, listener, opt) { + scope.mounted[nativeEventName] = listener; + scope.listenerOpts[nativeEventName] = opt; + addEventListener(scope.domTarget, nativeEventName, listener, opt); + } + + function unmountDOMEventListeners(scope) { + var mounted = scope.mounted; + + for (var nativeEventName in mounted) { + if (mounted.hasOwnProperty(nativeEventName)) { + removeEventListener(scope.domTarget, nativeEventName, mounted[nativeEventName], scope.listenerOpts[nativeEventName]); + } + } + + scope.mounted = {}; + } + + var DOMHandlerScope = function () { + function DOMHandlerScope(domTarget, domHandlers) { + this.mounted = {}; + this.listenerOpts = {}; + this.touching = false; + this.domTarget = domTarget; + this.domHandlers = domHandlers; + } + + return DOMHandlerScope; + }(); + + var HandlerDomProxy = function (_super) { + __extends(HandlerDomProxy, _super); + + function HandlerDomProxy(dom, painterRoot) { + var _this = _super.call(this) || this; + + _this.__pointerCapturing = false; + _this.dom = dom; + _this.painterRoot = painterRoot; + _this._localHandlerScope = new DOMHandlerScope(dom, localDOMHandlers); + + if (globalEventSupported) { + _this._globalHandlerScope = new DOMHandlerScope(document, globalDOMHandlers); + } + + mountLocalDOMEventListeners(_this, _this._localHandlerScope); + return _this; + } + + HandlerDomProxy.prototype.dispose = function () { + unmountDOMEventListeners(this._localHandlerScope); + + if (globalEventSupported) { + unmountDOMEventListeners(this._globalHandlerScope); + } + }; + + HandlerDomProxy.prototype.setCursor = function (cursorStyle) { + this.dom.style && (this.dom.style.cursor = cursorStyle || 'default'); + }; + + HandlerDomProxy.prototype.__togglePointerCapture = function (isPointerCapturing) { + this.__mayPointerCapture = null; + + if (globalEventSupported && +this.__pointerCapturing ^ +isPointerCapturing) { + this.__pointerCapturing = isPointerCapturing; + var globalHandlerScope = this._globalHandlerScope; + isPointerCapturing ? mountGlobalDOMEventListeners(this, globalHandlerScope) : unmountDOMEventListeners(globalHandlerScope); + } + }; + + return HandlerDomProxy; + }(Eventful); + + var dpr = 1; + + if (env.hasGlobalWindow) { + dpr = Math.max(window.devicePixelRatio || window.screen && window.screen.deviceXDPI / window.screen.logicalXDPI || 1, 1); + } + + var devicePixelRatio = dpr; + var DARK_MODE_THRESHOLD = 0.4; + var DARK_LABEL_COLOR = '#333'; + var LIGHT_LABEL_COLOR = '#ccc'; + var LIGHTER_LABEL_COLOR = '#eee'; + var mIdentity = identity; + var EPSILON$2 = 5e-5; + + function isNotAroundZero(val) { + return val > EPSILON$2 || val < -EPSILON$2; + } + + var scaleTmp = []; + var tmpTransform = []; + var originTransform = create(); + var abs = Math.abs; + + var Transformable = function () { + function Transformable() {} + + Transformable.prototype.getLocalTransform = function (m) { + return Transformable.getLocalTransform(this, m); + }; + + Transformable.prototype.setPosition = function (arr) { + this.x = arr[0]; + this.y = arr[1]; + }; + + Transformable.prototype.setScale = function (arr) { + this.scaleX = arr[0]; + this.scaleY = arr[1]; + }; + + Transformable.prototype.setSkew = function (arr) { + this.skewX = arr[0]; + this.skewY = arr[1]; + }; + + Transformable.prototype.setOrigin = function (arr) { + this.originX = arr[0]; + this.originY = arr[1]; + }; + + Transformable.prototype.needLocalTransform = function () { + return isNotAroundZero(this.rotation) || isNotAroundZero(this.x) || isNotAroundZero(this.y) || isNotAroundZero(this.scaleX - 1) || isNotAroundZero(this.scaleY - 1) || isNotAroundZero(this.skewX) || isNotAroundZero(this.skewY); + }; + + Transformable.prototype.updateTransform = function () { + var parentTransform = this.parent && this.parent.transform; + var needLocalTransform = this.needLocalTransform(); + var m = this.transform; + + if (!(needLocalTransform || parentTransform)) { + if (m) { + mIdentity(m); + this.invTransform = null; + } + + return; + } + + m = m || create(); + + if (needLocalTransform) { + this.getLocalTransform(m); + } else { + mIdentity(m); + } + + if (parentTransform) { + if (needLocalTransform) { + mul(m, parentTransform, m); + } else { + copy(m, parentTransform); + } + } + + this.transform = m; + + this._resolveGlobalScaleRatio(m); + }; + + Transformable.prototype._resolveGlobalScaleRatio = function (m) { + var globalScaleRatio = this.globalScaleRatio; + + if (globalScaleRatio != null && globalScaleRatio !== 1) { + this.getGlobalScale(scaleTmp); + var relX = scaleTmp[0] < 0 ? -1 : 1; + var relY = scaleTmp[1] < 0 ? -1 : 1; + var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0; + var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0; + m[0] *= sx; + m[1] *= sx; + m[2] *= sy; + m[3] *= sy; + } + + this.invTransform = this.invTransform || create(); + invert(this.invTransform, m); + }; + + Transformable.prototype.getComputedTransform = function () { + var transformNode = this; + var ancestors = []; + + while (transformNode) { + ancestors.push(transformNode); + transformNode = transformNode.parent; + } + + while (transformNode = ancestors.pop()) { + transformNode.updateTransform(); + } + + return this.transform; + }; + + Transformable.prototype.setLocalTransform = function (m) { + if (!m) { + return; + } + + var sx = m[0] * m[0] + m[1] * m[1]; + var sy = m[2] * m[2] + m[3] * m[3]; + var rotation = Math.atan2(m[1], m[0]); + var shearX = Math.PI / 2 + rotation - Math.atan2(m[3], m[2]); + sy = Math.sqrt(sy) * Math.cos(shearX); + sx = Math.sqrt(sx); + this.skewX = shearX; + this.skewY = 0; + this.rotation = -rotation; + this.x = +m[4]; + this.y = +m[5]; + this.scaleX = sx; + this.scaleY = sy; + this.originX = 0; + this.originY = 0; + }; + + Transformable.prototype.decomposeTransform = function () { + if (!this.transform) { + return; + } + + var parent = this.parent; + var m = this.transform; + + if (parent && parent.transform) { + parent.invTransform = parent.invTransform || create(); + mul(tmpTransform, parent.invTransform, m); + m = tmpTransform; + } + + var ox = this.originX; + var oy = this.originY; + + if (ox || oy) { + originTransform[4] = ox; + originTransform[5] = oy; + mul(tmpTransform, m, originTransform); + tmpTransform[4] -= ox; + tmpTransform[5] -= oy; + m = tmpTransform; + } + + this.setLocalTransform(m); + }; + + Transformable.prototype.getGlobalScale = function (out) { + var m = this.transform; + out = out || []; + + if (!m) { + out[0] = 1; + out[1] = 1; + return out; + } + + out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]); + out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]); + + if (m[0] < 0) { + out[0] = -out[0]; + } + + if (m[3] < 0) { + out[1] = -out[1]; + } + + return out; + }; + + Transformable.prototype.transformCoordToLocal = function (x, y) { + var v2 = [x, y]; + var invTransform = this.invTransform; + + if (invTransform) { + applyTransform$1(v2, v2, invTransform); + } + + return v2; + }; + + Transformable.prototype.transformCoordToGlobal = function (x, y) { + var v2 = [x, y]; + var transform = this.transform; + + if (transform) { + applyTransform$1(v2, v2, transform); + } + + return v2; + }; + + Transformable.prototype.getLineScale = function () { + var m = this.transform; + return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10 ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1])) : 1; + }; + + Transformable.prototype.copyTransform = function (source) { + copyTransform(this, source); + }; + + Transformable.getLocalTransform = function (target, m) { + m = m || []; + var ox = target.originX || 0; + var oy = target.originY || 0; + var sx = target.scaleX; + var sy = target.scaleY; + var ax = target.anchorX; + var ay = target.anchorY; + var rotation = target.rotation || 0; + var x = target.x; + var y = target.y; + var skewX = target.skewX ? Math.tan(target.skewX) : 0; + var skewY = target.skewY ? Math.tan(-target.skewY) : 0; + + if (ox || oy || ax || ay) { + var dx = ox + ax; + var dy = oy + ay; + m[4] = -dx * sx - skewX * dy * sy; + m[5] = -dy * sy - skewY * dx * sx; + } else { + m[4] = m[5] = 0; + } + + m[0] = sx; + m[3] = sy; + m[1] = skewY * sx; + m[2] = skewX * sy; + rotation && rotate(m, m, rotation); + m[4] += ox + x; + m[5] += oy + y; + return m; + }; + + Transformable.initDefaultProps = function () { + var proto = Transformable.prototype; + proto.scaleX = proto.scaleY = proto.globalScaleRatio = 1; + proto.x = proto.y = proto.originX = proto.originY = proto.skewX = proto.skewY = proto.rotation = proto.anchorX = proto.anchorY = 0; + }(); + + return Transformable; + }(); + + var TRANSFORMABLE_PROPS = ['x', 'y', 'originX', 'originY', 'anchorX', 'anchorY', 'rotation', 'scaleX', 'scaleY', 'skewX', 'skewY']; + + function copyTransform(target, source) { + for (var i = 0; i < TRANSFORMABLE_PROPS.length; i++) { + var propName = TRANSFORMABLE_PROPS[i]; + target[propName] = source[propName]; + } + } + + function ensureFontMeasureInfo(font) { + if (!_fontMeasureInfoCache) { + _fontMeasureInfoCache = new LRU(100); + } + + font = font || DEFAULT_FONT; + + var measureInfo = _fontMeasureInfoCache.get(font); + + if (!measureInfo) { + measureInfo = { + font: font, + strWidthCache: new LRU(500), + asciiWidthMap: null, + asciiWidthMapTried: false, + stWideCharWidth: platformApi.measureText('国', font).width, + asciiCharWidth: platformApi.measureText('a', font).width + }; + + _fontMeasureInfoCache.put(font, measureInfo); + } + + return measureInfo; + } + + var _fontMeasureInfoCache; + + function tryCreateASCIIWidthMap(font) { + if (_getASCIIWidthMapLongCount >= GET_ASCII_WIDTH_LONG_COUNT_MAX) { + return; + } + + font = font || DEFAULT_FONT; + var asciiWidthMap = []; + var start = +new Date(); + + for (var code = 0; code <= 127; code++) { + asciiWidthMap[code] = platformApi.measureText(String.fromCharCode(code), font).width; + } + + var cost = +new Date() - start; + + if (cost > 16) { + _getASCIIWidthMapLongCount = GET_ASCII_WIDTH_LONG_COUNT_MAX; + } else if (cost > 2) { + _getASCIIWidthMapLongCount++; + } + + return asciiWidthMap; + } + + var _getASCIIWidthMapLongCount = 0; + var GET_ASCII_WIDTH_LONG_COUNT_MAX = 5; + + function measureCharWidth(fontMeasureInfo, charCode) { + if (!fontMeasureInfo.asciiWidthMapTried) { + fontMeasureInfo.asciiWidthMap = tryCreateASCIIWidthMap(fontMeasureInfo.font); + fontMeasureInfo.asciiWidthMapTried = true; + } + + return 0 <= charCode && charCode <= 127 ? fontMeasureInfo.asciiWidthMap != null ? fontMeasureInfo.asciiWidthMap[charCode] : fontMeasureInfo.asciiCharWidth : fontMeasureInfo.stWideCharWidth; + } + + function measureWidth(fontMeasureInfo, text) { + var strWidthCache = fontMeasureInfo.strWidthCache; + var width = strWidthCache.get(text); + + if (width == null) { + width = platformApi.measureText(text, fontMeasureInfo.font).width; + strWidthCache.put(text, width); + } + + return width; + } + + function innerGetBoundingRect(text, font, textAlign, textBaseline) { + var width = measureWidth(ensureFontMeasureInfo(font), text); + var height = getLineHeight(font); + var x = adjustTextX(0, width, textAlign); + var y = adjustTextY(0, height, textBaseline); + var rect = new BoundingRect(x, y, width, height); + return rect; + } + + function getBoundingRect(text, font, textAlign, textBaseline) { + var textLines = ((text || '') + '').split('\n'); + var len = textLines.length; + + if (len === 1) { + return innerGetBoundingRect(textLines[0], font, textAlign, textBaseline); + } else { + var uniondRect = new BoundingRect(0, 0, 0, 0); + + for (var i = 0; i < textLines.length; i++) { + var rect = innerGetBoundingRect(textLines[i], font, textAlign, textBaseline); + i === 0 ? uniondRect.copy(rect) : uniondRect.union(rect); + } + + return uniondRect; + } + } + + function adjustTextX(x, width, textAlign, inverse) { + if (textAlign === 'right') { + !inverse ? x -= width : x += width; + } else if (textAlign === 'center') { + !inverse ? x -= width / 2 : x += width / 2; + } + + return x; + } + + function adjustTextY(y, height, verticalAlign, inverse) { + if (verticalAlign === 'middle') { + !inverse ? y -= height / 2 : y += height / 2; + } else if (verticalAlign === 'bottom') { + !inverse ? y -= height : y += height; + } + + return y; + } + + function getLineHeight(font) { + return ensureFontMeasureInfo(font).stWideCharWidth; + } + + function parsePercent$1(value, maxValue) { + if (typeof value === 'string') { + if (value.lastIndexOf('%') >= 0) { + return parseFloat(value) / 100 * maxValue; + } + + return parseFloat(value); + } + + return value; + } + + function calculateTextPosition(out, opts, rect) { + var textPosition = opts.position || 'inside'; + var distance = opts.distance != null ? opts.distance : 5; + var height = rect.height; + var width = rect.width; + var halfHeight = height / 2; + var x = rect.x; + var y = rect.y; + var textAlign = 'left'; + var textVerticalAlign = 'top'; + + if (textPosition instanceof Array) { + x += parsePercent$1(textPosition[0], rect.width); + y += parsePercent$1(textPosition[1], rect.height); + textAlign = null; + textVerticalAlign = null; + } else { + switch (textPosition) { + case 'left': + x -= distance; + y += halfHeight; + textAlign = 'right'; + textVerticalAlign = 'middle'; + break; + + case 'right': + x += distance + width; + y += halfHeight; + textVerticalAlign = 'middle'; + break; + + case 'top': + x += width / 2; + y -= distance; + textAlign = 'center'; + textVerticalAlign = 'bottom'; + break; + + case 'bottom': + x += width / 2; + y += height + distance; + textAlign = 'center'; + break; + + case 'inside': + x += width / 2; + y += halfHeight; + textAlign = 'center'; + textVerticalAlign = 'middle'; + break; + + case 'insideLeft': + x += distance; + y += halfHeight; + textVerticalAlign = 'middle'; + break; + + case 'insideRight': + x += width - distance; + y += halfHeight; + textAlign = 'right'; + textVerticalAlign = 'middle'; + break; + + case 'insideTop': + x += width / 2; + y += distance; + textAlign = 'center'; + break; + + case 'insideBottom': + x += width / 2; + y += height - distance; + textAlign = 'center'; + textVerticalAlign = 'bottom'; + break; + + case 'insideTopLeft': + x += distance; + y += distance; + break; + + case 'insideTopRight': + x += width - distance; + y += distance; + textAlign = 'right'; + break; + + case 'insideBottomLeft': + x += distance; + y += height - distance; + textVerticalAlign = 'bottom'; + break; + + case 'insideBottomRight': + x += width - distance; + y += height - distance; + textAlign = 'right'; + textVerticalAlign = 'bottom'; + break; + } + } + + out = out || {}; + out.x = x; + out.y = y; + out.align = textAlign; + out.verticalAlign = textVerticalAlign; + return out; + } + + var PRESERVED_NORMAL_STATE = '__zr_normal__'; + var PRIMARY_STATES_KEYS$1 = TRANSFORMABLE_PROPS.concat(['ignore']); + var DEFAULT_ANIMATABLE_MAP = reduce(TRANSFORMABLE_PROPS, function (obj, key) { + obj[key] = true; + return obj; + }, { + ignore: false + }); + var tmpTextPosCalcRes = {}; + var tmpBoundingRect = new BoundingRect(0, 0, 0, 0); + var tmpInnerTextTrans = []; + + var Element = function () { + function Element(props) { + this.id = guid(); + this.animators = []; + this.currentStates = []; + this.states = {}; + + this._init(props); + } + + Element.prototype._init = function (props) { + this.attr(props); + }; + + Element.prototype.drift = function (dx, dy, e) { + switch (this.draggable) { + case 'horizontal': + dy = 0; + break; + + case 'vertical': + dx = 0; + break; + } + + var m = this.transform; + + if (!m) { + m = this.transform = [1, 0, 0, 1, 0, 0]; + } + + m[4] += dx; + m[5] += dy; + this.decomposeTransform(); + this.markRedraw(); + }; + + Element.prototype.beforeUpdate = function () {}; + + Element.prototype.afterUpdate = function () {}; + + Element.prototype.update = function () { + this.updateTransform(); + + if (this.__dirty) { + this.updateInnerText(); + } + }; + + Element.prototype.updateInnerText = function (forceUpdate) { + var textEl = this._textContent; + + if (textEl && (!textEl.ignore || forceUpdate)) { + if (!this.textConfig) { + this.textConfig = {}; + } + + var textConfig = this.textConfig; + var isLocal = textConfig.local; + var innerTransformable = textEl.innerTransformable; + var textAlign = void 0; + var textVerticalAlign = void 0; + var textStyleChanged = false; + innerTransformable.parent = isLocal ? this : null; + var innerOrigin = false; + innerTransformable.copyTransform(textEl); + var hasPosition = textConfig.position != null; + var autoOverflowArea = textConfig.autoOverflowArea; + var layoutRect = void 0; + + if (autoOverflowArea || hasPosition) { + layoutRect = tmpBoundingRect; + + if (textConfig.layoutRect) { + layoutRect.copy(textConfig.layoutRect); + } else { + layoutRect.copy(this.getBoundingRect()); + } + + if (!isLocal) { + layoutRect.applyTransform(this.transform); + } + } + + if (hasPosition) { + if (this.calculateTextPosition) { + this.calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect); + } else { + calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect); + } + + innerTransformable.x = tmpTextPosCalcRes.x; + innerTransformable.y = tmpTextPosCalcRes.y; + textAlign = tmpTextPosCalcRes.align; + textVerticalAlign = tmpTextPosCalcRes.verticalAlign; + var textOrigin = textConfig.origin; + + if (textOrigin && textConfig.rotation != null) { + var relOriginX = void 0; + var relOriginY = void 0; + + if (textOrigin === 'center') { + relOriginX = layoutRect.width * 0.5; + relOriginY = layoutRect.height * 0.5; + } else { + relOriginX = parsePercent$1(textOrigin[0], layoutRect.width); + relOriginY = parsePercent$1(textOrigin[1], layoutRect.height); + } + + innerOrigin = true; + innerTransformable.originX = -innerTransformable.x + relOriginX + (isLocal ? 0 : layoutRect.x); + innerTransformable.originY = -innerTransformable.y + relOriginY + (isLocal ? 0 : layoutRect.y); + } + } + + if (textConfig.rotation != null) { + innerTransformable.rotation = textConfig.rotation; + } + + var textOffset = textConfig.offset; + + if (textOffset) { + innerTransformable.x += textOffset[0]; + innerTransformable.y += textOffset[1]; + + if (!innerOrigin) { + innerTransformable.originX = -textOffset[0]; + innerTransformable.originY = -textOffset[1]; + } + } + + var innerTextDefaultStyle = this._innerTextDefaultStyle || (this._innerTextDefaultStyle = {}); + + if (autoOverflowArea) { + var overflowRect = innerTextDefaultStyle.overflowRect = innerTextDefaultStyle.overflowRect || new BoundingRect(0, 0, 0, 0); + innerTransformable.getLocalTransform(tmpInnerTextTrans); + invert(tmpInnerTextTrans, tmpInnerTextTrans); + BoundingRect.copy(overflowRect, layoutRect); + overflowRect.applyTransform(tmpInnerTextTrans); + } else { + innerTextDefaultStyle.overflowRect = null; + } + + var isInside = textConfig.inside == null ? typeof textConfig.position === 'string' && textConfig.position.indexOf('inside') >= 0 : textConfig.inside; + var textFill = void 0; + var textStroke = void 0; + var autoStroke = void 0; + + if (isInside && this.canBeInsideText()) { + textFill = textConfig.insideFill; + textStroke = textConfig.insideStroke; + + if (textFill == null || textFill === 'auto') { + textFill = this.getInsideTextFill(); + } + + if (textStroke == null || textStroke === 'auto') { + textStroke = this.getInsideTextStroke(textFill); + autoStroke = true; + } + } else { + textFill = textConfig.outsideFill; + textStroke = textConfig.outsideStroke; + + if (textFill == null || textFill === 'auto') { + textFill = this.getOutsideFill(); + } + + if (textStroke == null || textStroke === 'auto') { + textStroke = this.getOutsideStroke(textFill); + autoStroke = true; + } + } + + textFill = textFill || '#000'; + + if (textFill !== innerTextDefaultStyle.fill || textStroke !== innerTextDefaultStyle.stroke || autoStroke !== innerTextDefaultStyle.autoStroke || textAlign !== innerTextDefaultStyle.align || textVerticalAlign !== innerTextDefaultStyle.verticalAlign) { + textStyleChanged = true; + innerTextDefaultStyle.fill = textFill; + innerTextDefaultStyle.stroke = textStroke; + innerTextDefaultStyle.autoStroke = autoStroke; + innerTextDefaultStyle.align = textAlign; + innerTextDefaultStyle.verticalAlign = textVerticalAlign; + textEl.setDefaultTextStyle(innerTextDefaultStyle); + } + + textEl.__dirty |= REDRAW_BIT; + + if (textStyleChanged) { + textEl.dirtyStyle(true); + } + } + }; + + Element.prototype.canBeInsideText = function () { + return true; + }; + + Element.prototype.getInsideTextFill = function () { + return '#fff'; + }; + + Element.prototype.getInsideTextStroke = function (textFill) { + return '#000'; + }; + + Element.prototype.getOutsideFill = function () { + return this.__zr && this.__zr.isDarkMode() ? LIGHT_LABEL_COLOR : DARK_LABEL_COLOR; + }; + + Element.prototype.getOutsideStroke = function (textFill) { + var backgroundColor = this.__zr && this.__zr.getBackgroundColor(); + + var colorArr = typeof backgroundColor === 'string' && parse(backgroundColor); + + if (!colorArr) { + colorArr = [255, 255, 255, 1]; + } + + var alpha = colorArr[3]; + + var isDark = this.__zr.isDarkMode(); + + for (var i = 0; i < 3; i++) { + colorArr[i] = colorArr[i] * alpha + (isDark ? 0 : 255) * (1 - alpha); + } + + colorArr[3] = 1; + return stringify(colorArr, 'rgba'); + }; + + Element.prototype.traverse = function (cb, context) {}; + + Element.prototype.attrKV = function (key, value) { + if (key === 'textConfig') { + this.setTextConfig(value); + } else if (key === 'textContent') { + this.setTextContent(value); + } else if (key === 'clipPath') { + this.setClipPath(value); + } else if (key === 'extra') { + this.extra = this.extra || {}; + extend(this.extra, value); + } else { + this[key] = value; + } + }; + + Element.prototype.hide = function () { + this.ignore = true; + this.markRedraw(); + }; + + Element.prototype.show = function () { + this.ignore = false; + this.markRedraw(); + }; + + Element.prototype.attr = function (keyOrObj, value) { + if (typeof keyOrObj === 'string') { + this.attrKV(keyOrObj, value); + } else if (isObject$2(keyOrObj)) { + var obj = keyOrObj; + var keysArr = keys(obj); + + for (var i = 0; i < keysArr.length; i++) { + var key = keysArr[i]; + this.attrKV(key, keyOrObj[key]); + } + } + + this.markRedraw(); + return this; + }; + + Element.prototype.saveCurrentToNormalState = function (toState) { + this._innerSaveToNormal(toState); + + var normalState = this._normalState; + + for (var i = 0; i < this.animators.length; i++) { + var animator = this.animators[i]; + var fromStateTransition = animator.__fromStateTransition; + + if (animator.getLoop() || fromStateTransition && fromStateTransition !== PRESERVED_NORMAL_STATE) { + continue; + } + + var targetName = animator.targetName; + var target = targetName ? normalState[targetName] : normalState; + animator.saveTo(target); + } + }; + + Element.prototype._innerSaveToNormal = function (toState) { + var normalState = this._normalState; + + if (!normalState) { + normalState = this._normalState = {}; + } + + if (toState.textConfig && !normalState.textConfig) { + normalState.textConfig = this.textConfig; + } + + this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS$1); + }; + + Element.prototype._savePrimaryToNormal = function (toState, normalState, primaryKeys) { + for (var i = 0; i < primaryKeys.length; i++) { + var key = primaryKeys[i]; + + if (toState[key] != null && !(key in normalState)) { + normalState[key] = this[key]; + } + } + }; + + Element.prototype.hasState = function () { + return this.currentStates.length > 0; + }; + + Element.prototype.getState = function (name) { + return this.states[name]; + }; + + Element.prototype.ensureState = function (name) { + var states = this.states; + + if (!states[name]) { + states[name] = {}; + } + + return states[name]; + }; + + Element.prototype.clearStates = function (noAnimation) { + this.useState(PRESERVED_NORMAL_STATE, false, noAnimation); + }; + + Element.prototype.useState = function (stateName, keepCurrentStates, noAnimation, forceUseHoverLayer) { + var toNormalState = stateName === PRESERVED_NORMAL_STATE; + var hasStates = this.hasState(); + + if (!hasStates && toNormalState) { + return; + } + + var currentStates = this.currentStates; + var animationCfg = this.stateTransition; + + if (indexOf(currentStates, stateName) >= 0 && (keepCurrentStates || currentStates.length === 1)) { + return; + } + + var state; + + if (this.stateProxy && !toNormalState) { + state = this.stateProxy(stateName); + } + + if (!state) { + state = this.states && this.states[stateName]; + } + + if (!state && !toNormalState) { + logError("State " + stateName + " not exists."); + return; + } + + if (!toNormalState) { + this.saveCurrentToNormalState(state); + } + + var useHoverLayer = !!(state && state.hoverLayer || forceUseHoverLayer); + + if (useHoverLayer) { + this._toggleHoverLayerFlag(true); + } + + this._applyStateObj(stateName, state, this._normalState, keepCurrentStates, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg); + + var textContent = this._textContent; + var textGuide = this._textGuide; + + if (textContent) { + textContent.useState(stateName, keepCurrentStates, noAnimation, useHoverLayer); + } + + if (textGuide) { + textGuide.useState(stateName, keepCurrentStates, noAnimation, useHoverLayer); + } + + if (toNormalState) { + this.currentStates = []; + this._normalState = {}; + } else { + if (!keepCurrentStates) { + this.currentStates = [stateName]; + } else { + this.currentStates.push(stateName); + } + } + + this._updateAnimationTargets(); + + this.markRedraw(); + + if (!useHoverLayer && this.__inHover) { + this._toggleHoverLayerFlag(false); + + this.__dirty &= ~REDRAW_BIT; + } + + return state; + }; + + Element.prototype.useStates = function (states, noAnimation, forceUseHoverLayer) { + if (!states.length) { + this.clearStates(); + } else { + var stateObjects = []; + var currentStates = this.currentStates; + var len = states.length; + var notChange = len === currentStates.length; + + if (notChange) { + for (var i = 0; i < len; i++) { + if (states[i] !== currentStates[i]) { + notChange = false; + break; + } + } + } + + if (notChange) { + return; + } + + for (var i = 0; i < len; i++) { + var stateName = states[i]; + var stateObj = void 0; + + if (this.stateProxy) { + stateObj = this.stateProxy(stateName, states); + } + + if (!stateObj) { + stateObj = this.states[stateName]; + } + + if (stateObj) { + stateObjects.push(stateObj); + } + } + + var lastStateObj = stateObjects[len - 1]; + var useHoverLayer = !!(lastStateObj && lastStateObj.hoverLayer || forceUseHoverLayer); + + if (useHoverLayer) { + this._toggleHoverLayerFlag(true); + } + + var mergedState = this._mergeStates(stateObjects); + + var animationCfg = this.stateTransition; + this.saveCurrentToNormalState(mergedState); + + this._applyStateObj(states.join(','), mergedState, this._normalState, false, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg); + + var textContent = this._textContent; + var textGuide = this._textGuide; + + if (textContent) { + textContent.useStates(states, noAnimation, useHoverLayer); + } + + if (textGuide) { + textGuide.useStates(states, noAnimation, useHoverLayer); + } + + this._updateAnimationTargets(); + + this.currentStates = states.slice(); + this.markRedraw(); + + if (!useHoverLayer && this.__inHover) { + this._toggleHoverLayerFlag(false); + + this.__dirty &= ~REDRAW_BIT; + } + } + }; + + Element.prototype.isSilent = function () { + var el = this; + + while (el) { + if (el.silent) { + return true; + } + + var hostEl = el.__hostTarget; + el = hostEl ? el.ignoreHostSilent ? null : hostEl : el.parent; + } + + return false; + }; + + Element.prototype._updateAnimationTargets = function () { + for (var i = 0; i < this.animators.length; i++) { + var animator = this.animators[i]; + + if (animator.targetName) { + animator.changeTarget(this[animator.targetName]); + } + } + }; + + Element.prototype.removeState = function (state) { + var idx = indexOf(this.currentStates, state); + + if (idx >= 0) { + var currentStates = this.currentStates.slice(); + currentStates.splice(idx, 1); + this.useStates(currentStates); + } + }; + + Element.prototype.replaceState = function (oldState, newState, forceAdd) { + var currentStates = this.currentStates.slice(); + var idx = indexOf(currentStates, oldState); + var newStateExists = indexOf(currentStates, newState) >= 0; + + if (idx >= 0) { + if (!newStateExists) { + currentStates[idx] = newState; + } else { + currentStates.splice(idx, 1); + } + } else if (forceAdd && !newStateExists) { + currentStates.push(newState); + } + + this.useStates(currentStates); + }; + + Element.prototype.toggleState = function (state, enable) { + if (enable) { + this.useState(state, true); + } else { + this.removeState(state); + } + }; + + Element.prototype._mergeStates = function (states) { + var mergedState = {}; + var mergedTextConfig; + + for (var i = 0; i < states.length; i++) { + var state = states[i]; + extend(mergedState, state); + + if (state.textConfig) { + mergedTextConfig = mergedTextConfig || {}; + extend(mergedTextConfig, state.textConfig); + } + } + + if (mergedTextConfig) { + mergedState.textConfig = mergedTextConfig; + } + + return mergedState; + }; + + Element.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) { + var needsRestoreToNormal = !(state && keepCurrentStates); + + if (state && state.textConfig) { + this.textConfig = extend({}, keepCurrentStates ? this.textConfig : normalState.textConfig); + extend(this.textConfig, state.textConfig); + } else if (needsRestoreToNormal) { + if (normalState.textConfig) { + this.textConfig = normalState.textConfig; + } + } + + var transitionTarget = {}; + var hasTransition = false; + + for (var i = 0; i < PRIMARY_STATES_KEYS$1.length; i++) { + var key = PRIMARY_STATES_KEYS$1[i]; + var propNeedsTransition = transition && DEFAULT_ANIMATABLE_MAP[key]; + + if (state && state[key] != null) { + if (propNeedsTransition) { + hasTransition = true; + transitionTarget[key] = state[key]; + } else { + this[key] = state[key]; + } + } else if (needsRestoreToNormal) { + if (normalState[key] != null) { + if (propNeedsTransition) { + hasTransition = true; + transitionTarget[key] = normalState[key]; + } else { + this[key] = normalState[key]; + } + } + } + } + + if (!transition) { + for (var i = 0; i < this.animators.length; i++) { + var animator = this.animators[i]; + var targetName = animator.targetName; + + if (!animator.getLoop()) { + animator.__changeFinalValue(targetName ? (state || normalState)[targetName] : state || normalState); + } + } + } + + if (hasTransition) { + this._transitionState(stateName, transitionTarget, animationCfg); + } + }; + + Element.prototype._attachComponent = function (componentEl) { + if (componentEl.__zr && !componentEl.__hostTarget) { + { + throw new Error('Text element has been added to zrender.'); + } + } + + if (componentEl === this) { + { + throw new Error('Recursive component attachment.'); + } + } + + var zr = this.__zr; + + if (zr) { + componentEl.addSelfToZr(zr); + } + + componentEl.__zr = zr; + componentEl.__hostTarget = this; + }; + + Element.prototype._detachComponent = function (componentEl) { + if (componentEl.__zr) { + componentEl.removeSelfFromZr(componentEl.__zr); + } + + componentEl.__zr = null; + componentEl.__hostTarget = null; + }; + + Element.prototype.getClipPath = function () { + return this._clipPath; + }; + + Element.prototype.setClipPath = function (clipPath) { + if (this._clipPath && this._clipPath !== clipPath) { + this.removeClipPath(); + } + + this._attachComponent(clipPath); + + this._clipPath = clipPath; + this.markRedraw(); + }; + + Element.prototype.removeClipPath = function () { + var clipPath = this._clipPath; + + if (clipPath) { + this._detachComponent(clipPath); + + this._clipPath = null; + this.markRedraw(); + } + }; + + Element.prototype.getTextContent = function () { + return this._textContent; + }; + + Element.prototype.setTextContent = function (textEl) { + var previousTextContent = this._textContent; + + if (previousTextContent === textEl) { + return; + } + + if (previousTextContent && previousTextContent !== textEl) { + this.removeTextContent(); + } + + { + if (textEl.__zr && !textEl.__hostTarget) { + throw new Error('Text element has been added to zrender.'); + } + } + textEl.innerTransformable = new Transformable(); + + this._attachComponent(textEl); + + this._textContent = textEl; + this.markRedraw(); + }; + + Element.prototype.setTextConfig = function (cfg) { + if (!this.textConfig) { + this.textConfig = {}; + } + + extend(this.textConfig, cfg); + this.markRedraw(); + }; + + Element.prototype.removeTextConfig = function () { + this.textConfig = null; + this.markRedraw(); + }; + + Element.prototype.removeTextContent = function () { + var textEl = this._textContent; + + if (textEl) { + textEl.innerTransformable = null; + + this._detachComponent(textEl); + + this._textContent = null; + this._innerTextDefaultStyle = null; + this.markRedraw(); + } + }; + + Element.prototype.getTextGuideLine = function () { + return this._textGuide; + }; + + Element.prototype.setTextGuideLine = function (guideLine) { + if (this._textGuide && this._textGuide !== guideLine) { + this.removeTextGuideLine(); + } + + this._attachComponent(guideLine); + + this._textGuide = guideLine; + this.markRedraw(); + }; + + Element.prototype.removeTextGuideLine = function () { + var textGuide = this._textGuide; + + if (textGuide) { + this._detachComponent(textGuide); + + this._textGuide = null; + this.markRedraw(); + } + }; + + Element.prototype.markRedraw = function () { + this.__dirty |= REDRAW_BIT; + var zr = this.__zr; + + if (zr) { + if (this.__inHover) { + zr.refreshHover(); + } else { + zr.refresh(); + } + } + + if (this.__hostTarget) { + this.__hostTarget.markRedraw(); + } + }; + + Element.prototype.dirty = function () { + this.markRedraw(); + }; + + Element.prototype._toggleHoverLayerFlag = function (inHover) { + this.__inHover = inHover; + var textContent = this._textContent; + var textGuide = this._textGuide; + + if (textContent) { + textContent.__inHover = inHover; + } + + if (textGuide) { + textGuide.__inHover = inHover; + } + }; + + Element.prototype.addSelfToZr = function (zr) { + if (this.__zr === zr) { + return; + } + + this.__zr = zr; + var animators = this.animators; + + if (animators) { + for (var i = 0; i < animators.length; i++) { + zr.animation.addAnimator(animators[i]); + } + } + + if (this._clipPath) { + this._clipPath.addSelfToZr(zr); + } + + if (this._textContent) { + this._textContent.addSelfToZr(zr); + } + + if (this._textGuide) { + this._textGuide.addSelfToZr(zr); + } + }; + + Element.prototype.removeSelfFromZr = function (zr) { + if (!this.__zr) { + return; + } + + this.__zr = null; + var animators = this.animators; + + if (animators) { + for (var i = 0; i < animators.length; i++) { + zr.animation.removeAnimator(animators[i]); + } + } + + if (this._clipPath) { + this._clipPath.removeSelfFromZr(zr); + } + + if (this._textContent) { + this._textContent.removeSelfFromZr(zr); + } + + if (this._textGuide) { + this._textGuide.removeSelfFromZr(zr); + } + }; + + Element.prototype.animate = function (key, loop, allowDiscreteAnimation) { + var target = key ? this[key] : this; + { + if (!target) { + logError('Property "' + key + '" is not existed in element ' + this.id); + return; + } + } + var animator = new Animator(target, loop, allowDiscreteAnimation); + key && (animator.targetName = key); + this.addAnimator(animator, key); + return animator; + }; + + Element.prototype.addAnimator = function (animator, key) { + var zr = this.__zr; + var el = this; + animator.during(function () { + el.updateDuringAnimation(key); + }).done(function () { + var animators = el.animators; + var idx = indexOf(animators, animator); + + if (idx >= 0) { + animators.splice(idx, 1); + } + }); + this.animators.push(animator); + + if (zr) { + zr.animation.addAnimator(animator); + } + + zr && zr.wakeUp(); + }; + + Element.prototype.updateDuringAnimation = function (key) { + this.markRedraw(); + }; + + Element.prototype.stopAnimation = function (scope, forwardToLast) { + var animators = this.animators; + var len = animators.length; + var leftAnimators = []; + + for (var i = 0; i < len; i++) { + var animator = animators[i]; + + if (!scope || scope === animator.scope) { + animator.stop(forwardToLast); + } else { + leftAnimators.push(animator); + } + } + + this.animators = leftAnimators; + return this; + }; + + Element.prototype.animateTo = function (target, cfg, animationProps) { + animateTo(this, target, cfg, animationProps); + }; + + Element.prototype.animateFrom = function (target, cfg, animationProps) { + animateTo(this, target, cfg, animationProps, true); + }; + + Element.prototype._transitionState = function (stateName, target, cfg, animationProps) { + var animators = animateTo(this, target, cfg, animationProps); + + for (var i = 0; i < animators.length; i++) { + animators[i].__fromStateTransition = stateName; + } + }; + + Element.prototype.getBoundingRect = function () { + return null; + }; + + Element.prototype.getPaintRect = function () { + return null; + }; + + Element.initDefaultProps = function () { + var elProto = Element.prototype; + elProto.type = 'element'; + elProto.name = ''; + elProto.ignore = elProto.silent = elProto.ignoreHostSilent = elProto.isGroup = elProto.draggable = elProto.dragging = elProto.ignoreClip = elProto.__inHover = false; + elProto.__dirty = REDRAW_BIT; + var logs = {}; + + function logDeprecatedError(key, xKey, yKey) { + if (!logs[key + xKey + yKey]) { + console.warn("DEPRECATED: '" + key + "' has been deprecated. use '" + xKey + "', '" + yKey + "' instead"); + logs[key + xKey + yKey] = true; + } + } + + function createLegacyProperty(key, privateKey, xKey, yKey) { + Object.defineProperty(elProto, key, { + get: function () { + { + logDeprecatedError(key, xKey, yKey); + } + + if (!this[privateKey]) { + var pos = this[privateKey] = []; + enhanceArray(this, pos); + } + + return this[privateKey]; + }, + set: function (pos) { + { + logDeprecatedError(key, xKey, yKey); + } + this[xKey] = pos[0]; + this[yKey] = pos[1]; + this[privateKey] = pos; + enhanceArray(this, pos); + } + }); + + function enhanceArray(self, pos) { + Object.defineProperty(pos, 0, { + get: function () { + return self[xKey]; + }, + set: function (val) { + self[xKey] = val; + } + }); + Object.defineProperty(pos, 1, { + get: function () { + return self[yKey]; + }, + set: function (val) { + self[yKey] = val; + } + }); + } + } + + if (Object.defineProperty) { + createLegacyProperty('position', '_legacyPos', 'x', 'y'); + createLegacyProperty('scale', '_legacyScale', 'scaleX', 'scaleY'); + createLegacyProperty('origin', '_legacyOrigin', 'originX', 'originY'); + } + }(); + + return Element; + }(); + + mixin(Element, Eventful); + mixin(Element, Transformable); + + function animateTo(animatable, target, cfg, animationProps, reverse) { + cfg = cfg || {}; + var animators = []; + animateToShallow(animatable, '', animatable, target, cfg, animationProps, animators, reverse); + var finishCount = animators.length; + var doneHappened = false; + var cfgDone = cfg.done; + var cfgAborted = cfg.aborted; + + var doneCb = function () { + doneHappened = true; + finishCount--; + + if (finishCount <= 0) { + doneHappened ? cfgDone && cfgDone() : cfgAborted && cfgAborted(); + } + }; + + var abortedCb = function () { + finishCount--; + + if (finishCount <= 0) { + doneHappened ? cfgDone && cfgDone() : cfgAborted && cfgAborted(); + } + }; + + if (!finishCount) { + cfgDone && cfgDone(); + } + + if (animators.length > 0 && cfg.during) { + animators[0].during(function (target, percent) { + cfg.during(percent); + }); + } + + for (var i = 0; i < animators.length; i++) { + var animator = animators[i]; + + if (doneCb) { + animator.done(doneCb); + } + + if (abortedCb) { + animator.aborted(abortedCb); + } + + if (cfg.force) { + animator.duration(cfg.duration); + } + + animator.start(cfg.easing); + } + + return animators; + } + + function copyArrShallow(source, target, len) { + for (var i = 0; i < len; i++) { + source[i] = target[i]; + } + } + + function is2DArray(value) { + return isArrayLike(value[0]); + } + + function copyValue(target, source, key) { + if (isArrayLike(source[key])) { + if (!isArrayLike(target[key])) { + target[key] = []; + } + + if (isTypedArray(source[key])) { + var len = source[key].length; + + if (target[key].length !== len) { + target[key] = new source[key].constructor(len); + copyArrShallow(target[key], source[key], len); + } + } else { + var sourceArr = source[key]; + var targetArr = target[key]; + var len0 = sourceArr.length; + + if (is2DArray(sourceArr)) { + var len1 = sourceArr[0].length; + + for (var i = 0; i < len0; i++) { + if (!targetArr[i]) { + targetArr[i] = Array.prototype.slice.call(sourceArr[i]); + } else { + copyArrShallow(targetArr[i], sourceArr[i], len1); + } + } + } else { + copyArrShallow(targetArr, sourceArr, len0); + } + + targetArr.length = sourceArr.length; + } + } else { + target[key] = source[key]; + } + } + + function isValueSame(val1, val2) { + return val1 === val2 || isArrayLike(val1) && isArrayLike(val2) && is1DArraySame(val1, val2); + } + + function is1DArraySame(arr0, arr1) { + var len = arr0.length; + + if (len !== arr1.length) { + return false; + } + + for (var i = 0; i < len; i++) { + if (arr0[i] !== arr1[i]) { + return false; + } + } + + return true; + } + + function animateToShallow(animatable, topKey, animateObj, target, cfg, animationProps, animators, reverse) { + var targetKeys = keys(target); + var duration = cfg.duration; + var delay = cfg.delay; + var additive = cfg.additive; + var setToFinal = cfg.setToFinal; + var animateAll = !isObject$2(animationProps); + var existsAnimators = animatable.animators; + var animationKeys = []; + + for (var k = 0; k < targetKeys.length; k++) { + var innerKey = targetKeys[k]; + var targetVal = target[innerKey]; + + if (targetVal != null && animateObj[innerKey] != null && (animateAll || animationProps[innerKey])) { + if (isObject$2(targetVal) && !isArrayLike(targetVal) && !isGradientObject(targetVal)) { + if (topKey) { + if (!reverse) { + animateObj[innerKey] = targetVal; + animatable.updateDuringAnimation(topKey); + } + + continue; + } + + animateToShallow(animatable, innerKey, animateObj[innerKey], targetVal, cfg, animationProps && animationProps[innerKey], animators, reverse); + } else { + animationKeys.push(innerKey); + } + } else if (!reverse) { + animateObj[innerKey] = targetVal; + animatable.updateDuringAnimation(topKey); + animationKeys.push(innerKey); + } + } + + var keyLen = animationKeys.length; + + if (!additive && keyLen) { + for (var i = 0; i < existsAnimators.length; i++) { + var animator = existsAnimators[i]; + + if (animator.targetName === topKey) { + var allAborted = animator.stopTracks(animationKeys); + + if (allAborted) { + var idx = indexOf(existsAnimators, animator); + existsAnimators.splice(idx, 1); + } + } + } + } + + if (!cfg.force) { + animationKeys = filter(animationKeys, function (key) { + return !isValueSame(target[key], animateObj[key]); + }); + keyLen = animationKeys.length; + } + + if (keyLen > 0 || cfg.force && !animators.length) { + var revertedSource = void 0; + var reversedTarget = void 0; + var sourceClone = void 0; + + if (reverse) { + reversedTarget = {}; + + if (setToFinal) { + revertedSource = {}; + } + + for (var i = 0; i < keyLen; i++) { + var innerKey = animationKeys[i]; + reversedTarget[innerKey] = animateObj[innerKey]; + + if (setToFinal) { + revertedSource[innerKey] = target[innerKey]; + } else { + animateObj[innerKey] = target[innerKey]; + } + } + } else if (setToFinal) { + sourceClone = {}; + + for (var i = 0; i < keyLen; i++) { + var innerKey = animationKeys[i]; + sourceClone[innerKey] = cloneValue(animateObj[innerKey]); + copyValue(animateObj, target, innerKey); + } + } + + var animator = new Animator(animateObj, false, false, additive ? filter(existsAnimators, function (animator) { + return animator.targetName === topKey; + }) : null); + animator.targetName = topKey; + + if (cfg.scope) { + animator.scope = cfg.scope; + } + + if (setToFinal && revertedSource) { + animator.whenWithKeys(0, revertedSource, animationKeys); + } + + if (sourceClone) { + animator.whenWithKeys(0, sourceClone, animationKeys); + } + + animator.whenWithKeys(duration == null ? 500 : duration, reverse ? reversedTarget : target, animationKeys).delay(delay || 0); + animatable.addAnimator(animator, topKey); + animators.push(animator); + } + } + + var Group$2 = function (_super) { + __extends(Group, _super); + + function Group(opts) { + var _this = _super.call(this) || this; + + _this.isGroup = true; + _this._children = []; + + _this.attr(opts); + + return _this; + } + + Group.prototype.childrenRef = function () { + return this._children; + }; + + Group.prototype.children = function () { + return this._children.slice(); + }; + + Group.prototype.childAt = function (idx) { + return this._children[idx]; + }; + + Group.prototype.childOfName = function (name) { + var children = this._children; + + for (var i = 0; i < children.length; i++) { + if (children[i].name === name) { + return children[i]; + } + } + }; + + Group.prototype.childCount = function () { + return this._children.length; + }; + + Group.prototype.add = function (child) { + if (child) { + if (child !== this && child.parent !== this) { + this._children.push(child); + + this._doAdd(child); + } + + { + if (child.__hostTarget) { + throw 'This elemenet has been used as an attachment'; + } + } + } + + return this; + }; + + Group.prototype.addBefore = function (child, nextSibling) { + if (child && child !== this && child.parent !== this && nextSibling && nextSibling.parent === this) { + var children = this._children; + var idx = children.indexOf(nextSibling); + + if (idx >= 0) { + children.splice(idx, 0, child); + + this._doAdd(child); + } + } + + return this; + }; + + Group.prototype.replace = function (oldChild, newChild) { + var idx = indexOf(this._children, oldChild); + + if (idx >= 0) { + this.replaceAt(newChild, idx); + } + + return this; + }; + + Group.prototype.replaceAt = function (child, index) { + var children = this._children; + var old = children[index]; + + if (child && child !== this && child.parent !== this && child !== old) { + children[index] = child; + old.parent = null; + var zr = this.__zr; + + if (zr) { + old.removeSelfFromZr(zr); + } + + this._doAdd(child); + } + + return this; + }; + + Group.prototype._doAdd = function (child) { + if (child.parent) { + child.parent.remove(child); + } + + child.parent = this; + var zr = this.__zr; + + if (zr && zr !== child.__zr) { + child.addSelfToZr(zr); + } + + zr && zr.refresh(); + }; + + Group.prototype.remove = function (child) { + var zr = this.__zr; + var children = this._children; + var idx = indexOf(children, child); + + if (idx < 0) { + return this; + } + + children.splice(idx, 1); + child.parent = null; + + if (zr) { + child.removeSelfFromZr(zr); + } + + zr && zr.refresh(); + return this; + }; + + Group.prototype.removeAll = function () { + var children = this._children; + var zr = this.__zr; + + for (var i = 0; i < children.length; i++) { + var child = children[i]; + + if (zr) { + child.removeSelfFromZr(zr); + } + + child.parent = null; + } + + children.length = 0; + return this; + }; + + Group.prototype.eachChild = function (cb, context) { + var children = this._children; + + for (var i = 0; i < children.length; i++) { + var child = children[i]; + cb.call(context, child, i); + } + + return this; + }; + + Group.prototype.traverse = function (cb, context) { + for (var i = 0; i < this._children.length; i++) { + var child = this._children[i]; + var stopped = cb.call(context, child); + + if (child.isGroup && !stopped) { + child.traverse(cb, context); + } + } + + return this; + }; + + Group.prototype.addSelfToZr = function (zr) { + _super.prototype.addSelfToZr.call(this, zr); + + for (var i = 0; i < this._children.length; i++) { + var child = this._children[i]; + child.addSelfToZr(zr); + } + }; + + Group.prototype.removeSelfFromZr = function (zr) { + _super.prototype.removeSelfFromZr.call(this, zr); + + for (var i = 0; i < this._children.length; i++) { + var child = this._children[i]; + child.removeSelfFromZr(zr); + } + }; + + Group.prototype.getBoundingRect = function (includeChildren) { + var tmpRect = new BoundingRect(0, 0, 0, 0); + var children = includeChildren || this._children; + var tmpMat = []; + var rect = null; + + for (var i = 0; i < children.length; i++) { + var child = children[i]; + + if (child.ignore || child.invisible) { + continue; + } + + var childRect = child.getBoundingRect(); + var transform = child.getLocalTransform(tmpMat); + + if (transform) { + BoundingRect.applyTransform(tmpRect, childRect, transform); + rect = rect || tmpRect.clone(); + rect.union(tmpRect); + } else { + rect = rect || childRect.clone(); + rect.union(childRect); + } + } + + return rect || tmpRect; + }; + + return Group; + }(Element); + + Group$2.prototype.type = 'group'; + /*! + * ZRender, a high performance 2d drawing library. + * + * Copyright (c) 2013, Baidu Inc. + * All rights reserved. + * + * LICENSE + * https://github.com/ecomfe/zrender/blob/master/LICENSE.txt + */ + + var painterCtors = {}; + var instances$1 = {}; + + function delInstance(id) { + delete instances$1[id]; + } + + function isDarkMode(backgroundColor) { + if (!backgroundColor) { + return false; + } + + if (typeof backgroundColor === 'string') { + return lum(backgroundColor, 1) < DARK_MODE_THRESHOLD; + } else if (backgroundColor.colorStops) { + var colorStops = backgroundColor.colorStops; + var totalLum = 0; + var len = colorStops.length; + + for (var i = 0; i < len; i++) { + totalLum += lum(colorStops[i].color, 1); + } + + totalLum /= len; + return totalLum < DARK_MODE_THRESHOLD; + } + + return false; + } + + var ZRender = function () { + function ZRender(id, dom, opts) { + var _this = this; + + this._sleepAfterStill = 10; + this._stillFrameAccum = 0; + this._needsRefresh = true; + this._needsRefreshHover = true; + this._darkMode = false; + opts = opts || {}; + this.dom = dom; + this.id = id; + var storage = new Storage(); + var rendererType = opts.renderer || 'canvas'; + + if (!painterCtors[rendererType]) { + rendererType = keys(painterCtors)[0]; + } + + { + if (!painterCtors[rendererType]) { + throw new Error("Renderer '" + rendererType + "' is not imported. Please import it first."); + } + } + opts.useDirtyRect = opts.useDirtyRect == null ? false : opts.useDirtyRect; + var painter = new painterCtors[rendererType](dom, storage, opts, id); + var ssrMode = opts.ssr || painter.ssrOnly; + this.storage = storage; + this.painter = painter; + var handlerProxy = !env.node && !env.worker && !ssrMode ? new HandlerDomProxy(painter.getViewportRoot(), painter.root) : null; + var useCoarsePointer = opts.useCoarsePointer; + var usePointerSize = useCoarsePointer == null || useCoarsePointer === 'auto' ? env.touchEventsSupported : !!useCoarsePointer; + var defaultPointerSize = 44; + var pointerSize; + + if (usePointerSize) { + pointerSize = retrieve2(opts.pointerSize, defaultPointerSize); + } + + this.handler = new Handler(storage, painter, handlerProxy, painter.root, pointerSize); + this.animation = new Animation({ + stage: { + update: ssrMode ? null : function () { + return _this._flush(true); + } + } + }); + + if (!ssrMode) { + this.animation.start(); + } + } + + ZRender.prototype.add = function (el) { + if (this._disposed || !el) { + return; + } + + this.storage.addRoot(el); + el.addSelfToZr(this); + this.refresh(); + }; + + ZRender.prototype.remove = function (el) { + if (this._disposed || !el) { + return; + } + + this.storage.delRoot(el); + el.removeSelfFromZr(this); + this.refresh(); + }; + + ZRender.prototype.configLayer = function (zLevel, config) { + if (this._disposed) { + return; + } + + if (this.painter.configLayer) { + this.painter.configLayer(zLevel, config); + } + + this.refresh(); + }; + + ZRender.prototype.setBackgroundColor = function (backgroundColor) { + if (this._disposed) { + return; + } + + if (this.painter.setBackgroundColor) { + this.painter.setBackgroundColor(backgroundColor); + } + + this.refresh(); + this._backgroundColor = backgroundColor; + this._darkMode = isDarkMode(backgroundColor); + }; + + ZRender.prototype.getBackgroundColor = function () { + return this._backgroundColor; + }; + + ZRender.prototype.setDarkMode = function (darkMode) { + this._darkMode = darkMode; + }; + + ZRender.prototype.isDarkMode = function () { + return this._darkMode; + }; + + ZRender.prototype.refreshImmediately = function (fromInside) { + if (this._disposed) { + return; + } + + if (!fromInside) { + this.animation.update(true); + } + + this._needsRefresh = false; + this.painter.refresh(); + this._needsRefresh = false; + }; + + ZRender.prototype.refresh = function () { + if (this._disposed) { + return; + } + + this._needsRefresh = true; + this.animation.start(); + }; + + ZRender.prototype.flush = function () { + if (this._disposed) { + return; + } + + this._flush(false); + }; + + ZRender.prototype._flush = function (fromInside) { + var triggerRendered; + var start = getTime(); + + if (this._needsRefresh) { + triggerRendered = true; + this.refreshImmediately(fromInside); + } + + if (this._needsRefreshHover) { + triggerRendered = true; + this.refreshHoverImmediately(); + } + + var end = getTime(); + + if (triggerRendered) { + this._stillFrameAccum = 0; + this.trigger('rendered', { + elapsedTime: end - start + }); + } else if (this._sleepAfterStill > 0) { + this._stillFrameAccum++; + + if (this._stillFrameAccum > this._sleepAfterStill) { + this.animation.stop(); + } + } + }; + + ZRender.prototype.setSleepAfterStill = function (stillFramesCount) { + this._sleepAfterStill = stillFramesCount; + }; + + ZRender.prototype.wakeUp = function () { + if (this._disposed) { + return; + } + + this.animation.start(); + this._stillFrameAccum = 0; + }; + + ZRender.prototype.refreshHover = function () { + this._needsRefreshHover = true; + }; + + ZRender.prototype.refreshHoverImmediately = function () { + if (this._disposed) { + return; + } + + this._needsRefreshHover = false; + + if (this.painter.refreshHover && this.painter.getType() === 'canvas') { + this.painter.refreshHover(); + } + }; + + ZRender.prototype.resize = function (opts) { + if (this._disposed) { + return; + } + + opts = opts || {}; + this.painter.resize(opts.width, opts.height); + this.handler.resize(); + }; + + ZRender.prototype.clearAnimation = function () { + if (this._disposed) { + return; + } + + this.animation.clear(); + }; + + ZRender.prototype.getWidth = function () { + if (this._disposed) { + return; + } + + return this.painter.getWidth(); + }; + + ZRender.prototype.getHeight = function () { + if (this._disposed) { + return; + } + + return this.painter.getHeight(); + }; + + ZRender.prototype.setCursorStyle = function (cursorStyle) { + if (this._disposed) { + return; + } + + this.handler.setCursorStyle(cursorStyle); + }; + + ZRender.prototype.findHover = function (x, y) { + if (this._disposed) { + return; + } + + return this.handler.findHover(x, y); + }; + + ZRender.prototype.on = function (eventName, eventHandler, context) { + if (!this._disposed) { + this.handler.on(eventName, eventHandler, context); + } + + return this; + }; + + ZRender.prototype.off = function (eventName, eventHandler) { + if (this._disposed) { + return; + } + + this.handler.off(eventName, eventHandler); + }; + + ZRender.prototype.trigger = function (eventName, event) { + if (this._disposed) { + return; + } + + this.handler.trigger(eventName, event); + }; + + ZRender.prototype.clear = function () { + if (this._disposed) { + return; + } + + var roots = this.storage.getRoots(); + + for (var i = 0; i < roots.length; i++) { + if (roots[i] instanceof Group$2) { + roots[i].removeSelfFromZr(this); + } + } + + this.storage.delAllRoots(); + this.painter.clear(); + }; + + ZRender.prototype.dispose = function () { + if (this._disposed) { + return; + } + + this.animation.stop(); + this.clear(); + this.storage.dispose(); + this.painter.dispose(); + this.handler.dispose(); + this.animation = this.storage = this.painter = this.handler = null; + this._disposed = true; + delInstance(this.id); + }; + + return ZRender; + }(); + + function init$1(dom, opts) { + var zr = new ZRender(guid(), dom, opts); + instances$1[zr.id] = zr; + return zr; + } + + function dispose$1(zr) { + zr.dispose(); + } + + function disposeAll() { + for (var key in instances$1) { + if (instances$1.hasOwnProperty(key)) { + instances$1[key].dispose(); + } + } + + instances$1 = {}; + } + + function getInstance(id) { + return instances$1[id]; + } + + function registerPainter(name, Ctor) { + painterCtors[name] = Ctor; + } + + var ssrDataGetter; + + function getElementSSRData(el) { + if (typeof ssrDataGetter === 'function') { + return ssrDataGetter(el); + } + } + + function registerSSRDataGetter(getter) { + ssrDataGetter = getter; + } + + var version$1 = '6.0.0'; + var zrender = /*#__PURE__*/Object.freeze({ + __proto__: null, + dispose: dispose$1, + disposeAll: disposeAll, + getElementSSRData: getElementSSRData, + getInstance: getInstance, + init: init$1, + registerPainter: registerPainter, + registerSSRDataGetter: registerSSRDataGetter, + version: version$1 + }); + var RADIAN_EPSILON = 1e-4; // Although chrome already enlarge this number to 100 for `toFixed`, but + // we sill follow the spec for compatibility. + + var ROUND_SUPPORTED_PRECISION_MAX = 20; + + function _trim(str) { + return str.replace(/^\s+|\s+$/g, ''); + } + + var mathMin$6 = Math.min; + var mathMax$6 = Math.max; + var mathAbs$3 = Math.abs; + /** + * Linear mapping a value from domain to range + * @param val + * @param domain Domain extent domain[0] can be bigger than domain[1] + * @param range Range extent range[0] can be bigger than range[1] + * @param clamp Default to be false + */ + + function linearMap(val, domain, range, clamp) { + var d0 = domain[0]; + var d1 = domain[1]; + var r0 = range[0]; + var r1 = range[1]; + var subDomain = d1 - d0; + var subRange = r1 - r0; + + if (subDomain === 0) { + return subRange === 0 ? r0 : (r0 + r1) / 2; + } // Avoid accuracy problem in edge, such as + // 146.39 - 62.83 === 83.55999999999999. + // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError + // It is a little verbose for efficiency considering this method + // is a hotspot. + + + if (clamp) { + if (subDomain > 0) { + if (val <= d0) { + return r0; + } else if (val >= d1) { + return r1; + } + } else { + if (val >= d0) { + return r0; + } else if (val <= d1) { + return r1; + } + } + } else { + if (val === d0) { + return r0; + } + + if (val === d1) { + return r1; + } + } + + return (val - d0) / subDomain * subRange + r0; + } + /** + * Preserve the name `parsePercent` for backward compatibility, + * and it's effectively published as `echarts.number.parsePercent`. + */ + + + var parsePercent = parsePositionOption; + /** + * @see {parsePositionSizeOption} and also accept a string preset. + * @see {PositionSizeOption} + */ + + function parsePositionOption(option, percentBase, percentOffset) { + switch (option) { + case 'center': + case 'middle': + option = '50%'; + break; + + case 'left': + case 'top': + option = '0%'; + break; + + case 'right': + case 'bottom': + option = '100%'; + break; + } + + return parsePositionSizeOption(option, percentBase, percentOffset); + } + /** + * Accept number, or numeric stirng (`'123'`), or percentage ('100%'), as x/y/width/height pixel number. + * If null/undefined or invalid, return NaN. + * (But allow JS type coercion (`+option`) due to backward compatibility) + * @see {PositionSizeOption} + */ + + + function parsePositionSizeOption(option, percentBase, percentOffset) { + if (isString(option)) { + if (_trim(option).match(/%$/)) { + return parseFloat(option) / 100 * percentBase + (percentOffset || 0); + } + + return parseFloat(option); + } // Allow flexible input due to backward compatibility. + + + return option == null ? NaN : +option; + } + + function round$1(x, precision, returnStr) { + if (precision == null) { + // FIXME: the default precision should not be provided, since there is no universally adaptable + // precision. The caller need to input a precision according to the scenarios. + precision = 10; + } // Avoid range error + + + precision = Math.min(Math.max(0, precision), ROUND_SUPPORTED_PRECISION_MAX); // PENDING: 1.005.toFixed(2) is '1.00' rather than '1.01' + + x = (+x).toFixed(precision); + return returnStr ? x : +x; + } + /** + * Inplacd asc sort arr. + * The input arr will be modified. + */ + + + function asc(arr) { + arr.sort(function (a, b) { + return a - b; + }); + return arr; + } + /** + * Get precision. + */ + + + function getPrecision(val) { + val = +val; + + if (isNaN(val)) { + return 0; + } // It is much faster than methods converting number to string as follows + // let tmp = val.toString(); + // return tmp.length - 1 - tmp.indexOf('.'); + // especially when precision is low + // Notice: + // (1) If the loop count is over about 20, it is slower than `getPrecisionSafe`. + // (see https://jsbench.me/2vkpcekkvw/1) + // (2) If the val is less than for example 1e-15, the result may be incorrect. + // (see test/ut/spec/util/number.test.ts `getPrecision_equal_random`) + + + if (val > 1e-14) { + var e = 1; + + for (var i = 0; i < 15; i++, e *= 10) { + if (Math.round(val * e) / e === val) { + return i; + } + } + } + + return getPrecisionSafe(val); + } + /** + * Get precision with slow but safe method + */ + + + function getPrecisionSafe(val) { + // toLowerCase for: '3.4E-12' + var str = val.toString().toLowerCase(); // Consider scientific notation: '3.4e-12' '3.4e+12' + + var eIndex = str.indexOf('e'); + var exp = eIndex > 0 ? +str.slice(eIndex + 1) : 0; + var significandPartLen = eIndex > 0 ? eIndex : str.length; + var dotIndex = str.indexOf('.'); + var decimalPartLen = dotIndex < 0 ? 0 : significandPartLen - 1 - dotIndex; + return Math.max(0, decimalPartLen - exp); + } + /** + * Minimal dicernible data precisioin according to a single pixel. + */ + + + function getPixelPrecision(dataExtent, pixelExtent) { + var log = Math.log; + var LN10 = Math.LN10; + var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10); + var sizeQuantity = Math.round(log(mathAbs$3(pixelExtent[1] - pixelExtent[0])) / LN10); // toFixed() digits argument must be between 0 and 20. + + var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20); + return !isFinite(precision) ? 20 : precision; + } + /** + * Get a data of given precision, assuring the sum of percentages + * in valueList is 1. + * The largest remainder method is used. + * https://en.wikipedia.org/wiki/Largest_remainder_method + * + * @param valueList a list of all data + * @param idx index of the data to be processed in valueList + * @param precision integer number showing digits of precision + * @return percent ranging from 0 to 100 + */ + + + function getPercentWithPrecision(valueList, idx, precision) { + if (!valueList[idx]) { + return 0; + } + + var seats = getPercentSeats(valueList, precision); + return seats[idx] || 0; + } + /** + * Get a data of given precision, assuring the sum of percentages + * in valueList is 1. + * The largest remainder method is used. + * https://en.wikipedia.org/wiki/Largest_remainder_method + * + * @param valueList a list of all data + * @param precision integer number showing digits of precision + * @return {Array} + */ + + + function getPercentSeats(valueList, precision) { + var sum = reduce(valueList, function (acc, val) { + return acc + (isNaN(val) ? 0 : val); + }, 0); + + if (sum === 0) { + return []; + } + + var digits = Math.pow(10, precision); + var votesPerQuota = map$1(valueList, function (val) { + return (isNaN(val) ? 0 : val) / sum * digits * 100; + }); + var targetSeats = digits * 100; + var seats = map$1(votesPerQuota, function (votes) { + // Assign automatic seats. + return Math.floor(votes); + }); + var currentSum = reduce(seats, function (acc, val) { + return acc + val; + }, 0); + var remainder = map$1(votesPerQuota, function (votes, idx) { + return votes - seats[idx]; + }); // Has remainding votes. + + while (currentSum < targetSeats) { + // Find next largest remainder. + var max = Number.NEGATIVE_INFINITY; + var maxId = null; + + for (var i = 0, len = remainder.length; i < len; ++i) { + if (remainder[i] > max) { + max = remainder[i]; + maxId = i; + } + } // Add a vote to max remainder. + + + ++seats[maxId]; + remainder[maxId] = 0; + ++currentSum; + } + + return map$1(seats, function (seat) { + return seat / digits; + }); + } + /** + * Solve the floating point adding problem like 0.1 + 0.2 === 0.30000000000000004 + * See + */ + + + function addSafe(val0, val1) { + var maxPrecision = Math.max(getPrecision(val0), getPrecision(val1)); // const multiplier = Math.pow(10, maxPrecision); + // return (Math.round(val0 * multiplier) + Math.round(val1 * multiplier)) / multiplier; + + var sum = val0 + val1; // // PENDING: support more? + + return maxPrecision > ROUND_SUPPORTED_PRECISION_MAX ? sum : round$1(sum, maxPrecision); + } // Number.MAX_SAFE_INTEGER, ie do not support. + + + var MAX_SAFE_INTEGER = 9007199254740991; + /** + * To 0 - 2 * PI, considering negative radian. + */ + + function remRadian(radian) { + var pi2 = Math.PI * 2; + return (radian % pi2 + pi2) % pi2; + } + /** + * @param {type} radian + * @return {boolean} + */ + + + function isRadianAroundZero(val) { + return val > -RADIAN_EPSILON && val < RADIAN_EPSILON; + } // eslint-disable-next-line + + + var TIME_REG = /^(?:(\d{4})(?:[-\/](\d{1,2})(?:[-\/](\d{1,2})(?:[T ](\d{1,2})(?::(\d{1,2})(?::(\d{1,2})(?:[.,](\d+))?)?)?(Z|[\+\-]\d\d:?\d\d)?)?)?)?)?$/; // jshint ignore:line + + /** + * @param value valid type: number | string | Date, otherwise return `new Date(NaN)` + * These values can be accepted: + * + An instance of Date, represent a time in its own time zone. + * + Or string in a subset of ISO 8601, only including: + * + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06', + * + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123', + * + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00', + * all of which will be treated as local time if time zone is not specified + * (see ). + * + Or other string format, including (all of which will be treated as local time): + * '2012', '2012-3-1', '2012/3/1', '2012/03/01', + * '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123' + * + a timestamp, which represent a time in UTC. + * @return date Never be null/undefined. If invalid, return `new Date(NaN)`. + */ + + function parseDate(value) { + if (value instanceof Date) { + return value; + } else if (isString(value)) { + // Different browsers parse date in different way, so we parse it manually. + // Some other issues: + // new Date('1970-01-01') is UTC, + // new Date('1970/01/01') and new Date('1970-1-01') is local. + // See issue #3623 + var match = TIME_REG.exec(value); + + if (!match) { + // return Invalid Date. + return new Date(NaN); + } // Use local time when no timezone offset is specified. + + + if (!match[8]) { + // match[n] can only be string or undefined. + // But take care of '12' + 1 => '121'. + return new Date(+match[1], +(match[2] || 1) - 1, +match[3] || 1, +match[4] || 0, +(match[5] || 0), +match[6] || 0, match[7] ? +match[7].substring(0, 3) : 0); + } // Timezoneoffset of Javascript Date has considered DST (Daylight Saving Time, + // https://tc39.github.io/ecma262/#sec-daylight-saving-time-adjustment). + // For example, system timezone is set as "Time Zone: America/Toronto", + // then these code will get different result: + // `new Date(1478411999999).getTimezoneOffset(); // get 240` + // `new Date(1478412000000).getTimezoneOffset(); // get 300` + // So we should not use `new Date`, but use `Date.UTC`. + else { + var hour = +match[4] || 0; + + if (match[8].toUpperCase() !== 'Z') { + hour -= +match[8].slice(0, 3); + } + + return new Date(Date.UTC(+match[1], +(match[2] || 1) - 1, +match[3] || 1, hour, +(match[5] || 0), +match[6] || 0, match[7] ? +match[7].substring(0, 3) : 0)); + } + } else if (value == null) { + return new Date(NaN); + } + + return new Date(Math.round(value)); + } + /** + * Quantity of a number. e.g. 0.1, 1, 10, 100 + * + * @param val + * @return + */ + + + function quantity(val) { + return Math.pow(10, quantityExponent(val)); + } + /** + * Exponent of the quantity of a number + * e.g., 1234 equals to 1.234*10^3, so quantityExponent(1234) is 3 + * + * @param val non-negative value + * @return + */ + + + function quantityExponent(val) { + if (val === 0) { + return 0; + } + + var exp = Math.floor(Math.log(val) / Math.LN10); + /** + * exp is expected to be the rounded-down result of the base-10 log of val. + * But due to the precision loss with Math.log(val), we need to restore it + * using 10^exp to make sure we can get val back from exp. #11249 + */ + + if (val / Math.pow(10, exp) >= 10) { + exp++; + } + + return exp; + } + /** + * find a “nice” number approximately equal to x. Round the number if round = true, + * take ceiling if round = false. The primary observation is that the “nicest” + * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers. + * + * See "Nice Numbers for Graph Labels" of Graphic Gems. + * + * @param val Non-negative value. + * @param round + * @return Niced number + */ + + + function nice(val, round) { + var exponent = quantityExponent(val); + var exp10 = Math.pow(10, exponent); + var f = val / exp10; // 1 <= f < 10 + + var nf; + + if (round) { + if (f < 1.5) { + nf = 1; + } else if (f < 2.5) { + nf = 2; + } else if (f < 4) { + nf = 3; + } else if (f < 7) { + nf = 5; + } else { + nf = 10; + } + } else { + if (f < 1) { + nf = 1; + } else if (f < 2) { + nf = 2; + } else if (f < 3) { + nf = 3; + } else if (f < 5) { + nf = 5; + } else { + nf = 10; + } + } + + val = nf * exp10; // Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754). + // 20 is the uppper bound of toFixed. + + return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val; + } + /** + * This code was copied from "d3.js" + * . + * See the license statement at the head of this file. + * @param ascArr + */ + + + function quantile(ascArr, p) { + var H = (ascArr.length - 1) * p + 1; + var h = Math.floor(H); + var v = +ascArr[h - 1]; + var e = H - h; + return e ? v + e * (ascArr[h] - v) : v; + } + /** + * Order intervals asc, and split them when overlap. + * expect(numberUtil.reformIntervals([ + * {interval: [18, 62], close: [1, 1]}, + * {interval: [-Infinity, -70], close: [0, 0]}, + * {interval: [-70, -26], close: [1, 1]}, + * {interval: [-26, 18], close: [1, 1]}, + * {interval: [62, 150], close: [1, 1]}, + * {interval: [106, 150], close: [1, 1]}, + * {interval: [150, Infinity], close: [0, 0]} + * ])).toEqual([ + * {interval: [-Infinity, -70], close: [0, 0]}, + * {interval: [-70, -26], close: [1, 1]}, + * {interval: [-26, 18], close: [0, 1]}, + * {interval: [18, 62], close: [0, 1]}, + * {interval: [62, 150], close: [0, 1]}, + * {interval: [150, Infinity], close: [0, 0]} + * ]); + * @param list, where `close` mean open or close + * of the interval, and Infinity can be used. + * @return The origin list, which has been reformed. + */ + + + function reformIntervals(list) { + list.sort(function (a, b) { + return littleThan(a, b, 0) ? -1 : 1; + }); + var curr = -Infinity; + var currClose = 1; + + for (var i = 0; i < list.length;) { + var interval = list[i].interval; + var close_1 = list[i].close; + + for (var lg = 0; lg < 2; lg++) { + if (interval[lg] <= curr) { + interval[lg] = curr; + close_1[lg] = !lg ? 1 - currClose : 1; + } + + curr = interval[lg]; + currClose = close_1[lg]; + } + + if (interval[0] === interval[1] && close_1[0] * close_1[1] !== 1) { + list.splice(i, 1); + } else { + i++; + } + } + + return list; + + function littleThan(a, b, lg) { + return a.interval[lg] < b.interval[lg] || a.interval[lg] === b.interval[lg] && (a.close[lg] - b.close[lg] === (!lg ? 1 : -1) || !lg && littleThan(a, b, 1)); + } + } + /** + * [Numeric is defined as]: + * `parseFloat(val) == val` + * For example: + * numeric: + * typeof number except NaN, '-123', '123', '2e3', '-2e3', '011', 'Infinity', Infinity, + * and they rounded by white-spaces or line-terminal like ' -123 \n ' (see es spec) + * not-numeric: + * null, undefined, [], {}, true, false, 'NaN', NaN, '123ab', + * empty string, string with only white-spaces or line-terminal (see es spec), + * 0x12, '0x12', '-0x12', 012, '012', '-012', + * non-string, ... + * + * @test See full test cases in `test/ut/spec/util/number.js`. + * @return Must be a typeof number. If not numeric, return NaN. + */ + + + function numericToNumber(val) { + var valFloat = parseFloat(val); + return valFloat == val // eslint-disable-line eqeqeq + && (valFloat !== 0 || !isString(val) || val.indexOf('x') <= 0) // For case ' 0x0 '. + ? valFloat : NaN; + } + /** + * Definition of "numeric": see `numericToNumber`. + */ + + + function isNumeric(val) { + return !isNaN(numericToNumber(val)); + } + /** + * Use random base to prevent users hard code depending on + * this auto generated marker id. + * @return An positive integer. + */ + + + function getRandomIdBase() { + return Math.round(Math.random() * 9); + } + /** + * Get the greatest common divisor. + * + * @param {number} a one number + * @param {number} b the other number + */ + + + function getGreatestCommonDividor(a, b) { + if (b === 0) { + return a; + } + + return getGreatestCommonDividor(b, a % b); + } + /** + * Get the least common multiple. + * + * @param {number} a one number + * @param {number} b the other number + */ + + + function getLeastCommonMultiple(a, b) { + if (a == null) { + return b; + } + + if (b == null) { + return a; + } + + return a * b / getGreatestCommonDividor(a, b); + } + + var ECHARTS_PREFIX = '[ECharts] '; + var storedLogs = {}; + var hasConsole = typeof console !== 'undefined' // eslint-disable-next-line + && console.warn && console.log; + + function outputLog(type, str, onlyOnce) { + if (hasConsole) { + if (onlyOnce) { + if (storedLogs[str]) { + return; + } + + storedLogs[str] = true; + } // eslint-disable-next-line + + + console[type](ECHARTS_PREFIX + str); + } + } + + function log(str, onlyOnce) { + outputLog('log', str, onlyOnce); + } + + function warn(str, onlyOnce) { + outputLog('warn', str, onlyOnce); + } + + function error(str, onlyOnce) { + outputLog('error', str, onlyOnce); + } + + function deprecateLog(str) { + { + // Not display duplicate message. + outputLog('warn', 'DEPRECATED: ' + str, true); + } + } + + function deprecateReplaceLog(oldOpt, newOpt, scope) { + { + deprecateLog((scope ? "[" + scope + "]" : '') + (oldOpt + " is deprecated; use " + newOpt + " instead.")); + } + } + /** + * If in __DEV__ environment, get console printable message for users hint. + * Parameters are separated by ' '. + * @usage + * makePrintable('This is an error on', someVar, someObj); + * + * @param hintInfo anything about the current execution context to hint users. + * @throws Error + */ + + + function makePrintable() { + var hintInfo = []; + + for (var _i = 0; _i < arguments.length; _i++) { + hintInfo[_i] = arguments[_i]; + } + + var msg = ''; + { + // Fuzzy stringify for print. + // This code only exist in dev environment. + var makePrintableStringIfPossible_1 = function (val) { + return val === void 0 ? 'undefined' : val === Infinity ? 'Infinity' : val === -Infinity ? '-Infinity' : eqNaN(val) ? 'NaN' : val instanceof Date ? 'Date(' + val.toISOString() + ')' : isFunction(val) ? 'function () { ... }' : isRegExp(val) ? val + '' : null; + }; + + msg = map$1(hintInfo, function (arg) { + if (isString(arg)) { + // Print without quotation mark for some statement. + return arg; + } else { + var printableStr = makePrintableStringIfPossible_1(arg); + + if (printableStr != null) { + return printableStr; + } else if (typeof JSON !== 'undefined' && JSON.stringify) { + try { + return JSON.stringify(arg, function (n, val) { + var printableStr = makePrintableStringIfPossible_1(val); + return printableStr == null ? val : printableStr; + }); // In most cases the info object is small, so do not line break. + } catch (err) { + return '?'; + } + } else { + return '?'; + } + } + }).join(' '); + } + return msg; + } + /** + * @throws Error + */ + + + function throwError(msg) { + throw new Error(msg); + } + + function interpolateNumber(p0, p1, percent) { + return (p1 - p0) * percent + p0; + } + /** + * Make the name displayable. But we should + * make sure it is not duplicated with user + * specified name, so use '\0'; + */ + + + var DUMMY_COMPONENT_NAME_PREFIX = 'series\0'; + var INTERNAL_COMPONENT_ID_PREFIX = '\0_ec_\0'; + /** + * If value is not array, then translate it to array. + * @param {*} value + * @return {Array} [value] or value + */ + + function normalizeToArray(value) { + return value instanceof Array ? value : value == null ? [] : [value]; + } + /** + * Sync default option between normal and emphasis like `position` and `show` + * In case some one will write code like + * label: { + * show: false, + * position: 'outside', + * fontSize: 18 + * }, + * emphasis: { + * label: { show: true } + * } + */ + + + function defaultEmphasis(opt, key, subOpts) { + // Caution: performance sensitive. + if (opt) { + opt[key] = opt[key] || {}; + opt.emphasis = opt.emphasis || {}; + opt.emphasis[key] = opt.emphasis[key] || {}; // Default emphasis option from normal + + for (var i = 0, len = subOpts.length; i < len; i++) { + var subOptName = subOpts[i]; + + if (!opt.emphasis[key].hasOwnProperty(subOptName) && opt[key].hasOwnProperty(subOptName)) { + opt.emphasis[key][subOptName] = opt[key][subOptName]; + } + } + } + } + + var TEXT_STYLE_OPTIONS = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'rich', 'tag', 'color', 'textBorderColor', 'textBorderWidth', 'width', 'height', 'lineHeight', 'align', 'verticalAlign', 'baseline', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY', 'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY', 'backgroundColor', 'borderColor', 'borderWidth', 'borderRadius', 'padding']; // modelUtil.LABEL_OPTIONS = modelUtil.TEXT_STYLE_OPTIONS.concat([ + // 'position', 'offset', 'rotate', 'origin', 'show', 'distance', 'formatter', + // 'fontStyle', 'fontWeight', 'fontSize', 'fontFamily', + // // FIXME: deprecated, check and remove it. + // 'textStyle' + // ]); + + /** + * The method does not ensure performance. + * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}] + * This helper method retrieves value from data. + */ + + function getDataItemValue(dataItem) { + return isObject$2(dataItem) && !isArray(dataItem) && !(dataItem instanceof Date) ? dataItem.value : dataItem; + } + /** + * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}] + * This helper method determine if dataItem has extra option besides value + */ + + + function isDataItemOption(dataItem) { + return isObject$2(dataItem) && !(dataItem instanceof Array); // // markLine data can be array + // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array)); + } + /** + * Mapping to existings for merge. + * + * Mode "normalMege": + * The mapping result (merge result) will keep the order of the existing + * component, rather than the order of new option. Because we should ensure + * some specified index reference (like xAxisIndex) keep work. + * And in most cases, "merge option" is used to update partial option but not + * be expected to change the order. + * + * Mode "replaceMege": + * (1) Only the id mapped components will be merged. + * (2) Other existing components (except internal components) will be removed. + * (3) Other new options will be used to create new component. + * (4) The index of the existing components will not be modified. + * That means their might be "hole" after the removal. + * The new components are created first at those available index. + * + * Mode "replaceAll": + * This mode try to support that reproduce an echarts instance from another + * echarts instance (via `getOption`) in some simple cases. + * In this scenario, the `result` index are exactly the consistent with the `newCmptOptions`, + * which ensures the component index referring (like `xAxisIndex: ?`) corrent. That is, + * the "hole" in `newCmptOptions` will also be kept. + * On the contrary, other modes try best to eliminate holes. + * PENDING: This is an experimental mode yet. + * + * @return See the comment of . + */ + + + function mappingToExists(existings, newCmptOptions, mode) { + var isNormalMergeMode = mode === 'normalMerge'; + var isReplaceMergeMode = mode === 'replaceMerge'; + var isReplaceAllMode = mode === 'replaceAll'; + existings = existings || []; + newCmptOptions = (newCmptOptions || []).slice(); + var existingIdIdxMap = createHashMap(); // Validate id and name on user input option. + + each$4(newCmptOptions, function (cmptOption, index) { + if (!isObject$2(cmptOption)) { + newCmptOptions[index] = null; + return; + } + + { + // There is some legacy case that name is set as `false`. + // But should work normally rather than throw error. + if (cmptOption.id != null && !isValidIdOrName(cmptOption.id)) { + warnInvalidateIdOrName(cmptOption.id); + } + + if (cmptOption.name != null && !isValidIdOrName(cmptOption.name)) { + warnInvalidateIdOrName(cmptOption.name); + } + } + }); + var result = prepareResult(existings, existingIdIdxMap, mode); + + if (isNormalMergeMode || isReplaceMergeMode) { + mappingById(result, existings, existingIdIdxMap, newCmptOptions); + } + + if (isNormalMergeMode) { + mappingByName(result, newCmptOptions); + } + + if (isNormalMergeMode || isReplaceMergeMode) { + mappingByIndex(result, newCmptOptions, isReplaceMergeMode); + } else if (isReplaceAllMode) { + mappingInReplaceAllMode(result, newCmptOptions); + } + + makeIdAndName(result); // The array `result` MUST NOT contain elided items, otherwise the + // forEach will omit those items and result in incorrect result. + + return result; + } + + function prepareResult(existings, existingIdIdxMap, mode) { + var result = []; + + if (mode === 'replaceAll') { + return result; + } // Do not use native `map` to in case that the array `existings` + // contains elided items, which will be omitted. + + + for (var index = 0; index < existings.length; index++) { + var existing = existings[index]; // Because of replaceMerge, `existing` may be null/undefined. + + if (existing && existing.id != null) { + existingIdIdxMap.set(existing.id, index); + } // For non-internal-componnets: + // Mode "normalMerge": all existings kept. + // Mode "replaceMerge": all existing removed unless mapped by id. + // For internal-components: + // go with "replaceMerge" approach in both mode. + + + result.push({ + existing: mode === 'replaceMerge' || isComponentIdInternal(existing) ? null : existing, + newOption: null, + keyInfo: null, + brandNew: null + }); + } + + return result; + } + + function mappingById(result, existings, existingIdIdxMap, newCmptOptions) { + // Mapping by id if specified. + each$4(newCmptOptions, function (cmptOption, index) { + if (!cmptOption || cmptOption.id == null) { + return; + } + + var optionId = makeComparableKey(cmptOption.id); + var existingIdx = existingIdIdxMap.get(optionId); + + if (existingIdx != null) { + var resultItem = result[existingIdx]; + assert(!resultItem.newOption, 'Duplicated option on id "' + optionId + '".'); + resultItem.newOption = cmptOption; // In both mode, if id matched, new option will be merged to + // the existings rather than creating new component model. + + resultItem.existing = existings[existingIdx]; + newCmptOptions[index] = null; + } + }); + } + + function mappingByName(result, newCmptOptions) { + // Mapping by name if specified. + each$4(newCmptOptions, function (cmptOption, index) { + if (!cmptOption || cmptOption.name == null) { + return; + } + + for (var i = 0; i < result.length; i++) { + var existing = result[i].existing; + + if (!result[i].newOption // Consider name: two map to one. + // Can not match when both ids existing but different. + && existing && (existing.id == null || cmptOption.id == null) && !isComponentIdInternal(cmptOption) && !isComponentIdInternal(existing) && keyExistAndEqual('name', existing, cmptOption)) { + result[i].newOption = cmptOption; + newCmptOptions[index] = null; + return; + } + } + }); + } + + function mappingByIndex(result, newCmptOptions, brandNew) { + each$4(newCmptOptions, function (cmptOption) { + if (!cmptOption) { + return; + } // Find the first place that not mapped by id and not internal component (consider the "hole"). + + + var resultItem; + var nextIdx = 0; + + while ( // Be `!resultItem` only when `nextIdx >= result.length`. + (resultItem = result[nextIdx] // (1) Existing models that already have id should be able to mapped to. Because + // after mapping performed, model will always be assigned with an id if user not given. + // After that all models have id. + // (2) If new option has id, it can only set to a hole or append to the last. It should + // not be merged to the existings with different id. Because id should not be overwritten. + // (3) Name can be overwritten, because axis use name as 'show label text'. + ) && (resultItem.newOption || isComponentIdInternal(resultItem.existing) || // In mode "replaceMerge", here no not-mapped-non-internal-existing. + resultItem.existing && cmptOption.id != null && !keyExistAndEqual('id', cmptOption, resultItem.existing))) { + nextIdx++; + } + + if (resultItem) { + resultItem.newOption = cmptOption; + resultItem.brandNew = brandNew; + } else { + result.push({ + newOption: cmptOption, + brandNew: brandNew, + existing: null, + keyInfo: null + }); + } + + nextIdx++; + }); + } + + function mappingInReplaceAllMode(result, newCmptOptions) { + each$4(newCmptOptions, function (cmptOption) { + // The feature "reproduce" requires "hole" will also reproduced + // in case that component index referring are broken. + result.push({ + newOption: cmptOption, + brandNew: true, + existing: null, + keyInfo: null + }); + }); + } + /** + * Make id and name for mapping result (result of mappingToExists) + * into `keyInfo` field. + */ + + + function makeIdAndName(mapResult) { + // We use this id to hash component models and view instances + // in echarts. id can be specified by user, or auto generated. + // The id generation rule ensures new view instance are able + // to mapped to old instance when setOption are called in + // no-merge mode. So we generate model id by name and plus + // type in view id. + // name can be duplicated among components, which is convenient + // to specify multi components (like series) by one name. + // Ensure that each id is distinct. + var idMap = createHashMap(); + each$4(mapResult, function (item) { + var existing = item.existing; + existing && idMap.set(existing.id, item); + }); + each$4(mapResult, function (item) { + var opt = item.newOption; // Force ensure id not duplicated. + + assert(!opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item, 'id duplicates: ' + (opt && opt.id)); + opt && opt.id != null && idMap.set(opt.id, item); + !item.keyInfo && (item.keyInfo = {}); + }); // Make name and id. + + each$4(mapResult, function (item, index) { + var existing = item.existing; + var opt = item.newOption; + var keyInfo = item.keyInfo; + + if (!isObject$2(opt)) { + return; + } // Name can be overwritten. Consider case: axis.name = '20km'. + // But id generated by name will not be changed, which affect + // only in that case: setOption with 'not merge mode' and view + // instance will be recreated, which can be accepted. + + + keyInfo.name = opt.name != null ? makeComparableKey(opt.name) : existing ? existing.name // Avoid that different series has the same name, + // because name may be used like in color pallet. + : DUMMY_COMPONENT_NAME_PREFIX + index; + + if (existing) { + keyInfo.id = makeComparableKey(existing.id); + } else if (opt.id != null) { + keyInfo.id = makeComparableKey(opt.id); + } else { + // Consider this situatoin: + // optionA: [{name: 'a'}, {name: 'a'}, {..}] + // optionB [{..}, {name: 'a'}, {name: 'a'}] + // Series with the same name between optionA and optionB + // should be mapped. + var idNum = 0; + + do { + keyInfo.id = '\0' + keyInfo.name + '\0' + idNum++; + } while (idMap.get(keyInfo.id)); + } + + idMap.set(keyInfo.id, item); + }); + } + + function keyExistAndEqual(attr, obj1, obj2) { + var key1 = convertOptionIdName(obj1[attr], null); + var key2 = convertOptionIdName(obj2[attr], null); // See `MappingExistingItem`. `id` and `name` trade string equals to number. + + return key1 != null && key2 != null && key1 === key2; + } + /** + * @return return null if not exist. + */ + + + function makeComparableKey(val) { + { + if (val == null) { + throw new Error(); + } + } + return convertOptionIdName(val, ''); + } + + function convertOptionIdName(idOrName, defaultValue) { + if (idOrName == null) { + return defaultValue; + } + + return isString(idOrName) ? idOrName : isNumber(idOrName) || isStringSafe(idOrName) ? idOrName + '' : defaultValue; + } + + function warnInvalidateIdOrName(idOrName) { + { + warn('`' + idOrName + '` is invalid id or name. Must be a string or number.'); + } + } + + function isValidIdOrName(idOrName) { + return isStringSafe(idOrName) || isNumeric(idOrName); + } + + function isNameSpecified(componentModel) { + var name = componentModel.name; // Is specified when `indexOf` get -1 or > 0. + + return !!(name && name.indexOf(DUMMY_COMPONENT_NAME_PREFIX)); + } + /** + * @public + * @param {Object} cmptOption + * @return {boolean} + */ + + + function isComponentIdInternal(cmptOption) { + return cmptOption && cmptOption.id != null && makeComparableKey(cmptOption.id).indexOf(INTERNAL_COMPONENT_ID_PREFIX) === 0; + } + + function setComponentTypeToKeyInfo(mappingResult, mainType, componentModelCtor) { + // Set mainType and complete subType. + each$4(mappingResult, function (item) { + var newOption = item.newOption; + + if (isObject$2(newOption)) { + item.keyInfo.mainType = mainType; + item.keyInfo.subType = determineSubType(mainType, newOption, item.existing, componentModelCtor); + } + }); + } + + function determineSubType(mainType, newCmptOption, existComponent, componentModelCtor) { + var subType = newCmptOption.type ? newCmptOption.type : existComponent ? existComponent.subType // Use determineSubType only when there is no existComponent. + : componentModelCtor.determineSubType(mainType, newCmptOption); // tooltip, markline, markpoint may always has no subType + + return subType; + } + /** + * @param payload Contains dataIndex (means rawIndex) / dataIndexInside / name + * each of which can be Array or primary type. + * @return dataIndex If not found, return undefined/null. + */ + + + function queryDataIndex(data, payload) { + if (payload.dataIndexInside != null) { + return payload.dataIndexInside; + } else if (payload.dataIndex != null) { + return isArray(payload.dataIndex) ? map$1(payload.dataIndex, function (value) { + return data.indexOfRawIndex(value); + }) : data.indexOfRawIndex(payload.dataIndex); + } else if (payload.name != null) { + return isArray(payload.name) ? map$1(payload.name, function (value) { + return data.indexOfName(value); + }) : data.indexOfName(payload.name); + } + } + /** + * Enable property storage to any host object. + * Notice: Serialization is not supported. + * + * For example: + * let inner = zrUitl.makeInner(); + * + * function some1(hostObj) { + * inner(hostObj).someProperty = 1212; + * ... + * } + * function some2() { + * let fields = inner(this); + * fields.someProperty1 = 1212; + * fields.someProperty2 = 'xx'; + * ... + * } + * + * @return {Function} + */ + + + function makeInner() { + var key = '__ec_inner_' + innerUniqueIndex++; + return function (hostObj) { + return hostObj[key] || (hostObj[key] = {}); + }; + } + + var innerUniqueIndex = getRandomIdBase(); + /** + * The same behavior as `component.getReferringComponents`. + */ + + function parseFinder(ecModel, finderInput, opt) { + var _a = preParseFinder(finderInput, opt), + mainTypeSpecified = _a.mainTypeSpecified, + queryOptionMap = _a.queryOptionMap, + others = _a.others; + + var result = others; + var defaultMainType = opt ? opt.defaultMainType : null; + + if (!mainTypeSpecified && defaultMainType) { + queryOptionMap.set(defaultMainType, {}); + } + + queryOptionMap.each(function (queryOption, mainType) { + var queryResult = queryReferringComponents(ecModel, mainType, queryOption, { + useDefault: defaultMainType === mainType, + enableAll: opt && opt.enableAll != null ? opt.enableAll : true, + enableNone: opt && opt.enableNone != null ? opt.enableNone : true + }); + result[mainType + 'Models'] = queryResult.models; + result[mainType + 'Model'] = queryResult.models[0]; + }); + return result; + } + + function preParseFinder(finderInput, opt) { + var finder; + + if (isString(finderInput)) { + var obj = {}; + obj[finderInput + 'Index'] = 0; + finder = obj; + } else { + finder = finderInput; + } + + var queryOptionMap = createHashMap(); + var others = {}; + var mainTypeSpecified = false; + each$4(finder, function (value, key) { + // Exclude 'dataIndex' and other illegal keys. + if (key === 'dataIndex' || key === 'dataIndexInside') { + others[key] = value; + return; + } + + var parsedKey = key.match(/^(\w+)(Index|Id|Name)$/) || []; + var mainType = parsedKey[1]; + var queryType = (parsedKey[2] || '').toLowerCase(); + + if (!mainType || !queryType || opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0) { + return; + } + + mainTypeSpecified = mainTypeSpecified || !!mainType; + var queryOption = queryOptionMap.get(mainType) || queryOptionMap.set(mainType, {}); + queryOption[queryType] = value; + }); + return { + mainTypeSpecified: mainTypeSpecified, + queryOptionMap: queryOptionMap, + others: others + }; + } + + var SINGLE_REFERRING = { + useDefault: true, + enableAll: false, + enableNone: false + }; + + function queryReferringComponents(ecModel, mainType, userOption, opt) { + opt = opt || SINGLE_REFERRING; + var indexOption = userOption.index; + var idOption = userOption.id; + var nameOption = userOption.name; + var result = { + models: null, + specified: indexOption != null || idOption != null || nameOption != null + }; + + if (!result.specified) { + // Use the first as default if `useDefault`. + var firstCmpt = void 0; + result.models = opt.useDefault && (firstCmpt = ecModel.getComponent(mainType)) ? [firstCmpt] : []; + return result; + } + + if (indexOption === 'none' || indexOption === false) { + if (opt.enableNone) { + result.models = []; + return result; + } else { + // Do not throw; consider if some component previously does not use this method, + // and start to use it, need to be fault-tolerant for backward compatibility. + { + error('`"none"` or `false` is not a valid value on index option.'); + } + indexOption = -1; // Can not query by index but may still query by id/name if specified. + } + } // `queryComponents` will return all components if + // both all of index/id/name are null/undefined. + + + if (indexOption === 'all') { + if (opt.enableAll) { + indexOption = idOption = nameOption = null; + } else { + { + error('`"all"` is not a valid value on index option.'); + } + indexOption = -1; + } + } + + result.models = ecModel.queryComponents({ + mainType: mainType, + index: indexOption, + id: idOption, + name: nameOption + }); + return result; + } + + function setAttribute(dom, key, value) { + dom.setAttribute ? dom.setAttribute(key, value) : dom[key] = value; + } + + function getAttribute(dom, key) { + return dom.getAttribute ? dom.getAttribute(key) : dom[key]; + } + + function getTooltipRenderMode(renderModeOption) { + if (renderModeOption === 'auto') { + // Using html when `document` exists, use richText otherwise + return env.domSupported ? 'html' : 'richText'; + } else { + return renderModeOption || 'html'; + } + } + /** + * Interpolate raw values of a series with percent + * + * @param data data + * @param labelModel label model of the text element + * @param sourceValue start value. May be null/undefined when init. + * @param targetValue end value + * @param percent 0~1 percentage; 0 uses start value while 1 uses end value + * @return interpolated values + * If `sourceValue` and `targetValue` are `number`, return `number`. + * If `sourceValue` and `targetValue` are `string`, return `string`. + * If `sourceValue` and `targetValue` are `(string | number)[]`, return `(string | number)[]`. + * Other cases do not supported. + */ + + + function interpolateRawValues(data, precision, sourceValue, targetValue, percent) { + var isAutoPrecision = precision == null || precision === 'auto'; + + if (targetValue == null) { + return targetValue; + } + + if (isNumber(targetValue)) { + var value = interpolateNumber(sourceValue || 0, targetValue, percent); + return round$1(value, isAutoPrecision ? Math.max(getPrecision(sourceValue || 0), getPrecision(targetValue)) : precision); + } else if (isString(targetValue)) { + return percent < 1 ? sourceValue : targetValue; + } else { + var interpolated = []; + var leftArr = sourceValue; + var rightArr = targetValue; + var length_1 = Math.max(leftArr ? leftArr.length : 0, rightArr.length); + + for (var i = 0; i < length_1; ++i) { + var info = data.getDimensionInfo(i); // Don't interpolate ordinal dims + + if (info && info.type === 'ordinal') { + // In init, there is no `sourceValue`, but should better not to get undefined result. + interpolated[i] = (percent < 1 && leftArr ? leftArr : rightArr)[i]; + } else { + var leftVal = leftArr && leftArr[i] ? leftArr[i] : 0; + var rightVal = rightArr[i]; + var value = interpolateNumber(leftVal, rightVal, percent); + interpolated[i] = round$1(value, isAutoPrecision ? Math.max(getPrecision(leftVal), getPrecision(rightVal)) : precision); + } + } + + return interpolated; + } + } + + var TYPE_DELIMITER = '.'; + var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___'; + var IS_EXTENDED_CLASS = '___EC__EXTENDED_CLASS___'; + /** + * Notice, parseClassType('') should returns {main: '', sub: ''} + * @public + */ + + function parseClassType(componentType) { + var ret = { + main: '', + sub: '' + }; + + if (componentType) { + var typeArr = componentType.split(TYPE_DELIMITER); + ret.main = typeArr[0] || ''; + ret.sub = typeArr[1] || ''; + } + + return ret; + } + /** + * @public + */ + + + function checkClassType(componentType) { + assert(/^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType), 'componentType "' + componentType + '" illegal'); + } + + function isExtendedClass(clz) { + return !!(clz && clz[IS_EXTENDED_CLASS]); + } + /** + * Implements `ExtendableConstructor` for `rootClz`. + * + * @usage + * ```ts + * class Xxx {} + * type XxxConstructor = typeof Xxx & ExtendableConstructor + * enableClassExtend(Xxx as XxxConstructor); + * ``` + */ + + + function enableClassExtend(rootClz, mandatoryMethods) { + rootClz.$constructor = rootClz; // FIXME: not necessary? + + rootClz.extend = function (proto) { + { + each$4(mandatoryMethods, function (method) { + if (!proto[method]) { + console.warn('Method `' + method + '` should be implemented' + (proto.type ? ' in ' + proto.type : '') + '.'); + } + }); + } + var superClass = this; + var ExtendedClass; + + if (isESClass(superClass)) { + ExtendedClass = + /** @class */ + function (_super) { + __extends(class_1, _super); + + function class_1() { + return _super.apply(this, arguments) || this; + } + + return class_1; + }(superClass); + } else { + // For backward compat, we both support ts class inheritance and this + // "extend" approach. + // The constructor should keep the same behavior as ts class inheritance: + // If this constructor/$constructor is not declared, auto invoke the super + // constructor. + // If this constructor/$constructor is declared, it is responsible for + // calling the super constructor. + ExtendedClass = function () { + (proto.$constructor || superClass).apply(this, arguments); + }; + + inherits(ExtendedClass, this); + } + + extend(ExtendedClass.prototype, proto); + ExtendedClass[IS_EXTENDED_CLASS] = true; + ExtendedClass.extend = this.extend; + ExtendedClass.superCall = superCall; + ExtendedClass.superApply = superApply; + ExtendedClass.superClass = superClass; + return ExtendedClass; + }; + } + + function isESClass(fn) { + return isFunction(fn) && /^class\s/.test(Function.prototype.toString.call(fn)); + } + /** + * A work around to both support ts extend and this extend mechanism. + * on sub-class. + * @usage + * ```ts + * class Component { ... } + * classUtil.enableClassExtend(Component); + * classUtil.enableClassManagement(Component, {registerWhenExtend: true}); + * + * class Series extends Component { ... } + * // Without calling `markExtend`, `registerWhenExtend` will not work. + * Component.markExtend(Series); + * ``` + */ + + + function mountExtend(SubClz, SupperClz) { + SubClz.extend = SupperClz.extend; + } // A random offset. + + + var classBase = Math.round(Math.random() * 10); + /** + * Implements `CheckableConstructor` for `target`. + * Can not use instanceof, consider different scope by + * cross domain or es module import in ec extensions. + * Mount a method "isInstance()" to Clz. + * + * @usage + * ```ts + * class Xxx {} + * type XxxConstructor = typeof Xxx & CheckableConstructor; + * enableClassCheck(Xxx as XxxConstructor) + * ``` + */ + + function enableClassCheck(target) { + var classAttr = ['__\0is_clz', classBase++].join('_'); + target.prototype[classAttr] = true; + { + assert(!target.isInstance, 'The method "is" can not be defined.'); + } + + target.isInstance = function (obj) { + return !!(obj && obj[classAttr]); + }; + } // superCall should have class info, which can not be fetched from 'this'. + // Consider this case: + // class A has method f, + // class B inherits class A, overrides method f, f call superApply('f'), + // class C inherits class B, does not override method f, + // then when method of class C is called, dead loop occurred. + + + function superCall(context, methodName) { + var args = []; + + for (var _i = 2; _i < arguments.length; _i++) { + args[_i - 2] = arguments[_i]; + } + + return this.superClass.prototype[methodName].apply(context, args); + } + + function superApply(context, methodName, args) { + return this.superClass.prototype[methodName].apply(context, args); + } + /** + * Implements `ClassManager` for `target` + * + * @usage + * ```ts + * class Xxx {} + * type XxxConstructor = typeof Xxx & ClassManager + * enableClassManagement(Xxx as XxxConstructor); + * ``` + */ + + + function enableClassManagement(target) { + /** + * Component model classes + * key: componentType, + * value: + * componentClass, when componentType is 'a' + * or Object., when componentType is 'a.b' + */ + var storage = {}; + + target.registerClass = function (clz) { + // `type` should not be a "instance member". + // If using TS class, should better declared as `static type = 'series.pie'`. + // otherwise users have to mount `type` on prototype manually. + // For backward compat and enable instance visit type via `this.type`, + // we still support fetch `type` from prototype. + var componentFullType = clz.type || clz.prototype.type; + + if (componentFullType) { + checkClassType(componentFullType); // If only static type declared, we assign it to prototype mandatorily. + + clz.prototype.type = componentFullType; + var componentTypeInfo = parseClassType(componentFullType); + + if (!componentTypeInfo.sub) { + { + if (storage[componentTypeInfo.main]) { + console.warn(componentTypeInfo.main + ' exists.'); + } + } + storage[componentTypeInfo.main] = clz; + } else if (componentTypeInfo.sub !== IS_CONTAINER) { + var container = makeContainer(componentTypeInfo); + container[componentTypeInfo.sub] = clz; + } + } + + return clz; + }; + + target.getClass = function (mainType, subType, throwWhenNotFound) { + var clz = storage[mainType]; + + if (clz && clz[IS_CONTAINER]) { + clz = subType ? clz[subType] : null; + } + + if (throwWhenNotFound && !clz) { + throw new Error(!subType ? mainType + '.' + 'type should be specified.' : 'Component ' + mainType + '.' + (subType || '') + ' is used but not imported.'); + } + + return clz; + }; + + target.getClassesByMainType = function (componentType) { + var componentTypeInfo = parseClassType(componentType); + var result = []; + var obj = storage[componentTypeInfo.main]; + + if (obj && obj[IS_CONTAINER]) { + each$4(obj, function (o, type) { + type !== IS_CONTAINER && result.push(o); + }); + } else { + result.push(obj); + } + + return result; + }; + + target.hasClass = function (componentType) { + // Just consider componentType.main. + var componentTypeInfo = parseClassType(componentType); + return !!storage[componentTypeInfo.main]; + }; + /** + * @return Like ['aa', 'bb'], but can not be ['aa.xx'] + */ + + + target.getAllClassMainTypes = function () { + var types = []; + each$4(storage, function (obj, type) { + types.push(type); + }); + return types; + }; + /** + * If a main type is container and has sub types + */ + + + target.hasSubTypes = function (componentType) { + var componentTypeInfo = parseClassType(componentType); + var obj = storage[componentTypeInfo.main]; + return obj && obj[IS_CONTAINER]; + }; + + function makeContainer(componentTypeInfo) { + var container = storage[componentTypeInfo.main]; + + if (!container || !container[IS_CONTAINER]) { + container = storage[componentTypeInfo.main] = {}; + container[IS_CONTAINER] = true; + } + + return container; + } + } // /** + // * @param {string|Array.} properties + // */ + // export function setReadOnly(obj, properties) { + // FIXME It seems broken in IE8 simulation of IE11 + // if (!zrUtil.isArray(properties)) { + // properties = properties != null ? [properties] : []; + // } + // zrUtil.each(properties, function (prop) { + // let value = obj[prop]; + // Object.defineProperty + // && Object.defineProperty(obj, prop, { + // value: value, writable: false + // }); + // zrUtil.isArray(obj[prop]) + // && Object.freeze + // && Object.freeze(obj[prop]); + // }); + // } + + + function makeStyleMapper(properties, ignoreParent) { + // Normalize + for (var i = 0; i < properties.length; i++) { + if (!properties[i][1]) { + properties[i][1] = properties[i][0]; + } + } + + ignoreParent = ignoreParent || false; + return function (model, excludes, includes) { + var style = {}; + + for (var i = 0; i < properties.length; i++) { + var propName = properties[i][1]; + + if (excludes && indexOf(excludes, propName) >= 0 || includes && indexOf(includes, propName) < 0) { + continue; + } + + var val = model.getShallow(propName, ignoreParent); + + if (val != null) { + style[properties[i][0]] = val; + } + } // TODO Text or image? + + + return style; + }; + } + + var AREA_STYLE_KEY_MAP = [['fill', 'color'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['opacity'], ['shadowColor'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`. + // So do not transfer decal directly. + ]; + var getAreaStyle = makeStyleMapper(AREA_STYLE_KEY_MAP); + + var AreaStyleMixin = + /** @class */ + function () { + function AreaStyleMixin() {} + + AreaStyleMixin.prototype.getAreaStyle = function (excludes, includes) { + return getAreaStyle(this, excludes, includes); + }; + + return AreaStyleMixin; + }(); + + var globalImageCache = new LRU(50); + + function findExistImage(newImageOrSrc) { + if (typeof newImageOrSrc === 'string') { + var cachedImgObj = globalImageCache.get(newImageOrSrc); + return cachedImgObj && cachedImgObj.image; + } else { + return newImageOrSrc; + } + } + + function createOrUpdateImage(newImageOrSrc, image, hostEl, onload, cbPayload) { + if (!newImageOrSrc) { + return image; + } else if (typeof newImageOrSrc === 'string') { + if (image && image.__zrImageSrc === newImageOrSrc || !hostEl) { + return image; + } + + var cachedImgObj = globalImageCache.get(newImageOrSrc); + var pendingWrap = { + hostEl: hostEl, + cb: onload, + cbPayload: cbPayload + }; + + if (cachedImgObj) { + image = cachedImgObj.image; + !isImageReady(image) && cachedImgObj.pending.push(pendingWrap); + } else { + image = platformApi.loadImage(newImageOrSrc, imageOnLoad, imageOnLoad); + image.__zrImageSrc = newImageOrSrc; + globalImageCache.put(newImageOrSrc, image.__cachedImgObj = { + image: image, + pending: [pendingWrap] + }); + } + + return image; + } else { + return newImageOrSrc; + } + } + + function imageOnLoad() { + var cachedImgObj = this.__cachedImgObj; + this.onload = this.onerror = this.__cachedImgObj = null; + + for (var i = 0; i < cachedImgObj.pending.length; i++) { + var pendingWrap = cachedImgObj.pending[i]; + var cb = pendingWrap.cb; + cb && cb(this, pendingWrap.cbPayload); + pendingWrap.hostEl.dirty(); + } + + cachedImgObj.pending.length = 0; + } + + function isImageReady(image) { + return image && image.width && image.height; + } + + var STYLE_REG = /\{([a-zA-Z0-9_]+)\|([^}]*)\}/g; + + function truncateText(text, containerWidth, font, ellipsis, options) { + var out = {}; + truncateText2(out, text, containerWidth, font, ellipsis, options); + return out.text; + } + + function truncateText2(out, text, containerWidth, font, ellipsis, options) { + if (!containerWidth) { + out.text = ''; + out.isTruncated = false; + return; + } + + var textLines = (text + '').split('\n'); + options = prepareTruncateOptions(containerWidth, font, ellipsis, options); + var isTruncated = false; + var truncateOut = {}; + + for (var i = 0, len = textLines.length; i < len; i++) { + truncateSingleLine(truncateOut, textLines[i], options); + textLines[i] = truncateOut.textLine; + isTruncated = isTruncated || truncateOut.isTruncated; + } + + out.text = textLines.join('\n'); + out.isTruncated = isTruncated; + } + + function prepareTruncateOptions(containerWidth, font, ellipsis, options) { + options = options || {}; + var preparedOpts = extend({}, options); + ellipsis = retrieve2(ellipsis, '...'); + preparedOpts.maxIterations = retrieve2(options.maxIterations, 2); + var minChar = preparedOpts.minChar = retrieve2(options.minChar, 0); + var fontMeasureInfo = preparedOpts.fontMeasureInfo = ensureFontMeasureInfo(font); + var ascCharWidth = fontMeasureInfo.asciiCharWidth; + preparedOpts.placeholder = retrieve2(options.placeholder, ''); + var contentWidth = containerWidth = Math.max(0, containerWidth - 1); + + for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) { + contentWidth -= ascCharWidth; + } + + var ellipsisWidth = measureWidth(fontMeasureInfo, ellipsis); + + if (ellipsisWidth > contentWidth) { + ellipsis = ''; + ellipsisWidth = 0; + } + + contentWidth = containerWidth - ellipsisWidth; + preparedOpts.ellipsis = ellipsis; + preparedOpts.ellipsisWidth = ellipsisWidth; + preparedOpts.contentWidth = contentWidth; + preparedOpts.containerWidth = containerWidth; + return preparedOpts; + } + + function truncateSingleLine(out, textLine, options) { + var containerWidth = options.containerWidth; + var contentWidth = options.contentWidth; + var fontMeasureInfo = options.fontMeasureInfo; + + if (!containerWidth) { + out.textLine = ''; + out.isTruncated = false; + return; + } + + var lineWidth = measureWidth(fontMeasureInfo, textLine); + + if (lineWidth <= containerWidth) { + out.textLine = textLine; + out.isTruncated = false; + return; + } + + for (var j = 0;; j++) { + if (lineWidth <= contentWidth || j >= options.maxIterations) { + textLine += options.ellipsis; + break; + } + + var subLength = j === 0 ? estimateLength(textLine, contentWidth, fontMeasureInfo) : lineWidth > 0 ? Math.floor(textLine.length * contentWidth / lineWidth) : 0; + textLine = textLine.substr(0, subLength); + lineWidth = measureWidth(fontMeasureInfo, textLine); + } + + if (textLine === '') { + textLine = options.placeholder; + } + + out.textLine = textLine; + out.isTruncated = true; + } + + function estimateLength(text, contentWidth, fontMeasureInfo) { + var width = 0; + var i = 0; + + for (var len = text.length; i < len && width < contentWidth; i++) { + width += measureCharWidth(fontMeasureInfo, text.charCodeAt(i)); + } + + return i; + } + + function parsePlainText(rawText, style, defaultOuterWidth, defaultOuterHeight) { + var text = formatText(rawText); + var overflow = style.overflow; + var padding = style.padding; + var paddingH = padding ? padding[1] + padding[3] : 0; + var paddingV = padding ? padding[0] + padding[2] : 0; + var font = style.font; + var truncate = overflow === 'truncate'; + var calculatedLineHeight = getLineHeight(font); + var lineHeight = retrieve2(style.lineHeight, calculatedLineHeight); + var truncateLineOverflow = style.lineOverflow === 'truncate'; + var isTruncated = false; + var width = style.width; + + if (width == null && defaultOuterWidth != null) { + width = defaultOuterWidth - paddingH; + } + + var height = style.height; + + if (height == null && defaultOuterHeight != null) { + height = defaultOuterHeight - paddingV; + } + + var lines; + + if (width != null && (overflow === 'break' || overflow === 'breakAll')) { + lines = text ? wrapText(text, style.font, width, overflow === 'breakAll', 0).lines : []; + } else { + lines = text ? text.split('\n') : []; + } + + var contentHeight = lines.length * lineHeight; + + if (height == null) { + height = contentHeight; + } + + if (contentHeight > height && truncateLineOverflow) { + var lineCount = Math.floor(height / lineHeight); + isTruncated = isTruncated || lines.length > lineCount; + lines = lines.slice(0, lineCount); + contentHeight = lines.length * lineHeight; + } + + if (text && truncate && width != null) { + var options = prepareTruncateOptions(width, font, style.ellipsis, { + minChar: style.truncateMinChar, + placeholder: style.placeholder + }); + var singleOut = {}; + + for (var i = 0; i < lines.length; i++) { + truncateSingleLine(singleOut, lines[i], options); + lines[i] = singleOut.textLine; + isTruncated = isTruncated || singleOut.isTruncated; + } + } + + var outerHeight = height; + var contentWidth = 0; + var fontMeasureInfo = ensureFontMeasureInfo(font); + + for (var i = 0; i < lines.length; i++) { + contentWidth = Math.max(measureWidth(fontMeasureInfo, lines[i]), contentWidth); + } + + if (width == null) { + width = contentWidth; + } + + var outerWidth = width; + outerHeight += paddingV; + outerWidth += paddingH; + return { + lines: lines, + height: height, + outerWidth: outerWidth, + outerHeight: outerHeight, + lineHeight: lineHeight, + calculatedLineHeight: calculatedLineHeight, + contentWidth: contentWidth, + contentHeight: contentHeight, + width: width, + isTruncated: isTruncated + }; + } + + var RichTextToken = function () { + function RichTextToken() {} + + return RichTextToken; + }(); + + var RichTextLine = function () { + function RichTextLine(tokens) { + this.tokens = []; + + if (tokens) { + this.tokens = tokens; + } + } + + return RichTextLine; + }(); + + var RichTextContentBlock = function () { + function RichTextContentBlock() { + this.width = 0; + this.height = 0; + this.contentWidth = 0; + this.contentHeight = 0; + this.outerWidth = 0; + this.outerHeight = 0; + this.lines = []; + this.isTruncated = false; + } + + return RichTextContentBlock; + }(); + + function parseRichText(rawText, style, defaultOuterWidth, defaultOuterHeight, topTextAlign) { + var contentBlock = new RichTextContentBlock(); + var text = formatText(rawText); + + if (!text) { + return contentBlock; + } + + var stlPadding = style.padding; + var stlPaddingH = stlPadding ? stlPadding[1] + stlPadding[3] : 0; + var stlPaddingV = stlPadding ? stlPadding[0] + stlPadding[2] : 0; + var topWidth = style.width; + + if (topWidth == null && defaultOuterWidth != null) { + topWidth = defaultOuterWidth - stlPaddingH; + } + + var topHeight = style.height; + + if (topHeight == null && defaultOuterHeight != null) { + topHeight = defaultOuterHeight - stlPaddingV; + } + + var overflow = style.overflow; + var wrapInfo = (overflow === 'break' || overflow === 'breakAll') && topWidth != null ? { + width: topWidth, + accumWidth: 0, + breakAll: overflow === 'breakAll' + } : null; + var lastIndex = STYLE_REG.lastIndex = 0; + var result; + + while ((result = STYLE_REG.exec(text)) != null) { + var matchedIndex = result.index; + + if (matchedIndex > lastIndex) { + pushTokens(contentBlock, text.substring(lastIndex, matchedIndex), style, wrapInfo); + } + + pushTokens(contentBlock, result[2], style, wrapInfo, result[1]); + lastIndex = STYLE_REG.lastIndex; + } + + if (lastIndex < text.length) { + pushTokens(contentBlock, text.substring(lastIndex, text.length), style, wrapInfo); + } + + var pendingList = []; + var calculatedHeight = 0; + var calculatedWidth = 0; + var truncate = overflow === 'truncate'; + var truncateLine = style.lineOverflow === 'truncate'; + var tmpTruncateOut = {}; + + function finishLine(line, lineWidth, lineHeight) { + line.width = lineWidth; + line.lineHeight = lineHeight; + calculatedHeight += lineHeight; + calculatedWidth = Math.max(calculatedWidth, lineWidth); + } + + outer: for (var i = 0; i < contentBlock.lines.length; i++) { + var line = contentBlock.lines[i]; + var lineHeight = 0; + var lineWidth = 0; + + for (var j = 0; j < line.tokens.length; j++) { + var token = line.tokens[j]; + var tokenStyle = token.styleName && style.rich[token.styleName] || {}; + var textPadding = token.textPadding = tokenStyle.padding; + var paddingH = textPadding ? textPadding[1] + textPadding[3] : 0; + var font = token.font = tokenStyle.font || style.font; + token.contentHeight = getLineHeight(font); + var tokenHeight = retrieve2(tokenStyle.height, token.contentHeight); + token.innerHeight = tokenHeight; + textPadding && (tokenHeight += textPadding[0] + textPadding[2]); + token.height = tokenHeight; + token.lineHeight = retrieve3(tokenStyle.lineHeight, style.lineHeight, tokenHeight); + token.align = tokenStyle && tokenStyle.align || topTextAlign; + token.verticalAlign = tokenStyle && tokenStyle.verticalAlign || 'middle'; + + if (truncateLine && topHeight != null && calculatedHeight + token.lineHeight > topHeight) { + var originalLength = contentBlock.lines.length; + + if (j > 0) { + line.tokens = line.tokens.slice(0, j); + finishLine(line, lineWidth, lineHeight); + contentBlock.lines = contentBlock.lines.slice(0, i + 1); + } else { + contentBlock.lines = contentBlock.lines.slice(0, i); + } + + contentBlock.isTruncated = contentBlock.isTruncated || contentBlock.lines.length < originalLength; + break outer; + } + + var styleTokenWidth = tokenStyle.width; + var tokenWidthNotSpecified = styleTokenWidth == null || styleTokenWidth === 'auto'; + + if (typeof styleTokenWidth === 'string' && styleTokenWidth.charAt(styleTokenWidth.length - 1) === '%') { + token.percentWidth = styleTokenWidth; + pendingList.push(token); + token.contentWidth = measureWidth(ensureFontMeasureInfo(font), token.text); + } else { + if (tokenWidthNotSpecified) { + var textBackgroundColor = tokenStyle.backgroundColor; + var bgImg = textBackgroundColor && textBackgroundColor.image; + + if (bgImg) { + bgImg = findExistImage(bgImg); + + if (isImageReady(bgImg)) { + token.width = Math.max(token.width, bgImg.width * tokenHeight / bgImg.height); + } + } + } + + var remainTruncWidth = truncate && topWidth != null ? topWidth - lineWidth : null; + + if (remainTruncWidth != null && remainTruncWidth < token.width) { + if (!tokenWidthNotSpecified || remainTruncWidth < paddingH) { + token.text = ''; + token.width = token.contentWidth = 0; + } else { + truncateText2(tmpTruncateOut, token.text, remainTruncWidth - paddingH, font, style.ellipsis, { + minChar: style.truncateMinChar + }); + token.text = tmpTruncateOut.text; + contentBlock.isTruncated = contentBlock.isTruncated || tmpTruncateOut.isTruncated; + token.width = token.contentWidth = measureWidth(ensureFontMeasureInfo(font), token.text); + } + } else { + token.contentWidth = measureWidth(ensureFontMeasureInfo(font), token.text); + } + } + + token.width += paddingH; + lineWidth += token.width; + tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight)); + } + + finishLine(line, lineWidth, lineHeight); + } + + contentBlock.outerWidth = contentBlock.width = retrieve2(topWidth, calculatedWidth); + contentBlock.outerHeight = contentBlock.height = retrieve2(topHeight, calculatedHeight); + contentBlock.contentHeight = calculatedHeight; + contentBlock.contentWidth = calculatedWidth; + contentBlock.outerWidth += stlPaddingH; + contentBlock.outerHeight += stlPaddingV; + + for (var i = 0; i < pendingList.length; i++) { + var token = pendingList[i]; + var percentWidth = token.percentWidth; + token.width = parseInt(percentWidth, 10) / 100 * contentBlock.width; + } + + return contentBlock; + } + + function pushTokens(block, str, style, wrapInfo, styleName) { + var isEmptyStr = str === ''; + var tokenStyle = styleName && style.rich[styleName] || {}; + var lines = block.lines; + var font = tokenStyle.font || style.font; + var newLine = false; + var strLines; + var linesWidths; + + if (wrapInfo) { + var tokenPadding = tokenStyle.padding; + var tokenPaddingH = tokenPadding ? tokenPadding[1] + tokenPadding[3] : 0; + + if (tokenStyle.width != null && tokenStyle.width !== 'auto') { + var outerWidth_1 = parsePercent$1(tokenStyle.width, wrapInfo.width) + tokenPaddingH; + + if (lines.length > 0) { + if (outerWidth_1 + wrapInfo.accumWidth > wrapInfo.width) { + strLines = str.split('\n'); + newLine = true; + } + } + + wrapInfo.accumWidth = outerWidth_1; + } else { + var res = wrapText(str, font, wrapInfo.width, wrapInfo.breakAll, wrapInfo.accumWidth); + wrapInfo.accumWidth = res.accumWidth + tokenPaddingH; + linesWidths = res.linesWidths; + strLines = res.lines; + } + } + + if (!strLines) { + strLines = str.split('\n'); + } + + var fontMeasureInfo = ensureFontMeasureInfo(font); + + for (var i = 0; i < strLines.length; i++) { + var text = strLines[i]; + var token = new RichTextToken(); + token.styleName = styleName; + token.text = text; + token.isLineHolder = !text && !isEmptyStr; + + if (typeof tokenStyle.width === 'number') { + token.width = tokenStyle.width; + } else { + token.width = linesWidths ? linesWidths[i] : measureWidth(fontMeasureInfo, text); + } + + if (!i && !newLine) { + var tokens = (lines[lines.length - 1] || (lines[0] = new RichTextLine())).tokens; + var tokensLen = tokens.length; + tokensLen === 1 && tokens[0].isLineHolder ? tokens[0] = token : (text || !tokensLen || isEmptyStr) && tokens.push(token); + } else { + lines.push(new RichTextLine([token])); + } + } + } + + function isAlphabeticLetter(ch) { + var code = ch.charCodeAt(0); + return code >= 0x20 && code <= 0x24F || code >= 0x370 && code <= 0x10FF || code >= 0x1200 && code <= 0x13FF || code >= 0x1E00 && code <= 0x206F; + } + + var breakCharMap = reduce(',&?/;] '.split(''), function (obj, ch) { + obj[ch] = true; + return obj; + }, {}); + + function isWordBreakChar(ch) { + if (isAlphabeticLetter(ch)) { + if (breakCharMap[ch]) { + return true; + } + + return false; + } + + return true; + } + + function wrapText(text, font, lineWidth, isBreakAll, lastAccumWidth) { + var lines = []; + var linesWidths = []; + var line = ''; + var currentWord = ''; + var currentWordWidth = 0; + var accumWidth = 0; + var fontMeasureInfo = ensureFontMeasureInfo(font); + + for (var i = 0; i < text.length; i++) { + var ch = text.charAt(i); + + if (ch === '\n') { + if (currentWord) { + line += currentWord; + accumWidth += currentWordWidth; + } + + lines.push(line); + linesWidths.push(accumWidth); + line = ''; + currentWord = ''; + currentWordWidth = 0; + accumWidth = 0; + continue; + } + + var chWidth = measureCharWidth(fontMeasureInfo, ch.charCodeAt(0)); + var inWord = isBreakAll ? false : !isWordBreakChar(ch); + + if (!lines.length ? lastAccumWidth + accumWidth + chWidth > lineWidth : accumWidth + chWidth > lineWidth) { + if (!accumWidth) { + if (inWord) { + lines.push(currentWord); + linesWidths.push(currentWordWidth); + currentWord = ch; + currentWordWidth = chWidth; + } else { + lines.push(ch); + linesWidths.push(chWidth); + } + } else if (line || currentWord) { + if (inWord) { + if (!line) { + line = currentWord; + currentWord = ''; + currentWordWidth = 0; + accumWidth = currentWordWidth; + } + + lines.push(line); + linesWidths.push(accumWidth - currentWordWidth); + currentWord += ch; + currentWordWidth += chWidth; + line = ''; + accumWidth = currentWordWidth; + } else { + if (currentWord) { + line += currentWord; + currentWord = ''; + currentWordWidth = 0; + } + + lines.push(line); + linesWidths.push(accumWidth); + line = ch; + accumWidth = chWidth; + } + } + + continue; + } + + accumWidth += chWidth; + + if (inWord) { + currentWord += ch; + currentWordWidth += chWidth; + } else { + if (currentWord) { + line += currentWord; + currentWord = ''; + currentWordWidth = 0; + } + + line += ch; + } + } + + if (currentWord) { + line += currentWord; + } + + if (line) { + lines.push(line); + linesWidths.push(accumWidth); + } + + if (lines.length === 1) { + accumWidth += lastAccumWidth; + } + + return { + accumWidth: accumWidth, + lines: lines, + linesWidths: linesWidths + }; + } + + function calcInnerTextOverflowArea(out, overflowRect, baseX, baseY, textAlign, textVerticalAlign) { + out.baseX = baseX; + out.baseY = baseY; + out.outerWidth = out.outerHeight = null; + + if (!overflowRect) { + return; + } + + var textWidth = overflowRect.width * 2; + var textHeight = overflowRect.height * 2; + BoundingRect.set(tmpCITCTextRect, adjustTextX(baseX, textWidth, textAlign), adjustTextY(baseY, textHeight, textVerticalAlign), textWidth, textHeight); + BoundingRect.intersect(overflowRect, tmpCITCTextRect, null, tmpCITCIntersectRectOpt); + var outIntersectRect = tmpCITCIntersectRectOpt.outIntersectRect; + out.outerWidth = outIntersectRect.width; + out.outerHeight = outIntersectRect.height; + out.baseX = adjustTextX(outIntersectRect.x, outIntersectRect.width, textAlign, true); + out.baseY = adjustTextY(outIntersectRect.y, outIntersectRect.height, textVerticalAlign, true); + } + + var tmpCITCTextRect = new BoundingRect(0, 0, 0, 0); + var tmpCITCIntersectRectOpt = { + outIntersectRect: {}, + clamp: true + }; + + function formatText(text) { + return text != null ? text += '' : text = ''; + } + + function tSpanCreateBoundingRect(style) { + var text = formatText(style.text); + var font = style.font; + var contentWidth = measureWidth(ensureFontMeasureInfo(font), text); + var contentHeight = getLineHeight(font); + return tSpanCreateBoundingRect2(style, contentWidth, contentHeight, null); + } + + function tSpanCreateBoundingRect2(style, contentWidth, contentHeight, forceLineWidth) { + var rect = new BoundingRect(adjustTextX(style.x || 0, contentWidth, style.textAlign), adjustTextY(style.y || 0, contentHeight, style.textBaseline), contentWidth, contentHeight); + var lineWidth = forceLineWidth != null ? forceLineWidth : tSpanHasStroke(style) ? style.lineWidth : 0; + + if (lineWidth > 0) { + rect.x -= lineWidth / 2; + rect.y -= lineWidth / 2; + rect.width += lineWidth; + rect.height += lineWidth; + } + + return rect; + } + + function tSpanHasStroke(style) { + var stroke = style.stroke; + return stroke != null && stroke !== 'none' && style.lineWidth > 0; + } + + var STYLE_MAGIC_KEY = '__zr_style_' + Math.round(Math.random() * 10); + var DEFAULT_COMMON_STYLE = { + shadowBlur: 0, + shadowOffsetX: 0, + shadowOffsetY: 0, + shadowColor: '#000', + opacity: 1, + blend: 'source-over' + }; + var DEFAULT_COMMON_ANIMATION_PROPS = { + style: { + shadowBlur: true, + shadowOffsetX: true, + shadowOffsetY: true, + shadowColor: true, + opacity: true + } + }; + DEFAULT_COMMON_STYLE[STYLE_MAGIC_KEY] = true; + var PRIMARY_STATES_KEYS = ['z', 'z2', 'invisible']; + var PRIMARY_STATES_KEYS_IN_HOVER_LAYER = ['invisible']; + + var Displayable = function (_super) { + __extends(Displayable, _super); + + function Displayable(props) { + return _super.call(this, props) || this; + } + + Displayable.prototype._init = function (props) { + var keysArr = keys(props); + + for (var i = 0; i < keysArr.length; i++) { + var key = keysArr[i]; + + if (key === 'style') { + this.useStyle(props[key]); + } else { + _super.prototype.attrKV.call(this, key, props[key]); + } + } + + if (!this.style) { + this.useStyle({}); + } + }; + + Displayable.prototype.beforeBrush = function () {}; + + Displayable.prototype.afterBrush = function () {}; + + Displayable.prototype.innerBeforeBrush = function () {}; + + Displayable.prototype.innerAfterBrush = function () {}; + + Displayable.prototype.shouldBePainted = function (viewWidth, viewHeight, considerClipPath, considerAncestors) { + var m = this.transform; + + if (this.ignore || this.invisible || this.style.opacity === 0 || this.culling && isDisplayableCulled(this, viewWidth, viewHeight) || m && !m[0] && !m[3]) { + return false; + } + + if (considerClipPath && this.__clipPaths && this.__clipPaths.length) { + for (var i = 0; i < this.__clipPaths.length; ++i) { + if (this.__clipPaths[i].isZeroArea()) { + return false; + } + } + } + + if (considerAncestors && this.parent) { + var parent_1 = this.parent; + + while (parent_1) { + if (parent_1.ignore) { + return false; + } + + parent_1 = parent_1.parent; + } + } + + return true; + }; + + Displayable.prototype.contain = function (x, y) { + return this.rectContain(x, y); + }; + + Displayable.prototype.traverse = function (cb, context) { + cb.call(context, this); + }; + + Displayable.prototype.rectContain = function (x, y) { + var coord = this.transformCoordToLocal(x, y); + var rect = this.getBoundingRect(); + return rect.contain(coord[0], coord[1]); + }; + + Displayable.prototype.getPaintRect = function () { + var rect = this._paintRect; + + if (!this._paintRect || this.__dirty) { + var transform = this.transform; + var elRect = this.getBoundingRect(); + var style = this.style; + var shadowSize = style.shadowBlur || 0; + var shadowOffsetX = style.shadowOffsetX || 0; + var shadowOffsetY = style.shadowOffsetY || 0; + rect = this._paintRect || (this._paintRect = new BoundingRect(0, 0, 0, 0)); + + if (transform) { + BoundingRect.applyTransform(rect, elRect, transform); + } else { + rect.copy(elRect); + } + + if (shadowSize || shadowOffsetX || shadowOffsetY) { + rect.width += shadowSize * 2 + Math.abs(shadowOffsetX); + rect.height += shadowSize * 2 + Math.abs(shadowOffsetY); + rect.x = Math.min(rect.x, rect.x + shadowOffsetX - shadowSize); + rect.y = Math.min(rect.y, rect.y + shadowOffsetY - shadowSize); + } + + var tolerance = this.dirtyRectTolerance; + + if (!rect.isZero()) { + rect.x = Math.floor(rect.x - tolerance); + rect.y = Math.floor(rect.y - tolerance); + rect.width = Math.ceil(rect.width + 1 + tolerance * 2); + rect.height = Math.ceil(rect.height + 1 + tolerance * 2); + } + } + + return rect; + }; + + Displayable.prototype.setPrevPaintRect = function (paintRect) { + if (paintRect) { + this._prevPaintRect = this._prevPaintRect || new BoundingRect(0, 0, 0, 0); + + this._prevPaintRect.copy(paintRect); + } else { + this._prevPaintRect = null; + } + }; + + Displayable.prototype.getPrevPaintRect = function () { + return this._prevPaintRect; + }; + + Displayable.prototype.animateStyle = function (loop) { + return this.animate('style', loop); + }; + + Displayable.prototype.updateDuringAnimation = function (targetKey) { + if (targetKey === 'style') { + this.dirtyStyle(); + } else { + this.markRedraw(); + } + }; + + Displayable.prototype.attrKV = function (key, value) { + if (key !== 'style') { + _super.prototype.attrKV.call(this, key, value); + } else { + if (!this.style) { + this.useStyle(value); + } else { + this.setStyle(value); + } + } + }; + + Displayable.prototype.setStyle = function (keyOrObj, value) { + if (typeof keyOrObj === 'string') { + this.style[keyOrObj] = value; + } else { + extend(this.style, keyOrObj); + } + + this.dirtyStyle(); + return this; + }; + + Displayable.prototype.dirtyStyle = function (notRedraw) { + if (!notRedraw) { + this.markRedraw(); + } + + this.__dirty |= STYLE_CHANGED_BIT; + + if (this._rect) { + this._rect = null; + } + }; + + Displayable.prototype.dirty = function () { + this.dirtyStyle(); + }; + + Displayable.prototype.styleChanged = function () { + return !!(this.__dirty & STYLE_CHANGED_BIT); + }; + + Displayable.prototype.styleUpdated = function () { + this.__dirty &= ~STYLE_CHANGED_BIT; + }; + + Displayable.prototype.createStyle = function (obj) { + return createObject(DEFAULT_COMMON_STYLE, obj); + }; + + Displayable.prototype.useStyle = function (obj) { + if (!obj[STYLE_MAGIC_KEY]) { + obj = this.createStyle(obj); + } + + if (this.__inHover) { + this.__hoverStyle = obj; + } else { + this.style = obj; + } + + this.dirtyStyle(); + }; + + Displayable.prototype.isStyleObject = function (obj) { + return obj[STYLE_MAGIC_KEY]; + }; + + Displayable.prototype._innerSaveToNormal = function (toState) { + _super.prototype._innerSaveToNormal.call(this, toState); + + var normalState = this._normalState; + + if (toState.style && !normalState.style) { + normalState.style = this._mergeStyle(this.createStyle(), this.style); + } + + this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS); + }; + + Displayable.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) { + _super.prototype._applyStateObj.call(this, stateName, state, normalState, keepCurrentStates, transition, animationCfg); + + var needsRestoreToNormal = !(state && keepCurrentStates); + var targetStyle; + + if (state && state.style) { + if (transition) { + if (keepCurrentStates) { + targetStyle = state.style; + } else { + targetStyle = this._mergeStyle(this.createStyle(), normalState.style); + + this._mergeStyle(targetStyle, state.style); + } + } else { + targetStyle = this._mergeStyle(this.createStyle(), keepCurrentStates ? this.style : normalState.style); + + this._mergeStyle(targetStyle, state.style); + } + } else if (needsRestoreToNormal) { + targetStyle = normalState.style; + } + + if (targetStyle) { + if (transition) { + var sourceStyle = this.style; + this.style = this.createStyle(needsRestoreToNormal ? {} : sourceStyle); + + if (needsRestoreToNormal) { + var changedKeys = keys(sourceStyle); + + for (var i = 0; i < changedKeys.length; i++) { + var key = changedKeys[i]; + + if (key in targetStyle) { + targetStyle[key] = targetStyle[key]; + this.style[key] = sourceStyle[key]; + } + } + } + + var targetKeys = keys(targetStyle); + + for (var i = 0; i < targetKeys.length; i++) { + var key = targetKeys[i]; + this.style[key] = this.style[key]; + } + + this._transitionState(stateName, { + style: targetStyle + }, animationCfg, this.getAnimationStyleProps()); + } else { + this.useStyle(targetStyle); + } + } + + var statesKeys = this.__inHover ? PRIMARY_STATES_KEYS_IN_HOVER_LAYER : PRIMARY_STATES_KEYS; + + for (var i = 0; i < statesKeys.length; i++) { + var key = statesKeys[i]; + + if (state && state[key] != null) { + this[key] = state[key]; + } else if (needsRestoreToNormal) { + if (normalState[key] != null) { + this[key] = normalState[key]; + } + } + } + }; + + Displayable.prototype._mergeStates = function (states) { + var mergedState = _super.prototype._mergeStates.call(this, states); + + var mergedStyle; + + for (var i = 0; i < states.length; i++) { + var state = states[i]; + + if (state.style) { + mergedStyle = mergedStyle || {}; + + this._mergeStyle(mergedStyle, state.style); + } + } + + if (mergedStyle) { + mergedState.style = mergedStyle; + } + + return mergedState; + }; + + Displayable.prototype._mergeStyle = function (targetStyle, sourceStyle) { + extend(targetStyle, sourceStyle); + return targetStyle; + }; + + Displayable.prototype.getAnimationStyleProps = function () { + return DEFAULT_COMMON_ANIMATION_PROPS; + }; + + Displayable.initDefaultProps = function () { + var dispProto = Displayable.prototype; + dispProto.type = 'displayable'; + dispProto.invisible = false; + dispProto.z = 0; + dispProto.z2 = 0; + dispProto.zlevel = 0; + dispProto.culling = false; + dispProto.cursor = 'pointer'; + dispProto.rectHover = false; + dispProto.incremental = false; + dispProto._rect = null; + dispProto.dirtyRectTolerance = 0; + dispProto.__dirty = REDRAW_BIT | STYLE_CHANGED_BIT; + }(); + + return Displayable; + }(Element); + + var tmpRect = new BoundingRect(0, 0, 0, 0); + var viewRect = new BoundingRect(0, 0, 0, 0); + + function isDisplayableCulled(el, width, height) { + tmpRect.copy(el.getBoundingRect()); + + if (el.transform) { + tmpRect.applyTransform(el.transform); + } + + viewRect.width = width; + viewRect.height = height; + return !tmpRect.intersect(viewRect); + } + + var mathMin$5 = Math.min; + var mathMax$5 = Math.max; + var mathSin$3 = Math.sin; + var mathCos$3 = Math.cos; + var PI2$6 = Math.PI * 2; + var start = create$1(); + var end = create$1(); + var extremity = create$1(); + + function fromLine(x0, y0, x1, y1, min, max) { + min[0] = mathMin$5(x0, x1); + min[1] = mathMin$5(y0, y1); + max[0] = mathMax$5(x0, x1); + max[1] = mathMax$5(y0, y1); + } + + var xDim = []; + var yDim = []; + + function fromCubic(x0, y0, x1, y1, x2, y2, x3, y3, min, max) { + var cubicExtrema$1 = cubicExtrema; + var cubicAt$1 = cubicAt; + var n = cubicExtrema$1(x0, x1, x2, x3, xDim); + min[0] = Infinity; + min[1] = Infinity; + max[0] = -Infinity; + max[1] = -Infinity; + + for (var i = 0; i < n; i++) { + var x = cubicAt$1(x0, x1, x2, x3, xDim[i]); + min[0] = mathMin$5(x, min[0]); + max[0] = mathMax$5(x, max[0]); + } + + n = cubicExtrema$1(y0, y1, y2, y3, yDim); + + for (var i = 0; i < n; i++) { + var y = cubicAt$1(y0, y1, y2, y3, yDim[i]); + min[1] = mathMin$5(y, min[1]); + max[1] = mathMax$5(y, max[1]); + } + + min[0] = mathMin$5(x0, min[0]); + max[0] = mathMax$5(x0, max[0]); + min[0] = mathMin$5(x3, min[0]); + max[0] = mathMax$5(x3, max[0]); + min[1] = mathMin$5(y0, min[1]); + max[1] = mathMax$5(y0, max[1]); + min[1] = mathMin$5(y3, min[1]); + max[1] = mathMax$5(y3, max[1]); + } + + function fromQuadratic(x0, y0, x1, y1, x2, y2, min, max) { + var quadraticExtremum$1 = quadraticExtremum; + var quadraticAt$1 = quadraticAt; + var tx = mathMax$5(mathMin$5(quadraticExtremum$1(x0, x1, x2), 1), 0); + var ty = mathMax$5(mathMin$5(quadraticExtremum$1(y0, y1, y2), 1), 0); + var x = quadraticAt$1(x0, x1, x2, tx); + var y = quadraticAt$1(y0, y1, y2, ty); + min[0] = mathMin$5(x0, x2, x); + min[1] = mathMin$5(y0, y2, y); + max[0] = mathMax$5(x0, x2, x); + max[1] = mathMax$5(y0, y2, y); + } + + function fromArc(x, y, rx, ry, startAngle, endAngle, anticlockwise, min, max) { + var vec2Min = min$1; + var vec2Max = max$1; + var diff = Math.abs(startAngle - endAngle); + + if (diff % PI2$6 < 1e-4 && diff > 1e-4) { + min[0] = x - rx; + min[1] = y - ry; + max[0] = x + rx; + max[1] = y + ry; + return; + } + + start[0] = mathCos$3(startAngle) * rx + x; + start[1] = mathSin$3(startAngle) * ry + y; + end[0] = mathCos$3(endAngle) * rx + x; + end[1] = mathSin$3(endAngle) * ry + y; + vec2Min(min, start, end); + vec2Max(max, start, end); + startAngle = startAngle % PI2$6; + + if (startAngle < 0) { + startAngle = startAngle + PI2$6; + } + + endAngle = endAngle % PI2$6; + + if (endAngle < 0) { + endAngle = endAngle + PI2$6; + } + + if (startAngle > endAngle && !anticlockwise) { + endAngle += PI2$6; + } else if (startAngle < endAngle && anticlockwise) { + startAngle += PI2$6; + } + + if (anticlockwise) { + var tmp = endAngle; + endAngle = startAngle; + startAngle = tmp; + } + + for (var angle = 0; angle < endAngle; angle += Math.PI / 2) { + if (angle > startAngle) { + extremity[0] = mathCos$3(angle) * rx + x; + extremity[1] = mathSin$3(angle) * ry + y; + vec2Min(min, extremity, min); + vec2Max(max, extremity, max); + } + } + } + + var CMD$3 = { + M: 1, + L: 2, + C: 3, + Q: 4, + A: 5, + Z: 6, + R: 7 + }; + var tmpOutX = []; + var tmpOutY = []; + var min = []; + var max = []; + var min2 = []; + var max2 = []; + var mathMin$4 = Math.min; + var mathMax$4 = Math.max; + var mathCos$2 = Math.cos; + var mathSin$2 = Math.sin; + var mathAbs$2 = Math.abs; + var PI$4 = Math.PI; + var PI2$5 = PI$4 * 2; + var hasTypedArray = typeof Float32Array !== 'undefined'; + var tmpAngles = []; + + function modPI2(radian) { + var n = Math.round(radian / PI$4 * 1e8) / 1e8; + return n % 2 * PI$4; + } + + function normalizeArcAngles(angles, anticlockwise) { + var newStartAngle = modPI2(angles[0]); + + if (newStartAngle < 0) { + newStartAngle += PI2$5; + } + + var delta = newStartAngle - angles[0]; + var newEndAngle = angles[1]; + newEndAngle += delta; + + if (!anticlockwise && newEndAngle - newStartAngle >= PI2$5) { + newEndAngle = newStartAngle + PI2$5; + } else if (anticlockwise && newStartAngle - newEndAngle >= PI2$5) { + newEndAngle = newStartAngle - PI2$5; + } else if (!anticlockwise && newStartAngle > newEndAngle) { + newEndAngle = newStartAngle + (PI2$5 - modPI2(newStartAngle - newEndAngle)); + } else if (anticlockwise && newStartAngle < newEndAngle) { + newEndAngle = newStartAngle - (PI2$5 - modPI2(newEndAngle - newStartAngle)); + } + + angles[0] = newStartAngle; + angles[1] = newEndAngle; + } + + var PathProxy = function () { + function PathProxy(notSaveData) { + this.dpr = 1; + this._xi = 0; + this._yi = 0; + this._x0 = 0; + this._y0 = 0; + this._len = 0; + + if (notSaveData) { + this._saveData = false; + } + + if (this._saveData) { + this.data = []; + } + } + + PathProxy.prototype.increaseVersion = function () { + this._version++; + }; + + PathProxy.prototype.getVersion = function () { + return this._version; + }; + + PathProxy.prototype.setScale = function (sx, sy, segmentIgnoreThreshold) { + segmentIgnoreThreshold = segmentIgnoreThreshold || 0; + + if (segmentIgnoreThreshold > 0) { + this._ux = mathAbs$2(segmentIgnoreThreshold / devicePixelRatio / sx) || 0; + this._uy = mathAbs$2(segmentIgnoreThreshold / devicePixelRatio / sy) || 0; + } + }; + + PathProxy.prototype.setDPR = function (dpr) { + this.dpr = dpr; + }; + + PathProxy.prototype.setContext = function (ctx) { + this._ctx = ctx; + }; + + PathProxy.prototype.getContext = function () { + return this._ctx; + }; + + PathProxy.prototype.beginPath = function () { + this._ctx && this._ctx.beginPath(); + this.reset(); + return this; + }; + + PathProxy.prototype.reset = function () { + if (this._saveData) { + this._len = 0; + } + + if (this._pathSegLen) { + this._pathSegLen = null; + this._pathLen = 0; + } + + this._version++; + }; + + PathProxy.prototype.moveTo = function (x, y) { + this._drawPendingPt(); + + this.addData(CMD$3.M, x, y); + this._ctx && this._ctx.moveTo(x, y); + this._x0 = x; + this._y0 = y; + this._xi = x; + this._yi = y; + return this; + }; + + PathProxy.prototype.lineTo = function (x, y) { + var dx = mathAbs$2(x - this._xi); + var dy = mathAbs$2(y - this._yi); + var exceedUnit = dx > this._ux || dy > this._uy; + this.addData(CMD$3.L, x, y); + + if (this._ctx && exceedUnit) { + this._ctx.lineTo(x, y); + } + + if (exceedUnit) { + this._xi = x; + this._yi = y; + this._pendingPtDist = 0; + } else { + var d2 = dx * dx + dy * dy; + + if (d2 > this._pendingPtDist) { + this._pendingPtX = x; + this._pendingPtY = y; + this._pendingPtDist = d2; + } + } + + return this; + }; + + PathProxy.prototype.bezierCurveTo = function (x1, y1, x2, y2, x3, y3) { + this._drawPendingPt(); + + this.addData(CMD$3.C, x1, y1, x2, y2, x3, y3); + + if (this._ctx) { + this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3); + } + + this._xi = x3; + this._yi = y3; + return this; + }; + + PathProxy.prototype.quadraticCurveTo = function (x1, y1, x2, y2) { + this._drawPendingPt(); + + this.addData(CMD$3.Q, x1, y1, x2, y2); + + if (this._ctx) { + this._ctx.quadraticCurveTo(x1, y1, x2, y2); + } + + this._xi = x2; + this._yi = y2; + return this; + }; + + PathProxy.prototype.arc = function (cx, cy, r, startAngle, endAngle, anticlockwise) { + this._drawPendingPt(); + + tmpAngles[0] = startAngle; + tmpAngles[1] = endAngle; + normalizeArcAngles(tmpAngles, anticlockwise); + startAngle = tmpAngles[0]; + endAngle = tmpAngles[1]; + var delta = endAngle - startAngle; + this.addData(CMD$3.A, cx, cy, r, r, startAngle, delta, 0, anticlockwise ? 0 : 1); + this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise); + this._xi = mathCos$2(endAngle) * r + cx; + this._yi = mathSin$2(endAngle) * r + cy; + return this; + }; + + PathProxy.prototype.arcTo = function (x1, y1, x2, y2, radius) { + this._drawPendingPt(); + + if (this._ctx) { + this._ctx.arcTo(x1, y1, x2, y2, radius); + } + + return this; + }; + + PathProxy.prototype.rect = function (x, y, w, h) { + this._drawPendingPt(); + + this._ctx && this._ctx.rect(x, y, w, h); + this.addData(CMD$3.R, x, y, w, h); + return this; + }; + + PathProxy.prototype.closePath = function () { + this._drawPendingPt(); + + this.addData(CMD$3.Z); + var ctx = this._ctx; + var x0 = this._x0; + var y0 = this._y0; + + if (ctx) { + ctx.closePath(); + } + + this._xi = x0; + this._yi = y0; + return this; + }; + + PathProxy.prototype.fill = function (ctx) { + ctx && ctx.fill(); + this.toStatic(); + }; + + PathProxy.prototype.stroke = function (ctx) { + ctx && ctx.stroke(); + this.toStatic(); + }; + + PathProxy.prototype.len = function () { + return this._len; + }; + + PathProxy.prototype.setData = function (data) { + if (!this._saveData) { + return; + } + + var len = data.length; + + if (!(this.data && this.data.length === len) && hasTypedArray) { + this.data = new Float32Array(len); + } + + for (var i = 0; i < len; i++) { + this.data[i] = data[i]; + } + + this._len = len; + }; + + PathProxy.prototype.appendPath = function (path) { + if (!this._saveData) { + return; + } + + if (!(path instanceof Array)) { + path = [path]; + } + + var len = path.length; + var appendSize = 0; + var offset = this._len; + + for (var i = 0; i < len; i++) { + appendSize += path[i].len(); + } + + var oldData = this.data; + + if (hasTypedArray && (oldData instanceof Float32Array || !oldData)) { + this.data = new Float32Array(offset + appendSize); + + if (offset > 0 && oldData) { + for (var k = 0; k < offset; k++) { + this.data[k] = oldData[k]; + } + } + } + + for (var i = 0; i < len; i++) { + var appendPathData = path[i].data; + + for (var k = 0; k < appendPathData.length; k++) { + this.data[offset++] = appendPathData[k]; + } + } + + this._len = offset; + }; + + PathProxy.prototype.addData = function (cmd, a, b, c, d, e, f, g, h) { + if (!this._saveData) { + return; + } + + var data = this.data; + + if (this._len + arguments.length > data.length) { + this._expandData(); + + data = this.data; + } + + for (var i = 0; i < arguments.length; i++) { + data[this._len++] = arguments[i]; + } + }; + + PathProxy.prototype._drawPendingPt = function () { + if (this._pendingPtDist > 0) { + this._ctx && this._ctx.lineTo(this._pendingPtX, this._pendingPtY); + this._pendingPtDist = 0; + } + }; + + PathProxy.prototype._expandData = function () { + if (!(this.data instanceof Array)) { + var newData = []; + + for (var i = 0; i < this._len; i++) { + newData[i] = this.data[i]; + } + + this.data = newData; + } + }; + + PathProxy.prototype.toStatic = function () { + if (!this._saveData) { + return; + } + + this._drawPendingPt(); + + var data = this.data; + + if (data instanceof Array) { + data.length = this._len; + + if (hasTypedArray && this._len > 11) { + this.data = new Float32Array(data); + } + } + }; + + PathProxy.prototype.getBoundingRect = function () { + min[0] = min[1] = min2[0] = min2[1] = Number.MAX_VALUE; + max[0] = max[1] = max2[0] = max2[1] = -Number.MAX_VALUE; + var data = this.data; + var xi = 0; + var yi = 0; + var x0 = 0; + var y0 = 0; + var i; + + for (i = 0; i < this._len;) { + var cmd = data[i++]; + var isFirst = i === 1; + + if (isFirst) { + xi = data[i]; + yi = data[i + 1]; + x0 = xi; + y0 = yi; + } + + switch (cmd) { + case CMD$3.M: + xi = x0 = data[i++]; + yi = y0 = data[i++]; + min2[0] = x0; + min2[1] = y0; + max2[0] = x0; + max2[1] = y0; + break; + + case CMD$3.L: + fromLine(xi, yi, data[i], data[i + 1], min2, max2); + xi = data[i++]; + yi = data[i++]; + break; + + case CMD$3.C: + fromCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], min2, max2); + xi = data[i++]; + yi = data[i++]; + break; + + case CMD$3.Q: + fromQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], min2, max2); + xi = data[i++]; + yi = data[i++]; + break; + + case CMD$3.A: + var cx = data[i++]; + var cy = data[i++]; + var rx = data[i++]; + var ry = data[i++]; + var startAngle = data[i++]; + var endAngle = data[i++] + startAngle; + i += 1; + var anticlockwise = !data[i++]; + + if (isFirst) { + x0 = mathCos$2(startAngle) * rx + cx; + y0 = mathSin$2(startAngle) * ry + cy; + } + + fromArc(cx, cy, rx, ry, startAngle, endAngle, anticlockwise, min2, max2); + xi = mathCos$2(endAngle) * rx + cx; + yi = mathSin$2(endAngle) * ry + cy; + break; + + case CMD$3.R: + x0 = xi = data[i++]; + y0 = yi = data[i++]; + var width = data[i++]; + var height = data[i++]; + fromLine(x0, y0, x0 + width, y0 + height, min2, max2); + break; + + case CMD$3.Z: + xi = x0; + yi = y0; + break; + } + + min$1(min, min, min2); + max$1(max, max, max2); + } + + if (i === 0) { + min[0] = min[1] = max[0] = max[1] = 0; + } + + return new BoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]); + }; + + PathProxy.prototype._calculateLength = function () { + var data = this.data; + var len = this._len; + var ux = this._ux; + var uy = this._uy; + var xi = 0; + var yi = 0; + var x0 = 0; + var y0 = 0; + + if (!this._pathSegLen) { + this._pathSegLen = []; + } + + var pathSegLen = this._pathSegLen; + var pathTotalLen = 0; + var segCount = 0; + + for (var i = 0; i < len;) { + var cmd = data[i++]; + var isFirst = i === 1; + + if (isFirst) { + xi = data[i]; + yi = data[i + 1]; + x0 = xi; + y0 = yi; + } + + var l = -1; + + switch (cmd) { + case CMD$3.M: + xi = x0 = data[i++]; + yi = y0 = data[i++]; + break; + + case CMD$3.L: + { + var x2 = data[i++]; + var y2 = data[i++]; + var dx = x2 - xi; + var dy = y2 - yi; + + if (mathAbs$2(dx) > ux || mathAbs$2(dy) > uy || i === len - 1) { + l = Math.sqrt(dx * dx + dy * dy); + xi = x2; + yi = y2; + } + + break; + } + + case CMD$3.C: + { + var x1 = data[i++]; + var y1 = data[i++]; + var x2 = data[i++]; + var y2 = data[i++]; + var x3 = data[i++]; + var y3 = data[i++]; + l = cubicLength(xi, yi, x1, y1, x2, y2, x3, y3, 10); + xi = x3; + yi = y3; + break; + } + + case CMD$3.Q: + { + var x1 = data[i++]; + var y1 = data[i++]; + var x2 = data[i++]; + var y2 = data[i++]; + l = quadraticLength(xi, yi, x1, y1, x2, y2, 10); + xi = x2; + yi = y2; + break; + } + + case CMD$3.A: + var cx = data[i++]; + var cy = data[i++]; + var rx = data[i++]; + var ry = data[i++]; + var startAngle = data[i++]; + var delta = data[i++]; + var endAngle = delta + startAngle; + i += 1; + + if (isFirst) { + x0 = mathCos$2(startAngle) * rx + cx; + y0 = mathSin$2(startAngle) * ry + cy; + } + + l = mathMax$4(rx, ry) * mathMin$4(PI2$5, Math.abs(delta)); + xi = mathCos$2(endAngle) * rx + cx; + yi = mathSin$2(endAngle) * ry + cy; + break; + + case CMD$3.R: + { + x0 = xi = data[i++]; + y0 = yi = data[i++]; + var width = data[i++]; + var height = data[i++]; + l = width * 2 + height * 2; + break; + } + + case CMD$3.Z: + { + var dx = x0 - xi; + var dy = y0 - yi; + l = Math.sqrt(dx * dx + dy * dy); + xi = x0; + yi = y0; + break; + } + } + + if (l >= 0) { + pathSegLen[segCount++] = l; + pathTotalLen += l; + } + } + + this._pathLen = pathTotalLen; + return pathTotalLen; + }; + + PathProxy.prototype.rebuildPath = function (ctx, percent) { + var d = this.data; + var ux = this._ux; + var uy = this._uy; + var len = this._len; + var x0; + var y0; + var xi; + var yi; + var x; + var y; + var drawPart = percent < 1; + var pathSegLen; + var pathTotalLen; + var accumLength = 0; + var segCount = 0; + var displayedLength; + var pendingPtDist = 0; + var pendingPtX; + var pendingPtY; + + if (drawPart) { + if (!this._pathSegLen) { + this._calculateLength(); + } + + pathSegLen = this._pathSegLen; + pathTotalLen = this._pathLen; + displayedLength = percent * pathTotalLen; + + if (!displayedLength) { + return; + } + } + + lo: for (var i = 0; i < len;) { + var cmd = d[i++]; + var isFirst = i === 1; + + if (isFirst) { + xi = d[i]; + yi = d[i + 1]; + x0 = xi; + y0 = yi; + } + + if (cmd !== CMD$3.L && pendingPtDist > 0) { + ctx.lineTo(pendingPtX, pendingPtY); + pendingPtDist = 0; + } + + switch (cmd) { + case CMD$3.M: + x0 = xi = d[i++]; + y0 = yi = d[i++]; + ctx.moveTo(xi, yi); + break; + + case CMD$3.L: + { + x = d[i++]; + y = d[i++]; + var dx = mathAbs$2(x - xi); + var dy = mathAbs$2(y - yi); + + if (dx > ux || dy > uy) { + if (drawPart) { + var l = pathSegLen[segCount++]; + + if (accumLength + l > displayedLength) { + var t = (displayedLength - accumLength) / l; + ctx.lineTo(xi * (1 - t) + x * t, yi * (1 - t) + y * t); + break lo; + } + + accumLength += l; + } + + ctx.lineTo(x, y); + xi = x; + yi = y; + pendingPtDist = 0; + } else { + var d2 = dx * dx + dy * dy; + + if (d2 > pendingPtDist) { + pendingPtX = x; + pendingPtY = y; + pendingPtDist = d2; + } + } + + break; + } + + case CMD$3.C: + { + var x1 = d[i++]; + var y1 = d[i++]; + var x2 = d[i++]; + var y2 = d[i++]; + var x3 = d[i++]; + var y3 = d[i++]; + + if (drawPart) { + var l = pathSegLen[segCount++]; + + if (accumLength + l > displayedLength) { + var t = (displayedLength - accumLength) / l; + cubicSubdivide(xi, x1, x2, x3, t, tmpOutX); + cubicSubdivide(yi, y1, y2, y3, t, tmpOutY); + ctx.bezierCurveTo(tmpOutX[1], tmpOutY[1], tmpOutX[2], tmpOutY[2], tmpOutX[3], tmpOutY[3]); + break lo; + } + + accumLength += l; + } + + ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3); + xi = x3; + yi = y3; + break; + } + + case CMD$3.Q: + { + var x1 = d[i++]; + var y1 = d[i++]; + var x2 = d[i++]; + var y2 = d[i++]; + + if (drawPart) { + var l = pathSegLen[segCount++]; + + if (accumLength + l > displayedLength) { + var t = (displayedLength - accumLength) / l; + quadraticSubdivide(xi, x1, x2, t, tmpOutX); + quadraticSubdivide(yi, y1, y2, t, tmpOutY); + ctx.quadraticCurveTo(tmpOutX[1], tmpOutY[1], tmpOutX[2], tmpOutY[2]); + break lo; + } + + accumLength += l; + } + + ctx.quadraticCurveTo(x1, y1, x2, y2); + xi = x2; + yi = y2; + break; + } + + case CMD$3.A: + var cx = d[i++]; + var cy = d[i++]; + var rx = d[i++]; + var ry = d[i++]; + var startAngle = d[i++]; + var delta = d[i++]; + var psi = d[i++]; + var anticlockwise = !d[i++]; + var r = rx > ry ? rx : ry; + var isEllipse = mathAbs$2(rx - ry) > 1e-3; + var endAngle = startAngle + delta; + var breakBuild = false; + + if (drawPart) { + var l = pathSegLen[segCount++]; + + if (accumLength + l > displayedLength) { + endAngle = startAngle + delta * (displayedLength - accumLength) / l; + breakBuild = true; + } + + accumLength += l; + } + + if (isEllipse && ctx.ellipse) { + ctx.ellipse(cx, cy, rx, ry, psi, startAngle, endAngle, anticlockwise); + } else { + ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise); + } + + if (breakBuild) { + break lo; + } + + if (isFirst) { + x0 = mathCos$2(startAngle) * rx + cx; + y0 = mathSin$2(startAngle) * ry + cy; + } + + xi = mathCos$2(endAngle) * rx + cx; + yi = mathSin$2(endAngle) * ry + cy; + break; + + case CMD$3.R: + x0 = xi = d[i]; + y0 = yi = d[i + 1]; + x = d[i++]; + y = d[i++]; + var width = d[i++]; + var height = d[i++]; + + if (drawPart) { + var l = pathSegLen[segCount++]; + + if (accumLength + l > displayedLength) { + var d_1 = displayedLength - accumLength; + ctx.moveTo(x, y); + ctx.lineTo(x + mathMin$4(d_1, width), y); + d_1 -= width; + + if (d_1 > 0) { + ctx.lineTo(x + width, y + mathMin$4(d_1, height)); + } + + d_1 -= height; + + if (d_1 > 0) { + ctx.lineTo(x + mathMax$4(width - d_1, 0), y + height); + } + + d_1 -= width; + + if (d_1 > 0) { + ctx.lineTo(x, y + mathMax$4(height - d_1, 0)); + } + + break lo; + } + + accumLength += l; + } + + ctx.rect(x, y, width, height); + break; + + case CMD$3.Z: + if (drawPart) { + var l = pathSegLen[segCount++]; + + if (accumLength + l > displayedLength) { + var t = (displayedLength - accumLength) / l; + ctx.lineTo(xi * (1 - t) + x0 * t, yi * (1 - t) + y0 * t); + break lo; + } + + accumLength += l; + } + + ctx.closePath(); + xi = x0; + yi = y0; + } + } + }; + + PathProxy.prototype.clone = function () { + var newProxy = new PathProxy(); + var data = this.data; + newProxy.data = data.slice ? data.slice() : Array.prototype.slice.call(data); + newProxy._len = this._len; + return newProxy; + }; + + PathProxy.prototype.canSave = function () { + return !!this._saveData; + }; + + PathProxy.CMD = CMD$3; + + PathProxy.initDefaultProps = function () { + var proto = PathProxy.prototype; + proto._saveData = true; + proto._ux = 0; + proto._uy = 0; + proto._pendingPtDist = 0; + proto._version = 0; + }(); + + return PathProxy; + }(); + + function containStroke$4(x0, y0, x1, y1, lineWidth, x, y) { + if (lineWidth === 0) { + return false; + } + + var _l = lineWidth; + var _a = 0; + var _b = x0; + + if (y > y0 + _l && y > y1 + _l || y < y0 - _l && y < y1 - _l || x > x0 + _l && x > x1 + _l || x < x0 - _l && x < x1 - _l) { + return false; + } + + if (x0 !== x1) { + _a = (y0 - y1) / (x0 - x1); + _b = (x0 * y1 - x1 * y0) / (x0 - x1); + } else { + return Math.abs(x - x0) <= _l / 2; + } + + var tmp = _a * x - y + _b; + + var _s = tmp * tmp / (_a * _a + 1); + + return _s <= _l / 2 * _l / 2; + } + + function containStroke$3(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) { + if (lineWidth === 0) { + return false; + } + + var _l = lineWidth; + + if (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l || y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l || x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l || x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l) { + return false; + } + + var d = cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, null); + return d <= _l / 2; + } + + function containStroke$2(x0, y0, x1, y1, x2, y2, lineWidth, x, y) { + if (lineWidth === 0) { + return false; + } + + var _l = lineWidth; + + if (y > y0 + _l && y > y1 + _l && y > y2 + _l || y < y0 - _l && y < y1 - _l && y < y2 - _l || x > x0 + _l && x > x1 + _l && x > x2 + _l || x < x0 - _l && x < x1 - _l && x < x2 - _l) { + return false; + } + + var d = quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, null); + return d <= _l / 2; + } + + var PI2$4 = Math.PI * 2; + + function normalizeRadian(angle) { + angle %= PI2$4; + + if (angle < 0) { + angle += PI2$4; + } + + return angle; + } + + var PI2$3 = Math.PI * 2; + + function containStroke$1(cx, cy, r, startAngle, endAngle, anticlockwise, lineWidth, x, y) { + if (lineWidth === 0) { + return false; + } + + var _l = lineWidth; + x -= cx; + y -= cy; + var d = Math.sqrt(x * x + y * y); + + if (d - _l > r || d + _l < r) { + return false; + } + + if (Math.abs(startAngle - endAngle) % PI2$3 < 1e-4) { + return true; + } + + if (anticlockwise) { + var tmp = startAngle; + startAngle = normalizeRadian(endAngle); + endAngle = normalizeRadian(tmp); + } else { + startAngle = normalizeRadian(startAngle); + endAngle = normalizeRadian(endAngle); + } + + if (startAngle > endAngle) { + endAngle += PI2$3; + } + + var angle = Math.atan2(y, x); + + if (angle < 0) { + angle += PI2$3; + } + + return angle >= startAngle && angle <= endAngle || angle + PI2$3 >= startAngle && angle + PI2$3 <= endAngle; + } + + function windingLine(x0, y0, x1, y1, x, y) { + if (y > y0 && y > y1 || y < y0 && y < y1) { + return 0; + } + + if (y1 === y0) { + return 0; + } + + var t = (y - y0) / (y1 - y0); + var dir = y1 < y0 ? 1 : -1; + + if (t === 1 || t === 0) { + dir = y1 < y0 ? 0.5 : -0.5; + } + + var x_ = t * (x1 - x0) + x0; + return x_ === x ? Infinity : x_ > x ? dir : 0; + } + + var CMD$2 = PathProxy.CMD; + var PI2$2 = Math.PI * 2; + var EPSILON$1 = 1e-4; + + function isAroundEqual$1(a, b) { + return Math.abs(a - b) < EPSILON$1; + } + + var roots = [-1, -1, -1]; + var extrema = [-1, -1]; + + function swapExtrema() { + var tmp = extrema[0]; + extrema[0] = extrema[1]; + extrema[1] = tmp; + } + + function windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) { + if (y > y0 && y > y1 && y > y2 && y > y3 || y < y0 && y < y1 && y < y2 && y < y3) { + return 0; + } + + var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots); + + if (nRoots === 0) { + return 0; + } else { + var w = 0; + var nExtrema = -1; + var y0_ = void 0; + var y1_ = void 0; + + for (var i = 0; i < nRoots; i++) { + var t = roots[i]; + var unit = t === 0 || t === 1 ? 0.5 : 1; + var x_ = cubicAt(x0, x1, x2, x3, t); + + if (x_ < x) { + continue; + } + + if (nExtrema < 0) { + nExtrema = cubicExtrema(y0, y1, y2, y3, extrema); + + if (extrema[1] < extrema[0] && nExtrema > 1) { + swapExtrema(); + } + + y0_ = cubicAt(y0, y1, y2, y3, extrema[0]); + + if (nExtrema > 1) { + y1_ = cubicAt(y0, y1, y2, y3, extrema[1]); + } + } + + if (nExtrema === 2) { + if (t < extrema[0]) { + w += y0_ < y0 ? unit : -unit; + } else if (t < extrema[1]) { + w += y1_ < y0_ ? unit : -unit; + } else { + w += y3 < y1_ ? unit : -unit; + } + } else { + if (t < extrema[0]) { + w += y0_ < y0 ? unit : -unit; + } else { + w += y3 < y0_ ? unit : -unit; + } + } + } + + return w; + } + } + + function windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) { + if (y > y0 && y > y1 && y > y2 || y < y0 && y < y1 && y < y2) { + return 0; + } + + var nRoots = quadraticRootAt(y0, y1, y2, y, roots); + + if (nRoots === 0) { + return 0; + } else { + var t = quadraticExtremum(y0, y1, y2); + + if (t >= 0 && t <= 1) { + var w = 0; + var y_ = quadraticAt(y0, y1, y2, t); + + for (var i = 0; i < nRoots; i++) { + var unit = roots[i] === 0 || roots[i] === 1 ? 0.5 : 1; + var x_ = quadraticAt(x0, x1, x2, roots[i]); + + if (x_ < x) { + continue; + } + + if (roots[i] < t) { + w += y_ < y0 ? unit : -unit; + } else { + w += y2 < y_ ? unit : -unit; + } + } + + return w; + } else { + var unit = roots[0] === 0 || roots[0] === 1 ? 0.5 : 1; + var x_ = quadraticAt(x0, x1, x2, roots[0]); + + if (x_ < x) { + return 0; + } + + return y2 < y0 ? unit : -unit; + } + } + } + + function windingArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y) { + y -= cy; + + if (y > r || y < -r) { + return 0; + } + + var tmp = Math.sqrt(r * r - y * y); + roots[0] = -tmp; + roots[1] = tmp; + var dTheta = Math.abs(startAngle - endAngle); + + if (dTheta < 1e-4) { + return 0; + } + + if (dTheta >= PI2$2 - 1e-4) { + startAngle = 0; + endAngle = PI2$2; + var dir = anticlockwise ? 1 : -1; + + if (x >= roots[0] + cx && x <= roots[1] + cx) { + return dir; + } else { + return 0; + } + } + + if (startAngle > endAngle) { + var tmp_1 = startAngle; + startAngle = endAngle; + endAngle = tmp_1; + } + + if (startAngle < 0) { + startAngle += PI2$2; + endAngle += PI2$2; + } + + var w = 0; + + for (var i = 0; i < 2; i++) { + var x_ = roots[i]; + + if (x_ + cx > x) { + var angle = Math.atan2(y, x_); + var dir = anticlockwise ? 1 : -1; + + if (angle < 0) { + angle = PI2$2 + angle; + } + + if (angle >= startAngle && angle <= endAngle || angle + PI2$2 >= startAngle && angle + PI2$2 <= endAngle) { + if (angle > Math.PI / 2 && angle < Math.PI * 1.5) { + dir = -dir; + } + + w += dir; + } + } + } + + return w; + } + + function containPath(path, lineWidth, isStroke, x, y) { + var data = path.data; + var len = path.len(); + var w = 0; + var xi = 0; + var yi = 0; + var x0 = 0; + var y0 = 0; + var x1; + var y1; + + for (var i = 0; i < len;) { + var cmd = data[i++]; + var isFirst = i === 1; + + if (cmd === CMD$2.M && i > 1) { + if (!isStroke) { + w += windingLine(xi, yi, x0, y0, x, y); + } + } + + if (isFirst) { + xi = data[i]; + yi = data[i + 1]; + x0 = xi; + y0 = yi; + } + + switch (cmd) { + case CMD$2.M: + x0 = data[i++]; + y0 = data[i++]; + xi = x0; + yi = y0; + break; + + case CMD$2.L: + if (isStroke) { + if (containStroke$4(xi, yi, data[i], data[i + 1], lineWidth, x, y)) { + return true; + } + } else { + w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0; + } + + xi = data[i++]; + yi = data[i++]; + break; + + case CMD$2.C: + if (isStroke) { + if (containStroke$3(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) { + return true; + } + } else { + w += windingCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y) || 0; + } + + xi = data[i++]; + yi = data[i++]; + break; + + case CMD$2.Q: + if (isStroke) { + if (containStroke$2(xi, yi, data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) { + return true; + } + } else { + w += windingQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y) || 0; + } + + xi = data[i++]; + yi = data[i++]; + break; + + case CMD$2.A: + var cx = data[i++]; + var cy = data[i++]; + var rx = data[i++]; + var ry = data[i++]; + var theta = data[i++]; + var dTheta = data[i++]; + i += 1; + var anticlockwise = !!(1 - data[i++]); + x1 = Math.cos(theta) * rx + cx; + y1 = Math.sin(theta) * ry + cy; + + if (!isFirst) { + w += windingLine(xi, yi, x1, y1, x, y); + } else { + x0 = x1; + y0 = y1; + } + + var _x = (x - cx) * ry / rx + cx; + + if (isStroke) { + if (containStroke$1(cx, cy, ry, theta, theta + dTheta, anticlockwise, lineWidth, _x, y)) { + return true; + } + } else { + w += windingArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y); + } + + xi = Math.cos(theta + dTheta) * rx + cx; + yi = Math.sin(theta + dTheta) * ry + cy; + break; + + case CMD$2.R: + x0 = xi = data[i++]; + y0 = yi = data[i++]; + var width = data[i++]; + var height = data[i++]; + x1 = x0 + width; + y1 = y0 + height; + + if (isStroke) { + if (containStroke$4(x0, y0, x1, y0, lineWidth, x, y) || containStroke$4(x1, y0, x1, y1, lineWidth, x, y) || containStroke$4(x1, y1, x0, y1, lineWidth, x, y) || containStroke$4(x0, y1, x0, y0, lineWidth, x, y)) { + return true; + } + } else { + w += windingLine(x1, y0, x1, y1, x, y); + w += windingLine(x0, y1, x0, y0, x, y); + } + + break; + + case CMD$2.Z: + if (isStroke) { + if (containStroke$4(xi, yi, x0, y0, lineWidth, x, y)) { + return true; + } + } else { + w += windingLine(xi, yi, x0, y0, x, y); + } + + xi = x0; + yi = y0; + break; + } + } + + if (!isStroke && !isAroundEqual$1(yi, y0)) { + w += windingLine(xi, yi, x0, y0, x, y) || 0; + } + + return w !== 0; + } + + function contain$2(pathProxy, x, y) { + return containPath(pathProxy, 0, false, x, y); + } + + function containStroke(pathProxy, lineWidth, x, y) { + return containPath(pathProxy, lineWidth, true, x, y); + } + + var DEFAULT_PATH_STYLE = defaults({ + fill: '#000', + stroke: null, + strokePercent: 1, + fillOpacity: 1, + strokeOpacity: 1, + lineDashOffset: 0, + lineWidth: 1, + lineCap: 'butt', + miterLimit: 10, + strokeNoScale: false, + strokeFirst: false + }, DEFAULT_COMMON_STYLE); + var DEFAULT_PATH_ANIMATION_PROPS = { + style: defaults({ + fill: true, + stroke: true, + strokePercent: true, + fillOpacity: true, + strokeOpacity: true, + lineDashOffset: true, + lineWidth: true, + miterLimit: true + }, DEFAULT_COMMON_ANIMATION_PROPS.style) + }; + var pathCopyParams = TRANSFORMABLE_PROPS.concat(['invisible', 'culling', 'z', 'z2', 'zlevel', 'parent']); + + var Path = function (_super) { + __extends(Path, _super); + + function Path(opts) { + return _super.call(this, opts) || this; + } + + Path.prototype.update = function () { + var _this = this; + + _super.prototype.update.call(this); + + var style = this.style; + + if (style.decal) { + var decalEl = this._decalEl = this._decalEl || new Path(); + + if (decalEl.buildPath === Path.prototype.buildPath) { + decalEl.buildPath = function (ctx) { + _this.buildPath(ctx, _this.shape); + }; + } + + decalEl.silent = true; + var decalElStyle = decalEl.style; + + for (var key in style) { + if (decalElStyle[key] !== style[key]) { + decalElStyle[key] = style[key]; + } + } + + decalElStyle.fill = style.fill ? style.decal : null; + decalElStyle.decal = null; + decalElStyle.shadowColor = null; + style.strokeFirst && (decalElStyle.stroke = null); + + for (var i = 0; i < pathCopyParams.length; ++i) { + decalEl[pathCopyParams[i]] = this[pathCopyParams[i]]; + } + + decalEl.__dirty |= REDRAW_BIT; + } else if (this._decalEl) { + this._decalEl = null; + } + }; + + Path.prototype.getDecalElement = function () { + return this._decalEl; + }; + + Path.prototype._init = function (props) { + var keysArr = keys(props); + this.shape = this.getDefaultShape(); + var defaultStyle = this.getDefaultStyle(); + + if (defaultStyle) { + this.useStyle(defaultStyle); + } + + for (var i = 0; i < keysArr.length; i++) { + var key = keysArr[i]; + var value = props[key]; + + if (key === 'style') { + if (!this.style) { + this.useStyle(value); + } else { + extend(this.style, value); + } + } else if (key === 'shape') { + extend(this.shape, value); + } else { + _super.prototype.attrKV.call(this, key, value); + } + } + + if (!this.style) { + this.useStyle({}); + } + }; + + Path.prototype.getDefaultStyle = function () { + return null; + }; + + Path.prototype.getDefaultShape = function () { + return {}; + }; + + Path.prototype.canBeInsideText = function () { + return this.hasFill(); + }; + + Path.prototype.getInsideTextFill = function () { + var pathFill = this.style.fill; + + if (pathFill !== 'none') { + if (isString(pathFill)) { + var fillLum = lum(pathFill, 0); + + if (fillLum > 0.5) { + return DARK_LABEL_COLOR; + } else if (fillLum > 0.2) { + return LIGHTER_LABEL_COLOR; + } + + return LIGHT_LABEL_COLOR; + } else if (pathFill) { + return LIGHT_LABEL_COLOR; + } + } + + return DARK_LABEL_COLOR; + }; + + Path.prototype.getInsideTextStroke = function (textFill) { + var pathFill = this.style.fill; + + if (isString(pathFill)) { + var zr = this.__zr; + var isDarkMode = !!(zr && zr.isDarkMode()); + var isDarkLabel = lum(textFill, 0) < DARK_MODE_THRESHOLD; + + if (isDarkMode === isDarkLabel) { + return pathFill; + } + } + }; + + Path.prototype.buildPath = function (ctx, shapeCfg, inBatch) {}; + + Path.prototype.pathUpdated = function () { + this.__dirty &= ~SHAPE_CHANGED_BIT; + }; + + Path.prototype.getUpdatedPathProxy = function (inBatch) { + !this.path && this.createPathProxy(); + this.path.beginPath(); + this.buildPath(this.path, this.shape, inBatch); + return this.path; + }; + + Path.prototype.createPathProxy = function () { + this.path = new PathProxy(false); + }; + + Path.prototype.hasStroke = function () { + var style = this.style; + var stroke = style.stroke; + return !(stroke == null || stroke === 'none' || !(style.lineWidth > 0)); + }; + + Path.prototype.hasFill = function () { + var style = this.style; + var fill = style.fill; + return fill != null && fill !== 'none'; + }; + + Path.prototype.getBoundingRect = function () { + var rect = this._rect; + var style = this.style; + var needsUpdateRect = !rect; + + if (needsUpdateRect) { + var firstInvoke = false; + + if (!this.path) { + firstInvoke = true; + this.createPathProxy(); + } + + var path = this.path; + + if (firstInvoke || this.__dirty & SHAPE_CHANGED_BIT) { + path.beginPath(); + this.buildPath(path, this.shape, false); + this.pathUpdated(); + } + + rect = path.getBoundingRect(); + } + + this._rect = rect; + + if (this.hasStroke() && this.path && this.path.len() > 0) { + var rectStroke = this._rectStroke || (this._rectStroke = rect.clone()); + + if (this.__dirty || needsUpdateRect) { + rectStroke.copy(rect); + var lineScale = style.strokeNoScale ? this.getLineScale() : 1; + var w = style.lineWidth; + + if (!this.hasFill()) { + var strokeContainThreshold = this.strokeContainThreshold; + w = Math.max(w, strokeContainThreshold == null ? 4 : strokeContainThreshold); + } + + if (lineScale > 1e-10) { + rectStroke.width += w / lineScale; + rectStroke.height += w / lineScale; + rectStroke.x -= w / lineScale / 2; + rectStroke.y -= w / lineScale / 2; + } + } + + return rectStroke; + } + + return rect; + }; + + Path.prototype.contain = function (x, y) { + var localPos = this.transformCoordToLocal(x, y); + var rect = this.getBoundingRect(); + var style = this.style; + x = localPos[0]; + y = localPos[1]; + + if (rect.contain(x, y)) { + var pathProxy = this.path; + + if (this.hasStroke()) { + var lineWidth = style.lineWidth; + var lineScale = style.strokeNoScale ? this.getLineScale() : 1; + + if (lineScale > 1e-10) { + if (!this.hasFill()) { + lineWidth = Math.max(lineWidth, this.strokeContainThreshold); + } + + if (containStroke(pathProxy, lineWidth / lineScale, x, y)) { + return true; + } + } + } + + if (this.hasFill()) { + return contain$2(pathProxy, x, y); + } + } + + return false; + }; + + Path.prototype.dirtyShape = function () { + this.__dirty |= SHAPE_CHANGED_BIT; + + if (this._rect) { + this._rect = null; + } + + if (this._decalEl) { + this._decalEl.dirtyShape(); + } + + this.markRedraw(); + }; + + Path.prototype.dirty = function () { + this.dirtyStyle(); + this.dirtyShape(); + }; + + Path.prototype.animateShape = function (loop) { + return this.animate('shape', loop); + }; + + Path.prototype.updateDuringAnimation = function (targetKey) { + if (targetKey === 'style') { + this.dirtyStyle(); + } else if (targetKey === 'shape') { + this.dirtyShape(); + } else { + this.markRedraw(); + } + }; + + Path.prototype.attrKV = function (key, value) { + if (key === 'shape') { + this.setShape(value); + } else { + _super.prototype.attrKV.call(this, key, value); + } + }; + + Path.prototype.setShape = function (keyOrObj, value) { + var shape = this.shape; + + if (!shape) { + shape = this.shape = {}; + } + + if (typeof keyOrObj === 'string') { + shape[keyOrObj] = value; + } else { + extend(shape, keyOrObj); + } + + this.dirtyShape(); + return this; + }; + + Path.prototype.shapeChanged = function () { + return !!(this.__dirty & SHAPE_CHANGED_BIT); + }; + + Path.prototype.createStyle = function (obj) { + return createObject(DEFAULT_PATH_STYLE, obj); + }; + + Path.prototype._innerSaveToNormal = function (toState) { + _super.prototype._innerSaveToNormal.call(this, toState); + + var normalState = this._normalState; + + if (toState.shape && !normalState.shape) { + normalState.shape = extend({}, this.shape); + } + }; + + Path.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) { + _super.prototype._applyStateObj.call(this, stateName, state, normalState, keepCurrentStates, transition, animationCfg); + + var needsRestoreToNormal = !(state && keepCurrentStates); + var targetShape; + + if (state && state.shape) { + if (transition) { + if (keepCurrentStates) { + targetShape = state.shape; + } else { + targetShape = extend({}, normalState.shape); + extend(targetShape, state.shape); + } + } else { + targetShape = extend({}, keepCurrentStates ? this.shape : normalState.shape); + extend(targetShape, state.shape); + } + } else if (needsRestoreToNormal) { + targetShape = normalState.shape; + } + + if (targetShape) { + if (transition) { + this.shape = extend({}, this.shape); + var targetShapePrimaryProps = {}; + var shapeKeys = keys(targetShape); + + for (var i = 0; i < shapeKeys.length; i++) { + var key = shapeKeys[i]; + + if (typeof targetShape[key] === 'object') { + this.shape[key] = targetShape[key]; + } else { + targetShapePrimaryProps[key] = targetShape[key]; + } + } + + this._transitionState(stateName, { + shape: targetShapePrimaryProps + }, animationCfg); + } else { + this.shape = targetShape; + this.dirtyShape(); + } + } + }; + + Path.prototype._mergeStates = function (states) { + var mergedState = _super.prototype._mergeStates.call(this, states); + + var mergedShape; + + for (var i = 0; i < states.length; i++) { + var state = states[i]; + + if (state.shape) { + mergedShape = mergedShape || {}; + + this._mergeStyle(mergedShape, state.shape); + } + } + + if (mergedShape) { + mergedState.shape = mergedShape; + } + + return mergedState; + }; + + Path.prototype.getAnimationStyleProps = function () { + return DEFAULT_PATH_ANIMATION_PROPS; + }; + + Path.prototype.isZeroArea = function () { + return false; + }; + + Path.extend = function (defaultProps) { + var Sub = function (_super) { + __extends(Sub, _super); + + function Sub(opts) { + var _this = _super.call(this, opts) || this; + + defaultProps.init && defaultProps.init.call(_this, opts); + return _this; + } + + Sub.prototype.getDefaultStyle = function () { + return clone$3(defaultProps.style); + }; + + Sub.prototype.getDefaultShape = function () { + return clone$3(defaultProps.shape); + }; + + return Sub; + }(Path); + + for (var key in defaultProps) { + if (typeof defaultProps[key] === 'function') { + Sub.prototype[key] = defaultProps[key]; + } + } + + return Sub; + }; + + Path.initDefaultProps = function () { + var pathProto = Path.prototype; + pathProto.type = 'path'; + pathProto.strokeContainThreshold = 5; + pathProto.segmentIgnoreThreshold = 0; + pathProto.subPixelOptimize = false; + pathProto.autoBatch = false; + pathProto.__dirty = REDRAW_BIT | STYLE_CHANGED_BIT | SHAPE_CHANGED_BIT; + }(); + + return Path; + }(Displayable); + + var DEFAULT_TSPAN_STYLE = defaults({ + strokeFirst: true, + font: DEFAULT_FONT, + x: 0, + y: 0, + textAlign: 'left', + textBaseline: 'top', + miterLimit: 2 + }, DEFAULT_PATH_STYLE); + + var TSpan = function (_super) { + __extends(TSpan, _super); + + function TSpan() { + return _super !== null && _super.apply(this, arguments) || this; + } + + TSpan.prototype.hasStroke = function () { + return tSpanHasStroke(this.style); + }; + + TSpan.prototype.hasFill = function () { + var style = this.style; + var fill = style.fill; + return fill != null && fill !== 'none'; + }; + + TSpan.prototype.createStyle = function (obj) { + return createObject(DEFAULT_TSPAN_STYLE, obj); + }; + + TSpan.prototype.setBoundingRect = function (rect) { + this._rect = rect; + }; + + TSpan.prototype.getBoundingRect = function () { + if (!this._rect) { + this._rect = tSpanCreateBoundingRect(this.style); + } + + return this._rect; + }; + + TSpan.initDefaultProps = function () { + var tspanProto = TSpan.prototype; + tspanProto.dirtyRectTolerance = 10; + }(); + + return TSpan; + }(Displayable); + + TSpan.prototype.type = 'tspan'; + var DEFAULT_IMAGE_STYLE = defaults({ + x: 0, + y: 0 + }, DEFAULT_COMMON_STYLE); + var DEFAULT_IMAGE_ANIMATION_PROPS = { + style: defaults({ + x: true, + y: true, + width: true, + height: true, + sx: true, + sy: true, + sWidth: true, + sHeight: true + }, DEFAULT_COMMON_ANIMATION_PROPS.style) + }; + + function isImageLike(source) { + return !!(source && typeof source !== 'string' && source.width && source.height); + } + + var ZRImage = function (_super) { + __extends(ZRImage, _super); + + function ZRImage() { + return _super !== null && _super.apply(this, arguments) || this; + } + + ZRImage.prototype.createStyle = function (obj) { + return createObject(DEFAULT_IMAGE_STYLE, obj); + }; + + ZRImage.prototype._getSize = function (dim) { + var style = this.style; + var size = style[dim]; + + if (size != null) { + return size; + } + + var imageSource = isImageLike(style.image) ? style.image : this.__image; + + if (!imageSource) { + return 0; + } + + var otherDim = dim === 'width' ? 'height' : 'width'; + var otherDimSize = style[otherDim]; + + if (otherDimSize == null) { + return imageSource[dim]; + } else { + return imageSource[dim] / imageSource[otherDim] * otherDimSize; + } + }; + + ZRImage.prototype.getWidth = function () { + return this._getSize('width'); + }; + + ZRImage.prototype.getHeight = function () { + return this._getSize('height'); + }; + + ZRImage.prototype.getAnimationStyleProps = function () { + return DEFAULT_IMAGE_ANIMATION_PROPS; + }; + + ZRImage.prototype.getBoundingRect = function () { + var style = this.style; + + if (!this._rect) { + this._rect = new BoundingRect(style.x || 0, style.y || 0, this.getWidth(), this.getHeight()); + } + + return this._rect; + }; + + return ZRImage; + }(Displayable); + + ZRImage.prototype.type = 'image'; + + function buildPath$2(ctx, shape) { + var x = shape.x; + var y = shape.y; + var width = shape.width; + var height = shape.height; + var r = shape.r; + var r1; + var r2; + var r3; + var r4; + + if (width < 0) { + x = x + width; + width = -width; + } + + if (height < 0) { + y = y + height; + height = -height; + } + + if (typeof r === 'number') { + r1 = r2 = r3 = r4 = r; + } else if (r instanceof Array) { + if (r.length === 1) { + r1 = r2 = r3 = r4 = r[0]; + } else if (r.length === 2) { + r1 = r3 = r[0]; + r2 = r4 = r[1]; + } else if (r.length === 3) { + r1 = r[0]; + r2 = r4 = r[1]; + r3 = r[2]; + } else { + r1 = r[0]; + r2 = r[1]; + r3 = r[2]; + r4 = r[3]; + } + } else { + r1 = r2 = r3 = r4 = 0; + } + + var total; + + if (r1 + r2 > width) { + total = r1 + r2; + r1 *= width / total; + r2 *= width / total; + } + + if (r3 + r4 > width) { + total = r3 + r4; + r3 *= width / total; + r4 *= width / total; + } + + if (r2 + r3 > height) { + total = r2 + r3; + r2 *= height / total; + r3 *= height / total; + } + + if (r1 + r4 > height) { + total = r1 + r4; + r1 *= height / total; + r4 *= height / total; + } + + ctx.moveTo(x + r1, y); + ctx.lineTo(x + width - r2, y); + r2 !== 0 && ctx.arc(x + width - r2, y + r2, r2, -Math.PI / 2, 0); + ctx.lineTo(x + width, y + height - r3); + r3 !== 0 && ctx.arc(x + width - r3, y + height - r3, r3, 0, Math.PI / 2); + ctx.lineTo(x + r4, y + height); + r4 !== 0 && ctx.arc(x + r4, y + height - r4, r4, Math.PI / 2, Math.PI); + ctx.lineTo(x, y + r1); + r1 !== 0 && ctx.arc(x + r1, y + r1, r1, Math.PI, Math.PI * 1.5); + } + + var round = Math.round; + + function subPixelOptimizeLine$1(outputShape, inputShape, style) { + if (!inputShape) { + return; + } + + var x1 = inputShape.x1; + var x2 = inputShape.x2; + var y1 = inputShape.y1; + var y2 = inputShape.y2; + outputShape.x1 = x1; + outputShape.x2 = x2; + outputShape.y1 = y1; + outputShape.y2 = y2; + var lineWidth = style && style.lineWidth; + + if (!lineWidth) { + return outputShape; + } + + if (round(x1 * 2) === round(x2 * 2)) { + outputShape.x1 = outputShape.x2 = subPixelOptimize$1(x1, lineWidth, true); + } + + if (round(y1 * 2) === round(y2 * 2)) { + outputShape.y1 = outputShape.y2 = subPixelOptimize$1(y1, lineWidth, true); + } + + return outputShape; + } + + function subPixelOptimizeRect$1(outputShape, inputShape, style) { + if (!inputShape) { + return; + } + + var originX = inputShape.x; + var originY = inputShape.y; + var originWidth = inputShape.width; + var originHeight = inputShape.height; + outputShape.x = originX; + outputShape.y = originY; + outputShape.width = originWidth; + outputShape.height = originHeight; + var lineWidth = style && style.lineWidth; + + if (!lineWidth) { + return outputShape; + } + + outputShape.x = subPixelOptimize$1(originX, lineWidth, true); + outputShape.y = subPixelOptimize$1(originY, lineWidth, true); + outputShape.width = Math.max(subPixelOptimize$1(originX + originWidth, lineWidth, false) - outputShape.x, originWidth === 0 ? 0 : 1); + outputShape.height = Math.max(subPixelOptimize$1(originY + originHeight, lineWidth, false) - outputShape.y, originHeight === 0 ? 0 : 1); + return outputShape; + } + + function subPixelOptimize$1(position, lineWidth, positiveOrNegative) { + if (!lineWidth) { + return position; + } + + var doubledPosition = round(position * 2); + return (doubledPosition + round(lineWidth)) % 2 === 0 ? doubledPosition / 2 : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2; + } + + var RectShape = function () { + function RectShape() { + this.x = 0; + this.y = 0; + this.width = 0; + this.height = 0; + } + + return RectShape; + }(); + + var subPixelOptimizeOutputShape$1 = {}; + + var Rect = function (_super) { + __extends(Rect, _super); + + function Rect(opts) { + return _super.call(this, opts) || this; + } + + Rect.prototype.getDefaultShape = function () { + return new RectShape(); + }; + + Rect.prototype.buildPath = function (ctx, shape) { + var x; + var y; + var width; + var height; + + if (this.subPixelOptimize) { + var optimizedShape = subPixelOptimizeRect$1(subPixelOptimizeOutputShape$1, shape, this.style); + x = optimizedShape.x; + y = optimizedShape.y; + width = optimizedShape.width; + height = optimizedShape.height; + optimizedShape.r = shape.r; + shape = optimizedShape; + } else { + x = shape.x; + y = shape.y; + width = shape.width; + height = shape.height; + } + + if (!shape.r) { + ctx.rect(x, y, width, height); + } else { + buildPath$2(ctx, shape); + } + }; + + Rect.prototype.isZeroArea = function () { + return !this.shape.width || !this.shape.height; + }; + + return Rect; + }(Path); + + Rect.prototype.type = 'rect'; + var DEFAULT_RICH_TEXT_COLOR = { + fill: '#000' + }; + var DEFAULT_STROKE_LINE_WIDTH = 2; + var tmpCITOverflowAreaOut = {}; + var DEFAULT_TEXT_ANIMATION_PROPS = { + style: defaults({ + fill: true, + stroke: true, + fillOpacity: true, + strokeOpacity: true, + lineWidth: true, + fontSize: true, + lineHeight: true, + width: true, + height: true, + textShadowColor: true, + textShadowBlur: true, + textShadowOffsetX: true, + textShadowOffsetY: true, + backgroundColor: true, + padding: true, + borderColor: true, + borderWidth: true, + borderRadius: true + }, DEFAULT_COMMON_ANIMATION_PROPS.style) + }; + + var ZRText = function (_super) { + __extends(ZRText, _super); + + function ZRText(opts) { + var _this = _super.call(this) || this; + + _this.type = 'text'; + _this._children = []; + _this._defaultStyle = DEFAULT_RICH_TEXT_COLOR; + + _this.attr(opts); + + return _this; + } + + ZRText.prototype.childrenRef = function () { + return this._children; + }; + + ZRText.prototype.update = function () { + _super.prototype.update.call(this); + + if (this.styleChanged()) { + this._updateSubTexts(); + } + + for (var i = 0; i < this._children.length; i++) { + var child = this._children[i]; + child.zlevel = this.zlevel; + child.z = this.z; + child.z2 = this.z2; + child.culling = this.culling; + child.cursor = this.cursor; + child.invisible = this.invisible; + } + }; + + ZRText.prototype.updateTransform = function () { + var innerTransformable = this.innerTransformable; + + if (innerTransformable) { + innerTransformable.updateTransform(); + + if (innerTransformable.transform) { + this.transform = innerTransformable.transform; + } + } else { + _super.prototype.updateTransform.call(this); + } + }; + + ZRText.prototype.getLocalTransform = function (m) { + var innerTransformable = this.innerTransformable; + return innerTransformable ? innerTransformable.getLocalTransform(m) : _super.prototype.getLocalTransform.call(this, m); + }; + + ZRText.prototype.getComputedTransform = function () { + if (this.__hostTarget) { + this.__hostTarget.getComputedTransform(); + + this.__hostTarget.updateInnerText(true); + } + + return _super.prototype.getComputedTransform.call(this); + }; + + ZRText.prototype._updateSubTexts = function () { + this._childCursor = 0; + normalizeTextStyle(this.style); + this.style.rich ? this._updateRichTexts() : this._updatePlainTexts(); + this._children.length = this._childCursor; + this.styleUpdated(); + }; + + ZRText.prototype.addSelfToZr = function (zr) { + _super.prototype.addSelfToZr.call(this, zr); + + for (var i = 0; i < this._children.length; i++) { + this._children[i].__zr = zr; + } + }; + + ZRText.prototype.removeSelfFromZr = function (zr) { + _super.prototype.removeSelfFromZr.call(this, zr); + + for (var i = 0; i < this._children.length; i++) { + this._children[i].__zr = null; + } + }; + + ZRText.prototype.getBoundingRect = function () { + if (this.styleChanged()) { + this._updateSubTexts(); + } + + if (!this._rect) { + var tmpRect = new BoundingRect(0, 0, 0, 0); + var children = this._children; + var tmpMat = []; + var rect = null; + + for (var i = 0; i < children.length; i++) { + var child = children[i]; + var childRect = child.getBoundingRect(); + var transform = child.getLocalTransform(tmpMat); + + if (transform) { + tmpRect.copy(childRect); + tmpRect.applyTransform(transform); + rect = rect || tmpRect.clone(); + rect.union(tmpRect); + } else { + rect = rect || childRect.clone(); + rect.union(childRect); + } + } + + this._rect = rect || tmpRect; + } + + return this._rect; + }; + + ZRText.prototype.setDefaultTextStyle = function (defaultTextStyle) { + this._defaultStyle = defaultTextStyle || DEFAULT_RICH_TEXT_COLOR; + }; + + ZRText.prototype.setTextContent = function (textContent) { + { + throw new Error('Can\'t attach text on another text'); + } + }; + + ZRText.prototype._mergeStyle = function (targetStyle, sourceStyle) { + if (!sourceStyle) { + return targetStyle; + } + + var sourceRich = sourceStyle.rich; + var targetRich = targetStyle.rich || sourceRich && {}; + extend(targetStyle, sourceStyle); + + if (sourceRich && targetRich) { + this._mergeRich(targetRich, sourceRich); + + targetStyle.rich = targetRich; + } else if (targetRich) { + targetStyle.rich = targetRich; + } + + return targetStyle; + }; + + ZRText.prototype._mergeRich = function (targetRich, sourceRich) { + var richNames = keys(sourceRich); + + for (var i = 0; i < richNames.length; i++) { + var richName = richNames[i]; + targetRich[richName] = targetRich[richName] || {}; + extend(targetRich[richName], sourceRich[richName]); + } + }; + + ZRText.prototype.getAnimationStyleProps = function () { + return DEFAULT_TEXT_ANIMATION_PROPS; + }; + + ZRText.prototype._getOrCreateChild = function (Ctor) { + var child = this._children[this._childCursor]; + + if (!child || !(child instanceof Ctor)) { + child = new Ctor(); + } + + this._children[this._childCursor++] = child; + child.__zr = this.__zr; + child.parent = this; + return child; + }; + + ZRText.prototype._updatePlainTexts = function () { + var style = this.style; + var textFont = style.font || DEFAULT_FONT; + var textPadding = style.padding; + var defaultStyle = this._defaultStyle; + var baseX = style.x || 0; + var baseY = style.y || 0; + var textAlign = style.align || defaultStyle.align || 'left'; + var verticalAlign = style.verticalAlign || defaultStyle.verticalAlign || 'top'; + calcInnerTextOverflowArea(tmpCITOverflowAreaOut, defaultStyle.overflowRect, baseX, baseY, textAlign, verticalAlign); + baseX = tmpCITOverflowAreaOut.baseX; + baseY = tmpCITOverflowAreaOut.baseY; + var text = getStyleText(style); + var contentBlock = parsePlainText(text, style, tmpCITOverflowAreaOut.outerWidth, tmpCITOverflowAreaOut.outerHeight); + var needDrawBg = needDrawBackground(style); + var bgColorDrawn = !!style.backgroundColor; + var outerHeight = contentBlock.outerHeight; + var outerWidth = contentBlock.outerWidth; + var textLines = contentBlock.lines; + var lineHeight = contentBlock.lineHeight; + this.isTruncated = !!contentBlock.isTruncated; + var textX = baseX; + var textY = adjustTextY(baseY, contentBlock.contentHeight, verticalAlign); + + if (needDrawBg || textPadding) { + var boxX = adjustTextX(baseX, outerWidth, textAlign); + var boxY = adjustTextY(baseY, outerHeight, verticalAlign); + needDrawBg && this._renderBackground(style, style, boxX, boxY, outerWidth, outerHeight); + } + + textY += lineHeight / 2; + + if (textPadding) { + textX = getTextXForPadding(baseX, textAlign, textPadding); + + if (verticalAlign === 'top') { + textY += textPadding[0]; + } else if (verticalAlign === 'bottom') { + textY -= textPadding[2]; + } + } + + var defaultLineWidth = 0; + var usingDefaultStroke = false; + var useDefaultFill = false; + var textFill = getFill('fill' in style ? style.fill : (useDefaultFill = true, defaultStyle.fill)); + var textStroke = getStroke('stroke' in style ? style.stroke : !bgColorDrawn && (!defaultStyle.autoStroke || useDefaultFill) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, usingDefaultStroke = true, defaultStyle.stroke) : null); + var hasShadow = style.textShadowBlur > 0; + + for (var i = 0; i < textLines.length; i++) { + var el = this._getOrCreateChild(TSpan); + + var subElStyle = el.createStyle(); + el.useStyle(subElStyle); + subElStyle.text = textLines[i]; + subElStyle.x = textX; + subElStyle.y = textY; + + if (textAlign) { + subElStyle.textAlign = textAlign; + } + + subElStyle.textBaseline = 'middle'; + subElStyle.opacity = style.opacity; + subElStyle.strokeFirst = true; + + if (hasShadow) { + subElStyle.shadowBlur = style.textShadowBlur || 0; + subElStyle.shadowColor = style.textShadowColor || 'transparent'; + subElStyle.shadowOffsetX = style.textShadowOffsetX || 0; + subElStyle.shadowOffsetY = style.textShadowOffsetY || 0; + } + + subElStyle.stroke = textStroke; + subElStyle.fill = textFill; + + if (textStroke) { + subElStyle.lineWidth = style.lineWidth || defaultLineWidth; + subElStyle.lineDash = style.lineDash; + subElStyle.lineDashOffset = style.lineDashOffset || 0; + } + + subElStyle.font = textFont; + setSeparateFont(subElStyle, style); + textY += lineHeight; + el.setBoundingRect(tSpanCreateBoundingRect2(subElStyle, contentBlock.contentWidth, contentBlock.calculatedLineHeight, usingDefaultStroke ? 0 : null)); + } + }; + + ZRText.prototype._updateRichTexts = function () { + var style = this.style; + var defaultStyle = this._defaultStyle; + var textAlign = style.align || defaultStyle.align; + var verticalAlign = style.verticalAlign || defaultStyle.verticalAlign; + var baseX = style.x || 0; + var baseY = style.y || 0; + calcInnerTextOverflowArea(tmpCITOverflowAreaOut, defaultStyle.overflowRect, baseX, baseY, textAlign, verticalAlign); + baseX = tmpCITOverflowAreaOut.baseX; + baseY = tmpCITOverflowAreaOut.baseY; + var text = getStyleText(style); + var contentBlock = parseRichText(text, style, tmpCITOverflowAreaOut.outerWidth, tmpCITOverflowAreaOut.outerHeight, textAlign); + var contentWidth = contentBlock.width; + var outerWidth = contentBlock.outerWidth; + var outerHeight = contentBlock.outerHeight; + var textPadding = style.padding; + this.isTruncated = !!contentBlock.isTruncated; + var boxX = adjustTextX(baseX, outerWidth, textAlign); + var boxY = adjustTextY(baseY, outerHeight, verticalAlign); + var xLeft = boxX; + var lineTop = boxY; + + if (textPadding) { + xLeft += textPadding[3]; + lineTop += textPadding[0]; + } + + var xRight = xLeft + contentWidth; + + if (needDrawBackground(style)) { + this._renderBackground(style, style, boxX, boxY, outerWidth, outerHeight); + } + + var bgColorDrawn = !!style.backgroundColor; + + for (var i = 0; i < contentBlock.lines.length; i++) { + var line = contentBlock.lines[i]; + var tokens = line.tokens; + var tokenCount = tokens.length; + var lineHeight = line.lineHeight; + var remainedWidth = line.width; + var leftIndex = 0; + var lineXLeft = xLeft; + var lineXRight = xRight; + var rightIndex = tokenCount - 1; + var token = void 0; + + while (leftIndex < tokenCount && (token = tokens[leftIndex], !token.align || token.align === 'left')) { + this._placeToken(token, style, lineHeight, lineTop, lineXLeft, 'left', bgColorDrawn); + + remainedWidth -= token.width; + lineXLeft += token.width; + leftIndex++; + } + + while (rightIndex >= 0 && (token = tokens[rightIndex], token.align === 'right')) { + this._placeToken(token, style, lineHeight, lineTop, lineXRight, 'right', bgColorDrawn); + + remainedWidth -= token.width; + lineXRight -= token.width; + rightIndex--; + } + + lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - remainedWidth) / 2; + + while (leftIndex <= rightIndex) { + token = tokens[leftIndex]; + + this._placeToken(token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center', bgColorDrawn); + + lineXLeft += token.width; + leftIndex++; + } + + lineTop += lineHeight; + } + }; + + ZRText.prototype._placeToken = function (token, style, lineHeight, lineTop, x, textAlign, parentBgColorDrawn) { + var tokenStyle = style.rich[token.styleName] || {}; + tokenStyle.text = token.text; + var verticalAlign = token.verticalAlign; + var y = lineTop + lineHeight / 2; + + if (verticalAlign === 'top') { + y = lineTop + token.height / 2; + } else if (verticalAlign === 'bottom') { + y = lineTop + lineHeight - token.height / 2; + } + + var needDrawBg = !token.isLineHolder && needDrawBackground(tokenStyle); + needDrawBg && this._renderBackground(tokenStyle, style, textAlign === 'right' ? x - token.width : textAlign === 'center' ? x - token.width / 2 : x, y - token.height / 2, token.width, token.height); + var bgColorDrawn = !!tokenStyle.backgroundColor; + var textPadding = token.textPadding; + + if (textPadding) { + x = getTextXForPadding(x, textAlign, textPadding); + y -= token.height / 2 - textPadding[0] - token.innerHeight / 2; + } + + var el = this._getOrCreateChild(TSpan); + + var subElStyle = el.createStyle(); + el.useStyle(subElStyle); + var defaultStyle = this._defaultStyle; + var useDefaultFill = false; + var defaultLineWidth = 0; + var usingDefaultStroke = false; + var textFill = getFill('fill' in tokenStyle ? tokenStyle.fill : 'fill' in style ? style.fill : (useDefaultFill = true, defaultStyle.fill)); + var textStroke = getStroke('stroke' in tokenStyle ? tokenStyle.stroke : 'stroke' in style ? style.stroke : !bgColorDrawn && !parentBgColorDrawn && (!defaultStyle.autoStroke || useDefaultFill) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, usingDefaultStroke = true, defaultStyle.stroke) : null); + var hasShadow = tokenStyle.textShadowBlur > 0 || style.textShadowBlur > 0; + subElStyle.text = token.text; + subElStyle.x = x; + subElStyle.y = y; + + if (hasShadow) { + subElStyle.shadowBlur = tokenStyle.textShadowBlur || style.textShadowBlur || 0; + subElStyle.shadowColor = tokenStyle.textShadowColor || style.textShadowColor || 'transparent'; + subElStyle.shadowOffsetX = tokenStyle.textShadowOffsetX || style.textShadowOffsetX || 0; + subElStyle.shadowOffsetY = tokenStyle.textShadowOffsetY || style.textShadowOffsetY || 0; + } + + subElStyle.textAlign = textAlign; + subElStyle.textBaseline = 'middle'; + subElStyle.font = token.font || DEFAULT_FONT; + subElStyle.opacity = retrieve3(tokenStyle.opacity, style.opacity, 1); + setSeparateFont(subElStyle, tokenStyle); + + if (textStroke) { + subElStyle.lineWidth = retrieve3(tokenStyle.lineWidth, style.lineWidth, defaultLineWidth); + subElStyle.lineDash = retrieve2(tokenStyle.lineDash, style.lineDash); + subElStyle.lineDashOffset = style.lineDashOffset || 0; + subElStyle.stroke = textStroke; + } + + if (textFill) { + subElStyle.fill = textFill; + } + + el.setBoundingRect(tSpanCreateBoundingRect2(subElStyle, token.contentWidth, token.contentHeight, usingDefaultStroke ? 0 : null)); + }; + + ZRText.prototype._renderBackground = function (style, topStyle, x, y, width, height) { + var textBackgroundColor = style.backgroundColor; + var textBorderWidth = style.borderWidth; + var textBorderColor = style.borderColor; + var isImageBg = textBackgroundColor && textBackgroundColor.image; + var isPlainOrGradientBg = textBackgroundColor && !isImageBg; + var textBorderRadius = style.borderRadius; + var self = this; + var rectEl; + var imgEl; + + if (isPlainOrGradientBg || style.lineHeight || textBorderWidth && textBorderColor) { + rectEl = this._getOrCreateChild(Rect); + rectEl.useStyle(rectEl.createStyle()); + rectEl.style.fill = null; + var rectShape = rectEl.shape; + rectShape.x = x; + rectShape.y = y; + rectShape.width = width; + rectShape.height = height; + rectShape.r = textBorderRadius; + rectEl.dirtyShape(); + } + + if (isPlainOrGradientBg) { + var rectStyle = rectEl.style; + rectStyle.fill = textBackgroundColor || null; + rectStyle.fillOpacity = retrieve2(style.fillOpacity, 1); + } else if (isImageBg) { + imgEl = this._getOrCreateChild(ZRImage); + + imgEl.onload = function () { + self.dirtyStyle(); + }; + + var imgStyle = imgEl.style; + imgStyle.image = textBackgroundColor.image; + imgStyle.x = x; + imgStyle.y = y; + imgStyle.width = width; + imgStyle.height = height; + } + + if (textBorderWidth && textBorderColor) { + var rectStyle = rectEl.style; + rectStyle.lineWidth = textBorderWidth; + rectStyle.stroke = textBorderColor; + rectStyle.strokeOpacity = retrieve2(style.strokeOpacity, 1); + rectStyle.lineDash = style.borderDash; + rectStyle.lineDashOffset = style.borderDashOffset || 0; + rectEl.strokeContainThreshold = 0; + + if (rectEl.hasFill() && rectEl.hasStroke()) { + rectStyle.strokeFirst = true; + rectStyle.lineWidth *= 2; + } + } + + var commonStyle = (rectEl || imgEl).style; + commonStyle.shadowBlur = style.shadowBlur || 0; + commonStyle.shadowColor = style.shadowColor || 'transparent'; + commonStyle.shadowOffsetX = style.shadowOffsetX || 0; + commonStyle.shadowOffsetY = style.shadowOffsetY || 0; + commonStyle.opacity = retrieve3(style.opacity, topStyle.opacity, 1); + }; + + ZRText.makeFont = function (style) { + var font = ''; + + if (hasSeparateFont(style)) { + font = [style.fontStyle, style.fontWeight, parseFontSize(style.fontSize), style.fontFamily || 'sans-serif'].join(' '); + } + + return font && trim(font) || style.textFont || style.font; + }; + + return ZRText; + }(Displayable); + + var VALID_TEXT_ALIGN = { + left: true, + right: 1, + center: 1 + }; + var VALID_TEXT_VERTICAL_ALIGN = { + top: 1, + bottom: 1, + middle: 1 + }; + var FONT_PARTS = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily']; + + function parseFontSize(fontSize) { + if (typeof fontSize === 'string' && (fontSize.indexOf('px') !== -1 || fontSize.indexOf('rem') !== -1 || fontSize.indexOf('em') !== -1)) { + return fontSize; + } else if (!isNaN(+fontSize)) { + return fontSize + 'px'; + } else { + return DEFAULT_FONT_SIZE + 'px'; + } + } + + function setSeparateFont(targetStyle, sourceStyle) { + for (var i = 0; i < FONT_PARTS.length; i++) { + var fontProp = FONT_PARTS[i]; + var val = sourceStyle[fontProp]; + + if (val != null) { + targetStyle[fontProp] = val; + } + } + } + + function hasSeparateFont(style) { + return style.fontSize != null || style.fontFamily || style.fontWeight; + } + + function normalizeTextStyle(style) { + normalizeStyle(style); + each$4(style.rich, normalizeStyle); + return style; + } + + function normalizeStyle(style) { + if (style) { + style.font = ZRText.makeFont(style); + var textAlign = style.align; + textAlign === 'middle' && (textAlign = 'center'); + style.align = textAlign == null || VALID_TEXT_ALIGN[textAlign] ? textAlign : 'left'; + var verticalAlign = style.verticalAlign; + verticalAlign === 'center' && (verticalAlign = 'middle'); + style.verticalAlign = verticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[verticalAlign] ? verticalAlign : 'top'; + var textPadding = style.padding; + + if (textPadding) { + style.padding = normalizeCssArray$1(style.padding); + } + } + } + + function getStroke(stroke, lineWidth) { + return stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none' ? null : stroke.image || stroke.colorStops ? '#000' : stroke; + } + + function getFill(fill) { + return fill == null || fill === 'none' ? null : fill.image || fill.colorStops ? '#000' : fill; + } + + function getTextXForPadding(x, textAlign, textPadding) { + return textAlign === 'right' ? x - textPadding[1] : textAlign === 'center' ? x + textPadding[3] / 2 - textPadding[1] / 2 : x + textPadding[3]; + } + + function getStyleText(style) { + var text = style.text; + text != null && (text += ''); + return text; + } + + function needDrawBackground(style) { + return !!(style.backgroundColor || style.lineHeight || style.borderWidth && style.borderColor); + } + + var getECData = makeInner(); + + var setCommonECData = function (seriesIndex, dataType, dataIdx, el) { + if (el) { + var ecData = getECData(el); // Add data index and series index for indexing the data by element + // Useful in tooltip + + ecData.dataIndex = dataIdx; + ecData.dataType = dataType; + ecData.seriesIndex = seriesIndex; + ecData.ssrType = 'chart'; // TODO: not store dataIndex on children. + + if (el.type === 'group') { + el.traverse(function (child) { + var childECData = getECData(child); + childECData.seriesIndex = seriesIndex; + childECData.dataIndex = dataIdx; + childECData.dataType = dataType; + childECData.ssrType = 'chart'; + }); + } + } + }; // Reserve 0 as default. + + + var _highlightNextDigit = 1; + var _highlightKeyMap = {}; + var getSavedStates = makeInner(); + var getComponentStates = makeInner(); + var HOVER_STATE_NORMAL = 0; + var HOVER_STATE_BLUR = 1; + var HOVER_STATE_EMPHASIS = 2; + var SPECIAL_STATES = ['emphasis', 'blur', 'select']; + var DISPLAY_STATES = ['normal', 'emphasis', 'blur', 'select']; + var Z2_EMPHASIS_LIFT = 10; + var Z2_SELECT_LIFT = 9; + var HIGHLIGHT_ACTION_TYPE = 'highlight'; + var DOWNPLAY_ACTION_TYPE = 'downplay'; + var SELECT_ACTION_TYPE = 'select'; + var UNSELECT_ACTION_TYPE = 'unselect'; + var TOGGLE_SELECT_ACTION_TYPE = 'toggleSelect'; + var SELECT_CHANGED_EVENT_TYPE = 'selectchanged'; + + function hasFillOrStroke(fillOrStroke) { + return fillOrStroke != null && fillOrStroke !== 'none'; + } + + function doChangeHoverState(el, stateName, hoverStateEnum) { + if (el.onHoverStateChange && (el.hoverState || 0) !== hoverStateEnum) { + el.onHoverStateChange(stateName); + } + + el.hoverState = hoverStateEnum; + } + + function singleEnterEmphasis(el) { + // Only mark the flag. + // States will be applied in the echarts.ts in next frame. + doChangeHoverState(el, 'emphasis', HOVER_STATE_EMPHASIS); + } + + function singleLeaveEmphasis(el) { + // Only mark the flag. + // States will be applied in the echarts.ts in next frame. + if (el.hoverState === HOVER_STATE_EMPHASIS) { + doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL); + } + } + + function singleEnterBlur(el) { + doChangeHoverState(el, 'blur', HOVER_STATE_BLUR); + } + + function singleLeaveBlur(el) { + if (el.hoverState === HOVER_STATE_BLUR) { + doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL); + } + } + + function singleEnterSelect(el) { + el.selected = true; + } + + function singleLeaveSelect(el) { + el.selected = false; + } + + function updateElementState(el, updater, commonParam) { + updater(el, commonParam); + } + + function traverseUpdateState(el, updater, commonParam) { + updateElementState(el, updater, commonParam); + el.isGroup && el.traverse(function (child) { + updateElementState(child, updater, commonParam); + }); + } + + function setStatesFlag(el, stateName) { + switch (stateName) { + case 'emphasis': + el.hoverState = HOVER_STATE_EMPHASIS; + break; + + case 'normal': + el.hoverState = HOVER_STATE_NORMAL; + break; + + case 'blur': + el.hoverState = HOVER_STATE_BLUR; + break; + + case 'select': + el.selected = true; + } + } + + function getFromStateStyle(el, props, toStateName, defaultValue) { + var style = el.style; + var fromState = {}; + + for (var i = 0; i < props.length; i++) { + var propName = props[i]; + var val = style[propName]; + fromState[propName] = val == null ? defaultValue && defaultValue[propName] : val; + } + + for (var i = 0; i < el.animators.length; i++) { + var animator = el.animators[i]; + + if (animator.__fromStateTransition // Don't consider the animation to emphasis state. + && animator.__fromStateTransition.indexOf(toStateName) < 0 && animator.targetName === 'style') { + animator.saveTo(fromState, props); + } + } + + return fromState; + } + + function createEmphasisDefaultState(el, stateName, targetStates, state) { + var hasSelect = targetStates && indexOf(targetStates, 'select') >= 0; + var cloned = false; + + if (el instanceof Path) { + var store = getSavedStates(el); + var fromFill = hasSelect ? store.selectFill || store.normalFill : store.normalFill; + var fromStroke = hasSelect ? store.selectStroke || store.normalStroke : store.normalStroke; + + if (hasFillOrStroke(fromFill) || hasFillOrStroke(fromStroke)) { + state = state || {}; + var emphasisStyle = state.style || {}; // inherit case + + if (emphasisStyle.fill === 'inherit') { + cloned = true; + state = extend({}, state); + emphasisStyle = extend({}, emphasisStyle); + emphasisStyle.fill = fromFill; + } // Apply default color lift + else if (!hasFillOrStroke(emphasisStyle.fill) && hasFillOrStroke(fromFill)) { + cloned = true; // Not modify the original value. + + state = extend({}, state); + emphasisStyle = extend({}, emphasisStyle); // Already being applied 'emphasis'. DON'T lift color multiple times. + + emphasisStyle.fill = liftColor(fromFill); + } // Not highlight stroke if fill has been highlighted. + else if (!hasFillOrStroke(emphasisStyle.stroke) && hasFillOrStroke(fromStroke)) { + if (!cloned) { + state = extend({}, state); + emphasisStyle = extend({}, emphasisStyle); + } + + emphasisStyle.stroke = liftColor(fromStroke); + } + + state.style = emphasisStyle; + } + } + + if (state) { + // TODO Share with textContent? + if (state.z2 == null) { + if (!cloned) { + state = extend({}, state); + } + + var z2EmphasisLift = el.z2EmphasisLift; + state.z2 = el.z2 + (z2EmphasisLift != null ? z2EmphasisLift : Z2_EMPHASIS_LIFT); + } + } + + return state; + } + + function createSelectDefaultState(el, stateName, state) { + // const hasSelect = indexOf(el.currentStates, stateName) >= 0; + if (state) { + // TODO Share with textContent? + if (state.z2 == null) { + state = extend({}, state); + var z2SelectLift = el.z2SelectLift; + state.z2 = el.z2 + (z2SelectLift != null ? z2SelectLift : Z2_SELECT_LIFT); + } + } + + return state; + } + + function createBlurDefaultState(el, stateName, state) { + var hasBlur = indexOf(el.currentStates, stateName) >= 0; + var currentOpacity = el.style.opacity; + var fromState = !hasBlur ? getFromStateStyle(el, ['opacity'], stateName, { + opacity: 1 + }) : null; + state = state || {}; + var blurStyle = state.style || {}; + + if (blurStyle.opacity == null) { + // clone state + state = extend({}, state); + blurStyle = extend({ + // Already being applied 'emphasis'. DON'T mul opacity multiple times. + opacity: hasBlur ? currentOpacity : fromState.opacity * 0.1 + }, blurStyle); + state.style = blurStyle; + } + + return state; + } + + function elementStateProxy(stateName, targetStates) { + var state = this.states[stateName]; + + if (this.style) { + if (stateName === 'emphasis') { + return createEmphasisDefaultState(this, stateName, targetStates, state); + } else if (stateName === 'blur') { + return createBlurDefaultState(this, stateName, state); + } else if (stateName === 'select') { + return createSelectDefaultState(this, stateName, state); + } + } + + return state; + } + /** + * Set hover style (namely "emphasis style") of element. + * @param el Should not be `zrender/graphic/Group`. + * @param focus 'self' | 'selfInSeries' | 'series' + */ + + + function setDefaultStateProxy(el) { + el.stateProxy = elementStateProxy; + var textContent = el.getTextContent(); + var textGuide = el.getTextGuideLine(); + + if (textContent) { + textContent.stateProxy = elementStateProxy; + } + + if (textGuide) { + textGuide.stateProxy = elementStateProxy; + } + } + + function enterEmphasisWhenMouseOver(el, e) { + !shouldSilent(el, e) // "emphasis" event highlight has higher priority than mouse highlight. + && !el.__highByOuter && traverseUpdateState(el, singleEnterEmphasis); + } + + function leaveEmphasisWhenMouseOut(el, e) { + !shouldSilent(el, e) // "emphasis" event highlight has higher priority than mouse highlight. + && !el.__highByOuter && traverseUpdateState(el, singleLeaveEmphasis); + } + + function enterEmphasis(el, highlightDigit) { + el.__highByOuter |= 1 << (highlightDigit || 0); + traverseUpdateState(el, singleEnterEmphasis); + } + + function leaveEmphasis(el, highlightDigit) { + !(el.__highByOuter &= ~(1 << (highlightDigit || 0))) && traverseUpdateState(el, singleLeaveEmphasis); + } + + function enterBlur(el) { + traverseUpdateState(el, singleEnterBlur); + } + + function leaveBlur(el) { + traverseUpdateState(el, singleLeaveBlur); + } + + function enterSelect(el) { + traverseUpdateState(el, singleEnterSelect); + } + + function leaveSelect(el) { + traverseUpdateState(el, singleLeaveSelect); + } + + function shouldSilent(el, e) { + return el.__highDownSilentOnTouch && e.zrByTouch; + } + + function allLeaveBlur(api) { + var model = api.getModel(); + var leaveBlurredSeries = []; + var allComponentViews = []; + model.eachComponent(function (componentType, componentModel) { + var componentStates = getComponentStates(componentModel); + var isSeries = componentType === 'series'; + var view = isSeries ? api.getViewOfSeriesModel(componentModel) : api.getViewOfComponentModel(componentModel); + !isSeries && allComponentViews.push(view); + + if (componentStates.isBlured) { + // Leave blur anyway + view.group.traverse(function (child) { + singleLeaveBlur(child); + }); + isSeries && leaveBlurredSeries.push(componentModel); + } + + componentStates.isBlured = false; + }); + each$4(allComponentViews, function (view) { + if (view && view.toggleBlurSeries) { + view.toggleBlurSeries(leaveBlurredSeries, false, model); + } + }); + } + + function blurSeries(targetSeriesIndex, focus, blurScope, api) { + var ecModel = api.getModel(); + blurScope = blurScope || 'coordinateSystem'; + + function leaveBlurOfIndices(data, dataIndices) { + for (var i = 0; i < dataIndices.length; i++) { + var itemEl = data.getItemGraphicEl(dataIndices[i]); + itemEl && leaveBlur(itemEl); + } + } + + if (targetSeriesIndex == null) { + return; + } + + if (!focus || focus === 'none') { + return; + } + + var targetSeriesModel = ecModel.getSeriesByIndex(targetSeriesIndex); + var targetCoordSys = targetSeriesModel.coordinateSystem; + + if (targetCoordSys && targetCoordSys.master) { + targetCoordSys = targetCoordSys.master; + } + + var blurredSeries = []; + ecModel.eachSeries(function (seriesModel) { + var sameSeries = targetSeriesModel === seriesModel; + var coordSys = seriesModel.coordinateSystem; + + if (coordSys && coordSys.master) { + coordSys = coordSys.master; + } + + var sameCoordSys = coordSys && targetCoordSys ? coordSys === targetCoordSys : sameSeries; // If there is no coordinate system. use sameSeries instead. + + if (!( // Not blur other series if blurScope series + blurScope === 'series' && !sameSeries // Not blur other coordinate system if blurScope is coordinateSystem + || blurScope === 'coordinateSystem' && !sameCoordSys // Not blur self series if focus is series. + || focus === 'series' && sameSeries // TODO blurScope: coordinate system + )) { + var view = api.getViewOfSeriesModel(seriesModel); + view.group.traverse(function (child) { + // For the elements that have been triggered by other components, + // and are still required to be highlighted, + // because the current is directly forced to blur the element, + // it will cause the focus self to be unable to highlight, so skip the blur of this element. + if (child.__highByOuter && sameSeries && focus === 'self') { + return; + } + + singleEnterBlur(child); + }); + + if (isArrayLike(focus)) { + leaveBlurOfIndices(seriesModel.getData(), focus); + } else if (isObject$2(focus)) { + var dataTypes = keys(focus); + + for (var d = 0; d < dataTypes.length; d++) { + leaveBlurOfIndices(seriesModel.getData(dataTypes[d]), focus[dataTypes[d]]); + } + } + + blurredSeries.push(seriesModel); + getComponentStates(seriesModel).isBlured = true; + } + }); + ecModel.eachComponent(function (componentType, componentModel) { + if (componentType === 'series') { + return; + } + + var view = api.getViewOfComponentModel(componentModel); + + if (view && view.toggleBlurSeries) { + view.toggleBlurSeries(blurredSeries, true, ecModel); + } + }); + } + + function blurComponent(componentMainType, componentIndex, api) { + if (componentMainType == null || componentIndex == null) { + return; + } + + var componentModel = api.getModel().getComponent(componentMainType, componentIndex); + + if (!componentModel) { + return; + } + + getComponentStates(componentModel).isBlured = true; + var view = api.getViewOfComponentModel(componentModel); + + if (!view || !view.focusBlurEnabled) { + return; + } + + view.group.traverse(function (child) { + singleEnterBlur(child); + }); + } + + function blurSeriesFromHighlightPayload(seriesModel, payload, api) { + var seriesIndex = seriesModel.seriesIndex; + var data = seriesModel.getData(payload.dataType); + + if (!data) { + { + error("Unknown dataType " + payload.dataType); + } + return; + } + + var dataIndex = queryDataIndex(data, payload); // Pick the first one if there is multiple/none exists. + + dataIndex = (isArray(dataIndex) ? dataIndex[0] : dataIndex) || 0; + var el = data.getItemGraphicEl(dataIndex); + + if (!el) { + var count = data.count(); + var current = 0; // If data on dataIndex is NaN. + + while (!el && current < count) { + el = data.getItemGraphicEl(current++); + } + } + + if (el) { + var ecData = getECData(el); + blurSeries(seriesIndex, ecData.focus, ecData.blurScope, api); + } else { + // If there is no element put on the data. Try getting it from raw option + // TODO Should put it on seriesModel? + var focus_1 = seriesModel.get(['emphasis', 'focus']); + var blurScope = seriesModel.get(['emphasis', 'blurScope']); + + if (focus_1 != null) { + blurSeries(seriesIndex, focus_1, blurScope, api); + } + } + } + + function findComponentHighDownDispatchers(componentMainType, componentIndex, name, api) { + var ret = { + focusSelf: false, + dispatchers: null + }; + + if (componentMainType == null || componentMainType === 'series' || componentIndex == null || name == null) { + return ret; + } + + var componentModel = api.getModel().getComponent(componentMainType, componentIndex); + + if (!componentModel) { + return ret; + } + + var view = api.getViewOfComponentModel(componentModel); + + if (!view || !view.findHighDownDispatchers) { + return ret; + } + + var dispatchers = view.findHighDownDispatchers(name); // At presnet, the component (like Geo) only blur inside itself. + // So we do not use `blurScope` in component. + + var focusSelf; + + for (var i = 0; i < dispatchers.length; i++) { + if (!isHighDownDispatcher(dispatchers[i])) { + error('param should be highDownDispatcher'); + } + + if (getECData(dispatchers[i]).focus === 'self') { + focusSelf = true; + break; + } + } + + return { + focusSelf: focusSelf, + dispatchers: dispatchers + }; + } + + function handleGlobalMouseOverForHighDown(dispatcher, e, api) { + if (!isHighDownDispatcher(dispatcher)) { + error('param should be highDownDispatcher'); + } + + var ecData = getECData(dispatcher); + + var _a = findComponentHighDownDispatchers(ecData.componentMainType, ecData.componentIndex, ecData.componentHighDownName, api), + dispatchers = _a.dispatchers, + focusSelf = _a.focusSelf; // If `findHighDownDispatchers` is supported on the component, + // highlight/downplay elements with the same name. + + + if (dispatchers) { + if (focusSelf) { + blurComponent(ecData.componentMainType, ecData.componentIndex, api); + } + + each$4(dispatchers, function (dispatcher) { + return enterEmphasisWhenMouseOver(dispatcher, e); + }); + } else { + // Try blur all in the related series. Then emphasis the hoverred. + // TODO. progressive mode. + blurSeries(ecData.seriesIndex, ecData.focus, ecData.blurScope, api); + + if (ecData.focus === 'self') { + blurComponent(ecData.componentMainType, ecData.componentIndex, api); + } // Other than series, component that not support `findHighDownDispatcher` will + // also use it. But in this case, highlight/downplay are only supported in + // mouse hover but not in dispatchAction. + + + enterEmphasisWhenMouseOver(dispatcher, e); + } + } + + function handleGlobalMouseOutForHighDown(dispatcher, e, api) { + if (!isHighDownDispatcher(dispatcher)) { + error('param should be highDownDispatcher'); + } + + allLeaveBlur(api); + var ecData = getECData(dispatcher); + var dispatchers = findComponentHighDownDispatchers(ecData.componentMainType, ecData.componentIndex, ecData.componentHighDownName, api).dispatchers; + + if (dispatchers) { + each$4(dispatchers, function (dispatcher) { + return leaveEmphasisWhenMouseOut(dispatcher, e); + }); + } else { + leaveEmphasisWhenMouseOut(dispatcher, e); + } + } + + function toggleSelectionFromPayload(seriesModel, payload, api) { + if (!isSelectChangePayload(payload)) { + return; + } + + var dataType = payload.dataType; + var data = seriesModel.getData(dataType); + var dataIndex = queryDataIndex(data, payload); + + if (!isArray(dataIndex)) { + dataIndex = [dataIndex]; + } + + seriesModel[payload.type === TOGGLE_SELECT_ACTION_TYPE ? 'toggleSelect' : payload.type === SELECT_ACTION_TYPE ? 'select' : 'unselect'](dataIndex, dataType); + } + + function updateSeriesElementSelection(seriesModel) { + var allData = seriesModel.getAllData(); + each$4(allData, function (_a) { + var data = _a.data, + type = _a.type; + data.eachItemGraphicEl(function (el, idx) { + seriesModel.isSelected(idx, type) ? enterSelect(el) : leaveSelect(el); + }); + }); + } + + function getAllSelectedIndices(ecModel) { + var ret = []; + ecModel.eachSeries(function (seriesModel) { + var allData = seriesModel.getAllData(); + each$4(allData, function (_a) { + _a.data; + var type = _a.type; + var dataIndices = seriesModel.getSelectedDataIndices(); + + if (dataIndices.length > 0) { + var item = { + dataIndex: dataIndices, + seriesIndex: seriesModel.seriesIndex + }; + + if (type != null) { + item.dataType = type; + } + + ret.push(item); + } + }); + }); + return ret; + } + /** + * Enable the function that mouseover will trigger the emphasis state. + * + * NOTE: + * This function should be used on the element with dataIndex, seriesIndex. + * + */ + + + function enableHoverEmphasis(el, focus, blurScope) { + setAsHighDownDispatcher(el, true); + traverseUpdateState(el, setDefaultStateProxy); + enableHoverFocus(el, focus, blurScope); + } + + function disableHoverEmphasis(el) { + setAsHighDownDispatcher(el, false); + } + + function toggleHoverEmphasis(el, focus, blurScope, isDisabled) { + isDisabled ? disableHoverEmphasis(el) : enableHoverEmphasis(el, focus, blurScope); + } + + function enableHoverFocus(el, focus, blurScope) { + var ecData = getECData(el); + + if (focus != null) { + // TODO dataIndex may be set after this function. This check is not useful. + // if (ecData.dataIndex == null) { + // if (__DEV__) { + // console.warn('focus can only been set on element with dataIndex'); + // } + // } + // else { + ecData.focus = focus; + ecData.blurScope = blurScope; // } + } else if (ecData.focus) { + ecData.focus = null; + } + } + + var OTHER_STATES = ['emphasis', 'blur', 'select']; + var defaultStyleGetterMap = { + itemStyle: 'getItemStyle', + lineStyle: 'getLineStyle', + areaStyle: 'getAreaStyle' + }; + /** + * Set emphasis/blur/selected states of element. + */ + + function setStatesStylesFromModel(el, itemModel, styleType, // default itemStyle + getter) { + styleType = styleType || 'itemStyle'; + + for (var i = 0; i < OTHER_STATES.length; i++) { + var stateName = OTHER_STATES[i]; + var model = itemModel.getModel([stateName, styleType]); + var state = el.ensureState(stateName); // Let it throw error if getterType is not found. + + state.style = getter ? getter(model) : model[defaultStyleGetterMap[styleType]](); + } + } + /** + * + * Set element as highlight / downplay dispatcher. + * It will be checked when element received mouseover event or from highlight action. + * It's in change of all highlight/downplay behavior of it's children. + * + * @param el + * @param el.highDownSilentOnTouch + * In touch device, mouseover event will be trigger on touchstart event + * (see module:zrender/dom/HandlerProxy). By this mechanism, we can + * conveniently use hoverStyle when tap on touch screen without additional + * code for compatibility. + * But if the chart/component has select feature, which usually also use + * hoverStyle, there might be conflict between 'select-highlight' and + * 'hover-highlight' especially when roam is enabled (see geo for example). + * In this case, `highDownSilentOnTouch` should be used to disable + * hover-highlight on touch device. + * @param asDispatcher If `false`, do not set as "highDownDispatcher". + */ + + + function setAsHighDownDispatcher(el, asDispatcher) { + var disable = asDispatcher === false; + var extendedEl = el; // Make `highDownSilentOnTouch` and `onStateChange` only work after + // `setAsHighDownDispatcher` called. Avoid it is modified by user unexpectedly. + + if (el.highDownSilentOnTouch) { + extendedEl.__highDownSilentOnTouch = el.highDownSilentOnTouch; + } // Simple optimize, since this method might be + // called for each elements of a group in some cases. + + + if (!disable || extendedEl.__highDownDispatcher) { + // Emphasis, normal can be triggered manually by API or other components like hover link. + // el[method]('emphasis', onElementEmphasisEvent)[method]('normal', onElementNormalEvent); + // Also keep previous record. + extendedEl.__highByOuter = extendedEl.__highByOuter || 0; + extendedEl.__highDownDispatcher = !disable; + } + } + + function isHighDownDispatcher(el) { + return !!(el && el.__highDownDispatcher); + } + /** + * Support highlight/downplay record on each elements. + * For the case: hover highlight/downplay (legend, visualMap, ...) and + * user triggered highlight/downplay should not conflict. + * Only all of the highlightDigit cleared, return to normal. + * @param {string} highlightKey + * @return {number} highlightDigit + */ + + + function getHighlightDigit(highlightKey) { + var highlightDigit = _highlightKeyMap[highlightKey]; + + if (highlightDigit == null && _highlightNextDigit <= 32) { + highlightDigit = _highlightKeyMap[highlightKey] = _highlightNextDigit++; + } + + return highlightDigit; + } + + function isSelectChangePayload(payload) { + var payloadType = payload.type; + return payloadType === SELECT_ACTION_TYPE || payloadType === UNSELECT_ACTION_TYPE || payloadType === TOGGLE_SELECT_ACTION_TYPE; + } + + function isHighDownPayload(payload) { + var payloadType = payload.type; + return payloadType === HIGHLIGHT_ACTION_TYPE || payloadType === DOWNPLAY_ACTION_TYPE; + } + + function savePathStates(el) { + var store = getSavedStates(el); + store.normalFill = el.style.fill; + store.normalStroke = el.style.stroke; + var selectState = el.states.select || {}; + store.selectFill = selectState.style && selectState.style.fill || null; + store.selectStroke = selectState.style && selectState.style.stroke || null; + } + + var CMD$1 = PathProxy.CMD; + var points = [[], [], []]; + var mathSqrt$2 = Math.sqrt; + var mathAtan2 = Math.atan2; + + function transformPath(path, m) { + if (!m) { + return; + } + + var data = path.data; + var len = path.len(); + var cmd; + var nPoint; + var i; + var j; + var k; + var p; + var M = CMD$1.M; + var C = CMD$1.C; + var L = CMD$1.L; + var R = CMD$1.R; + var A = CMD$1.A; + var Q = CMD$1.Q; + + for (i = 0, j = 0; i < len;) { + cmd = data[i++]; + j = i; + nPoint = 0; + + switch (cmd) { + case M: + nPoint = 1; + break; + + case L: + nPoint = 1; + break; + + case C: + nPoint = 3; + break; + + case Q: + nPoint = 2; + break; + + case A: + var x = m[4]; + var y = m[5]; + var sx = mathSqrt$2(m[0] * m[0] + m[1] * m[1]); + var sy = mathSqrt$2(m[2] * m[2] + m[3] * m[3]); + var angle = mathAtan2(-m[1] / sy, m[0] / sx); + data[i] *= sx; + data[i++] += x; + data[i] *= sy; + data[i++] += y; + data[i++] *= sx; + data[i++] *= sy; + data[i++] += angle; + data[i++] += angle; + i += 2; + j = i; + break; + + case R: + p[0] = data[i++]; + p[1] = data[i++]; + applyTransform$1(p, p, m); + data[j++] = p[0]; + data[j++] = p[1]; + p[0] += data[i++]; + p[1] += data[i++]; + applyTransform$1(p, p, m); + data[j++] = p[0]; + data[j++] = p[1]; + } + + for (k = 0; k < nPoint; k++) { + var p_1 = points[k]; + p_1[0] = data[i++]; + p_1[1] = data[i++]; + applyTransform$1(p_1, p_1, m); + data[j++] = p_1[0]; + data[j++] = p_1[1]; + } + } + + path.increaseVersion(); + } + + var mathSqrt$1 = Math.sqrt; + var mathSin$1 = Math.sin; + var mathCos$1 = Math.cos; + var PI$3 = Math.PI; + + function vMag(v) { + return Math.sqrt(v[0] * v[0] + v[1] * v[1]); + } + + function vRatio(u, v) { + return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v)); + } + + function vAngle(u, v) { + return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(vRatio(u, v)); + } + + function processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) { + var psi = psiDeg * (PI$3 / 180.0); + var xp = mathCos$1(psi) * (x1 - x2) / 2.0 + mathSin$1(psi) * (y1 - y2) / 2.0; + var yp = -1 * mathSin$1(psi) * (x1 - x2) / 2.0 + mathCos$1(psi) * (y1 - y2) / 2.0; + var lambda = xp * xp / (rx * rx) + yp * yp / (ry * ry); + + if (lambda > 1) { + rx *= mathSqrt$1(lambda); + ry *= mathSqrt$1(lambda); + } + + var f = (fa === fs ? -1 : 1) * mathSqrt$1((rx * rx * (ry * ry) - rx * rx * (yp * yp) - ry * ry * (xp * xp)) / (rx * rx * (yp * yp) + ry * ry * (xp * xp))) || 0; + var cxp = f * rx * yp / ry; + var cyp = f * -ry * xp / rx; + var cx = (x1 + x2) / 2.0 + mathCos$1(psi) * cxp - mathSin$1(psi) * cyp; + var cy = (y1 + y2) / 2.0 + mathSin$1(psi) * cxp + mathCos$1(psi) * cyp; + var theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]); + var u = [(xp - cxp) / rx, (yp - cyp) / ry]; + var v = [(-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry]; + var dTheta = vAngle(u, v); + + if (vRatio(u, v) <= -1) { + dTheta = PI$3; + } + + if (vRatio(u, v) >= 1) { + dTheta = 0; + } + + if (dTheta < 0) { + var n = Math.round(dTheta / PI$3 * 1e6) / 1e6; + dTheta = PI$3 * 2 + n % 2 * PI$3; + } + + path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs); + } + + var commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig; + var numberReg = /-?([0-9]*\.)?[0-9]+([eE]-?[0-9]+)?/g; + + function createPathProxyFromString(data) { + var path = new PathProxy(); + + if (!data) { + return path; + } + + var cpx = 0; + var cpy = 0; + var subpathX = cpx; + var subpathY = cpy; + var prevCmd; + var CMD = PathProxy.CMD; + var cmdList = data.match(commandReg); + + if (!cmdList) { + return path; + } + + for (var l = 0; l < cmdList.length; l++) { + var cmdText = cmdList[l]; + var cmdStr = cmdText.charAt(0); + var cmd = void 0; + var p = cmdText.match(numberReg) || []; + var pLen = p.length; + + for (var i = 0; i < pLen; i++) { + p[i] = parseFloat(p[i]); + } + + var off = 0; + + while (off < pLen) { + var ctlPtx = void 0; + var ctlPty = void 0; + var rx = void 0; + var ry = void 0; + var psi = void 0; + var fa = void 0; + var fs = void 0; + var x1 = cpx; + var y1 = cpy; + var len = void 0; + var pathData = void 0; + + switch (cmdStr) { + case 'l': + cpx += p[off++]; + cpy += p[off++]; + cmd = CMD.L; + path.addData(cmd, cpx, cpy); + break; + + case 'L': + cpx = p[off++]; + cpy = p[off++]; + cmd = CMD.L; + path.addData(cmd, cpx, cpy); + break; + + case 'm': + cpx += p[off++]; + cpy += p[off++]; + cmd = CMD.M; + path.addData(cmd, cpx, cpy); + subpathX = cpx; + subpathY = cpy; + cmdStr = 'l'; + break; + + case 'M': + cpx = p[off++]; + cpy = p[off++]; + cmd = CMD.M; + path.addData(cmd, cpx, cpy); + subpathX = cpx; + subpathY = cpy; + cmdStr = 'L'; + break; + + case 'h': + cpx += p[off++]; + cmd = CMD.L; + path.addData(cmd, cpx, cpy); + break; + + case 'H': + cpx = p[off++]; + cmd = CMD.L; + path.addData(cmd, cpx, cpy); + break; + + case 'v': + cpy += p[off++]; + cmd = CMD.L; + path.addData(cmd, cpx, cpy); + break; + + case 'V': + cpy = p[off++]; + cmd = CMD.L; + path.addData(cmd, cpx, cpy); + break; + + case 'C': + cmd = CMD.C; + path.addData(cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]); + cpx = p[off - 2]; + cpy = p[off - 1]; + break; + + case 'c': + cmd = CMD.C; + path.addData(cmd, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy); + cpx += p[off - 2]; + cpy += p[off - 1]; + break; + + case 'S': + ctlPtx = cpx; + ctlPty = cpy; + len = path.len(); + pathData = path.data; + + if (prevCmd === CMD.C) { + ctlPtx += cpx - pathData[len - 4]; + ctlPty += cpy - pathData[len - 3]; + } + + cmd = CMD.C; + x1 = p[off++]; + y1 = p[off++]; + cpx = p[off++]; + cpy = p[off++]; + path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy); + break; + + case 's': + ctlPtx = cpx; + ctlPty = cpy; + len = path.len(); + pathData = path.data; + + if (prevCmd === CMD.C) { + ctlPtx += cpx - pathData[len - 4]; + ctlPty += cpy - pathData[len - 3]; + } + + cmd = CMD.C; + x1 = cpx + p[off++]; + y1 = cpy + p[off++]; + cpx += p[off++]; + cpy += p[off++]; + path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy); + break; + + case 'Q': + x1 = p[off++]; + y1 = p[off++]; + cpx = p[off++]; + cpy = p[off++]; + cmd = CMD.Q; + path.addData(cmd, x1, y1, cpx, cpy); + break; + + case 'q': + x1 = p[off++] + cpx; + y1 = p[off++] + cpy; + cpx += p[off++]; + cpy += p[off++]; + cmd = CMD.Q; + path.addData(cmd, x1, y1, cpx, cpy); + break; + + case 'T': + ctlPtx = cpx; + ctlPty = cpy; + len = path.len(); + pathData = path.data; + + if (prevCmd === CMD.Q) { + ctlPtx += cpx - pathData[len - 4]; + ctlPty += cpy - pathData[len - 3]; + } + + cpx = p[off++]; + cpy = p[off++]; + cmd = CMD.Q; + path.addData(cmd, ctlPtx, ctlPty, cpx, cpy); + break; + + case 't': + ctlPtx = cpx; + ctlPty = cpy; + len = path.len(); + pathData = path.data; + + if (prevCmd === CMD.Q) { + ctlPtx += cpx - pathData[len - 4]; + ctlPty += cpy - pathData[len - 3]; + } + + cpx += p[off++]; + cpy += p[off++]; + cmd = CMD.Q; + path.addData(cmd, ctlPtx, ctlPty, cpx, cpy); + break; + + case 'A': + rx = p[off++]; + ry = p[off++]; + psi = p[off++]; + fa = p[off++]; + fs = p[off++]; + x1 = cpx, y1 = cpy; + cpx = p[off++]; + cpy = p[off++]; + cmd = CMD.A; + processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path); + break; + + case 'a': + rx = p[off++]; + ry = p[off++]; + psi = p[off++]; + fa = p[off++]; + fs = p[off++]; + x1 = cpx, y1 = cpy; + cpx += p[off++]; + cpy += p[off++]; + cmd = CMD.A; + processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path); + break; + } + } + + if (cmdStr === 'z' || cmdStr === 'Z') { + cmd = CMD.Z; + path.addData(cmd); + cpx = subpathX; + cpy = subpathY; + } + + prevCmd = cmd; + } + + path.toStatic(); + return path; + } + + var SVGPath = function (_super) { + __extends(SVGPath, _super); + + function SVGPath() { + return _super !== null && _super.apply(this, arguments) || this; + } + + SVGPath.prototype.applyTransform = function (m) {}; + + return SVGPath; + }(Path); + + function isPathProxy(path) { + return path.setData != null; + } + + function createPathOptions(str, opts) { + var pathProxy = createPathProxyFromString(str); + var innerOpts = extend({}, opts); + + innerOpts.buildPath = function (path) { + var beProxy = isPathProxy(path); + + if (beProxy && path.canSave()) { + path.appendPath(pathProxy); + var ctx = path.getContext(); + + if (ctx) { + path.rebuildPath(ctx, 1); + } + } else { + var ctx = beProxy ? path.getContext() : path; + + if (ctx) { + pathProxy.rebuildPath(ctx, 1); + } + } + }; + + innerOpts.applyTransform = function (m) { + transformPath(pathProxy, m); + this.dirtyShape(); + }; + + return innerOpts; + } + + function createFromString(str, opts) { + return new SVGPath(createPathOptions(str, opts)); + } + + function extendFromString(str, defaultOpts) { + var innerOpts = createPathOptions(str, defaultOpts); + + var Sub = function (_super) { + __extends(Sub, _super); + + function Sub(opts) { + var _this = _super.call(this, opts) || this; + + _this.applyTransform = innerOpts.applyTransform; + _this.buildPath = innerOpts.buildPath; + return _this; + } + + return Sub; + }(SVGPath); + + return Sub; + } + + function mergePath$1(pathEls, opts) { + var pathList = []; + var len = pathEls.length; + + for (var i = 0; i < len; i++) { + var pathEl = pathEls[i]; + pathList.push(pathEl.getUpdatedPathProxy(true)); + } + + var pathBundle = new Path(opts); + pathBundle.createPathProxy(); + + pathBundle.buildPath = function (path) { + if (isPathProxy(path)) { + path.appendPath(pathList); + var ctx = path.getContext(); + + if (ctx) { + path.rebuildPath(ctx, 1); + } + } + }; + + return pathBundle; + } + + var CircleShape = function () { + function CircleShape() { + this.cx = 0; + this.cy = 0; + this.r = 0; + } + + return CircleShape; + }(); + + var Circle = function (_super) { + __extends(Circle, _super); + + function Circle(opts) { + return _super.call(this, opts) || this; + } + + Circle.prototype.getDefaultShape = function () { + return new CircleShape(); + }; + + Circle.prototype.buildPath = function (ctx, shape) { + ctx.moveTo(shape.cx + shape.r, shape.cy); + ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2); + }; + + return Circle; + }(Path); + + Circle.prototype.type = 'circle'; + + var EllipseShape = function () { + function EllipseShape() { + this.cx = 0; + this.cy = 0; + this.rx = 0; + this.ry = 0; + } + + return EllipseShape; + }(); + + var Ellipse = function (_super) { + __extends(Ellipse, _super); + + function Ellipse(opts) { + return _super.call(this, opts) || this; + } + + Ellipse.prototype.getDefaultShape = function () { + return new EllipseShape(); + }; + + Ellipse.prototype.buildPath = function (ctx, shape) { + var k = 0.5522848; + var x = shape.cx; + var y = shape.cy; + var a = shape.rx; + var b = shape.ry; + var ox = a * k; + var oy = b * k; + ctx.moveTo(x - a, y); + ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b); + ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y); + ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b); + ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y); + ctx.closePath(); + }; + + return Ellipse; + }(Path); + + Ellipse.prototype.type = 'ellipse'; + var PI$2 = Math.PI; + var PI2$1 = PI$2 * 2; + var mathSin = Math.sin; + var mathCos = Math.cos; + var mathACos = Math.acos; + var mathATan2 = Math.atan2; + var mathAbs$1 = Math.abs; + var mathSqrt = Math.sqrt; + var mathMax$3 = Math.max; + var mathMin$3 = Math.min; + var e = 1e-4; + + function intersect(x0, y0, x1, y1, x2, y2, x3, y3) { + var dx10 = x1 - x0; + var dy10 = y1 - y0; + var dx32 = x3 - x2; + var dy32 = y3 - y2; + var t = dy32 * dx10 - dx32 * dy10; + + if (t * t < e) { + return; + } + + t = (dx32 * (y0 - y2) - dy32 * (x0 - x2)) / t; + return [x0 + t * dx10, y0 + t * dy10]; + } + + function computeCornerTangents(x0, y0, x1, y1, radius, cr, clockwise) { + var x01 = x0 - x1; + var y01 = y0 - y1; + var lo = (clockwise ? cr : -cr) / mathSqrt(x01 * x01 + y01 * y01); + var ox = lo * y01; + var oy = -lo * x01; + var x11 = x0 + ox; + var y11 = y0 + oy; + var x10 = x1 + ox; + var y10 = y1 + oy; + var x00 = (x11 + x10) / 2; + var y00 = (y11 + y10) / 2; + var dx = x10 - x11; + var dy = y10 - y11; + var d2 = dx * dx + dy * dy; + var r = radius - cr; + var s = x11 * y10 - x10 * y11; + var d = (dy < 0 ? -1 : 1) * mathSqrt(mathMax$3(0, r * r * d2 - s * s)); + var cx0 = (s * dy - dx * d) / d2; + var cy0 = (-s * dx - dy * d) / d2; + var cx1 = (s * dy + dx * d) / d2; + var cy1 = (-s * dx + dy * d) / d2; + var dx0 = cx0 - x00; + var dy0 = cy0 - y00; + var dx1 = cx1 - x00; + var dy1 = cy1 - y00; + + if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) { + cx0 = cx1; + cy0 = cy1; + } + + return { + cx: cx0, + cy: cy0, + x0: -ox, + y0: -oy, + x1: cx0 * (radius / r - 1), + y1: cy0 * (radius / r - 1) + }; + } + + function normalizeCornerRadius(cr) { + var arr; + + if (isArray(cr)) { + var len = cr.length; + + if (!len) { + return cr; + } + + if (len === 1) { + arr = [cr[0], cr[0], 0, 0]; + } else if (len === 2) { + arr = [cr[0], cr[0], cr[1], cr[1]]; + } else if (len === 3) { + arr = cr.concat(cr[2]); + } else { + arr = cr; + } + } else { + arr = [cr, cr, cr, cr]; + } + + return arr; + } + + function buildPath$1(ctx, shape) { + var _a; + + var radius = mathMax$3(shape.r, 0); + var innerRadius = mathMax$3(shape.r0 || 0, 0); + var hasRadius = radius > 0; + var hasInnerRadius = innerRadius > 0; + + if (!hasRadius && !hasInnerRadius) { + return; + } + + if (!hasRadius) { + radius = innerRadius; + innerRadius = 0; + } + + if (innerRadius > radius) { + var tmp = radius; + radius = innerRadius; + innerRadius = tmp; + } + + var startAngle = shape.startAngle, + endAngle = shape.endAngle; + + if (isNaN(startAngle) || isNaN(endAngle)) { + return; + } + + var cx = shape.cx, + cy = shape.cy; + var clockwise = !!shape.clockwise; + var arc = mathAbs$1(endAngle - startAngle); + var mod = arc > PI2$1 && arc % PI2$1; + mod > e && (arc = mod); + + if (!(radius > e)) { + ctx.moveTo(cx, cy); + } else if (arc > PI2$1 - e) { + ctx.moveTo(cx + radius * mathCos(startAngle), cy + radius * mathSin(startAngle)); + ctx.arc(cx, cy, radius, startAngle, endAngle, !clockwise); + + if (innerRadius > e) { + ctx.moveTo(cx + innerRadius * mathCos(endAngle), cy + innerRadius * mathSin(endAngle)); + ctx.arc(cx, cy, innerRadius, endAngle, startAngle, clockwise); + } + } else { + var icrStart = void 0; + var icrEnd = void 0; + var ocrStart = void 0; + var ocrEnd = void 0; + var ocrs = void 0; + var ocre = void 0; + var icrs = void 0; + var icre = void 0; + var ocrMax = void 0; + var icrMax = void 0; + var limitedOcrMax = void 0; + var limitedIcrMax = void 0; + var xre = void 0; + var yre = void 0; + var xirs = void 0; + var yirs = void 0; + var xrs = radius * mathCos(startAngle); + var yrs = radius * mathSin(startAngle); + var xire = innerRadius * mathCos(endAngle); + var yire = innerRadius * mathSin(endAngle); + var hasArc = arc > e; + + if (hasArc) { + var cornerRadius = shape.cornerRadius; + + if (cornerRadius) { + _a = normalizeCornerRadius(cornerRadius), icrStart = _a[0], icrEnd = _a[1], ocrStart = _a[2], ocrEnd = _a[3]; + } + + var halfRd = mathAbs$1(radius - innerRadius) / 2; + ocrs = mathMin$3(halfRd, ocrStart); + ocre = mathMin$3(halfRd, ocrEnd); + icrs = mathMin$3(halfRd, icrStart); + icre = mathMin$3(halfRd, icrEnd); + limitedOcrMax = ocrMax = mathMax$3(ocrs, ocre); + limitedIcrMax = icrMax = mathMax$3(icrs, icre); + + if (ocrMax > e || icrMax > e) { + xre = radius * mathCos(endAngle); + yre = radius * mathSin(endAngle); + xirs = innerRadius * mathCos(startAngle); + yirs = innerRadius * mathSin(startAngle); + + if (arc < PI$2) { + var it_1 = intersect(xrs, yrs, xirs, yirs, xre, yre, xire, yire); + + if (it_1) { + var x0 = xrs - it_1[0]; + var y0 = yrs - it_1[1]; + var x1 = xre - it_1[0]; + var y1 = yre - it_1[1]; + var a = 1 / mathSin(mathACos((x0 * x1 + y0 * y1) / (mathSqrt(x0 * x0 + y0 * y0) * mathSqrt(x1 * x1 + y1 * y1))) / 2); + var b = mathSqrt(it_1[0] * it_1[0] + it_1[1] * it_1[1]); + limitedOcrMax = mathMin$3(ocrMax, (radius - b) / (a + 1)); + limitedIcrMax = mathMin$3(icrMax, (innerRadius - b) / (a - 1)); + } + } + } + } + + if (!hasArc) { + ctx.moveTo(cx + xrs, cy + yrs); + } else if (limitedOcrMax > e) { + var crStart = mathMin$3(ocrStart, limitedOcrMax); + var crEnd = mathMin$3(ocrEnd, limitedOcrMax); + var ct0 = computeCornerTangents(xirs, yirs, xrs, yrs, radius, crStart, clockwise); + var ct1 = computeCornerTangents(xre, yre, xire, yire, radius, crEnd, clockwise); + ctx.moveTo(cx + ct0.cx + ct0.x0, cy + ct0.cy + ct0.y0); + + if (limitedOcrMax < ocrMax && crStart === crEnd) { + ctx.arc(cx + ct0.cx, cy + ct0.cy, limitedOcrMax, mathATan2(ct0.y0, ct0.x0), mathATan2(ct1.y0, ct1.x0), !clockwise); + } else { + crStart > 0 && ctx.arc(cx + ct0.cx, cy + ct0.cy, crStart, mathATan2(ct0.y0, ct0.x0), mathATan2(ct0.y1, ct0.x1), !clockwise); + ctx.arc(cx, cy, radius, mathATan2(ct0.cy + ct0.y1, ct0.cx + ct0.x1), mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1), !clockwise); + crEnd > 0 && ctx.arc(cx + ct1.cx, cy + ct1.cy, crEnd, mathATan2(ct1.y1, ct1.x1), mathATan2(ct1.y0, ct1.x0), !clockwise); + } + } else { + ctx.moveTo(cx + xrs, cy + yrs); + ctx.arc(cx, cy, radius, startAngle, endAngle, !clockwise); + } + + if (!(innerRadius > e) || !hasArc) { + ctx.lineTo(cx + xire, cy + yire); + } else if (limitedIcrMax > e) { + var crStart = mathMin$3(icrStart, limitedIcrMax); + var crEnd = mathMin$3(icrEnd, limitedIcrMax); + var ct0 = computeCornerTangents(xire, yire, xre, yre, innerRadius, -crEnd, clockwise); + var ct1 = computeCornerTangents(xrs, yrs, xirs, yirs, innerRadius, -crStart, clockwise); + ctx.lineTo(cx + ct0.cx + ct0.x0, cy + ct0.cy + ct0.y0); + + if (limitedIcrMax < icrMax && crStart === crEnd) { + ctx.arc(cx + ct0.cx, cy + ct0.cy, limitedIcrMax, mathATan2(ct0.y0, ct0.x0), mathATan2(ct1.y0, ct1.x0), !clockwise); + } else { + crEnd > 0 && ctx.arc(cx + ct0.cx, cy + ct0.cy, crEnd, mathATan2(ct0.y0, ct0.x0), mathATan2(ct0.y1, ct0.x1), !clockwise); + ctx.arc(cx, cy, innerRadius, mathATan2(ct0.cy + ct0.y1, ct0.cx + ct0.x1), mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1), clockwise); + crStart > 0 && ctx.arc(cx + ct1.cx, cy + ct1.cy, crStart, mathATan2(ct1.y1, ct1.x1), mathATan2(ct1.y0, ct1.x0), !clockwise); + } + } else { + ctx.lineTo(cx + xire, cy + yire); + ctx.arc(cx, cy, innerRadius, endAngle, startAngle, clockwise); + } + } + + ctx.closePath(); + } + + var SectorShape = function () { + function SectorShape() { + this.cx = 0; + this.cy = 0; + this.r0 = 0; + this.r = 0; + this.startAngle = 0; + this.endAngle = Math.PI * 2; + this.clockwise = true; + this.cornerRadius = 0; + } + + return SectorShape; + }(); + + var Sector = function (_super) { + __extends(Sector, _super); + + function Sector(opts) { + return _super.call(this, opts) || this; + } + + Sector.prototype.getDefaultShape = function () { + return new SectorShape(); + }; + + Sector.prototype.buildPath = function (ctx, shape) { + buildPath$1(ctx, shape); + }; + + Sector.prototype.isZeroArea = function () { + return this.shape.startAngle === this.shape.endAngle || this.shape.r === this.shape.r0; + }; + + return Sector; + }(Path); + + Sector.prototype.type = 'sector'; + + var RingShape = function () { + function RingShape() { + this.cx = 0; + this.cy = 0; + this.r = 0; + this.r0 = 0; + } + + return RingShape; + }(); + + var Ring = function (_super) { + __extends(Ring, _super); + + function Ring(opts) { + return _super.call(this, opts) || this; + } + + Ring.prototype.getDefaultShape = function () { + return new RingShape(); + }; + + Ring.prototype.buildPath = function (ctx, shape) { + var x = shape.cx; + var y = shape.cy; + var PI2 = Math.PI * 2; + ctx.moveTo(x + shape.r, y); + ctx.arc(x, y, shape.r, 0, PI2, false); + ctx.moveTo(x + shape.r0, y); + ctx.arc(x, y, shape.r0, 0, PI2, true); + }; + + return Ring; + }(Path); + + Ring.prototype.type = 'ring'; + + function smoothBezier(points, smooth, isLoop, constraint) { + var cps = []; + var v = []; + var v1 = []; + var v2 = []; + var prevPoint; + var nextPoint; + var min; + var max; + + if (constraint) { + min = [Infinity, Infinity]; + max = [-Infinity, -Infinity]; + + for (var i = 0, len = points.length; i < len; i++) { + min$1(min, min, points[i]); + max$1(max, max, points[i]); + } + + min$1(min, min, constraint[0]); + max$1(max, max, constraint[1]); + } + + for (var i = 0, len = points.length; i < len; i++) { + var point = points[i]; + + if (isLoop) { + prevPoint = points[i ? i - 1 : len - 1]; + nextPoint = points[(i + 1) % len]; + } else { + if (i === 0 || i === len - 1) { + cps.push(clone$2(points[i])); + continue; + } else { + prevPoint = points[i - 1]; + nextPoint = points[i + 1]; + } + } + + sub(v, nextPoint, prevPoint); + scale$2(v, v, smooth); + var d0 = distance(point, prevPoint); + var d1 = distance(point, nextPoint); + var sum = d0 + d1; + + if (sum !== 0) { + d0 /= sum; + d1 /= sum; + } + + scale$2(v1, v, -d0); + scale$2(v2, v, d1); + var cp0 = add([], point, v1); + var cp1 = add([], point, v2); + + if (constraint) { + max$1(cp0, cp0, min); + min$1(cp0, cp0, max); + max$1(cp1, cp1, min); + min$1(cp1, cp1, max); + } + + cps.push(cp0); + cps.push(cp1); + } + + if (isLoop) { + cps.push(cps.shift()); + } + + return cps; + } + + function buildPath(ctx, shape, closePath) { + var smooth = shape.smooth; + var points = shape.points; + + if (points && points.length >= 2) { + if (smooth) { + var controlPoints = smoothBezier(points, smooth, closePath, shape.smoothConstraint); + ctx.moveTo(points[0][0], points[0][1]); + var len = points.length; + + for (var i = 0; i < (closePath ? len : len - 1); i++) { + var cp1 = controlPoints[i * 2]; + var cp2 = controlPoints[i * 2 + 1]; + var p = points[(i + 1) % len]; + ctx.bezierCurveTo(cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]); + } + } else { + ctx.moveTo(points[0][0], points[0][1]); + + for (var i = 1, l = points.length; i < l; i++) { + ctx.lineTo(points[i][0], points[i][1]); + } + } + + closePath && ctx.closePath(); + } + } + + var PolygonShape = function () { + function PolygonShape() { + this.points = null; + this.smooth = 0; + this.smoothConstraint = null; + } + + return PolygonShape; + }(); + + var Polygon = function (_super) { + __extends(Polygon, _super); + + function Polygon(opts) { + return _super.call(this, opts) || this; + } + + Polygon.prototype.getDefaultShape = function () { + return new PolygonShape(); + }; + + Polygon.prototype.buildPath = function (ctx, shape) { + buildPath(ctx, shape, true); + }; + + return Polygon; + }(Path); + + Polygon.prototype.type = 'polygon'; + + var PolylineShape = function () { + function PolylineShape() { + this.points = null; + this.percent = 1; + this.smooth = 0; + this.smoothConstraint = null; + } + + return PolylineShape; + }(); + + var Polyline = function (_super) { + __extends(Polyline, _super); + + function Polyline(opts) { + return _super.call(this, opts) || this; + } + + Polyline.prototype.getDefaultStyle = function () { + return { + stroke: '#000', + fill: null + }; + }; + + Polyline.prototype.getDefaultShape = function () { + return new PolylineShape(); + }; + + Polyline.prototype.buildPath = function (ctx, shape) { + buildPath(ctx, shape, false); + }; + + return Polyline; + }(Path); + + Polyline.prototype.type = 'polyline'; + var subPixelOptimizeOutputShape = {}; + + var LineShape = function () { + function LineShape() { + this.x1 = 0; + this.y1 = 0; + this.x2 = 0; + this.y2 = 0; + this.percent = 1; + } + + return LineShape; + }(); + + var Line = function (_super) { + __extends(Line, _super); + + function Line(opts) { + return _super.call(this, opts) || this; + } + + Line.prototype.getDefaultStyle = function () { + return { + stroke: '#000', + fill: null + }; + }; + + Line.prototype.getDefaultShape = function () { + return new LineShape(); + }; + + Line.prototype.buildPath = function (ctx, shape) { + var x1; + var y1; + var x2; + var y2; + + if (this.subPixelOptimize) { + var optimizedShape = subPixelOptimizeLine$1(subPixelOptimizeOutputShape, shape, this.style); + x1 = optimizedShape.x1; + y1 = optimizedShape.y1; + x2 = optimizedShape.x2; + y2 = optimizedShape.y2; + } else { + x1 = shape.x1; + y1 = shape.y1; + x2 = shape.x2; + y2 = shape.y2; + } + + var percent = shape.percent; + + if (percent === 0) { + return; + } + + ctx.moveTo(x1, y1); + + if (percent < 1) { + x2 = x1 * (1 - percent) + x2 * percent; + y2 = y1 * (1 - percent) + y2 * percent; + } + + ctx.lineTo(x2, y2); + }; + + Line.prototype.pointAt = function (p) { + var shape = this.shape; + return [shape.x1 * (1 - p) + shape.x2 * p, shape.y1 * (1 - p) + shape.y2 * p]; + }; + + return Line; + }(Path); + + Line.prototype.type = 'line'; + var out = []; + + var BezierCurveShape = function () { + function BezierCurveShape() { + this.x1 = 0; + this.y1 = 0; + this.x2 = 0; + this.y2 = 0; + this.cpx1 = 0; + this.cpy1 = 0; + this.percent = 1; + } + + return BezierCurveShape; + }(); + + function someVectorAt(shape, t, isTangent) { + var cpx2 = shape.cpx2; + var cpy2 = shape.cpy2; + + if (cpx2 != null || cpy2 != null) { + return [(isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t), (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)]; + } else { + return [(isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t), (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)]; + } + } + + var BezierCurve = function (_super) { + __extends(BezierCurve, _super); + + function BezierCurve(opts) { + return _super.call(this, opts) || this; + } + + BezierCurve.prototype.getDefaultStyle = function () { + return { + stroke: '#000', + fill: null + }; + }; + + BezierCurve.prototype.getDefaultShape = function () { + return new BezierCurveShape(); + }; + + BezierCurve.prototype.buildPath = function (ctx, shape) { + var x1 = shape.x1; + var y1 = shape.y1; + var x2 = shape.x2; + var y2 = shape.y2; + var cpx1 = shape.cpx1; + var cpy1 = shape.cpy1; + var cpx2 = shape.cpx2; + var cpy2 = shape.cpy2; + var percent = shape.percent; + + if (percent === 0) { + return; + } + + ctx.moveTo(x1, y1); + + if (cpx2 == null || cpy2 == null) { + if (percent < 1) { + quadraticSubdivide(x1, cpx1, x2, percent, out); + cpx1 = out[1]; + x2 = out[2]; + quadraticSubdivide(y1, cpy1, y2, percent, out); + cpy1 = out[1]; + y2 = out[2]; + } + + ctx.quadraticCurveTo(cpx1, cpy1, x2, y2); + } else { + if (percent < 1) { + cubicSubdivide(x1, cpx1, cpx2, x2, percent, out); + cpx1 = out[1]; + cpx2 = out[2]; + x2 = out[3]; + cubicSubdivide(y1, cpy1, cpy2, y2, percent, out); + cpy1 = out[1]; + cpy2 = out[2]; + y2 = out[3]; + } + + ctx.bezierCurveTo(cpx1, cpy1, cpx2, cpy2, x2, y2); + } + }; + + BezierCurve.prototype.pointAt = function (t) { + return someVectorAt(this.shape, t, false); + }; + + BezierCurve.prototype.tangentAt = function (t) { + var p = someVectorAt(this.shape, t, true); + return normalize$1(p, p); + }; + + return BezierCurve; + }(Path); + + BezierCurve.prototype.type = 'bezier-curve'; + + var ArcShape = function () { + function ArcShape() { + this.cx = 0; + this.cy = 0; + this.r = 0; + this.startAngle = 0; + this.endAngle = Math.PI * 2; + this.clockwise = true; + } + + return ArcShape; + }(); + + var Arc = function (_super) { + __extends(Arc, _super); + + function Arc(opts) { + return _super.call(this, opts) || this; + } + + Arc.prototype.getDefaultStyle = function () { + return { + stroke: '#000', + fill: null + }; + }; + + Arc.prototype.getDefaultShape = function () { + return new ArcShape(); + }; + + Arc.prototype.buildPath = function (ctx, shape) { + var x = shape.cx; + var y = shape.cy; + var r = Math.max(shape.r, 0); + var startAngle = shape.startAngle; + var endAngle = shape.endAngle; + var clockwise = shape.clockwise; + var unitX = Math.cos(startAngle); + var unitY = Math.sin(startAngle); + ctx.moveTo(unitX * r + x, unitY * r + y); + ctx.arc(x, y, r, startAngle, endAngle, !clockwise); + }; + + return Arc; + }(Path); + + Arc.prototype.type = 'arc'; + + var CompoundPath = function (_super) { + __extends(CompoundPath, _super); + + function CompoundPath() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'compound'; + return _this; + } + + CompoundPath.prototype._updatePathDirty = function () { + var paths = this.shape.paths; + var dirtyPath = this.shapeChanged(); + + for (var i = 0; i < paths.length; i++) { + dirtyPath = dirtyPath || paths[i].shapeChanged(); + } + + if (dirtyPath) { + this.dirtyShape(); + } + }; + + CompoundPath.prototype.beforeBrush = function () { + this._updatePathDirty(); + + var paths = this.shape.paths || []; + var scale = this.getGlobalScale(); + + for (var i = 0; i < paths.length; i++) { + if (!paths[i].path) { + paths[i].createPathProxy(); + } + + paths[i].path.setScale(scale[0], scale[1], paths[i].segmentIgnoreThreshold); + } + }; + + CompoundPath.prototype.buildPath = function (ctx, shape) { + var paths = shape.paths || []; + + for (var i = 0; i < paths.length; i++) { + paths[i].buildPath(ctx, paths[i].shape, true); + } + }; + + CompoundPath.prototype.afterBrush = function () { + var paths = this.shape.paths || []; + + for (var i = 0; i < paths.length; i++) { + paths[i].pathUpdated(); + } + }; + + CompoundPath.prototype.getBoundingRect = function () { + this._updatePathDirty.call(this); + + return Path.prototype.getBoundingRect.call(this); + }; + + return CompoundPath; + }(Path); + + var Gradient = function () { + function Gradient(colorStops) { + this.colorStops = colorStops || []; + } + + Gradient.prototype.addColorStop = function (offset, color) { + this.colorStops.push({ + offset: offset, + color: color + }); + }; + + return Gradient; + }(); + + var LinearGradient = function (_super) { + __extends(LinearGradient, _super); + + function LinearGradient(x, y, x2, y2, colorStops, globalCoord) { + var _this = _super.call(this, colorStops) || this; + + _this.x = x == null ? 0 : x; + _this.y = y == null ? 0 : y; + _this.x2 = x2 == null ? 1 : x2; + _this.y2 = y2 == null ? 0 : y2; + _this.type = 'linear'; + _this.global = globalCoord || false; + return _this; + } + + return LinearGradient; + }(Gradient); + + var RadialGradient = function (_super) { + __extends(RadialGradient, _super); + + function RadialGradient(x, y, r, colorStops, globalCoord) { + var _this = _super.call(this, colorStops) || this; + + _this.x = x == null ? 0.5 : x; + _this.y = y == null ? 0.5 : y; + _this.r = r == null ? 0.5 : r; + _this.type = 'radial'; + _this.global = globalCoord || false; + return _this; + } + + return RadialGradient; + }(Gradient); + + var mathMin$2 = Math.min; + var mathMax$2 = Math.max; + var mathAbs = Math.abs; + var _extent = [0, 0]; + var _extent2 = [0, 0]; + + var _intersectCtx = createIntersectContext(); + + var _minTv = _intersectCtx.minTv; + var _maxTv = _intersectCtx.maxTv; + + var OrientedBoundingRect = function () { + function OrientedBoundingRect(rect, transform) { + this._corners = []; + this._axes = []; + this._origin = [0, 0]; + + for (var i = 0; i < 4; i++) { + this._corners[i] = new Point(); + } + + for (var i = 0; i < 2; i++) { + this._axes[i] = new Point(); + } + + if (rect) { + this.fromBoundingRect(rect, transform); + } + } + + OrientedBoundingRect.prototype.fromBoundingRect = function (rect, transform) { + var corners = this._corners; + var axes = this._axes; + var x = rect.x; + var y = rect.y; + var x2 = x + rect.width; + var y2 = y + rect.height; + corners[0].set(x, y); + corners[1].set(x2, y); + corners[2].set(x2, y2); + corners[3].set(x, y2); + + if (transform) { + for (var i = 0; i < 4; i++) { + corners[i].transform(transform); + } + } + + Point.sub(axes[0], corners[1], corners[0]); + Point.sub(axes[1], corners[3], corners[0]); + axes[0].normalize(); + axes[1].normalize(); + + for (var i = 0; i < 2; i++) { + this._origin[i] = axes[i].dot(corners[0]); + } + }; + + OrientedBoundingRect.prototype.intersect = function (other, mtv, opt) { + var overlapped = true; + var noMtv = !mtv; + + if (mtv) { + Point.set(mtv, 0, 0); + } + + _intersectCtx.reset(opt, !noMtv); + + if (!this._intersectCheckOneSide(this, other, noMtv, 1)) { + overlapped = false; + + if (noMtv) { + return overlapped; + } + } + + if (!this._intersectCheckOneSide(other, this, noMtv, -1)) { + overlapped = false; + + if (noMtv) { + return overlapped; + } + } + + if (!noMtv && !_intersectCtx.negativeSize) { + Point.copy(mtv, overlapped ? _intersectCtx.useDir ? _intersectCtx.dirMinTv : _minTv : _maxTv); + } + + return overlapped; + }; + + OrientedBoundingRect.prototype._intersectCheckOneSide = function (self, other, noMtv, inverse) { + var overlapped = true; + + for (var i = 0; i < 2; i++) { + var axis = self._axes[i]; + + self._getProjMinMaxOnAxis(i, self._corners, _extent); + + self._getProjMinMaxOnAxis(i, other._corners, _extent2); + + if (_intersectCtx.negativeSize || _extent[1] < _extent2[0] || _extent[0] > _extent2[1]) { + overlapped = false; + + if (_intersectCtx.negativeSize || noMtv) { + return overlapped; + } + + var dist0 = mathAbs(_extent2[0] - _extent[1]); + var dist1 = mathAbs(_extent[0] - _extent2[1]); + + if (mathMin$2(dist0, dist1) > _maxTv.len()) { + if (dist0 < dist1) { + Point.scale(_maxTv, axis, -dist0 * inverse); + } else { + Point.scale(_maxTv, axis, dist1 * inverse); + } + } + } else if (!noMtv) { + var dist0 = mathAbs(_extent2[0] - _extent[1]); + var dist1 = mathAbs(_extent[0] - _extent2[1]); + + if (_intersectCtx.useDir || mathMin$2(dist0, dist1) < _minTv.len()) { + if (dist0 < dist1 || !_intersectCtx.bidirectional) { + Point.scale(_minTv, axis, dist0 * inverse); + + if (_intersectCtx.useDir) { + _intersectCtx.calcDirMTV(); + } + } + + if (dist0 >= dist1 || !_intersectCtx.bidirectional) { + Point.scale(_minTv, axis, -dist1 * inverse); + + if (_intersectCtx.useDir) { + _intersectCtx.calcDirMTV(); + } + } + } + } + } + + return overlapped; + }; + + OrientedBoundingRect.prototype._getProjMinMaxOnAxis = function (dim, corners, out) { + var axis = this._axes[dim]; + var origin = this._origin; + var proj = corners[0].dot(axis) + origin[dim]; + var min = proj; + var max = proj; + + for (var i = 1; i < corners.length; i++) { + var proj_1 = corners[i].dot(axis) + origin[dim]; + min = mathMin$2(proj_1, min); + max = mathMax$2(proj_1, max); + } + + out[0] = min + _intersectCtx.touchThreshold; + out[1] = max - _intersectCtx.touchThreshold; + _intersectCtx.negativeSize = out[1] < out[0]; + }; + + return OrientedBoundingRect; + }(); + + var m = []; + + var IncrementalDisplayable = function (_super) { + __extends(IncrementalDisplayable, _super); + + function IncrementalDisplayable() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.notClear = true; + _this.incremental = true; + _this._displayables = []; + _this._temporaryDisplayables = []; + _this._cursor = 0; + return _this; + } + + IncrementalDisplayable.prototype.traverse = function (cb, context) { + cb.call(context, this); + }; + + IncrementalDisplayable.prototype.useStyle = function () { + this.style = {}; + }; + + IncrementalDisplayable.prototype.getCursor = function () { + return this._cursor; + }; + + IncrementalDisplayable.prototype.innerAfterBrush = function () { + this._cursor = this._displayables.length; + }; + + IncrementalDisplayable.prototype.clearDisplaybles = function () { + this._displayables = []; + this._temporaryDisplayables = []; + this._cursor = 0; + this.markRedraw(); + this.notClear = false; + }; + + IncrementalDisplayable.prototype.clearTemporalDisplayables = function () { + this._temporaryDisplayables = []; + }; + + IncrementalDisplayable.prototype.addDisplayable = function (displayable, notPersistent) { + if (notPersistent) { + this._temporaryDisplayables.push(displayable); + } else { + this._displayables.push(displayable); + } + + this.markRedraw(); + }; + + IncrementalDisplayable.prototype.addDisplayables = function (displayables, notPersistent) { + notPersistent = notPersistent || false; + + for (var i = 0; i < displayables.length; i++) { + this.addDisplayable(displayables[i], notPersistent); + } + }; + + IncrementalDisplayable.prototype.getDisplayables = function () { + return this._displayables; + }; + + IncrementalDisplayable.prototype.getTemporalDisplayables = function () { + return this._temporaryDisplayables; + }; + + IncrementalDisplayable.prototype.eachPendingDisplayable = function (cb) { + for (var i = this._cursor; i < this._displayables.length; i++) { + cb && cb(this._displayables[i]); + } + + for (var i = 0; i < this._temporaryDisplayables.length; i++) { + cb && cb(this._temporaryDisplayables[i]); + } + }; + + IncrementalDisplayable.prototype.update = function () { + this.updateTransform(); + + for (var i = this._cursor; i < this._displayables.length; i++) { + var displayable = this._displayables[i]; + displayable.parent = this; + displayable.update(); + displayable.parent = null; + } + + for (var i = 0; i < this._temporaryDisplayables.length; i++) { + var displayable = this._temporaryDisplayables[i]; + displayable.parent = this; + displayable.update(); + displayable.parent = null; + } + }; + + IncrementalDisplayable.prototype.getBoundingRect = function () { + if (!this._rect) { + var rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity); + + for (var i = 0; i < this._displayables.length; i++) { + var displayable = this._displayables[i]; + var childRect = displayable.getBoundingRect().clone(); + + if (displayable.needLocalTransform()) { + childRect.applyTransform(displayable.getLocalTransform(m)); + } + + rect.union(childRect); + } + + this._rect = rect; + } + + return this._rect; + }; + + IncrementalDisplayable.prototype.contain = function (x, y) { + var localPos = this.transformCoordToLocal(x, y); + var rect = this.getBoundingRect(); + + if (rect.contain(localPos[0], localPos[1])) { + for (var i = 0; i < this._displayables.length; i++) { + var displayable = this._displayables[i]; + + if (displayable.contain(x, y)) { + return true; + } + } + } + + return false; + }; + + return IncrementalDisplayable; + }(Displayable); // Stored properties for further transition. + + + var transitionStore = makeInner(); + /** + * Return null if animation is disabled. + */ + + function getAnimationConfig(animationType, animatableModel, dataIndex, // Extra opts can override the option in animatable model. + extraOpts, // TODO It's only for pictorial bar now. + extraDelayParams) { + var animationPayload; // Check if there is global animation configuration from dataZoom/resize can override the config in option. + // If animation is enabled. Will use this animation config in payload. + // If animation is disabled. Just ignore it. + + if (animatableModel && animatableModel.ecModel) { + var updatePayload = animatableModel.ecModel.getUpdatePayload(); + animationPayload = updatePayload && updatePayload.animation; + } + + var animationEnabled = animatableModel && animatableModel.isAnimationEnabled(); + var isUpdate = animationType === 'update'; + + if (animationEnabled) { + var duration = void 0; + var easing = void 0; + var delay = void 0; + + if (extraOpts) { + duration = retrieve2(extraOpts.duration, 200); + easing = retrieve2(extraOpts.easing, 'cubicOut'); + delay = 0; + } else { + duration = animatableModel.getShallow(isUpdate ? 'animationDurationUpdate' : 'animationDuration'); + easing = animatableModel.getShallow(isUpdate ? 'animationEasingUpdate' : 'animationEasing'); + delay = animatableModel.getShallow(isUpdate ? 'animationDelayUpdate' : 'animationDelay'); + } // animation from payload has highest priority. + + + if (animationPayload) { + animationPayload.duration != null && (duration = animationPayload.duration); + animationPayload.easing != null && (easing = animationPayload.easing); + animationPayload.delay != null && (delay = animationPayload.delay); + } + + if (isFunction(delay)) { + delay = delay(dataIndex, extraDelayParams); + } + + if (isFunction(duration)) { + duration = duration(dataIndex); + } + + var config = { + duration: duration || 0, + delay: delay, + easing: easing + }; + return config; + } else { + return null; + } + } + + function animateOrSetProps(animationType, el, props, animatableModel, dataIndex, cb, during) { + var isFrom = false; + var removeOpt; + + if (isFunction(dataIndex)) { + during = cb; + cb = dataIndex; + dataIndex = null; + } else if (isObject$2(dataIndex)) { + cb = dataIndex.cb; + during = dataIndex.during; + isFrom = dataIndex.isFrom; + removeOpt = dataIndex.removeOpt; + dataIndex = dataIndex.dataIndex; + } + + var isRemove = animationType === 'leave'; + + if (!isRemove) { + // Must stop the remove animation. + el.stopAnimation('leave'); + } + + var animationConfig = getAnimationConfig(animationType, animatableModel, dataIndex, isRemove ? removeOpt || {} : null, animatableModel && animatableModel.getAnimationDelayParams ? animatableModel.getAnimationDelayParams(el, dataIndex) : null); + + if (animationConfig && animationConfig.duration > 0) { + var duration = animationConfig.duration; + var animationDelay = animationConfig.delay; + var animationEasing = animationConfig.easing; + var animateConfig = { + duration: duration, + delay: animationDelay || 0, + easing: animationEasing, + done: cb, + force: !!cb || !!during, + // Set to final state in update/init animation. + // So the post processing based on the path shape can be done correctly. + setToFinal: !isRemove, + scope: animationType, + during: during + }; + isFrom ? el.animateFrom(props, animateConfig) : el.animateTo(props, animateConfig); + } else { + el.stopAnimation(); // If `isFrom`, the props is the "from" props. + + !isFrom && el.attr(props); // Call during at least once. + + during && during(1); + cb && cb(); + } + } + /** + * Update graphic element properties with or without animation according to the + * configuration in series. + * + * Caution: this method will stop previous animation. + * So do not use this method to one element twice before + * animation starts, unless you know what you are doing. + * @example + * graphic.updateProps(el, { + * position: [100, 100] + * }, seriesModel, dataIndex, function () { console.log('Animation done!'); }); + * // Or + * graphic.updateProps(el, { + * position: [100, 100] + * }, seriesModel, function () { console.log('Animation done!'); }); + */ + + + function updateProps$1(el, props, // TODO: TYPE AnimatableModel + animatableModel, dataIndex, cb, during) { + animateOrSetProps('update', el, props, animatableModel, dataIndex, cb, during); + } + /** + * Init graphic element properties with or without animation according to the + * configuration in series. + * + * Caution: this method will stop previous animation. + * So do not use this method to one element twice before + * animation starts, unless you know what you are doing. + */ + + + function initProps(el, props, animatableModel, dataIndex, cb, during) { + animateOrSetProps('enter', el, props, animatableModel, dataIndex, cb, during); + } + /** + * If element is removed. + * It can determine if element is having remove animation. + */ + + + function isElementRemoved(el) { + if (!el.__zr) { + return true; + } + + for (var i = 0; i < el.animators.length; i++) { + var animator = el.animators[i]; + + if (animator.scope === 'leave') { + return true; + } + } + + return false; + } + /** + * Remove graphic element + */ + + + function removeElement(el, props, animatableModel, dataIndex, cb, during) { + // Don't do remove animation twice. + if (isElementRemoved(el)) { + return; + } + + animateOrSetProps('leave', el, props, animatableModel, dataIndex, cb, during); + } + + function fadeOutDisplayable(el, animatableModel, dataIndex, done) { + el.removeTextContent(); + el.removeTextGuideLine(); + removeElement(el, { + style: { + opacity: 0 + } + }, animatableModel, dataIndex, done); + } + + function removeElementWithFadeOut(el, animatableModel, dataIndex) { + function doRemove() { + el.parent && el.parent.remove(el); + } // Hide label and labelLine first + // TODO Also use fade out animation? + + + if (!el.isGroup) { + fadeOutDisplayable(el, animatableModel, dataIndex, doRemove); + } else { + el.traverse(function (disp) { + if (!disp.isGroup) { + // Can invoke doRemove multiple times. + fadeOutDisplayable(disp, animatableModel, dataIndex, doRemove); + } + }); + } + } + /** + * Save old style for style transition in universalTransition module. + * It's used when element will be reused in each render. + * For chart like map, heatmap, which will always create new element. + * We don't need to save this because universalTransition can get old style from the old element + */ + + + function saveOldStyle(el) { + transitionStore(el).oldStyle = el.style; + } + + var _customShapeMap = {}; + var XY$1 = ['x', 'y']; + var WH$1 = ['width', 'height']; + /** + * Extend shape with parameters + */ + + function extendShape(opts) { + return Path.extend(opts); + } + + var extendPathFromString = extendFromString; + /** + * Extend path + */ + + function extendPath(pathData, opts) { + return extendPathFromString(pathData, opts); + } + /** + * Register a user defined shape. + * The shape class can be fetched by `getShapeClass` + * This method will overwrite the registered shapes, including + * the registered built-in shapes, if using the same `name`. + * The shape can be used in `custom series` and + * `graphic component` by declaring `{type: name}`. + * + * @param name + * @param ShapeClass Can be generated by `extendShape`. + */ + + + function registerShape(name, ShapeClass) { + _customShapeMap[name] = ShapeClass; + } + /** + * Find shape class registered by `registerShape`. Usually used in + * fetching user defined shape. + * + * [Caution]: + * (1) This method **MUST NOT be used inside echarts !!!**, unless it is prepared + * to use user registered shapes. + * Because the built-in shape (see `getBuiltInShape`) will be registered by + * `registerShape` by default. That enables users to get both built-in + * shapes as well as the shapes belonging to themsleves. But users can overwrite + * the built-in shapes by using names like 'circle', 'rect' via calling + * `registerShape`. So the echarts inner featrues should not fetch shapes from here + * in case that it is overwritten by users, except that some features, like + * `custom series`, `graphic component`, do it deliberately. + * + * (2) In the features like `custom series`, `graphic component`, the user input + * `{tpye: 'xxx'}` does not only specify shapes but also specify other graphic + * elements like `'group'`, `'text'`, `'image'` or event `'path'`. Those names + * are reserved names, that is, if some user registers a shape named `'image'`, + * the shape will not be used. If we intending to add some more reserved names + * in feature, that might bring break changes (disable some existing user shape + * names). But that case probably rarely happens. So we don't make more mechanism + * to resolve this issue here. + * + * @param name + * @return The shape class. If not found, return nothing. + */ + + + function getShapeClass(name) { + if (_customShapeMap.hasOwnProperty(name)) { + return _customShapeMap[name]; + } + } + /** + * Create a path element from path data string + * @param pathData + * @param opts + * @param rect + * @param layout 'center' or 'cover' default to be cover + */ + + + function makePath(pathData, opts, rect, layout) { + var path = createFromString(pathData, opts); + + if (rect) { + if (layout === 'center') { + rect = centerGraphic(rect, path.getBoundingRect()); + } + + resizePath(path, rect); + } + + return path; + } + /** + * Create a image element from image url + * @param imageUrl image url + * @param opts options + * @param rect constrain rect + * @param layout 'center' or 'cover'. Default to be 'cover' + */ + + + function makeImage(imageUrl, rect, layout) { + var zrImg = new ZRImage({ + style: { + image: imageUrl, + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height + }, + onload: function (img) { + if (layout === 'center') { + var boundingRect = { + width: img.width, + height: img.height + }; + zrImg.setStyle(centerGraphic(rect, boundingRect)); + } + } + }); + return zrImg; + } + /** + * Get position of centered element in bounding box. + * + * @param rect element local bounding box + * @param boundingRect constraint bounding box + * @return element position containing x, y, width, and height + */ + + + function centerGraphic(rect, boundingRect) { + // Set rect to center, keep width / height ratio. + var aspect = boundingRect.width / boundingRect.height; + var width = rect.height * aspect; + var height; + + if (width <= rect.width) { + height = rect.height; + } else { + width = rect.width; + height = width / aspect; + } + + var cx = rect.x + rect.width / 2; + var cy = rect.y + rect.height / 2; + return { + x: cx - width / 2, + y: cy - height / 2, + width: width, + height: height + }; + } + + var mergePath = mergePath$1; + /** + * Resize a path to fit the rect + * @param path + * @param rect + */ + + function resizePath(path, rect) { + if (!path.applyTransform) { + return; + } + + var pathRect = path.getBoundingRect(); + var m = pathRect.calculateTransform(rect); + path.applyTransform(m); + } + /** + * Sub pixel optimize line for canvas + */ + + + function subPixelOptimizeLine(shape, lineWidth) { + subPixelOptimizeLine$1(shape, shape, { + lineWidth: lineWidth + }); + return shape; + } + /** + * Sub pixel optimize rect for canvas + */ + + + function subPixelOptimizeRect(shape, style) { + subPixelOptimizeRect$1(shape, shape, style); + return shape; + } + /** + * Sub pixel optimize for canvas + * + * @param position Coordinate, such as x, y + * @param lineWidth Should be nonnegative integer. + * @param positiveOrNegative Default false (negative). + * @return Optimized position. + */ + + + var subPixelOptimize = subPixelOptimize$1; + /** + * Get transform matrix of target (param target), + * in coordinate of its ancestor (param ancestor) + * + * @param target + * @param [ancestor] + */ + + function getTransform(target, ancestor) { + var mat = identity([]); + + while (target && target !== ancestor) { + mul(mat, target.getLocalTransform(), mat); + target = target.parent; + } + + return mat; + } + /** + * Apply transform to an vertex. + * @param target [x, y] + * @param transform Can be: + * + Transform matrix: like [1, 0, 0, 1, 0, 0] + * + {position, rotation, scale}, the same as `zrender/Transformable`. + * @param invert Whether use invert matrix. + * @return [x, y] + */ + + + function applyTransform(target, transform, invert$1) { + if (transform && !isArrayLike(transform)) { + transform = Transformable.getLocalTransform(transform); + } + + if (invert$1) { + transform = invert([], transform); + } + + return applyTransform$1([], target, transform); + } + /** + * @param direction 'left' 'right' 'top' 'bottom' + * @param transform Transform matrix: like [1, 0, 0, 1, 0, 0] + * @param invert Whether use invert matrix. + * @return Transformed direction. 'left' 'right' 'top' 'bottom' + */ + + + function transformDirection(direction, transform, invert) { + // Pick a base, ensure that transform result will not be (0, 0). + var hBase = transform[4] === 0 || transform[5] === 0 || transform[0] === 0 ? 1 : mathAbs$3(2 * transform[4] / transform[0]); + var vBase = transform[4] === 0 || transform[5] === 0 || transform[2] === 0 ? 1 : mathAbs$3(2 * transform[4] / transform[2]); + var vertex = [direction === 'left' ? -hBase : direction === 'right' ? hBase : 0, direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0]; + vertex = applyTransform(vertex, transform, invert); + return mathAbs$3(vertex[0]) > mathAbs$3(vertex[1]) ? vertex[0] > 0 ? 'right' : 'left' : vertex[1] > 0 ? 'bottom' : 'top'; + } + + function isNotGroup(el) { + return !el.isGroup; + } + + function isPath(el) { + return el.shape != null; + } + /** + * Apply group transition animation from g1 to g2. + * If no animatableModel, no animation. + */ + + + function groupTransition(g1, g2, animatableModel) { + if (!g1 || !g2) { + return; + } + + function getElMap(g) { + var elMap = {}; + g.traverse(function (el) { + if (isNotGroup(el) && el.anid) { + elMap[el.anid] = el; + } + }); + return elMap; + } + + function getAnimatableProps(el) { + var obj = { + x: el.x, + y: el.y, + rotation: el.rotation + }; + + if (isPath(el)) { + obj.shape = clone$3(el.shape); + } + + return obj; + } + + var elMap1 = getElMap(g1); + g2.traverse(function (el) { + if (isNotGroup(el) && el.anid) { + var oldEl = elMap1[el.anid]; + + if (oldEl) { + var newProp = getAnimatableProps(el); + el.attr(getAnimatableProps(oldEl)); + updateProps$1(el, newProp, animatableModel, getECData(el).dataIndex); + } + } + }); + } + + function clipPointsByRect(points, rect) { + // FIXME: This way might be incorrect when graphic clipped by a corner + // and when element has a border. + return map$1(points, function (point) { + var x = point[0]; + x = mathMax$6(x, rect.x); + x = mathMin$6(x, rect.x + rect.width); + var y = point[1]; + y = mathMax$6(y, rect.y); + y = mathMin$6(y, rect.y + rect.height); + return [x, y]; + }); + } + /** + * Return a new clipped rect. If rect size are negative, return undefined. + */ + + + function clipRectByRect(targetRect, rect) { + var x = mathMax$6(targetRect.x, rect.x); + var x2 = mathMin$6(targetRect.x + targetRect.width, rect.x + rect.width); + var y = mathMax$6(targetRect.y, rect.y); + var y2 = mathMin$6(targetRect.y + targetRect.height, rect.y + rect.height); // If the total rect is cliped, nothing, including the border, + // should be painted. So return undefined. + + if (x2 >= x && y2 >= y) { + return { + x: x, + y: y, + width: x2 - x, + height: y2 - y + }; + } + } + + function createIcon(iconStr, // Support 'image://' or 'path://' or direct svg path. + opt, rect) { + var innerOpts = extend({ + rectHover: true + }, opt); + var style = innerOpts.style = { + strokeNoScale: true + }; + rect = rect || { + x: -1, + y: -1, + width: 2, + height: 2 + }; + + if (iconStr) { + return iconStr.indexOf('image://') === 0 ? (style.image = iconStr.slice(8), defaults(style, rect), new ZRImage(innerOpts)) : makePath(iconStr.replace('path://', ''), innerOpts, rect, 'center'); + } + } + /** + * Return `true` if the given line (line `a`) and the given polygon + * are intersect. + * Note that we do not count colinear as intersect here because no + * requirement for that. We could do that if required in future. + */ + + + function linePolygonIntersect(a1x, a1y, a2x, a2y, points) { + for (var i = 0, p2 = points[points.length - 1]; i < points.length; i++) { + var p = points[i]; + + if (lineLineIntersect(a1x, a1y, a2x, a2y, p[0], p[1], p2[0], p2[1])) { + return true; + } + + p2 = p; + } + } + /** + * Return `true` if the given two lines (line `a` and line `b`) + * are intersect. + * Note that we do not count colinear as intersect here because no + * requirement for that. We could do that if required in future. + */ + + + function lineLineIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) { + // let `vec_m` to be `vec_a2 - vec_a1` and `vec_n` to be `vec_b2 - vec_b1`. + var mx = a2x - a1x; + var my = a2y - a1y; + var nx = b2x - b1x; + var ny = b2y - b1y; // `vec_m` and `vec_n` are parallel iff + // existing `k` such that `vec_m = k · vec_n`, equivalent to `vec_m X vec_n = 0`. + + var nmCrossProduct = crossProduct2d(nx, ny, mx, my); + + if (nearZero(nmCrossProduct)) { + return false; + } // `vec_m` and `vec_n` are intersect iff + // existing `p` and `q` in [0, 1] such that `vec_a1 + p * vec_m = vec_b1 + q * vec_n`, + // such that `q = ((vec_a1 - vec_b1) X vec_m) / (vec_n X vec_m)` + // and `p = ((vec_a1 - vec_b1) X vec_n) / (vec_n X vec_m)`. + + + var b1a1x = a1x - b1x; + var b1a1y = a1y - b1y; + var q = crossProduct2d(b1a1x, b1a1y, mx, my) / nmCrossProduct; + + if (q < 0 || q > 1) { + return false; + } + + var p = crossProduct2d(b1a1x, b1a1y, nx, ny) / nmCrossProduct; + + if (p < 0 || p > 1) { + return false; + } + + return true; + } + /** + * Cross product of 2-dimension vector. + */ + + + function crossProduct2d(x1, y1, x2, y2) { + return x1 * y2 - x2 * y1; + } + + function nearZero(val) { + return val <= 1e-6 && val >= -1e-6; + } + /** + * NOTE: + * A negative-width/height rect (due to negative margins) is not supported; + * it will be clampped to zero width/height. + * Although negative-width/height rects can be defined reasonably following the + * similar sense in CSS, but they are rarely used, hard to understand and complicated. + * + * @param rect Assume its width/height >= 0 if existing. + * x/y/width/height is allowed to be NaN, + * for the case that only x/width or y/height is intended to be computed. + * @param delta + * If be `number[]`, should be `[top, right, bottom, left]`, + * which can be used in padding or margin case. + * @see `normalizeCssArray` in `util/format.ts` + * If be `number`, it means [delta, delta, delta, delta], + * which can be used in lineWidth (borderWith) case, + * [NOTICE]: commonly pass lineWidth / 2, following the convention that border is + * half inside half outside of the rect. + * @param shrinkOrExpand + * `true` - shrink if `delta[i]` is positive, commmonly used in `padding` case. + * `false` - expand if `delta[i]` is positive, commmonly used in `margin` case. (default) + * @param noNegative + * `true` - negative `delta[i]` will be clampped to 0. + * `false` - No clamp to `delta`. (default). + * @return The input `rect`. + */ + + + function expandOrShrinkRect(rect, delta, shrinkOrExpand, noNegative, minSize // by default [0, 0]. + ) { + if (delta == null) { + return rect; + } else if (isNumber(delta)) { + _tmpExpandRectDelta[0] = _tmpExpandRectDelta[1] = _tmpExpandRectDelta[2] = _tmpExpandRectDelta[3] = delta; + } else { + { + assert(delta.length === 4); + } + _tmpExpandRectDelta[0] = delta[0]; + _tmpExpandRectDelta[1] = delta[1]; + _tmpExpandRectDelta[2] = delta[2]; + _tmpExpandRectDelta[3] = delta[3]; + } + + if (noNegative) { + _tmpExpandRectDelta[0] = mathMax$6(0, _tmpExpandRectDelta[0]); + _tmpExpandRectDelta[1] = mathMax$6(0, _tmpExpandRectDelta[1]); + _tmpExpandRectDelta[2] = mathMax$6(0, _tmpExpandRectDelta[2]); + _tmpExpandRectDelta[3] = mathMax$6(0, _tmpExpandRectDelta[3]); + } + + if (shrinkOrExpand) { + _tmpExpandRectDelta[0] = -_tmpExpandRectDelta[0]; + _tmpExpandRectDelta[1] = -_tmpExpandRectDelta[1]; + _tmpExpandRectDelta[2] = -_tmpExpandRectDelta[2]; + _tmpExpandRectDelta[3] = -_tmpExpandRectDelta[3]; + } + + expandRectOnOneDimension(rect, _tmpExpandRectDelta, 'x', 'width', 3, 1, minSize && minSize[0] || 0); + expandRectOnOneDimension(rect, _tmpExpandRectDelta, 'y', 'height', 0, 2, minSize && minSize[1] || 0); + return rect; + } + + var _tmpExpandRectDelta = [0, 0, 0, 0]; + + function expandRectOnOneDimension(rect, delta, xy, wh, ltIdx, rbIdx, minSize) { + var deltaSum = delta[rbIdx] + delta[ltIdx]; + var oldSize = rect[wh]; + rect[wh] += deltaSum; + minSize = mathMax$6(0, mathMin$6(minSize, oldSize)); + + if (rect[wh] < minSize) { + rect[wh] = minSize; // Try to make the position of the zero rect reasonable in most visual cases. + + rect[xy] += delta[ltIdx] >= 0 ? -delta[ltIdx] : delta[rbIdx] >= 0 ? oldSize + delta[rbIdx] : mathAbs$3(deltaSum) > 1e-8 ? (oldSize - minSize) * delta[ltIdx] / deltaSum : 0; + } else { + rect[xy] -= delta[ltIdx]; + } + } + + function setTooltipConfig(opt) { + var itemTooltipOption = opt.itemTooltipOption; + var componentModel = opt.componentModel; + var itemName = opt.itemName; + var itemTooltipOptionObj = isString(itemTooltipOption) ? { + formatter: itemTooltipOption + } : itemTooltipOption; + var mainType = componentModel.mainType; + var componentIndex = componentModel.componentIndex; + var formatterParams = { + componentType: mainType, + name: itemName, + $vars: ['name'] + }; + formatterParams[mainType + 'Index'] = componentIndex; + var formatterParamsExtra = opt.formatterParamsExtra; + + if (formatterParamsExtra) { + each$4(keys(formatterParamsExtra), function (key) { + if (!hasOwn(formatterParams, key)) { + formatterParams[key] = formatterParamsExtra[key]; + formatterParams.$vars.push(key); + } + }); + } + + var ecData = getECData(opt.el); + ecData.componentMainType = mainType; + ecData.componentIndex = componentIndex; + ecData.tooltipConfig = { + name: itemName, + option: defaults({ + content: itemName, + encodeHTMLContent: true, + formatterParams: formatterParams + }, itemTooltipOptionObj) + }; + } + + function traverseElement(el, cb) { + var stopped; // TODO + // Polyfill for fixing zrender group traverse don't visit it's root issue. + + if (el.isGroup) { + stopped = cb(el); + } + + if (!stopped) { + el.traverse(cb); + } + } + + function traverseElements(els, cb) { + if (els) { + if (isArray(els)) { + for (var i = 0; i < els.length; i++) { + traverseElement(els[i], cb); + } + } else { + traverseElement(els, cb); + } + } + } + /** + * After a boundingRect applying a `transform`, whether to be still parallel screen X and Y. + */ + + + function isBoundingRectAxisAligned(transform) { + return !transform || mathAbs$3(transform[1]) < AXIS_ALIGN_EPSILON && mathAbs$3(transform[2]) < AXIS_ALIGN_EPSILON || mathAbs$3(transform[0]) < AXIS_ALIGN_EPSILON && mathAbs$3(transform[3]) < AXIS_ALIGN_EPSILON; + } + + var AXIS_ALIGN_EPSILON = 1e-5; + /** + * Create or copy to the existing bounding rect to avoid modifying `source`. + * + * @usage + * out.rect = ensureCopyRect(out.rect, sourceRect); + */ + + function ensureCopyRect(target, source) { + return target ? BoundingRect.copy(target, source) : source.clone(); + } + /** + * Create or copy to the existing transform to avoid modifying `source`. + * + * [CAUTION]: transform is `NullUndefined` if no transform, following convention of zrender, + * and enable to bypass some unnecessary calculation, since in most cases there is no transform. + * + * @usage + * out.transform = ensureCopyTransform(out.transform, sourceTransform); + */ + + + function ensureCopyTransform(target, source) { + return source ? copy(target || create(), source) : undefined; + } + + function retrieveZInfo(model) { + return { + z: model.get('z') || 0, + zlevel: model.get('zlevel') || 0 + }; + } + /** + * Assume all of the elements has the same `z` and `zlevel`. + */ + + + function calcZ2Range(el) { + var max = -Infinity; + var min = Infinity; + traverseElement(el, function (el) { + visitEl(el); + visitEl(el.getTextContent()); + visitEl(el.getTextGuideLine()); + }); + + function visitEl(el) { + if (!el || el.isGroup) { + return; + } + + var currentStates = el.currentStates; + + if (currentStates.length) { + for (var idx = 0; idx < currentStates.length; idx++) { + calcZ2(el.states[currentStates[idx]]); + } + } + + calcZ2(el); + } + + function calcZ2(entity) { + if (entity) { + var z2 = entity.z2; // Consider z2 may be NullUndefined + + if (z2 > max) { + max = z2; + } + + if (z2 < min) { + min = z2; + } + } + } + + if (min > max) { + min = max = 0; + } + + return { + min: min, + max: max + }; + } + + function traverseUpdateZ(el, z, zlevel) { + doUpdateZ(el, z, zlevel, -Infinity); + } + + function doUpdateZ(el, z, zlevel, // FIXME: Ideally all the labels should be above all the glyphs by default, + // e.g. in graph, edge labels should be above node elements. + // Currently impl does not guarantee that. + maxZ2) { + // `ignoreModelZ` is used to intentionally lift elements to cover other elements, + // where maxZ2 (for label.z2) should also not be counted for its parents. + if (el.ignoreModelZ) { + return maxZ2; + } // Group may also have textContent + + + var label = el.getTextContent(); + var labelLine = el.getTextGuideLine(); + var isGroup = el.isGroup; + + if (isGroup) { + // set z & zlevel of children elements of Group + var children = el.childrenRef(); + + for (var i = 0; i < children.length; i++) { + maxZ2 = mathMax$6(doUpdateZ(children[i], z, zlevel, maxZ2), maxZ2); + } + } else { + // not Group + el.z = z; + el.zlevel = zlevel; + maxZ2 = mathMax$6(el.z2 || 0, maxZ2); + } // always set z and zlevel if label/labelLine exists + + + if (label) { + label.z = z; + label.zlevel = zlevel; // lift z2 of text content + // TODO if el.emphasis.z2 is spcefied, what about textContent. + + isFinite(maxZ2) && (label.z2 = maxZ2 + 2); + } + + if (labelLine) { + var textGuideLineConfig = el.textGuideLineConfig; + labelLine.z = z; + labelLine.zlevel = zlevel; + isFinite(maxZ2) && (labelLine.z2 = maxZ2 + (textGuideLineConfig && textGuideLineConfig.showAbove ? 1 : -1)); + } + + return maxZ2; + } // Register built-in shapes. These shapes might be overwritten + // by users, although we do not recommend that. + + + registerShape('circle', Circle); + registerShape('ellipse', Ellipse); + registerShape('sector', Sector); + registerShape('ring', Ring); + registerShape('polygon', Polygon); + registerShape('polyline', Polyline); + registerShape('rect', Rect); + registerShape('line', Line); + registerShape('bezierCurve', BezierCurve); + registerShape('arc', Arc); + var graphic$1 = /*#__PURE__*/Object.freeze({ + __proto__: null, + Arc: Arc, + BezierCurve: BezierCurve, + BoundingRect: BoundingRect, + Circle: Circle, + CompoundPath: CompoundPath, + Ellipse: Ellipse, + Group: Group$2, + Image: ZRImage, + IncrementalDisplayable: IncrementalDisplayable, + Line: Line, + LinearGradient: LinearGradient, + OrientedBoundingRect: OrientedBoundingRect, + Path: Path, + Point: Point, + Polygon: Polygon, + Polyline: Polyline, + RadialGradient: RadialGradient, + Rect: Rect, + Ring: Ring, + Sector: Sector, + Text: ZRText, + WH: WH$1, + XY: XY$1, + applyTransform: applyTransform, + calcZ2Range: calcZ2Range, + clipPointsByRect: clipPointsByRect, + clipRectByRect: clipRectByRect, + createIcon: createIcon, + ensureCopyRect: ensureCopyRect, + ensureCopyTransform: ensureCopyTransform, + expandOrShrinkRect: expandOrShrinkRect, + extendPath: extendPath, + extendShape: extendShape, + getShapeClass: getShapeClass, + getTransform: getTransform, + groupTransition: groupTransition, + initProps: initProps, + isBoundingRectAxisAligned: isBoundingRectAxisAligned, + isElementRemoved: isElementRemoved, + lineLineIntersect: lineLineIntersect, + linePolygonIntersect: linePolygonIntersect, + makeImage: makeImage, + makePath: makePath, + mergePath: mergePath, + registerShape: registerShape, + removeElement: removeElement, + removeElementWithFadeOut: removeElementWithFadeOut, + resizePath: resizePath, + retrieveZInfo: retrieveZInfo, + setTooltipConfig: setTooltipConfig, + subPixelOptimize: subPixelOptimize, + subPixelOptimizeLine: subPixelOptimizeLine, + subPixelOptimizeRect: subPixelOptimizeRect, + transformDirection: transformDirection, + traverseElements: traverseElements, + traverseUpdateZ: traverseUpdateZ, + updateProps: updateProps$1 + }); + var EMPTY_OBJ = {}; + + function setLabelText(label, labelTexts) { + for (var i = 0; i < SPECIAL_STATES.length; i++) { + var stateName = SPECIAL_STATES[i]; + var text = labelTexts[stateName]; + var state = label.ensureState(stateName); + state.style = state.style || {}; + state.style.text = text; + } + + var oldStates = label.currentStates.slice(); + label.clearStates(true); + label.setStyle({ + text: labelTexts.normal + }); + label.useStates(oldStates, true); + } + + function getLabelText(opt, stateModels, interpolatedValue) { + var labelFetcher = opt.labelFetcher; + var labelDataIndex = opt.labelDataIndex; + var labelDimIndex = opt.labelDimIndex; + var normalModel = stateModels.normal; + var baseText; + + if (labelFetcher) { + baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex, normalModel && normalModel.get('formatter'), interpolatedValue != null ? { + interpolatedValue: interpolatedValue + } : null); + } + + if (baseText == null) { + baseText = isFunction(opt.defaultText) ? opt.defaultText(labelDataIndex, opt, interpolatedValue) : opt.defaultText; + } + + var statesText = { + normal: baseText + }; + + for (var i = 0; i < SPECIAL_STATES.length; i++) { + var stateName = SPECIAL_STATES[i]; + var stateModel = stateModels[stateName]; + statesText[stateName] = retrieve2(labelFetcher ? labelFetcher.getFormattedLabel(labelDataIndex, stateName, null, labelDimIndex, stateModel && stateModel.get('formatter')) : null, baseText); + } + + return statesText; + } + + function setLabelStyle(targetEl, labelStatesModels, opt, stateSpecified // TODO specified position? + ) { + opt = opt || EMPTY_OBJ; + var isSetOnText = targetEl instanceof ZRText; + var needsCreateText = false; + + for (var i = 0; i < DISPLAY_STATES.length; i++) { + var stateModel = labelStatesModels[DISPLAY_STATES[i]]; + + if (stateModel && stateModel.getShallow('show')) { + needsCreateText = true; + break; + } + } + + var textContent = isSetOnText ? targetEl : targetEl.getTextContent(); + + if (needsCreateText) { + if (!isSetOnText) { + // Reuse the previous + if (!textContent) { + textContent = new ZRText(); + targetEl.setTextContent(textContent); + } // Use same state proxy + + + if (targetEl.stateProxy) { + textContent.stateProxy = targetEl.stateProxy; + } + } + + var labelStatesTexts = getLabelText(opt, labelStatesModels); + var normalModel = labelStatesModels.normal; + var showNormal = !!normalModel.getShallow('show'); + var normalStyle = createTextStyle$1(normalModel, stateSpecified && stateSpecified.normal, opt, false, !isSetOnText); + normalStyle.text = labelStatesTexts.normal; + + if (!isSetOnText) { + // Always create new + targetEl.setTextConfig(createTextConfig(normalModel, opt, false)); + } + + for (var i = 0; i < SPECIAL_STATES.length; i++) { + var stateName = SPECIAL_STATES[i]; + var stateModel = labelStatesModels[stateName]; + + if (stateModel) { + var stateObj = textContent.ensureState(stateName); + var stateShow = !!retrieve2(stateModel.getShallow('show'), showNormal); + + if (stateShow !== showNormal) { + stateObj.ignore = !stateShow; + } + + stateObj.style = createTextStyle$1(stateModel, stateSpecified && stateSpecified[stateName], opt, true, !isSetOnText); + stateObj.style.text = labelStatesTexts[stateName]; + + if (!isSetOnText) { + var targetElEmphasisState = targetEl.ensureState(stateName); + targetElEmphasisState.textConfig = createTextConfig(stateModel, opt, true); + } + } + } // PENDING: if there is many requirements that emphasis position + // need to be different from normal position, we might consider + // auto silent is those cases. + + + textContent.silent = !!normalModel.getShallow('silent'); // Keep x and y + + if (textContent.style.x != null) { + normalStyle.x = textContent.style.x; + } + + if (textContent.style.y != null) { + normalStyle.y = textContent.style.y; + } + + textContent.ignore = !showNormal; // Always create new style. + + textContent.useStyle(normalStyle); + textContent.dirty(); + + if (opt.enableTextSetter) { + labelInner(textContent).setLabelText = function (interpolatedValue) { + var labelStatesTexts = getLabelText(opt, labelStatesModels, interpolatedValue); + setLabelText(textContent, labelStatesTexts); + }; + } + } else if (textContent) { + // Not display rich text. + textContent.ignore = true; + } + + targetEl.dirty(); + } + + function getLabelStatesModels(itemModel, labelName) { + labelName = labelName || 'label'; + var statesModels = { + normal: itemModel.getModel(labelName) + }; + + for (var i = 0; i < SPECIAL_STATES.length; i++) { + var stateName = SPECIAL_STATES[i]; + statesModels[stateName] = itemModel.getModel([stateName, labelName]); + } + + return statesModels; + } + /** + * Set basic textStyle properties. + */ + + + function createTextStyle$1(textStyleModel, specifiedTextStyle, // Fixed style in the code. Can't be set by model. + opt, isNotNormal, isAttached // If text is attached on an element. If so, auto color will handling in zrender. + ) { + var textStyle = {}; + setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached); + specifiedTextStyle && extend(textStyle, specifiedTextStyle); // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false); + + return textStyle; + } + + function createTextConfig(textStyleModel, opt, isNotNormal) { + opt = opt || {}; + var textConfig = {}; + var labelPosition; + var labelRotate = textStyleModel.getShallow('rotate'); + var labelDistance = retrieve2(textStyleModel.getShallow('distance'), isNotNormal ? null : 5); + var labelOffset = textStyleModel.getShallow('offset'); + labelPosition = textStyleModel.getShallow('position') || (isNotNormal ? null : 'inside'); // 'outside' is not a valid zr textPostion value, but used + // in bar series, and magic type should be considered. + + labelPosition === 'outside' && (labelPosition = opt.defaultOutsidePosition || 'top'); + + if (labelPosition != null) { + textConfig.position = labelPosition; + } + + if (labelOffset != null) { + textConfig.offset = labelOffset; + } + + if (labelRotate != null) { + labelRotate *= Math.PI / 180; + textConfig.rotation = labelRotate; + } + + if (labelDistance != null) { + textConfig.distance = labelDistance; + } // fill and auto is determined by the color of path fill if it's not specified by developers. + + + textConfig.outsideFill = textStyleModel.get('color') === 'inherit' ? opt.inheritColor || null : 'auto'; + + if (opt.autoOverflowArea != null) { + textConfig.autoOverflowArea = opt.autoOverflowArea; + } + + if (opt.layoutRect != null) { + textConfig.layoutRect = opt.layoutRect; + } + + return textConfig; + } + /** + * The uniform entry of set text style, that is, retrieve style definitions + * from `model` and set to `textStyle` object. + * + * Never in merge mode, but in overwrite mode, that is, all of the text style + * properties will be set. (Consider the states of normal and emphasis and + * default value can be adopted, merge would make the logic too complicated + * to manage.) + */ + + + function setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached) { + // Consider there will be abnormal when merge hover style to normal style if given default value. + opt = opt || EMPTY_OBJ; + var ecModel = textStyleModel.ecModel; + var globalTextStyle = ecModel && ecModel.option.textStyle; // Consider case: + // { + // data: [{ + // value: 12, + // label: { + // rich: { + // // no 'a' here but using parent 'a'. + // } + // } + // }], + // rich: { + // a: { ... } + // } + // } + + var richItemNames = getRichItemNames(textStyleModel); + var richResult; + + if (richItemNames) { + richResult = {}; + var richInheritPlainLabelOptionName = 'richInheritPlainLabel'; + var richInheritPlainLabel = retrieve2(textStyleModel.get(richInheritPlainLabelOptionName), ecModel ? ecModel.get(richInheritPlainLabelOptionName) : undefined); + + for (var name_1 in richItemNames) { + if (richItemNames.hasOwnProperty(name_1)) { + // Cascade is supported in rich. + var richTextStyle = textStyleModel.getModel(['rich', name_1]); // In rich, never `disableBox`. + // consider `label: {formatter: '{a|xx}', color: 'blue', rich: {a: {}}}`, + // the default color `'blue'` will not be adopted if no color declared in `rich`. + // That might confuses users. So probably we should put `textStyleModel` as the + // root ancestor of the `richTextStyle`. But that would be a break change. + // Since v6, the rich style inherits plain label by default + // but this behavior can be disabled by setting `richInheritPlainLabel` to `false`. + + setTokenTextStyle(richResult[name_1] = {}, richTextStyle, globalTextStyle, textStyleModel, richInheritPlainLabel, opt, isNotNormal, isAttached, false, true); + } + } + } + + if (richResult) { + textStyle.rich = richResult; + } + + var overflow = textStyleModel.get('overflow'); + + if (overflow) { + textStyle.overflow = overflow; + } + + var lineOverflow = textStyleModel.get('lineOverflow'); + + if (lineOverflow) { + textStyle.lineOverflow = lineOverflow; + } + + var labelTextStyle = textStyle; // `minMargin` has a higher precedence than `textMargin`, because `textMargin` is allowed + // to be set in `defaultOption`. + + var minMargin = textStyleModel.get('minMargin'); + + if (minMargin != null) { + // `minMargin` only support number value. + minMargin = !isNumber(minMargin) ? 0 : minMargin / 2; + labelTextStyle.margin = [minMargin, minMargin, minMargin, minMargin]; + labelTextStyle.__marginType = LabelMarginType.minMargin; + } else { + var textMargin = textStyleModel.get('textMargin'); + + if (textMargin != null) { + labelTextStyle.margin = normalizeCssArray$1(textMargin); + labelTextStyle.__marginType = LabelMarginType.textMargin; + } + } + + setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, null, null, opt, isNotNormal, isAttached, true, false); + } // Consider case: + // { + // data: [{ + // value: 12, + // label: { + // rich: { + // // no 'a' here but using parent 'a'. + // } + // } + // }], + // rich: { + // a: { ... } + // } + // } + // TODO TextStyleModel + + + function getRichItemNames(textStyleModel) { + // Use object to remove duplicated names. + var richItemNameMap; + + while (textStyleModel && textStyleModel !== textStyleModel.ecModel) { + var rich = (textStyleModel.option || EMPTY_OBJ).rich; + + if (rich) { + richItemNameMap = richItemNameMap || {}; + var richKeys = keys(rich); + + for (var i = 0; i < richKeys.length; i++) { + var richKey = richKeys[i]; + richItemNameMap[richKey] = 1; + } + } + + textStyleModel = textStyleModel.parentModel; + } + + return richItemNameMap; + } + + var TEXT_PROPS_WITH_GLOBAL = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY']; + var TEXT_PROPS_SELF = ['align', 'lineHeight', 'width', 'height', 'tag', 'verticalAlign', 'ellipsis']; + var TEXT_PROPS_BOX = ['padding', 'borderWidth', 'borderRadius', 'borderDashOffset', 'backgroundColor', 'borderColor', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY']; + + function setTokenTextStyle(textStyle, // FIXME: check/refactor for ellipsis handling of rich text. + textStyleModel, globalTextStyle, plainTextModel, richInheritPlainLabel, opt, isNotNormal, isAttached, isBlock, inRich) { + // In merge mode, default value should not be given. + globalTextStyle = !isNotNormal && globalTextStyle || EMPTY_OBJ; + var inheritColor = opt && opt.inheritColor; + var fillColor = textStyleModel.getShallow('color'); + var strokeColor = textStyleModel.getShallow('textBorderColor'); + var opacity = retrieve2(textStyleModel.getShallow('opacity'), globalTextStyle.opacity); + + if (fillColor === 'inherit' || fillColor === 'auto') { + { + if (fillColor === 'auto') { + deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\''); + } + } + + if (inheritColor) { + fillColor = inheritColor; + } else { + fillColor = null; + } + } + + if (strokeColor === 'inherit' || strokeColor === 'auto') { + { + if (strokeColor === 'auto') { + deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\''); + } + } + + if (inheritColor) { + strokeColor = inheritColor; + } else { + strokeColor = null; + } + } + + if (!isAttached) { + // Only use default global textStyle.color if text is individual. + // Otherwise it will use the strategy of attached text color because text may be on a path. + fillColor = fillColor || globalTextStyle.color; + strokeColor = strokeColor || globalTextStyle.textBorderColor; + } + + if (fillColor != null) { + // Might not be a string, e.g, it's a function in axisLabel case; but assume that it will + // be erased by a correct value outside. + textStyle.fill = fillColor; + } + + if (strokeColor != null) { + textStyle.stroke = strokeColor; + } + + var textBorderWidth = retrieve2(textStyleModel.getShallow('textBorderWidth'), globalTextStyle.textBorderWidth); + + if (textBorderWidth != null) { + textStyle.lineWidth = textBorderWidth; + } + + var textBorderType = retrieve2(textStyleModel.getShallow('textBorderType'), globalTextStyle.textBorderType); + + if (textBorderType != null) { + textStyle.lineDash = textBorderType; + } + + var textBorderDashOffset = retrieve2(textStyleModel.getShallow('textBorderDashOffset'), globalTextStyle.textBorderDashOffset); + + if (textBorderDashOffset != null) { + textStyle.lineDashOffset = textBorderDashOffset; + } + + if (!isNotNormal && opacity == null && !inRich) { + opacity = opt && opt.defaultOpacity; + } + + if (opacity != null) { + textStyle.opacity = opacity; + } // TODO + + + if (!isNotNormal && !isAttached) { + // Set default finally. + if (textStyle.fill == null && opt.inheritColor) { + textStyle.fill = opt.inheritColor; + } + } // Do not use `getFont` here, because merge should be supported, where + // part of these properties may be changed in emphasis style, and the + // others should remain their original value got from normal style. + + + for (var i = 0; i < TEXT_PROPS_WITH_GLOBAL.length; i++) { + var key = TEXT_PROPS_WITH_GLOBAL[i]; // props width, height, padding, margin, tag, backgroundColor, borderColor, + // borderWidth, borderRadius, shadowColor, shadowBlur, shadowOffsetX, shadowOffsetY + // may inappropriate to inherit from plainTextStyle. + // And if some props is specified in default options, users may have to reset them one by one. + // Therefore, we only allow these props to inherit from plainTextStyle. + // `richInheritPlainLabel` is switch for backward compatibility + + var val = richInheritPlainLabel !== false && plainTextModel ? retrieve3(textStyleModel.getShallow(key), plainTextModel.getShallow(key), globalTextStyle[key]) : retrieve2(textStyleModel.getShallow(key), globalTextStyle[key]); + + if (val != null) { + textStyle[key] = val; + } + } + + for (var i = 0; i < TEXT_PROPS_SELF.length; i++) { + var key = TEXT_PROPS_SELF[i]; + var val = textStyleModel.getShallow(key); + + if (val != null) { + textStyle[key] = val; + } + } + + if (textStyle.verticalAlign == null) { + var baseline = textStyleModel.getShallow('baseline'); + + if (baseline != null) { + textStyle.verticalAlign = baseline; + } + } + + if (!isBlock || !opt.disableBox) { + for (var i = 0; i < TEXT_PROPS_BOX.length; i++) { + var key = TEXT_PROPS_BOX[i]; + var val = textStyleModel.getShallow(key); + + if (val != null) { + textStyle[key] = val; + } + } + + var borderType = textStyleModel.getShallow('borderType'); + + if (borderType != null) { + textStyle.borderDash = borderType; + } + + if ((textStyle.backgroundColor === 'auto' || textStyle.backgroundColor === 'inherit') && inheritColor) { + { + if (textStyle.backgroundColor === 'auto') { + deprecateReplaceLog('backgroundColor: \'auto\'', 'backgroundColor: \'inherit\''); + } + } + textStyle.backgroundColor = inheritColor; + } + + if ((textStyle.borderColor === 'auto' || textStyle.borderColor === 'inherit') && inheritColor) { + { + if (textStyle.borderColor === 'auto') { + deprecateReplaceLog('borderColor: \'auto\'', 'borderColor: \'inherit\''); + } + } + textStyle.borderColor = inheritColor; + } + } + } + + function getFont(opt, ecModel) { + var gTextStyleModel = ecModel && ecModel.getModel('textStyle'); + return trim([// FIXME in node-canvas fontWeight is before fontStyle + opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '', opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '', (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px', opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'].join(' ')); + } + + var labelInner = makeInner(); + + function setLabelValueAnimation(label, labelStatesModels, value, getDefaultText) { + if (!label) { + return; + } + + var obj = labelInner(label); + obj.prevValue = obj.value; + obj.value = value; + var normalLabelModel = labelStatesModels.normal; + obj.valueAnimation = normalLabelModel.get('valueAnimation'); + + if (obj.valueAnimation) { + obj.precision = normalLabelModel.get('precision'); + obj.defaultInterpolatedText = getDefaultText; + obj.statesModels = labelStatesModels; + } + } + + function animateLabelValue(textEl, dataIndex, data, animatableModel, labelFetcher) { + var labelInnerStore = labelInner(textEl); + + if (!labelInnerStore.valueAnimation || labelInnerStore.prevValue === labelInnerStore.value) { + // Value not changed, no new label animation + return; + } + + var defaultInterpolatedText = labelInnerStore.defaultInterpolatedText; // Consider the case that being animating, do not use the `obj.value`, + // Otherwise it will jump to the `obj.value` when this new animation started. + + var currValue = retrieve2(labelInnerStore.interpolatedValue, labelInnerStore.prevValue); + var targetValue = labelInnerStore.value; + + function during(percent) { + var interpolated = interpolateRawValues(data, labelInnerStore.precision, currValue, targetValue, percent); + labelInnerStore.interpolatedValue = percent === 1 ? null : interpolated; + var labelText = getLabelText({ + labelDataIndex: dataIndex, + labelFetcher: labelFetcher, + defaultText: defaultInterpolatedText ? defaultInterpolatedText(interpolated) : interpolated + '' + }, labelInnerStore.statesModels, interpolated); + setLabelText(textEl, labelText); + } + + textEl.percent = 0; + (labelInnerStore.prevValue == null ? initProps : updateProps$1)(textEl, { + // percent is used to prevent animation from being aborted #15916 + percent: 1 + }, animatableModel, dataIndex, null, during); + } + /** + * PENDING: Temporary impl. unify them? + * @see {LabelCommonOption['textMargin']} + * @see {LabelCommonOption['minMargin']} + */ + + + var LabelMarginType = { + minMargin: 1, + textMargin: 2 + }; + var PATH_COLOR = ['textStyle', 'color']; + var textStyleParams = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'padding', 'lineHeight', 'rich', 'width', 'height', 'overflow']; // TODO Performance improvement? + + var tmpText = new ZRText(); + + var TextStyleMixin = + /** @class */ + function () { + function TextStyleMixin() {} + /** + * Get color property or get color from option.textStyle.color + */ + // TODO Callback + + + TextStyleMixin.prototype.getTextColor = function (isEmphasis) { + var ecModel = this.ecModel; + return this.getShallow('color') || (!isEmphasis && ecModel ? ecModel.get(PATH_COLOR) : null); + }; + /** + * Create font string from fontStyle, fontWeight, fontSize, fontFamily + * @return {string} + */ + + + TextStyleMixin.prototype.getFont = function () { + return getFont({ + fontStyle: this.getShallow('fontStyle'), + fontWeight: this.getShallow('fontWeight'), + fontSize: this.getShallow('fontSize'), + fontFamily: this.getShallow('fontFamily') + }, this.ecModel); + }; + + TextStyleMixin.prototype.getTextRect = function (text) { + var style = { + text: text, + verticalAlign: this.getShallow('verticalAlign') || this.getShallow('baseline') + }; + + for (var i = 0; i < textStyleParams.length; i++) { + style[textStyleParams[i]] = this.getShallow(textStyleParams[i]); + } + + tmpText.useStyle(style); + tmpText.update(); + return tmpText.getBoundingRect(); + }; + + return TextStyleMixin; + }(); + + var LINE_STYLE_KEY_MAP = [['lineWidth', 'width'], ['stroke', 'color'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'], ['lineDash', 'type'], ['lineDashOffset', 'dashOffset'], ['lineCap', 'cap'], ['lineJoin', 'join'], ['miterLimit'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`. + // So do not transfer decal directly. + ]; + var getLineStyle = makeStyleMapper(LINE_STYLE_KEY_MAP); + + var LineStyleMixin = + /** @class */ + function () { + function LineStyleMixin() {} + + LineStyleMixin.prototype.getLineStyle = function (excludes) { + return getLineStyle(this, excludes); + }; + + return LineStyleMixin; + }(); + + var ITEM_STYLE_KEY_MAP = [['fill', 'color'], ['stroke', 'borderColor'], ['lineWidth', 'borderWidth'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'], ['lineDash', 'borderType'], ['lineDashOffset', 'borderDashOffset'], ['lineCap', 'borderCap'], ['lineJoin', 'borderJoin'], ['miterLimit', 'borderMiterLimit'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`. + // So do not transfer decal directly. + ]; + var getItemStyle = makeStyleMapper(ITEM_STYLE_KEY_MAP); + + var ItemStyleMixin = + /** @class */ + function () { + function ItemStyleMixin() {} + + ItemStyleMixin.prototype.getItemStyle = function (excludes, includes) { + return getItemStyle(this, excludes, includes); + }; + + return ItemStyleMixin; + }(); + + var Model = + /** @class */ + function () { + function Model(option, parentModel, ecModel) { + this.parentModel = parentModel; + this.ecModel = ecModel; + this.option = option; // Simple optimization + // if (this.init) { + // if (arguments.length <= 4) { + // this.init(option, parentModel, ecModel, extraOpt); + // } + // else { + // this.init.apply(this, arguments); + // } + // } + } + + Model.prototype.init = function (option, parentModel, ecModel) {}; + /** + * Merge the input option to me. + */ + + + Model.prototype.mergeOption = function (option, ecModel) { + merge(this.option, option, true); + }; // `path` can be 'a.b.c', so the return value type have to be `ModelOption` + // TODO: TYPE strict key check? + // get(path: string | string[], ignoreParent?: boolean): ModelOption; + + + Model.prototype.get = function (path, ignoreParent) { + if (path == null) { + return this.option; + } + + return this._doGet(this.parsePath(path), !ignoreParent && this.parentModel); + }; + + Model.prototype.getShallow = function (key, ignoreParent) { + var option = this.option; + var val = option == null ? option : option[key]; + + if (val == null && !ignoreParent) { + var parentModel = this.parentModel; + + if (parentModel) { + // FIXME:TS do not know how to make it works + val = parentModel.getShallow(key); + } + } + + return val; + }; // `path` can be 'a.b.c', so the return value type have to be `Model` + // getModel(path: string | string[], parentModel?: Model): Model; + // TODO 'a.b.c' is deprecated + + + Model.prototype.getModel = function (path, parentModel) { + var hasPath = path != null; + var pathFinal = hasPath ? this.parsePath(path) : null; + var obj = hasPath ? this._doGet(pathFinal) : this.option; + parentModel = parentModel || this.parentModel && this.parentModel.getModel(this.resolveParentPath(pathFinal)); + return new Model(obj, parentModel, this.ecModel); + }; + /** + * If model has option + */ + + + Model.prototype.isEmpty = function () { + return this.option == null; + }; + + Model.prototype.restoreData = function () {}; // Pending + + + Model.prototype.clone = function () { + var Ctor = this.constructor; + return new Ctor(clone$3(this.option)); + }; // setReadOnly(properties): void { + // clazzUtil.setReadOnly(this, properties); + // } + // If path is null/undefined, return null/undefined. + + + Model.prototype.parsePath = function (path) { + if (typeof path === 'string') { + return path.split('.'); + } + + return path; + }; // Resolve path for parent. Perhaps useful when parent use a different property. + // Default to be a identity resolver. + // Can be modified to a different resolver. + + + Model.prototype.resolveParentPath = function (path) { + return path; + }; // FIXME:TS check whether put this method here + + + Model.prototype.isAnimationEnabled = function () { + if (!env.node && this.option) { + if (this.option.animation != null) { + return !!this.option.animation; + } else if (this.parentModel) { + return this.parentModel.isAnimationEnabled(); + } + } + }; + + Model.prototype._doGet = function (pathArr, parentModel) { + var obj = this.option; + + if (!pathArr) { + return obj; + } + + for (var i = 0; i < pathArr.length; i++) { + // Ignore empty + if (!pathArr[i]) { + continue; + } // obj could be number/string/... (like 0) + + + obj = obj && typeof obj === 'object' ? obj[pathArr[i]] : null; + + if (obj == null) { + break; + } + } + + if (obj == null && parentModel) { + obj = parentModel._doGet(this.resolveParentPath(pathArr), parentModel.parentModel); + } + + return obj; + }; + + return Model; + }(); // Enable Model.extend. + + + enableClassExtend(Model); + enableClassCheck(Model); + mixin(Model, LineStyleMixin); + mixin(Model, ItemStyleMixin); + mixin(Model, AreaStyleMixin); + mixin(Model, TextStyleMixin); // A random offset + + var base = Math.round(Math.random() * 10); + /** + * @public + * @param {string} type + * @return {string} + */ + + function getUID(type) { + // Considering the case of crossing js context, + // use Math.random to make id as unique as possible. + return [type || '', base++].join('_'); + } + /** + * Implements `SubTypeDefaulterManager` for `target`. + */ + + + function enableSubTypeDefaulter(target) { + var subTypeDefaulters = {}; + + target.registerSubTypeDefaulter = function (componentType, defaulter) { + var componentTypeInfo = parseClassType(componentType); + subTypeDefaulters[componentTypeInfo.main] = defaulter; + }; + + target.determineSubType = function (componentType, option) { + var type = option.type; + + if (!type) { + var componentTypeMain = parseClassType(componentType).main; + + if (target.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) { + type = subTypeDefaulters[componentTypeMain](option); + } + } + + return type; + }; + } + /** + * Implements `TopologicalTravelable` for `entity`. + * + * Topological travel on Activity Network (Activity On Vertices). + * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis']. + * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology. + * If there is circular dependencey, Error will be thrown. + */ + + + function enableTopologicalTravel(entity, dependencyGetter) { + /** + * @param targetNameList Target Component type list. + * Can be ['aa', 'bb', 'aa.xx'] + * @param fullNameList By which we can build dependency graph. + * @param callback Params: componentType, dependencies. + * @param context Scope of callback. + */ + entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) { + if (!targetNameList.length) { + return; + } + + var result = makeDepndencyGraph(fullNameList); + var graph = result.graph; + var noEntryList = result.noEntryList; + var targetNameSet = {}; + each$4(targetNameList, function (name) { + targetNameSet[name] = true; + }); + + while (noEntryList.length) { + var currComponentType = noEntryList.pop(); + var currVertex = graph[currComponentType]; + var isInTargetNameSet = !!targetNameSet[currComponentType]; + + if (isInTargetNameSet) { + callback.call(context, currComponentType, currVertex.originalDeps.slice()); + delete targetNameSet[currComponentType]; + } + + each$4(currVertex.successor, isInTargetNameSet ? removeEdgeAndAdd : removeEdge); + } + + each$4(targetNameSet, function () { + var errMsg = ''; + { + errMsg = makePrintable('Circular dependency may exists: ', targetNameSet, targetNameList, fullNameList); + } + throw new Error(errMsg); + }); + + function removeEdge(succComponentType) { + graph[succComponentType].entryCount--; + + if (graph[succComponentType].entryCount === 0) { + noEntryList.push(succComponentType); + } + } // Consider this case: legend depends on series, and we call + // chart.setOption({series: [...]}), where only series is in option. + // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will + // not be called, but only sereis.mergeOption is called. Thus legend + // have no chance to update its local record about series (like which + // name of series is available in legend). + + + function removeEdgeAndAdd(succComponentType) { + targetNameSet[succComponentType] = true; + removeEdge(succComponentType); + } + }; + + function makeDepndencyGraph(fullNameList) { + var graph = {}; + var noEntryList = []; + each$4(fullNameList, function (name) { + var thisItem = createDependencyGraphItem(graph, name); + var originalDeps = thisItem.originalDeps = dependencyGetter(name); + var availableDeps = getAvailableDependencies(originalDeps, fullNameList); + thisItem.entryCount = availableDeps.length; + + if (thisItem.entryCount === 0) { + noEntryList.push(name); + } + + each$4(availableDeps, function (dependentName) { + if (indexOf(thisItem.predecessor, dependentName) < 0) { + thisItem.predecessor.push(dependentName); + } + + var thatItem = createDependencyGraphItem(graph, dependentName); + + if (indexOf(thatItem.successor, dependentName) < 0) { + thatItem.successor.push(name); + } + }); + }); + return { + graph: graph, + noEntryList: noEntryList + }; + } + + function createDependencyGraphItem(graph, name) { + if (!graph[name]) { + graph[name] = { + predecessor: [], + successor: [] + }; + } + + return graph[name]; + } + + function getAvailableDependencies(originalDeps, fullNameList) { + var availableDeps = []; + each$4(originalDeps, function (dep) { + indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep); + }); + return availableDeps; + } + } + + function inheritDefaultOption(superOption, subOption) { + // See also `model/Component.ts#getDefaultOption` + return merge(merge({}, superOption, true), subOption, true); + } + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * Language: English. + */ + + + var langEN = { + time: { + month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + monthAbbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + dayOfWeek: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + dayOfWeekAbbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] + }, + legend: { + selector: { + all: 'All', + inverse: 'Inv' + } + }, + toolbox: { + brush: { + title: { + rect: 'Box Select', + polygon: 'Lasso Select', + lineX: 'Horizontally Select', + lineY: 'Vertically Select', + keep: 'Keep Selections', + clear: 'Clear Selections' + } + }, + dataView: { + title: 'Data View', + lang: ['Data View', 'Close', 'Refresh'] + }, + dataZoom: { + title: { + zoom: 'Zoom', + back: 'Zoom Reset' + } + }, + magicType: { + title: { + line: 'Switch to Line Chart', + bar: 'Switch to Bar Chart', + stack: 'Stack', + tiled: 'Tile' + } + }, + restore: { + title: 'Restore' + }, + saveAsImage: { + title: 'Save as Image', + lang: ['Right Click to Save Image'] + } + }, + series: { + typeNames: { + pie: 'Pie chart', + bar: 'Bar chart', + line: 'Line chart', + scatter: 'Scatter plot', + effectScatter: 'Ripple scatter plot', + radar: 'Radar chart', + tree: 'Tree', + treemap: 'Treemap', + boxplot: 'Boxplot', + candlestick: 'Candlestick', + k: 'K line chart', + heatmap: 'Heat map', + map: 'Map', + parallel: 'Parallel coordinate map', + lines: 'Line graph', + graph: 'Relationship graph', + sankey: 'Sankey diagram', + funnel: 'Funnel chart', + gauge: 'Gauge', + pictorialBar: 'Pictorial bar', + themeRiver: 'Theme River Map', + sunburst: 'Sunburst', + custom: 'Custom chart', + chart: 'Chart' + } + }, + aria: { + general: { + withTitle: 'This is a chart about "{title}"', + withoutTitle: 'This is a chart' + }, + series: { + single: { + prefix: '', + withName: ' with type {seriesType} named {seriesName}.', + withoutName: ' with type {seriesType}.' + }, + multiple: { + prefix: '. It consists of {seriesCount} series count.', + withName: ' The {seriesId} series is a {seriesType} representing {seriesName}.', + withoutName: ' The {seriesId} series is a {seriesType}.', + separator: { + middle: '', + end: '' + } + } + }, + data: { + allData: 'The data is as follows: ', + partialData: 'The first {displayCnt} items are: ', + withName: 'the data for {name} is {value}', + withoutName: '{value}', + separator: { + middle: ', ', + end: '. ' + } + } + } + }; + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + var langZH = { + time: { + month: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], + monthAbbr: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], + dayOfWeek: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'], + dayOfWeekAbbr: ['日', '一', '二', '三', '四', '五', '六'] + }, + legend: { + selector: { + all: '全选', + inverse: '反选' + } + }, + toolbox: { + brush: { + title: { + rect: '矩形选择', + polygon: '圈选', + lineX: '横向选择', + lineY: '纵向选择', + keep: '保持选择', + clear: '清除选择' + } + }, + dataView: { + title: '数据视图', + lang: ['数据视图', '关闭', '刷新'] + }, + dataZoom: { + title: { + zoom: '区域缩放', + back: '区域缩放还原' + } + }, + magicType: { + title: { + line: '切换为折线图', + bar: '切换为柱状图', + stack: '切换为堆叠', + tiled: '切换为平铺' + } + }, + restore: { + title: '还原' + }, + saveAsImage: { + title: '保存为图片', + lang: ['右键另存为图片'] + } + }, + series: { + typeNames: { + pie: '饼图', + bar: '柱状图', + line: '折线图', + scatter: '散点图', + effectScatter: '涟漪散点图', + radar: '雷达图', + tree: '树图', + treemap: '矩形树图', + boxplot: '箱型图', + candlestick: 'K线图', + k: 'K线图', + heatmap: '热力图', + map: '地图', + parallel: '平行坐标图', + lines: '线图', + graph: '关系图', + sankey: '桑基图', + funnel: '漏斗图', + gauge: '仪表盘图', + pictorialBar: '象形柱图', + themeRiver: '主题河流图', + sunburst: '旭日图', + custom: '自定义图表', + chart: '图表' + } + }, + aria: { + general: { + withTitle: '这是一个关于“{title}”的图表。', + withoutTitle: '这是一个图表,' + }, + series: { + single: { + prefix: '', + withName: '图表类型是{seriesType},表示{seriesName}。', + withoutName: '图表类型是{seriesType}。' + }, + multiple: { + prefix: '它由{seriesCount}个图表系列组成。', + withName: '第{seriesId}个系列是一个表示{seriesName}的{seriesType},', + withoutName: '第{seriesId}个系列是一个{seriesType},', + separator: { + middle: ';', + end: '。' + } + } + }, + data: { + allData: '其数据是——', + partialData: '其中,前{displayCnt}项是——', + withName: '{name}的数据是{value}', + withoutName: '{value}', + separator: { + middle: ',', + end: '' + } + } + } + }; + var LOCALE_ZH = 'ZH'; + var LOCALE_EN = 'EN'; + var DEFAULT_LOCALE = LOCALE_EN; + var localeStorage = {}; + var localeModels = {}; + var SYSTEM_LANG = !env.domSupported ? DEFAULT_LOCALE : function () { + var langStr = ( + /* eslint-disable-next-line */ + document.documentElement.lang || navigator.language || navigator.browserLanguage || DEFAULT_LOCALE).toUpperCase(); + return langStr.indexOf(LOCALE_ZH) > -1 ? LOCALE_ZH : DEFAULT_LOCALE; + }(); + + function registerLocale(locale, localeObj) { + locale = locale.toUpperCase(); + localeModels[locale] = new Model(localeObj); + localeStorage[locale] = localeObj; + } // export function getLocale(locale: string) { + // return localeStorage[locale]; + // } + + + function createLocaleObject(locale) { + if (isString(locale)) { + var localeObj = localeStorage[locale.toUpperCase()] || {}; + + if (locale === LOCALE_ZH || locale === LOCALE_EN) { + return clone$3(localeObj); + } else { + return merge(clone$3(localeObj), clone$3(localeStorage[DEFAULT_LOCALE]), false); + } + } else { + return merge(clone$3(locale), clone$3(localeStorage[DEFAULT_LOCALE]), false); + } + } + + function getLocaleModel(lang) { + return localeModels[lang]; + } + + function getDefaultLocaleModel() { + return localeModels[DEFAULT_LOCALE]; + } // Default locale + + + registerLocale(LOCALE_EN, langEN); + registerLocale(LOCALE_ZH, langZH); + var _impl$1 = null; + + function getScaleBreakHelper() { + return _impl$1; + } + + var ONE_SECOND = 1000; + var ONE_MINUTE = ONE_SECOND * 60; + var ONE_HOUR = ONE_MINUTE * 60; + var ONE_DAY = ONE_HOUR * 24; + var ONE_YEAR = ONE_DAY * 365; + var primaryTimeUnitFormatterMatchers = { + year: /({yyyy}|{yy})/, + month: /({MMMM}|{MMM}|{MM}|{M})/, + day: /({dd}|{d})/, + hour: /({HH}|{H}|{hh}|{h})/, + minute: /({mm}|{m})/, + second: /({ss}|{s})/, + millisecond: /({SSS}|{S})/ + }; + var defaultFormatterSeed = { + year: '{yyyy}', + month: '{MMM}', + day: '{d}', + hour: '{HH}:{mm}', + minute: '{HH}:{mm}', + second: '{HH}:{mm}:{ss}', + millisecond: '{HH}:{mm}:{ss} {SSS}' + }; + var defaultFullFormatter = '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss} {SSS}'; + var fullDayFormatter = '{yyyy}-{MM}-{dd}'; + var fullLeveledFormatter = { + year: '{yyyy}', + month: '{yyyy}-{MM}', + day: fullDayFormatter, + hour: fullDayFormatter + ' ' + defaultFormatterSeed.hour, + minute: fullDayFormatter + ' ' + defaultFormatterSeed.minute, + second: fullDayFormatter + ' ' + defaultFormatterSeed.second, + millisecond: defaultFullFormatter + }; // Order must be ensured from big to small. + + var primaryTimeUnits = ['year', 'month', 'day', 'hour', 'minute', 'second', 'millisecond']; + var timeUnits = ['year', 'half-year', 'quarter', 'month', 'week', 'half-week', 'day', 'half-day', 'quarter-day', 'hour', 'minute', 'second', 'millisecond']; + + function parseTimeAxisLabelFormatter(formatter) { + // Keep the logic the same with function `leveledFormat`. + return !isString(formatter) && !isFunction(formatter) ? parseTimeAxisLabelFormatterDictionary(formatter) : formatter; + } + /** + * The final generated dictionary is like: + * generated_dict = { + * year: { + * year: ['{yyyy}', ...] + * }, + * month: { + * year: ['{yyyy} {MMM}', ...], + * month: ['{MMM}', ...] + * }, + * day: { + * year: ['{yyyy} {MMM} {d}', ...], + * month: ['{MMM} {d}', ...], + * day: ['{d}', ...] + * }, + * ... + * } + * + * In echarts option, users can specify the entire dictionary or typically just: + * {formatter: { + * year: '{yyyy}', // Or an array of leveled templates: `['{yyyy}', '{bold1|{yyyy}}', ...]`, + * // corresponding to `[level0, level1, level2, ...]`. + * month: '{MMM}', + * day: '{d}', + * hour: '{HH}:{mm}', + * second: '{HH}:{mm}', + * ... + * }} + * If any time unit is not specified in echarts option, the default template is used, + * such as `['{yyyy}', {primary|{yyyy}']`. + * + * The `tick.level` is only used to read string from each array, meaning the style type. + * + * Let `lowerUnit = getUnitFromValue(tick.value)`. + * The non-break axis ticks only use `generated_dict[lowerUnit][lowerUnit][level]`. + * The break axis ticks may use `generated_dict[lowerUnit][upperUnit][level]`, because: + * Consider the case: the non-break ticks are `16th, 23th, Feb, 7th, ...`, where `Feb` is in the break + * range and pruned by breaks, and the break ends might be in lower time unit than day. e.g., break start + * is `Jan 25th 18:00`(in unit `hour`) and break end is `Feb 6th 18:30` (in unit `minute`). Thus the break + * label prefers `Jan 25th 18:00` and `Feb 6th 18:30` rather than only `18:00` and `18:30`, otherwise it + * causes misleading. + * In this case, the tick of the break start and end will both be: + * `{level: 1, lowerTimeUnit: 'minute', upperTimeUnit: 'month'}` + * And get the final template by `generated_dict[lowerTimeUnit][upperTimeUnit][level]`. + * Note that the time unit can not be calculated directly by a single tick value, since the two breaks have + * to be at the same time unit to avoid awkward appearance. i.e., `Jan 25th 18:00` is in the time unit "hour" + * but we need it to be "minute", following `Feb 6th 18:30`. + */ + + + function parseTimeAxisLabelFormatterDictionary(dictOption) { + dictOption = dictOption || {}; + var dict = {}; // Currently if any template is specified by user, it may contain rich text tag, + // such as `'{my_bold|{YYYY}}'`, thus we do add highlight style to it. + // (Note that nested tag (`'{some|{some2|xxx}}'`) in rich text is not supported yet.) + + var canAddHighlight = true; + each$4(primaryTimeUnits, function (lowestUnit) { + canAddHighlight && (canAddHighlight = dictOption[lowestUnit] == null); + }); + each$4(primaryTimeUnits, function (lowestUnit, lowestUnitIdx) { + var upperDictOption = dictOption[lowestUnit]; + dict[lowestUnit] = {}; + var lowerTpl = null; + + for (var upperUnitIdx = lowestUnitIdx; upperUnitIdx >= 0; upperUnitIdx--) { + var upperUnit = primaryTimeUnits[upperUnitIdx]; + var upperDictItemOption = isObject$2(upperDictOption) && !isArray(upperDictOption) ? upperDictOption[upperUnit] : upperDictOption; + var tplArr = void 0; + + if (isArray(upperDictItemOption)) { + tplArr = upperDictItemOption.slice(); + lowerTpl = tplArr[0] || ''; + } else if (isString(upperDictItemOption)) { + lowerTpl = upperDictItemOption; + tplArr = [lowerTpl]; + } else { + if (lowerTpl == null) { + lowerTpl = defaultFormatterSeed[lowestUnit]; + } // Generate the dict by the rule as follows: + // If the user specify (or by default): + // {formatter: { + // year: '{yyyy}', + // month: '{MMM}', + // day: '{d}', + // ... + // }} + // Concat them to make the final dictionary: + // {formatter: { + // year: {year: ['{yyyy}']}, + // month: {year: ['{yyyy} {MMM}'], month: ['{MMM}']}, + // day: {year: ['{yyyy} {MMM} {d}'], month: ['{MMM} {d}'], day: ['{d}']} + // ... + // }} + // And then add `{primary|...}` to each array if from default template. + // This strategy is convinient for user configurating and works for most cases. + // If bad cases encountered, users can specify the entire dictionary themselves + // instead of going through this logic. + else if (!primaryTimeUnitFormatterMatchers[upperUnit].test(lowerTpl)) { + lowerTpl = dict[upperUnit][upperUnit][0] + " " + lowerTpl; + } + + tplArr = [lowerTpl]; + + if (canAddHighlight) { + tplArr[1] = "{primary|" + lowerTpl + "}"; + } + } + + dict[lowestUnit][upperUnit] = tplArr; + } + }); + return dict; + } + + function pad(str, len) { + str += ''; + return '0000'.substr(0, len - str.length) + str; + } + + function getPrimaryTimeUnit(timeUnit) { + switch (timeUnit) { + case 'half-year': + case 'quarter': + return 'month'; + + case 'week': + case 'half-week': + return 'day'; + + case 'half-day': + case 'quarter-day': + return 'hour'; + + default: + // year, minutes, second, milliseconds + return timeUnit; + } + } + + function isPrimaryTimeUnit(timeUnit) { + return timeUnit === getPrimaryTimeUnit(timeUnit); + } + + function getDefaultFormatPrecisionOfInterval(timeUnit) { + switch (timeUnit) { + case 'year': + case 'month': + return 'day'; + + case 'millisecond': + return 'millisecond'; + + default: + // Also for day, hour, minute, second + return 'second'; + } + } + + function format$1( // Note: The result based on `isUTC` are totally different, which can not be just simply + // substituted by the result without `isUTC`. So we make the param `isUTC` mandatory. + time, template, isUTC, lang) { + var date = parseDate(time); + var y = date[fullYearGetterName(isUTC)](); + var M = date[monthGetterName(isUTC)]() + 1; + var q = Math.floor((M - 1) / 3) + 1; + var d = date[dateGetterName(isUTC)](); + var e = date['get' + (isUTC ? 'UTC' : '') + 'Day'](); + var H = date[hoursGetterName(isUTC)](); + var h = (H - 1) % 12 + 1; + var m = date[minutesGetterName(isUTC)](); + var s = date[secondsGetterName(isUTC)](); + var S = date[millisecondsGetterName(isUTC)](); + var a = H >= 12 ? 'pm' : 'am'; + var A = a.toUpperCase(); + var localeModel = lang instanceof Model ? lang : getLocaleModel(lang || SYSTEM_LANG) || getDefaultLocaleModel(); + var timeModel = localeModel.getModel('time'); + var month = timeModel.get('month'); + var monthAbbr = timeModel.get('monthAbbr'); + var dayOfWeek = timeModel.get('dayOfWeek'); + var dayOfWeekAbbr = timeModel.get('dayOfWeekAbbr'); + return (template || '').replace(/{a}/g, a + '').replace(/{A}/g, A + '').replace(/{yyyy}/g, y + '').replace(/{yy}/g, pad(y % 100 + '', 2)).replace(/{Q}/g, q + '').replace(/{MMMM}/g, month[M - 1]).replace(/{MMM}/g, monthAbbr[M - 1]).replace(/{MM}/g, pad(M, 2)).replace(/{M}/g, M + '').replace(/{dd}/g, pad(d, 2)).replace(/{d}/g, d + '').replace(/{eeee}/g, dayOfWeek[e]).replace(/{ee}/g, dayOfWeekAbbr[e]).replace(/{e}/g, e + '').replace(/{HH}/g, pad(H, 2)).replace(/{H}/g, H + '').replace(/{hh}/g, pad(h + '', 2)).replace(/{h}/g, h + '').replace(/{mm}/g, pad(m, 2)).replace(/{m}/g, m + '').replace(/{ss}/g, pad(s, 2)).replace(/{s}/g, s + '').replace(/{SSS}/g, pad(S, 3)).replace(/{S}/g, S + ''); + } + + function leveledFormat(tick, idx, formatter, lang, isUTC) { + var template = null; + + if (isString(formatter)) { + // Single formatter for all units at all levels + template = formatter; + } else if (isFunction(formatter)) { + var extra = { + time: tick.time, + level: tick.time.level + }; + var scaleBreakHelper = getScaleBreakHelper(); + + if (scaleBreakHelper) { + scaleBreakHelper.makeAxisLabelFormatterParamBreak(extra, tick["break"]); + } + + template = formatter(tick.value, idx, extra); + } else { + var tickTime = tick.time; + + if (tickTime) { + var leveledTplArr = formatter[tickTime.lowerTimeUnit][tickTime.upperTimeUnit]; + template = leveledTplArr[Math.min(tickTime.level, leveledTplArr.length - 1)] || ''; + } else { + // tick may be from customTicks or timeline therefore no tick.time. + var unit = getUnitFromValue(tick.value, isUTC); + template = formatter[unit][unit][0]; + } + } + + return format$1(new Date(tick.value), template, isUTC, lang); + } + + function getUnitFromValue(value, isUTC) { + var date = parseDate(value); + var M = date[monthGetterName(isUTC)]() + 1; + var d = date[dateGetterName(isUTC)](); + var h = date[hoursGetterName(isUTC)](); + var m = date[minutesGetterName(isUTC)](); + var s = date[secondsGetterName(isUTC)](); + var S = date[millisecondsGetterName(isUTC)](); + var isSecond = S === 0; + var isMinute = isSecond && s === 0; + var isHour = isMinute && m === 0; + var isDay = isHour && h === 0; + var isMonth = isDay && d === 1; + var isYear = isMonth && M === 1; + + if (isYear) { + return 'year'; + } else if (isMonth) { + return 'month'; + } else if (isDay) { + return 'day'; + } else if (isHour) { + return 'hour'; + } else if (isMinute) { + return 'minute'; + } else if (isSecond) { + return 'second'; + } else { + return 'millisecond'; + } + } // export function getUnitValue( + // value: number | Date, + // unit: TimeUnit, + // isUTC: boolean + // ) : number { + // const date = zrUtil.isNumber(value) + // ? numberUtil.parseDate(value) + // : value; + // unit = unit || getUnitFromValue(value, isUTC); + // switch (unit) { + // case 'year': + // return date[fullYearGetterName(isUTC)](); + // case 'half-year': + // return date[monthGetterName(isUTC)]() >= 6 ? 1 : 0; + // case 'quarter': + // return Math.floor((date[monthGetterName(isUTC)]() + 1) / 4); + // case 'month': + // return date[monthGetterName(isUTC)](); + // case 'day': + // return date[dateGetterName(isUTC)](); + // case 'half-day': + // return date[hoursGetterName(isUTC)]() / 24; + // case 'hour': + // return date[hoursGetterName(isUTC)](); + // case 'minute': + // return date[minutesGetterName(isUTC)](); + // case 'second': + // return date[secondsGetterName(isUTC)](); + // case 'millisecond': + // return date[millisecondsGetterName(isUTC)](); + // } + // } + + /** + * e.g., + * If timeUnit is 'year', return the Jan 1st 00:00:00 000 of that year. + * If timeUnit is 'day', return the 00:00:00 000 of that day. + * + * @return The input date. + */ + + + function roundTime(date, timeUnit, isUTC) { + switch (timeUnit) { + case 'year': + date[monthSetterName(isUTC)](0); + + case 'month': + date[dateSetterName(isUTC)](1); + + case 'day': + date[hoursSetterName(isUTC)](0); + + case 'hour': + date[minutesSetterName(isUTC)](0); + + case 'minute': + date[secondsSetterName(isUTC)](0); + + case 'second': + date[millisecondsSetterName(isUTC)](0); + } + + return date; + } + + function fullYearGetterName(isUTC) { + return isUTC ? 'getUTCFullYear' : 'getFullYear'; + } + + function monthGetterName(isUTC) { + return isUTC ? 'getUTCMonth' : 'getMonth'; + } + + function dateGetterName(isUTC) { + return isUTC ? 'getUTCDate' : 'getDate'; + } + + function hoursGetterName(isUTC) { + return isUTC ? 'getUTCHours' : 'getHours'; + } + + function minutesGetterName(isUTC) { + return isUTC ? 'getUTCMinutes' : 'getMinutes'; + } + + function secondsGetterName(isUTC) { + return isUTC ? 'getUTCSeconds' : 'getSeconds'; + } + + function millisecondsGetterName(isUTC) { + return isUTC ? 'getUTCMilliseconds' : 'getMilliseconds'; + } + + function fullYearSetterName(isUTC) { + return isUTC ? 'setUTCFullYear' : 'setFullYear'; + } + + function monthSetterName(isUTC) { + return isUTC ? 'setUTCMonth' : 'setMonth'; + } + + function dateSetterName(isUTC) { + return isUTC ? 'setUTCDate' : 'setDate'; + } + + function hoursSetterName(isUTC) { + return isUTC ? 'setUTCHours' : 'setHours'; + } + + function minutesSetterName(isUTC) { + return isUTC ? 'setUTCMinutes' : 'setMinutes'; + } + + function secondsSetterName(isUTC) { + return isUTC ? 'setUTCSeconds' : 'setSeconds'; + } + + function millisecondsSetterName(isUTC) { + return isUTC ? 'setUTCMilliseconds' : 'setMilliseconds'; + } + + function getTextRect(text, font, align, verticalAlign, padding, rich, truncate, lineHeight) { + var textEl = new ZRText({ + style: { + text: text, + font: font, + align: align, + verticalAlign: verticalAlign, + padding: padding, + rich: rich, + overflow: truncate ? 'truncate' : null, + lineHeight: lineHeight + } + }); + return textEl.getBoundingRect(); + } + /** + * Add a comma each three digit. + */ + + + function addCommas(x) { + if (!isNumeric(x)) { + return isString(x) ? x : '-'; + } + + var parts = (x + '').split('.'); + return parts[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g, '$1,') + (parts.length > 1 ? '.' + parts[1] : ''); + } + + function toCamelCase(str, upperCaseFirst) { + str = (str || '').toLowerCase().replace(/-(.)/g, function (match, group1) { + return group1.toUpperCase(); + }); + + if (upperCaseFirst && str) { + str = str.charAt(0).toUpperCase() + str.slice(1); + } + + return str; + } + + var normalizeCssArray = normalizeCssArray$1; + /** + * Make value user readable for tooltip and label. + * "User readable": + * Try to not print programmer-specific text like NaN, Infinity, null, undefined. + * Avoid to display an empty string, which users can not recognize there is + * a value and it might look like a bug. + */ + + function makeValueReadable(value, valueType, useUTC) { + var USER_READABLE_DEFUALT_TIME_PATTERN = '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}'; + + function stringToUserReadable(str) { + return str && trim(str) ? str : '-'; + } + + function isNumberUserReadable(num) { + return !!(num != null && !isNaN(num) && isFinite(num)); + } + + var isTypeTime = valueType === 'time'; + var isValueDate = value instanceof Date; + + if (isTypeTime || isValueDate) { + var date = isTypeTime ? parseDate(value) : value; + + if (!isNaN(+date)) { + return format$1(date, USER_READABLE_DEFUALT_TIME_PATTERN, useUTC); + } else if (isValueDate) { + return '-'; + } // In other cases, continue to try to display the value in the following code. + + } + + if (valueType === 'ordinal') { + return isStringSafe(value) ? stringToUserReadable(value) : isNumber(value) ? isNumberUserReadable(value) ? value + '' : '-' : '-'; + } // By default. + + + var numericResult = numericToNumber(value); + return isNumberUserReadable(numericResult) ? addCommas(numericResult) : isStringSafe(value) ? stringToUserReadable(value) : typeof value === 'boolean' ? value + '' : '-'; + } + + var TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; + + var wrapVar = function (varName, seriesIdx) { + return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}'; + }; + /** + * Template formatter + * @param {Array.|Object} paramsList + */ + + + function formatTpl(tpl, paramsList, encode) { + if (!isArray(paramsList)) { + paramsList = [paramsList]; + } + + var seriesLen = paramsList.length; + + if (!seriesLen) { + return ''; + } + + var $vars = paramsList[0].$vars || []; + + for (var i = 0; i < $vars.length; i++) { + var alias = TPL_VAR_ALIAS[i]; + tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0)); + } + + for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) { + for (var k = 0; k < $vars.length; k++) { + var val = paramsList[seriesIdx][$vars[k]]; + tpl = tpl.replace(wrapVar(TPL_VAR_ALIAS[k], seriesIdx), encode ? encodeHTML(val) : val); + } + } + + return tpl; + } + + function getTooltipMarker(inOpt, extraCssText) { + var opt = isString(inOpt) ? { + color: inOpt, + extraCssText: extraCssText + } : inOpt || {}; + var color = opt.color; + var type = opt.type; + extraCssText = opt.extraCssText; + var renderMode = opt.renderMode || 'html'; + + if (!color) { + return ''; + } + + if (renderMode === 'html') { + return type === 'subItem' ? '' : ''; + } else { + // Should better not to auto generate style name by auto-increment number here. + // Because this util is usually called in tooltip formatter, which is probably + // called repeatedly when mouse move and the auto-increment number increases fast. + // Users can make their own style name by theirselves, make it unique and readable. + var markerId = opt.markerId || 'markerX'; + return { + renderMode: renderMode, + content: '{' + markerId + '|} ', + style: type === 'subItem' ? { + width: 4, + height: 4, + borderRadius: 2, + backgroundColor: color + } : { + width: 10, + height: 10, + borderRadius: 5, + backgroundColor: color + } + }; + } + } + /** + * @deprecated Use `time/format` instead. + * ISO Date format + * @param {string} tpl + * @param {number} value + * @param {boolean} [isUTC=false] Default in local time. + * see `module:echarts/scale/Time` + * and `module:echarts/util/number#parseDate`. + * @inner + */ + + + function formatTime(tpl, value, isUTC) { + { + deprecateReplaceLog('echarts.format.formatTime', 'echarts.time.format'); + } + + if (tpl === 'week' || tpl === 'month' || tpl === 'quarter' || tpl === 'half-year' || tpl === 'year') { + tpl = 'MM-dd\nyyyy'; + } + + var date = parseDate(value); + var getUTC = isUTC ? 'getUTC' : 'get'; + var y = date[getUTC + 'FullYear'](); + var M = date[getUTC + 'Month']() + 1; + var d = date[getUTC + 'Date'](); + var h = date[getUTC + 'Hours'](); + var m = date[getUTC + 'Minutes'](); + var s = date[getUTC + 'Seconds'](); + var S = date[getUTC + 'Milliseconds'](); + tpl = tpl.replace('MM', pad(M, 2)).replace('M', M).replace('yyyy', y).replace('yy', pad(y % 100 + '', 2)).replace('dd', pad(d, 2)).replace('d', d).replace('hh', pad(h, 2)).replace('h', h).replace('mm', pad(m, 2)).replace('m', m).replace('ss', pad(s, 2)).replace('s', s).replace('SSS', pad(S, 3)); + return tpl; + } + /** + * Capital first + * @param {string} str + * @return {string} + */ + + + function capitalFirst(str) { + return str ? str.charAt(0).toUpperCase() + str.substr(1) : str; + } + /** + * @return Never be null/undefined. + */ + + + function convertToColorString(color, defaultColor) { + defaultColor = defaultColor || 'transparent'; + return isString(color) ? color : isObject$2(color) ? color.colorStops && (color.colorStops[0] || {}).color || defaultColor : defaultColor; + } + /** + * open new tab + * @param link url + * @param target blank or self + */ + + + function windowOpen(link, target) { + /* global window */ + if (target === '_blank' || target === 'blank') { + var blank = window.open(); + blank.opener = null; + blank.location.href = link; + } else { + window.open(link, target); + } + } + /** + * FIXME: + * `nonSeriesBoxCoordSysCreators` and `_nonSeriesBoxMasterList` are hardcoded implementations. + * Regarding "coord sys layout based on another coord sys", currently we only exprimentally support one level + * dpendency, such as, "grid(cartesian)s can be laid out based on matrix/calendar coord sys." + * But a comprehensive implementation may need to support: + * - Recursive dependencies. e.g., a matrix coord sys lays out based on another matrix coord sys. + * That requires in the implementation `create` and `update` of coord sys are called by a dependency graph. + * (@see enableTopologicalTravel in `util/component.ts`) + */ + + + var nonSeriesBoxCoordSysCreators = {}; + var normalCoordSysCreators = {}; + + var CoordinateSystemManager = + /** @class */ + function () { + function CoordinateSystemManager() { + this._normalMasterList = []; + this._nonSeriesBoxMasterList = []; + } + /** + * Typically, + * - in `create`, a coord sys lays out based on a given rect; + * - in `update`, update the pixel and data extent of there axes (if any) based on processed `series.data`. + * After that, a coord sys can serve (typically by `dataToPoint`/`dataToLayout`/`pointToData`). + * If the coordinate system do not lay out based on `series.data`, `update` is not needed. + */ + + + CoordinateSystemManager.prototype.create = function (ecModel, api) { + this._nonSeriesBoxMasterList = dealCreate(nonSeriesBoxCoordSysCreators, true); + this._normalMasterList = dealCreate(normalCoordSysCreators, false); + + function dealCreate(creatorMap, canBeNonSeriesBox) { + var coordinateSystems = []; + each$4(creatorMap, function (creator, type) { + var list = creator.create(ecModel, api); + coordinateSystems = coordinateSystems.concat(list || []); + { + if (canBeNonSeriesBox) { + // Disallow `update` is a brutal way to ensure `_nonSeriesBoxMasterList`s are ready to + // serve after `create`. But if `update` has to be involved in `_nonSeriesBoxMasterList` + // for some future case, more complicated mechanisms need to be introduced. + each$4(list, function (master) { + return assert(!master.update); + }); + } + } + }); + return coordinateSystems; + } + }; + /** + * @see CoordinateSystem['create'] + */ + + + CoordinateSystemManager.prototype.update = function (ecModel, api) { + each$4(this._normalMasterList, function (coordSys) { + coordSys.update && coordSys.update(ecModel, api); + }); + }; + + CoordinateSystemManager.prototype.getCoordinateSystems = function () { + return this._normalMasterList.concat(this._nonSeriesBoxMasterList); + }; + + CoordinateSystemManager.register = function (type, creator) { + if (type === 'matrix' || type === 'calendar') { + // FIXME: hardcode, @see nonSeriesBoxCoordSysCreators + nonSeriesBoxCoordSysCreators[type] = creator; + return; + } + + normalCoordSysCreators[type] = creator; + }; + + CoordinateSystemManager.get = function (type) { + return normalCoordSysCreators[type] || nonSeriesBoxCoordSysCreators[type]; + }; + + return CoordinateSystemManager; + }(); + + function canBeNonSeriesBoxCoordSys(coordSysType) { + return !!nonSeriesBoxCoordSysCreators[coordSysType]; + } + + var BoxCoordinateSystemCoordFrom = { + // By default fetch coord from `model.get('coord')`. + coord: 1, + // Some model/series, such as pie, is allowed to also get coord from `model.get('center')`, + // if cannot get from `model.get('coord')`. But historically pie use `center` option, but + // geo use `layoutCenter` option to specify layout center; they are not able to be unified. + // Therefor it is not recommended. + coord2: 2 + }; + var coordSysUseMap = createHashMap(); + /** + * @return Be an object, but never be NullUndefined. + */ + + function getCoordForBoxCoordSys(model) { + var coord = model.getShallow('coord', true); + var from = BoxCoordinateSystemCoordFrom.coord; + + if (coord == null) { + var store = coordSysUseMap.get(model.type); + + if (store && store.getCoord2) { + from = BoxCoordinateSystemCoordFrom.coord2; + coord = store.getCoord2(model); + } + } + + return { + coord: coord, + from: from + }; + } + /** + * - "dataCoordSys": each data item is laid out based on a coord sys. + * - "boxCoordSys": the overall bounding rect or anchor point is calculated based on a coord sys. + * e.g., + * grid rect (cartesian rect) is calculate based on matrix/calendar coord sys; + * pie center is calculated based on calendar/cartesian; + * + * The default value (if not declared in option `coordinateSystemUsage`): + * For series, use `dataCoordSys`, since this is the most case and backward compatible. + * For non-series components, use `boxCoordSys`, since `dataCoordSys` is not applicable. + */ + + + var CoordinateSystemUsageKind = { + none: 0, + dataCoordSys: 1, + boxCoordSys: 2 + }; + + function decideCoordSysUsageKind( // Component or series + model, printError) { + // For backward compat, still not use `true` in model.get. + var coordSysType = model.getShallow('coordinateSystem'); + var coordSysUsageOption = model.getShallow('coordinateSystemUsage', true); + var isDeclaredExplicitly = coordSysUsageOption != null; + var kind = CoordinateSystemUsageKind.none; + + if (coordSysType) { + var isSeries = model.mainType === 'series'; + + if (coordSysUsageOption == null) { + coordSysUsageOption = isSeries ? 'data' : 'box'; + } + + if (coordSysUsageOption === 'data') { + kind = CoordinateSystemUsageKind.dataCoordSys; + + if (!isSeries) { + { + if (isDeclaredExplicitly && printError) { + error('coordinateSystemUsage "data" is not supported in non-series components.'); + } + } + kind = CoordinateSystemUsageKind.none; + } + } else if (coordSysUsageOption === 'box') { + kind = CoordinateSystemUsageKind.boxCoordSys; + + if (!isSeries && !canBeNonSeriesBoxCoordSys(coordSysType)) { + { + if (isDeclaredExplicitly && printError) { + error("coordinateSystem \"" + coordSysType + "\" cannot be used" + (" as coordinateSystemUsage \"box\" for \"" + model.type + "\" yet.")); + } + } + kind = CoordinateSystemUsageKind.none; + } + } + } + + return { + coordSysType: coordSysType, + kind: kind + }; + } + /** + * These cases are considered: + * (A) Most series can use only "dataCoordSys", but "boxCoordSys" is not applicable: + * - e.g., series.heatmap, series.line, series.bar, series.scatter, ... + * (B) Some series and most components can use only "boxCoordSys", but "dataCoordSys" is not applicable: + * - e.g., series.pie, series.funnel, ... + * - e.g., grid, polar, geo, title, ... + * (C) Several series can use both "boxCoordSys" and "dataCoordSys", even at the same time: + * - e.g., series.graph, series.map + * - If graph or map series use a "boxCoordSys", it creates a internal "dataCoordSys" to lay out its data. + * - Graph series can use matrix coord sys as either the "dataCoordSys" (each item layout on one cell) + * or "boxCoordSys" (the entire series are layout within one cell). + * - To achieve this effect, + * `series.coordinateSystemUsage: 'box'` needs to be specified explicitly. + * + * Check these echarts option settings: + * - If `series: {type: 'bar'}`: + * dataCoordSys: "cartesian2d", boxCoordSys: "none". + * (since `coordinateSystem: 'cartesian2d'` is the default option in bar.) + * - If `grid: {coordinateSystem: 'matrix'}` + * dataCoordSys: "none", boxCoordSys: "matrix". + * - If `series: {type: 'pie', coordinateSystem: 'matrix'}`: + * dataCoordSys: "none", boxCoordSys: "matrix". + * (since `coordinateSystemUsage: 'box'` is the default option in pie.) + * - If `series: {type: 'graph', coordinateSystem: 'matrix'}`: + * dataCoordSys: "matrix", boxCoordSys: "none" + * - If `series: {type: 'graph', coordinateSystem: 'matrix', coordinateSystemUsage: 'box'}`: + * dataCoordSys: "an internal view", boxCoordSys: "the internal view is laid out on a matrix" + * - If `series: {type: 'map'}`: + * dataCoordSys: "a internal geo", boxCoordSys: "none" + * - If `series: {type: 'map', coordinateSystem: 'geo', geoIndex: 0}`: + * dataCoordSys: "a geo", boxCoordSys: "none" + * - If `series: {type: 'map', coordinateSystem: 'matrix'}`: + * not_applicable + * - If `series: {type: 'map', coordinateSystem: 'matrix', coordinateSystemUsage: 'box'}`: + * dataCoordSys: "an internal geo", boxCoordSys: "the internal geo is laid out on a matrix" + * + * @usage + * For case (A) & (B), + * call `injectCoordSysByOption({coordSysType: 'aaa', ...})` once for each series/components. + * For case (C), + * call `injectCoordSysByOption({coordSysType: 'aaa', ...})` once for each series/components, + * and then call `injectCoordSysByOption({coordSysType: 'bbb', ..., isDefaultDataCoordSys: true})` + * once for each series/components. + * + * @return Whether injected. + */ + + + function injectCoordSysByOption(opt) { + var targetModel = opt.targetModel, + coordSysType = opt.coordSysType, + coordSysProvider = opt.coordSysProvider, + isDefaultDataCoordSys = opt.isDefaultDataCoordSys, + allowNotFound = opt.allowNotFound; + { + assert(!!coordSysType); + } + + var _a = decideCoordSysUsageKind(targetModel, true), + kind = _a.kind, + declaredType = _a.coordSysType; + + if (isDefaultDataCoordSys && kind !== CoordinateSystemUsageKind.dataCoordSys) { + // If both dataCoordSys and boxCoordSys declared in one model. + // There is the only case in series-graph, and no other cases yet. + kind = CoordinateSystemUsageKind.dataCoordSys; + declaredType = coordSysType; + } + + if (kind === CoordinateSystemUsageKind.none || declaredType !== coordSysType) { + return false; + } + + var coordSys = coordSysProvider(coordSysType, targetModel); + + if (!coordSys) { + { + if (!allowNotFound) { + error(coordSysType + " cannot be found for" + (" " + targetModel.type + " (index: " + targetModel.componentIndex + ").")); + } + } + return false; + } + + if (kind === CoordinateSystemUsageKind.dataCoordSys) { + { + assert(targetModel.mainType === 'series'); + } + targetModel.coordinateSystem = coordSys; + } else { + // kind === 'boxCoordSys' + targetModel.boxCoordinateSystem = coordSys; + } + + return true; + } + + var each$3 = each$4; + /** + * @public + */ + + var LOCATION_PARAMS = ['left', 'right', 'top', 'bottom', 'width', 'height']; + /** + * @public + */ + + var HV_NAMES = [['width', 'left', 'right'], ['height', 'top', 'bottom']]; + + function boxLayout(orient, group, gap, maxWidth, maxHeight) { + var x = 0; + var y = 0; + + if (maxWidth == null) { + maxWidth = Infinity; + } + + if (maxHeight == null) { + maxHeight = Infinity; + } + + var currentLineMaxSize = 0; + group.eachChild(function (child, idx) { + var rect = child.getBoundingRect(); + var nextChild = group.childAt(idx + 1); + var nextChildRect = nextChild && nextChild.getBoundingRect(); + var nextX; + var nextY; + + if (orient === 'horizontal') { + var moveX = rect.width + (nextChildRect ? -nextChildRect.x + rect.x : 0); + nextX = x + moveX; // Wrap when width exceeds maxWidth or meet a `newline` group + // FIXME compare before adding gap? + + if (nextX > maxWidth || child.newline) { + x = 0; + nextX = moveX; + y += currentLineMaxSize + gap; + currentLineMaxSize = rect.height; + } else { + // FIXME: consider rect.y is not `0`? + currentLineMaxSize = Math.max(currentLineMaxSize, rect.height); + } + } else { + var moveY = rect.height + (nextChildRect ? -nextChildRect.y + rect.y : 0); + nextY = y + moveY; // Wrap when width exceeds maxHeight or meet a `newline` group + + if (nextY > maxHeight || child.newline) { + x += currentLineMaxSize + gap; + y = 0; + nextY = moveY; + currentLineMaxSize = rect.width; + } else { + currentLineMaxSize = Math.max(currentLineMaxSize, rect.width); + } + } + + if (child.newline) { + return; + } + + child.x = x; + child.y = y; + child.markRedraw(); + orient === 'horizontal' ? x = nextX + gap : y = nextY + gap; + }); + } + /** + * VBox or HBox layouting + * @param {string} orient + * @param {module:zrender/graphic/Group} group + * @param {number} gap + * @param {number} [width=Infinity] + * @param {number} [height=Infinity] + */ + + + var box = boxLayout; + /** + * VBox layouting + * @param {module:zrender/graphic/Group} group + * @param {number} gap + * @param {number} [width=Infinity] + * @param {number} [height=Infinity] + */ + + curry$1(boxLayout, 'vertical'); + /** + * HBox layouting + * @param {module:zrender/graphic/Group} group + * @param {number} gap + * @param {number} [width=Infinity] + * @param {number} [height=Infinity] + */ + + curry$1(boxLayout, 'horizontal'); + + function getBoxLayoutParams(boxLayoutModel, ignoreParent) { + return { + left: boxLayoutModel.getShallow('left', ignoreParent), + top: boxLayoutModel.getShallow('top', ignoreParent), + right: boxLayoutModel.getShallow('right', ignoreParent), + bottom: boxLayoutModel.getShallow('bottom', ignoreParent), + width: boxLayoutModel.getShallow('width', ignoreParent), + height: boxLayoutModel.getShallow('height', ignoreParent) + }; + } + /** + * Parse position info. + */ + + + function getLayoutRect(positionInfo, containerRect, // This is the space from the `containerRect` to the returned bounding rect. + // Commonly used in option `legend.padding`, `timeline.padding`, `title.padding`, + // `visualMap.padding`, ... + // [NOTICE]: + // It's named `margin`, because it's the space that outside the bounding rect. But from + // the perspective of the the caller, it's commonly used as the `padding` of a component, + // because conventionally background color covers this space. + // [BEHAVIOR]: + // - If width/height is specified, `margin` does not effect them. + // - Otherwise, they are calculated based on the rect that `containerRect` shrinked by `margin`. + // - left/right/top/bottom are based on the rect that `containerRect` shrinked by `margin`. + margin) { + margin = normalizeCssArray(margin || 0); + var containerWidth = containerRect.width; + var containerHeight = containerRect.height; + var left = parsePercent(positionInfo.left, containerWidth); + var top = parsePercent(positionInfo.top, containerHeight); + var right = parsePercent(positionInfo.right, containerWidth); + var bottom = parsePercent(positionInfo.bottom, containerHeight); + var width = parsePercent(positionInfo.width, containerWidth); + var height = parsePercent(positionInfo.height, containerHeight); + var verticalMargin = margin[2] + margin[0]; + var horizontalMargin = margin[1] + margin[3]; + var aspect = positionInfo.aspect; // If width is not specified, calculate width from left and right + + if (isNaN(width)) { + width = containerWidth - right - horizontalMargin - left; + } + + if (isNaN(height)) { + height = containerHeight - bottom - verticalMargin - top; + } + + if (aspect != null) { + // If width and height are not given + // 1. Graph should not exceeds the container + // 2. Aspect must be keeped + // 3. Graph should take the space as more as possible + // FIXME + // Margin is not considered, because there is no case that both + // using margin and aspect so far. + if (isNaN(width) && isNaN(height)) { + // PENDING: if only `left` or `right` is defined, perhaps it's more preferable to + // calculate size based on `containerWidth - left` or `containerWidth - left` here, + // but for backward compatibility we do not change it. + if (aspect > containerWidth / containerHeight) { + width = containerWidth * 0.8; + } else { + height = containerHeight * 0.8; + } + } // Calculate width or height with given aspect + + + if (isNaN(width)) { + width = aspect * height; + } + + if (isNaN(height)) { + height = width / aspect; + } + } // If left is not specified, calculate left from right and width + + + if (isNaN(left)) { + left = containerWidth - right - width - horizontalMargin; + } + + if (isNaN(top)) { + top = containerHeight - bottom - height - verticalMargin; + } // Align left and top + + + switch (positionInfo.left || positionInfo.right) { + case 'center': + left = containerWidth / 2 - width / 2 - margin[3]; + break; + + case 'right': + left = containerWidth - width - horizontalMargin; + break; + } + + switch (positionInfo.top || positionInfo.bottom) { + case 'middle': + case 'center': + top = containerHeight / 2 - height / 2 - margin[0]; + break; + + case 'bottom': + top = containerHeight - height - verticalMargin; + break; + } // If something is wrong and left, top, width, height are calculated as NaN + + + left = left || 0; + top = top || 0; + + if (isNaN(width)) { + // Width may be NaN if only one value is given except width + width = containerWidth - horizontalMargin - left - (right || 0); + } + + if (isNaN(height)) { + // Height may be NaN if only one value is given except height + height = containerHeight - verticalMargin - top - (bottom || 0); + } + + var rect = new BoundingRect((containerRect.x || 0) + left + margin[3], (containerRect.y || 0) + top + margin[0], width, height); + rect.margin = margin; + return rect; + } + + var BoxLayoutReferenceType = { + rect: 1, + point: 2 + }; + /** + * Uniformly calculate layout reference (rect or center) based on either: + * - viewport: + * - Get `refContainer` as `{x: 0, y: 0, width: api.getWidth(), height: api.getHeight()}` + * - coordinate system, which can serve in several ways: + * - Use `dataToPoint` to get the `refPoint`, such as, in cartesian2d coord sys. + * - Use `dataToLayout` to get the `refContainer`, such as, in matrix coord sys. + */ + + function createBoxLayoutReference(model, api, opt) { + var refContainer; + var refPoint; + var layoutRefType; + var boxCoordSys = model.boxCoordinateSystem; + var boxCoordFrom; + + if (boxCoordSys) { + var _a = getCoordForBoxCoordSys(model), + coord = _a.coord, + from = _a.from; // Do not use `clamp` in `dataToLayout` and `dataToPoint`, because: + // 1. Should support overflow (such as, by dataZoom), where NaN should be in the result. + // 2. Be consistent with the way used in `series.data` + + + if (boxCoordSys.dataToLayout) { + layoutRefType = BoxLayoutReferenceType.rect; + boxCoordFrom = from; + var result = boxCoordSys.dataToLayout(coord); + refContainer = result.contentRect || result.rect; + } else if (opt && opt.enableLayoutOnlyByCenter && boxCoordSys.dataToPoint) { + layoutRefType = BoxLayoutReferenceType.point; + boxCoordFrom = from; + refPoint = boxCoordSys.dataToPoint(coord); + } else { + { + error(model.type + "[" + model.componentIndex + "]" + (" layout based on " + boxCoordSys.type + " is not supported.")); + } + } + } + + if (layoutRefType == null) { + layoutRefType = BoxLayoutReferenceType.rect; + } + + if (layoutRefType === BoxLayoutReferenceType.rect) { + if (!refContainer) { + refContainer = { + x: 0, + y: 0, + width: api.getWidth(), + height: api.getHeight() + }; + } + + refPoint = [refContainer.x + refContainer.width / 2, refContainer.y + refContainer.height / 2]; + } + + return { + type: layoutRefType, + refContainer: refContainer, + refPoint: refPoint, + boxCoordFrom: boxCoordFrom + }; + } + + function fetchLayoutMode(ins) { + var layoutMode = ins.layoutMode || ins.constructor.layoutMode; + return isObject$2(layoutMode) ? layoutMode : layoutMode ? { + type: layoutMode + } : null; + } + /** + * Consider Case: + * When default option has {left: 0, width: 100}, and we set {right: 0} + * through setOption or media query, using normal zrUtil.merge will cause + * {right: 0} does not take effect. + * + * @example + * ComponentModel.extend({ + * init: function () { + * ... + * let inputPositionParams = layout.getLayoutParams(option); + * this.mergeOption(inputPositionParams); + * }, + * mergeOption: function (newOption) { + * newOption && zrUtil.merge(thisOption, newOption, true); + * layout.mergeLayoutParam(thisOption, newOption); + * } + * }); + * + * @param targetOption + * @param newOption + * @param opt + */ + + + function mergeLayoutParam(targetOption, newOption, opt) { + var ignoreSize = opt && opt.ignoreSize; + !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]); + var hResult = merge(HV_NAMES[0], 0); + var vResult = merge(HV_NAMES[1], 1); + copy(HV_NAMES[0], targetOption, hResult); + copy(HV_NAMES[1], targetOption, vResult); + + function merge(names, hvIdx) { + var newParams = {}; + var newValueCount = 0; + var merged = {}; + var mergedValueCount = 0; + var enoughParamNumber = 2; + each$3(names, function (name) { + merged[name] = targetOption[name]; + }); + each$3(names, function (name) { + // Consider case: newOption.width is null, which is + // set by user for removing width setting. + hasOwn(newOption, name) && (newParams[name] = merged[name] = newOption[name]); + hasValue(newParams, name) && newValueCount++; + hasValue(merged, name) && mergedValueCount++; + }); + + if (ignoreSize[hvIdx]) { + // Only one of left/right is premitted to exist. + if (hasValue(newOption, names[1])) { + merged[names[2]] = null; + } else if (hasValue(newOption, names[2])) { + merged[names[1]] = null; + } + + return merged; + } // Case: newOption: {width: ..., right: ...}, + // or targetOption: {right: ...} and newOption: {width: ...}, + // There is no conflict when merged only has params count + // little than enoughParamNumber. + + + if (mergedValueCount === enoughParamNumber || !newValueCount) { + return merged; + } // Case: newOption: {width: ..., right: ...}, + // Than we can make sure user only want those two, and ignore + // all origin params in targetOption. + else if (newValueCount >= enoughParamNumber) { + return newParams; + } else { + // Chose another param from targetOption by priority. + for (var i = 0; i < names.length; i++) { + var name_1 = names[i]; + + if (!hasOwn(newParams, name_1) && hasOwn(targetOption, name_1)) { + newParams[name_1] = targetOption[name_1]; + break; + } + } + + return newParams; + } + } + + function hasValue(obj, name) { + return obj[name] != null && obj[name] !== 'auto'; + } + + function copy(names, target, source) { + each$3(names, function (name) { + target[name] = source[name]; + }); + } + } + /** + * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object. + */ + + + function getLayoutParams(source) { + return copyLayoutParams({}, source); + } + /** + * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object. + * @param {Object} source + * @return {Object} Result contains those props. + */ + + + function copyLayoutParams(target, source) { + source && target && each$3(LOCATION_PARAMS, function (name) { + hasOwn(source, name) && (target[name] = source[name]); + }); + return target; + } + + var inner$b = makeInner(); + + var ComponentModel = + /** @class */ + function (_super) { + __extends(ComponentModel, _super); + + function ComponentModel(option, parentModel, ecModel) { + var _this = _super.call(this, option, parentModel, ecModel) || this; + + _this.uid = getUID('ec_cpt_model'); + return _this; + } + + ComponentModel.prototype.init = function (option, parentModel, ecModel) { + this.mergeDefaultAndTheme(option, ecModel); + }; + + ComponentModel.prototype.mergeDefaultAndTheme = function (option, ecModel) { + var layoutMode = fetchLayoutMode(this); + var inputPositionParams = layoutMode ? getLayoutParams(option) : {}; + var themeModel = ecModel.getTheme(); + merge(option, themeModel.get(this.mainType)); + merge(option, this.getDefaultOption()); + + if (layoutMode) { + mergeLayoutParam(option, inputPositionParams, layoutMode); + } + }; + + ComponentModel.prototype.mergeOption = function (option, ecModel) { + merge(this.option, option, true); + var layoutMode = fetchLayoutMode(this); + + if (layoutMode) { + mergeLayoutParam(this.option, option, layoutMode); + } + }; + /** + * Called immediately after `init` or `mergeOption` of this instance called. + */ + + + ComponentModel.prototype.optionUpdated = function (newCptOption, isInit) {}; + /** + * [How to declare defaultOption]: + * + * (A) If using class declaration in typescript (since echarts 5): + * ```ts + * import {ComponentOption} from '../model/option.js'; + * export interface XxxOption extends ComponentOption { + * aaa: number + * } + * export class XxxModel extends Component { + * static type = 'xxx'; + * static defaultOption: XxxOption = { + * aaa: 123 + * } + * } + * Component.registerClass(XxxModel); + * ``` + * ```ts + * import {inheritDefaultOption} from '../util/component.js'; + * import {XxxModel, XxxOption} from './XxxModel.js'; + * export interface XxxSubOption extends XxxOption { + * bbb: number + * } + * class XxxSubModel extends XxxModel { + * static defaultOption: XxxSubOption = inheritDefaultOption(XxxModel.defaultOption, { + * bbb: 456 + * }) + * fn() { + * let opt = this.getDefaultOption(); + * // opt is {aaa: 123, bbb: 456} + * } + * } + * ``` + * + * (B) If using class extend (previous approach in echarts 3 & 4): + * ```js + * let XxxComponent = Component.extend({ + * defaultOption: { + * xx: 123 + * } + * }) + * ``` + * ```js + * let XxxSubComponent = XxxComponent.extend({ + * defaultOption: { + * yy: 456 + * }, + * fn: function () { + * let opt = this.getDefaultOption(); + * // opt is {xx: 123, yy: 456} + * } + * }) + * ``` + */ + + + ComponentModel.prototype.getDefaultOption = function () { + var ctor = this.constructor; + + if (!isExtendedClass(ctor)) { + // When using ES class declaration, defaultOption must be declared as static. + // And manually inherit the defaultOption from its parent class if needed, such as, + // ```ts + // static defaultOption = inheritDefaultOption(ParentModel.defaultOption, {...}); + // ``` + return ctor.defaultOption; + } // FIXME: remove this approach? + // Legacy: auto merge defaultOption from ancestor classes if using ParentClass.extend(subProto) + + + var fields = inner$b(this); + + if (!fields.defaultOption) { + var optList = []; + var clz = ctor; + + while (clz) { + var opt = clz.prototype.defaultOption; + opt && optList.push(opt); + clz = clz.superClass; + } + + var defaultOption = {}; + + for (var i = optList.length - 1; i >= 0; i--) { + defaultOption = merge(defaultOption, optList[i], true); + } + + fields.defaultOption = defaultOption; + } + + return fields.defaultOption; + }; + /** + * Notice: always force to input param `useDefault` in case that forget to consider it. + * The same behavior as `modelUtil.parseFinder`. + * + * @param useDefault In many cases like series refer axis and axis refer grid, + * If axis index / axis id not specified, use the first target as default. + * In other cases like dataZoom refer axis, if not specified, measn no refer. + */ + + + ComponentModel.prototype.getReferringComponents = function (mainType, opt) { + var indexKey = mainType + 'Index'; + var idKey = mainType + 'Id'; + return queryReferringComponents(this.ecModel, mainType, { + index: this.get(indexKey, true), + id: this.get(idKey, true) + }, opt); + }; + + ComponentModel.prototype.getBoxLayoutParams = function () { + // Consider itself having box layout configs. + // For backward compatibility, by default do not `ignoreParent`. + return getBoxLayoutParams(this, false); + }; + /** + * Get key for zlevel. + * If developers don't configure zlevel. We will assign zlevel to series based on the key. + * For example, lines with trail effect and progressive series will in an individual zlevel. + */ + + + ComponentModel.prototype.getZLevelKey = function () { + return ''; + }; + + ComponentModel.prototype.setZLevel = function (zlevel) { + this.option.zlevel = zlevel; + }; + + ComponentModel.protoInitialize = function () { + var proto = ComponentModel.prototype; + proto.type = 'component'; + proto.id = ''; + proto.name = ''; + proto.mainType = ''; + proto.subType = ''; + proto.componentIndex = 0; + }(); + + return ComponentModel; + }(Model); + + mountExtend(ComponentModel, Model); + enableClassManagement(ComponentModel); + enableSubTypeDefaulter(ComponentModel); + enableTopologicalTravel(ComponentModel, getDependencies); + + function getDependencies(componentType) { + var deps = []; + each$4(ComponentModel.getClassesByMainType(componentType), function (clz) { + deps = deps.concat(clz.dependencies || clz.prototype.dependencies || []); + }); // Ensure main type. + + deps = map$1(deps, function (type) { + return parseClassType(type).main; + }); // Hack dataset for convenience. + + if (componentType !== 'dataset' && indexOf(deps, 'dataset') <= 0) { + deps.unshift('dataset'); + } + + return deps; + } + + var tokens = { + color: {}, + darkColor: {}, + size: {} + }; + var color$1 = tokens.color = { + theme: ['#5070dd', '#b6d634', '#505372', '#ff994d', '#0ca8df', '#ffd10a', '#fb628b', '#785db0', '#3fbe95'], + neutral00: '#fff', + neutral05: '#f4f7fd', + neutral10: '#e8ebf0', + neutral15: '#dbdee4', + neutral20: '#cfd2d7', + neutral25: '#c3c5cb', + neutral30: '#b7b9be', + neutral35: '#aaacb2', + neutral40: '#9ea0a5', + neutral45: '#929399', + neutral50: '#86878c', + neutral55: '#797b7f', + neutral60: '#6d6e73', + neutral65: '#616266', + neutral70: '#54555a', + neutral75: '#48494d', + neutral80: '#3c3c41', + neutral85: '#303034', + neutral90: '#232328', + neutral95: '#17171b', + neutral99: '#000', + accent05: '#eff1f9', + accent10: '#e0e4f2', + accent15: '#d0d6ec', + accent20: '#c0c9e6', + accent25: '#b1bbdf', + accent30: '#a1aed9', + accent35: '#91a0d3', + accent40: '#8292cc', + accent45: '#7285c6', + accent50: '#6578ba', + accent55: '#5c6da9', + accent60: '#536298', + accent65: '#4a5787', + accent70: '#404c76', + accent75: '#374165', + accent80: '#2e3654', + accent85: '#252b43', + accent90: '#1b2032', + accent95: '#121521', + transparent: 'rgba(0,0,0,0)', + highlight: 'rgba(255,231,130,0.8)' + }; + extend(color$1, { + primary: color$1.neutral80, + secondary: color$1.neutral70, + tertiary: color$1.neutral60, + quaternary: color$1.neutral50, + disabled: color$1.neutral20, + border: color$1.neutral30, + borderTint: color$1.neutral20, + borderShade: color$1.neutral40, + background: color$1.neutral05, + backgroundTint: 'rgba(234,237,245,0.5)', + backgroundTransparent: 'rgba(255,255,255,0)', + backgroundShade: color$1.neutral10, + shadow: 'rgba(0,0,0,0.2)', + shadowTint: 'rgba(129,130,136,0.2)', + axisLine: color$1.neutral70, + axisLineTint: color$1.neutral40, + axisTick: color$1.neutral70, + axisTickMinor: color$1.neutral60, + axisLabel: color$1.neutral70, + axisSplitLine: color$1.neutral15, + axisMinorSplitLine: color$1.neutral05 + }); + + for (var key in color$1) { + if (color$1.hasOwnProperty(key)) { + var hex = color$1[key]; + + if (key === 'theme') { + // Don't modify theme colors. + tokens.darkColor.theme = color$1.theme.slice(); + } else if (key === 'highlight') { + tokens.darkColor.highlight = 'rgba(255,231,130,0.4)'; + } else if (key.indexOf('accent') === 0) { + // Desaturate and lighten accent colors. + tokens.darkColor[key] = modifyHSL(hex, null, function (s) { + return s * 0.5; + }, function (l) { + return Math.min(1, 1.3 - l); + }); + } else { + tokens.darkColor[key] = modifyHSL(hex, null, function (s) { + return s * 0.9; + }, function (l) { + return 1 - Math.pow(l, 1.5); + }); + } + } + } + + tokens.size = { + xxs: 2, + xs: 5, + s: 10, + m: 15, + l: 20, + xl: 30, + xxl: 40, + xxxl: 50 + }; + var platform = ''; // Navigator not exists in node + + if (typeof navigator !== 'undefined') { + /* global navigator */ + platform = navigator.platform || ''; + } + + var decalColor = 'rgba(0, 0, 0, 0.2)'; + var themeColor = tokens.color.theme[0]; + var lightThemeColor = modifyHSL(themeColor, null, null, 0.9); + var globalDefault = { + darkMode: 'auto', + // backgroundColor: 'rgba(0,0,0,0)', + colorBy: 'series', + color: tokens.color.theme, + gradientColor: [lightThemeColor, themeColor], + aria: { + decal: { + decals: [{ + color: decalColor, + dashArrayX: [1, 0], + dashArrayY: [2, 5], + symbolSize: 1, + rotation: Math.PI / 6 + }, { + color: decalColor, + symbol: 'circle', + dashArrayX: [[8, 8], [0, 8, 8, 0]], + dashArrayY: [6, 0], + symbolSize: 0.8 + }, { + color: decalColor, + dashArrayX: [1, 0], + dashArrayY: [4, 3], + rotation: -Math.PI / 4 + }, { + color: decalColor, + dashArrayX: [[6, 6], [0, 6, 6, 0]], + dashArrayY: [6, 0] + }, { + color: decalColor, + dashArrayX: [[1, 0], [1, 6]], + dashArrayY: [1, 0, 6, 0], + rotation: Math.PI / 4 + }, { + color: decalColor, + symbol: 'triangle', + dashArrayX: [[9, 9], [0, 9, 9, 0]], + dashArrayY: [7, 2], + symbolSize: 0.75 + }] + } + }, + // If xAxis and yAxis declared, grid is created by default. + // grid: {}, + textStyle: { + // color: '#000', + // decoration: 'none', + // PENDING + fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif', + // fontFamily: 'Arial, Verdana, sans-serif', + fontSize: 12, + fontStyle: 'normal', + fontWeight: 'normal' + }, + // http://blogs.adobe.com/webplatform/2014/02/24/using-blend-modes-in-html-canvas/ + // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation + // Default is source-over + blendMode: null, + stateAnimation: { + duration: 300, + easing: 'cubicOut' + }, + animation: 'auto', + animationDuration: 1000, + animationDurationUpdate: 500, + animationEasing: 'cubicInOut', + animationEasingUpdate: 'cubicInOut', + animationThreshold: 2000, + // Configuration for progressive/incremental rendering + progressiveThreshold: 3000, + progressive: 400, + // Threshold of if use single hover layer to optimize. + // It is recommended that `hoverLayerThreshold` is equivalent to or less than + // `progressiveThreshold`, otherwise hover will cause restart of progressive, + // which is unexpected. + // see example . + hoverLayerThreshold: 3000, + // See: module:echarts/scale/Time + useUTC: false + }; + var VISUAL_DIMENSIONS = createHashMap(['tooltip', 'label', 'itemName', 'itemId', 'itemGroupId', 'itemChildGroupId', 'seriesName']); + var SOURCE_FORMAT_ORIGINAL = 'original'; + var SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows'; + var SOURCE_FORMAT_OBJECT_ROWS = 'objectRows'; + var SOURCE_FORMAT_KEYED_COLUMNS = 'keyedColumns'; + var SOURCE_FORMAT_TYPED_ARRAY = 'typedArray'; + var SOURCE_FORMAT_UNKNOWN = 'unknown'; + var SERIES_LAYOUT_BY_COLUMN = 'column'; + var SERIES_LAYOUT_BY_ROW = 'row'; // The result of `guessOrdinal`. + + var BE_ORDINAL = { + Must: 1, + Might: 2, + Not: 3 // Other cases + + }; + var innerGlobalModel = makeInner(); + /** + * MUST be called before mergeOption of all series. + */ + + function resetSourceDefaulter(ecModel) { + // `datasetMap` is used to make default encode. + innerGlobalModel(ecModel).datasetMap = createHashMap(); + } + /** + * [The strategy of the arrengment of data dimensions for dataset]: + * "value way": all axes are non-category axes. So series one by one take + * several (the number is coordSysDims.length) dimensions from dataset. + * The result of data arrengment of data dimensions like: + * | ser0_x | ser0_y | ser1_x | ser1_y | ser2_x | ser2_y | + * "category way": at least one axis is category axis. So the the first data + * dimension is always mapped to the first category axis and shared by + * all of the series. The other data dimensions are taken by series like + * "value way" does. + * The result of data arrengment of data dimensions like: + * | ser_shared_x | ser0_y | ser1_y | ser2_y | + * + * @return encode Never be `null/undefined`. + */ + + + function makeSeriesEncodeForAxisCoordSys(coordDimensions, seriesModel, source) { + var encode = {}; + var datasetModel = querySeriesUpstreamDatasetModel(seriesModel); // Currently only make default when using dataset, util more reqirements occur. + + if (!datasetModel || !coordDimensions) { + return encode; + } + + var encodeItemName = []; + var encodeSeriesName = []; + var ecModel = seriesModel.ecModel; + var datasetMap = innerGlobalModel(ecModel).datasetMap; + var key = datasetModel.uid + '_' + source.seriesLayoutBy; + var baseCategoryDimIndex; + var categoryWayValueDimStart; + coordDimensions = coordDimensions.slice(); + each$4(coordDimensions, function (coordDimInfoLoose, coordDimIdx) { + var coordDimInfo = isObject$2(coordDimInfoLoose) ? coordDimInfoLoose : coordDimensions[coordDimIdx] = { + name: coordDimInfoLoose + }; + + if (coordDimInfo.type === 'ordinal' && baseCategoryDimIndex == null) { + baseCategoryDimIndex = coordDimIdx; + categoryWayValueDimStart = getDataDimCountOnCoordDim(coordDimInfo); + } + + encode[coordDimInfo.name] = []; + }); + var datasetRecord = datasetMap.get(key) || datasetMap.set(key, { + categoryWayDim: categoryWayValueDimStart, + valueWayDim: 0 + }); // TODO + // Auto detect first time axis and do arrangement. + + each$4(coordDimensions, function (coordDimInfo, coordDimIdx) { + var coordDimName = coordDimInfo.name; + var count = getDataDimCountOnCoordDim(coordDimInfo); // In value way. + + if (baseCategoryDimIndex == null) { + var start = datasetRecord.valueWayDim; + pushDim(encode[coordDimName], start, count); + pushDim(encodeSeriesName, start, count); + datasetRecord.valueWayDim += count; // ??? TODO give a better default series name rule? + // especially when encode x y specified. + // consider: when multiple series share one dimension + // category axis, series name should better use + // the other dimension name. On the other hand, use + // both dimensions name. + } // In category way, the first category axis. + else if (baseCategoryDimIndex === coordDimIdx) { + pushDim(encode[coordDimName], 0, count); + pushDim(encodeItemName, 0, count); + } // In category way, the other axis. + else { + var start = datasetRecord.categoryWayDim; + pushDim(encode[coordDimName], start, count); + pushDim(encodeSeriesName, start, count); + datasetRecord.categoryWayDim += count; + } + }); + + function pushDim(dimIdxArr, idxFrom, idxCount) { + for (var i = 0; i < idxCount; i++) { + dimIdxArr.push(idxFrom + i); + } + } + + function getDataDimCountOnCoordDim(coordDimInfo) { + var dimsDef = coordDimInfo.dimsDef; + return dimsDef ? dimsDef.length : 1; + } + + encodeItemName.length && (encode.itemName = encodeItemName); + encodeSeriesName.length && (encode.seriesName = encodeSeriesName); + return encode; + } + /** + * @return If return null/undefined, indicate that should not use datasetModel. + */ + + + function querySeriesUpstreamDatasetModel(seriesModel) { + // Caution: consider the scenario: + // A dataset is declared and a series is not expected to use the dataset, + // and at the beginning `setOption({series: { noData })` (just prepare other + // option but no data), then `setOption({series: {data: [...]}); In this case, + // the user should set an empty array to avoid that dataset is used by default. + var thisData = seriesModel.get('data', true); + + if (!thisData) { + return queryReferringComponents(seriesModel.ecModel, 'dataset', { + index: seriesModel.get('datasetIndex', true), + id: seriesModel.get('datasetId', true) + }, SINGLE_REFERRING).models[0]; + } + } + /** + * @return Always return an array event empty. + */ + + + function queryDatasetUpstreamDatasetModels(datasetModel) { + // Only these attributes declared, we by default reference to `datasetIndex: 0`. + // Otherwise, no reference. + if (!datasetModel.get('transform', true) && !datasetModel.get('fromTransformResult', true)) { + return []; + } + + return queryReferringComponents(datasetModel.ecModel, 'dataset', { + index: datasetModel.get('fromDatasetIndex', true), + id: datasetModel.get('fromDatasetId', true) + }, SINGLE_REFERRING).models; + } + /** + * The rule should not be complex, otherwise user might not + * be able to known where the data is wrong. + * The code is ugly, but how to make it neat? + */ + + + function guessOrdinal(source, dimIndex) { + return doGuessOrdinal(source.data, source.sourceFormat, source.seriesLayoutBy, source.dimensionsDefine, source.startIndex, dimIndex); + } // dimIndex may be overflow source data. + // return {BE_ORDINAL} + + + function doGuessOrdinal(data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex) { + var result; // Experience value. + + var maxLoop = 5; + + if (isTypedArray(data)) { + return BE_ORDINAL.Not; + } // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine + // always exists in source. + + + var dimName; + var dimType; + + if (dimensionsDefine) { + var dimDefItem = dimensionsDefine[dimIndex]; + + if (isObject$2(dimDefItem)) { + dimName = dimDefItem.name; + dimType = dimDefItem.type; + } else if (isString(dimDefItem)) { + dimName = dimDefItem; + } + } + + if (dimType != null) { + return dimType === 'ordinal' ? BE_ORDINAL.Must : BE_ORDINAL.Not; + } + + if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) { + var dataArrayRows = data; + + if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) { + var sample = dataArrayRows[dimIndex]; + + for (var i = 0; i < (sample || []).length && i < maxLoop; i++) { + if ((result = detectValue(sample[startIndex + i])) != null) { + return result; + } + } + } else { + for (var i = 0; i < dataArrayRows.length && i < maxLoop; i++) { + var row = dataArrayRows[startIndex + i]; + + if (row && (result = detectValue(row[dimIndex])) != null) { + return result; + } + } + } + } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) { + var dataObjectRows = data; + + if (!dimName) { + return BE_ORDINAL.Not; + } + + for (var i = 0; i < dataObjectRows.length && i < maxLoop; i++) { + var item = dataObjectRows[i]; + + if (item && (result = detectValue(item[dimName])) != null) { + return result; + } + } + } else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) { + var dataKeyedColumns = data; + + if (!dimName) { + return BE_ORDINAL.Not; + } + + var sample = dataKeyedColumns[dimName]; + + if (!sample || isTypedArray(sample)) { + return BE_ORDINAL.Not; + } + + for (var i = 0; i < sample.length && i < maxLoop; i++) { + if ((result = detectValue(sample[i])) != null) { + return result; + } + } + } else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) { + var dataOriginal = data; + + for (var i = 0; i < dataOriginal.length && i < maxLoop; i++) { + var item = dataOriginal[i]; + var val = getDataItemValue(item); + + if (!isArray(val)) { + return BE_ORDINAL.Not; + } + + if ((result = detectValue(val[dimIndex])) != null) { + return result; + } + } + } + + function detectValue(val) { + var beStr = isString(val); // Consider usage convenience, '1', '2' will be treated as "number". + // `Number('')` (or any whitespace) is `0`. + + if (val != null && Number.isFinite(Number(val)) && val !== '') { + return beStr ? BE_ORDINAL.Might : BE_ORDINAL.Not; + } else if (beStr && val !== '-') { + return BE_ORDINAL.Must; + } + } + + return BE_ORDINAL.Not; + } + + var internalOptionCreatorMap = createHashMap(); + + function concatInternalOptions(ecModel, mainType, newCmptOptionList) { + var internalOptionCreator = internalOptionCreatorMap.get(mainType); + + if (!internalOptionCreator) { + return newCmptOptionList; + } + + var internalOptions = internalOptionCreator(ecModel); + + if (!internalOptions) { + return newCmptOptionList; + } + + { + for (var i = 0; i < internalOptions.length; i++) { + assert(isComponentIdInternal(internalOptions[i])); + } + } + return newCmptOptionList.concat(internalOptions); + } + + var innerColor = makeInner(); + makeInner(); + + var PaletteMixin = + /** @class */ + function () { + function PaletteMixin() {} + + PaletteMixin.prototype.getColorFromPalette = function (name, scope, requestNum) { + var defaultPalette = normalizeToArray(this.get('color', true)); + var layeredPalette = this.get('colorLayer', true); + return getFromPalette(this, innerColor, defaultPalette, layeredPalette, name, scope, requestNum); + }; + + PaletteMixin.prototype.clearColorPalette = function () { + clearPalette(this, innerColor); + }; + + return PaletteMixin; + }(); + + function getNearestPalette(palettes, requestColorNum) { + var paletteNum = palettes.length; // TODO palettes must be in order + + for (var i = 0; i < paletteNum; i++) { + if (palettes[i].length > requestColorNum) { + return palettes[i]; + } + } + + return palettes[paletteNum - 1]; + } + /** + * @param name MUST NOT be null/undefined. Otherwise call this function + * twise with the same parameters will get different result. + * @param scope default this. + * @return Can be null/undefined + */ + + + function getFromPalette(that, inner, defaultPalette, layeredPalette, name, scope, requestNum) { + scope = scope || that; + var scopeFields = inner(scope); + var paletteIdx = scopeFields.paletteIdx || 0; + var paletteNameMap = scopeFields.paletteNameMap = scopeFields.paletteNameMap || {}; // Use `hasOwnProperty` to avoid conflict with Object.prototype. + + if (paletteNameMap.hasOwnProperty(name)) { + return paletteNameMap[name]; + } + + var palette = requestNum == null || !layeredPalette ? defaultPalette : getNearestPalette(layeredPalette, requestNum); // In case can't find in layered color palette. + + palette = palette || defaultPalette; + + if (!palette || !palette.length) { + return; + } + + var pickedPaletteItem = palette[paletteIdx]; + + if (name) { + paletteNameMap[name] = pickedPaletteItem; + } + + scopeFields.paletteIdx = (paletteIdx + 1) % palette.length; + return pickedPaletteItem; + } + + function clearPalette(that, inner) { + inner(that).paletteIdx = 0; + inner(that).paletteNameMap = {}; + } // ----------------------- + // Internal method names: + // ----------------------- + + + var reCreateSeriesIndices; + var assertSeriesInitialized; + var initBase; + var OPTION_INNER_KEY = '\0_ec_inner'; + var OPTION_INNER_VALUE = 1; + var BUITIN_COMPONENTS_MAP = { + grid: 'GridComponent', + polar: 'PolarComponent', + geo: 'GeoComponent', + singleAxis: 'SingleAxisComponent', + parallel: 'ParallelComponent', + calendar: 'CalendarComponent', + matrix: 'MatrixComponent', + graphic: 'GraphicComponent', + toolbox: 'ToolboxComponent', + tooltip: 'TooltipComponent', + axisPointer: 'AxisPointerComponent', + brush: 'BrushComponent', + title: 'TitleComponent', + timeline: 'TimelineComponent', + markPoint: 'MarkPointComponent', + markLine: 'MarkLineComponent', + markArea: 'MarkAreaComponent', + legend: 'LegendComponent', + dataZoom: 'DataZoomComponent', + visualMap: 'VisualMapComponent', + // aria: 'AriaComponent', + // dataset: 'DatasetComponent', + // Dependencies + xAxis: 'GridComponent', + yAxis: 'GridComponent', + angleAxis: 'PolarComponent', + radiusAxis: 'PolarComponent' + }; + var BUILTIN_CHARTS_MAP = { + line: 'LineChart', + bar: 'BarChart', + pie: 'PieChart', + scatter: 'ScatterChart', + radar: 'RadarChart', + map: 'MapChart', + tree: 'TreeChart', + treemap: 'TreemapChart', + graph: 'GraphChart', + chord: 'ChordChart', + gauge: 'GaugeChart', + funnel: 'FunnelChart', + parallel: 'ParallelChart', + sankey: 'SankeyChart', + boxplot: 'BoxplotChart', + candlestick: 'CandlestickChart', + effectScatter: 'EffectScatterChart', + lines: 'LinesChart', + heatmap: 'HeatmapChart', + pictorialBar: 'PictorialBarChart', + themeRiver: 'ThemeRiverChart', + sunburst: 'SunburstChart', + custom: 'CustomChart' + }; + var componetsMissingLogPrinted = {}; + + function checkMissingComponents(option) { + each$4(option, function (componentOption, mainType) { + if (!ComponentModel.hasClass(mainType)) { + var componentImportName = BUITIN_COMPONENTS_MAP[mainType]; + + if (componentImportName && !componetsMissingLogPrinted[componentImportName]) { + error("Component " + mainType + " is used but not imported.\nimport { " + componentImportName + " } from 'echarts/components';\necharts.use([" + componentImportName + "]);"); + componetsMissingLogPrinted[componentImportName] = true; + } + } + }); + } + + var GlobalModel = + /** @class */ + function (_super) { + __extends(GlobalModel, _super); + + function GlobalModel() { + return _super !== null && _super.apply(this, arguments) || this; + } + + GlobalModel.prototype.init = function (option, parentModel, ecModel, theme, locale, optionManager) { + theme = theme || {}; + this.option = null; // Mark as not initialized. + + this._theme = new Model(theme); + this._locale = new Model(locale); + this._optionManager = optionManager; + }; + + GlobalModel.prototype.setOption = function (option, opts, optionPreprocessorFuncs) { + { + assert(option != null, 'option is null/undefined'); + assert(option[OPTION_INNER_KEY] !== OPTION_INNER_VALUE, 'please use chart.getOption()'); + } + var innerOpt = normalizeSetOptionInput(opts); + + this._optionManager.setOption(option, optionPreprocessorFuncs, innerOpt); + + this._resetOption(null, innerOpt); + }; + /** + * @param type null/undefined: reset all. + * 'recreate': force recreate all. + * 'timeline': only reset timeline option + * 'media': only reset media query option + * @return Whether option changed. + */ + + + GlobalModel.prototype.resetOption = function (type, opt) { + return this._resetOption(type, normalizeSetOptionInput(opt)); + }; + + GlobalModel.prototype._resetOption = function (type, opt) { + var optionChanged = false; + var optionManager = this._optionManager; + + if (!type || type === 'recreate') { + var baseOption = optionManager.mountOption(type === 'recreate'); + { + checkMissingComponents(baseOption); + } + + if (!this.option || type === 'recreate') { + initBase(this, baseOption); + } else { + this.restoreData(); + + this._mergeOption(baseOption, opt); + } + + optionChanged = true; + } + + if (type === 'timeline' || type === 'media') { + this.restoreData(); + } // By design, if `setOption(option2)` at the second time, and `option2` is a `ECUnitOption`, + // it should better not have the same props with `MediaUnit['option']`. + // Because either `option2` or `MediaUnit['option']` will be always merged to "current option" + // rather than original "baseOption". If they both override a prop, the result might be + // unexpected when media state changed after `setOption` called. + // If we really need to modify a props in each `MediaUnit['option']`, use the full version + // (`{baseOption, media}`) in `setOption`. + // For `timeline`, the case is the same. + + + if (!type || type === 'recreate' || type === 'timeline') { + var timelineOption = optionManager.getTimelineOption(this); + + if (timelineOption) { + optionChanged = true; + + this._mergeOption(timelineOption, opt); + } + } + + if (!type || type === 'recreate' || type === 'media') { + var mediaOptions = optionManager.getMediaOption(this); + + if (mediaOptions.length) { + each$4(mediaOptions, function (mediaOption) { + optionChanged = true; + + this._mergeOption(mediaOption, opt); + }, this); + } + } + + return optionChanged; + }; + + GlobalModel.prototype.mergeOption = function (option) { + this._mergeOption(option, null); + }; + + GlobalModel.prototype._mergeOption = function (newOption, opt) { + var option = this.option; + var componentsMap = this._componentsMap; + var componentsCount = this._componentsCount; + var newCmptTypes = []; + var newCmptTypeMap = createHashMap(); + var replaceMergeMainTypeMap = opt && opt.replaceMergeMainTypeMap; + resetSourceDefaulter(this); // If no component class, merge directly. + // For example: color, animaiton options, etc. + + each$4(newOption, function (componentOption, mainType) { + if (componentOption == null) { + return; + } + + if (!ComponentModel.hasClass(mainType)) { + // globalSettingTask.dirty(); + option[mainType] = option[mainType] == null ? clone$3(componentOption) : merge(option[mainType], componentOption, true); + } else if (mainType) { + newCmptTypes.push(mainType); + newCmptTypeMap.set(mainType, true); + } + }); + + if (replaceMergeMainTypeMap) { + // If there is a mainType `xxx` in `replaceMerge` but not declared in option, + // we trade it as it is declared in option as `{xxx: []}`. Because: + // (1) for normal merge, `{xxx: null/undefined}` are the same meaning as `{xxx: []}`. + // (2) some preprocessor may convert some of `{xxx: null/undefined}` to `{xxx: []}`. + replaceMergeMainTypeMap.each(function (val, mainTypeInReplaceMerge) { + if (ComponentModel.hasClass(mainTypeInReplaceMerge) && !newCmptTypeMap.get(mainTypeInReplaceMerge)) { + newCmptTypes.push(mainTypeInReplaceMerge); + newCmptTypeMap.set(mainTypeInReplaceMerge, true); + } + }); + } + + ComponentModel.topologicalTravel(newCmptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this); + + function visitComponent(mainType) { + var newCmptOptionList = concatInternalOptions(this, mainType, normalizeToArray(newOption[mainType])); + var oldCmptList = componentsMap.get(mainType); + var mergeMode = // `!oldCmptList` means init. See the comment in `mappingToExists` + !oldCmptList ? 'replaceAll' : replaceMergeMainTypeMap && replaceMergeMainTypeMap.get(mainType) ? 'replaceMerge' : 'normalMerge'; + var mappingResult = mappingToExists(oldCmptList, newCmptOptionList, mergeMode); // Set mainType and complete subType. + + setComponentTypeToKeyInfo(mappingResult, mainType, ComponentModel); // Empty it before the travel, in order to prevent `this._componentsMap` + // from being used in the `init`/`mergeOption`/`optionUpdated` of some + // components, which is probably incorrect logic. + + option[mainType] = null; + componentsMap.set(mainType, null); + componentsCount.set(mainType, 0); + var optionsByMainType = []; + var cmptsByMainType = []; + var cmptsCountByMainType = 0; + var tooltipExists; + var tooltipWarningLogged; + each$4(mappingResult, function (resultItem, index) { + var componentModel = resultItem.existing; + var newCmptOption = resultItem.newOption; + + if (!newCmptOption) { + if (componentModel) { + // Consider where is no new option and should be merged using {}, + // see removeEdgeAndAdd in topologicalTravel and + // ComponentModel.getAllClassMainTypes. + componentModel.mergeOption({}, this); + componentModel.optionUpdated({}, false); + } // If no both `resultItem.exist` and `resultItem.option`, + // either it is in `replaceMerge` and not matched by any id, + // or it has been removed in previous `replaceMerge` and left a "hole" in this component index. + + } else { + var isSeriesType = mainType === 'series'; + var ComponentModelClass = ComponentModel.getClass(mainType, resultItem.keyInfo.subType, !isSeriesType // Give a more detailed warn later if series don't exists + ); + + if (!ComponentModelClass) { + { + var subType = resultItem.keyInfo.subType; + var seriesImportName = BUILTIN_CHARTS_MAP[subType]; + + if (!componetsMissingLogPrinted[subType]) { + componetsMissingLogPrinted[subType] = true; + + if (seriesImportName) { + error("Series " + subType + " is used but not imported.\nimport { " + seriesImportName + " } from 'echarts/charts';\necharts.use([" + seriesImportName + "]);"); + } else { + error("Unknown series " + subType); + } + } + } + return; + } // TODO Before multiple tooltips get supported, we do this check to avoid unexpected exception. + + + if (mainType === 'tooltip') { + if (tooltipExists) { + { + if (!tooltipWarningLogged) { + warn('Currently only one tooltip component is allowed.'); + tooltipWarningLogged = true; + } + } + return; + } + + tooltipExists = true; + } + + if (componentModel && componentModel.constructor === ComponentModelClass) { + componentModel.name = resultItem.keyInfo.name; // componentModel.settingTask && componentModel.settingTask.dirty(); + + componentModel.mergeOption(newCmptOption, this); + componentModel.optionUpdated(newCmptOption, false); + } else { + // PENDING Global as parent ? + var extraOpt = extend({ + componentIndex: index + }, resultItem.keyInfo); + componentModel = new ComponentModelClass(newCmptOption, this, this, extraOpt); // Assign `keyInfo` + + extend(componentModel, extraOpt); + + if (resultItem.brandNew) { + componentModel.__requireNewView = true; + } + + componentModel.init(newCmptOption, this, this); // Call optionUpdated after init. + // newCmptOption has been used as componentModel.option + // and may be merged with theme and default, so pass null + // to avoid confusion. + + componentModel.optionUpdated(null, true); + } + } + + if (componentModel) { + optionsByMainType.push(componentModel.option); + cmptsByMainType.push(componentModel); + cmptsCountByMainType++; + } else { + // Always do assign to avoid elided item in array. + optionsByMainType.push(void 0); + cmptsByMainType.push(void 0); + } + }, this); + option[mainType] = optionsByMainType; + componentsMap.set(mainType, cmptsByMainType); + componentsCount.set(mainType, cmptsCountByMainType); // Backup series for filtering. + + if (mainType === 'series') { + reCreateSeriesIndices(this); + } + } // If no series declared, ensure `_seriesIndices` initialized. + + + if (!this._seriesIndices) { + reCreateSeriesIndices(this); + } + }; + /** + * Get option for output (cloned option and inner info removed) + */ + + + GlobalModel.prototype.getOption = function () { + var option = clone$3(this.option); + each$4(option, function (optInMainType, mainType) { + if (ComponentModel.hasClass(mainType)) { + var opts = normalizeToArray(optInMainType); // Inner cmpts need to be removed. + // Inner cmpts might not be at last since ec5.0, but still + // compatible for users: if inner cmpt at last, splice the returned array. + + var realLen = opts.length; + var metNonInner = false; + + for (var i = realLen - 1; i >= 0; i--) { + // Remove options with inner id. + if (opts[i] && !isComponentIdInternal(opts[i])) { + metNonInner = true; + } else { + opts[i] = null; + !metNonInner && realLen--; + } + } + + opts.length = realLen; + option[mainType] = opts; + } + }); + delete option[OPTION_INNER_KEY]; + return option; + }; + + GlobalModel.prototype.setTheme = function (theme) { + this._theme = new Model(theme); + + this._resetOption('recreate', null); + }; + + GlobalModel.prototype.getTheme = function () { + return this._theme; + }; + + GlobalModel.prototype.getLocaleModel = function () { + return this._locale; + }; + + GlobalModel.prototype.setUpdatePayload = function (payload) { + this._payload = payload; + }; + + GlobalModel.prototype.getUpdatePayload = function () { + return this._payload; + }; + /** + * @param idx If not specified, return the first one. + */ + + + GlobalModel.prototype.getComponent = function (mainType, idx) { + var list = this._componentsMap.get(mainType); + + if (list) { + var cmpt = list[idx || 0]; + + if (cmpt) { + return cmpt; + } else if (idx == null) { + for (var i = 0; i < list.length; i++) { + if (list[i]) { + return list[i]; + } + } + } + } + }; + /** + * @return Never be null/undefined. + */ + + + GlobalModel.prototype.queryComponents = function (condition) { + var mainType = condition.mainType; + + if (!mainType) { + return []; + } + + var index = condition.index; + var id = condition.id; + var name = condition.name; + + var cmpts = this._componentsMap.get(mainType); + + if (!cmpts || !cmpts.length) { + return []; + } + + var result; + + if (index != null) { + result = []; + each$4(normalizeToArray(index), function (idx) { + cmpts[idx] && result.push(cmpts[idx]); + }); + } else if (id != null) { + result = queryByIdOrName('id', id, cmpts); + } else if (name != null) { + result = queryByIdOrName('name', name, cmpts); + } else { + // Return all non-empty components in that mainType + result = filter(cmpts, function (cmpt) { + return !!cmpt; + }); + } + + return filterBySubType(result, condition); + }; + /** + * The interface is different from queryComponents, + * which is convenient for inner usage. + * + * @usage + * let result = findComponents( + * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}} + * ); + * let result = findComponents( + * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}} + * ); + * let result = findComponents( + * {mainType: 'series', + * filter: function (model, index) {...}} + * ); + * // result like [component0, componnet1, ...] + */ + + + GlobalModel.prototype.findComponents = function (condition) { + var query = condition.query; + var mainType = condition.mainType; + var queryCond = getQueryCond(query); + var result = queryCond ? this.queryComponents(queryCond) // Retrieve all non-empty components. + : filter(this._componentsMap.get(mainType), function (cmpt) { + return !!cmpt; + }); + return doFilter(filterBySubType(result, condition)); + + function getQueryCond(q) { + var indexAttr = mainType + 'Index'; + var idAttr = mainType + 'Id'; + var nameAttr = mainType + 'Name'; + return q && (q[indexAttr] != null || q[idAttr] != null || q[nameAttr] != null) ? { + mainType: mainType, + // subType will be filtered finally. + index: q[indexAttr], + id: q[idAttr], + name: q[nameAttr] + } : null; + } + + function doFilter(res) { + return condition.filter ? filter(res, condition.filter) : res; + } + }; + + GlobalModel.prototype.eachComponent = function (mainType, cb, context) { + var componentsMap = this._componentsMap; + + if (isFunction(mainType)) { + var ctxForAll_1 = cb; + var cbForAll_1 = mainType; + componentsMap.each(function (cmpts, componentType) { + for (var i = 0; cmpts && i < cmpts.length; i++) { + var cmpt = cmpts[i]; + cmpt && cbForAll_1.call(ctxForAll_1, componentType, cmpt, cmpt.componentIndex); + } + }); + } else { + var cmpts = isString(mainType) ? componentsMap.get(mainType) : isObject$2(mainType) ? this.findComponents(mainType) : null; + + for (var i = 0; cmpts && i < cmpts.length; i++) { + var cmpt = cmpts[i]; + cmpt && cb.call(context, cmpt, cmpt.componentIndex); + } + } + }; + /** + * Get series list before filtered by name. + */ + + + GlobalModel.prototype.getSeriesByName = function (name) { + var nameStr = convertOptionIdName(name, null); + return filter(this._componentsMap.get('series'), function (oneSeries) { + return !!oneSeries && nameStr != null && oneSeries.name === nameStr; + }); + }; + /** + * Get series list before filtered by index. + */ + + + GlobalModel.prototype.getSeriesByIndex = function (seriesIndex) { + return this._componentsMap.get('series')[seriesIndex]; + }; + /** + * Get series list before filtered by type. + * FIXME: rename to getRawSeriesByType? + */ + + + GlobalModel.prototype.getSeriesByType = function (subType) { + return filter(this._componentsMap.get('series'), function (oneSeries) { + return !!oneSeries && oneSeries.subType === subType; + }); + }; + /** + * Get all series before filtered. + */ + + + GlobalModel.prototype.getSeries = function () { + return filter(this._componentsMap.get('series'), function (oneSeries) { + return !!oneSeries; + }); + }; + /** + * Count series before filtered. + */ + + + GlobalModel.prototype.getSeriesCount = function () { + return this._componentsCount.get('series'); + }; + /** + * After filtering, series may be different + * from raw series. + */ + + + GlobalModel.prototype.eachSeries = function (cb, context) { + assertSeriesInitialized(this); + each$4(this._seriesIndices, function (rawSeriesIndex) { + var series = this._componentsMap.get('series')[rawSeriesIndex]; + + cb.call(context, series, rawSeriesIndex); + }, this); + }; + /** + * Iterate raw series before filtered. + * + * @param {Function} cb + * @param {*} context + */ + + + GlobalModel.prototype.eachRawSeries = function (cb, context) { + each$4(this._componentsMap.get('series'), function (series) { + series && cb.call(context, series, series.componentIndex); + }); + }; + /** + * After filtering, series may be different. + * from raw series. + */ + + + GlobalModel.prototype.eachSeriesByType = function (subType, cb, context) { + assertSeriesInitialized(this); + each$4(this._seriesIndices, function (rawSeriesIndex) { + var series = this._componentsMap.get('series')[rawSeriesIndex]; + + if (series.subType === subType) { + cb.call(context, series, rawSeriesIndex); + } + }, this); + }; + /** + * Iterate raw series before filtered of given type. + */ + + + GlobalModel.prototype.eachRawSeriesByType = function (subType, cb, context) { + return each$4(this.getSeriesByType(subType), cb, context); + }; + + GlobalModel.prototype.isSeriesFiltered = function (seriesModel) { + assertSeriesInitialized(this); + return this._seriesIndicesMap.get(seriesModel.componentIndex) == null; + }; + + GlobalModel.prototype.getCurrentSeriesIndices = function () { + return (this._seriesIndices || []).slice(); + }; + + GlobalModel.prototype.filterSeries = function (cb, context) { + assertSeriesInitialized(this); + var newSeriesIndices = []; + each$4(this._seriesIndices, function (seriesRawIdx) { + var series = this._componentsMap.get('series')[seriesRawIdx]; + + cb.call(context, series, seriesRawIdx) && newSeriesIndices.push(seriesRawIdx); + }, this); + this._seriesIndices = newSeriesIndices; + this._seriesIndicesMap = createHashMap(newSeriesIndices); + }; + + GlobalModel.prototype.restoreData = function (payload) { + reCreateSeriesIndices(this); + var componentsMap = this._componentsMap; + var componentTypes = []; + componentsMap.each(function (components, componentType) { + if (ComponentModel.hasClass(componentType)) { + componentTypes.push(componentType); + } + }); + ComponentModel.topologicalTravel(componentTypes, ComponentModel.getAllClassMainTypes(), function (componentType) { + each$4(componentsMap.get(componentType), function (component) { + if (component && (componentType !== 'series' || !isNotTargetSeries(component, payload))) { + component.restoreData(); + } + }); + }); + }; + + GlobalModel.internalField = function () { + reCreateSeriesIndices = function (ecModel) { + var seriesIndices = ecModel._seriesIndices = []; + each$4(ecModel._componentsMap.get('series'), function (series) { + // series may have been removed by `replaceMerge`. + series && seriesIndices.push(series.componentIndex); + }); + ecModel._seriesIndicesMap = createHashMap(seriesIndices); + }; + + assertSeriesInitialized = function (ecModel) { + // Components that use _seriesIndices should depends on series component, + // which make sure that their initialization is after series. + { + if (!ecModel._seriesIndices) { + throw new Error('Option should contains series.'); + } + } + }; + + initBase = function (ecModel, baseOption) { + // Using OPTION_INNER_KEY to mark that this option cannot be used outside, + // i.e. `chart.setOption(chart.getModel().option);` is forbidden. + ecModel.option = {}; + ecModel.option[OPTION_INNER_KEY] = OPTION_INNER_VALUE; // Init with series: [], in case of calling findSeries method + // before series initialized. + + ecModel._componentsMap = createHashMap({ + series: [] + }); + ecModel._componentsCount = createHashMap(); // If user spefied `option.aria`, aria will be enable. This detection should be + // performed before theme and globalDefault merge. + + var airaOption = baseOption.aria; + + if (isObject$2(airaOption) && airaOption.enabled == null) { + airaOption.enabled = true; + } + + mergeTheme(baseOption, ecModel._theme.option); // TODO Needs clone when merging to the unexisted property + + merge(baseOption, globalDefault, false); + + ecModel._mergeOption(baseOption, null); + }; + }(); + + return GlobalModel; + }(Model); + + function isNotTargetSeries(seriesModel, payload) { + if (payload) { + var index = payload.seriesIndex; + var id = payload.seriesId; + var name_1 = payload.seriesName; + return index != null && seriesModel.componentIndex !== index || id != null && seriesModel.id !== id || name_1 != null && seriesModel.name !== name_1; + } + } + + function mergeTheme(option, theme) { + // PENDING + // NOT use `colorLayer` in theme if option has `color` + var notMergeColorLayer = option.color && !option.colorLayer; + each$4(theme, function (themeItem, name) { + if (name === 'colorLayer' && notMergeColorLayer || name === 'color' && option.color) { + return; + } // If it is component model mainType, the model handles that merge later. + // otherwise, merge them here. + + + if (!ComponentModel.hasClass(name)) { + if (typeof themeItem === 'object') { + option[name] = !option[name] ? clone$3(themeItem) : merge(option[name], themeItem, false); + } else { + if (option[name] == null) { + option[name] = themeItem; + } + } + } + }); + } + + function queryByIdOrName(attr, idOrName, cmpts) { + // Here is a break from echarts4: string and number are + // treated as equal. + if (isArray(idOrName)) { + var keyMap_1 = createHashMap(); + each$4(idOrName, function (idOrNameItem) { + if (idOrNameItem != null) { + var idName = convertOptionIdName(idOrNameItem, null); + idName != null && keyMap_1.set(idOrNameItem, true); + } + }); + return filter(cmpts, function (cmpt) { + return cmpt && keyMap_1.get(cmpt[attr]); + }); + } else { + var idName_1 = convertOptionIdName(idOrName, null); + return filter(cmpts, function (cmpt) { + return cmpt && idName_1 != null && cmpt[attr] === idName_1; + }); + } + } + + function filterBySubType(components, condition) { + // Using hasOwnProperty for restrict. Consider + // subType is undefined in user payload. + return condition.hasOwnProperty('subType') ? filter(components, function (cmpt) { + return cmpt && cmpt.subType === condition.subType; + }) : components; + } + + function normalizeSetOptionInput(opts) { + var replaceMergeMainTypeMap = createHashMap(); + opts && each$4(normalizeToArray(opts.replaceMerge), function (mainType) { + { + assert(ComponentModel.hasClass(mainType), '"' + mainType + '" is not valid component main type in "replaceMerge"'); + } + replaceMergeMainTypeMap.set(mainType, true); + }); + return { + replaceMergeMainTypeMap: replaceMergeMainTypeMap + }; + } + + mixin(GlobalModel, PaletteMixin); + var availableMethods = ['getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isSSR', 'isDisposed', 'on', 'off', 'getDataURL', 'getConnectedDataURL', // 'getModel', + 'getOption', // 'getViewOfComponentModel', + // 'getViewOfSeriesModel', + 'getId', 'updateLabelLayout']; + + var ExtensionAPI = + /** @class */ + function () { + function ExtensionAPI(ecInstance) { + each$4(availableMethods, function (methodName) { + this[methodName] = bind$1(ecInstance[methodName], ecInstance); + }, this); + } + + return ExtensionAPI; + }(); + + var QUERY_REG = /^(min|max)?(.+)$/; // Key: mainType + // type FakeComponentsMap = HashMap<(MappingExistingItem & { subType: string })[]>; + + /** + * TERM EXPLANATIONS: + * See `ECOption` and `ECUnitOption` in `src/util/types.ts`. + */ + + var OptionManager = + /** @class */ + function () { + // timeline.notMerge is not supported in ec3. Firstly there is rearly + // case that notMerge is needed. Secondly supporting 'notMerge' requires + // rawOption cloned and backuped when timeline changed, which does no + // good to performance. What's more, that both timeline and setOption + // method supply 'notMerge' brings complex and some problems. + // Consider this case: + // (step1) chart.setOption({timeline: {notMerge: false}, ...}, false); + // (step2) chart.setOption({timeline: {notMerge: true}, ...}, false); + function OptionManager(api) { + this._timelineOptions = []; + this._mediaList = []; + /** + * -1, means default. + * empty means no media. + */ + + this._currentMediaIndices = []; + this._api = api; + } + + OptionManager.prototype.setOption = function (rawOption, optionPreprocessorFuncs, opt) { + if (rawOption) { + // That set dat primitive is dangerous if user reuse the data when setOption again. + each$4(normalizeToArray(rawOption.series), function (series) { + series && series.data && isTypedArray(series.data) && setAsPrimitive(series.data); + }); + each$4(normalizeToArray(rawOption.dataset), function (dataset) { + dataset && dataset.source && isTypedArray(dataset.source) && setAsPrimitive(dataset.source); + }); + } // Caution: some series modify option data, if do not clone, + // it should ensure that the repeat modify correctly + // (create a new object when modify itself). + + + rawOption = clone$3(rawOption); // FIXME + // If some property is set in timeline options or media option but + // not set in baseOption, a warning should be given. + + var optionBackup = this._optionBackup; + var newParsedOption = parseRawOption(rawOption, optionPreprocessorFuncs, !optionBackup); + this._newBaseOption = newParsedOption.baseOption; // For setOption at second time (using merge mode); + + if (optionBackup) { + // FIXME + // the restore merge solution is essentially incorrect. + // the mapping can not be 100% consistent with ecModel, which probably brings + // potential bug! + // The first merge is delayed, because in most cases, users do not call `setOption` twice. + // let fakeCmptsMap = this._fakeCmptsMap; + // if (!fakeCmptsMap) { + // fakeCmptsMap = this._fakeCmptsMap = createHashMap(); + // mergeToBackupOption(fakeCmptsMap, null, optionBackup.baseOption, null); + // } + // mergeToBackupOption( + // fakeCmptsMap, optionBackup.baseOption, newParsedOption.baseOption, opt + // ); + // For simplicity, timeline options and media options do not support merge, + // that is, if you `setOption` twice and both has timeline options, the latter + // timeline options will not be merged to the former, but just substitute them. + if (newParsedOption.timelineOptions.length) { + optionBackup.timelineOptions = newParsedOption.timelineOptions; + } + + if (newParsedOption.mediaList.length) { + optionBackup.mediaList = newParsedOption.mediaList; + } + + if (newParsedOption.mediaDefault) { + optionBackup.mediaDefault = newParsedOption.mediaDefault; + } + } else { + this._optionBackup = newParsedOption; + } + }; + + OptionManager.prototype.mountOption = function (isRecreate) { + var optionBackup = this._optionBackup; + this._timelineOptions = optionBackup.timelineOptions; + this._mediaList = optionBackup.mediaList; + this._mediaDefault = optionBackup.mediaDefault; + this._currentMediaIndices = []; + return clone$3(isRecreate // this._optionBackup.baseOption, which is created at the first `setOption` + // called, and is merged into every new option by inner method `mergeToBackupOption` + // each time `setOption` called, can be only used in `isRecreate`, because + // its reliability is under suspicion. In other cases option merge is + // performed by `model.mergeOption`. + ? optionBackup.baseOption : this._newBaseOption); + }; + + OptionManager.prototype.getTimelineOption = function (ecModel) { + var option; + var timelineOptions = this._timelineOptions; + + if (timelineOptions.length) { + // getTimelineOption can only be called after ecModel inited, + // so we can get currentIndex from timelineModel. + var timelineModel = ecModel.getComponent('timeline'); + + if (timelineModel) { + option = clone$3( // FIXME:TS as TimelineModel or quivlant interface + timelineOptions[timelineModel.getCurrentIndex()]); + } + } + + return option; + }; + + OptionManager.prototype.getMediaOption = function (ecModel) { + var ecWidth = this._api.getWidth(); + + var ecHeight = this._api.getHeight(); + + var mediaList = this._mediaList; + var mediaDefault = this._mediaDefault; + var indices = []; + var result = []; // No media defined. + + if (!mediaList.length && !mediaDefault) { + return result; + } // Multi media may be applied, the latter defined media has higher priority. + + + for (var i = 0, len = mediaList.length; i < len; i++) { + if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) { + indices.push(i); + } + } // FIXME + // Whether mediaDefault should force users to provide? Otherwise + // the change by media query can not be recorvered. + + + if (!indices.length && mediaDefault) { + indices = [-1]; + } + + if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) { + result = map$1(indices, function (index) { + return clone$3(index === -1 ? mediaDefault.option : mediaList[index].option); + }); + } // Otherwise return nothing. + + + this._currentMediaIndices = indices; + return result; + }; + + return OptionManager; + }(); + /** + * [RAW_OPTION_PATTERNS] + * (Note: "series: []" represents all other props in `ECUnitOption`) + * + * (1) No prop "baseOption" declared: + * Root option is used as "baseOption" (except prop "options" and "media"). + * ```js + * option = { + * series: [], + * timeline: {}, + * options: [], + * }; + * option = { + * series: [], + * media: {}, + * }; + * option = { + * series: [], + * timeline: {}, + * options: [], + * media: {}, + * } + * ``` + * + * (2) Prop "baseOption" declared: + * If "baseOption" declared, `ECUnitOption` props can only be declared + * inside "baseOption" except prop "timeline" (compat ec2). + * ```js + * option = { + * baseOption: { + * timeline: {}, + * series: [], + * }, + * options: [] + * }; + * option = { + * baseOption: { + * series: [], + * }, + * media: [] + * }; + * option = { + * baseOption: { + * timeline: {}, + * series: [], + * }, + * options: [] + * media: [] + * }; + * option = { + * // ec3 compat ec2: allow (only) `timeline` declared + * // outside baseOption. Keep this setting for compat. + * timeline: {}, + * baseOption: { + * series: [], + * }, + * options: [], + * media: [] + * }; + * ``` + */ + + + function parseRawOption( // `rawOption` May be modified + rawOption, optionPreprocessorFuncs, isNew) { + var mediaList = []; + var mediaDefault; + var baseOption; + var declaredBaseOption = rawOption.baseOption; // Compatible with ec2, [RAW_OPTION_PATTERNS] above. + + var timelineOnRoot = rawOption.timeline; + var timelineOptionsOnRoot = rawOption.options; + var mediaOnRoot = rawOption.media; + var hasMedia = !!rawOption.media; + var hasTimeline = !!(timelineOptionsOnRoot || timelineOnRoot || declaredBaseOption && declaredBaseOption.timeline); + + if (declaredBaseOption) { + baseOption = declaredBaseOption; // For merge option. + + if (!baseOption.timeline) { + baseOption.timeline = timelineOnRoot; + } + } // For convenience, enable to use the root option as the `baseOption`: + // `{ ...normalOptionProps, media: [{ ... }, { ... }] }` + else { + if (hasTimeline || hasMedia) { + rawOption.options = rawOption.media = null; + } + + baseOption = rawOption; + } + + if (hasMedia) { + if (isArray(mediaOnRoot)) { + each$4(mediaOnRoot, function (singleMedia) { + { + // Real case of wrong config. + if (singleMedia && !singleMedia.option && isObject$2(singleMedia.query) && isObject$2(singleMedia.query.option)) { + error('Illegal media option. Must be like { media: [ { query: {}, option: {} } ] }'); + } + } + + if (singleMedia && singleMedia.option) { + if (singleMedia.query) { + mediaList.push(singleMedia); + } else if (!mediaDefault) { + // Use the first media default. + mediaDefault = singleMedia; + } + } + }); + } else { + { + // Real case of wrong config. + error('Illegal media option. Must be an array. Like { media: [ {...}, {...} ] }'); + } + } + } + + doPreprocess(baseOption); + each$4(timelineOptionsOnRoot, function (option) { + return doPreprocess(option); + }); + each$4(mediaList, function (media) { + return doPreprocess(media.option); + }); + + function doPreprocess(option) { + each$4(optionPreprocessorFuncs, function (preProcess) { + preProcess(option, isNew); + }); + } + + return { + baseOption: baseOption, + timelineOptions: timelineOptionsOnRoot || [], + mediaDefault: mediaDefault, + mediaList: mediaList + }; + } + /** + * @see + * Support: width, height, aspectRatio + * Can use max or min as prefix. + */ + + + function applyMediaQuery(query, ecWidth, ecHeight) { + var realMap = { + width: ecWidth, + height: ecHeight, + aspectratio: ecWidth / ecHeight // lower case for convenience. + + }; + var applicable = true; + each$4(query, function (value, attr) { + var matched = attr.match(QUERY_REG); + + if (!matched || !matched[1] || !matched[2]) { + return; + } + + var operator = matched[1]; + var realAttr = matched[2].toLowerCase(); + + if (!compare(realMap[realAttr], value, operator)) { + applicable = false; + } + }); + return applicable; + } + + function compare(real, expect, operator) { + if (operator === 'min') { + return real >= expect; + } else if (operator === 'max') { + return real <= expect; + } else { + // Equals + return real === expect; + } + } + + function indicesEquals(indices1, indices2) { + // indices is always order by asc and has only finite number. + return indices1.join(',') === indices2.join(','); + } + + var each$2 = each$4; + var isObject$1 = isObject$2; + var POSSIBLE_STYLES = ['areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle', 'chordStyle', 'label', 'labelLine']; + + function compatEC2ItemStyle(opt) { + var itemStyleOpt = opt && opt.itemStyle; + + if (!itemStyleOpt) { + return; + } + + for (var i = 0, len = POSSIBLE_STYLES.length; i < len; i++) { + var styleName = POSSIBLE_STYLES[i]; + var normalItemStyleOpt = itemStyleOpt.normal; + var emphasisItemStyleOpt = itemStyleOpt.emphasis; + + if (normalItemStyleOpt && normalItemStyleOpt[styleName]) { + { + deprecateReplaceLog("itemStyle.normal." + styleName, styleName); + } + opt[styleName] = opt[styleName] || {}; + + if (!opt[styleName].normal) { + opt[styleName].normal = normalItemStyleOpt[styleName]; + } else { + merge(opt[styleName].normal, normalItemStyleOpt[styleName]); + } + + normalItemStyleOpt[styleName] = null; + } + + if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) { + { + deprecateReplaceLog("itemStyle.emphasis." + styleName, "emphasis." + styleName); + } + opt[styleName] = opt[styleName] || {}; + + if (!opt[styleName].emphasis) { + opt[styleName].emphasis = emphasisItemStyleOpt[styleName]; + } else { + merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]); + } + + emphasisItemStyleOpt[styleName] = null; + } + } + } + + function convertNormalEmphasis(opt, optType, useExtend) { + if (opt && opt[optType] && (opt[optType].normal || opt[optType].emphasis)) { + var normalOpt = opt[optType].normal; + var emphasisOpt = opt[optType].emphasis; + + if (normalOpt) { + { + // eslint-disable-next-line max-len + deprecateLog("'normal' hierarchy in " + optType + " has been removed since 4.0. All style properties are configured in " + optType + " directly now."); + } // Timeline controlStyle has other properties besides normal and emphasis + + if (useExtend) { + opt[optType].normal = opt[optType].emphasis = null; + defaults(opt[optType], normalOpt); + } else { + opt[optType] = normalOpt; + } + } + + if (emphasisOpt) { + { + deprecateLog(optType + ".emphasis has been changed to emphasis." + optType + " since 4.0"); + } + opt.emphasis = opt.emphasis || {}; + opt.emphasis[optType] = emphasisOpt; // Also compat the case user mix the style and focus together in ec3 style + // for example: { itemStyle: { normal: {}, emphasis: {focus, shadowBlur} } } + + if (emphasisOpt.focus) { + opt.emphasis.focus = emphasisOpt.focus; + } + + if (emphasisOpt.blurScope) { + opt.emphasis.blurScope = emphasisOpt.blurScope; + } + } + } + } + + function removeEC3NormalStatus(opt) { + convertNormalEmphasis(opt, 'itemStyle'); + convertNormalEmphasis(opt, 'lineStyle'); + convertNormalEmphasis(opt, 'areaStyle'); + convertNormalEmphasis(opt, 'label'); + convertNormalEmphasis(opt, 'labelLine'); // treemap + + convertNormalEmphasis(opt, 'upperLabel'); // graph + + convertNormalEmphasis(opt, 'edgeLabel'); + } + + function compatTextStyle(opt, propName) { + // Check whether is not object (string\null\undefined ...) + var labelOptSingle = isObject$1(opt) && opt[propName]; + var textStyle = isObject$1(labelOptSingle) && labelOptSingle.textStyle; + + if (textStyle) { + { + // eslint-disable-next-line max-len + deprecateLog("textStyle hierarchy in " + propName + " has been removed since 4.0. All textStyle properties are configured in " + propName + " directly now."); + } + + for (var i = 0, len = TEXT_STYLE_OPTIONS.length; i < len; i++) { + var textPropName = TEXT_STYLE_OPTIONS[i]; + + if (textStyle.hasOwnProperty(textPropName)) { + labelOptSingle[textPropName] = textStyle[textPropName]; + } + } + } + } + + function compatEC3CommonStyles(opt) { + if (opt) { + removeEC3NormalStatus(opt); + compatTextStyle(opt, 'label'); + opt.emphasis && compatTextStyle(opt.emphasis, 'label'); + } + } + + function processSeries(seriesOpt) { + if (!isObject$1(seriesOpt)) { + return; + } + + compatEC2ItemStyle(seriesOpt); + removeEC3NormalStatus(seriesOpt); + compatTextStyle(seriesOpt, 'label'); // treemap + + compatTextStyle(seriesOpt, 'upperLabel'); // graph + + compatTextStyle(seriesOpt, 'edgeLabel'); + + if (seriesOpt.emphasis) { + compatTextStyle(seriesOpt.emphasis, 'label'); // treemap + + compatTextStyle(seriesOpt.emphasis, 'upperLabel'); // graph + + compatTextStyle(seriesOpt.emphasis, 'edgeLabel'); + } + + var markPoint = seriesOpt.markPoint; + + if (markPoint) { + compatEC2ItemStyle(markPoint); + compatEC3CommonStyles(markPoint); + } + + var markLine = seriesOpt.markLine; + + if (markLine) { + compatEC2ItemStyle(markLine); + compatEC3CommonStyles(markLine); + } + + var markArea = seriesOpt.markArea; + + if (markArea) { + compatEC3CommonStyles(markArea); + } + + var data = seriesOpt.data; // Break with ec3: if `setOption` again, there may be no `type` in option, + // then the backward compat based on option type will not be performed. + + if (seriesOpt.type === 'graph') { + data = data || seriesOpt.nodes; + var edgeData = seriesOpt.links || seriesOpt.edges; + + if (edgeData && !isTypedArray(edgeData)) { + for (var i = 0; i < edgeData.length; i++) { + compatEC3CommonStyles(edgeData[i]); + } + } + + each$4(seriesOpt.categories, function (opt) { + removeEC3NormalStatus(opt); + }); + } + + if (data && !isTypedArray(data)) { + for (var i = 0; i < data.length; i++) { + compatEC3CommonStyles(data[i]); + } + } // mark point data + + + markPoint = seriesOpt.markPoint; + + if (markPoint && markPoint.data) { + var mpData = markPoint.data; + + for (var i = 0; i < mpData.length; i++) { + compatEC3CommonStyles(mpData[i]); + } + } // mark line data + + + markLine = seriesOpt.markLine; + + if (markLine && markLine.data) { + var mlData = markLine.data; + + for (var i = 0; i < mlData.length; i++) { + if (isArray(mlData[i])) { + compatEC3CommonStyles(mlData[i][0]); + compatEC3CommonStyles(mlData[i][1]); + } else { + compatEC3CommonStyles(mlData[i]); + } + } + } // Series + + + if (seriesOpt.type === 'gauge') { + compatTextStyle(seriesOpt, 'axisLabel'); + compatTextStyle(seriesOpt, 'title'); + compatTextStyle(seriesOpt, 'detail'); + } else if (seriesOpt.type === 'treemap') { + convertNormalEmphasis(seriesOpt.breadcrumb, 'itemStyle'); + each$4(seriesOpt.levels, function (opt) { + removeEC3NormalStatus(opt); + }); + } else if (seriesOpt.type === 'tree') { + removeEC3NormalStatus(seriesOpt.leaves); + } // sunburst starts from ec4, so it does not need to compat levels. + + } + + function toArr(o) { + return isArray(o) ? o : o ? [o] : []; + } + + function toObj(o) { + return (isArray(o) ? o[0] : o) || {}; + } + + function globalCompatStyle(option, isTheme) { + each$2(toArr(option.series), function (seriesOpt) { + isObject$1(seriesOpt) && processSeries(seriesOpt); + }); + var axes = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'parallelAxis', 'radar']; + isTheme && axes.push('valueAxis', 'categoryAxis', 'logAxis', 'timeAxis'); + each$2(axes, function (axisName) { + each$2(toArr(option[axisName]), function (axisOpt) { + if (axisOpt) { + compatTextStyle(axisOpt, 'axisLabel'); + compatTextStyle(axisOpt.axisPointer, 'label'); + } + }); + }); + each$2(toArr(option.parallel), function (parallelOpt) { + var parallelAxisDefault = parallelOpt && parallelOpt.parallelAxisDefault; + compatTextStyle(parallelAxisDefault, 'axisLabel'); + compatTextStyle(parallelAxisDefault && parallelAxisDefault.axisPointer, 'label'); + }); + each$2(toArr(option.calendar), function (calendarOpt) { + convertNormalEmphasis(calendarOpt, 'itemStyle'); + compatTextStyle(calendarOpt, 'dayLabel'); + compatTextStyle(calendarOpt, 'monthLabel'); + compatTextStyle(calendarOpt, 'yearLabel'); + }); // radar.name.textStyle + + each$2(toArr(option.radar), function (radarOpt) { + compatTextStyle(radarOpt, 'name'); // Use axisName instead of name because component has name property + + if (radarOpt.name && radarOpt.axisName == null) { + radarOpt.axisName = radarOpt.name; + delete radarOpt.name; + { + deprecateLog('name property in radar component has been changed to axisName'); + } + } + + if (radarOpt.nameGap != null && radarOpt.axisNameGap == null) { + radarOpt.axisNameGap = radarOpt.nameGap; + delete radarOpt.nameGap; + { + deprecateLog('nameGap property in radar component has been changed to axisNameGap'); + } + } + + { + each$2(radarOpt.indicator, function (indicatorOpt) { + if (indicatorOpt.text) { + deprecateReplaceLog('text', 'name', 'radar.indicator'); + } + }); + } + }); + each$2(toArr(option.geo), function (geoOpt) { + if (isObject$1(geoOpt)) { + compatEC3CommonStyles(geoOpt); + each$2(toArr(geoOpt.regions), function (regionObj) { + compatEC3CommonStyles(regionObj); + }); + } + }); + each$2(toArr(option.timeline), function (timelineOpt) { + compatEC3CommonStyles(timelineOpt); + convertNormalEmphasis(timelineOpt, 'label'); + convertNormalEmphasis(timelineOpt, 'itemStyle'); + convertNormalEmphasis(timelineOpt, 'controlStyle', true); + var data = timelineOpt.data; + isArray(data) && each$4(data, function (item) { + if (isObject$2(item)) { + convertNormalEmphasis(item, 'label'); + convertNormalEmphasis(item, 'itemStyle'); + } + }); + }); + each$2(toArr(option.toolbox), function (toolboxOpt) { + convertNormalEmphasis(toolboxOpt, 'iconStyle'); + each$2(toolboxOpt.feature, function (featureOpt) { + convertNormalEmphasis(featureOpt, 'iconStyle'); + }); + }); + compatTextStyle(toObj(option.axisPointer), 'label'); + compatTextStyle(toObj(option.tooltip).axisPointer, 'label'); // Clean logs + // storedLogs = {}; + } + + function get(opt, path) { + var pathArr = path.split(','); + var obj = opt; + + for (var i = 0; i < pathArr.length; i++) { + obj = obj && obj[pathArr[i]]; + + if (obj == null) { + break; + } + } + + return obj; + } + + function set(opt, path, val, overwrite) { + var pathArr = path.split(','); + var obj = opt; + var key; + var i = 0; + + for (; i < pathArr.length - 1; i++) { + key = pathArr[i]; + + if (obj[key] == null) { + obj[key] = {}; + } + + obj = obj[key]; + } + + if (overwrite || obj[pathArr[i]] == null) { + obj[pathArr[i]] = val; + } + } + + function compatLayoutProperties(option) { + option && each$4(LAYOUT_PROPERTIES, function (prop) { + if (prop[0] in option && !(prop[1] in option)) { + option[prop[1]] = option[prop[0]]; + } + }); + } + + var LAYOUT_PROPERTIES = [['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']]; + var COMPATITABLE_COMPONENTS = ['grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline']; + var BAR_ITEM_STYLE_MAP = [['borderRadius', 'barBorderRadius'], ['borderColor', 'barBorderColor'], ['borderWidth', 'barBorderWidth']]; + + function compatBarItemStyle(option) { + var itemStyle = option && option.itemStyle; + + if (itemStyle) { + for (var i = 0; i < BAR_ITEM_STYLE_MAP.length; i++) { + var oldName = BAR_ITEM_STYLE_MAP[i][1]; + var newName = BAR_ITEM_STYLE_MAP[i][0]; + + if (itemStyle[oldName] != null) { + itemStyle[newName] = itemStyle[oldName]; + { + deprecateReplaceLog(oldName, newName); + } + } + } + } + } + + function compatPieLabel(option) { + if (!option) { + return; + } + + if (option.alignTo === 'edge' && option.margin != null && option.edgeDistance == null) { + { + deprecateReplaceLog('label.margin', 'label.edgeDistance', 'pie'); + } + option.edgeDistance = option.margin; + } + } + + function compatSunburstState(option) { + if (!option) { + return; + } + + if (option.downplay && !option.blur) { + option.blur = option.downplay; + { + deprecateReplaceLog('downplay', 'blur', 'sunburst'); + } + } + } + + function compatGraphFocus(option) { + if (!option) { + return; + } + + if (option.focusNodeAdjacency != null) { + option.emphasis = option.emphasis || {}; + + if (option.emphasis.focus == null) { + { + deprecateReplaceLog('focusNodeAdjacency', 'emphasis: { focus: \'adjacency\'}', 'graph/sankey'); + } + option.emphasis.focus = 'adjacency'; + } + } + } + + function traverseTree(data, cb) { + if (data) { + for (var i = 0; i < data.length; i++) { + cb(data[i]); + data[i] && traverseTree(data[i].children, cb); + } + } + } + + function globalBackwardCompat(option, isTheme) { + globalCompatStyle(option, isTheme); // Make sure series array for model initialization. + + option.series = normalizeToArray(option.series); + each$4(option.series, function (seriesOpt) { + if (!isObject$2(seriesOpt)) { + return; + } + + var seriesType = seriesOpt.type; + + if (seriesType === 'line') { + if (seriesOpt.clipOverflow != null) { + seriesOpt.clip = seriesOpt.clipOverflow; + { + deprecateReplaceLog('clipOverflow', 'clip', 'line'); + } + } + } else if (seriesType === 'pie' || seriesType === 'gauge') { + if (seriesOpt.clockWise != null) { + seriesOpt.clockwise = seriesOpt.clockWise; + { + deprecateReplaceLog('clockWise', 'clockwise'); + } + } + + compatPieLabel(seriesOpt.label); + var data = seriesOpt.data; + + if (data && !isTypedArray(data)) { + for (var i = 0; i < data.length; i++) { + compatPieLabel(data[i]); + } + } + + if (seriesOpt.hoverOffset != null) { + seriesOpt.emphasis = seriesOpt.emphasis || {}; + + if (seriesOpt.emphasis.scaleSize = null) { + { + deprecateReplaceLog('hoverOffset', 'emphasis.scaleSize'); + } + seriesOpt.emphasis.scaleSize = seriesOpt.hoverOffset; + } + } + } else if (seriesType === 'gauge') { + var pointerColor = get(seriesOpt, 'pointer.color'); + pointerColor != null && set(seriesOpt, 'itemStyle.color', pointerColor); + } else if (seriesType === 'bar') { + compatBarItemStyle(seriesOpt); + compatBarItemStyle(seriesOpt.backgroundStyle); + compatBarItemStyle(seriesOpt.emphasis); + var data = seriesOpt.data; + + if (data && !isTypedArray(data)) { + for (var i = 0; i < data.length; i++) { + if (typeof data[i] === 'object') { + compatBarItemStyle(data[i]); + compatBarItemStyle(data[i] && data[i].emphasis); + } + } + } + } else if (seriesType === 'sunburst') { + var highlightPolicy = seriesOpt.highlightPolicy; + + if (highlightPolicy) { + seriesOpt.emphasis = seriesOpt.emphasis || {}; + + if (!seriesOpt.emphasis.focus) { + seriesOpt.emphasis.focus = highlightPolicy; + { + deprecateReplaceLog('highlightPolicy', 'emphasis.focus', 'sunburst'); + } + } + } + + compatSunburstState(seriesOpt); + traverseTree(seriesOpt.data, compatSunburstState); + } else if (seriesType === 'graph' || seriesType === 'sankey') { + compatGraphFocus(seriesOpt); // TODO nodes, edges? + } else if (seriesType === 'map') { + if (seriesOpt.mapType && !seriesOpt.map) { + { + deprecateReplaceLog('mapType', 'map', 'map'); + } + seriesOpt.map = seriesOpt.mapType; + } + + if (seriesOpt.mapLocation) { + { + deprecateLog('`mapLocation` is not used anymore.'); + } + defaults(seriesOpt, seriesOpt.mapLocation); + } + } + + if (seriesOpt.hoverAnimation != null) { + seriesOpt.emphasis = seriesOpt.emphasis || {}; + + if (seriesOpt.emphasis && seriesOpt.emphasis.scale == null) { + { + deprecateReplaceLog('hoverAnimation', 'emphasis.scale'); + } + seriesOpt.emphasis.scale = seriesOpt.hoverAnimation; + } + } + + compatLayoutProperties(seriesOpt); + }); // dataRange has changed to visualMap + + if (option.dataRange) { + option.visualMap = option.dataRange; + } + + each$4(COMPATITABLE_COMPONENTS, function (componentName) { + var options = option[componentName]; + + if (options) { + if (!isArray(options)) { + options = [options]; + } + + each$4(options, function (option) { + compatLayoutProperties(option); + }); + } + }); + } // (1) [Caution]: the logic is correct based on the premises: + // data processing stage is blocked in stream. + // See + // (2) Only register once when import repeatedly. + // Should be executed after series is filtered and before stack calculation. + + + function dataStack$1(ecModel) { + var stackInfoMap = createHashMap(); + ecModel.eachSeries(function (seriesModel) { + var stack = seriesModel.get('stack'); // Compatible: when `stack` is set as '', do not stack. + + if (stack) { + var stackInfoList = stackInfoMap.get(stack) || stackInfoMap.set(stack, []); + var data = seriesModel.getData(); + var stackInfo = { + // Used for calculate axis extent automatically. + // TODO: Type getCalculationInfo return more specific type? + stackResultDimension: data.getCalculationInfo('stackResultDimension'), + stackedOverDimension: data.getCalculationInfo('stackedOverDimension'), + stackedDimension: data.getCalculationInfo('stackedDimension'), + stackedByDimension: data.getCalculationInfo('stackedByDimension'), + isStackedByIndex: data.getCalculationInfo('isStackedByIndex'), + data: data, + seriesModel: seriesModel + }; // If stacked on axis that do not support data stack. + + if (!stackInfo.stackedDimension || !(stackInfo.isStackedByIndex || stackInfo.stackedByDimension)) { + return; + } + + stackInfoList.push(stackInfo); + } + }); // Process each stack group + + stackInfoMap.each(function (stackInfoList) { + if (stackInfoList.length === 0) { + return; + } // Check if stack order needs to be reversed + + + var firstSeries = stackInfoList[0].seriesModel; + var stackOrder = firstSeries.get('stackOrder') || 'seriesAsc'; + + if (stackOrder === 'seriesDesc') { + stackInfoList.reverse(); + } // Set stackedOnSeries for each series in the final order + + + each$4(stackInfoList, function (stackInfo, index) { + stackInfo.data.setCalculationInfo('stackedOnSeries', index > 0 ? stackInfoList[index - 1].seriesModel : null); + }); // Calculate stack values + + calculateStack(stackInfoList); + }); + } + + function calculateStack(stackInfoList) { + each$4(stackInfoList, function (targetStackInfo, idxInStack) { + var resultVal = []; + var resultNaN = [NaN, NaN]; + var dims = [targetStackInfo.stackResultDimension, targetStackInfo.stackedOverDimension]; + var targetData = targetStackInfo.data; + var isStackedByIndex = targetStackInfo.isStackedByIndex; + var stackStrategy = targetStackInfo.seriesModel.get('stackStrategy') || 'samesign'; // Should not write on raw data, because stack series model list changes + // depending on legend selection. + + targetData.modify(dims, function (v0, v1, dataIndex) { + var sum = targetData.get(targetStackInfo.stackedDimension, dataIndex); // Consider `connectNulls` of line area, if value is NaN, stackedOver + // should also be NaN, to draw a appropriate belt area. + + if (isNaN(sum)) { + return resultNaN; + } + + var byValue; + var stackedDataRawIndex; + + if (isStackedByIndex) { + stackedDataRawIndex = targetData.getRawIndex(dataIndex); + } else { + byValue = targetData.get(targetStackInfo.stackedByDimension, dataIndex); + } // If stackOver is NaN, chart view will render point on value start. + + + var stackedOver = NaN; + + for (var j = idxInStack - 1; j >= 0; j--) { + var stackInfo = stackInfoList[j]; // Has been optimized by inverted indices on `stackedByDimension`. + + if (!isStackedByIndex) { + stackedDataRawIndex = stackInfo.data.rawIndexOf(stackInfo.stackedByDimension, byValue); + } + + if (stackedDataRawIndex >= 0) { + var val = stackInfo.data.getByRawIndex(stackInfo.stackResultDimension, stackedDataRawIndex); // Considering positive stack, negative stack and empty data + + if (stackStrategy === 'all' // single stack group + || stackStrategy === 'positive' && val > 0 || stackStrategy === 'negative' && val < 0 || stackStrategy === 'samesign' && sum >= 0 && val > 0 // All positive stack + || stackStrategy === 'samesign' && sum <= 0 && val < 0 // All negative stack + ) { + // The sum has to be very small to be affected by the + // floating arithmetic problem. An incorrect result will probably + // cause axis min/max to be filtered incorrectly. + sum = addSafe(sum, val); + stackedOver = val; + break; + } + } + } + + resultVal[0] = sum; + resultVal[1] = stackedOver; + return resultVal; + }); + }); + } // @inner + + + var SourceImpl = + /** @class */ + function () { + function SourceImpl(fields) { + this.data = fields.data || (fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []); + this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN; // Visit config + + this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN; + this.startIndex = fields.startIndex || 0; + this.dimensionsDetectedCount = fields.dimensionsDetectedCount; + this.metaRawOption = fields.metaRawOption; + var dimensionsDefine = this.dimensionsDefine = fields.dimensionsDefine; + + if (dimensionsDefine) { + for (var i = 0; i < dimensionsDefine.length; i++) { + var dim = dimensionsDefine[i]; + + if (dim.type == null) { + if (guessOrdinal(this, i) === BE_ORDINAL.Must) { + dim.type = 'ordinal'; + } + } + } + } + } + + return SourceImpl; + }(); + + function isSourceInstance(val) { + return val instanceof SourceImpl; + } + /** + * Create a source from option. + * NOTE: Created source is immutable. Don't change any properties in it. + */ + + + function createSource(sourceData, thisMetaRawOption, // can be null. If not provided, auto detect it from `sourceData`. + sourceFormat) { + sourceFormat = sourceFormat || detectSourceFormat(sourceData); + var seriesLayoutBy = thisMetaRawOption.seriesLayoutBy; + var determined = determineSourceDimensions(sourceData, sourceFormat, seriesLayoutBy, thisMetaRawOption.sourceHeader, thisMetaRawOption.dimensions); + var source = new SourceImpl({ + data: sourceData, + sourceFormat: sourceFormat, + seriesLayoutBy: seriesLayoutBy, + dimensionsDefine: determined.dimensionsDefine, + startIndex: determined.startIndex, + dimensionsDetectedCount: determined.dimensionsDetectedCount, + metaRawOption: clone$3(thisMetaRawOption) + }); + return source; + } + /** + * Wrap original series data for some compatibility cases. + */ + + + function createSourceFromSeriesDataOption(data) { + return new SourceImpl({ + data: data, + sourceFormat: isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL + }); + } + /** + * Clone source but excludes source data. + */ + + + function cloneSourceShallow(source) { + return new SourceImpl({ + data: source.data, + sourceFormat: source.sourceFormat, + seriesLayoutBy: source.seriesLayoutBy, + dimensionsDefine: clone$3(source.dimensionsDefine), + startIndex: source.startIndex, + dimensionsDetectedCount: source.dimensionsDetectedCount + }); + } + /** + * Note: An empty array will be detected as `SOURCE_FORMAT_ARRAY_ROWS`. + */ + + + function detectSourceFormat(data) { + var sourceFormat = SOURCE_FORMAT_UNKNOWN; + + if (isTypedArray(data)) { + sourceFormat = SOURCE_FORMAT_TYPED_ARRAY; + } else if (isArray(data)) { + // FIXME Whether tolerate null in top level array? + if (data.length === 0) { + sourceFormat = SOURCE_FORMAT_ARRAY_ROWS; + } + + for (var i = 0, len = data.length; i < len; i++) { + var item = data[i]; + + if (item == null) { + continue; + } else if (isArray(item) || isTypedArray(item)) { + sourceFormat = SOURCE_FORMAT_ARRAY_ROWS; + break; + } else if (isObject$2(item)) { + sourceFormat = SOURCE_FORMAT_OBJECT_ROWS; + break; + } + } + } else if (isObject$2(data)) { + for (var key in data) { + if (hasOwn(data, key) && isArrayLike(data[key])) { + sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS; + break; + } + } + } + + return sourceFormat; + } + /** + * Determine the source definitions from data standalone dimensions definitions + * are not specified. + */ + + + function determineSourceDimensions(data, sourceFormat, seriesLayoutBy, sourceHeader, // standalone raw dimensions definition, like: + // { + // dimensions: ['aa', 'bb', { name: 'cc', type: 'time' }] + // } + // in `dataset` or `series` + dimensionsDefine) { + var dimensionsDetectedCount; + var startIndex; // PENDING: Could data be null/undefined here? + // currently, if `dataset.source` not specified, error thrown. + // if `series.data` not specified, nothing rendered without error thrown. + // Should test these cases. + + if (!data) { + return { + dimensionsDefine: normalizeDimensionsOption(dimensionsDefine), + startIndex: startIndex, + dimensionsDetectedCount: dimensionsDetectedCount + }; + } + + if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) { + var dataArrayRows = data; // Rule: Most of the first line are string: it is header. + // Caution: consider a line with 5 string and 1 number, + // it still can not be sure it is a head, because the + // 5 string may be 5 values of category columns. + + if (sourceHeader === 'auto' || sourceHeader == null) { + arrayRowsTravelFirst(function (val) { + // '-' is regarded as null/undefined. + if (val != null && val !== '-') { + if (isString(val)) { + startIndex == null && (startIndex = 1); + } else { + startIndex = 0; + } + } // 10 is an experience number, avoid long loop. + + }, seriesLayoutBy, dataArrayRows, 10); + } else { + startIndex = isNumber(sourceHeader) ? sourceHeader : sourceHeader ? 1 : 0; + } + + if (!dimensionsDefine && startIndex === 1) { + dimensionsDefine = []; + arrayRowsTravelFirst(function (val, index) { + dimensionsDefine[index] = val != null ? val + '' : ''; + }, seriesLayoutBy, dataArrayRows, Infinity); + } + + dimensionsDetectedCount = dimensionsDefine ? dimensionsDefine.length : seriesLayoutBy === SERIES_LAYOUT_BY_ROW ? dataArrayRows.length : dataArrayRows[0] ? dataArrayRows[0].length : null; + } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) { + if (!dimensionsDefine) { + dimensionsDefine = objectRowsCollectDimensions(data); + } + } else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) { + if (!dimensionsDefine) { + dimensionsDefine = []; + each$4(data, function (colArr, key) { + dimensionsDefine.push(key); + }); + } + } else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) { + var value0 = getDataItemValue(data[0]); + dimensionsDetectedCount = isArray(value0) && value0.length || 1; + } else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) { + { + assert(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.'); + } + } + + return { + startIndex: startIndex, + dimensionsDefine: normalizeDimensionsOption(dimensionsDefine), + dimensionsDetectedCount: dimensionsDetectedCount + }; + } + + function objectRowsCollectDimensions(data) { + var firstIndex = 0; + var obj; + + while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line + + + if (obj) { + return keys(obj); + } + } // Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'], + // which is reasonable. But dimension name is duplicated. + // Returns undefined or an array contains only object without null/undefined or string. + + + function normalizeDimensionsOption(dimensionsDefine) { + if (!dimensionsDefine) { + // The meaning of null/undefined is different from empty array. + return; + } + + var nameMap = createHashMap(); + return map$1(dimensionsDefine, function (rawItem, index) { + rawItem = isObject$2(rawItem) ? rawItem : { + name: rawItem + }; // Other fields will be discarded. + + var item = { + name: rawItem.name, + displayName: rawItem.displayName, + type: rawItem.type + }; // User can set null in dimensions. + // We don't auto specify name, otherwise a given name may + // cause it to be referred unexpectedly. + + if (item.name == null) { + return item; + } // Also consider number form like 2012. + + + item.name += ''; // User may also specify displayName. + // displayName will always exists except user not + // specified or dim name is not specified or detected. + // (A auto generated dim name will not be used as + // displayName). + + if (item.displayName == null) { + item.displayName = item.name; + } + + var exist = nameMap.get(item.name); + + if (!exist) { + nameMap.set(item.name, { + count: 1 + }); + } else { + item.name += '-' + exist.count++; + } + + return item; + }); + } + + function arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) { + if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) { + for (var i = 0; i < data.length && i < maxLoop; i++) { + cb(data[i] ? data[i][0] : null, i); + } + } else { + var value0 = data[0] || []; + + for (var i = 0; i < value0.length && i < maxLoop; i++) { + cb(value0[i], i); + } + } + } + + function shouldRetrieveDataByName(source) { + var sourceFormat = source.sourceFormat; + return sourceFormat === SOURCE_FORMAT_OBJECT_ROWS || sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS; + } + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + var _a, _b, _c, _d; + + var providerMethods; + var mountMethods; + /** + * If normal array used, mutable chunk size is supported. + * If typed array used, chunk size must be fixed. + */ + + var DefaultDataProvider = + /** @class */ + function () { + function DefaultDataProvider(sourceParam, dimSize) { + // let source: Source; + var source = !isSourceInstance(sourceParam) ? createSourceFromSeriesDataOption(sourceParam) : sourceParam; // declare source is Source; + + this._source = source; + var data = this._data = source.data; + var sourceFormat = source.sourceFormat; + var seriesLayoutBy = source.seriesLayoutBy; // Typed array. TODO IE10+? + + if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) { + { + if (dimSize == null) { + throw new Error('Typed array data must specify dimension size'); + } + } + this._offset = 0; + this._dimSize = dimSize; + this._data = data; + } + + { + var validator = rawSourceDataValidatorMap[getMethodMapKey(sourceFormat, seriesLayoutBy)]; + validator && validator(data, source.dimensionsDefine); + } + mountMethods(this, data, source); + } + + DefaultDataProvider.prototype.getSource = function () { + return this._source; + }; + + DefaultDataProvider.prototype.count = function () { + return 0; + }; + + DefaultDataProvider.prototype.getItem = function (idx, out) { + return; + }; + + DefaultDataProvider.prototype.appendData = function (newData) {}; + + DefaultDataProvider.prototype.clean = function () {}; + + DefaultDataProvider.protoInitialize = function () { + // PENDING: To avoid potential incompat (e.g., prototype + // is visited somewhere), still init them on prototype. + var proto = DefaultDataProvider.prototype; + proto.pure = false; + proto.persistent = true; + }(); + + DefaultDataProvider.internalField = function () { + var _a; + + mountMethods = function (provider, data, source) { + var sourceFormat = source.sourceFormat; + var seriesLayoutBy = source.seriesLayoutBy; + var startIndex = source.startIndex; + var dimsDef = source.dimensionsDefine; + var methods = providerMethods[getMethodMapKey(sourceFormat, seriesLayoutBy)]; + { + assert(methods, 'Invalide sourceFormat: ' + sourceFormat); + } + extend(provider, methods); + + if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) { + provider.getItem = getItemForTypedArray; + provider.count = countForTypedArray; + provider.fillStorage = fillStorageForTypedArray; + } else { + var rawItemGetter = getRawSourceItemGetter(sourceFormat, seriesLayoutBy); + provider.getItem = bind$1(rawItemGetter, null, data, startIndex, dimsDef); + var rawCounter = getRawSourceDataCounter(sourceFormat, seriesLayoutBy); + provider.count = bind$1(rawCounter, null, data, startIndex, dimsDef); + } + }; + + var getItemForTypedArray = function (idx, out) { + idx = idx - this._offset; + out = out || []; + var data = this._data; + var dimSize = this._dimSize; + var offset = dimSize * idx; + + for (var i = 0; i < dimSize; i++) { + out[i] = data[offset + i]; + } + + return out; + }; + + var fillStorageForTypedArray = function (start, end, storage, extent) { + var data = this._data; + var dimSize = this._dimSize; + + for (var dim = 0; dim < dimSize; dim++) { + var dimExtent = extent[dim]; + var min = dimExtent[0] == null ? Infinity : dimExtent[0]; + var max = dimExtent[1] == null ? -Infinity : dimExtent[1]; + var count = end - start; + var arr = storage[dim]; + + for (var i = 0; i < count; i++) { + // appendData with TypedArray will always do replace in provider. + var val = data[i * dimSize + dim]; + arr[start + i] = val; + val < min && (min = val); + val > max && (max = val); + } + + dimExtent[0] = min; + dimExtent[1] = max; + } + }; + + var countForTypedArray = function () { + return this._data ? this._data.length / this._dimSize : 0; + }; + + providerMethods = (_a = {}, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = { + pure: true, + appendData: appendDataSimply + }, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = { + pure: true, + appendData: function () { + throw new Error('Do not support appendData when set seriesLayoutBy: "row".'); + } + }, _a[SOURCE_FORMAT_OBJECT_ROWS] = { + pure: true, + appendData: appendDataSimply + }, _a[SOURCE_FORMAT_KEYED_COLUMNS] = { + pure: true, + appendData: function (newData) { + var data = this._data; + each$4(newData, function (newCol, key) { + var oldCol = data[key] || (data[key] = []); + + for (var i = 0; i < (newCol || []).length; i++) { + oldCol.push(newCol[i]); + } + }); + } + }, _a[SOURCE_FORMAT_ORIGINAL] = { + appendData: appendDataSimply + }, _a[SOURCE_FORMAT_TYPED_ARRAY] = { + persistent: false, + pure: true, + appendData: function (newData) { + { + assert(isTypedArray(newData), 'Added data must be TypedArray if data in initialization is TypedArray'); + } + this._data = newData; + }, + // Clean self if data is already used. + clean: function () { + // PENDING + this._offset += this.count(); + this._data = null; + } + }, _a); + + function appendDataSimply(newData) { + for (var i = 0; i < newData.length; i++) { + this._data.push(newData[i]); + } + } + }(); + + return DefaultDataProvider; + }(); + + var validateSimply = function (rawData) { + if (!isArray(rawData)) { + error('series.data or dataset.source must be an array.'); + } + }; + /** + * Only run in dev mode - hint users for debug. + */ + + + var rawSourceDataValidatorMap = (_a = {}, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = validateSimply, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = validateSimply, _a[SOURCE_FORMAT_OBJECT_ROWS] = validateSimply, _a[SOURCE_FORMAT_KEYED_COLUMNS] = function (rawData, dimsDef) { + for (var i = 0; i < dimsDef.length; i++) { + var dimName = dimsDef[i].name; + + if (dimName == null) { + error('dimension name must not be null/undefined.'); + } + } + }, _a[SOURCE_FORMAT_ORIGINAL] = validateSimply, _a); + + var getItemSimply = function (rawData, startIndex, dimsDef, idx) { + return rawData[idx]; + }; + + var rawSourceItemGetterMap = (_b = {}, _b[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = function (rawData, startIndex, dimsDef, idx) { + return rawData[idx + startIndex]; + }, _b[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = function (rawData, startIndex, dimsDef, idx, out) { + idx += startIndex; + var item = out || []; + var data = rawData; + + for (var i = 0; i < data.length; i++) { + var row = data[i]; + item[i] = row ? row[idx] : null; + } + + return item; + }, _b[SOURCE_FORMAT_OBJECT_ROWS] = getItemSimply, _b[SOURCE_FORMAT_KEYED_COLUMNS] = function (rawData, startIndex, dimsDef, idx, out) { + var item = out || []; + + for (var i = 0; i < dimsDef.length; i++) { + var dimName = dimsDef[i].name; + var col = dimName != null ? rawData[dimName] : null; + item[i] = col ? col[idx] : null; + } + + return item; + }, _b[SOURCE_FORMAT_ORIGINAL] = getItemSimply, _b); + + function getRawSourceItemGetter(sourceFormat, seriesLayoutBy) { + var method = rawSourceItemGetterMap[getMethodMapKey(sourceFormat, seriesLayoutBy)]; + { + assert(method, 'Do not support get item on "' + sourceFormat + '", "' + seriesLayoutBy + '".'); + } + return method; + } + + var countSimply = function (rawData, startIndex, dimsDef) { + return rawData.length; + }; + + var rawSourceDataCounterMap = (_c = {}, _c[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = function (rawData, startIndex, dimsDef) { + return Math.max(0, rawData.length - startIndex); + }, _c[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = function (rawData, startIndex, dimsDef) { + var row = rawData[0]; + return row ? Math.max(0, row.length - startIndex) : 0; + }, _c[SOURCE_FORMAT_OBJECT_ROWS] = countSimply, _c[SOURCE_FORMAT_KEYED_COLUMNS] = function (rawData, startIndex, dimsDef) { + var dimName = dimsDef[0].name; + var col = dimName != null ? rawData[dimName] : null; + return col ? col.length : 0; + }, _c[SOURCE_FORMAT_ORIGINAL] = countSimply, _c); + + function getRawSourceDataCounter(sourceFormat, seriesLayoutBy) { + var method = rawSourceDataCounterMap[getMethodMapKey(sourceFormat, seriesLayoutBy)]; + { + assert(method, 'Do not support count on "' + sourceFormat + '", "' + seriesLayoutBy + '".'); + } + return method; + } + + var getRawValueSimply = function (dataItem, dimIndex, property) { + return dataItem[dimIndex]; + }; + + var rawSourceValueGetterMap = (_d = {}, _d[SOURCE_FORMAT_ARRAY_ROWS] = getRawValueSimply, _d[SOURCE_FORMAT_OBJECT_ROWS] = function (dataItem, dimIndex, property) { + return dataItem[property]; + }, _d[SOURCE_FORMAT_KEYED_COLUMNS] = getRawValueSimply, _d[SOURCE_FORMAT_ORIGINAL] = function (dataItem, dimIndex, property) { + // FIXME: In some case (markpoint in geo (geo-map.html)), + // dataItem is {coord: [...]} + var value = getDataItemValue(dataItem); + return !(value instanceof Array) ? value : value[dimIndex]; + }, _d[SOURCE_FORMAT_TYPED_ARRAY] = getRawValueSimply, _d); + + function getRawSourceValueGetter(sourceFormat) { + var method = rawSourceValueGetterMap[sourceFormat]; + { + assert(method, 'Do not support get value on "' + sourceFormat + '".'); + } + return method; + } + + function getMethodMapKey(sourceFormat, seriesLayoutBy) { + return sourceFormat === SOURCE_FORMAT_ARRAY_ROWS ? sourceFormat + '_' + seriesLayoutBy : sourceFormat; + } // ??? FIXME can these logic be more neat: getRawValue, getRawDataItem, + // Consider persistent. + // Caution: why use raw value to display on label or tooltip? + // A reason is to avoid format. For example time value we do not know + // how to format is expected. More over, if stack is used, calculated + // value may be 0.91000000001, which have brings trouble to display. + // TODO: consider how to treat null/undefined/NaN when display? + + + function retrieveRawValue(data, dataIndex, // If dimIndex is null/undefined, return OptionDataItem. + // Otherwise, return OptionDataValue. + dim) { + if (!data) { + return; + } // Consider data may be not persistent. + + + var dataItem = data.getRawDataItem(dataIndex); + + if (dataItem == null) { + return; + } + + var store = data.getStore(); + var sourceFormat = store.getSource().sourceFormat; + + if (dim != null) { + var dimIndex = data.getDimensionIndex(dim); + var property = store.getDimensionProperty(dimIndex); + return getRawSourceValueGetter(sourceFormat)(dataItem, dimIndex, property); + } else { + var result = dataItem; + + if (sourceFormat === SOURCE_FORMAT_ORIGINAL) { + result = getDataItemValue(dataItem); + } + + return result; + } + } + + var DIMENSION_LABEL_REG = /\{@(.+?)\}/g; + + var DataFormatMixin = + /** @class */ + function () { + function DataFormatMixin() {} + /** + * Get params for formatter + */ + + + DataFormatMixin.prototype.getDataParams = function (dataIndex, dataType) { + var data = this.getData(dataType); + var rawValue = this.getRawValue(dataIndex, dataType); + var rawDataIndex = data.getRawIndex(dataIndex); + var name = data.getName(dataIndex); + var itemOpt = data.getRawDataItem(dataIndex); + var style = data.getItemVisual(dataIndex, 'style'); + var color = style && style[data.getItemVisual(dataIndex, 'drawType') || 'fill']; + var borderColor = style && style.stroke; + var mainType = this.mainType; + var isSeries = mainType === 'series'; + var userOutput = data.userOutput && data.userOutput.get(); + return { + componentType: mainType, + componentSubType: this.subType, + componentIndex: this.componentIndex, + seriesType: isSeries ? this.subType : null, + seriesIndex: this.seriesIndex, + seriesId: isSeries ? this.id : null, + seriesName: isSeries ? this.name : null, + name: name, + dataIndex: rawDataIndex, + data: itemOpt, + dataType: dataType, + value: rawValue, + color: color, + borderColor: borderColor, + dimensionNames: userOutput ? userOutput.fullDimensions : null, + encode: userOutput ? userOutput.encode : null, + // Param name list for mapping `a`, `b`, `c`, `d`, `e` + $vars: ['seriesName', 'name', 'value'] + }; + }; + /** + * Format label + * @param dataIndex + * @param status 'normal' by default + * @param dataType + * @param labelDimIndex Only used in some chart that + * use formatter in different dimensions, like radar. + * @param formatter Formatter given outside. + * @return return null/undefined if no formatter + */ + + + DataFormatMixin.prototype.getFormattedLabel = function (dataIndex, status, dataType, labelDimIndex, formatter, extendParams) { + status = status || 'normal'; + var data = this.getData(dataType); + var params = this.getDataParams(dataIndex, dataType); + + if (extendParams) { + params.value = extendParams.interpolatedValue; + } + + if (labelDimIndex != null && isArray(params.value)) { + params.value = params.value[labelDimIndex]; + } + + if (!formatter) { + var itemModel = data.getItemModel(dataIndex); // @ts-ignore + + formatter = itemModel.get(status === 'normal' ? ['label', 'formatter'] : [status, 'label', 'formatter']); + } + + if (isFunction(formatter)) { + params.status = status; + params.dimensionIndex = labelDimIndex; + return formatter(params); + } else if (isString(formatter)) { + var str = formatTpl(formatter, params); // Support 'aaa{@[3]}bbb{@product}ccc'. + // Do not support '}' in dim name util have to. + + return str.replace(DIMENSION_LABEL_REG, function (origin, dimStr) { + var len = dimStr.length; + var dimLoose = dimStr; + + if (dimLoose.charAt(0) === '[' && dimLoose.charAt(len - 1) === ']') { + dimLoose = +dimLoose.slice(1, len - 1); // Also support: '[]' => 0 + + { + if (isNaN(dimLoose)) { + error("Invalide label formatter: @" + dimStr + ", only support @[0], @[1], @[2], ..."); + } + } + } + + var val = retrieveRawValue(data, dataIndex, dimLoose); + + if (extendParams && isArray(extendParams.interpolatedValue)) { + var dimIndex = data.getDimensionIndex(dimLoose); + + if (dimIndex >= 0) { + val = extendParams.interpolatedValue[dimIndex]; + } + } + + return val != null ? val + '' : ''; + }); + } + }; + /** + * Get raw value in option + */ + + + DataFormatMixin.prototype.getRawValue = function (idx, dataType) { + return retrieveRawValue(this.getData(dataType), idx); + }; + /** + * Should be implemented. + * @param {number} dataIndex + * @param {boolean} [multipleSeries=false] + * @param {string} [dataType] + */ + + + DataFormatMixin.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + // Empty function + return; + }; + + return DataFormatMixin; + }(); // PENDING: previously we accept this type when calling `formatTooltip`, + // but guess little chance has been used outside. Do we need to backward + // compat it? + // type TooltipFormatResultLegacyObject = { + // // `html` means the markup language text, either in 'html' or 'richText'. + // // The name `html` is not appropriate because in 'richText' it is not a HTML + // // string. But still support it for backward compatibility. + // html: string; + // markers: Dictionary; + // }; + + /** + * For backward compat, normalize the return from `formatTooltip`. + */ + + + function normalizeTooltipFormatResult(result) { + var markupText; // let markers: Dictionary; + + var markupFragment; + + if (isObject$2(result)) { + if (result.type) { + markupFragment = result; + } else { + { + console.warn('The return type of `formatTooltip` is not supported: ' + makePrintable(result)); + } + } // else { + // markupText = (result as TooltipFormatResultLegacyObject).html; + // markers = (result as TooltipFormatResultLegacyObject).markers; + // if (markersExisting) { + // markers = zrUtil.merge(markersExisting, markers); + // } + // } + + } else { + markupText = result; + } + + return { + text: markupText, + // markers: markers || markersExisting, + frag: markupFragment + }; + } + /** + * @param {Object} define + * @return See the return of `createTask`. + */ + + + function createTask(define) { + return new Task(define); + } + + var Task = + /** @class */ + function () { + function Task(define) { + define = define || {}; + this._reset = define.reset; + this._plan = define.plan; + this._count = define.count; + this._onDirty = define.onDirty; + this._dirty = true; + } + /** + * @param step Specified step. + * @param skip Skip customer perform call. + * @param modBy Sampling window size. + * @param modDataCount Sampling count. + * @return whether unfinished. + */ + + + Task.prototype.perform = function (performArgs) { + var upTask = this._upstream; + var skip = performArgs && performArgs.skip; // TODO some refactor. + // Pull data. Must pull data each time, because context.data + // may be updated by Series.setData. + + if (this._dirty && upTask) { + var context = this.context; + context.data = context.outputData = upTask.context.outputData; + } + + if (this.__pipeline) { + this.__pipeline.currentTask = this; + } + + var planResult; + + if (this._plan && !skip) { + planResult = this._plan(this.context); + } // Support sharding by mod, which changes the render sequence and makes the rendered graphic + // elements uniformed distributed when progress, especially when moving or zooming. + + + var lastModBy = normalizeModBy(this._modBy); + var lastModDataCount = this._modDataCount || 0; + var modBy = normalizeModBy(performArgs && performArgs.modBy); + var modDataCount = performArgs && performArgs.modDataCount || 0; + + if (lastModBy !== modBy || lastModDataCount !== modDataCount) { + planResult = 'reset'; + } + + function normalizeModBy(val) { + !(val >= 1) && (val = 1); // jshint ignore:line + + return val; + } + + var forceFirstProgress; + + if (this._dirty || planResult === 'reset') { + this._dirty = false; + forceFirstProgress = this._doReset(skip); + } + + this._modBy = modBy; + this._modDataCount = modDataCount; + var step = performArgs && performArgs.step; + + if (upTask) { + { + assert(upTask._outputDueEnd != null); + } + this._dueEnd = upTask._outputDueEnd; + } // DataTask or overallTask + else { + { + assert(!this._progress || this._count); + } + this._dueEnd = this._count ? this._count(this.context) : Infinity; + } // Note: Stubs, that its host overall task let it has progress, has progress. + // If no progress, pass index from upstream to downstream each time plan called. + + + if (this._progress) { + var start = this._dueIndex; + var end = Math.min(step != null ? this._dueIndex + step : Infinity, this._dueEnd); + + if (!skip && (forceFirstProgress || start < end)) { + var progress = this._progress; + + if (isArray(progress)) { + for (var i = 0; i < progress.length; i++) { + this._doProgress(progress[i], start, end, modBy, modDataCount); + } + } else { + this._doProgress(progress, start, end, modBy, modDataCount); + } + } + + this._dueIndex = end; // If no `outputDueEnd`, assume that output data and + // input data is the same, so use `dueIndex` as `outputDueEnd`. + + var outputDueEnd = this._settedOutputEnd != null ? this._settedOutputEnd : end; + { + // ??? Can not rollback. + assert(outputDueEnd >= this._outputDueEnd); + } + this._outputDueEnd = outputDueEnd; + } else { + // (1) Some overall task has no progress. + // (2) Stubs, that its host overall task do not let it has progress, has no progress. + // This should always be performed so it can be passed to downstream. + this._dueIndex = this._outputDueEnd = this._settedOutputEnd != null ? this._settedOutputEnd : this._dueEnd; + } + + return this.unfinished(); + }; + + Task.prototype.dirty = function () { + this._dirty = true; + this._onDirty && this._onDirty(this.context); + }; + + Task.prototype._doProgress = function (progress, start, end, modBy, modDataCount) { + iterator.reset(start, end, modBy, modDataCount); + this._callingProgress = progress; + + this._callingProgress({ + start: start, + end: end, + count: end - start, + next: iterator.next + }, this.context); + }; + + Task.prototype._doReset = function (skip) { + this._dueIndex = this._outputDueEnd = this._dueEnd = 0; + this._settedOutputEnd = null; + var progress; + var forceFirstProgress; + + if (!skip && this._reset) { + progress = this._reset(this.context); + + if (progress && progress.progress) { + forceFirstProgress = progress.forceFirstProgress; + progress = progress.progress; + } // To simplify no progress checking, array must has item. + + + if (isArray(progress) && !progress.length) { + progress = null; + } + } + + this._progress = progress; + this._modBy = this._modDataCount = null; + var downstream = this._downstream; + downstream && downstream.dirty(); + return forceFirstProgress; + }; + + Task.prototype.unfinished = function () { + return this._progress && this._dueIndex < this._dueEnd; + }; + /** + * @param downTask The downstream task. + * @return The downstream task. + */ + + + Task.prototype.pipe = function (downTask) { + { + assert(downTask && !downTask._disposed && downTask !== this); + } // If already downstream, do not dirty downTask. + + if (this._downstream !== downTask || this._dirty) { + this._downstream = downTask; + downTask._upstream = this; + downTask.dirty(); + } + }; + + Task.prototype.dispose = function () { + if (this._disposed) { + return; + } + + this._upstream && (this._upstream._downstream = null); + this._downstream && (this._downstream._upstream = null); + this._dirty = false; + this._disposed = true; + }; + + Task.prototype.getUpstream = function () { + return this._upstream; + }; + + Task.prototype.getDownstream = function () { + return this._downstream; + }; + + Task.prototype.setOutputEnd = function (end) { + // This only happens in dataTask, dataZoom, map, currently. + // where dataZoom do not set end each time, but only set + // when reset. So we should record the set end, in case + // that the stub of dataZoom perform again and earse the + // set end by upstream. + this._outputDueEnd = this._settedOutputEnd = end; + }; + + return Task; + }(); + + var iterator = function () { + var end; + var current; + var modBy; + var modDataCount; + var winCount; + var it = { + reset: function (s, e, sStep, sCount) { + current = s; + end = e; + modBy = sStep; + modDataCount = sCount; + winCount = Math.ceil(modDataCount / modBy); + it.next = modBy > 1 && modDataCount > 0 ? modNext : sequentialNext; + } + }; + return it; + + function sequentialNext() { + return current < end ? current++ : null; + } + + function modNext() { + var dataIndex = current % winCount * modBy + Math.ceil(current / winCount); + var result = current >= end ? null : dataIndex < modDataCount ? dataIndex // If modDataCount is smaller than data.count() (consider `appendData` case), + // Use normal linear rendering mode. + : current; + current++; + return result; + } + }(); // ----------------------------------------------------------------------------- + // For stream debug (Should be commented out after used!) + // @usage: printTask(this, 'begin'); + // @usage: printTask(this, null, {someExtraProp}); + // @usage: Use `__idxInPipeline` as conditional breakpiont. + // + // window.printTask = function (task: any, prefix: string, extra: { [key: string]: unknown }): void { + // window.ecTaskUID == null && (window.ecTaskUID = 0); + // task.uidDebug == null && (task.uidDebug = `task_${window.ecTaskUID++}`); + // task.agent && task.agent.uidDebug == null && (task.agent.uidDebug = `task_${window.ecTaskUID++}`); + // let props = []; + // if (task.__pipeline) { + // let val = `${task.__idxInPipeline}/${task.__pipeline.tail.__idxInPipeline} ${task.agent ? '(stub)' : ''}`; + // props.push({text: '__idxInPipeline/total', value: val}); + // } else { + // let stubCount = 0; + // task.agentStubMap.each(() => stubCount++); + // props.push({text: 'idx', value: `overall (stubs: ${stubCount})`}); + // } + // props.push({text: 'uid', value: task.uidDebug}); + // if (task.__pipeline) { + // props.push({text: 'pipelineId', value: task.__pipeline.id}); + // task.agent && props.push( + // {text: 'stubFor', value: task.agent.uidDebug} + // ); + // } + // props.push( + // {text: 'dirty', value: task._dirty}, + // {text: 'dueIndex', value: task._dueIndex}, + // {text: 'dueEnd', value: task._dueEnd}, + // {text: 'outputDueEnd', value: task._outputDueEnd} + // ); + // if (extra) { + // Object.keys(extra).forEach(key => { + // props.push({text: key, value: extra[key]}); + // }); + // } + // let args = ['color: blue']; + // let msg = `%c[${prefix || 'T'}] %c` + props.map(item => ( + // args.push('color: green', 'color: red'), + // `${item.text}: %c${item.value}` + // )).join('%c, '); + // console.log.apply(console, [msg].concat(args)); + // // console.log(this); + // }; + // window.printPipeline = function (task: any, prefix: string) { + // const pipeline = task.__pipeline; + // let currTask = pipeline.head; + // while (currTask) { + // window.printTask(currTask, prefix); + // currTask = currTask._downstream; + // } + // }; + // window.showChain = function (chainHeadTask) { + // var chain = []; + // var task = chainHeadTask; + // while (task) { + // chain.push({ + // task: task, + // up: task._upstream, + // down: task._downstream, + // idxInPipeline: task.__idxInPipeline + // }); + // task = task._downstream; + // } + // return chain; + // }; + // window.findTaskInChain = function (task, chainHeadTask) { + // let chain = window.showChain(chainHeadTask); + // let result = []; + // for (let i = 0; i < chain.length; i++) { + // let chainItem = chain[i]; + // if (chainItem.task === task) { + // result.push(i); + // } + // } + // return result; + // }; + // window.printChainAEachInChainB = function (chainHeadTaskA, chainHeadTaskB) { + // let chainA = window.showChain(chainHeadTaskA); + // for (let i = 0; i < chainA.length; i++) { + // console.log('chainAIdx:', i, 'inChainB:', window.findTaskInChain(chainA[i].task, chainHeadTaskB)); + // } + // }; + + /** + * Convert raw the value in to inner value in List. + * + * [Performance sensitive] + * + * [Caution]: this is the key logic of user value parser. + * For backward compatibility, do not modify it until you have to! + */ + + + function parseDataValue(value, // For high performance, do not omit the second param. + opt) { + // Performance sensitive. + var dimType = opt && opt.type; + + if (dimType === 'ordinal') { + // If given value is a category string + return value; + } + + if (dimType === 'time' // spead up when using timestamp + && !isNumber(value) && value != null && value !== '-') { + value = +parseDate(value); + } // dimType defaults 'number'. + // If dimType is not ordinal and value is null or undefined or NaN or '-', + // parse to NaN. + // number-like string (like ' 123 ') can be converted to a number. + // where null/undefined or other string will be converted to NaN. + + + return value == null || value === '' ? NaN // If string (like '-'), using '+' parse to NaN + // If object, also parse to NaN + : Number(value); + } + + var valueParserMap = createHashMap({ + 'number': function (val) { + // Do not use `numericToNumber` here. We have `numericToNumber` by default. + // Here the number parser can have loose rule: + // enable to cut suffix: "120px" => 120, "14%" => 14. + return parseFloat(val); + }, + 'time': function (val) { + // return timestamp. + return +parseDate(val); + }, + 'trim': function (val) { + return isString(val) ? trim(val) : val; + } + }); + + function getRawValueParser(type) { + return valueParserMap.get(type); + } + + var ORDER_COMPARISON_OP_MAP = { + lt: function (lval, rval) { + return lval < rval; + }, + lte: function (lval, rval) { + return lval <= rval; + }, + gt: function (lval, rval) { + return lval > rval; + }, + gte: function (lval, rval) { + return lval >= rval; + } + }; + + var FilterOrderComparator = + /** @class */ + function () { + function FilterOrderComparator(op, rval) { + if (!isNumber(rval)) { + var errMsg = ''; + { + errMsg = 'rvalue of "<", ">", "<=", ">=" can only be number in filter.'; + } + throwError(errMsg); + } + + this._opFn = ORDER_COMPARISON_OP_MAP[op]; + this._rvalFloat = numericToNumber(rval); + } // Performance sensitive. + + + FilterOrderComparator.prototype.evaluate = function (lval) { + // Most cases is 'number', and typeof maybe 10 times faseter than parseFloat. + return isNumber(lval) ? this._opFn(lval, this._rvalFloat) : this._opFn(numericToNumber(lval), this._rvalFloat); + }; + + return FilterOrderComparator; + }(); + + var SortOrderComparator = + /** @class */ + function () { + /** + * @param order by default: 'asc' + * @param incomparable by default: Always on the tail. + * That is, if 'asc' => 'max', if 'desc' => 'min' + * See the definition of "incomparable" in [SORT_COMPARISON_RULE]. + */ + function SortOrderComparator(order, incomparable) { + var isDesc = order === 'desc'; + this._resultLT = isDesc ? 1 : -1; + + if (incomparable == null) { + incomparable = isDesc ? 'min' : 'max'; + } + + this._incomparable = incomparable === 'min' ? -Infinity : Infinity; + } // See [SORT_COMPARISON_RULE]. + // Performance sensitive. + + + SortOrderComparator.prototype.evaluate = function (lval, rval) { + // Most cases is 'number', and typeof maybe 10 times faseter than parseFloat. + var lvalFloat = isNumber(lval) ? lval : numericToNumber(lval); + var rvalFloat = isNumber(rval) ? rval : numericToNumber(rval); + var lvalNotNumeric = isNaN(lvalFloat); + var rvalNotNumeric = isNaN(rvalFloat); + + if (lvalNotNumeric) { + lvalFloat = this._incomparable; + } + + if (rvalNotNumeric) { + rvalFloat = this._incomparable; + } + + if (lvalNotNumeric && rvalNotNumeric) { + var lvalIsStr = isString(lval); + var rvalIsStr = isString(rval); + + if (lvalIsStr) { + lvalFloat = rvalIsStr ? lval : 0; + } + + if (rvalIsStr) { + rvalFloat = lvalIsStr ? rval : 0; + } + } + + return lvalFloat < rvalFloat ? this._resultLT : lvalFloat > rvalFloat ? -this._resultLT : 0; + }; + + return SortOrderComparator; + }(); + + var FilterEqualityComparator = + /** @class */ + function () { + function FilterEqualityComparator(isEq, rval) { + this._rval = rval; + this._isEQ = isEq; + this._rvalTypeof = typeof rval; + this._rvalFloat = numericToNumber(rval); + } // Performance sensitive. + + + FilterEqualityComparator.prototype.evaluate = function (lval) { + var eqResult = lval === this._rval; + + if (!eqResult) { + var lvalTypeof = typeof lval; + + if (lvalTypeof !== this._rvalTypeof && (lvalTypeof === 'number' || this._rvalTypeof === 'number')) { + eqResult = numericToNumber(lval) === this._rvalFloat; + } + } + + return this._isEQ ? eqResult : !eqResult; + }; + + return FilterEqualityComparator; + }(); + /** + * [FILTER_COMPARISON_RULE] + * `lt`|`lte`|`gt`|`gte`: + * + rval must be a number. And lval will be converted to number (`numericToNumber`) to compare. + * `eq`: + * + If same type, compare with `===`. + * + If there is one number, convert to number (`numericToNumber`) to compare. + * + Else return `false`. + * `ne`: + * + Not `eq`. + * + * + * [SORT_COMPARISON_RULE] + * All the values are grouped into three categories: + * + "numeric" (number and numeric string) + * + "non-numeric-string" (string that excluding numeric string) + * + "others" + * "numeric" vs "numeric": values are ordered by number order. + * "non-numeric-string" vs "non-numeric-string": values are ordered by ES spec (#sec-abstract-relational-comparison). + * "others" vs "others": do not change order (always return 0). + * "numeric" vs "non-numeric-string": "non-numeric-string" is treated as "incomparable". + * "number" vs "others": "others" is treated as "incomparable". + * "non-numeric-string" vs "others": "others" is treated as "incomparable". + * "incomparable" will be seen as -Infinity or Infinity (depends on the settings). + * MEMO: + * Non-numeric string sort makes sense when we need to put the items with the same tag together. + * But if we support string sort, we still need to avoid the misleading like `'2' > '12'`, + * So we treat "numeric-string" sorted by number order rather than string comparison. + * + * + * [CHECK_LIST_OF_THE_RULE_DESIGN] + * + Do not support string comparison until required. And also need to + * avoid the misleading of "2" > "12". + * + Should avoid the misleading case: + * `" 22 " gte "22"` is `true` but `" 22 " eq "22"` is `false`. + * + JS bad case should be avoided: null <= 0, [] <= 0, ' ' <= 0, ... + * + Only "numeric" can be converted to comparable number, otherwise converted to NaN. + * See `util/number.ts#numericToNumber`. + * + * @return If `op` is not `RelationalOperator`, return null; + */ + + + function createFilterComparator(op, rval) { + return op === 'eq' || op === 'ne' ? new FilterEqualityComparator(op === 'eq', rval) : hasOwn(ORDER_COMPARISON_OP_MAP, op) ? new FilterOrderComparator(op, rval) : null; + } + /** + * TODO: disable writable. + * This structure will be exposed to users. + */ + + + var ExternalSource = + /** @class */ + function () { + function ExternalSource() {} + + ExternalSource.prototype.getRawData = function () { + // Only built-in transform available. + throw new Error('not supported'); + }; + + ExternalSource.prototype.getRawDataItem = function (dataIndex) { + // Only built-in transform available. + throw new Error('not supported'); + }; + + ExternalSource.prototype.cloneRawData = function () { + return; + }; + /** + * @return If dimension not found, return null/undefined. + */ + + + ExternalSource.prototype.getDimensionInfo = function (dim) { + return; + }; + /** + * dimensions defined if and only if either: + * (a) dataset.dimensions are declared. + * (b) dataset data include dimensions definitions in data (detected or via specified `sourceHeader`). + * If dimensions are defined, `dimensionInfoAll` is corresponding to + * the defined dimensions. + * Otherwise, `dimensionInfoAll` is determined by data columns. + * @return Always return an array (even empty array). + */ + + + ExternalSource.prototype.cloneAllDimensionInfo = function () { + return; + }; + + ExternalSource.prototype.count = function () { + return; + }; + /** + * Only support by dimension index. + * No need to support by dimension name in transform function, + * because transform function is not case-specific, no need to use name literally. + */ + + + ExternalSource.prototype.retrieveValue = function (dataIndex, dimIndex) { + return; + }; + + ExternalSource.prototype.retrieveValueFromItem = function (dataItem, dimIndex) { + return; + }; + + ExternalSource.prototype.convertValue = function (rawVal, dimInfo) { + return parseDataValue(rawVal, dimInfo); + }; + + return ExternalSource; + }(); + + function createExternalSource(internalSource, externalTransform) { + var extSource = new ExternalSource(); + var data = internalSource.data; + var sourceFormat = extSource.sourceFormat = internalSource.sourceFormat; + var sourceHeaderCount = internalSource.startIndex; + var errMsg = ''; + + if (internalSource.seriesLayoutBy !== SERIES_LAYOUT_BY_COLUMN) { + // For the logic simplicity in transformer, only 'culumn' is + // supported in data transform. Otherwise, the `dimensionsDefine` + // might be detected by 'row', which probably confuses users. + { + errMsg = '`seriesLayoutBy` of upstream dataset can only be "column" in data transform.'; + } + throwError(errMsg); + } // [MEMO] + // Create a new dimensions structure for exposing. + // Do not expose all dimension info to users directly. + // Because the dimension is probably auto detected from data and not might reliable. + // Should not lead the transformers to think that is reliable and return it. + // See [DIMENSION_INHERIT_RULE] in `sourceManager.ts`. + + + var dimensions = []; + var dimsByName = {}; + var dimsDef = internalSource.dimensionsDefine; + + if (dimsDef) { + each$4(dimsDef, function (dimDef, idx) { + var name = dimDef.name; + var dimDefExt = { + index: idx, + name: name, + displayName: dimDef.displayName + }; + dimensions.push(dimDefExt); // Users probably do not specify dimension name. For simplicity, data transform + // does not generate dimension name. + + if (name != null) { + // Dimension name should not be duplicated. + // For simplicity, data transform forbids name duplication, do not generate + // new name like module `completeDimensions.ts` did, but just tell users. + var errMsg_1 = ''; + + if (hasOwn(dimsByName, name)) { + { + errMsg_1 = 'dimension name "' + name + '" duplicated.'; + } + throwError(errMsg_1); + } + + dimsByName[name] = dimDefExt; + } + }); + } // If dimension definitions are not defined and can not be detected. + // e.g., pure data `[[11, 22], ...]`. + else { + for (var i = 0; i < internalSource.dimensionsDetectedCount || 0; i++) { + // Do not generete name or anything others. The consequence process in + // `transform` or `series` probably have there own name generation strategry. + dimensions.push({ + index: i + }); + } + } // Implement public methods: + + + var rawItemGetter = getRawSourceItemGetter(sourceFormat, SERIES_LAYOUT_BY_COLUMN); + + if (externalTransform.__isBuiltIn) { + extSource.getRawDataItem = function (dataIndex) { + return rawItemGetter(data, sourceHeaderCount, dimensions, dataIndex); + }; + + extSource.getRawData = bind$1(getRawData, null, internalSource); + } + + extSource.cloneRawData = bind$1(cloneRawData, null, internalSource); + var rawCounter = getRawSourceDataCounter(sourceFormat, SERIES_LAYOUT_BY_COLUMN); + extSource.count = bind$1(rawCounter, null, data, sourceHeaderCount, dimensions); + var rawValueGetter = getRawSourceValueGetter(sourceFormat); + + extSource.retrieveValue = function (dataIndex, dimIndex) { + var rawItem = rawItemGetter(data, sourceHeaderCount, dimensions, dataIndex); + return retrieveValueFromItem(rawItem, dimIndex); + }; + + var retrieveValueFromItem = extSource.retrieveValueFromItem = function (dataItem, dimIndex) { + if (dataItem == null) { + return; + } + + var dimDef = dimensions[dimIndex]; // When `dimIndex` is `null`, `rawValueGetter` return the whole item. + + if (dimDef) { + return rawValueGetter(dataItem, dimIndex, dimDef.name); + } + }; + + extSource.getDimensionInfo = bind$1(getDimensionInfo, null, dimensions, dimsByName); + extSource.cloneAllDimensionInfo = bind$1(cloneAllDimensionInfo, null, dimensions); + return extSource; + } + + function getRawData(upstream) { + var sourceFormat = upstream.sourceFormat; + + if (!isSupportedSourceFormat(sourceFormat)) { + var errMsg = ''; + { + errMsg = '`getRawData` is not supported in source format ' + sourceFormat; + } + throwError(errMsg); + } + + return upstream.data; + } + + function cloneRawData(upstream) { + var sourceFormat = upstream.sourceFormat; + var data = upstream.data; + + if (!isSupportedSourceFormat(sourceFormat)) { + var errMsg = ''; + { + errMsg = '`cloneRawData` is not supported in source format ' + sourceFormat; + } + throwError(errMsg); + } + + if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) { + var result = []; + + for (var i = 0, len = data.length; i < len; i++) { + // Not strictly clone for performance + result.push(data[i].slice()); + } + + return result; + } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) { + var result = []; + + for (var i = 0, len = data.length; i < len; i++) { + // Not strictly clone for performance + result.push(extend({}, data[i])); + } + + return result; + } + } + + function getDimensionInfo(dimensions, dimsByName, dim) { + if (dim == null) { + return; + } // Keep the same logic as `List::getDimension` did. + + + if (isNumber(dim) // If being a number-like string but not being defined a dimension name. + || !isNaN(dim) && !hasOwn(dimsByName, dim)) { + return dimensions[dim]; + } else if (hasOwn(dimsByName, dim)) { + return dimsByName[dim]; + } + } + + function cloneAllDimensionInfo(dimensions) { + return clone$3(dimensions); + } + + var externalTransformMap = createHashMap(); + + function registerExternalTransform(externalTransform) { + externalTransform = clone$3(externalTransform); + var type = externalTransform.type; + var errMsg = ''; + + if (!type) { + { + errMsg = 'Must have a `type` when `registerTransform`.'; + } + throwError(errMsg); + } + + var typeParsed = type.split(':'); + + if (typeParsed.length !== 2) { + { + errMsg = 'Name must include namespace like "ns:regression".'; + } + throwError(errMsg); + } // Namespace 'echarts:xxx' is official namespace, where the transforms should + // be called directly via 'xxx' rather than 'echarts:xxx'. + + + var isBuiltIn = false; + + if (typeParsed[0] === 'echarts') { + type = typeParsed[1]; + isBuiltIn = true; + } + + externalTransform.__isBuiltIn = isBuiltIn; + externalTransformMap.set(type, externalTransform); + } + + function applyDataTransform(rawTransOption, sourceList, infoForPrint) { + var pipedTransOption = normalizeToArray(rawTransOption); + var pipeLen = pipedTransOption.length; + var errMsg = ''; + + if (!pipeLen) { + { + errMsg = 'If `transform` declared, it should at least contain one transform.'; + } + throwError(errMsg); + } + + for (var i = 0, len = pipeLen; i < len; i++) { + var transOption = pipedTransOption[i]; + sourceList = applySingleDataTransform(transOption, sourceList, infoForPrint, pipeLen === 1 ? null : i); // piped transform only support single input, except the fist one. + // piped transform only support single output, except the last one. + + if (i !== len - 1) { + sourceList.length = Math.max(sourceList.length, 1); + } + } + + return sourceList; + } + + function applySingleDataTransform(transOption, upSourceList, infoForPrint, // If `pipeIndex` is null/undefined, no piped transform. + pipeIndex) { + var errMsg = ''; + + if (!upSourceList.length) { + { + errMsg = 'Must have at least one upstream dataset.'; + } + throwError(errMsg); + } + + if (!isObject$2(transOption)) { + { + errMsg = 'transform declaration must be an object rather than ' + typeof transOption + '.'; + } + throwError(errMsg); + } + + var transType = transOption.type; + var externalTransform = externalTransformMap.get(transType); + + if (!externalTransform) { + { + errMsg = 'Can not find transform on type "' + transType + '".'; + } + throwError(errMsg); + } // Prepare source + + + var extUpSourceList = map$1(upSourceList, function (upSource) { + return createExternalSource(upSource, externalTransform); + }); + var resultList = normalizeToArray(externalTransform.transform({ + upstream: extUpSourceList[0], + upstreamList: extUpSourceList, + config: clone$3(transOption.config) + })); + { + if (transOption.print) { + var printStrArr = map$1(resultList, function (extSource) { + var pipeIndexStr = pipeIndex != null ? ' === pipe index: ' + pipeIndex : ''; + return ['=== dataset index: ' + infoForPrint.datasetIndex + pipeIndexStr + ' ===', '- transform result data:', makePrintable(extSource.data), '- transform result dimensions:', makePrintable(extSource.dimensions)].join('\n'); + }).join('\n'); + log(printStrArr); + } + } + return map$1(resultList, function (result, resultIndex) { + var errMsg = ''; + + if (!isObject$2(result)) { + { + errMsg = 'A transform should not return some empty results.'; + } + throwError(errMsg); + } + + if (!result.data) { + { + errMsg = 'Transform result data should be not be null or undefined'; + } + throwError(errMsg); + } + + var sourceFormat = detectSourceFormat(result.data); + + if (!isSupportedSourceFormat(sourceFormat)) { + { + errMsg = 'Transform result data should be array rows or object rows.'; + } + throwError(errMsg); + } + + var resultMetaRawOption; + var firstUpSource = upSourceList[0]; + /** + * Intuitively, the end users known the content of the original `dataset.source`, + * calucating the transform result in mind. + * Suppose the original `dataset.source` is: + * ```js + * [ + * ['product', '2012', '2013', '2014', '2015'], + * ['AAA', 41.1, 30.4, 65.1, 53.3], + * ['BBB', 86.5, 92.1, 85.7, 83.1], + * ['CCC', 24.1, 67.2, 79.5, 86.4] + * ] + * ``` + * The dimension info have to be detected from the source data. + * Some of the transformers (like filter, sort) will follow the dimension info + * of upstream, while others use new dimensions (like aggregate). + * Transformer can output a field `dimensions` to define the its own output dimensions. + * We also allow transformers to ignore the output `dimensions` field, and + * inherit the upstream dimensions definition. It can reduce the burden of handling + * dimensions in transformers. + * + * See also [DIMENSION_INHERIT_RULE] in `sourceManager.ts`. + */ + + if (firstUpSource && resultIndex === 0 // If transformer returns `dimensions`, it means that the transformer has different + // dimensions definitions. We do not inherit anything from upstream. + && !result.dimensions) { + var startIndex = firstUpSource.startIndex; // We copy the header of upstream to the result, because: + // (1) The returned data always does not contain header line and can not be used + // as dimension-detection. In this case we can not use "detected dimensions" of + // upstream directly, because it might be detected based on different `seriesLayoutBy`. + // (2) We should support that the series read the upstream source in `seriesLayoutBy: 'row'`. + // So the original detected header should be add to the result, otherwise they can not be read. + + if (startIndex) { + result.data = firstUpSource.data.slice(0, startIndex).concat(result.data); + } + + resultMetaRawOption = { + seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN, + sourceHeader: startIndex, + dimensions: firstUpSource.metaRawOption.dimensions + }; + } else { + resultMetaRawOption = { + seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN, + sourceHeader: 0, + dimensions: result.dimensions + }; + } + + return createSource(result.data, resultMetaRawOption, null); + }); + } + + function isSupportedSourceFormat(sourceFormat) { + return sourceFormat === SOURCE_FORMAT_ARRAY_ROWS || sourceFormat === SOURCE_FORMAT_OBJECT_ROWS; + } + + var UNDEFINED = 'undefined'; + /* global Float64Array, Int32Array, Uint32Array, Uint16Array */ + // Caution: MUST not use `new CtorUint32Array(arr, 0, len)`, because the Ctor of array is + // different from the Ctor of typed array. + + var CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array; + var CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array; + var CtorInt32Array$1 = typeof Int32Array === UNDEFINED ? Array : Int32Array; + var CtorFloat64Array = typeof Float64Array === UNDEFINED ? Array : Float64Array; + /** + * Multi dimensional data store + */ + + var dataCtors = { + 'float': CtorFloat64Array, + 'int': CtorInt32Array$1, + // Ordinal data type can be string or int + 'ordinal': Array, + 'number': Array, + 'time': CtorFloat64Array + }; + var defaultDimValueGetters; + + function getIndicesCtor(rawCount) { + // The possible max value in this._indicies is always this._rawCount despite of filtering. + return rawCount > 65535 ? CtorUint32Array : CtorUint16Array; + } + + function getInitialExtent() { + return [Infinity, -Infinity]; + } + + function cloneChunk(originalChunk) { + var Ctor = originalChunk.constructor; // Only shallow clone is enough when Array. + + return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk); + } + + function prepareStore(store, dimIdx, dimType, end, append) { + var DataCtor = dataCtors[dimType || 'float']; + + if (append) { + var oldStore = store[dimIdx]; + var oldLen = oldStore && oldStore.length; + + if (!(oldLen === end)) { + var newStore = new DataCtor(end); // The cost of the copy is probably inconsiderable + // within the initial chunkSize. + + for (var j = 0; j < oldLen; j++) { + newStore[j] = oldStore[j]; + } + + store[dimIdx] = newStore; + } + } else { + store[dimIdx] = new DataCtor(end); + } + } + /** + * Basically, DataStore API keep immutable. + */ + + + var DataStore = + /** @class */ + function () { + function DataStore() { + this._chunks = []; // It will not be calculated until needed. + + this._rawExtent = []; + this._extent = []; + this._count = 0; + this._rawCount = 0; + this._calcDimNameToIdx = createHashMap(); + } + /** + * Initialize from data + */ + + + DataStore.prototype.initData = function (provider, inputDimensions, dimValueGetter) { + { + assert(isFunction(provider.getItem) && isFunction(provider.count), 'Invalid data provider.'); + } + this._provider = provider; // Clear + + this._chunks = []; + this._indices = null; + this.getRawIndex = this._getRawIdxIdentity; + var source = provider.getSource(); + var defaultGetter = this.defaultDimValueGetter = defaultDimValueGetters[source.sourceFormat]; // Default dim value getter + + this._dimValueGetter = dimValueGetter || defaultGetter; // Reset raw extent. + + this._rawExtent = []; + var willRetrieveDataByName = shouldRetrieveDataByName(source); + this._dimensions = map$1(inputDimensions, function (dim) { + { + if (willRetrieveDataByName) { + assert(dim.property != null); + } + } + return { + // Only pick these two props. Not leak other properties like orderMeta. + type: dim.type, + property: dim.property + }; + }); + + this._initDataFromProvider(0, provider.count()); + }; + + DataStore.prototype.getProvider = function () { + return this._provider; + }; + /** + * Caution: even when a `source` instance owned by a series, the created data store + * may still be shared by different sereis (the source hash does not use all `source` + * props, see `sourceManager`). In this case, the `source` props that are not used in + * hash (like `source.dimensionDefine`) probably only belongs to a certain series and + * thus should not be fetch here. + */ + + + DataStore.prototype.getSource = function () { + return this._provider.getSource(); + }; + /** + * @caution Only used in dataStack. + */ + + + DataStore.prototype.ensureCalculationDimension = function (dimName, type) { + var calcDimNameToIdx = this._calcDimNameToIdx; + var dimensions = this._dimensions; + var calcDimIdx = calcDimNameToIdx.get(dimName); + + if (calcDimIdx != null) { + if (dimensions[calcDimIdx].type === type) { + return calcDimIdx; + } + } else { + calcDimIdx = dimensions.length; + } + + dimensions[calcDimIdx] = { + type: type + }; + calcDimNameToIdx.set(dimName, calcDimIdx); + this._chunks[calcDimIdx] = new dataCtors[type || 'float'](this._rawCount); + this._rawExtent[calcDimIdx] = getInitialExtent(); + return calcDimIdx; + }; + + DataStore.prototype.collectOrdinalMeta = function (dimIdx, ordinalMeta) { + var chunk = this._chunks[dimIdx]; + var dim = this._dimensions[dimIdx]; + var rawExtents = this._rawExtent; + var offset = dim.ordinalOffset || 0; + var len = chunk.length; + + if (offset === 0) { + // We need to reset the rawExtent if collect is from start. + // Because this dimension may be guessed as number and calcuating a wrong extent. + rawExtents[dimIdx] = getInitialExtent(); + } + + var dimRawExtent = rawExtents[dimIdx]; // Parse from previous data offset. len may be changed after appendData + + for (var i = offset; i < len; i++) { + var val = chunk[i] = ordinalMeta.parseAndCollect(chunk[i]); + + if (!isNaN(val)) { + dimRawExtent[0] = Math.min(val, dimRawExtent[0]); + dimRawExtent[1] = Math.max(val, dimRawExtent[1]); + } + } + + dim.ordinalMeta = ordinalMeta; + dim.ordinalOffset = len; + dim.type = 'ordinal'; // Force to be ordinal + }; + + DataStore.prototype.getOrdinalMeta = function (dimIdx) { + var dimInfo = this._dimensions[dimIdx]; + var ordinalMeta = dimInfo.ordinalMeta; + return ordinalMeta; + }; + + DataStore.prototype.getDimensionProperty = function (dimIndex) { + var item = this._dimensions[dimIndex]; + return item && item.property; + }; + /** + * Caution: Can be only called on raw data (before `this._indices` created). + */ + + + DataStore.prototype.appendData = function (data) { + { + assert(!this._indices, 'appendData can only be called on raw data.'); + } + var provider = this._provider; + var start = this.count(); + provider.appendData(data); + var end = provider.count(); + + if (!provider.persistent) { + end += start; + } + + if (start < end) { + this._initDataFromProvider(start, end, true); + } + + return [start, end]; + }; + + DataStore.prototype.appendValues = function (values, minFillLen) { + var chunks = this._chunks; + var dimensions = this._dimensions; + var dimLen = dimensions.length; + var rawExtent = this._rawExtent; + var start = this.count(); + var end = start + Math.max(values.length, minFillLen || 0); + + for (var i = 0; i < dimLen; i++) { + var dim = dimensions[i]; + prepareStore(chunks, i, dim.type, end, true); + } + + var emptyDataItem = []; + + for (var idx = start; idx < end; idx++) { + var sourceIdx = idx - start; // Store the data by dimensions + + for (var dimIdx = 0; dimIdx < dimLen; dimIdx++) { + var dim = dimensions[dimIdx]; + var val = defaultDimValueGetters.arrayRows.call(this, values[sourceIdx] || emptyDataItem, dim.property, sourceIdx, dimIdx); + chunks[dimIdx][idx] = val; + var dimRawExtent = rawExtent[dimIdx]; + val < dimRawExtent[0] && (dimRawExtent[0] = val); + val > dimRawExtent[1] && (dimRawExtent[1] = val); + } + } + + this._rawCount = this._count = end; + return { + start: start, + end: end + }; + }; + + DataStore.prototype._initDataFromProvider = function (start, end, append) { + var provider = this._provider; + var chunks = this._chunks; + var dimensions = this._dimensions; + var dimLen = dimensions.length; + var rawExtent = this._rawExtent; + var dimNames = map$1(dimensions, function (dim) { + return dim.property; + }); + + for (var i = 0; i < dimLen; i++) { + var dim = dimensions[i]; + + if (!rawExtent[i]) { + rawExtent[i] = getInitialExtent(); + } + + prepareStore(chunks, i, dim.type, end, append); + } + + if (provider.fillStorage) { + provider.fillStorage(start, end, chunks, rawExtent); + } else { + var dataItem = []; + + for (var idx = start; idx < end; idx++) { + // NOTICE: Try not to write things into dataItem + dataItem = provider.getItem(idx, dataItem); // Each data item is value + // [1, 2] + // 2 + // Bar chart, line chart which uses category axis + // only gives the 'y' value. 'x' value is the indices of category + // Use a tempValue to normalize the value to be a (x, y) value + // Store the data by dimensions + + for (var dimIdx = 0; dimIdx < dimLen; dimIdx++) { + var dimStorage = chunks[dimIdx]; // PENDING NULL is empty or zero + + var val = this._dimValueGetter(dataItem, dimNames[dimIdx], idx, dimIdx); + + dimStorage[idx] = val; + var dimRawExtent = rawExtent[dimIdx]; + val < dimRawExtent[0] && (dimRawExtent[0] = val); + val > dimRawExtent[1] && (dimRawExtent[1] = val); + } + } + } + + if (!provider.persistent && provider.clean) { + // Clean unused data if data source is typed array. + provider.clean(); + } + + this._rawCount = this._count = end; // Reset data extent + + this._extent = []; + }; + + DataStore.prototype.count = function () { + return this._count; + }; + /** + * Get value. Return NaN if idx is out of range. + */ + + + DataStore.prototype.get = function (dim, idx) { + if (!(idx >= 0 && idx < this._count)) { + return NaN; + } + + var dimStore = this._chunks[dim]; + return dimStore ? dimStore[this.getRawIndex(idx)] : NaN; + }; + + DataStore.prototype.getValues = function (dimensions, idx) { + var values = []; + var dimArr = []; + + if (idx == null) { + idx = dimensions; // TODO get all from store? + + dimensions = []; // All dimensions + + for (var i = 0; i < this._dimensions.length; i++) { + dimArr.push(i); + } + } else { + dimArr = dimensions; + } + + for (var i = 0, len = dimArr.length; i < len; i++) { + values.push(this.get(dimArr[i], idx)); + } + + return values; + }; + /** + * @param dim concrete dim + */ + + + DataStore.prototype.getByRawIndex = function (dim, rawIdx) { + if (!(rawIdx >= 0 && rawIdx < this._rawCount)) { + return NaN; + } + + var dimStore = this._chunks[dim]; + return dimStore ? dimStore[rawIdx] : NaN; + }; + /** + * Get sum of data in one dimension + */ + + + DataStore.prototype.getSum = function (dim) { + var dimData = this._chunks[dim]; + var sum = 0; + + if (dimData) { + for (var i = 0, len = this.count(); i < len; i++) { + var value = this.get(dim, i); + + if (!isNaN(value)) { + sum += value; + } + } + } + + return sum; + }; + /** + * Get median of data in one dimension + */ + + + DataStore.prototype.getMedian = function (dim) { + var dimDataArray = []; // map all data of one dimension + + this.each([dim], function (val) { + if (!isNaN(val)) { + dimDataArray.push(val); + } + }); // TODO + // Use quick select? + + var sortedDimDataArray = dimDataArray.sort(function (a, b) { + return a - b; + }); + var len = this.count(); // calculate median + + return len === 0 ? 0 : len % 2 === 1 ? sortedDimDataArray[(len - 1) / 2] : (sortedDimDataArray[len / 2] + sortedDimDataArray[len / 2 - 1]) / 2; + }; + /** + * Retrieve the index with given raw data index. + */ + + + DataStore.prototype.indexOfRawIndex = function (rawIndex) { + if (rawIndex >= this._rawCount || rawIndex < 0) { + return -1; + } + + if (!this._indices) { + return rawIndex; + } // Indices are ascending + + + var indices = this._indices; // If rawIndex === dataIndex + + var rawDataIndex = indices[rawIndex]; + + if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) { + return rawIndex; + } + + var left = 0; + var right = this._count - 1; + + while (left <= right) { + var mid = (left + right) / 2 | 0; + + if (indices[mid] < rawIndex) { + left = mid + 1; + } else if (indices[mid] > rawIndex) { + right = mid - 1; + } else { + return mid; + } + } + + return -1; + }; + + DataStore.prototype.getIndices = function () { + var newIndices; + var indices = this._indices; + + if (indices) { + var Ctor = indices.constructor; + var thisCount = this._count; // `new Array(a, b, c)` is different from `new Uint32Array(a, b, c)`. + + if (Ctor === Array) { + newIndices = new Ctor(thisCount); + + for (var i = 0; i < thisCount; i++) { + newIndices[i] = indices[i]; + } + } else { + newIndices = new Ctor(indices.buffer, 0, thisCount); + } + } else { + var Ctor = getIndicesCtor(this._rawCount); + newIndices = new Ctor(this.count()); + + for (var i = 0; i < newIndices.length; i++) { + newIndices[i] = i; + } + } + + return newIndices; + }; + /** + * Data filter. + */ + + + DataStore.prototype.filter = function (dims, cb) { + if (!this._count) { + return this; + } + + var newStore = this.clone(); + var count = newStore.count(); + var Ctor = getIndicesCtor(newStore._rawCount); + var newIndices = new Ctor(count); + var value = []; + var dimSize = dims.length; + var offset = 0; + var dim0 = dims[0]; + var chunks = newStore._chunks; + + for (var i = 0; i < count; i++) { + var keep = void 0; + var rawIdx = newStore.getRawIndex(i); // Simple optimization + + if (dimSize === 0) { + keep = cb(i); + } else if (dimSize === 1) { + var val = chunks[dim0][rawIdx]; + keep = cb(val, i); + } else { + var k = 0; + + for (; k < dimSize; k++) { + value[k] = chunks[dims[k]][rawIdx]; + } + + value[k] = i; + keep = cb.apply(null, value); + } + + if (keep) { + newIndices[offset++] = rawIdx; + } + } // Set indices after filtered. + + + if (offset < count) { + newStore._indices = newIndices; + } + + newStore._count = offset; // Reset data extent + + newStore._extent = []; + + newStore._updateGetRawIdx(); + + return newStore; + }; + /** + * Select data in range. (For optimization of filter) + * (Manually inline code, support 5 million data filtering in data zoom.) + */ + + + DataStore.prototype.selectRange = function (range) { + var newStore = this.clone(); + var len = newStore._count; + + if (!len) { + return this; + } + + var dims = keys(range); + var dimSize = dims.length; + + if (!dimSize) { + return this; + } + + var originalCount = newStore.count(); + var Ctor = getIndicesCtor(newStore._rawCount); + var newIndices = new Ctor(originalCount); + var offset = 0; + var dim0 = dims[0]; + var min = range[dim0][0]; + var max = range[dim0][1]; + var storeArr = newStore._chunks; + var quickFinished = false; + + if (!newStore._indices) { + // Extreme optimization for common case. About 2x faster in chrome. + var idx = 0; + + if (dimSize === 1) { + var dimStorage = storeArr[dims[0]]; + + for (var i = 0; i < len; i++) { + var val = dimStorage[i]; // NaN will not be filtered. Consider the case, in line chart, empty + // value indicates the line should be broken. But for the case like + // scatter plot, a data item with empty value will not be rendered, + // but the axis extent may be effected if some other dim of the data + // item has value. Fortunately it is not a significant negative effect. + + if (val >= min && val <= max || isNaN(val)) { + newIndices[offset++] = idx; + } + + idx++; + } + + quickFinished = true; + } else if (dimSize === 2) { + var dimStorage = storeArr[dims[0]]; + var dimStorage2 = storeArr[dims[1]]; + var min2 = range[dims[1]][0]; + var max2 = range[dims[1]][1]; + + for (var i = 0; i < len; i++) { + var val = dimStorage[i]; + var val2 = dimStorage2[i]; // Do not filter NaN, see comment above. + + if ((val >= min && val <= max || isNaN(val)) && (val2 >= min2 && val2 <= max2 || isNaN(val2))) { + newIndices[offset++] = idx; + } + + idx++; + } + + quickFinished = true; + } + } + + if (!quickFinished) { + if (dimSize === 1) { + for (var i = 0; i < originalCount; i++) { + var rawIndex = newStore.getRawIndex(i); + var val = storeArr[dims[0]][rawIndex]; // Do not filter NaN, see comment above. + + if (val >= min && val <= max || isNaN(val)) { + newIndices[offset++] = rawIndex; + } + } + } else { + for (var i = 0; i < originalCount; i++) { + var keep = true; + var rawIndex = newStore.getRawIndex(i); + + for (var k = 0; k < dimSize; k++) { + var dimk = dims[k]; + var val = storeArr[dimk][rawIndex]; // Do not filter NaN, see comment above. + + if (val < range[dimk][0] || val > range[dimk][1]) { + keep = false; + } + } + + if (keep) { + newIndices[offset++] = newStore.getRawIndex(i); + } + } + } + } // Set indices after filtered. + + + if (offset < originalCount) { + newStore._indices = newIndices; + } + + newStore._count = offset; // Reset data extent + + newStore._extent = []; + + newStore._updateGetRawIdx(); + + return newStore; + }; // /** + // * Data mapping to a plain array + // */ + // mapArray(dims: DimensionIndex[], cb: MapArrayCb): any[] { + // const result: any[] = []; + // this.each(dims, function () { + // result.push(cb && (cb as MapArrayCb).apply(null, arguments)); + // }); + // return result; + // } + + /** + * Data mapping to a new List with given dimensions + */ + + + DataStore.prototype.map = function (dims, cb) { + // TODO only clone picked chunks. + var target = this.clone(dims); + + this._updateDims(target, dims, cb); + + return target; + }; + /** + * @caution Danger!! Only used in dataStack. + */ + + + DataStore.prototype.modify = function (dims, cb) { + this._updateDims(this, dims, cb); + }; + + DataStore.prototype._updateDims = function (target, dims, cb) { + var targetChunks = target._chunks; + var tmpRetValue = []; + var dimSize = dims.length; + var dataCount = target.count(); + var values = []; + var rawExtent = target._rawExtent; + + for (var i = 0; i < dims.length; i++) { + rawExtent[dims[i]] = getInitialExtent(); + } + + for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) { + var rawIndex = target.getRawIndex(dataIndex); + + for (var k = 0; k < dimSize; k++) { + values[k] = targetChunks[dims[k]][rawIndex]; + } + + values[dimSize] = dataIndex; + var retValue = cb && cb.apply(null, values); + + if (retValue != null) { + // a number or string (in oridinal dimension)? + if (typeof retValue !== 'object') { + tmpRetValue[0] = retValue; + retValue = tmpRetValue; + } + + for (var i = 0; i < retValue.length; i++) { + var dim = dims[i]; + var val = retValue[i]; + var rawExtentOnDim = rawExtent[dim]; + var dimStore = targetChunks[dim]; + + if (dimStore) { + dimStore[rawIndex] = val; + } + + if (val < rawExtentOnDim[0]) { + rawExtentOnDim[0] = val; + } + + if (val > rawExtentOnDim[1]) { + rawExtentOnDim[1] = val; + } + } + } + } + }; + /** + * Large data down sampling using largest-triangle-three-buckets + * @param {string} valueDimension + * @param {number} targetCount + */ + + + DataStore.prototype.lttbDownSample = function (valueDimension, rate) { + var target = this.clone([valueDimension], true); + var targetStorage = target._chunks; + var dimStore = targetStorage[valueDimension]; + var len = this.count(); + var sampledIndex = 0; + var frameSize = Math.floor(1 / rate); + var currentRawIndex = this.getRawIndex(0); + var maxArea; + var area; + var nextRawIndex; + var newIndices = new (getIndicesCtor(this._rawCount))(Math.min((Math.ceil(len / frameSize) + 2) * 2, len)); // First frame use the first data. + + newIndices[sampledIndex++] = currentRawIndex; + + for (var i = 1; i < len - 1; i += frameSize) { + var nextFrameStart = Math.min(i + frameSize, len - 1); + var nextFrameEnd = Math.min(i + frameSize * 2, len); + var avgX = (nextFrameEnd + nextFrameStart) / 2; + var avgY = 0; + + for (var idx = nextFrameStart; idx < nextFrameEnd; idx++) { + var rawIndex = this.getRawIndex(idx); + var y = dimStore[rawIndex]; + + if (isNaN(y)) { + continue; + } + + avgY += y; + } + + avgY /= nextFrameEnd - nextFrameStart; + var frameStart = i; + var frameEnd = Math.min(i + frameSize, len); + var pointAX = i - 1; + var pointAY = dimStore[currentRawIndex]; + maxArea = -1; + nextRawIndex = frameStart; + var firstNaNIndex = -1; + var countNaN = 0; // Find a point from current frame that construct a triangle with largest area with previous selected point + // And the average of next frame. + + for (var idx = frameStart; idx < frameEnd; idx++) { + var rawIndex = this.getRawIndex(idx); + var y = dimStore[rawIndex]; + + if (isNaN(y)) { + countNaN++; + + if (firstNaNIndex < 0) { + firstNaNIndex = rawIndex; + } + + continue; + } // Calculate triangle area over three buckets + + + area = Math.abs((pointAX - avgX) * (y - pointAY) - (pointAX - idx) * (avgY - pointAY)); + + if (area > maxArea) { + maxArea = area; + nextRawIndex = rawIndex; // Next a is this b + } + } + + if (countNaN > 0 && countNaN < frameEnd - frameStart) { + // Append first NaN point in every bucket. + // It is necessary to ensure the correct order of indices. + newIndices[sampledIndex++] = Math.min(firstNaNIndex, nextRawIndex); + nextRawIndex = Math.max(firstNaNIndex, nextRawIndex); + } + + newIndices[sampledIndex++] = nextRawIndex; + currentRawIndex = nextRawIndex; // This a is the next a (chosen b) + } // First frame use the last data. + + + newIndices[sampledIndex++] = this.getRawIndex(len - 1); + target._count = sampledIndex; + target._indices = newIndices; + target.getRawIndex = this._getRawIdx; + return target; + }; + /** + * Large data down sampling using min-max + * @param {string} valueDimension + * @param {number} rate + */ + + + DataStore.prototype.minmaxDownSample = function (valueDimension, rate) { + var target = this.clone([valueDimension], true); + var targetStorage = target._chunks; + var frameSize = Math.floor(1 / rate); + var dimStore = targetStorage[valueDimension]; + var len = this.count(); // Each frame results in 2 data points, one for min and one for max + + var newIndices = new (getIndicesCtor(this._rawCount))(Math.ceil(len / frameSize) * 2); + var offset = 0; + + for (var i = 0; i < len; i += frameSize) { + var minIndex = i; + var minValue = dimStore[this.getRawIndex(minIndex)]; + var maxIndex = i; + var maxValue = dimStore[this.getRawIndex(maxIndex)]; + var thisFrameSize = frameSize; // Handle final smaller frame + + if (i + frameSize > len) { + thisFrameSize = len - i; + } // Determine min and max within the current frame + + + for (var k = 0; k < thisFrameSize; k++) { + var rawIndex = this.getRawIndex(i + k); + var value = dimStore[rawIndex]; + + if (value < minValue) { + minValue = value; + minIndex = i + k; + } + + if (value > maxValue) { + maxValue = value; + maxIndex = i + k; + } + } + + var rawMinIndex = this.getRawIndex(minIndex); + var rawMaxIndex = this.getRawIndex(maxIndex); // Set the order of the min and max values, based on their ordering in the frame + + if (minIndex < maxIndex) { + newIndices[offset++] = rawMinIndex; + newIndices[offset++] = rawMaxIndex; + } else { + newIndices[offset++] = rawMaxIndex; + newIndices[offset++] = rawMinIndex; + } + } + + target._count = offset; + target._indices = newIndices; + + target._updateGetRawIdx(); + + return target; + }; + /** + * Large data down sampling on given dimension + * @param sampleIndex Sample index for name and id + */ + + + DataStore.prototype.downSample = function (dimension, rate, sampleValue, sampleIndex) { + var target = this.clone([dimension], true); + var targetStorage = target._chunks; + var frameValues = []; + var frameSize = Math.floor(1 / rate); + var dimStore = targetStorage[dimension]; + var len = this.count(); + var rawExtentOnDim = target._rawExtent[dimension] = getInitialExtent(); + var newIndices = new (getIndicesCtor(this._rawCount))(Math.ceil(len / frameSize)); + var offset = 0; + + for (var i = 0; i < len; i += frameSize) { + // Last frame + if (frameSize > len - i) { + frameSize = len - i; + frameValues.length = frameSize; + } + + for (var k = 0; k < frameSize; k++) { + var dataIdx = this.getRawIndex(i + k); + frameValues[k] = dimStore[dataIdx]; + } + + var value = sampleValue(frameValues); + var sampleFrameIdx = this.getRawIndex(Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)); // Only write value on the filtered data + + dimStore[sampleFrameIdx] = value; + + if (value < rawExtentOnDim[0]) { + rawExtentOnDim[0] = value; + } + + if (value > rawExtentOnDim[1]) { + rawExtentOnDim[1] = value; + } + + newIndices[offset++] = sampleFrameIdx; + } + + target._count = offset; + target._indices = newIndices; + + target._updateGetRawIdx(); + + return target; + }; + /** + * Data iteration + * @param ctx default this + * @example + * list.each('x', function (x, idx) {}); + * list.each(['x', 'y'], function (x, y, idx) {}); + * list.each(function (idx) {}) + */ + + + DataStore.prototype.each = function (dims, cb) { + if (!this._count) { + return; + } + + var dimSize = dims.length; + var chunks = this._chunks; + + for (var i = 0, len = this.count(); i < len; i++) { + var rawIdx = this.getRawIndex(i); // Simple optimization + + switch (dimSize) { + case 0: + cb(i); + break; + + case 1: + cb(chunks[dims[0]][rawIdx], i); + break; + + case 2: + cb(chunks[dims[0]][rawIdx], chunks[dims[1]][rawIdx], i); + break; + + default: + var k = 0; + var value = []; + + for (; k < dimSize; k++) { + value[k] = chunks[dims[k]][rawIdx]; + } // Index + + + value[k] = i; + cb.apply(null, value); + } + } + }; + /** + * Get extent of data in one dimension + */ + + + DataStore.prototype.getDataExtent = function (dim) { + // Make sure use concrete dim as cache name. + var dimData = this._chunks[dim]; + var initialExtent = getInitialExtent(); + + if (!dimData) { + return initialExtent; + } // Make more strict checkings to ensure hitting cache. + + + var currEnd = this.count(); // Consider the most cases when using data zoom, `getDataExtent` + // happened before filtering. We cache raw extent, which is not + // necessary to be cleared and recalculated when restore data. + + var useRaw = !this._indices; + var dimExtent; + + if (useRaw) { + return this._rawExtent[dim].slice(); + } + + dimExtent = this._extent[dim]; + + if (dimExtent) { + return dimExtent.slice(); + } + + dimExtent = initialExtent; + var min = dimExtent[0]; + var max = dimExtent[1]; + + for (var i = 0; i < currEnd; i++) { + var rawIdx = this.getRawIndex(i); + var value = dimData[rawIdx]; + value < min && (min = value); + value > max && (max = value); + } + + dimExtent = [min, max]; + this._extent[dim] = dimExtent; + return dimExtent; + }; + /** + * Get raw data item + */ + + + DataStore.prototype.getRawDataItem = function (idx) { + var rawIdx = this.getRawIndex(idx); + + if (!this._provider.persistent) { + var val = []; + var chunks = this._chunks; + + for (var i = 0; i < chunks.length; i++) { + val.push(chunks[i][rawIdx]); + } + + return val; + } else { + return this._provider.getItem(rawIdx); + } + }; + /** + * Clone shallow. + * + * @param clonedDims Determine which dims to clone. Will share the data if not specified. + */ + + + DataStore.prototype.clone = function (clonedDims, ignoreIndices) { + var target = new DataStore(); + var chunks = this._chunks; + var clonedDimsMap = clonedDims && reduce(clonedDims, function (obj, dimIdx) { + obj[dimIdx] = true; + return obj; + }, {}); + + if (clonedDimsMap) { + for (var i = 0; i < chunks.length; i++) { + // Not clone if dim is not picked. + target._chunks[i] = !clonedDimsMap[i] ? chunks[i] : cloneChunk(chunks[i]); + } + } else { + target._chunks = chunks; + } + + this._copyCommonProps(target); + + if (!ignoreIndices) { + target._indices = this._cloneIndices(); + } + + target._updateGetRawIdx(); + + return target; + }; + + DataStore.prototype._copyCommonProps = function (target) { + target._count = this._count; + target._rawCount = this._rawCount; + target._provider = this._provider; + target._dimensions = this._dimensions; + target._extent = clone$3(this._extent); + target._rawExtent = clone$3(this._rawExtent); + }; + + DataStore.prototype._cloneIndices = function () { + if (this._indices) { + var Ctor = this._indices.constructor; + var indices = void 0; + + if (Ctor === Array) { + var thisCount = this._indices.length; + indices = new Ctor(thisCount); + + for (var i = 0; i < thisCount; i++) { + indices[i] = this._indices[i]; + } + } else { + indices = new Ctor(this._indices); + } + + return indices; + } + + return null; + }; + + DataStore.prototype._getRawIdxIdentity = function (idx) { + return idx; + }; + + DataStore.prototype._getRawIdx = function (idx) { + if (idx < this._count && idx >= 0) { + return this._indices[idx]; + } + + return -1; + }; + + DataStore.prototype._updateGetRawIdx = function () { + this.getRawIndex = this._indices ? this._getRawIdx : this._getRawIdxIdentity; + }; + + DataStore.internalField = function () { + function getDimValueSimply(dataItem, property, dataIndex, dimIndex) { + return parseDataValue(dataItem[dimIndex], this._dimensions[dimIndex]); + } + + defaultDimValueGetters = { + arrayRows: getDimValueSimply, + objectRows: function (dataItem, property, dataIndex, dimIndex) { + return parseDataValue(dataItem[property], this._dimensions[dimIndex]); + }, + keyedColumns: getDimValueSimply, + original: function (dataItem, property, dataIndex, dimIndex) { + // Performance sensitive, do not use modelUtil.getDataItemValue. + // If dataItem is an plain object with no value field, the let `value` + // will be assigned with the object, but it will be tread correctly + // in the `convertValue`. + var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value); + return parseDataValue(value instanceof Array ? value[dimIndex] // If value is a single number or something else not array. + : value, this._dimensions[dimIndex]); + }, + typedArray: function (dataItem, property, dataIndex, dimIndex) { + return dataItem[dimIndex]; + } + }; + }(); + + return DataStore; + }(); + /** + * [REQUIREMENT_MEMO]: + * (0) `metaRawOption` means `dimensions`/`sourceHeader`/`seriesLayoutBy` in raw option. + * (1) Keep support the feature: `metaRawOption` can be specified both on `series` and + * `root-dataset`. Them on `series` has higher priority. + * (2) Do not support to set `metaRawOption` on a `non-root-dataset`, because it might + * confuse users: whether those props indicate how to visit the upstream source or visit + * the transform result source, and some transforms has nothing to do with these props, + * and some transforms might have multiple upstream. + * (3) Transforms should specify `metaRawOption` in each output, just like they can be + * declared in `root-dataset`. + * (4) At present only support visit source in `SERIES_LAYOUT_BY_COLUMN` in transforms. + * That is for reducing complexity in transforms. + * PENDING: Whether to provide transposition transform? + * + * [IMPLEMENTAION_MEMO]: + * "sourceVisitConfig" are calculated from `metaRawOption` and `data`. + * They will not be calculated until `source` is about to be visited (to prevent from + * duplicate calcuation). `source` is visited only in series and input to transforms. + * + * [DIMENSION_INHERIT_RULE]: + * By default the dimensions are inherited from ancestors, unless a transform return + * a new dimensions definition. + * Consider the case: + * ```js + * dataset: [{ + * source: [ ['Product', 'Sales', 'Prise'], ['Cookies', 321, 44.21], ...] + * }, { + * transform: { type: 'filter', ... } + * }] + * dataset: [{ + * dimension: ['Product', 'Sales', 'Prise'], + * source: [ ['Cookies', 321, 44.21], ...] + * }, { + * transform: { type: 'filter', ... } + * }] + * ``` + * The two types of option should have the same behavior after transform. + * + * + * [SCENARIO]: + * (1) Provide source data directly: + * ```js + * series: { + * encode: {...}, + * dimensions: [...] + * seriesLayoutBy: 'row', + * data: [[...]] + * } + * ``` + * (2) Series refer to dataset. + * ```js + * series: [{ + * encode: {...} + * // Ignore datasetIndex means `datasetIndex: 0` + * // and the dimensions defination in dataset is used + * }, { + * encode: {...}, + * seriesLayoutBy: 'column', + * datasetIndex: 1 + * }] + * ``` + * (3) dataset transform + * ```js + * dataset: [{ + * source: [...] + * }, { + * source: [...] + * }, { + * // By default from 0. + * transform: { type: 'filter', config: {...} } + * }, { + * // Piped. + * transform: [ + * { type: 'filter', config: {...} }, + * { type: 'sort', config: {...} } + * ] + * }, { + * id: 'regressionData', + * fromDatasetIndex: 1, + * // Third-party transform + * transform: { type: 'ecStat:regression', config: {...} } + * }, { + * // retrieve the extra result. + * id: 'regressionFormula', + * fromDatasetId: 'regressionData', + * fromTransformResult: 1 + * }] + * ``` + */ + + + var SourceManager = + /** @class */ + function () { + function SourceManager(sourceHost) { + // Cached source. Do not repeat calculating if not dirty. + this._sourceList = []; + this._storeList = []; // version sign of each upstream source manager. + + this._upstreamSignList = []; + this._versionSignBase = 0; + this._dirty = true; + this._sourceHost = sourceHost; + } + /** + * Mark dirty. + */ + + + SourceManager.prototype.dirty = function () { + this._setLocalSource([], []); + + this._storeList = []; + this._dirty = true; + }; + + SourceManager.prototype._setLocalSource = function (sourceList, upstreamSignList) { + this._sourceList = sourceList; + this._upstreamSignList = upstreamSignList; + this._versionSignBase++; + + if (this._versionSignBase > 9e10) { + this._versionSignBase = 0; + } + }; + /** + * For detecting whether the upstream source is dirty, so that + * the local cached source (in `_sourceList`) should be discarded. + */ + + + SourceManager.prototype._getVersionSign = function () { + return this._sourceHost.uid + '_' + this._versionSignBase; + }; + /** + * Always return a source instance. Otherwise throw error. + */ + + + SourceManager.prototype.prepareSource = function () { + // For the case that call `setOption` multiple time but no data changed, + // cache the result source to prevent from repeating transform. + if (this._isDirty()) { + this._createSource(); + + this._dirty = false; + } + }; + + SourceManager.prototype._createSource = function () { + this._setLocalSource([], []); + + var sourceHost = this._sourceHost; + + var upSourceMgrList = this._getUpstreamSourceManagers(); + + var hasUpstream = !!upSourceMgrList.length; + var resultSourceList; + var upstreamSignList; + + if (isSeries(sourceHost)) { + var seriesModel = sourceHost; + var data = void 0; + var sourceFormat = void 0; + var upSource = void 0; // Has upstream dataset + + if (hasUpstream) { + var upSourceMgr = upSourceMgrList[0]; + upSourceMgr.prepareSource(); + upSource = upSourceMgr.getSource(); + data = upSource.data; + sourceFormat = upSource.sourceFormat; + upstreamSignList = [upSourceMgr._getVersionSign()]; + } // Series data is from own. + else { + data = seriesModel.get('data', true); + sourceFormat = isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL; + upstreamSignList = []; + } // See [REQUIREMENT_MEMO], merge settings on series and parent dataset if it is root. + + + var newMetaRawOption = this._getSourceMetaRawOption() || {}; + var upMetaRawOption = upSource && upSource.metaRawOption || {}; + var seriesLayoutBy = retrieve2(newMetaRawOption.seriesLayoutBy, upMetaRawOption.seriesLayoutBy) || null; + var sourceHeader = retrieve2(newMetaRawOption.sourceHeader, upMetaRawOption.sourceHeader); // Note here we should not use `upSource.dimensionsDefine`. Consider the case: + // `upSource.dimensionsDefine` is detected by `seriesLayoutBy: 'column'`, + // but series need `seriesLayoutBy: 'row'`. + + var dimensions = retrieve2(newMetaRawOption.dimensions, upMetaRawOption.dimensions); // We share source with dataset as much as possible + // to avoid extra memory cost of high dimensional data. + + var needsCreateSource = seriesLayoutBy !== upMetaRawOption.seriesLayoutBy || !!sourceHeader !== !!upMetaRawOption.sourceHeader || dimensions; + resultSourceList = needsCreateSource ? [createSource(data, { + seriesLayoutBy: seriesLayoutBy, + sourceHeader: sourceHeader, + dimensions: dimensions + }, sourceFormat)] : []; + } else { + var datasetModel = sourceHost; // Has upstream dataset. + + if (hasUpstream) { + var result = this._applyTransform(upSourceMgrList); + + resultSourceList = result.sourceList; + upstreamSignList = result.upstreamSignList; + } // Is root dataset. + else { + var sourceData = datasetModel.get('source', true); + resultSourceList = [createSource(sourceData, this._getSourceMetaRawOption(), null)]; + upstreamSignList = []; + } + } + + { + assert(resultSourceList && upstreamSignList); + } + + this._setLocalSource(resultSourceList, upstreamSignList); + }; + + SourceManager.prototype._applyTransform = function (upMgrList) { + var datasetModel = this._sourceHost; + var transformOption = datasetModel.get('transform', true); + var fromTransformResult = datasetModel.get('fromTransformResult', true); + { + assert(fromTransformResult != null || transformOption != null); + } + + if (fromTransformResult != null) { + var errMsg = ''; + + if (upMgrList.length !== 1) { + { + errMsg = 'When using `fromTransformResult`, there should be only one upstream dataset'; + } + doThrow(errMsg); + } + } + + var sourceList; + var upSourceList = []; + var upstreamSignList = []; + each$4(upMgrList, function (upMgr) { + upMgr.prepareSource(); + var upSource = upMgr.getSource(fromTransformResult || 0); + var errMsg = ''; + + if (fromTransformResult != null && !upSource) { + { + errMsg = 'Can not retrieve result by `fromTransformResult`: ' + fromTransformResult; + } + doThrow(errMsg); + } + + upSourceList.push(upSource); + upstreamSignList.push(upMgr._getVersionSign()); + }); + + if (transformOption) { + sourceList = applyDataTransform(transformOption, upSourceList, { + datasetIndex: datasetModel.componentIndex + }); + } else if (fromTransformResult != null) { + sourceList = [cloneSourceShallow(upSourceList[0])]; + } + + return { + sourceList: sourceList, + upstreamSignList: upstreamSignList + }; + }; + + SourceManager.prototype._isDirty = function () { + if (this._dirty) { + return true; + } // All sourceList is from the some upstream. + + + var upSourceMgrList = this._getUpstreamSourceManagers(); + + for (var i = 0; i < upSourceMgrList.length; i++) { + var upSrcMgr = upSourceMgrList[i]; + + if ( // Consider the case that there is ancestor diry, call it recursively. + // The performance is probably not an issue because usually the chain is not long. + upSrcMgr._isDirty() || this._upstreamSignList[i] !== upSrcMgr._getVersionSign()) { + return true; + } + } + }; + /** + * @param sourceIndex By default 0, means "main source". + * In most cases there is only one source. + */ + + + SourceManager.prototype.getSource = function (sourceIndex) { + sourceIndex = sourceIndex || 0; + var source = this._sourceList[sourceIndex]; + + if (!source) { + // Series may share source instance with dataset. + var upSourceMgrList = this._getUpstreamSourceManagers(); + + return upSourceMgrList[0] && upSourceMgrList[0].getSource(sourceIndex); + } + + return source; + }; + /** + * + * Get a data store which can be shared across series. + * Only available for series. + * + * @param seriesDimRequest Dimensions that are generated in series. + * Should have been sorted by `storeDimIndex` asc. + */ + + + SourceManager.prototype.getSharedDataStore = function (seriesDimRequest) { + { + assert(isSeries(this._sourceHost), 'Can only call getDataStore on series source manager.'); + } + var schema = seriesDimRequest.makeStoreSchema(); + return this._innerGetDataStore(schema.dimensions, seriesDimRequest.source, schema.hash); + }; + + SourceManager.prototype._innerGetDataStore = function (storeDims, seriesSource, sourceReadKey) { + // TODO Can use other sourceIndex? + var sourceIndex = 0; + var storeList = this._storeList; + var cachedStoreMap = storeList[sourceIndex]; + + if (!cachedStoreMap) { + cachedStoreMap = storeList[sourceIndex] = {}; + } + + var cachedStore = cachedStoreMap[sourceReadKey]; + + if (!cachedStore) { + var upSourceMgr = this._getUpstreamSourceManagers()[0]; + + if (isSeries(this._sourceHost) && upSourceMgr) { + cachedStore = upSourceMgr._innerGetDataStore(storeDims, seriesSource, sourceReadKey); + } else { + cachedStore = new DataStore(); // Always create store from source of series. + + cachedStore.initData(new DefaultDataProvider(seriesSource, storeDims.length), storeDims); + } + + cachedStoreMap[sourceReadKey] = cachedStore; + } + + return cachedStore; + }; + /** + * PENDING: Is it fast enough? + * If no upstream, return empty array. + */ + + + SourceManager.prototype._getUpstreamSourceManagers = function () { + // Always get the relationship from the raw option. + // Do not cache the link of the dependency graph, so that + // there is no need to update them when change happens. + var sourceHost = this._sourceHost; + + if (isSeries(sourceHost)) { + var datasetModel = querySeriesUpstreamDatasetModel(sourceHost); + return !datasetModel ? [] : [datasetModel.getSourceManager()]; + } else { + return map$1(queryDatasetUpstreamDatasetModels(sourceHost), function (datasetModel) { + return datasetModel.getSourceManager(); + }); + } + }; + + SourceManager.prototype._getSourceMetaRawOption = function () { + var sourceHost = this._sourceHost; + var seriesLayoutBy; + var sourceHeader; + var dimensions; + + if (isSeries(sourceHost)) { + seriesLayoutBy = sourceHost.get('seriesLayoutBy', true); + sourceHeader = sourceHost.get('sourceHeader', true); + dimensions = sourceHost.get('dimensions', true); + } // See [REQUIREMENT_MEMO], `non-root-dataset` do not support them. + else if (!this._getUpstreamSourceManagers().length) { + var model = sourceHost; + seriesLayoutBy = model.get('seriesLayoutBy', true); + sourceHeader = model.get('sourceHeader', true); + dimensions = model.get('dimensions', true); + } + + return { + seriesLayoutBy: seriesLayoutBy, + sourceHeader: sourceHeader, + dimensions: dimensions + }; + }; + + return SourceManager; + }(); // Call this method after `super.init` and `super.mergeOption` to + // disable the transform merge, but do not disable transform clone from rawOption. + + + function disableTransformOptionMerge(datasetModel) { + var transformOption = datasetModel.option.transform; + transformOption && setAsPrimitive(datasetModel.option.transform); + } + + function isSeries(sourceHost) { + // Avoid circular dependency with Series.ts + return sourceHost.mainType === 'series'; + } + + function doThrow(errMsg) { + throw new Error(errMsg); + } + + var TOOLTIP_LINE_HEIGHT_CSS = 'line-height:1'; + + function getTooltipLineHeight(textStyle) { + var lineHeight = textStyle.lineHeight; + + if (lineHeight == null) { + return TOOLTIP_LINE_HEIGHT_CSS; + } else { + return "line-height:" + encodeHTML(lineHeight + '') + "px"; + } + } // TODO: more textStyle option + + + function getTooltipTextStyle(textStyle, renderMode) { + var nameFontColor = textStyle.color || tokens.color.tertiary; + var nameFontSize = textStyle.fontSize || 12; + var nameFontWeight = textStyle.fontWeight || '400'; + var valueFontColor = textStyle.color || tokens.color.secondary; + var valueFontSize = textStyle.fontSize || 14; + var valueFontWeight = textStyle.fontWeight || '900'; + + if (renderMode === 'html') { + // `textStyle` is probably from user input, should be encoded to reduce security risk. + return { + // eslint-disable-next-line max-len + nameStyle: "font-size:" + encodeHTML(nameFontSize + '') + "px;color:" + encodeHTML(nameFontColor) + ";font-weight:" + encodeHTML(nameFontWeight + ''), + // eslint-disable-next-line max-len + valueStyle: "font-size:" + encodeHTML(valueFontSize + '') + "px;color:" + encodeHTML(valueFontColor) + ";font-weight:" + encodeHTML(valueFontWeight + '') + }; + } else { + return { + nameStyle: { + fontSize: nameFontSize, + fill: nameFontColor, + fontWeight: nameFontWeight + }, + valueStyle: { + fontSize: valueFontSize, + fill: valueFontColor, + fontWeight: valueFontWeight + } + }; + } + } // See `TooltipMarkupLayoutIntent['innerGapLevel']`. + // (value from UI design) + + + var HTML_GAPS = [0, 10, 20, 30]; + var RICH_TEXT_GAPS = ['', '\n', '\n\n', '\n\n\n']; // eslint-disable-next-line max-len + + function createTooltipMarkup(type, option) { + option.type = type; + return option; + } + + function isSectionFragment(frag) { + return frag.type === 'section'; + } + + function getBuilder(frag) { + return isSectionFragment(frag) ? buildSection : buildNameValue; + } + + function getBlockGapLevel(frag) { + if (isSectionFragment(frag)) { + var gapLevel_1 = 0; + var subBlockLen = frag.blocks.length; + var hasInnerGap_1 = subBlockLen > 1 || subBlockLen > 0 && !frag.noHeader; + each$4(frag.blocks, function (subBlock) { + var subGapLevel = getBlockGapLevel(subBlock); // If the some of the sub-blocks have some gaps (like 10px) inside, this block + // should use a larger gap (like 20px) to distinguish those sub-blocks. + + if (subGapLevel >= gapLevel_1) { + gapLevel_1 = subGapLevel + +(hasInnerGap_1 && ( // 0 always can not be readable gap level. + !subGapLevel // If no header, always keep the sub gap level. Otherwise + // look weird in case `multipleSeries`. + || isSectionFragment(subBlock) && !subBlock.noHeader)); + } + }); + return gapLevel_1; + } + + return 0; + } + + function buildSection(ctx, fragment, topMarginForOuterGap, toolTipTextStyle) { + var noHeader = fragment.noHeader; + var gaps = getGap(getBlockGapLevel(fragment)); + var subMarkupTextList = []; + var subBlocks = fragment.blocks || []; + assert(!subBlocks || isArray(subBlocks)); + subBlocks = subBlocks || []; + var orderMode = ctx.orderMode; + + if (fragment.sortBlocks && orderMode) { + subBlocks = subBlocks.slice(); + var orderMap = { + valueAsc: 'asc', + valueDesc: 'desc' + }; + + if (hasOwn(orderMap, orderMode)) { + var comparator_1 = new SortOrderComparator(orderMap[orderMode], null); + subBlocks.sort(function (a, b) { + return comparator_1.evaluate(a.sortParam, b.sortParam); + }); + } // FIXME 'seriesDesc' necessary? + else if (orderMode === 'seriesDesc') { + subBlocks.reverse(); + } + } + + each$4(subBlocks, function (subBlock, idx) { + var valueFormatter = fragment.valueFormatter; + var subMarkupText = getBuilder(subBlock)( // Inherit valueFormatter + valueFormatter ? extend(extend({}, ctx), { + valueFormatter: valueFormatter + }) : ctx, subBlock, idx > 0 ? gaps.html : 0, toolTipTextStyle); + subMarkupText != null && subMarkupTextList.push(subMarkupText); + }); + var subMarkupText = ctx.renderMode === 'richText' ? subMarkupTextList.join(gaps.richText) : wrapBlockHTML(toolTipTextStyle, subMarkupTextList.join(''), noHeader ? topMarginForOuterGap : gaps.html); + + if (noHeader) { + return subMarkupText; + } + + var displayableHeader = makeValueReadable(fragment.header, 'ordinal', ctx.useUTC); + var nameStyle = getTooltipTextStyle(toolTipTextStyle, ctx.renderMode).nameStyle; + var tooltipLineHeight = getTooltipLineHeight(toolTipTextStyle); + + if (ctx.renderMode === 'richText') { + return wrapInlineNameRichText(ctx, displayableHeader, nameStyle) + gaps.richText + subMarkupText; + } else { + return wrapBlockHTML(toolTipTextStyle, "
" + encodeHTML(displayableHeader) + '
' + subMarkupText, topMarginForOuterGap); + } + } + + function buildNameValue(ctx, fragment, topMarginForOuterGap, toolTipTextStyle) { + var renderMode = ctx.renderMode; + var noName = fragment.noName; + var noValue = fragment.noValue; + var noMarker = !fragment.markerType; + var name = fragment.name; + var useUTC = ctx.useUTC; + + var valueFormatter = fragment.valueFormatter || ctx.valueFormatter || function (value) { + value = isArray(value) ? value : [value]; + return map$1(value, function (val, idx) { + return makeValueReadable(val, isArray(valueTypeOption) ? valueTypeOption[idx] : valueTypeOption, useUTC); + }); + }; + + if (noName && noValue) { + return; + } + + var markerStr = noMarker ? '' : ctx.markupStyleCreator.makeTooltipMarker(fragment.markerType, fragment.markerColor || tokens.color.secondary, renderMode); + var readableName = noName ? '' : makeValueReadable(name, 'ordinal', useUTC); + var valueTypeOption = fragment.valueType; + var readableValueList = noValue ? [] : valueFormatter(fragment.value, fragment.dataIndex); + var valueAlignRight = !noMarker || !noName; // It little weird if only value next to marker but far from marker. + + var valueCloseToMarker = !noMarker && noName; + + var _a = getTooltipTextStyle(toolTipTextStyle, renderMode), + nameStyle = _a.nameStyle, + valueStyle = _a.valueStyle; + + return renderMode === 'richText' ? (noMarker ? '' : markerStr) + (noName ? '' : wrapInlineNameRichText(ctx, readableName, nameStyle)) // Value has commas inside, so use ' ' as delimiter for multiple values. + + (noValue ? '' : wrapInlineValueRichText(ctx, readableValueList, valueAlignRight, valueCloseToMarker, valueStyle)) : wrapBlockHTML(toolTipTextStyle, (noMarker ? '' : markerStr) + (noName ? '' : wrapInlineNameHTML(readableName, !noMarker, nameStyle)) + (noValue ? '' : wrapInlineValueHTML(readableValueList, valueAlignRight, valueCloseToMarker, valueStyle)), topMarginForOuterGap); + } + /** + * @return markupText. null/undefined means no content. + */ + + + function buildTooltipMarkup(fragment, markupStyleCreator, renderMode, orderMode, useUTC, toolTipTextStyle) { + if (!fragment) { + return; + } + + var builder = getBuilder(fragment); + var ctx = { + useUTC: useUTC, + renderMode: renderMode, + orderMode: orderMode, + markupStyleCreator: markupStyleCreator, + valueFormatter: fragment.valueFormatter + }; + return builder(ctx, fragment, 0, toolTipTextStyle); + } + + function getGap(gapLevel) { + return { + html: HTML_GAPS[gapLevel], + richText: RICH_TEXT_GAPS[gapLevel] + }; + } + + function wrapBlockHTML(textStyle, encodedContent, topGap) { + var clearfix = '
'; + var marginCSS = "margin: " + topGap + "px 0 0"; + var tooltipLineHeight = getTooltipLineHeight(textStyle); + return "
" + encodedContent + clearfix + '
'; + } + + function wrapInlineNameHTML(name, leftHasMarker, style) { + var marginCss = leftHasMarker ? 'margin-left:2px' : ''; + return "" + encodeHTML(name) + ''; + } + + function wrapInlineValueHTML(valueList, alignRight, valueCloseToMarker, style) { + // Do not too close to marker, considering there are multiple values separated by spaces. + var paddingStr = valueCloseToMarker ? '10px' : '20px'; + var alignCSS = alignRight ? "float:right;margin-left:" + paddingStr : ''; + valueList = isArray(valueList) ? valueList : [valueList]; + return "" // Value has commas inside, so use ' ' as delimiter for multiple values. + + map$1(valueList, function (value) { + return encodeHTML(value); + }).join('  ') + ''; + } + + function wrapInlineNameRichText(ctx, name, style) { + return ctx.markupStyleCreator.wrapRichTextStyle(name, style); + } + + function wrapInlineValueRichText(ctx, values, alignRight, valueCloseToMarker, style) { + var styles = [style]; + var paddingLeft = valueCloseToMarker ? 10 : 20; + alignRight && styles.push({ + padding: [0, 0, 0, paddingLeft], + align: 'right' + }); // Value has commas inside, so use ' ' as delimiter for multiple values. + + return ctx.markupStyleCreator.wrapRichTextStyle(isArray(values) ? values.join(' ') : values, styles); + } + + function retrieveVisualColorForTooltipMarker(series, dataIndex) { + var style = series.getData().getItemVisual(dataIndex, 'style'); + var color = style[series.visualDrawType]; + return convertToColorString(color); + } + + function getPaddingFromTooltipModel(model, renderMode) { + var padding = model.get('padding'); + return padding != null ? padding // We give slightly different to look pretty. + : renderMode === 'richText' ? [8, 10] : 10; + } + /** + * The major feature is generate styles for `renderMode: 'richText'`. + * But it also serves `renderMode: 'html'` to provide + * "renderMode-independent" API. + */ + + + var TooltipMarkupStyleCreator = + /** @class */ + function () { + function TooltipMarkupStyleCreator() { + this.richTextStyles = {}; // Notice that "generate a style name" usually happens repeatedly when mouse is moving and + // a tooltip is displayed. So we put the `_nextStyleNameId` as a member of each creator + // rather than static shared by all creators (which will cause it increase to fast). + + this._nextStyleNameId = getRandomIdBase(); + } + + TooltipMarkupStyleCreator.prototype._generateStyleName = function () { + return '__EC_aUTo_' + this._nextStyleNameId++; + }; + + TooltipMarkupStyleCreator.prototype.makeTooltipMarker = function (markerType, colorStr, renderMode) { + var markerId = renderMode === 'richText' ? this._generateStyleName() : null; + var marker = getTooltipMarker({ + color: colorStr, + type: markerType, + renderMode: renderMode, + markerId: markerId + }); + + if (isString(marker)) { + return marker; + } else { + { + assert(markerId); + } + this.richTextStyles[markerId] = marker.style; + return marker.content; + } + }; + /** + * @usage + * ```ts + * const styledText = markupStyleCreator.wrapRichTextStyle([ + * // The styles will be auto merged. + * { + * fontSize: 12, + * color: 'blue' + * }, + * { + * padding: 20 + * } + * ]); + * ``` + */ + + + TooltipMarkupStyleCreator.prototype.wrapRichTextStyle = function (text, styles) { + var finalStl = {}; + + if (isArray(styles)) { + each$4(styles, function (stl) { + return extend(finalStl, stl); + }); + } else { + extend(finalStl, styles); + } + + var styleName = this._generateStyleName(); + + this.richTextStyles[styleName] = finalStl; + return "{" + styleName + "|" + text + "}"; + }; + + return TooltipMarkupStyleCreator; + }(); + + function defaultSeriesFormatTooltip(opt) { + var series = opt.series; + var dataIndex = opt.dataIndex; + var multipleSeries = opt.multipleSeries; + var data = series.getData(); + var tooltipDims = data.mapDimensionsAll('defaultedTooltip'); + var tooltipDimLen = tooltipDims.length; + var value = series.getRawValue(dataIndex); + var isValueArr = isArray(value); + var markerColor = retrieveVisualColorForTooltipMarker(series, dataIndex); // Complicated rule for pretty tooltip. + + var inlineValue; + var inlineValueType; + var subBlocks; + var sortParam; + + if (tooltipDimLen > 1 || isValueArr && !tooltipDimLen) { + var formatArrResult = formatTooltipArrayValue(value, series, dataIndex, tooltipDims, markerColor); + inlineValue = formatArrResult.inlineValues; + inlineValueType = formatArrResult.inlineValueTypes; + subBlocks = formatArrResult.blocks; // Only support tooltip sort by the first inline value. It's enough in most cases. + + sortParam = formatArrResult.inlineValues[0]; + } else if (tooltipDimLen) { + var dimInfo = data.getDimensionInfo(tooltipDims[0]); + sortParam = inlineValue = retrieveRawValue(data, dataIndex, tooltipDims[0]); + inlineValueType = dimInfo.type; + } else { + sortParam = inlineValue = isValueArr ? value[0] : value; + } // Do not show generated series name. It might not be readable. + + + var seriesNameSpecified = isNameSpecified(series); + var seriesName = seriesNameSpecified && series.name || ''; + var itemName = data.getName(dataIndex); + var inlineName = multipleSeries ? seriesName : itemName; + return createTooltipMarkup('section', { + header: seriesName, + // When series name is not specified, do not show a header line with only '-'. + // This case always happens in tooltip.trigger: 'item'. + noHeader: multipleSeries || !seriesNameSpecified, + sortParam: sortParam, + blocks: [createTooltipMarkup('nameValue', { + markerType: 'item', + markerColor: markerColor, + // Do not mix display seriesName and itemName in one tooltip, + // which might confuses users. + name: inlineName, + // name dimension might be auto assigned, where the name might + // be not readable. So we check trim here. + noName: !trim(inlineName), + value: inlineValue, + valueType: inlineValueType, + dataIndex: dataIndex + })].concat(subBlocks || []) + }); + } + + function formatTooltipArrayValue(value, series, dataIndex, tooltipDims, colorStr) { + // check: category-no-encode-has-axis-data in dataset.html + var data = series.getData(); + var isValueMultipleLine = reduce(value, function (isValueMultipleLine, val, idx) { + var dimItem = data.getDimensionInfo(idx); + return isValueMultipleLine = isValueMultipleLine || dimItem && dimItem.tooltip !== false && dimItem.displayName != null; + }, false); + var inlineValues = []; + var inlineValueTypes = []; + var blocks = []; + tooltipDims.length ? each$4(tooltipDims, function (dim) { + setEachItem(retrieveRawValue(data, dataIndex, dim), dim); + }) // By default, all dims is used on tooltip. + : each$4(value, setEachItem); + + function setEachItem(val, dim) { + var dimInfo = data.getDimensionInfo(dim); // If `dimInfo.tooltip` is not set, show tooltip. + + if (!dimInfo || dimInfo.otherDims.tooltip === false) { + return; + } + + if (isValueMultipleLine) { + blocks.push(createTooltipMarkup('nameValue', { + markerType: 'subItem', + markerColor: colorStr, + name: dimInfo.displayName, + value: val, + valueType: dimInfo.type + })); + } else { + inlineValues.push(val); + inlineValueTypes.push(dimInfo.type); + } + } + + return { + inlineValues: inlineValues, + inlineValueTypes: inlineValueTypes, + blocks: blocks + }; + } + + var inner$a = makeInner(); + + function getSelectionKey(data, dataIndex) { + return data.getName(dataIndex) || data.getId(dataIndex); + } + + var SERIES_UNIVERSAL_TRANSITION_PROP = '__universalTransitionEnabled'; + + var SeriesModel = + /** @class */ + function (_super) { + __extends(SeriesModel, _super); + + function SeriesModel() { + // [Caution]: Because this class or desecendants can be used as `XXX.extend(subProto)`, + // the class members must not be initialized in constructor or declaration place. + // Otherwise there is bad case: + // class A {xxx = 1;} + // enableClassExtend(A); + // class B extends A {} + // var C = B.extend({xxx: 5}); + // var c = new C(); + // console.log(c.xxx); // expect 5 but always 1. + var _this = _super !== null && _super.apply(this, arguments) || this; // --------------------------------------- + // Props about data selection + // --------------------------------------- + + + _this._selectedDataIndicesMap = {}; + return _this; + } + + SeriesModel.prototype.init = function (option, parentModel, ecModel) { + this.seriesIndex = this.componentIndex; + this.dataTask = createTask({ + count: dataTaskCount, + reset: dataTaskReset + }); + this.dataTask.context = { + model: this + }; + this.mergeDefaultAndTheme(option, ecModel); + var sourceManager = inner$a(this).sourceManager = new SourceManager(this); + sourceManager.prepareSource(); + var data = this.getInitialData(option, ecModel); + wrapData(data, this); + this.dataTask.context.data = data; + { + assert(data, 'getInitialData returned invalid data.'); + } + inner$a(this).dataBeforeProcessed = data; // If we reverse the order (make data firstly, and then make + // dataBeforeProcessed by cloneShallow), cloneShallow will + // cause data.graph.data !== data when using + // module:echarts/data/Graph or module:echarts/data/Tree. + // See module:echarts/data/helper/linkSeriesData + // Theoretically, it is unreasonable to call `seriesModel.getData()` in the model + // init or merge stage, because the data can be restored. So we do not `restoreData` + // and `setData` here, which forbids calling `seriesModel.getData()` in this stage. + // Call `seriesModel.getRawData()` instead. + // this.restoreData(); + + autoSeriesName(this); + + this._initSelectedMapFromData(data); + }; + /** + * Util for merge default and theme to option + */ + + + SeriesModel.prototype.mergeDefaultAndTheme = function (option, ecModel) { + var layoutMode = fetchLayoutMode(this); + var inputPositionParams = layoutMode ? getLayoutParams(option) : {}; // Backward compat: using subType on theme. + // But if name duplicate between series subType + // (for example: parallel) add component mainType, + // add suffix 'Series'. + + var themeSubType = this.subType; + + if (ComponentModel.hasClass(themeSubType)) { + themeSubType += 'Series'; + } + + merge(option, ecModel.getTheme().get(this.subType)); + merge(option, this.getDefaultOption()); // Default label emphasis `show` + + defaultEmphasis(option, 'label', ['show']); + this.fillDataTextStyle(option.data); + + if (layoutMode) { + mergeLayoutParam(option, inputPositionParams, layoutMode); + } + }; + + SeriesModel.prototype.mergeOption = function (newSeriesOption, ecModel) { + // this.settingTask.dirty(); + newSeriesOption = merge(this.option, newSeriesOption, true); + this.fillDataTextStyle(newSeriesOption.data); + var layoutMode = fetchLayoutMode(this); + + if (layoutMode) { + mergeLayoutParam(this.option, newSeriesOption, layoutMode); + } + + var sourceManager = inner$a(this).sourceManager; + sourceManager.dirty(); + sourceManager.prepareSource(); + var data = this.getInitialData(newSeriesOption, ecModel); + wrapData(data, this); + this.dataTask.dirty(); + this.dataTask.context.data = data; + inner$a(this).dataBeforeProcessed = data; + autoSeriesName(this); + + this._initSelectedMapFromData(data); + }; + + SeriesModel.prototype.fillDataTextStyle = function (data) { + // Default data label emphasis `show` + // FIXME Tree structure data ? + // FIXME Performance ? + if (data && !isTypedArray(data)) { + var props = ['show']; + + for (var i = 0; i < data.length; i++) { + if (data[i] && data[i].label) { + defaultEmphasis(data[i], 'label', props); + } + } + } + }; + /** + * Init a data structure from data related option in series + * Must be overridden. + */ + + + SeriesModel.prototype.getInitialData = function (option, ecModel) { + return; + }; + /** + * Append data to list + */ + + + SeriesModel.prototype.appendData = function (params) { + // FIXME ??? + // (1) If data from dataset, forbidden append. + // (2) support append data of dataset. + var data = this.getRawData(); + data.appendData(params.data); + }; + /** + * Consider some method like `filter`, `map` need make new data, + * We should make sure that `seriesModel.getData()` get correct + * data in the stream procedure. So we fetch data from upstream + * each time `task.perform` called. + */ + + + SeriesModel.prototype.getData = function (dataType) { + var task = getCurrentTask(this); + + if (task) { + var data = task.context.data; + return dataType == null || !data.getLinkedData ? data : data.getLinkedData(dataType); + } else { + // When series is not alive (that may happen when click toolbox + // restore or setOption with not merge mode), series data may + // be still need to judge animation or something when graphic + // elements want to know whether fade out. + return inner$a(this).data; + } + }; + + SeriesModel.prototype.getAllData = function () { + var mainData = this.getData(); + return mainData && mainData.getLinkedDataAll ? mainData.getLinkedDataAll() : [{ + data: mainData + }]; + }; + + SeriesModel.prototype.setData = function (data) { + var task = getCurrentTask(this); + + if (task) { + var context = task.context; // Consider case: filter, data sample. + // FIXME:TS never used, so comment it + // if (context.data !== data && task.modifyOutputEnd) { + // task.setOutputEnd(data.count()); + // } + + context.outputData = data; // Caution: setData should update context.data, + // Because getData may be called multiply in a + // single stage and expect to get the data just + // set. (For example, AxisProxy, x y both call + // getData and setDate sequentially). + // So the context.data should be fetched from + // upstream each time when a stage starts to be + // performed. + + if (task !== this.dataTask) { + context.data = data; + } + } + + inner$a(this).data = data; + }; + + SeriesModel.prototype.getEncode = function () { + var encode = this.get('encode', true); + + if (encode) { + return createHashMap(encode); + } + }; + + SeriesModel.prototype.getSourceManager = function () { + return inner$a(this).sourceManager; + }; + + SeriesModel.prototype.getSource = function () { + return this.getSourceManager().getSource(); + }; + /** + * Get data before processed + */ + + + SeriesModel.prototype.getRawData = function () { + return inner$a(this).dataBeforeProcessed; + }; + + SeriesModel.prototype.getColorBy = function () { + var colorBy = this.get('colorBy'); + return colorBy || 'series'; + }; + + SeriesModel.prototype.isColorBySeries = function () { + return this.getColorBy() === 'series'; + }; + /** + * Get base axis if has coordinate system and has axis. + * By default use coordSys.getBaseAxis(); + * Can be overridden for some chart. + * @return {type} description + */ + + + SeriesModel.prototype.getBaseAxis = function () { + var coordSys = this.coordinateSystem; // @ts-ignore + + return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis(); + }; + /** + * Retrieve the index of nearest value in the view coordinate. + * Data position is compared with each axis's dataToCoord. + * + * @param axisDim axis dimension + * @param dim data dimension + * @param value + * @param [maxDistance=Infinity] The maximum distance in view coordinate space + * @return If and only if multiple indices has + * the same value, they are put to the result. + */ + + + SeriesModel.prototype.indicesOfNearest = function (axisDim, dim, value, maxDistance) { + var data = this.getData(); + var coordSys = this.coordinateSystem; + var axis = coordSys && coordSys.getAxis(axisDim); + + if (!coordSys || !axis) { + return []; + } + + var targetCoord = axis.dataToCoord(value); + + if (maxDistance == null) { + maxDistance = Infinity; + } + + var nearestIndices = []; + var minDist = Infinity; + var minDiff = -1; + var nearestIndicesLen = 0; + data.each(dim, function (dimValue, idx) { + var dataCoord = axis.dataToCoord(dimValue); + var diff = targetCoord - dataCoord; + var dist = Math.abs(diff); + + if (dist <= maxDistance) { + // When the `value` is at the middle of `this.get(dim, i)` and `this.get(dim, i+1)`, + // we'd better not push both of them to `nearestIndices`, otherwise it is easy to + // get more than one item in `nearestIndices` (more specifically, in `tooltip`). + // So we choose the one that `diff >= 0` in this case. + // But if `this.get(dim, i)` and `this.get(dim, j)` get the same value, both of them + // should be push to `nearestIndices`. + if (dist < minDist || dist === minDist && diff >= 0 && minDiff < 0) { + minDist = dist; + minDiff = diff; + nearestIndicesLen = 0; + } + + if (diff === minDiff) { + nearestIndices[nearestIndicesLen++] = idx; + } + } + }); + nearestIndices.length = nearestIndicesLen; + return nearestIndices; + }; + /** + * Default tooltip formatter + * + * @param dataIndex + * @param multipleSeries + * @param dataType + * @param renderMode valid values: 'html'(by default) and 'richText'. + * 'html' is used for rendering tooltip in extra DOM form, and the result + * string is used as DOM HTML content. + * 'richText' is used for rendering tooltip in rich text form, for those where + * DOM operation is not supported. + * @return formatted tooltip with `html` and `markers` + * Notice: The override method can also return string + */ + + + SeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + return defaultSeriesFormatTooltip({ + series: this, + dataIndex: dataIndex, + multipleSeries: multipleSeries + }); + }; + + SeriesModel.prototype.isAnimationEnabled = function () { + var ecModel = this.ecModel; // Disable animation if using echarts in node but not give ssr flag. + // In ssr mode, renderToString will generate svg with css animation. + + if (env.node && !(ecModel && ecModel.ssr)) { + return false; + } + + var animationEnabled = this.getShallow('animation'); + + if (animationEnabled) { + if (this.getData().count() > this.getShallow('animationThreshold')) { + animationEnabled = false; + } + } + + return !!animationEnabled; + }; + + SeriesModel.prototype.restoreData = function () { + this.dataTask.dirty(); + }; + + SeriesModel.prototype.getColorFromPalette = function (name, scope, requestColorNum) { + var ecModel = this.ecModel; // PENDING + + var color = PaletteMixin.prototype.getColorFromPalette.call(this, name, scope, requestColorNum); + + if (!color) { + color = ecModel.getColorFromPalette(name, scope, requestColorNum); + } + + return color; + }; + /** + * Use `data.mapDimensionsAll(coordDim)` instead. + * @deprecated + */ + + + SeriesModel.prototype.coordDimToDataDim = function (coordDim) { + return this.getRawData().mapDimensionsAll(coordDim); + }; + /** + * Get progressive rendering count each step + */ + + + SeriesModel.prototype.getProgressive = function () { + return this.get('progressive'); + }; + /** + * Get progressive rendering count each step + */ + + + SeriesModel.prototype.getProgressiveThreshold = function () { + return this.get('progressiveThreshold'); + }; // PENGING If selectedMode is null ? + + + SeriesModel.prototype.select = function (innerDataIndices, dataType) { + this._innerSelect(this.getData(dataType), innerDataIndices); + }; + + SeriesModel.prototype.unselect = function (innerDataIndices, dataType) { + var selectedMap = this.option.selectedMap; + + if (!selectedMap) { + return; + } + + var selectedMode = this.option.selectedMode; + var data = this.getData(dataType); + + if (selectedMode === 'series' || selectedMap === 'all') { + this.option.selectedMap = {}; + this._selectedDataIndicesMap = {}; + return; + } + + for (var i = 0; i < innerDataIndices.length; i++) { + var dataIndex = innerDataIndices[i]; + var nameOrId = getSelectionKey(data, dataIndex); + selectedMap[nameOrId] = false; + this._selectedDataIndicesMap[nameOrId] = -1; + } + }; + + SeriesModel.prototype.toggleSelect = function (innerDataIndices, dataType) { + var tmpArr = []; + + for (var i = 0; i < innerDataIndices.length; i++) { + tmpArr[0] = innerDataIndices[i]; + this.isSelected(innerDataIndices[i], dataType) ? this.unselect(tmpArr, dataType) : this.select(tmpArr, dataType); + } + }; + + SeriesModel.prototype.getSelectedDataIndices = function () { + if (this.option.selectedMap === 'all') { + return [].slice.call(this.getData().getIndices()); + } + + var selectedDataIndicesMap = this._selectedDataIndicesMap; + var nameOrIds = keys(selectedDataIndicesMap); + var dataIndices = []; + + for (var i = 0; i < nameOrIds.length; i++) { + var dataIndex = selectedDataIndicesMap[nameOrIds[i]]; + + if (dataIndex >= 0) { + dataIndices.push(dataIndex); + } + } + + return dataIndices; + }; + + SeriesModel.prototype.isSelected = function (dataIndex, dataType) { + var selectedMap = this.option.selectedMap; + + if (!selectedMap) { + return false; + } + + var data = this.getData(dataType); + return (selectedMap === 'all' || selectedMap[getSelectionKey(data, dataIndex)]) && !data.getItemModel(dataIndex).get(['select', 'disabled']); + }; + + SeriesModel.prototype.isUniversalTransitionEnabled = function () { + if (this[SERIES_UNIVERSAL_TRANSITION_PROP]) { + return true; + } + + var universalTransitionOpt = this.option.universalTransition; // Quick reject + + if (!universalTransitionOpt) { + return false; + } + + if (universalTransitionOpt === true) { + return true; + } // Can be simply 'universalTransition: true' + + + return universalTransitionOpt && universalTransitionOpt.enabled; + }; + + SeriesModel.prototype._innerSelect = function (data, innerDataIndices) { + var _a, _b; + + var option = this.option; + var selectedMode = option.selectedMode; + var len = innerDataIndices.length; + + if (!selectedMode || !len) { + return; + } + + if (selectedMode === 'series') { + option.selectedMap = 'all'; + } else if (selectedMode === 'multiple') { + if (!isObject$2(option.selectedMap)) { + option.selectedMap = {}; + } + + var selectedMap = option.selectedMap; + + for (var i = 0; i < len; i++) { + var dataIndex = innerDataIndices[i]; // TODO different types of data share same object. + + var nameOrId = getSelectionKey(data, dataIndex); + selectedMap[nameOrId] = true; + this._selectedDataIndicesMap[nameOrId] = data.getRawIndex(dataIndex); + } + } else if (selectedMode === 'single' || selectedMode === true) { + var lastDataIndex = innerDataIndices[len - 1]; + var nameOrId = getSelectionKey(data, lastDataIndex); + option.selectedMap = (_a = {}, _a[nameOrId] = true, _a); + this._selectedDataIndicesMap = (_b = {}, _b[nameOrId] = data.getRawIndex(lastDataIndex), _b); + } + }; + + SeriesModel.prototype._initSelectedMapFromData = function (data) { + // Ignore select info in data if selectedMap exists. + // NOTE It's only for legacy usage. edge data is not supported. + if (this.option.selectedMap) { + return; + } + + var dataIndices = []; + + if (data.hasItemOption) { + data.each(function (idx) { + var rawItem = data.getRawDataItem(idx); + + if (rawItem && rawItem.selected) { + dataIndices.push(idx); + } + }); + } + + if (dataIndices.length > 0) { + this._innerSelect(data, dataIndices); + } + }; // /** + // * @see {module:echarts/stream/Scheduler} + // */ + // abstract pipeTask: null + + + SeriesModel.registerClass = function (clz) { + return ComponentModel.registerClass(clz); + }; + + SeriesModel.protoInitialize = function () { + var proto = SeriesModel.prototype; + proto.type = 'series.__base__'; + proto.seriesIndex = 0; + proto.ignoreStyleOnData = false; + proto.hasSymbolVisual = false; + proto.defaultSymbol = 'circle'; // Make sure the values can be accessed! + + proto.visualStyleAccessPath = 'itemStyle'; + proto.visualDrawType = 'fill'; + }(); + + return SeriesModel; + }(ComponentModel); + + mixin(SeriesModel, DataFormatMixin); + mixin(SeriesModel, PaletteMixin); + mountExtend(SeriesModel, ComponentModel); + /** + * MUST be called after `prepareSource` called + * Here we need to make auto series, especially for auto legend. But we + * do not modify series.name in option to avoid side effects. + */ + + function autoSeriesName(seriesModel) { + // User specified name has higher priority, otherwise it may cause + // series can not be queried unexpectedly. + var name = seriesModel.name; + + if (!isNameSpecified(seriesModel)) { + seriesModel.name = getSeriesAutoName(seriesModel) || name; + } + } + + function getSeriesAutoName(seriesModel) { + var data = seriesModel.getRawData(); + var dataDims = data.mapDimensionsAll('seriesName'); + var nameArr = []; + each$4(dataDims, function (dataDim) { + var dimInfo = data.getDimensionInfo(dataDim); + dimInfo.displayName && nameArr.push(dimInfo.displayName); + }); + return nameArr.join(' '); + } + + function dataTaskCount(context) { + return context.model.getRawData().count(); + } + + function dataTaskReset(context) { + var seriesModel = context.model; + seriesModel.setData(seriesModel.getRawData().cloneShallow()); + return dataTaskProgress; + } + + function dataTaskProgress(param, context) { + // Avoid repeat cloneShallow when data just created in reset. + if (context.outputData && param.end > context.outputData.count()) { + context.model.getRawData().cloneShallow(context.outputData); + } + } // TODO refactor + + + function wrapData(data, seriesModel) { + each$4(concatArray(data.CHANGABLE_METHODS, data.DOWNSAMPLE_METHODS), function (methodName) { + data.wrapMethod(methodName, curry$1(onDataChange, seriesModel)); + }); + } + + function onDataChange(seriesModel, newList) { + var task = getCurrentTask(seriesModel); + + if (task) { + // Consider case: filter, selectRange + task.setOutputEnd((newList || this).count()); + } + + return newList; + } + + function getCurrentTask(seriesModel) { + var scheduler = (seriesModel.ecModel || {}).scheduler; + var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid); + + if (pipeline) { + // When pipline finished, the currrentTask keep the last + // task (renderTask). + var task = pipeline.currentTask; + + if (task) { + var agentStubMap = task.agentStubMap; + + if (agentStubMap) { + task = agentStubMap.get(seriesModel.uid); + } + } + + return task; + } + } + + var ComponentView = + /** @class */ + function () { + function ComponentView() { + this.group = new Group$2(); + this.uid = getUID('viewComponent'); + } + + ComponentView.prototype.init = function (ecModel, api) {}; + + ComponentView.prototype.render = function (model, ecModel, api, payload) {}; + + ComponentView.prototype.dispose = function (ecModel, api) {}; + + ComponentView.prototype.updateView = function (model, ecModel, api, payload) {// Do nothing; + }; + + ComponentView.prototype.updateLayout = function (model, ecModel, api, payload) {// Do nothing; + }; + + ComponentView.prototype.updateVisual = function (model, ecModel, api, payload) {// Do nothing; + }; + /** + * Hook for toggle blur target series. + * Can be used in marker for blur or leave blur the markers + */ + + + ComponentView.prototype.toggleBlurSeries = function (seriesModels, isBlur, ecModel) {// Do nothing; + }; + /** + * Traverse the new rendered elements. + * + * It will traverse the new added element in progressive rendering. + * And traverse all in normal rendering. + */ + + + ComponentView.prototype.eachRendered = function (cb) { + var group = this.group; + + if (group) { + group.traverse(cb); + } + }; + + return ComponentView; + }(); + + enableClassExtend(ComponentView); + enableClassManagement(ComponentView); + /** + * @return {string} If large mode changed, return string 'reset'; + */ + + function createRenderPlanner() { + var inner = makeInner(); + return function (seriesModel) { + var fields = inner(seriesModel); + var pipelineContext = seriesModel.pipelineContext; + var originalLarge = !!fields.large; + var originalProgressive = !!fields.progressiveRender; // FIXME: if the planner works on a filtered series, `pipelineContext` does not + // exists. See #11611 . Probably we need to modify this structure, see the comment + // on `performRawSeries` in `Schedular.js`. + + var large = fields.large = !!(pipelineContext && pipelineContext.large); + var progressive = fields.progressiveRender = !!(pipelineContext && pipelineContext.progressiveRender); + return !!(originalLarge !== large || originalProgressive !== progressive) && 'reset'; + }; + } + + var inner$9 = makeInner(); + var renderPlanner = createRenderPlanner(); + + var ChartView = + /** @class */ + function () { + function ChartView() { + this.group = new Group$2(); + this.uid = getUID('viewChart'); + this.renderTask = createTask({ + plan: renderTaskPlan, + reset: renderTaskReset + }); + this.renderTask.context = { + view: this + }; + } + + ChartView.prototype.init = function (ecModel, api) {}; + + ChartView.prototype.render = function (seriesModel, ecModel, api, payload) { + { + throw new Error('render method must been implemented'); + } + }; + /** + * Highlight series or specified data item. + */ + + + ChartView.prototype.highlight = function (seriesModel, ecModel, api, payload) { + var data = seriesModel.getData(payload && payload.dataType); + + if (!data) { + { + error("Unknown dataType " + payload.dataType); + } + return; + } + + toggleHighlight(data, payload, 'emphasis'); + }; + /** + * Downplay series or specified data item. + */ + + + ChartView.prototype.downplay = function (seriesModel, ecModel, api, payload) { + var data = seriesModel.getData(payload && payload.dataType); + + if (!data) { + { + error("Unknown dataType " + payload.dataType); + } + return; + } + + toggleHighlight(data, payload, 'normal'); + }; + /** + * Remove self. + */ + + + ChartView.prototype.remove = function (ecModel, api) { + this.group.removeAll(); + }; + /** + * Dispose self. + */ + + + ChartView.prototype.dispose = function (ecModel, api) {}; + + ChartView.prototype.updateView = function (seriesModel, ecModel, api, payload) { + this.render(seriesModel, ecModel, api, payload); + }; // FIXME never used? + + + ChartView.prototype.updateLayout = function (seriesModel, ecModel, api, payload) { + this.render(seriesModel, ecModel, api, payload); + }; // FIXME never used? + + + ChartView.prototype.updateVisual = function (seriesModel, ecModel, api, payload) { + this.render(seriesModel, ecModel, api, payload); + }; + /** + * Traverse the new rendered elements. + * + * It will traverse the new added element in progressive rendering. + * And traverse all in normal rendering. + */ + + + ChartView.prototype.eachRendered = function (cb) { + traverseElements(this.group, cb); + }; + + ChartView.markUpdateMethod = function (payload, methodName) { + inner$9(payload).updateMethod = methodName; + }; + + ChartView.protoInitialize = function () { + var proto = ChartView.prototype; + proto.type = 'chart'; + }(); + + return ChartView; + }(); + /** + * Set state of single element + */ + + + function elSetState(el, state, highlightDigit) { + if (el && isHighDownDispatcher(el)) { + (state === 'emphasis' ? enterEmphasis : leaveEmphasis)(el, highlightDigit); + } + } + + function toggleHighlight(data, payload, state) { + var dataIndex = queryDataIndex(data, payload); + var highlightDigit = payload && payload.highlightKey != null ? getHighlightDigit(payload.highlightKey) : null; + + if (dataIndex != null) { + each$4(normalizeToArray(dataIndex), function (dataIdx) { + elSetState(data.getItemGraphicEl(dataIdx), state, highlightDigit); + }); + } else { + data.eachItemGraphicEl(function (el) { + elSetState(el, state, highlightDigit); + }); + } + } + + enableClassExtend(ChartView, ['dispose']); + enableClassManagement(ChartView); + + function renderTaskPlan(context) { + return renderPlanner(context.model); + } + + function renderTaskReset(context) { + var seriesModel = context.model; + var ecModel = context.ecModel; + var api = context.api; + var payload = context.payload; // FIXME: remove updateView updateVisual + + var progressiveRender = seriesModel.pipelineContext.progressiveRender; + var view = context.view; + var updateMethod = payload && inner$9(payload).updateMethod; + var methodName = progressiveRender ? 'incrementalPrepareRender' : updateMethod && view[updateMethod] ? updateMethod // `appendData` is also supported when data amount + // is less than progressive threshold. + : 'render'; + + if (methodName !== 'render') { + view[methodName](seriesModel, ecModel, api, payload); + } + + return progressMethodMap[methodName]; + } + + var progressMethodMap = { + incrementalPrepareRender: { + progress: function (params, context) { + context.view.incrementalRender(params, context.model, context.ecModel, context.api, context.payload); + } + }, + render: { + // Put view.render in `progress` to support appendData. But in this case + // view.render should not be called in reset, otherwise it will be called + // twise. Use `forceFirstProgress` to make sure that view.render is called + // in any cases. + forceFirstProgress: true, + progress: function (params, context) { + context.view.render(context.model, context.ecModel, context.api, context.payload); + } + } + }; + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + var ORIGIN_METHOD = '\0__throttleOriginMethod'; + var RATE = '\0__throttleRate'; + var THROTTLE_TYPE = '\0__throttleType'; + /** + * @public + * @param {(Function)} fn + * @param {number} [delay=0] Unit: ms. + * @param {boolean} [debounce=false] + * true: If call interval less than `delay`, only the last call works. + * false: If call interval less than `delay, call works on fixed rate. + * @return {(Function)} throttled fn. + */ + + function throttle(fn, delay, debounce) { + var currCall; + var lastCall = 0; + var lastExec = 0; + var timer = null; + var diff; + var scope; + var args; + var debounceNextCall; + delay = delay || 0; + + function exec() { + lastExec = new Date().getTime(); + timer = null; + fn.apply(scope, args || []); + } + + var cb = function () { + var cbArgs = []; + + for (var _i = 0; _i < arguments.length; _i++) { + cbArgs[_i] = arguments[_i]; + } + + currCall = new Date().getTime(); + scope = this; + args = cbArgs; + var thisDelay = debounceNextCall || delay; + var thisDebounce = debounceNextCall || debounce; + debounceNextCall = null; + diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay; + clearTimeout(timer); // Here we should make sure that: the `exec` SHOULD NOT be called later + // than a new call of `cb`, that is, preserving the command order. Consider + // calculating "scale rate" when roaming as an example. When a call of `cb` + // happens, either the `exec` is called dierectly, or the call is delayed. + // But the delayed call should never be later than next call of `cb`. Under + // this assurance, we can simply update view state each time `dispatchAction` + // triggered by user roaming, but not need to add extra code to avoid the + // state being "rolled-back". + + if (thisDebounce) { + timer = setTimeout(exec, thisDelay); + } else { + if (diff >= 0) { + exec(); + } else { + timer = setTimeout(exec, -diff); + } + } + + lastCall = currCall; + }; + /** + * Clear throttle. + * @public + */ + + + cb.clear = function () { + if (timer) { + clearTimeout(timer); + timer = null; + } + }; + /** + * Enable debounce once. + */ + + + cb.debounceNextCall = function (debounceDelay) { + debounceNextCall = debounceDelay; + }; + + return cb; + } + /** + * Create throttle method or update throttle rate. + * + * @example + * ComponentView.prototype.render = function () { + * ... + * throttle.createOrUpdate( + * this, + * '_dispatchAction', + * this.model.get('throttle'), + * 'fixRate' + * ); + * }; + * ComponentView.prototype.remove = function () { + * throttle.clear(this, '_dispatchAction'); + * }; + * ComponentView.prototype.dispose = function () { + * throttle.clear(this, '_dispatchAction'); + * }; + * + */ + + + function createOrUpdate(obj, fnAttr, rate, throttleType) { + var fn = obj[fnAttr]; + + if (!fn) { + return; + } + + var originFn = fn[ORIGIN_METHOD] || fn; + var lastThrottleType = fn[THROTTLE_TYPE]; + var lastRate = fn[RATE]; + + if (lastRate !== rate || lastThrottleType !== throttleType) { + if (rate == null || !throttleType) { + return obj[fnAttr] = originFn; + } + + fn = obj[fnAttr] = throttle(originFn, rate, throttleType === 'debounce'); + fn[ORIGIN_METHOD] = originFn; + fn[THROTTLE_TYPE] = throttleType; + fn[RATE] = rate; + } + + return fn; + } + /** + * Clear throttle. Example see throttle.createOrUpdate. + */ + + + function clear(obj, fnAttr) { + var fn = obj[fnAttr]; + + if (fn && fn[ORIGIN_METHOD]) { + // Clear throttle + fn.clear && fn.clear(); + obj[fnAttr] = fn[ORIGIN_METHOD]; + } + } + + var inner$8 = makeInner(); + var defaultStyleMappers = { + itemStyle: makeStyleMapper(ITEM_STYLE_KEY_MAP, true), + lineStyle: makeStyleMapper(LINE_STYLE_KEY_MAP, true) + }; + var defaultColorKey = { + lineStyle: 'stroke', + itemStyle: 'fill' + }; + + function getStyleMapper(seriesModel, stylePath) { + var styleMapper = seriesModel.visualStyleMapper || defaultStyleMappers[stylePath]; + + if (!styleMapper) { + console.warn("Unknown style type '" + stylePath + "'."); + return defaultStyleMappers.itemStyle; + } + + return styleMapper; + } + + function getDefaultColorKey(seriesModel, stylePath) { + // return defaultColorKey[stylePath] || + var colorKey = seriesModel.visualDrawType || defaultColorKey[stylePath]; + + if (!colorKey) { + console.warn("Unknown style type '" + stylePath + "'."); + return 'fill'; + } + + return colorKey; + } + + var seriesStyleTask = { + createOnAllSeries: true, + performRawSeries: true, + reset: function (seriesModel, ecModel) { + var data = seriesModel.getData(); + var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; // Set in itemStyle + + var styleModel = seriesModel.getModel(stylePath); + var getStyle = getStyleMapper(seriesModel, stylePath); + var globalStyle = getStyle(styleModel); + var decalOption = styleModel.getShallow('decal'); + + if (decalOption) { + data.setVisual('decal', decalOption); + decalOption.dirty = true; + } // TODO + + + var colorKey = getDefaultColorKey(seriesModel, stylePath); + var color = globalStyle[colorKey]; // TODO style callback + + var colorCallback = isFunction(color) ? color : null; + var hasAutoColor = globalStyle.fill === 'auto' || globalStyle.stroke === 'auto'; // Get from color palette by default. + + if (!globalStyle[colorKey] || colorCallback || hasAutoColor) { + // Note: If some series has color specified (e.g., by itemStyle.color), we DO NOT + // make it effect palette. Because some scenarios users need to make some series + // transparent or as background, which should better not effect the palette. + var colorPalette = seriesModel.getColorFromPalette( // TODO series count changed. + seriesModel.name, null, ecModel.getSeriesCount()); + + if (!globalStyle[colorKey]) { + globalStyle[colorKey] = colorPalette; + data.setVisual('colorFromPalette', true); + } + + globalStyle.fill = globalStyle.fill === 'auto' || isFunction(globalStyle.fill) ? colorPalette : globalStyle.fill; + globalStyle.stroke = globalStyle.stroke === 'auto' || isFunction(globalStyle.stroke) ? colorPalette : globalStyle.stroke; + } + + data.setVisual('style', globalStyle); + data.setVisual('drawType', colorKey); // Only visible series has each data be visual encoded + + if (!ecModel.isSeriesFiltered(seriesModel) && colorCallback) { + data.setVisual('colorFromPalette', false); + return { + dataEach: function (data, idx) { + var dataParams = seriesModel.getDataParams(idx); + var itemStyle = extend({}, globalStyle); + itemStyle[colorKey] = colorCallback(dataParams); + data.setItemVisual(idx, 'style', itemStyle); + } + }; + } + } + }; + var sharedModel = new Model(); + var dataStyleTask = { + createOnAllSeries: true, + performRawSeries: true, + reset: function (seriesModel, ecModel) { + if (seriesModel.ignoreStyleOnData || ecModel.isSeriesFiltered(seriesModel)) { + return; + } + + var data = seriesModel.getData(); + var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; // Set in itemStyle + + var getStyle = getStyleMapper(seriesModel, stylePath); + var colorKey = data.getVisual('drawType'); + return { + dataEach: data.hasItemOption ? function (data, idx) { + // Not use getItemModel for performance considuration + var rawItem = data.getRawDataItem(idx); + + if (rawItem && rawItem[stylePath]) { + sharedModel.option = rawItem[stylePath]; + var style = getStyle(sharedModel); + var existsStyle = data.ensureUniqueItemVisual(idx, 'style'); + extend(existsStyle, style); + + if (sharedModel.option.decal) { + data.setItemVisual(idx, 'decal', sharedModel.option.decal); + sharedModel.option.decal.dirty = true; + } + + if (colorKey in style) { + data.setItemVisual(idx, 'colorFromPalette', false); + } + } + } : null + }; + } + }; // Pick color from palette for the data which has not been set with color yet. + // Note: do not support stream rendering. No such cases yet. + + var dataColorPaletteTask = { + performRawSeries: true, + overallReset: function (ecModel) { + // Each type of series uses one scope. + // Pie and funnel are using different scopes. + var paletteScopeGroupByType = createHashMap(); + ecModel.eachSeries(function (seriesModel) { + var colorBy = seriesModel.getColorBy(); + + if (seriesModel.isColorBySeries()) { + return; + } + + var key = seriesModel.type + '-' + colorBy; + var colorScope = paletteScopeGroupByType.get(key); + + if (!colorScope) { + colorScope = {}; + paletteScopeGroupByType.set(key, colorScope); + } + + inner$8(seriesModel).scope = colorScope; + }); + ecModel.eachSeries(function (seriesModel) { + if (seriesModel.isColorBySeries() || ecModel.isSeriesFiltered(seriesModel)) { + return; + } + + var dataAll = seriesModel.getRawData(); + var idxMap = {}; + var data = seriesModel.getData(); + var colorScope = inner$8(seriesModel).scope; + var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; + var colorKey = getDefaultColorKey(seriesModel, stylePath); + data.each(function (idx) { + var rawIdx = data.getRawIndex(idx); + idxMap[rawIdx] = idx; + }); // Iterate on data before filtered. To make sure color from palette can be + // Consistent when toggling legend. + + dataAll.each(function (rawIdx) { + var idx = idxMap[rawIdx]; + var fromPalette = data.getItemVisual(idx, 'colorFromPalette'); // Get color from palette for each data only when the color is inherited from series color, which is + // also picked from color palette. So following situation is not in the case: + // 1. series.itemStyle.color is set + // 2. color is encoded by visualMap + + if (fromPalette) { + var itemStyle = data.ensureUniqueItemVisual(idx, 'style'); + var name_1 = dataAll.getName(rawIdx) || rawIdx + ''; + var dataCount = dataAll.count(); + itemStyle[colorKey] = seriesModel.getColorFromPalette(name_1, colorScope, dataCount); + } + }); + }); + } + }; + var PI$1 = Math.PI; + /** + * @param {module:echarts/ExtensionAPI} api + * @param {Object} [opts] + * @param {string} [opts.text] + * @param {string} [opts.color] + * @param {string} [opts.textColor] + * @return {module:zrender/Element} + */ + + function defaultLoading(api, opts) { + opts = opts || {}; + defaults(opts, { + text: 'loading', + textColor: tokens.color.primary, + fontSize: 12, + fontWeight: 'normal', + fontStyle: 'normal', + fontFamily: 'sans-serif', + maskColor: 'rgba(255,255,255,0.8)', + showSpinner: true, + color: tokens.color.theme[0], + spinnerRadius: 10, + lineWidth: 5, + zlevel: 0 + }); + var group = new Group$2(); + var mask = new Rect({ + style: { + fill: opts.maskColor + }, + zlevel: opts.zlevel, + z: 10000 + }); + group.add(mask); + var textContent = new ZRText({ + style: { + text: opts.text, + fill: opts.textColor, + fontSize: opts.fontSize, + fontWeight: opts.fontWeight, + fontStyle: opts.fontStyle, + fontFamily: opts.fontFamily + }, + zlevel: opts.zlevel, + z: 10001 + }); + var labelRect = new Rect({ + style: { + fill: 'none' + }, + textContent: textContent, + textConfig: { + position: 'right', + distance: 10 + }, + zlevel: opts.zlevel, + z: 10001 + }); + group.add(labelRect); + var arc; + + if (opts.showSpinner) { + arc = new Arc({ + shape: { + startAngle: -PI$1 / 2, + endAngle: -PI$1 / 2 + 0.1, + r: opts.spinnerRadius + }, + style: { + stroke: opts.color, + lineCap: 'round', + lineWidth: opts.lineWidth + }, + zlevel: opts.zlevel, + z: 10001 + }); + arc.animateShape(true).when(1000, { + endAngle: PI$1 * 3 / 2 + }).start('circularInOut'); + arc.animateShape(true).when(1000, { + startAngle: PI$1 * 3 / 2 + }).delay(300).start('circularInOut'); + group.add(arc); + } // Inject resize + + + group.resize = function () { + var textWidth = textContent.getBoundingRect().width; + var r = opts.showSpinner ? opts.spinnerRadius : 0; // cx = (containerWidth - arcDiameter - textDistance - textWidth) / 2 + // textDistance needs to be calculated when both animation and text exist + + var cx = (api.getWidth() - r * 2 - (opts.showSpinner && textWidth ? 10 : 0) - textWidth) / 2 - (opts.showSpinner && textWidth ? 0 : 5 + textWidth / 2) // only show the text + + (opts.showSpinner ? 0 : textWidth / 2) // only show the spinner + + (textWidth ? 0 : r); + var cy = api.getHeight() / 2; + opts.showSpinner && arc.setShape({ + cx: cx, + cy: cy + }); + labelRect.setShape({ + x: cx - r, + y: cy - r, + width: r * 2, + height: r * 2 + }); + mask.setShape({ + x: 0, + y: 0, + width: api.getWidth(), + height: api.getHeight() + }); + }; + + group.resize(); + return group; + } + + var Scheduler = + /** @class */ + function () { + function Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) { + // key: handlerUID + this._stageTaskMap = createHashMap(); + this.ecInstance = ecInstance; + this.api = api; // Fix current processors in case that in some rear cases that + // processors might be registered after echarts instance created. + // Register processors incrementally for a echarts instance is + // not supported by this stream architecture. + + dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice(); + visualHandlers = this._visualHandlers = visualHandlers.slice(); + this._allHandlers = dataProcessorHandlers.concat(visualHandlers); + } + + Scheduler.prototype.restoreData = function (ecModel, payload) { + // TODO: Only restore needed series and components, but not all components. + // Currently `restoreData` of all of the series and component will be called. + // But some independent components like `title`, `legend`, `graphic`, `toolbox`, + // `tooltip`, `axisPointer`, etc, do not need series refresh when `setOption`, + // and some components like coordinate system, axes, dataZoom, visualMap only + // need their target series refresh. + // (1) If we are implementing this feature some day, we should consider these cases: + // if a data processor depends on a component (e.g., dataZoomProcessor depends + // on the settings of `dataZoom`), it should be re-performed if the component + // is modified by `setOption`. + // (2) If a processor depends on sevral series, speicified by its `getTargetSeries`, + // it should be re-performed when the result array of `getTargetSeries` changed. + // We use `dependencies` to cover these issues. + // (3) How to update target series when coordinate system related components modified. + // TODO: simply the dirty mechanism? Check whether only the case here can set tasks dirty, + // and this case all of the tasks will be set as dirty. + ecModel.restoreData(payload); // Theoretically an overall task not only depends on each of its target series, but also + // depends on all of the series. + // The overall task is not in pipeline, and `ecModel.restoreData` only set pipeline tasks + // dirty. If `getTargetSeries` of an overall task returns nothing, we should also ensure + // that the overall task is set as dirty and to be performed, otherwise it probably cause + // state chaos. So we have to set dirty of all of the overall tasks manually, otherwise it + // probably cause state chaos (consider `dataZoomProcessor`). + + this._stageTaskMap.each(function (taskRecord) { + var overallTask = taskRecord.overallTask; + overallTask && overallTask.dirty(); + }); + }; // If seriesModel provided, incremental threshold is check by series data. + + + Scheduler.prototype.getPerformArgs = function (task, isBlock) { + // For overall task + if (!task.__pipeline) { + return; + } + + var pipeline = this._pipelineMap.get(task.__pipeline.id); + + var pCtx = pipeline.context; + var incremental = !isBlock && pipeline.progressiveEnabled && (!pCtx || pCtx.progressiveRender) && task.__idxInPipeline > pipeline.blockIndex; + var step = incremental ? pipeline.step : null; + var modDataCount = pCtx && pCtx.modDataCount; + var modBy = modDataCount != null ? Math.ceil(modDataCount / step) : null; + return { + step: step, + modBy: modBy, + modDataCount: modDataCount + }; + }; + + Scheduler.prototype.getPipeline = function (pipelineId) { + return this._pipelineMap.get(pipelineId); + }; + /** + * Current, progressive rendering starts from visual and layout. + * Always detect render mode in the same stage, avoiding that incorrect + * detection caused by data filtering. + * Caution: + * `updateStreamModes` use `seriesModel.getData()`. + */ + + + Scheduler.prototype.updateStreamModes = function (seriesModel, view) { + var pipeline = this._pipelineMap.get(seriesModel.uid); + + var data = seriesModel.getData(); + var dataLen = data.count(); // `progressiveRender` means that can render progressively in each + // animation frame. Note that some types of series do not provide + // `view.incrementalPrepareRender` but support `chart.appendData`. We + // use the term `incremental` but not `progressive` to describe the + // case that `chart.appendData`. + + var progressiveRender = pipeline.progressiveEnabled && view.incrementalPrepareRender && dataLen >= pipeline.threshold; + var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold'); // TODO: modDataCount should not updated if `appendData`, otherwise cause whole repaint. + // see `test/candlestick-large3.html` + + var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null; + seriesModel.pipelineContext = pipeline.context = { + progressiveRender: progressiveRender, + modDataCount: modDataCount, + large: large + }; + }; + + Scheduler.prototype.restorePipelines = function (ecModel) { + var scheduler = this; + var pipelineMap = scheduler._pipelineMap = createHashMap(); + ecModel.eachSeries(function (seriesModel) { + var progressive = seriesModel.getProgressive(); + var pipelineId = seriesModel.uid; + pipelineMap.set(pipelineId, { + id: pipelineId, + head: null, + tail: null, + threshold: seriesModel.getProgressiveThreshold(), + progressiveEnabled: progressive && !(seriesModel.preventIncremental && seriesModel.preventIncremental()), + blockIndex: -1, + step: Math.round(progressive || 700), + count: 0 + }); + + scheduler._pipe(seriesModel, seriesModel.dataTask); + }); + }; + + Scheduler.prototype.prepareStageTasks = function () { + var stageTaskMap = this._stageTaskMap; + var ecModel = this.api.getModel(); + var api = this.api; + each$4(this._allHandlers, function (handler) { + var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, {}); + var errMsg = ''; + { + // Currently do not need to support to sepecify them both. + errMsg = '"reset" and "overallReset" must not be both specified.'; + } + assert(!(handler.reset && handler.overallReset), errMsg); + handler.reset && this._createSeriesStageTask(handler, record, ecModel, api); + handler.overallReset && this._createOverallStageTask(handler, record, ecModel, api); + }, this); + }; + + Scheduler.prototype.prepareView = function (view, model, ecModel, api) { + var renderTask = view.renderTask; + var context = renderTask.context; + context.model = model; + context.ecModel = ecModel; + context.api = api; + renderTask.__block = !view.incrementalPrepareRender; + + this._pipe(model, renderTask); + }; + + Scheduler.prototype.performDataProcessorTasks = function (ecModel, payload) { + // If we do not use `block` here, it should be considered when to update modes. + this._performStageTasks(this._dataProcessorHandlers, ecModel, payload, { + block: true + }); + }; + + Scheduler.prototype.performVisualTasks = function (ecModel, payload, opt) { + this._performStageTasks(this._visualHandlers, ecModel, payload, opt); + }; + + Scheduler.prototype._performStageTasks = function (stageHandlers, ecModel, payload, opt) { + opt = opt || {}; + var unfinished = false; + var scheduler = this; + each$4(stageHandlers, function (stageHandler, idx) { + if (opt.visualType && opt.visualType !== stageHandler.visualType) { + return; + } + + var stageHandlerRecord = scheduler._stageTaskMap.get(stageHandler.uid); + + var seriesTaskMap = stageHandlerRecord.seriesTaskMap; + var overallTask = stageHandlerRecord.overallTask; + + if (overallTask) { + var overallNeedDirty_1; + var agentStubMap = overallTask.agentStubMap; + agentStubMap.each(function (stub) { + if (needSetDirty(opt, stub)) { + stub.dirty(); + overallNeedDirty_1 = true; + } + }); + overallNeedDirty_1 && overallTask.dirty(); + scheduler.updatePayload(overallTask, payload); + var performArgs_1 = scheduler.getPerformArgs(overallTask, opt.block); // Execute stubs firstly, which may set the overall task dirty, + // then execute the overall task. And stub will call seriesModel.setData, + // which ensures that in the overallTask seriesModel.getData() will not + // return incorrect data. + + agentStubMap.each(function (stub) { + stub.perform(performArgs_1); + }); + + if (overallTask.perform(performArgs_1)) { + unfinished = true; + } + } else if (seriesTaskMap) { + seriesTaskMap.each(function (task, pipelineId) { + if (needSetDirty(opt, task)) { + task.dirty(); + } + + var performArgs = scheduler.getPerformArgs(task, opt.block); // FIXME + // if intending to declare `performRawSeries` in handlers, only + // stream-independent (specifically, data item independent) operations can be + // performed. Because if a series is filtered, most of the tasks will not + // be performed. A stream-dependent operation probably cause wrong biz logic. + // Perhaps we should not provide a separate callback for this case instead + // of providing the config `performRawSeries`. The stream-dependent operations + // and stream-independent operations should better not be mixed. + + performArgs.skip = !stageHandler.performRawSeries && ecModel.isSeriesFiltered(task.context.model); + scheduler.updatePayload(task, payload); + + if (task.perform(performArgs)) { + unfinished = true; + } + }); + } + }); + + function needSetDirty(opt, task) { + return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id)); + } + + this.unfinished = unfinished || this.unfinished; + }; + + Scheduler.prototype.performSeriesTasks = function (ecModel) { + var unfinished; + ecModel.eachSeries(function (seriesModel) { + // Progress to the end for dataInit and dataRestore. + unfinished = seriesModel.dataTask.perform() || unfinished; + }); + this.unfinished = unfinished || this.unfinished; + }; + + Scheduler.prototype.plan = function () { + // Travel pipelines, check block. + this._pipelineMap.each(function (pipeline) { + var task = pipeline.tail; + + do { + if (task.__block) { + pipeline.blockIndex = task.__idxInPipeline; + break; + } + + task = task.getUpstream(); + } while (task); + }); + }; + + Scheduler.prototype.updatePayload = function (task, payload) { + payload !== 'remain' && (task.context.payload = payload); + }; + + Scheduler.prototype._createSeriesStageTask = function (stageHandler, stageHandlerRecord, ecModel, api) { + var scheduler = this; + var oldSeriesTaskMap = stageHandlerRecord.seriesTaskMap; // The count of stages are totally about only several dozen, so + // do not need to reuse the map. + + var newSeriesTaskMap = stageHandlerRecord.seriesTaskMap = createHashMap(); + var seriesType = stageHandler.seriesType; + var getTargetSeries = stageHandler.getTargetSeries; // If a stageHandler should cover all series, `createOnAllSeries` should be declared mandatorily, + // to avoid some typo or abuse. Otherwise if an extension do not specify a `seriesType`, + // it works but it may cause other irrelevant charts blocked. + + if (stageHandler.createOnAllSeries) { + ecModel.eachRawSeries(create); + } else if (seriesType) { + ecModel.eachRawSeriesByType(seriesType, create); + } else if (getTargetSeries) { + getTargetSeries(ecModel, api).each(create); + } + + function create(seriesModel) { + var pipelineId = seriesModel.uid; // Init tasks for each seriesModel only once. + // Reuse original task instance. + + var task = newSeriesTaskMap.set(pipelineId, oldSeriesTaskMap && oldSeriesTaskMap.get(pipelineId) || createTask({ + plan: seriesTaskPlan, + reset: seriesTaskReset, + count: seriesTaskCount + })); + task.context = { + model: seriesModel, + ecModel: ecModel, + api: api, + // PENDING: `useClearVisual` not used? + useClearVisual: stageHandler.isVisual && !stageHandler.isLayout, + plan: stageHandler.plan, + reset: stageHandler.reset, + scheduler: scheduler + }; + + scheduler._pipe(seriesModel, task); + } + }; + + Scheduler.prototype._createOverallStageTask = function (stageHandler, stageHandlerRecord, ecModel, api) { + var scheduler = this; + var overallTask = stageHandlerRecord.overallTask = stageHandlerRecord.overallTask // For overall task, the function only be called on reset stage. + || createTask({ + reset: overallTaskReset + }); + overallTask.context = { + ecModel: ecModel, + api: api, + overallReset: stageHandler.overallReset, + scheduler: scheduler + }; + var oldAgentStubMap = overallTask.agentStubMap; // The count of stages are totally about only several dozen, so + // do not need to reuse the map. + + var newAgentStubMap = overallTask.agentStubMap = createHashMap(); + var seriesType = stageHandler.seriesType; + var getTargetSeries = stageHandler.getTargetSeries; + var overallProgress = true; + var shouldOverallTaskDirty = false; // FIXME:TS never used, so comment it + // let modifyOutputEnd = stageHandler.modifyOutputEnd; + // An overall task with seriesType detected or has `getTargetSeries`, we add + // stub in each pipelines, it will set the overall task dirty when the pipeline + // progress. Moreover, to avoid call the overall task each frame (too frequent), + // we set the pipeline block. + + var errMsg = ''; + { + errMsg = '"createOnAllSeries" is not supported for "overallReset", ' + 'because it will block all streams.'; + } + assert(!stageHandler.createOnAllSeries, errMsg); + + if (seriesType) { + ecModel.eachRawSeriesByType(seriesType, createStub); + } else if (getTargetSeries) { + getTargetSeries(ecModel, api).each(createStub); + } // Otherwise, (usually it is legacy case), the overall task will only be + // executed when upstream is dirty. Otherwise the progressive rendering of all + // pipelines will be disabled unexpectedly. But it still needs stubs to receive + // dirty info from upstream. + else { + overallProgress = false; + each$4(ecModel.getSeries(), createStub); + } + + function createStub(seriesModel) { + var pipelineId = seriesModel.uid; + var stub = newAgentStubMap.set(pipelineId, oldAgentStubMap && oldAgentStubMap.get(pipelineId) || ( // When the result of `getTargetSeries` changed, the overallTask + // should be set as dirty and re-performed. + shouldOverallTaskDirty = true, createTask({ + reset: stubReset, + onDirty: stubOnDirty + }))); + stub.context = { + model: seriesModel, + overallProgress: overallProgress // FIXME:TS never used, so comment it + // modifyOutputEnd: modifyOutputEnd + + }; + stub.agent = overallTask; + stub.__block = overallProgress; + + scheduler._pipe(seriesModel, stub); + } + + if (shouldOverallTaskDirty) { + overallTask.dirty(); + } + }; + + Scheduler.prototype._pipe = function (seriesModel, task) { + var pipelineId = seriesModel.uid; + + var pipeline = this._pipelineMap.get(pipelineId); + + !pipeline.head && (pipeline.head = task); + pipeline.tail && pipeline.tail.pipe(task); + pipeline.tail = task; + task.__idxInPipeline = pipeline.count++; + task.__pipeline = pipeline; + }; + + Scheduler.wrapStageHandler = function (stageHandler, visualType) { + if (isFunction(stageHandler)) { + stageHandler = { + overallReset: stageHandler, + seriesType: detectSeriseType(stageHandler) + }; + } + + stageHandler.uid = getUID('stageHandler'); + visualType && (stageHandler.visualType = visualType); + return stageHandler; + }; + + return Scheduler; + }(); + + function overallTaskReset(context) { + context.overallReset(context.ecModel, context.api, context.payload); + } + + function stubReset(context) { + return context.overallProgress && stubProgress; + } + + function stubProgress() { + this.agent.dirty(); + this.getDownstream().dirty(); + } + + function stubOnDirty() { + this.agent && this.agent.dirty(); + } + + function seriesTaskPlan(context) { + return context.plan ? context.plan(context.model, context.ecModel, context.api, context.payload) : null; + } + + function seriesTaskReset(context) { + if (context.useClearVisual) { + context.data.clearAllVisual(); + } + + var resetDefines = context.resetDefines = normalizeToArray(context.reset(context.model, context.ecModel, context.api, context.payload)); + return resetDefines.length > 1 ? map$1(resetDefines, function (v, idx) { + return makeSeriesTaskProgress(idx); + }) : singleSeriesTaskProgress; + } + + var singleSeriesTaskProgress = makeSeriesTaskProgress(0); + + function makeSeriesTaskProgress(resetDefineIdx) { + return function (params, context) { + var data = context.data; + var resetDefine = context.resetDefines[resetDefineIdx]; + + if (resetDefine && resetDefine.dataEach) { + for (var i = params.start; i < params.end; i++) { + resetDefine.dataEach(data, i); + } + } else if (resetDefine && resetDefine.progress) { + resetDefine.progress(params, data); + } + }; + } + + function seriesTaskCount(context) { + return context.data.count(); + } + /** + * Only some legacy stage handlers (usually in echarts extensions) are pure function. + * To ensure that they can work normally, they should work in block mode, that is, + * they should not be started util the previous tasks finished. So they cause the + * progressive rendering disabled. We try to detect the series type, to narrow down + * the block range to only the series type they concern, but not all series. + */ + + + function detectSeriseType(legacyFunc) { + seriesType = null; + + try { + // Assume there is no async when calling `eachSeriesByType`. + legacyFunc(ecModelMock, apiMock); + } catch (e) {} + + return seriesType; + } + + var ecModelMock = {}; + var apiMock = {}; + var seriesType; + mockMethods(ecModelMock, GlobalModel); + mockMethods(apiMock, ExtensionAPI); + + ecModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) { + seriesType = type; + }; + + ecModelMock.eachComponent = function (cond) { + if (cond.mainType === 'series' && cond.subType) { + seriesType = cond.subType; + } + }; + + function mockMethods(target, Clz) { + /* eslint-disable */ + for (var name_1 in Clz.prototype) { + // Do not use hasOwnProperty + target[name_1] = noop; + } + /* eslint-enable */ + + } + + var color = tokens.darkColor; + var backgroundColor = color.background; + + var axisCommon = function () { + return { + axisLine: { + lineStyle: { + color: color.axisLine + } + }, + splitLine: { + lineStyle: { + color: color.axisSplitLine + } + }, + splitArea: { + areaStyle: { + color: [color.backgroundTint, color.backgroundTransparent] + } + }, + minorSplitLine: { + lineStyle: { + color: color.axisMinorSplitLine + } + }, + axisLabel: { + color: color.axisLabel + }, + axisName: {} + }; + }; + + var matrixAxis = { + label: { + color: color.secondary + }, + itemStyle: { + borderColor: color.borderTint + }, + dividerLineStyle: { + color: color.border + } + }; + var theme = { + darkMode: true, + color: color.theme, + backgroundColor: backgroundColor, + axisPointer: { + lineStyle: { + color: color.border + }, + crossStyle: { + color: color.borderShade + }, + label: { + color: color.tertiary + } + }, + legend: { + textStyle: { + color: color.secondary + }, + pageTextStyle: { + color: color.tertiary + } + }, + textStyle: { + color: color.secondary + }, + title: { + textStyle: { + color: color.primary + }, + subtextStyle: { + color: color.quaternary + } + }, + toolbox: { + iconStyle: { + borderColor: color.accent50 + } + }, + tooltip: { + backgroundColor: color.neutral20, + defaultBorderColor: color.border, + textStyle: { + color: color.tertiary + } + }, + dataZoom: { + borderColor: color.accent10, + textStyle: { + color: color.tertiary + }, + brushStyle: { + color: color.backgroundTint + }, + handleStyle: { + color: color.neutral00, + borderColor: color.accent20 + }, + moveHandleStyle: { + color: color.accent40 + }, + emphasis: { + handleStyle: { + borderColor: color.accent50 + } + }, + dataBackground: { + lineStyle: { + color: color.accent30 + }, + areaStyle: { + color: color.accent20 + } + }, + selectedDataBackground: { + lineStyle: { + color: color.accent50 + }, + areaStyle: { + color: color.accent30 + } + } + }, + visualMap: { + textStyle: { + color: color.secondary + }, + handleStyle: { + borderColor: color.neutral30 + } + }, + timeline: { + lineStyle: { + color: color.accent10 + }, + label: { + color: color.tertiary + }, + controlStyle: { + color: color.accent30, + borderColor: color.accent30 + } + }, + calendar: { + itemStyle: { + color: color.neutral00, + borderColor: color.neutral20 + }, + dayLabel: { + color: color.tertiary + }, + monthLabel: { + color: color.secondary + }, + yearLabel: { + color: color.secondary + } + }, + matrix: { + x: matrixAxis, + y: matrixAxis, + backgroundColor: { + borderColor: color.axisLine + }, + body: { + itemStyle: { + borderColor: color.borderTint + } + } + }, + timeAxis: axisCommon(), + logAxis: axisCommon(), + valueAxis: axisCommon(), + categoryAxis: axisCommon(), + line: { + symbol: 'circle' + }, + graph: { + color: color.theme + }, + gauge: { + title: { + color: color.secondary + }, + axisLine: { + lineStyle: { + color: [[1, color.neutral05]] + } + }, + axisLabel: { + color: color.axisLabel + }, + detail: { + color: color.primary + } + }, + candlestick: { + itemStyle: { + color: '#f64e56', + color0: '#54ea92', + borderColor: '#f64e56', + borderColor0: '#54ea92' // borderColor: '#ca2824', + // borderColor0: '#09a443' + + } + }, + funnel: { + itemStyle: { + borderColor: color.background + } + }, + radar: function () { + var radar = axisCommon(); + radar.axisName = { + color: color.axisLabel + }; + radar.axisLine.lineStyle.color = color.neutral20; + return radar; + }(), + treemap: { + breadcrumb: { + itemStyle: { + color: color.neutral20, + textStyle: { + color: color.secondary + } + }, + emphasis: { + itemStyle: { + color: color.neutral30 + } + } + } + }, + sunburst: { + itemStyle: { + borderColor: color.background + } + }, + map: { + itemStyle: { + borderColor: color.border, + areaColor: color.neutral10 + }, + label: { + color: color.tertiary + }, + emphasis: { + label: { + color: color.primary + }, + itemStyle: { + areaColor: color.highlight + } + }, + select: { + label: { + color: color.primary + }, + itemStyle: { + areaColor: color.highlight + } + } + }, + geo: { + itemStyle: { + borderColor: color.border, + areaColor: color.neutral10 + }, + emphasis: { + label: { + color: color.primary + }, + itemStyle: { + areaColor: color.highlight + } + }, + select: { + label: { + color: color.primary + }, + itemStyle: { + color: color.highlight + } + } + } + }; + theme.categoryAxis.splitLine.show = false; + /** + * Usage of query: + * `chart.on('click', query, handler);` + * The `query` can be: + * + The component type query string, only `mainType` or `mainType.subType`, + * like: 'xAxis', 'series', 'xAxis.category' or 'series.line'. + * + The component query object, like: + * `{seriesIndex: 2}`, `{seriesName: 'xx'}`, `{seriesId: 'some'}`, + * `{xAxisIndex: 2}`, `{xAxisName: 'xx'}`, `{xAxisId: 'some'}`. + * + The data query object, like: + * `{dataIndex: 123}`, `{dataType: 'link'}`, `{name: 'some'}`. + * + The other query object (cmponent customized query), like: + * `{element: 'some'}` (only available in custom series). + * + * Caveat: If a prop in the `query` object is `null/undefined`, it is the + * same as there is no such prop in the `query` object. + */ + + var ECEventProcessor = + /** @class */ + function () { + function ECEventProcessor() {} + + ECEventProcessor.prototype.normalizeQuery = function (query) { + var cptQuery = {}; + var dataQuery = {}; + var otherQuery = {}; // `query` is `mainType` or `mainType.subType` of component. + + if (isString(query)) { + var condCptType = parseClassType(query); // `.main` and `.sub` may be ''. + + cptQuery.mainType = condCptType.main || null; + cptQuery.subType = condCptType.sub || null; + } // `query` is an object, convert to {mainType, index, name, id}. + else { + // `xxxIndex`, `xxxName`, `xxxId`, `name`, `dataIndex`, `dataType` is reserved, + // can not be used in `compomentModel.filterForExposedEvent`. + var suffixes_1 = ['Index', 'Name', 'Id']; + var dataKeys_1 = { + name: 1, + dataIndex: 1, + dataType: 1 + }; + each$4(query, function (val, key) { + var reserved = false; + + for (var i = 0; i < suffixes_1.length; i++) { + var propSuffix = suffixes_1[i]; + var suffixPos = key.lastIndexOf(propSuffix); + + if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) { + var mainType = key.slice(0, suffixPos); // Consider `dataIndex`. + + if (mainType !== 'data') { + cptQuery.mainType = mainType; + cptQuery[propSuffix.toLowerCase()] = val; + reserved = true; + } + } + } + + if (dataKeys_1.hasOwnProperty(key)) { + dataQuery[key] = val; + reserved = true; + } + + if (!reserved) { + otherQuery[key] = val; + } + }); + } + + return { + cptQuery: cptQuery, + dataQuery: dataQuery, + otherQuery: otherQuery + }; + }; + + ECEventProcessor.prototype.filter = function (eventType, query) { + // They should be assigned before each trigger call. + var eventInfo = this.eventInfo; + + if (!eventInfo) { + return true; + } + + var targetEl = eventInfo.targetEl; + var packedEvent = eventInfo.packedEvent; + var model = eventInfo.model; + var view = eventInfo.view; // For event like 'globalout'. + + if (!model || !view) { + return true; + } + + var cptQuery = query.cptQuery; + var dataQuery = query.dataQuery; + return check(cptQuery, model, 'mainType') && check(cptQuery, model, 'subType') && check(cptQuery, model, 'index', 'componentIndex') && check(cptQuery, model, 'name') && check(cptQuery, model, 'id') && check(dataQuery, packedEvent, 'name') && check(dataQuery, packedEvent, 'dataIndex') && check(dataQuery, packedEvent, 'dataType') && (!view.filterForExposedEvent || view.filterForExposedEvent(eventType, query.otherQuery, targetEl, packedEvent)); + + function check(query, host, prop, propOnHost) { + return query[prop] == null || host[propOnHost || prop] === query[prop]; + } + }; + + ECEventProcessor.prototype.afterTrigger = function () { + // Make sure the eventInfo won't be used in next trigger. + this.eventInfo = null; + }; + + return ECEventProcessor; + }(); + + var SYMBOL_PROPS_WITH_CB = ['symbol', 'symbolSize', 'symbolRotate', 'symbolOffset']; + var SYMBOL_PROPS = SYMBOL_PROPS_WITH_CB.concat(['symbolKeepAspect']); // Encoding visual for all series include which is filtered for legend drawing + + var seriesSymbolTask = { + createOnAllSeries: true, + // For legend. + performRawSeries: true, + reset: function (seriesModel, ecModel) { + var data = seriesModel.getData(); + + if (seriesModel.legendIcon) { + data.setVisual('legendIcon', seriesModel.legendIcon); + } + + if (!seriesModel.hasSymbolVisual) { + return; + } + + var symbolOptions = {}; + var symbolOptionsCb = {}; + var hasCallback = false; + + for (var i = 0; i < SYMBOL_PROPS_WITH_CB.length; i++) { + var symbolPropName = SYMBOL_PROPS_WITH_CB[i]; + var val = seriesModel.get(symbolPropName); + + if (isFunction(val)) { + hasCallback = true; + symbolOptionsCb[symbolPropName] = val; + } else { + symbolOptions[symbolPropName] = val; + } + } + + symbolOptions.symbol = symbolOptions.symbol || seriesModel.defaultSymbol; + data.setVisual(extend({ + legendIcon: seriesModel.legendIcon || symbolOptions.symbol, + symbolKeepAspect: seriesModel.get('symbolKeepAspect') + }, symbolOptions)); // Only visible series has each data be visual encoded + + if (ecModel.isSeriesFiltered(seriesModel)) { + return; + } + + var symbolPropsCb = keys(symbolOptionsCb); + + function dataEach(data, idx) { + var rawValue = seriesModel.getRawValue(idx); + var params = seriesModel.getDataParams(idx); + + for (var i = 0; i < symbolPropsCb.length; i++) { + var symbolPropName = symbolPropsCb[i]; + data.setItemVisual(idx, symbolPropName, symbolOptionsCb[symbolPropName](rawValue, params)); + } + } + + return { + dataEach: hasCallback ? dataEach : null + }; + } + }; + var dataSymbolTask = { + createOnAllSeries: true, + // For legend. + performRawSeries: true, + reset: function (seriesModel, ecModel) { + if (!seriesModel.hasSymbolVisual) { + return; + } // Only visible series has each data be visual encoded + + + if (ecModel.isSeriesFiltered(seriesModel)) { + return; + } + + var data = seriesModel.getData(); + + function dataEach(data, idx) { + var itemModel = data.getItemModel(idx); + + for (var i = 0; i < SYMBOL_PROPS.length; i++) { + var symbolPropName = SYMBOL_PROPS[i]; + var val = itemModel.getShallow(symbolPropName, true); + + if (val != null) { + data.setItemVisual(idx, symbolPropName, val); + } + } + } + + return { + dataEach: data.hasItemOption ? dataEach : null + }; + } + }; + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + function getItemVisualFromData(data, dataIndex, key) { + switch (key) { + case 'color': + var style = data.getItemVisual(dataIndex, 'style'); + return style[data.getVisual('drawType')]; + + case 'opacity': + return data.getItemVisual(dataIndex, 'style').opacity; + + case 'symbol': + case 'symbolSize': + case 'liftZ': + return data.getItemVisual(dataIndex, key); + + default: + { + console.warn("Unknown visual type " + key); + } + } + } + + function getVisualFromData(data, key) { + switch (key) { + case 'color': + var style = data.getVisual('style'); + return style[data.getVisual('drawType')]; + + case 'opacity': + return data.getVisual('style').opacity; + + case 'symbol': + case 'symbolSize': + case 'liftZ': + return data.getVisual(key); + + default: + { + console.warn("Unknown visual type " + key); + } + } + } + + function handleSeriesLegacySelectEvents(type, eventPostfix, ecIns, ecModel, payload) { + var legacyEventName = type + eventPostfix; + + if (!ecIns.isSilent(legacyEventName)) { + { + deprecateLog("event " + legacyEventName + " is deprecated."); + } + ecModel.eachComponent({ + mainType: 'series', + subType: 'pie' + }, function (seriesModel) { + var seriesIndex = seriesModel.seriesIndex; + var selectedMap = seriesModel.option.selectedMap; + var selected = payload.selected; + + for (var i = 0; i < selected.length; i++) { + if (selected[i].seriesIndex === seriesIndex) { + var data = seriesModel.getData(); + var dataIndex = queryDataIndex(data, payload.fromActionPayload); + ecIns.trigger(legacyEventName, { + type: legacyEventName, + seriesId: seriesModel.id, + name: isArray(dataIndex) ? data.getName(dataIndex[0]) : data.getName(dataIndex), + selected: isString(selectedMap) ? selectedMap : extend({}, selectedMap) + }); + } + } + }); + } + } + + function handleLegacySelectEvents(messageCenter, ecIns, api) { + messageCenter.on('selectchanged', function (params) { + var ecModel = api.getModel(); + + if (params.isFromClick) { + handleSeriesLegacySelectEvents('map', 'selectchanged', ecIns, ecModel, params); + handleSeriesLegacySelectEvents('pie', 'selectchanged', ecIns, ecModel, params); + } else if (params.fromAction === 'select') { + handleSeriesLegacySelectEvents('map', 'selected', ecIns, ecModel, params); + handleSeriesLegacySelectEvents('pie', 'selected', ecIns, ecModel, params); + } else if (params.fromAction === 'unselect') { + handleSeriesLegacySelectEvents('map', 'unselected', ecIns, ecModel, params); + handleSeriesLegacySelectEvents('pie', 'unselected', ecIns, ecModel, params); + } + }); + } + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + function findEventDispatcher(target, det, returnFirstMatch) { + var found; + + while (target) { + if (det(target)) { + found = target; + + if (returnFirstMatch) { + break; + } + } + + target = target.__hostTarget || target.parent; + } + + return found; + } + + var wmUniqueIndex = Math.round(Math.random() * 9); + var supportDefineProperty = typeof Object.defineProperty === 'function'; + + var WeakMap = function () { + function WeakMap() { + this._id = '__ec_inner_' + wmUniqueIndex++; + } + + WeakMap.prototype.get = function (key) { + return this._guard(key)[this._id]; + }; + + WeakMap.prototype.set = function (key, value) { + var target = this._guard(key); + + if (supportDefineProperty) { + Object.defineProperty(target, this._id, { + value: value, + enumerable: false, + configurable: true + }); + } else { + target[this._id] = value; + } + + return this; + }; + + WeakMap.prototype["delete"] = function (key) { + if (this.has(key)) { + delete this._guard(key)[this._id]; + return true; + } + + return false; + }; + + WeakMap.prototype.has = function (key) { + return !!this._guard(key)[this._id]; + }; + + WeakMap.prototype._guard = function (key) { + if (key !== Object(key)) { + throw TypeError('Value of WeakMap is not a non-null object.'); + } + + return key; + }; + + return WeakMap; + }(); + /** + * Triangle shape + * @inner + */ + + + var Triangle = Path.extend({ + type: 'triangle', + shape: { + cx: 0, + cy: 0, + width: 0, + height: 0 + }, + buildPath: function (path, shape) { + var cx = shape.cx; + var cy = shape.cy; + var width = shape.width / 2; + var height = shape.height / 2; + path.moveTo(cx, cy - height); + path.lineTo(cx + width, cy + height); + path.lineTo(cx - width, cy + height); + path.closePath(); + } + }); + /** + * Diamond shape + * @inner + */ + + var Diamond = Path.extend({ + type: 'diamond', + shape: { + cx: 0, + cy: 0, + width: 0, + height: 0 + }, + buildPath: function (path, shape) { + var cx = shape.cx; + var cy = shape.cy; + var width = shape.width / 2; + var height = shape.height / 2; + path.moveTo(cx, cy - height); + path.lineTo(cx + width, cy); + path.lineTo(cx, cy + height); + path.lineTo(cx - width, cy); + path.closePath(); + } + }); + /** + * Pin shape + * @inner + */ + + var Pin = Path.extend({ + type: 'pin', + shape: { + // x, y on the cusp + x: 0, + y: 0, + width: 0, + height: 0 + }, + buildPath: function (path, shape) { + var x = shape.x; + var y = shape.y; + var w = shape.width / 5 * 3; // Height must be larger than width + + var h = Math.max(w, shape.height); + var r = w / 2; // Dist on y with tangent point and circle center + + var dy = r * r / (h - r); + var cy = y - h + r + dy; + var angle = Math.asin(dy / r); // Dist on x with tangent point and circle center + + var dx = Math.cos(angle) * r; + var tanX = Math.sin(angle); + var tanY = Math.cos(angle); + var cpLen = r * 0.6; + var cpLen2 = r * 0.7; + path.moveTo(x - dx, cy + dy); + path.arc(x, cy, r, Math.PI - angle, Math.PI * 2 + angle); + path.bezierCurveTo(x + dx - tanX * cpLen, cy + dy + tanY * cpLen, x, y - cpLen2, x, y); + path.bezierCurveTo(x, y - cpLen2, x - dx + tanX * cpLen, cy + dy + tanY * cpLen, x - dx, cy + dy); + path.closePath(); + } + }); + /** + * Arrow shape + * @inner + */ + + var Arrow = Path.extend({ + type: 'arrow', + shape: { + x: 0, + y: 0, + width: 0, + height: 0 + }, + buildPath: function (ctx, shape) { + var height = shape.height; + var width = shape.width; + var x = shape.x; + var y = shape.y; + var dx = width / 3 * 2; + ctx.moveTo(x, y); + ctx.lineTo(x + dx, y + height); + ctx.lineTo(x, y + height / 4 * 3); + ctx.lineTo(x - dx, y + height); + ctx.lineTo(x, y); + ctx.closePath(); + } + }); + /** + * Map of path constructors + */ + // TODO Use function to build symbol path. + + var symbolCtors = { + line: Line, + rect: Rect, + roundRect: Rect, + square: Rect, + circle: Circle, + diamond: Diamond, + pin: Pin, + arrow: Arrow, + triangle: Triangle + }; + var symbolShapeMakers = { + line: function (x, y, w, h, shape) { + shape.x1 = x; + shape.y1 = y + h / 2; + shape.x2 = x + w; + shape.y2 = y + h / 2; + }, + rect: function (x, y, w, h, shape) { + shape.x = x; + shape.y = y; + shape.width = w; + shape.height = h; + }, + roundRect: function (x, y, w, h, shape) { + shape.x = x; + shape.y = y; + shape.width = w; + shape.height = h; + shape.r = Math.min(w, h) / 4; + }, + square: function (x, y, w, h, shape) { + var size = Math.min(w, h); + shape.x = x; + shape.y = y; + shape.width = size; + shape.height = size; + }, + circle: function (x, y, w, h, shape) { + // Put circle in the center of square + shape.cx = x + w / 2; + shape.cy = y + h / 2; + shape.r = Math.min(w, h) / 2; + }, + diamond: function (x, y, w, h, shape) { + shape.cx = x + w / 2; + shape.cy = y + h / 2; + shape.width = w; + shape.height = h; + }, + pin: function (x, y, w, h, shape) { + shape.x = x + w / 2; + shape.y = y + h / 2; + shape.width = w; + shape.height = h; + }, + arrow: function (x, y, w, h, shape) { + shape.x = x + w / 2; + shape.y = y + h / 2; + shape.width = w; + shape.height = h; + }, + triangle: function (x, y, w, h, shape) { + shape.cx = x + w / 2; + shape.cy = y + h / 2; + shape.width = w; + shape.height = h; + } + }; + var symbolBuildProxies = {}; + each$4(symbolCtors, function (Ctor, name) { + symbolBuildProxies[name] = new Ctor(); + }); + var SymbolClz = Path.extend({ + type: 'symbol', + shape: { + symbolType: '', + x: 0, + y: 0, + width: 0, + height: 0 + }, + calculateTextPosition: function (out, config, rect) { + var res = calculateTextPosition(out, config, rect); + var shape = this.shape; + + if (shape && shape.symbolType === 'pin' && config.position === 'inside') { + res.y = rect.y + rect.height * 0.4; + } + + return res; + }, + buildPath: function (ctx, shape, inBundle) { + var symbolType = shape.symbolType; + + if (symbolType !== 'none') { + var proxySymbol = symbolBuildProxies[symbolType]; + + if (!proxySymbol) { + // Default rect + symbolType = 'rect'; + proxySymbol = symbolBuildProxies[symbolType]; + } + + symbolShapeMakers[symbolType](shape.x, shape.y, shape.width, shape.height, proxySymbol.shape); + proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle); + } + } + }); // Provide setColor helper method to avoid determine if set the fill or stroke outside + + function symbolPathSetColor(color, innerColor) { + if (this.type !== 'image') { + var symbolStyle = this.style; + + if (this.__isEmptyBrush) { + symbolStyle.stroke = color; + symbolStyle.fill = innerColor || tokens.color.neutral00; // TODO Same width with lineStyle in LineView + + symbolStyle.lineWidth = 2; + } else if (this.shape.symbolType === 'line') { + symbolStyle.stroke = color; + } else { + symbolStyle.fill = color; + } + + this.markRedraw(); + } + } + /** + * Create a symbol element with given symbol configuration: shape, x, y, width, height, color + */ + + + function createSymbol(symbolType, x, y, w, h, color, // whether to keep the ratio of w/h, + keepAspect) { + // TODO Support image object, DynamicImage. + var isEmpty = symbolType.indexOf('empty') === 0; + + if (isEmpty) { + symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6); + } + + var symbolPath; + + if (symbolType.indexOf('image://') === 0) { + symbolPath = makeImage(symbolType.slice(8), new BoundingRect(x, y, w, h), keepAspect ? 'center' : 'cover'); + } else if (symbolType.indexOf('path://') === 0) { + symbolPath = makePath(symbolType.slice(7), {}, new BoundingRect(x, y, w, h), keepAspect ? 'center' : 'cover'); + } else { + symbolPath = new SymbolClz({ + shape: { + symbolType: symbolType, + x: x, + y: y, + width: w, + height: h + } + }); + } + + symbolPath.__isEmptyBrush = isEmpty; // TODO Should deprecate setColor + + symbolPath.setColor = symbolPathSetColor; + + if (color) { + symbolPath.setColor(color); + } + + return symbolPath; + } + + function normalizeSymbolSize(symbolSize) { + if (!isArray(symbolSize)) { + symbolSize = [+symbolSize, +symbolSize]; + } + + return [symbolSize[0] || 0, symbolSize[1] || 0]; + } + + function normalizeSymbolOffset(symbolOffset, symbolSize) { + if (symbolOffset == null) { + return; + } + + if (!isArray(symbolOffset)) { + symbolOffset = [symbolOffset, symbolOffset]; + } + + return [parsePercent(symbolOffset[0], symbolSize[0]) || 0, parsePercent(retrieve2(symbolOffset[1], symbolOffset[0]), symbolSize[1]) || 0]; + } + + function isSafeNum(num) { + return isFinite(num); + } + + function createLinearGradient(ctx, obj, rect) { + var x = obj.x == null ? 0 : obj.x; + var x2 = obj.x2 == null ? 1 : obj.x2; + var y = obj.y == null ? 0 : obj.y; + var y2 = obj.y2 == null ? 0 : obj.y2; + + if (!obj.global) { + x = x * rect.width + rect.x; + x2 = x2 * rect.width + rect.x; + y = y * rect.height + rect.y; + y2 = y2 * rect.height + rect.y; + } + + x = isSafeNum(x) ? x : 0; + x2 = isSafeNum(x2) ? x2 : 1; + y = isSafeNum(y) ? y : 0; + y2 = isSafeNum(y2) ? y2 : 0; + var canvasGradient = ctx.createLinearGradient(x, y, x2, y2); + return canvasGradient; + } + + function createRadialGradient(ctx, obj, rect) { + var width = rect.width; + var height = rect.height; + var min = Math.min(width, height); + var x = obj.x == null ? 0.5 : obj.x; + var y = obj.y == null ? 0.5 : obj.y; + var r = obj.r == null ? 0.5 : obj.r; + + if (!obj.global) { + x = x * width + rect.x; + y = y * height + rect.y; + r = r * min; + } + + x = isSafeNum(x) ? x : 0.5; + y = isSafeNum(y) ? y : 0.5; + r = r >= 0 && isSafeNum(r) ? r : 0.5; + var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r); + return canvasGradient; + } + + function getCanvasGradient(ctx, obj, rect) { + var canvasGradient = obj.type === 'radial' ? createRadialGradient(ctx, obj, rect) : createLinearGradient(ctx, obj, rect); + var colorStops = obj.colorStops; + + for (var i = 0; i < colorStops.length; i++) { + canvasGradient.addColorStop(colorStops[i].offset, colorStops[i].color); + } + + return canvasGradient; + } + + function isClipPathChanged(clipPaths, prevClipPaths) { + if (clipPaths === prevClipPaths || !clipPaths && !prevClipPaths) { + return false; + } + + if (!clipPaths || !prevClipPaths || clipPaths.length !== prevClipPaths.length) { + return true; + } + + for (var i = 0; i < clipPaths.length; i++) { + if (clipPaths[i] !== prevClipPaths[i]) { + return true; + } + } + + return false; + } + + function parseInt10(val) { + return parseInt(val, 10); + } + + function getSize(root, whIdx, opts) { + var wh = ['width', 'height'][whIdx]; + var cwh = ['clientWidth', 'clientHeight'][whIdx]; + var plt = ['paddingLeft', 'paddingTop'][whIdx]; + var prb = ['paddingRight', 'paddingBottom'][whIdx]; + + if (opts[wh] != null && opts[wh] !== 'auto') { + return parseFloat(opts[wh]); + } + + var stl = document.defaultView.getComputedStyle(root); + return (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh])) - (parseInt10(stl[plt]) || 0) - (parseInt10(stl[prb]) || 0) | 0; + } + + function normalizeLineDash(lineType, lineWidth) { + if (!lineType || lineType === 'solid' || !(lineWidth > 0)) { + return null; + } + + return lineType === 'dashed' ? [4 * lineWidth, 2 * lineWidth] : lineType === 'dotted' ? [lineWidth] : isNumber(lineType) ? [lineType] : isArray(lineType) ? lineType : null; + } + + function getLineDash(el) { + var style = el.style; + var lineDash = style.lineDash && style.lineWidth > 0 && normalizeLineDash(style.lineDash, style.lineWidth); + var lineDashOffset = style.lineDashOffset; + + if (lineDash) { + var lineScale_1 = style.strokeNoScale && el.getLineScale ? el.getLineScale() : 1; + + if (lineScale_1 && lineScale_1 !== 1) { + lineDash = map$1(lineDash, function (rawVal) { + return rawVal / lineScale_1; + }); + lineDashOffset /= lineScale_1; + } + } + + return [lineDash, lineDashOffset]; + } + + var pathProxyForDraw = new PathProxy(true); + + function styleHasStroke(style) { + var stroke = style.stroke; + return !(stroke == null || stroke === 'none' || !(style.lineWidth > 0)); + } + + function isValidStrokeFillStyle(strokeOrFill) { + return typeof strokeOrFill === 'string' && strokeOrFill !== 'none'; + } + + function styleHasFill(style) { + var fill = style.fill; + return fill != null && fill !== 'none'; + } + + function doFillPath(ctx, style) { + if (style.fillOpacity != null && style.fillOpacity !== 1) { + var originalGlobalAlpha = ctx.globalAlpha; + ctx.globalAlpha = style.fillOpacity * style.opacity; + ctx.fill(); + ctx.globalAlpha = originalGlobalAlpha; + } else { + ctx.fill(); + } + } + + function doStrokePath(ctx, style) { + if (style.strokeOpacity != null && style.strokeOpacity !== 1) { + var originalGlobalAlpha = ctx.globalAlpha; + ctx.globalAlpha = style.strokeOpacity * style.opacity; + ctx.stroke(); + ctx.globalAlpha = originalGlobalAlpha; + } else { + ctx.stroke(); + } + } + + function createCanvasPattern(ctx, pattern, el) { + var image = createOrUpdateImage(pattern.image, pattern.__image, el); + + if (isImageReady(image)) { + var canvasPattern = ctx.createPattern(image, pattern.repeat || 'repeat'); + + if (typeof DOMMatrix === 'function' && canvasPattern && canvasPattern.setTransform) { + var matrix = new DOMMatrix(); + matrix.translateSelf(pattern.x || 0, pattern.y || 0); + matrix.rotateSelf(0, 0, (pattern.rotation || 0) * RADIAN_TO_DEGREE); + matrix.scaleSelf(pattern.scaleX || 1, pattern.scaleY || 1); + canvasPattern.setTransform(matrix); + } + + return canvasPattern; + } + } + + function brushPath(ctx, el, style, inBatch) { + var _a; + + var hasStroke = styleHasStroke(style); + var hasFill = styleHasFill(style); + var strokePercent = style.strokePercent; + var strokePart = strokePercent < 1; + var firstDraw = !el.path; + + if ((!el.silent || strokePart) && firstDraw) { + el.createPathProxy(); + } + + var path = el.path || pathProxyForDraw; + var dirtyFlag = el.__dirty; + + if (!inBatch) { + var fill = style.fill; + var stroke = style.stroke; + var hasFillGradient = hasFill && !!fill.colorStops; + var hasStrokeGradient = hasStroke && !!stroke.colorStops; + var hasFillPattern = hasFill && !!fill.image; + var hasStrokePattern = hasStroke && !!stroke.image; + var fillGradient = void 0; + var strokeGradient = void 0; + var fillPattern = void 0; + var strokePattern = void 0; + var rect = void 0; + + if (hasFillGradient || hasStrokeGradient) { + rect = el.getBoundingRect(); + } + + if (hasFillGradient) { + fillGradient = dirtyFlag ? getCanvasGradient(ctx, fill, rect) : el.__canvasFillGradient; + el.__canvasFillGradient = fillGradient; + } + + if (hasStrokeGradient) { + strokeGradient = dirtyFlag ? getCanvasGradient(ctx, stroke, rect) : el.__canvasStrokeGradient; + el.__canvasStrokeGradient = strokeGradient; + } + + if (hasFillPattern) { + fillPattern = dirtyFlag || !el.__canvasFillPattern ? createCanvasPattern(ctx, fill, el) : el.__canvasFillPattern; + el.__canvasFillPattern = fillPattern; + } + + if (hasStrokePattern) { + strokePattern = dirtyFlag || !el.__canvasStrokePattern ? createCanvasPattern(ctx, stroke, el) : el.__canvasStrokePattern; + el.__canvasStrokePattern = strokePattern; + } + + if (hasFillGradient) { + ctx.fillStyle = fillGradient; + } else if (hasFillPattern) { + if (fillPattern) { + ctx.fillStyle = fillPattern; + } else { + hasFill = false; + } + } + + if (hasStrokeGradient) { + ctx.strokeStyle = strokeGradient; + } else if (hasStrokePattern) { + if (strokePattern) { + ctx.strokeStyle = strokePattern; + } else { + hasStroke = false; + } + } + } + + var scale = el.getGlobalScale(); + path.setScale(scale[0], scale[1], el.segmentIgnoreThreshold); + var lineDash; + var lineDashOffset; + + if (ctx.setLineDash && style.lineDash) { + _a = getLineDash(el), lineDash = _a[0], lineDashOffset = _a[1]; + } + + var needsRebuild = true; + + if (firstDraw || dirtyFlag & SHAPE_CHANGED_BIT) { + path.setDPR(ctx.dpr); + + if (strokePart) { + path.setContext(null); + } else { + path.setContext(ctx); + needsRebuild = false; + } + + path.reset(); + el.buildPath(path, el.shape, inBatch); + path.toStatic(); + el.pathUpdated(); + } + + if (needsRebuild) { + path.rebuildPath(ctx, strokePart ? strokePercent : 1); + } + + if (lineDash) { + ctx.setLineDash(lineDash); + ctx.lineDashOffset = lineDashOffset; + } + + if (!inBatch) { + if (style.strokeFirst) { + if (hasStroke) { + doStrokePath(ctx, style); + } + + if (hasFill) { + doFillPath(ctx, style); + } + } else { + if (hasFill) { + doFillPath(ctx, style); + } + + if (hasStroke) { + doStrokePath(ctx, style); + } + } + } + + if (lineDash) { + ctx.setLineDash([]); + } + } + + function brushImage(ctx, el, style) { + var image = el.__image = createOrUpdateImage(style.image, el.__image, el, el.onload); + + if (!image || !isImageReady(image)) { + return; + } + + var x = style.x || 0; + var y = style.y || 0; + var width = el.getWidth(); + var height = el.getHeight(); + var aspect = image.width / image.height; + + if (width == null && height != null) { + width = height * aspect; + } else if (height == null && width != null) { + height = width / aspect; + } else if (width == null && height == null) { + width = image.width; + height = image.height; + } + + if (style.sWidth && style.sHeight) { + var sx = style.sx || 0; + var sy = style.sy || 0; + ctx.drawImage(image, sx, sy, style.sWidth, style.sHeight, x, y, width, height); + } else if (style.sx && style.sy) { + var sx = style.sx; + var sy = style.sy; + var sWidth = width - sx; + var sHeight = height - sy; + ctx.drawImage(image, sx, sy, sWidth, sHeight, x, y, width, height); + } else { + ctx.drawImage(image, x, y, width, height); + } + } + + function brushText(ctx, el, style) { + var _a; + + var text = style.text; + text != null && (text += ''); + + if (text) { + ctx.font = style.font || DEFAULT_FONT; + ctx.textAlign = style.textAlign; + ctx.textBaseline = style.textBaseline; + var lineDash = void 0; + var lineDashOffset = void 0; + + if (ctx.setLineDash && style.lineDash) { + _a = getLineDash(el), lineDash = _a[0], lineDashOffset = _a[1]; + } + + if (lineDash) { + ctx.setLineDash(lineDash); + ctx.lineDashOffset = lineDashOffset; + } + + if (style.strokeFirst) { + if (styleHasStroke(style)) { + ctx.strokeText(text, style.x, style.y); + } + + if (styleHasFill(style)) { + ctx.fillText(text, style.x, style.y); + } + } else { + if (styleHasFill(style)) { + ctx.fillText(text, style.x, style.y); + } + + if (styleHasStroke(style)) { + ctx.strokeText(text, style.x, style.y); + } + } + + if (lineDash) { + ctx.setLineDash([]); + } + } + } + + var SHADOW_NUMBER_PROPS = ['shadowBlur', 'shadowOffsetX', 'shadowOffsetY']; + var STROKE_PROPS = [['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]]; + + function bindCommonProps(ctx, style, prevStyle, forceSetAll, scope) { + var styleChanged = false; + + if (!forceSetAll) { + prevStyle = prevStyle || {}; + + if (style === prevStyle) { + return false; + } + } + + if (forceSetAll || style.opacity !== prevStyle.opacity) { + flushPathDrawn(ctx, scope); + styleChanged = true; + var opacity = Math.max(Math.min(style.opacity, 1), 0); + ctx.globalAlpha = isNaN(opacity) ? DEFAULT_COMMON_STYLE.opacity : opacity; + } + + if (forceSetAll || style.blend !== prevStyle.blend) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + + ctx.globalCompositeOperation = style.blend || DEFAULT_COMMON_STYLE.blend; + } + + for (var i = 0; i < SHADOW_NUMBER_PROPS.length; i++) { + var propName = SHADOW_NUMBER_PROPS[i]; + + if (forceSetAll || style[propName] !== prevStyle[propName]) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + + ctx[propName] = ctx.dpr * (style[propName] || 0); + } + } + + if (forceSetAll || style.shadowColor !== prevStyle.shadowColor) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + + ctx.shadowColor = style.shadowColor || DEFAULT_COMMON_STYLE.shadowColor; + } + + return styleChanged; + } + + function bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetAll, scope) { + var style = getStyle(el, scope.inHover); + var prevStyle = forceSetAll ? null : prevEl && getStyle(prevEl, scope.inHover) || {}; + + if (style === prevStyle) { + return false; + } + + var styleChanged = bindCommonProps(ctx, style, prevStyle, forceSetAll, scope); + + if (forceSetAll || style.fill !== prevStyle.fill) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + + isValidStrokeFillStyle(style.fill) && (ctx.fillStyle = style.fill); + } + + if (forceSetAll || style.stroke !== prevStyle.stroke) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + + isValidStrokeFillStyle(style.stroke) && (ctx.strokeStyle = style.stroke); + } + + if (forceSetAll || style.opacity !== prevStyle.opacity) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + + ctx.globalAlpha = style.opacity == null ? 1 : style.opacity; + } + + if (el.hasStroke()) { + var lineWidth = style.lineWidth; + var newLineWidth = lineWidth / (style.strokeNoScale && el.getLineScale ? el.getLineScale() : 1); + + if (ctx.lineWidth !== newLineWidth) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + + ctx.lineWidth = newLineWidth; + } + } + + for (var i = 0; i < STROKE_PROPS.length; i++) { + var prop = STROKE_PROPS[i]; + var propName = prop[0]; + + if (forceSetAll || style[propName] !== prevStyle[propName]) { + if (!styleChanged) { + flushPathDrawn(ctx, scope); + styleChanged = true; + } + + ctx[propName] = style[propName] || prop[1]; + } + } + + return styleChanged; + } + + function bindImageStyle(ctx, el, prevEl, forceSetAll, scope) { + return bindCommonProps(ctx, getStyle(el, scope.inHover), prevEl && getStyle(prevEl, scope.inHover), forceSetAll, scope); + } + + function setContextTransform(ctx, el) { + var m = el.transform; + var dpr = ctx.dpr || 1; + + if (m) { + ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]); + } else { + ctx.setTransform(dpr, 0, 0, dpr, 0, 0); + } + } + + function updateClipStatus(clipPaths, ctx, scope) { + var allClipped = false; + + for (var i = 0; i < clipPaths.length; i++) { + var clipPath = clipPaths[i]; + allClipped = allClipped || clipPath.isZeroArea(); + setContextTransform(ctx, clipPath); + ctx.beginPath(); + clipPath.buildPath(ctx, clipPath.shape); + ctx.clip(); + } + + scope.allClipped = allClipped; + } + + function isTransformChanged(m0, m1) { + if (m0 && m1) { + return m0[0] !== m1[0] || m0[1] !== m1[1] || m0[2] !== m1[2] || m0[3] !== m1[3] || m0[4] !== m1[4] || m0[5] !== m1[5]; + } else if (!m0 && !m1) { + return false; + } + + return true; + } + + var DRAW_TYPE_PATH = 1; + var DRAW_TYPE_IMAGE = 2; + var DRAW_TYPE_TEXT = 3; + var DRAW_TYPE_INCREMENTAL = 4; + + function canPathBatch(style) { + var hasFill = styleHasFill(style); + var hasStroke = styleHasStroke(style); + return !(style.lineDash || !(+hasFill ^ +hasStroke) || hasFill && typeof style.fill !== 'string' || hasStroke && typeof style.stroke !== 'string' || style.strokePercent < 1 || style.strokeOpacity < 1 || style.fillOpacity < 1); + } + + function flushPathDrawn(ctx, scope) { + scope.batchFill && ctx.fill(); + scope.batchStroke && ctx.stroke(); + scope.batchFill = ''; + scope.batchStroke = ''; + } + + function getStyle(el, inHover) { + return inHover ? el.__hoverStyle || el.style : el.style; + } + + function brushSingle(ctx, el) { + brush(ctx, el, { + inHover: false, + viewWidth: 0, + viewHeight: 0 + }, true); + } + + function brush(ctx, el, scope, isLast) { + var m = el.transform; + + if (!el.shouldBePainted(scope.viewWidth, scope.viewHeight, false, false)) { + el.__dirty &= ~REDRAW_BIT; + el.__isRendered = false; + return; + } + + var clipPaths = el.__clipPaths; + var prevElClipPaths = scope.prevElClipPaths; + var forceSetTransform = false; + var forceSetStyle = false; + + if (!prevElClipPaths || isClipPathChanged(clipPaths, prevElClipPaths)) { + if (prevElClipPaths && prevElClipPaths.length) { + flushPathDrawn(ctx, scope); + ctx.restore(); + forceSetStyle = forceSetTransform = true; + scope.prevElClipPaths = null; + scope.allClipped = false; + scope.prevEl = null; + } + + if (clipPaths && clipPaths.length) { + flushPathDrawn(ctx, scope); + ctx.save(); + updateClipStatus(clipPaths, ctx, scope); + forceSetTransform = true; + } + + scope.prevElClipPaths = clipPaths; + } + + if (scope.allClipped) { + el.__isRendered = false; + return; + } + + el.beforeBrush && el.beforeBrush(); + el.innerBeforeBrush(); + var prevEl = scope.prevEl; + + if (!prevEl) { + forceSetStyle = forceSetTransform = true; + } + + var canBatchPath = el instanceof Path && el.autoBatch && canPathBatch(el.style); + + if (forceSetTransform || isTransformChanged(m, prevEl.transform)) { + flushPathDrawn(ctx, scope); + setContextTransform(ctx, el); + } else if (!canBatchPath) { + flushPathDrawn(ctx, scope); + } + + var style = getStyle(el, scope.inHover); + + if (el instanceof Path) { + if (scope.lastDrawType !== DRAW_TYPE_PATH) { + forceSetStyle = true; + scope.lastDrawType = DRAW_TYPE_PATH; + } + + bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetStyle, scope); + + if (!canBatchPath || !scope.batchFill && !scope.batchStroke) { + ctx.beginPath(); + } + + brushPath(ctx, el, style, canBatchPath); + + if (canBatchPath) { + scope.batchFill = style.fill || ''; + scope.batchStroke = style.stroke || ''; + } + } else { + if (el instanceof TSpan) { + if (scope.lastDrawType !== DRAW_TYPE_TEXT) { + forceSetStyle = true; + scope.lastDrawType = DRAW_TYPE_TEXT; + } + + bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetStyle, scope); + brushText(ctx, el, style); + } else if (el instanceof ZRImage) { + if (scope.lastDrawType !== DRAW_TYPE_IMAGE) { + forceSetStyle = true; + scope.lastDrawType = DRAW_TYPE_IMAGE; + } + + bindImageStyle(ctx, el, prevEl, forceSetStyle, scope); + brushImage(ctx, el, style); + } else if (el.getTemporalDisplayables) { + if (scope.lastDrawType !== DRAW_TYPE_INCREMENTAL) { + forceSetStyle = true; + scope.lastDrawType = DRAW_TYPE_INCREMENTAL; + } + + brushIncremental(ctx, el, scope); + } + } + + if (canBatchPath && isLast) { + flushPathDrawn(ctx, scope); + } + + el.innerAfterBrush(); + el.afterBrush && el.afterBrush(); + scope.prevEl = el; + el.__dirty = 0; + el.__isRendered = true; + } + + function brushIncremental(ctx, el, scope) { + var displayables = el.getDisplayables(); + var temporalDisplayables = el.getTemporalDisplayables(); + ctx.save(); + var innerScope = { + prevElClipPaths: null, + prevEl: null, + allClipped: false, + viewWidth: scope.viewWidth, + viewHeight: scope.viewHeight, + inHover: scope.inHover + }; + var i; + var len; + + for (i = el.getCursor(), len = displayables.length; i < len; i++) { + var displayable = displayables[i]; + displayable.beforeBrush && displayable.beforeBrush(); + displayable.innerBeforeBrush(); + brush(ctx, displayable, innerScope, i === len - 1); + displayable.innerAfterBrush(); + displayable.afterBrush && displayable.afterBrush(); + innerScope.prevEl = displayable; + } + + for (var i_1 = 0, len_1 = temporalDisplayables.length; i_1 < len_1; i_1++) { + var displayable = temporalDisplayables[i_1]; + displayable.beforeBrush && displayable.beforeBrush(); + displayable.innerBeforeBrush(); + brush(ctx, displayable, innerScope, i_1 === len_1 - 1); + displayable.innerAfterBrush(); + displayable.afterBrush && displayable.afterBrush(); + innerScope.prevEl = displayable; + } + + el.clearTemporalDisplayables(); + el.notClear = true; + ctx.restore(); + } + + var decalMap = new WeakMap(); + var decalCache = new LRU(100); + var decalKeys = ['symbol', 'symbolSize', 'symbolKeepAspect', 'color', 'backgroundColor', 'dashArrayX', 'dashArrayY', 'maxTileWidth', 'maxTileHeight']; + /** + * Create or update pattern image from decal options + * + * @param {InnerDecalObject | 'none'} decalObject decal options, 'none' if no decal + * @return {Pattern} pattern with generated image, null if no decal + */ + + function createOrUpdatePatternFromDecal(decalObject, api) { + if (decalObject === 'none') { + return null; + } + + var dpr = api.getDevicePixelRatio(); + var zr = api.getZr(); + var isSVG = zr.painter.type === 'svg'; + + if (decalObject.dirty) { + decalMap["delete"](decalObject); + } + + var oldPattern = decalMap.get(decalObject); + + if (oldPattern) { + return oldPattern; + } + + var decalOpt = defaults(decalObject, { + symbol: 'rect', + symbolSize: 1, + symbolKeepAspect: true, + color: 'rgba(0, 0, 0, 0.2)', + backgroundColor: null, + dashArrayX: 5, + dashArrayY: 5, + rotation: 0, + maxTileWidth: 512, + maxTileHeight: 512 + }); + + if (decalOpt.backgroundColor === 'none') { + decalOpt.backgroundColor = null; + } + + var pattern = { + repeat: 'repeat' + }; + setPatternnSource(pattern); + pattern.rotation = decalOpt.rotation; + pattern.scaleX = pattern.scaleY = isSVG ? 1 : 1 / dpr; + decalMap.set(decalObject, pattern); + decalObject.dirty = false; + return pattern; + + function setPatternnSource(pattern) { + var keys = [dpr]; + var isValidKey = true; + + for (var i = 0; i < decalKeys.length; ++i) { + var value = decalOpt[decalKeys[i]]; + + if (value != null && !isArray(value) && !isString(value) && !isNumber(value) && typeof value !== 'boolean') { + isValidKey = false; + break; + } + + keys.push(value); + } + + var cacheKey; + + if (isValidKey) { + cacheKey = keys.join(',') + (isSVG ? '-svg' : ''); + var cache = decalCache.get(cacheKey); + + if (cache) { + isSVG ? pattern.svgElement = cache : pattern.image = cache; + } + } + + var dashArrayX = normalizeDashArrayX(decalOpt.dashArrayX); + var dashArrayY = normalizeDashArrayY(decalOpt.dashArrayY); + var symbolArray = normalizeSymbolArray(decalOpt.symbol); + var lineBlockLengthsX = getLineBlockLengthX(dashArrayX); + var lineBlockLengthY = getLineBlockLengthY(dashArrayY); + var canvas = !isSVG && platformApi.createCanvas(); + var svgRoot = isSVG && { + tag: 'g', + attrs: {}, + key: 'dcl', + children: [] + }; + var pSize = getPatternSize(); + var ctx; + + if (canvas) { + canvas.width = pSize.width * dpr; + canvas.height = pSize.height * dpr; + ctx = canvas.getContext('2d'); + } + + brushDecal(); + + if (isValidKey) { + decalCache.put(cacheKey, canvas || svgRoot); + } + + pattern.image = canvas; + pattern.svgElement = svgRoot; + pattern.svgWidth = pSize.width; + pattern.svgHeight = pSize.height; + /** + * Get minimum length that can make a repeatable pattern. + * + * @return {Object} pattern width and height + */ + + function getPatternSize() { + /** + * For example, if dash is [[3, 2], [2, 1]] for X, it looks like + * |--- --- --- --- --- ... + * |-- -- -- -- -- -- -- -- ... + * |--- --- --- --- --- ... + * |-- -- -- -- -- -- -- -- ... + * So the minimum length of X is 15, + * which is the least common multiple of `3 + 2` and `2 + 1` + * |--- --- --- |--- --- ... + * |-- -- -- -- -- |-- -- -- ... + */ + var width = 1; + + for (var i = 0, xlen = lineBlockLengthsX.length; i < xlen; ++i) { + width = getLeastCommonMultiple(width, lineBlockLengthsX[i]); + } + + var symbolRepeats = 1; + + for (var i = 0, xlen = symbolArray.length; i < xlen; ++i) { + symbolRepeats = getLeastCommonMultiple(symbolRepeats, symbolArray[i].length); + } + + width *= symbolRepeats; + var height = lineBlockLengthY * lineBlockLengthsX.length * symbolArray.length; + { + var warn = function (attrName) { + /* eslint-disable-next-line */ + console.warn("Calculated decal size is greater than " + attrName + " due to decal option settings so " + attrName + " is used for the decal size. Please consider changing the decal option to make a smaller decal or set " + attrName + " to be larger to avoid incontinuity."); + }; + + if (width > decalOpt.maxTileWidth) { + warn('maxTileWidth'); + } + + if (height > decalOpt.maxTileHeight) { + warn('maxTileHeight'); + } + } + return { + width: Math.max(1, Math.min(width, decalOpt.maxTileWidth)), + height: Math.max(1, Math.min(height, decalOpt.maxTileHeight)) + }; + } + + function brushDecal() { + if (ctx) { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + if (decalOpt.backgroundColor) { + ctx.fillStyle = decalOpt.backgroundColor; + ctx.fillRect(0, 0, canvas.width, canvas.height); + } + } + + var ySum = 0; + + for (var i = 0; i < dashArrayY.length; ++i) { + ySum += dashArrayY[i]; + } + + if (ySum <= 0) { + // dashArrayY is 0, draw nothing + return; + } + + var y = -lineBlockLengthY; + var yId = 0; + var yIdTotal = 0; + var xId0 = 0; + + while (y < pSize.height) { + if (yId % 2 === 0) { + var symbolYId = yIdTotal / 2 % symbolArray.length; + var x = 0; + var xId1 = 0; + var xId1Total = 0; + + while (x < pSize.width * 2) { + var xSum = 0; + + for (var i = 0; i < dashArrayX[xId0].length; ++i) { + xSum += dashArrayX[xId0][i]; + } + + if (xSum <= 0) { + // Skip empty line + break; + } // E.g., [15, 5, 20, 5] draws only for 15 and 20 + + + if (xId1 % 2 === 0) { + var size = (1 - decalOpt.symbolSize) * 0.5; + var left = x + dashArrayX[xId0][xId1] * size; + var top_1 = y + dashArrayY[yId] * size; + var width = dashArrayX[xId0][xId1] * decalOpt.symbolSize; + var height = dashArrayY[yId] * decalOpt.symbolSize; + var symbolXId = xId1Total / 2 % symbolArray[symbolYId].length; + brushSymbol(left, top_1, width, height, symbolArray[symbolYId][symbolXId]); + } + + x += dashArrayX[xId0][xId1]; + ++xId1Total; + ++xId1; + + if (xId1 === dashArrayX[xId0].length) { + xId1 = 0; + } + } + + ++xId0; + + if (xId0 === dashArrayX.length) { + xId0 = 0; + } + } + + y += dashArrayY[yId]; + ++yIdTotal; + ++yId; + + if (yId === dashArrayY.length) { + yId = 0; + } + } + + function brushSymbol(x, y, width, height, symbolType) { + var scale = isSVG ? 1 : dpr; + var symbol = createSymbol(symbolType, x * scale, y * scale, width * scale, height * scale, decalOpt.color, decalOpt.symbolKeepAspect); + + if (isSVG) { + var symbolVNode = zr.painter.renderOneToVNode(symbol); + + if (symbolVNode) { + svgRoot.children.push(symbolVNode); + } + } else { + // Paint to canvas for all other renderers. + brushSingle(ctx, symbol); + } + } + } + } + } + /** + * Convert symbol array into normalized array + * + * @param {string | (string | string[])[]} symbol symbol input + * @return {string[][]} normolized symbol array + */ + + + function normalizeSymbolArray(symbol) { + if (!symbol || symbol.length === 0) { + return [['rect']]; + } + + if (isString(symbol)) { + return [[symbol]]; + } + + var isAllString = true; + + for (var i = 0; i < symbol.length; ++i) { + if (!isString(symbol[i])) { + isAllString = false; + break; + } + } + + if (isAllString) { + return normalizeSymbolArray([symbol]); + } + + var result = []; + + for (var i = 0; i < symbol.length; ++i) { + if (isString(symbol[i])) { + result.push([symbol[i]]); + } else { + result.push(symbol[i]); + } + } + + return result; + } + /** + * Convert dash input into dashArray + * + * @param {DecalDashArrayX} dash dash input + * @return {number[][]} normolized dash array + */ + + + function normalizeDashArrayX(dash) { + if (!dash || dash.length === 0) { + return [[0, 0]]; + } + + if (isNumber(dash)) { + var dashValue = Math.ceil(dash); + return [[dashValue, dashValue]]; + } + /** + * [20, 5] should be normalized into [[20, 5]], + * while [20, [5, 10]] should be normalized into [[20, 20], [5, 10]] + */ + + + var isAllNumber = true; + + for (var i = 0; i < dash.length; ++i) { + if (!isNumber(dash[i])) { + isAllNumber = false; + break; + } + } + + if (isAllNumber) { + return normalizeDashArrayX([dash]); + } + + var result = []; + + for (var i = 0; i < dash.length; ++i) { + if (isNumber(dash[i])) { + var dashValue = Math.ceil(dash[i]); + result.push([dashValue, dashValue]); + } else { + var dashValue = map$1(dash[i], function (n) { + return Math.ceil(n); + }); + + if (dashValue.length % 2 === 1) { + // [4, 2, 1] means |---- - -- |---- - -- | + // so normalize it to be [4, 2, 1, 4, 2, 1] + result.push(dashValue.concat(dashValue)); + } else { + result.push(dashValue); + } + } + } + + return result; + } + /** + * Convert dash input into dashArray + * + * @param {DecalDashArrayY} dash dash input + * @return {number[]} normolized dash array + */ + + + function normalizeDashArrayY(dash) { + if (!dash || typeof dash === 'object' && dash.length === 0) { + return [0, 0]; + } + + if (isNumber(dash)) { + var dashValue_1 = Math.ceil(dash); + return [dashValue_1, dashValue_1]; + } + + var dashValue = map$1(dash, function (n) { + return Math.ceil(n); + }); + return dash.length % 2 ? dashValue.concat(dashValue) : dashValue; + } + /** + * Get block length of each line. A block is the length of dash line and space. + * For example, a line with [4, 1] has a dash line of 4 and a space of 1 after + * that, so the block length of this line is 5. + * + * @param {number[][]} dash dash array of X or Y + * @return {number[]} block length of each line + */ + + + function getLineBlockLengthX(dash) { + return map$1(dash, function (line) { + return getLineBlockLengthY(line); + }); + } + + function getLineBlockLengthY(dash) { + var blockLength = 0; + + for (var i = 0; i < dash.length; ++i) { + blockLength += dash[i]; + } + + if (dash.length % 2 === 1) { + // [4, 2, 1] means |---- - -- |---- - -- | + // So total length is (4 + 2 + 1) * 2 + return blockLength * 2; + } + + return blockLength; + } + + function decalVisual(ecModel, api) { + ecModel.eachRawSeries(function (seriesModel) { + if (ecModel.isSeriesFiltered(seriesModel)) { + return; + } + + var data = seriesModel.getData(); + + if (data.hasItemVisual()) { + data.each(function (idx) { + var decal = data.getItemVisual(idx, 'decal'); + + if (decal) { + var itemStyle = data.ensureUniqueItemVisual(idx, 'style'); + itemStyle.decal = createOrUpdatePatternFromDecal(decal, api); + } + }); + } + + var decal = data.getVisual('decal'); + + if (decal) { + var style = data.getVisual('style'); + style.decal = createOrUpdatePatternFromDecal(decal, api); + } + }); + } + + var lifecycle = new Eventful(); // Implementation of exported APIs. For example registerMap, getMap. + // The implementations will be registered when installing the component. + // Avoid these code being bundled to the core module. + + var implsStore = {}; // TODO Type + + function registerImpl(name, impl) { + { + if (implsStore[name]) { + error("Already has an implementation of " + name + "."); + } + } + implsStore[name] = impl; + } + + function getImpl(name) { + { + if (!implsStore[name]) { + error("Implementation of " + name + " doesn't exists."); + } + } + return implsStore[name]; + } + + var version = '6.0.0'; + var dependencies = { + zrender: '6.0.0' + }; + var TEST_FRAME_REMAIN_TIME = 1; + var PRIORITY_PROCESSOR_SERIES_FILTER = 800; // Some data processors depends on the stack result dimension (to calculate data extent). + // So data stack stage should be in front of data processing stage. + + var PRIORITY_PROCESSOR_DATASTACK = 900; // "Data filter" will block the stream, so it should be + // put at the beginning of data processing. + + var PRIORITY_PROCESSOR_FILTER = 1000; + var PRIORITY_PROCESSOR_DEFAULT = 2000; + var PRIORITY_PROCESSOR_STATISTIC = 5000; + var PRIORITY_VISUAL_LAYOUT = 1000; + var PRIORITY_VISUAL_PROGRESSIVE_LAYOUT = 1100; + var PRIORITY_VISUAL_GLOBAL = 2000; + var PRIORITY_VISUAL_CHART = 3000; + var PRIORITY_VISUAL_COMPONENT = 4000; // Visual property in data. Greater than `PRIORITY_VISUAL_COMPONENT` to enable to + // overwrite the viusal result of component (like `visualMap`) + // using data item specific setting (like itemStyle.xxx on data item) + + var PRIORITY_VISUAL_CHART_DATA_CUSTOM = 4500; // Greater than `PRIORITY_VISUAL_CHART_DATA_CUSTOM` to enable to layout based on + // visual result like `symbolSize`. + + var PRIORITY_VISUAL_POST_CHART_LAYOUT = 4600; + var PRIORITY_VISUAL_BRUSH = 5000; + var PRIORITY_VISUAL_ARIA = 6000; + var PRIORITY_VISUAL_DECAL = 7000; + var PRIORITY = { + PROCESSOR: { + FILTER: PRIORITY_PROCESSOR_FILTER, + SERIES_FILTER: PRIORITY_PROCESSOR_SERIES_FILTER, + STATISTIC: PRIORITY_PROCESSOR_STATISTIC + }, + VISUAL: { + LAYOUT: PRIORITY_VISUAL_LAYOUT, + PROGRESSIVE_LAYOUT: PRIORITY_VISUAL_PROGRESSIVE_LAYOUT, + GLOBAL: PRIORITY_VISUAL_GLOBAL, + CHART: PRIORITY_VISUAL_CHART, + POST_CHART_LAYOUT: PRIORITY_VISUAL_POST_CHART_LAYOUT, + COMPONENT: PRIORITY_VISUAL_COMPONENT, + BRUSH: PRIORITY_VISUAL_BRUSH, + CHART_ITEM: PRIORITY_VISUAL_CHART_DATA_CUSTOM, + ARIA: PRIORITY_VISUAL_ARIA, + DECAL: PRIORITY_VISUAL_DECAL + } + }; // Main process have three entries: `setOption`, `dispatchAction` and `resize`, + // where they must not be invoked nestedly, except the only case: invoke + // dispatchAction with updateMethod "none" in main process. + // This flag is used to carry out this rule. + // All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]). + + var IN_MAIN_PROCESS_KEY = '__flagInMainProcess'; // Useful for detecting outdated rendering results in scenarios that these issues are involved: + // - Use shortcut (such as, updateTransform, or no update) to start a main process. + // - Asynchronously update rendered view (e.g., graph force layout). + // - Multiple ChartView/ComponentView render to one group cooperatively. + + var MAIN_PROCESS_VERSION_KEY = '__mainProcessVersion'; + var PENDING_UPDATE = '__pendingUpdate'; + var STATUS_NEEDS_UPDATE_KEY = '__needsUpdateStatus'; + var ACTION_REG = /^[a-zA-Z0-9_]+$/; + var CONNECT_STATUS_KEY = '__connectUpdateStatus'; + var CONNECT_STATUS_PENDING = 0; + var CONNECT_STATUS_UPDATING = 1; + var CONNECT_STATUS_UPDATED = 2; + + function createRegisterEventWithLowercaseECharts(method) { + return function () { + var args = []; + + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + + if (this.isDisposed()) { + disposedWarning(this.id); + return; + } + + return toLowercaseNameAndCallEventful(this, method, args); + }; + } + + function createRegisterEventWithLowercaseMessageCenter(method) { + return function () { + var args = []; + + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + + return toLowercaseNameAndCallEventful(this, method, args); + }; + } + + function toLowercaseNameAndCallEventful(host, method, args) { + // `args[0]` is event name. Event name is all lowercase. + args[0] = args[0] && args[0].toLowerCase(); + return Eventful.prototype[method].apply(host, args); + } + + var MessageCenter = + /** @class */ + function (_super) { + __extends(MessageCenter, _super); + + function MessageCenter() { + return _super !== null && _super.apply(this, arguments) || this; + } + + return MessageCenter; + }(Eventful); + + var messageCenterProto = MessageCenter.prototype; + messageCenterProto.on = createRegisterEventWithLowercaseMessageCenter('on'); + messageCenterProto.off = createRegisterEventWithLowercaseMessageCenter('off'); // --------------------------------------- + // Internal method names for class ECharts + // --------------------------------------- + + var prepare; + var prepareView; + var updateDirectly; + var updateMethods; + var doConvertPixel; + var updateStreamModes; + var doDispatchAction; + var flushPendingActions; + var triggerUpdatedEvent; + var bindRenderedEvent; + var bindMouseEvent; + var render; + var renderComponents; + var renderSeries; + var createExtensionAPI; + var enableConnect; + var markStatusToUpdate; + var applyChangedStates; + var updateMainProcessVersion; + + var ECharts = + /** @class */ + function (_super) { + __extends(ECharts, _super); + + function ECharts(dom, // Theme name or themeOption. + theme, opts) { + var _this = _super.call(this, new ECEventProcessor()) || this; + + _this._chartsViews = []; + _this._chartsMap = {}; + _this._componentsViews = []; + _this._componentsMap = {}; // Can't dispatch action during rendering procedure + + _this._pendingActions = []; + opts = opts || {}; + _this._dom = dom; + var defaultRenderer = 'canvas'; + var defaultCoarsePointer = 'auto'; + var defaultUseDirtyRect = false; + _this[MAIN_PROCESS_VERSION_KEY] = 1; + { + var root = + /* eslint-disable-next-line */ + env.hasGlobalWindow ? window : global; + + if (root) { + defaultRenderer = retrieve2(root.__ECHARTS__DEFAULT__RENDERER__, defaultRenderer); + defaultCoarsePointer = retrieve2(root.__ECHARTS__DEFAULT__COARSE_POINTER, defaultCoarsePointer); + defaultUseDirtyRect = retrieve2(root.__ECHARTS__DEFAULT__USE_DIRTY_RECT__, defaultUseDirtyRect); + } + } + + if (opts.ssr) { + registerSSRDataGetter(function (el) { + var ecData = getECData(el); + var dataIndex = ecData.dataIndex; + + if (dataIndex == null) { + return; + } + + var hashMap = createHashMap(); + hashMap.set('series_index', ecData.seriesIndex); + hashMap.set('data_index', dataIndex); + ecData.ssrType && hashMap.set('ssr_type', ecData.ssrType); + return hashMap; + }); + } + + var zr = _this._zr = init$1(dom, { + renderer: opts.renderer || defaultRenderer, + devicePixelRatio: opts.devicePixelRatio, + width: opts.width, + height: opts.height, + ssr: opts.ssr, + useDirtyRect: retrieve2(opts.useDirtyRect, defaultUseDirtyRect), + useCoarsePointer: retrieve2(opts.useCoarsePointer, defaultCoarsePointer), + pointerSize: opts.pointerSize + }); + _this._ssr = opts.ssr; // Expect 60 fps. + + _this._throttledZrFlush = throttle(bind$1(zr.flush, zr), 17); + + _this._updateTheme(theme); + + _this._locale = createLocaleObject(opts.locale || SYSTEM_LANG); + _this._coordSysMgr = new CoordinateSystemManager(); + var api = _this._api = createExtensionAPI(_this); // Sort on demand + + function prioritySortFunc(a, b) { + return a.__prio - b.__prio; + } + + sort(visualFuncs, prioritySortFunc); + sort(dataProcessorFuncs, prioritySortFunc); + _this._scheduler = new Scheduler(_this, api, dataProcessorFuncs, visualFuncs); + _this._messageCenter = new MessageCenter(); // Init mouse events + + _this._initEvents(); // In case some people write `window.onresize = chart.resize` + + + _this.resize = bind$1(_this.resize, _this); + zr.animation.on('frame', _this._onframe, _this); + bindRenderedEvent(zr, _this); + bindMouseEvent(zr, _this); // ECharts instance can be used as value. + + setAsPrimitive(_this); + return _this; + } + + ECharts.prototype._onframe = function () { + if (this._disposed) { + return; + } + + applyChangedStates(this); + var scheduler = this._scheduler; // Lazy update + + if (this[PENDING_UPDATE]) { + var silent = this[PENDING_UPDATE].silent; + this[IN_MAIN_PROCESS_KEY] = true; + updateMainProcessVersion(this); + + try { + prepare(this); + updateMethods.update.call(this, null, this[PENDING_UPDATE].updateParams); + } catch (e) { + this[IN_MAIN_PROCESS_KEY] = false; + this[PENDING_UPDATE] = null; + throw e; + } // At present, in each frame, zrender performs: + // (1) animation step forward. + // (2) trigger('frame') (where this `_onframe` is called) + // (3) zrender flush (render). + // If we do nothing here, since we use `setToFinal: true`, the step (3) above + // will render the final state of the elements before the real animation started. + + + this._zr.flush(); + + this[IN_MAIN_PROCESS_KEY] = false; + this[PENDING_UPDATE] = null; + flushPendingActions.call(this, silent); + triggerUpdatedEvent.call(this, silent); + } // Avoid do both lazy update and progress in one frame. + else if (scheduler.unfinished) { + // Stream progress. + var remainTime = TEST_FRAME_REMAIN_TIME; + var ecModel = this._model; + var api = this._api; + scheduler.unfinished = false; + + do { + var startTime = +new Date(); + scheduler.performSeriesTasks(ecModel); // Currently dataProcessorFuncs do not check threshold. + + scheduler.performDataProcessorTasks(ecModel); + updateStreamModes(this, ecModel); // Do not update coordinate system here. Because that coord system update in + // each frame is not a good user experience. So we follow the rule that + // the extent of the coordinate system is determined in the first frame (the + // frame is executed immediately after task reset. + // this._coordSysMgr.update(ecModel, api); + // console.log('--- ec frame visual ---', remainTime); + + scheduler.performVisualTasks(ecModel); + renderSeries(this, this._model, api, 'remain', {}); + remainTime -= +new Date() - startTime; + } while (remainTime > 0 && scheduler.unfinished); // Call flush explicitly for trigger finished event. + + + if (!scheduler.unfinished) { + this._zr.flush(); + } // Else, zr flushing be ensue within the same frame, + // because zr flushing is after onframe event. + + } + }; + + ECharts.prototype.getDom = function () { + return this._dom; + }; + + ECharts.prototype.getId = function () { + return this.id; + }; + + ECharts.prototype.getZr = function () { + return this._zr; + }; + + ECharts.prototype.isSSR = function () { + return this._ssr; + }; + /* eslint-disable-next-line */ + + + ECharts.prototype.setOption = function (option, notMerge, lazyUpdate) { + if (this[IN_MAIN_PROCESS_KEY]) { + { + error('`setOption` should not be called during main process.'); + } + return; + } + + if (this._disposed) { + disposedWarning(this.id); + return; + } + + var silent; + var replaceMerge; + var transitionOpt; + + if (isObject$2(notMerge)) { + lazyUpdate = notMerge.lazyUpdate; + silent = notMerge.silent; + replaceMerge = notMerge.replaceMerge; + transitionOpt = notMerge.transition; + notMerge = notMerge.notMerge; + } + + this[IN_MAIN_PROCESS_KEY] = true; + updateMainProcessVersion(this); + + if (!this._model || notMerge) { + var optionManager = new OptionManager(this._api); + var theme = this._theme; + var ecModel = this._model = new GlobalModel(); + ecModel.scheduler = this._scheduler; + ecModel.ssr = this._ssr; + ecModel.init(null, null, null, theme, this._locale, optionManager); + } + + this._model.setOption(option, { + replaceMerge: replaceMerge + }, optionPreprocessorFuncs); + + var updateParams = { + seriesTransition: transitionOpt, + optionChanged: true + }; + + if (lazyUpdate) { + this[PENDING_UPDATE] = { + silent: silent, + updateParams: updateParams + }; + this[IN_MAIN_PROCESS_KEY] = false; // `setOption(option, {lazyMode: true})` may be called when zrender has been slept. + // It should wake it up to make sure zrender start to render at the next frame. + + this.getZr().wakeUp(); + } else { + try { + prepare(this); + updateMethods.update.call(this, null, updateParams); + } catch (e) { + this[PENDING_UPDATE] = null; + this[IN_MAIN_PROCESS_KEY] = false; + throw e; + } // Ensure zr refresh sychronously, and then pixel in canvas can be + // fetched after `setOption`. + + + if (!this._ssr) { + // not use flush when using ssr mode. + this._zr.flush(); + } + + this[PENDING_UPDATE] = null; + this[IN_MAIN_PROCESS_KEY] = false; + flushPendingActions.call(this, silent); + triggerUpdatedEvent.call(this, silent); + } + }; + /** + * Update theme with name or theme option and repaint the chart. + * @param theme Theme name or theme option. + * @param opts Optional settings + */ + + + ECharts.prototype.setTheme = function (theme, opts) { + if (this[IN_MAIN_PROCESS_KEY]) { + { + error('`setTheme` should not be called during main process.'); + } + return; + } + + if (this._disposed) { + disposedWarning(this.id); + return; + } + + var ecModel = this._model; + + if (!ecModel) { + return; + } + + var silent = opts && opts.silent; + var updateParams = null; + + if (this[PENDING_UPDATE]) { + if (silent == null) { + silent = this[PENDING_UPDATE].silent; + } + + updateParams = this[PENDING_UPDATE].updateParams; + this[PENDING_UPDATE] = null; + } + + this[IN_MAIN_PROCESS_KEY] = true; + updateMainProcessVersion(this); + + try { + this._updateTheme(theme); + + ecModel.setTheme(this._theme); + prepare(this); + updateMethods.update.call(this, { + type: 'setTheme' + }, updateParams); + } catch (e) { + this[IN_MAIN_PROCESS_KEY] = false; + throw e; + } + + this[IN_MAIN_PROCESS_KEY] = false; + flushPendingActions.call(this, silent); + triggerUpdatedEvent.call(this, silent); + }; + + ECharts.prototype._updateTheme = function (theme) { + if (isString(theme)) { + theme = themeStorage[theme]; + } + + if (theme) { + theme = clone$3(theme); + theme && globalBackwardCompat(theme, true); + this._theme = theme; + } + }; // We don't want developers to use getModel directly. + + + ECharts.prototype.getModel = function () { + return this._model; + }; + + ECharts.prototype.getOption = function () { + return this._model && this._model.getOption(); + }; + + ECharts.prototype.getWidth = function () { + return this._zr.getWidth(); + }; + + ECharts.prototype.getHeight = function () { + return this._zr.getHeight(); + }; + + ECharts.prototype.getDevicePixelRatio = function () { + return this._zr.painter.dpr + /* eslint-disable-next-line */ + || env.hasGlobalWindow && window.devicePixelRatio || 1; + }; + /** + * Get canvas which has all thing rendered + * @deprecated Use renderToCanvas instead. + */ + + + ECharts.prototype.getRenderedCanvas = function (opts) { + { + deprecateReplaceLog('getRenderedCanvas', 'renderToCanvas'); + } + return this.renderToCanvas(opts); + }; + + ECharts.prototype.renderToCanvas = function (opts) { + opts = opts || {}; + var painter = this._zr.painter; + { + if (painter.type !== 'canvas') { + throw new Error('renderToCanvas can only be used in the canvas renderer.'); + } + } + return painter.getRenderedCanvas({ + backgroundColor: opts.backgroundColor || this._model.get('backgroundColor'), + pixelRatio: opts.pixelRatio || this.getDevicePixelRatio() + }); + }; + + ECharts.prototype.renderToSVGString = function (opts) { + opts = opts || {}; + var painter = this._zr.painter; + { + if (painter.type !== 'svg') { + throw new Error('renderToSVGString can only be used in the svg renderer.'); + } + } + return painter.renderToString({ + useViewBox: opts.useViewBox + }); + }; + /** + * Get svg data url + */ + + + ECharts.prototype.getSvgDataURL = function () { + var zr = this._zr; + var list = zr.storage.getDisplayList(); // Stop animations + + each$4(list, function (el) { + el.stopAnimation(null, true); + }); + return zr.painter.toDataURL(); + }; + + ECharts.prototype.getDataURL = function (opts) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + opts = opts || {}; + var excludeComponents = opts.excludeComponents; + var ecModel = this._model; + var excludesComponentViews = []; + var self = this; + each$4(excludeComponents, function (componentType) { + ecModel.eachComponent({ + mainType: componentType + }, function (component) { + var view = self._componentsMap[component.__viewId]; + + if (!view.group.ignore) { + excludesComponentViews.push(view); + view.group.ignore = true; + } + }); + }); + var url = this._zr.painter.getType() === 'svg' ? this.getSvgDataURL() : this.renderToCanvas(opts).toDataURL('image/' + (opts && opts.type || 'png')); + each$4(excludesComponentViews, function (view) { + view.group.ignore = false; + }); + return url; + }; + + ECharts.prototype.getConnectedDataURL = function (opts) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + var isSvg = opts.type === 'svg'; + var groupId = this.group; + var mathMin = Math.min; + var mathMax = Math.max; + var MAX_NUMBER = Infinity; + + if (connectedGroups[groupId]) { + var left_1 = MAX_NUMBER; + var top_1 = MAX_NUMBER; + var right_1 = -MAX_NUMBER; + var bottom_1 = -MAX_NUMBER; + var canvasList_1 = []; + var dpr_1 = opts && opts.pixelRatio || this.getDevicePixelRatio(); + each$4(instances, function (chart, id) { + if (chart.group === groupId) { + var canvas = isSvg ? chart.getZr().painter.getSvgDom().innerHTML : chart.renderToCanvas(clone$3(opts)); + var boundingRect = chart.getDom().getBoundingClientRect(); + left_1 = mathMin(boundingRect.left, left_1); + top_1 = mathMin(boundingRect.top, top_1); + right_1 = mathMax(boundingRect.right, right_1); + bottom_1 = mathMax(boundingRect.bottom, bottom_1); + canvasList_1.push({ + dom: canvas, + left: boundingRect.left, + top: boundingRect.top + }); + } + }); + left_1 *= dpr_1; + top_1 *= dpr_1; + right_1 *= dpr_1; + bottom_1 *= dpr_1; + var width = right_1 - left_1; + var height = bottom_1 - top_1; + var targetCanvas = platformApi.createCanvas(); + var zr_1 = init$1(targetCanvas, { + renderer: isSvg ? 'svg' : 'canvas' + }); + zr_1.resize({ + width: width, + height: height + }); + + if (isSvg) { + var content_1 = ''; + each$4(canvasList_1, function (item) { + var x = item.left - left_1; + var y = item.top - top_1; + content_1 += '' + item.dom + ''; + }); + zr_1.painter.getSvgRoot().innerHTML = content_1; + + if (opts.connectedBackgroundColor) { + zr_1.painter.setBackgroundColor(opts.connectedBackgroundColor); + } + + zr_1.refreshImmediately(); + return zr_1.painter.toDataURL(); + } else { + // Background between the charts + if (opts.connectedBackgroundColor) { + zr_1.add(new Rect({ + shape: { + x: 0, + y: 0, + width: width, + height: height + }, + style: { + fill: opts.connectedBackgroundColor + } + })); + } + + each$4(canvasList_1, function (item) { + var img = new ZRImage({ + style: { + x: item.left * dpr_1 - left_1, + y: item.top * dpr_1 - top_1, + image: item.dom + } + }); + zr_1.add(img); + }); + zr_1.refreshImmediately(); + return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png')); + } + } else { + return this.getDataURL(opts); + } + }; + + ECharts.prototype.convertToPixel = function (finder, value, opt) { + return doConvertPixel(this, 'convertToPixel', finder, value, opt); + }; + /** + * Convert from logical coordinate system to pixel coordinate system. + * See CoordinateSystem#convertToPixel. + * + * @see CoordinateSystem['dataToLayout'] for parameters and return. + * @see CoordinateSystemDataCoord + */ + + + ECharts.prototype.convertToLayout = function (finder, value, opt) { + return doConvertPixel(this, 'convertToLayout', finder, value, opt); + }; // The above are signatures from before v6, thus they should be preserved for backward compat. + + + ECharts.prototype.convertFromPixel = function (finder, value, opt) { + return doConvertPixel(this, 'convertFromPixel', finder, value, opt); + }; + /** + * Is the specified coordinate systems or components contain the given pixel point. + * @param {Array|number} value + * @return {boolean} result + */ + + + ECharts.prototype.containPixel = function (finder, value) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + var ecModel = this._model; + var result; + var findResult = parseFinder(ecModel, finder); + each$4(findResult, function (models, key) { + key.indexOf('Models') >= 0 && each$4(models, function (model) { + var coordSys = model.coordinateSystem; + + if (coordSys && coordSys.containPoint) { + result = result || !!coordSys.containPoint(value); + } else if (key === 'seriesModels') { + var view = this._chartsMap[model.__viewId]; + + if (view && view.containPoint) { + result = result || view.containPoint(value, model); + } else { + { + warn(key + ': ' + (view ? 'The found component do not support containPoint.' : 'No view mapping to the found component.')); + } + } + } else { + { + warn(key + ': containPoint is not supported'); + } + } + }, this); + }, this); + return !!result; + }; + /** + * Get visual from series or data. + * @param finder + * If string, e.g., 'series', means {seriesIndex: 0}. + * If Object, could contain some of these properties below: + * { + * seriesIndex / seriesId / seriesName, + * dataIndex / dataIndexInside + * } + * If dataIndex is not specified, series visual will be fetched, + * but not data item visual. + * If all of seriesIndex, seriesId, seriesName are not specified, + * visual will be fetched from first series. + * @param visualType 'color', 'symbol', 'symbolSize' + */ + + + ECharts.prototype.getVisual = function (finder, visualType) { + var ecModel = this._model; + var parsedFinder = parseFinder(ecModel, finder, { + defaultMainType: 'series' + }); + var seriesModel = parsedFinder.seriesModel; + { + if (!seriesModel) { + warn('There is no specified series model'); + } + } + var data = seriesModel.getData(); + var dataIndexInside = parsedFinder.hasOwnProperty('dataIndexInside') ? parsedFinder.dataIndexInside : parsedFinder.hasOwnProperty('dataIndex') ? data.indexOfRawIndex(parsedFinder.dataIndex) : null; + return dataIndexInside != null ? getItemVisualFromData(data, dataIndexInside, visualType) : getVisualFromData(data, visualType); + }; + /** + * Get view of corresponding component model + */ + + + ECharts.prototype.getViewOfComponentModel = function (componentModel) { + return this._componentsMap[componentModel.__viewId]; + }; + /** + * Get view of corresponding series model + */ + + + ECharts.prototype.getViewOfSeriesModel = function (seriesModel) { + return this._chartsMap[seriesModel.__viewId]; + }; + + ECharts.prototype._initEvents = function () { + var _this = this; + + each$4(MOUSE_EVENT_NAMES, function (eveName) { + var handler = function (e) { + var ecModel = _this.getModel(); + + var el = e.target; + var params; + var isGlobalOut = eveName === 'globalout'; // no e.target when 'globalout'. + + if (isGlobalOut) { + params = {}; + } else { + el && findEventDispatcher(el, function (parent) { + var ecData = getECData(parent); + + if (ecData && ecData.dataIndex != null) { + var dataModel = ecData.dataModel || ecModel.getSeriesByIndex(ecData.seriesIndex); + params = dataModel && dataModel.getDataParams(ecData.dataIndex, ecData.dataType, el) || {}; + return true; + } // If element has custom eventData of components + else if (ecData.eventData) { + params = extend({}, ecData.eventData); + return true; + } + }, true); + } // Contract: if params prepared in mouse event, + // these properties must be specified: + // { + // componentType: string (component main type) + // componentIndex: number + // } + // Otherwise event query can not work. + + + if (params) { + var componentType = params.componentType; + var componentIndex = params.componentIndex; // Special handling for historic reason: when trigger by + // markLine/markPoint/markArea, the componentType is + // 'markLine'/'markPoint'/'markArea', but we should better + // enable them to be queried by seriesIndex, since their + // option is set in each series. + + if (componentType === 'markLine' || componentType === 'markPoint' || componentType === 'markArea') { + componentType = 'series'; + componentIndex = params.seriesIndex; + } + + var model = componentType && componentIndex != null && ecModel.getComponent(componentType, componentIndex); + var view = model && _this[model.mainType === 'series' ? '_chartsMap' : '_componentsMap'][model.__viewId]; + { + // `event.componentType` and `event[componentTpype + 'Index']` must not + // be missed, otherwise there is no way to distinguish source component. + // See `dataFormat.getDataParams`. + if (!isGlobalOut && !(model && view)) { + warn('model or view can not be found by params'); + } + } + params.event = e; + params.type = eveName; + _this._$eventProcessor.eventInfo = { + targetEl: el, + packedEvent: params, + model: model, + view: view + }; + + _this.trigger(eveName, params); + } + }; // Consider that some component (like tooltip, brush, ...) + // register zr event handler, but user event handler might + // do anything, such as call `setOption` or `dispatchAction`, + // which probably update any of the content and probably + // cause problem if it is called previous other inner handlers. + + + handler.zrEventfulCallAtLast = true; + + _this._zr.on(eveName, handler, _this); + }); + var messageCenter = this._messageCenter; + each$4(publicEventTypeMap, function (_, eventType) { + messageCenter.on(eventType, function (event) { + _this.trigger(eventType, event); + }); + }); + handleLegacySelectEvents(messageCenter, this, this._api); + }; + + ECharts.prototype.isDisposed = function () { + return this._disposed; + }; + + ECharts.prototype.clear = function () { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + this.setOption({ + series: [] + }, true); + }; + + ECharts.prototype.dispose = function () { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + this._disposed = true; + var dom = this.getDom(); + + if (dom) { + setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, ''); + } + + var chart = this; + var api = chart._api; + var ecModel = chart._model; + each$4(chart._componentsViews, function (component) { + component.dispose(ecModel, api); + }); + each$4(chart._chartsViews, function (chart) { + chart.dispose(ecModel, api); + }); // Dispose after all views disposed + + chart._zr.dispose(); // Set properties to null. + // To reduce the memory cost in case the top code still holds this instance unexpectedly. + + + chart._dom = chart._model = chart._chartsMap = chart._componentsMap = chart._chartsViews = chart._componentsViews = chart._scheduler = chart._api = chart._zr = chart._throttledZrFlush = chart._theme = chart._coordSysMgr = chart._messageCenter = null; + delete instances[chart.id]; + }; + /** + * Resize the chart + */ + + + ECharts.prototype.resize = function (opts) { + if (this[IN_MAIN_PROCESS_KEY]) { + { + error('`resize` should not be called during main process.'); + } + return; + } + + if (this._disposed) { + disposedWarning(this.id); + return; + } + + this._zr.resize(opts); + + var ecModel = this._model; // Resize loading effect + + this._loadingFX && this._loadingFX.resize(); + + if (!ecModel) { + return; + } + + var needPrepare = ecModel.resetOption('media'); + var silent = opts && opts.silent; // There is some real cases that: + // chart.setOption(option, { lazyUpdate: true }); + // chart.resize(); + + if (this[PENDING_UPDATE]) { + if (silent == null) { + silent = this[PENDING_UPDATE].silent; + } + + needPrepare = true; + this[PENDING_UPDATE] = null; + } + + this[IN_MAIN_PROCESS_KEY] = true; + updateMainProcessVersion(this); + + try { + needPrepare && prepare(this); + updateMethods.update.call(this, { + type: 'resize', + animation: extend({ + // Disable animation + duration: 0 + }, opts && opts.animation) + }); + } catch (e) { + this[IN_MAIN_PROCESS_KEY] = false; + throw e; + } + + this[IN_MAIN_PROCESS_KEY] = false; + flushPendingActions.call(this, silent); + triggerUpdatedEvent.call(this, silent); + }; + + ECharts.prototype.showLoading = function (name, cfg) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + if (isObject$2(name)) { + cfg = name; + name = ''; + } + + name = name || 'default'; + this.hideLoading(); + + if (!loadingEffects[name]) { + { + warn('Loading effects ' + name + ' not exists.'); + } + return; + } + + var el = loadingEffects[name](this._api, cfg); + var zr = this._zr; + this._loadingFX = el; + zr.add(el); + }; + /** + * Hide loading effect + */ + + + ECharts.prototype.hideLoading = function () { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + this._loadingFX && this._zr.remove(this._loadingFX); + this._loadingFX = null; + }; + + ECharts.prototype.makeActionFromEvent = function (eventObj) { + var payload = extend({}, eventObj); + payload.type = connectionEventRevertMap[eventObj.type]; + return payload; + }; + /** + * @param opt If pass boolean, means opt.silent + * @param opt.silent Default `false`. Whether trigger events. + * @param opt.flush Default `undefined`. + * true: Flush immediately, and then pixel in canvas can be fetched + * immediately. Caution: it might affect performance. + * false: Not flush. + * undefined: Auto decide whether perform flush. + */ + + + ECharts.prototype.dispatchAction = function (payload, opt) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + if (!isObject$2(opt)) { + opt = { + silent: !!opt + }; + } + + if (!actions[payload.type]) { + return; + } // Avoid dispatch action before setOption. Especially in `connect`. + + + if (!this._model) { + return; + } // May dispatchAction in rendering procedure + + + if (this[IN_MAIN_PROCESS_KEY]) { + this._pendingActions.push(payload); + + return; + } + + var silent = opt.silent; + doDispatchAction.call(this, payload, silent); + var flush = opt.flush; + + if (flush) { + this._zr.flush(); + } else if (flush !== false && env.browser.weChat) { + // In WeChat embedded browser, `requestAnimationFrame` and `setInterval` + // hang when sliding page (on touch event), which cause that zr does not + // refresh until user interaction finished, which is not expected. + // But `dispatchAction` may be called too frequently when pan on touch + // screen, which impacts performance if do not throttle them. + this._throttledZrFlush(); + } + + flushPendingActions.call(this, silent); + triggerUpdatedEvent.call(this, silent); + }; + + ECharts.prototype.updateLabelLayout = function () { + lifecycle.trigger('series:layoutlabels', this._model, this._api, { + // Not adding series labels. + // TODO + updatedSeries: [] + }); + }; + + ECharts.prototype.appendData = function (params) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + + var seriesIndex = params.seriesIndex; + var ecModel = this.getModel(); + var seriesModel = ecModel.getSeriesByIndex(seriesIndex); + { + assert(params.data && seriesModel); + } + seriesModel.appendData(params); // Note: `appendData` does not support that update extent of coordinate + // system, util some scenario require that. In the expected usage of + // `appendData`, the initial extent of coordinate system should better + // be fixed by axis `min`/`max` setting or initial data, otherwise if + // the extent changed while `appendData`, the location of the painted + // graphic elements have to be changed, which make the usage of + // `appendData` meaningless. + + this._scheduler.unfinished = true; + this.getZr().wakeUp(); + }; // A work around for no `internal` modifier in ts yet but + // need to strictly hide private methods to JS users. + + + ECharts.internalField = function () { + prepare = function (ecIns) { + var scheduler = ecIns._scheduler; + scheduler.restorePipelines(ecIns._model); + scheduler.prepareStageTasks(); + prepareView(ecIns, true); + prepareView(ecIns, false); + scheduler.plan(); + }; + /** + * Prepare view instances of charts and components + */ + + + prepareView = function (ecIns, isComponent) { + var ecModel = ecIns._model; + var scheduler = ecIns._scheduler; + var viewList = isComponent ? ecIns._componentsViews : ecIns._chartsViews; + var viewMap = isComponent ? ecIns._componentsMap : ecIns._chartsMap; + var zr = ecIns._zr; + var api = ecIns._api; + + for (var i = 0; i < viewList.length; i++) { + viewList[i].__alive = false; + } + + isComponent ? ecModel.eachComponent(function (componentType, model) { + componentType !== 'series' && doPrepare(model); + }) : ecModel.eachSeries(doPrepare); + + function doPrepare(model) { + // By default view will be reused if possible for the case that `setOption` with "notMerge" + // mode and need to enable transition animation. (Usually, when they have the same id, or + // especially no id but have the same type & name & index. See the `model.id` generation + // rule in `makeIdAndName` and `viewId` generation rule here). + // But in `replaceMerge` mode, this feature should be able to disabled when it is clear that + // the new model has nothing to do with the old model. + var requireNewView = model.__requireNewView; // This command should not work twice. + + model.__requireNewView = false; // Consider: id same and type changed. + + var viewId = '_ec_' + model.id + '_' + model.type; + var view = !requireNewView && viewMap[viewId]; + + if (!view) { + var classType = parseClassType(model.type); + var Clazz = isComponent ? ComponentView.getClass(classType.main, classType.sub) : // FIXME:TS + // (ChartView as ChartViewConstructor).getClass('series', classType.sub) + // For backward compat, still support a chart type declared as only subType + // like "liquidfill", but recommend "series.liquidfill" + // But need a base class to make a type series. + ChartView.getClass(classType.sub); + { + assert(Clazz, classType.sub + ' does not exist.'); + } + view = new Clazz(); + view.init(ecModel, api); + viewMap[viewId] = view; + viewList.push(view); + zr.add(view.group); + } + + model.__viewId = view.__id = viewId; + view.__alive = true; + view.__model = model; + view.group.__ecComponentInfo = { + mainType: model.mainType, + index: model.componentIndex + }; + !isComponent && scheduler.prepareView(view, model, ecModel, api); + } + + for (var i = 0; i < viewList.length;) { + var view = viewList[i]; + + if (!view.__alive) { + !isComponent && view.renderTask.dispose(); + zr.remove(view.group); + view.dispose(ecModel, api); + viewList.splice(i, 1); + + if (viewMap[view.__id] === view) { + delete viewMap[view.__id]; + } + + view.__id = view.group.__ecComponentInfo = null; + } else { + i++; + } + } + }; + + updateDirectly = function (ecIns, method, payload, mainType, subType) { + var ecModel = ecIns._model; + ecModel.setUpdatePayload(payload); // broadcast + + if (!mainType) { + // FIXME + // Chart will not be update directly here, except set dirty. + // But there is no such scenario now. + each$4([].concat(ecIns._componentsViews).concat(ecIns._chartsViews), callView); + return; + } + + var query = {}; + query[mainType + 'Id'] = payload[mainType + 'Id']; + query[mainType + 'Index'] = payload[mainType + 'Index']; + query[mainType + 'Name'] = payload[mainType + 'Name']; + var condition = { + mainType: mainType, + query: query + }; + subType && (condition.subType = subType); // subType may be '' by parseClassType; + + var excludeSeriesId = payload.excludeSeriesId; + var excludeSeriesIdMap; + + if (excludeSeriesId != null) { + excludeSeriesIdMap = createHashMap(); + each$4(normalizeToArray(excludeSeriesId), function (id) { + var modelId = convertOptionIdName(id, null); + + if (modelId != null) { + excludeSeriesIdMap.set(modelId, true); + } + }); + } // If dispatchAction before setOption, do nothing. + + + ecModel && ecModel.eachComponent(condition, function (model) { + var isExcluded = excludeSeriesIdMap && excludeSeriesIdMap.get(model.id) != null; + + if (isExcluded) { + return; + } + + if (isHighDownPayload(payload)) { + if (model instanceof SeriesModel) { + if (payload.type === HIGHLIGHT_ACTION_TYPE && !payload.notBlur && !model.get(['emphasis', 'disabled'])) { + blurSeriesFromHighlightPayload(model, payload, ecIns._api); + } + } else { + var _a = findComponentHighDownDispatchers(model.mainType, model.componentIndex, payload.name, ecIns._api), + focusSelf = _a.focusSelf, + dispatchers = _a.dispatchers; + + if (payload.type === HIGHLIGHT_ACTION_TYPE && focusSelf && !payload.notBlur) { + blurComponent(model.mainType, model.componentIndex, ecIns._api); + } // PENDING: + // Whether to put this "enter emphasis" code in `ComponentView`, + // which will be the same as `ChartView` but might be not necessary + // and will be far from this logic. + + + if (dispatchers) { + each$4(dispatchers, function (dispatcher) { + payload.type === HIGHLIGHT_ACTION_TYPE ? enterEmphasis(dispatcher) : leaveEmphasis(dispatcher); + }); + } + } + } else if (isSelectChangePayload(payload)) { + // TODO geo + if (model instanceof SeriesModel) { + toggleSelectionFromPayload(model, payload, ecIns._api); + updateSeriesElementSelection(model); + markStatusToUpdate(ecIns); + } + } + }, ecIns); + ecModel && ecModel.eachComponent(condition, function (model) { + var isExcluded = excludeSeriesIdMap && excludeSeriesIdMap.get(model.id) != null; + + if (isExcluded) { + return; + } + + callView(ecIns[mainType === 'series' ? '_chartsMap' : '_componentsMap'][model.__viewId]); + }, ecIns); + + function callView(view) { + view && view.__alive && view[method] && view[method](view.__model, ecModel, ecIns._api, payload); + } + }; + + updateMethods = { + prepareAndUpdate: function (payload) { + prepare(this); + updateMethods.update.call(this, payload, payload && { + // Needs to mark option changed if newOption is given. + // It's from MagicType. + // TODO If use a separate flag optionChanged in payload? + optionChanged: payload.newOption != null + }); + }, + update: function (payload, updateParams) { + var ecModel = this._model; + var api = this._api; + var zr = this._zr; + var coordSysMgr = this._coordSysMgr; + var scheduler = this._scheduler; // update before setOption + + if (!ecModel) { + return; + } + + ecModel.setUpdatePayload(payload); + scheduler.restoreData(ecModel, payload); + scheduler.performSeriesTasks(ecModel); // TODO + // Save total ecModel here for undo/redo (after restoring data and before processing data). + // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call. + // Create new coordinate system each update + // In LineView may save the old coordinate system and use it to get the original point. + + coordSysMgr.create(ecModel, api); + scheduler.performDataProcessorTasks(ecModel, payload); // Current stream render is not supported in data process. So we can update + // stream modes after data processing, where the filtered data is used to + // determine whether to use progressive rendering. + + updateStreamModes(this, ecModel); // We update stream modes before coordinate system updated, then the modes info + // can be fetched when coord sys updating (consider the barGrid extent fix). But + // the drawback is the full coord info can not be fetched. Fortunately this full + // coord is not required in stream mode updater currently. + + coordSysMgr.update(ecModel, api); + clearColorPalette(ecModel); + scheduler.performVisualTasks(ecModel, payload); // Set background and dark mode before rendering, because they affect auto-color-determination + // in zrender Text, and consequently affect the bounding rect if stroke is added. + + var backgroundColor = ecModel.get('backgroundColor') || 'transparent'; + zr.setBackgroundColor(backgroundColor); // Force set dark mode. + + var darkMode = ecModel.get('darkMode'); + + if (darkMode != null && darkMode !== 'auto') { + zr.setDarkMode(darkMode); + } + + render(this, ecModel, api, payload, updateParams); + lifecycle.trigger('afterupdate', ecModel, api); + }, + updateTransform: function (payload) { + var _this = this; + + var ecModel = this._model; + var api = this._api; // update before setOption + + if (!ecModel) { + return; + } + + ecModel.setUpdatePayload(payload); // ChartView.markUpdateMethod(payload, 'updateTransform'); + + var componentDirtyList = []; + ecModel.eachComponent(function (componentType, componentModel) { + if (componentType === 'series') { + return; + } + + var componentView = _this.getViewOfComponentModel(componentModel); + + if (componentView && componentView.__alive) { + if (componentView.updateTransform) { + var result = componentView.updateTransform(componentModel, ecModel, api, payload); + result && result.update && componentDirtyList.push(componentView); + } else { + componentDirtyList.push(componentView); + } + } + }); + var seriesDirtyMap = createHashMap(); + ecModel.eachSeries(function (seriesModel) { + var chartView = _this._chartsMap[seriesModel.__viewId]; + + if (chartView.updateTransform) { + var result = chartView.updateTransform(seriesModel, ecModel, api, payload); + result && result.update && seriesDirtyMap.set(seriesModel.uid, 1); + } else { + seriesDirtyMap.set(seriesModel.uid, 1); + } + }); + clearColorPalette(ecModel); // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline. + // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true); + + this._scheduler.performVisualTasks(ecModel, payload, { + setDirty: true, + dirtyMap: seriesDirtyMap + }); // Currently, not call render of components. Geo render cost a lot. + // renderComponents(ecIns, ecModel, api, payload, componentDirtyList); + + + renderSeries(this, ecModel, api, payload, {}, seriesDirtyMap); + lifecycle.trigger('afterupdate', ecModel, api); + }, + updateView: function (payload) { + var ecModel = this._model; // update before setOption + + if (!ecModel) { + return; + } + + ecModel.setUpdatePayload(payload); + ChartView.markUpdateMethod(payload, 'updateView'); + clearColorPalette(ecModel); // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline. + + this._scheduler.performVisualTasks(ecModel, payload, { + setDirty: true + }); + + render(this, ecModel, this._api, payload, {}); + lifecycle.trigger('afterupdate', ecModel, this._api); + }, + updateVisual: function (payload) { + // updateMethods.update.call(this, payload); + var _this = this; + + var ecModel = this._model; // update before setOption + + if (!ecModel) { + return; + } + + ecModel.setUpdatePayload(payload); // clear all visual + + ecModel.eachSeries(function (seriesModel) { + seriesModel.getData().clearAllVisual(); + }); // Perform visual + + ChartView.markUpdateMethod(payload, 'updateVisual'); + clearColorPalette(ecModel); // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline. + + this._scheduler.performVisualTasks(ecModel, payload, { + visualType: 'visual', + setDirty: true + }); + + ecModel.eachComponent(function (componentType, componentModel) { + if (componentType !== 'series') { + var componentView = _this.getViewOfComponentModel(componentModel); + + componentView && componentView.__alive && componentView.updateVisual(componentModel, ecModel, _this._api, payload); + } + }); + ecModel.eachSeries(function (seriesModel) { + var chartView = _this._chartsMap[seriesModel.__viewId]; + chartView.updateVisual(seriesModel, ecModel, _this._api, payload); + }); + lifecycle.trigger('afterupdate', ecModel, this._api); + }, + updateLayout: function (payload) { + updateMethods.update.call(this, payload); + } + }; + + function doConvertPixelImpl(ecIns, methodName, finder, value, opt) { + if (ecIns._disposed) { + disposedWarning(ecIns.id); + return; + } + + var ecModel = ecIns._model; + + var coordSysList = ecIns._coordSysMgr.getCoordinateSystems(); + + var result; + var parsedFinder = parseFinder(ecModel, finder); + + for (var i = 0; i < coordSysList.length; i++) { + var coordSys = coordSysList[i]; + + if (coordSys[methodName] && (result = coordSys[methodName](ecModel, parsedFinder, value, opt)) != null) { + return result; + } + } + + { + warn('No coordinate system that supports ' + methodName + ' found by the given finder.'); + } + } + + doConvertPixel = doConvertPixelImpl; + + updateStreamModes = function (ecIns, ecModel) { + var chartsMap = ecIns._chartsMap; + var scheduler = ecIns._scheduler; + ecModel.eachSeries(function (seriesModel) { + scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]); + }); + }; + + doDispatchAction = function (payload, silent) { + var _this = this; + + var ecModel = this.getModel(); + var payloadType = payload.type; + var escapeConnect = payload.escapeConnect; + var actionInfo = actions[payloadType]; + var cptTypeTmp = (actionInfo.update || 'update').split(':'); + var updateMethod = cptTypeTmp.pop(); + var cptType = cptTypeTmp[0] != null && parseClassType(cptTypeTmp[0]); + this[IN_MAIN_PROCESS_KEY] = true; + updateMainProcessVersion(this); + var payloads = [payload]; + var batched = false; // Batch action + + if (payload.batch) { + batched = true; + payloads = map$1(payload.batch, function (item) { + item = defaults(extend({}, item), payload); + item.batch = null; + return item; + }); + } + + var eventObjBatch = []; + var eventObj; + var actionResultBatch = []; + var nonRefinedEventType = actionInfo.nonRefinedEventType; + var isSelectChange = isSelectChangePayload(payload); + var isHighDown = isHighDownPayload(payload); // Only leave blur once if there are multiple batches. + + if (isHighDown) { + allLeaveBlur(this._api); + } + + each$4(payloads, function (batchItem) { + // Action can specify the event by return it. + var actionResult = actionInfo.action(batchItem, ecModel, _this._api); + + if (actionInfo.refineEvent) { + actionResultBatch.push(actionResult); + } else { + eventObj = actionResult; + } + + eventObj = eventObj || extend({}, batchItem); + eventObj.type = nonRefinedEventType; + eventObjBatch.push(eventObj); // light update does not perform data process, layout and visual. + + if (isHighDown) { + var _a = preParseFinder(payload), + queryOptionMap = _a.queryOptionMap, + mainTypeSpecified = _a.mainTypeSpecified; + + var componentMainType = mainTypeSpecified ? queryOptionMap.keys()[0] : 'series'; + updateDirectly(_this, updateMethod, batchItem, componentMainType); + markStatusToUpdate(_this); + } else if (isSelectChange) { + // At present `dispatchAction({ type: 'select', ... })` is not supported on components. + // geo still use 'geoselect'. + updateDirectly(_this, updateMethod, batchItem, 'series'); + markStatusToUpdate(_this); + } else if (cptType) { + updateDirectly(_this, updateMethod, batchItem, cptType.main, cptType.sub); + } + }); + + if (updateMethod !== 'none' && !isHighDown && !isSelectChange && !cptType) { + try { + // Still dirty + if (this[PENDING_UPDATE]) { + prepare(this); + updateMethods.update.call(this, payload); + this[PENDING_UPDATE] = null; + } else { + updateMethods[updateMethod].call(this, payload); + } + } catch (e) { + this[IN_MAIN_PROCESS_KEY] = false; + throw e; + } + } // Follow the rule of action batch + + + if (batched) { + eventObj = { + type: nonRefinedEventType, + escapeConnect: escapeConnect, + batch: eventObjBatch + }; + } else { + eventObj = eventObjBatch[0]; + } + + this[IN_MAIN_PROCESS_KEY] = false; + + if (!silent) { + var refinedEvent = void 0; + + if (actionInfo.refineEvent) { + var eventContent = actionInfo.refineEvent(actionResultBatch, payload, ecModel, this._api).eventContent; + assert(isObject$2(eventContent)); + refinedEvent = defaults({ + type: actionInfo.refinedEventType + }, eventContent); + refinedEvent.fromAction = payload.type; + refinedEvent.fromActionPayload = payload; + refinedEvent.escapeConnect = true; + } + + var messageCenter = this._messageCenter; // - If `refineEvent` created a `refinedEvent`, `eventObj` (replicated from the original payload) + // is still needed to be triggered for the feature `connect`. But it will not be triggered to + // users in this case. + // - If no `refineEvent` used, `eventObj` will be triggered for both `connect` and users. + + messageCenter.trigger(eventObj.type, eventObj); + + if (refinedEvent) { + messageCenter.trigger(refinedEvent.type, refinedEvent); + } + } + }; + + flushPendingActions = function (silent) { + var pendingActions = this._pendingActions; + + while (pendingActions.length) { + var payload = pendingActions.shift(); + doDispatchAction.call(this, payload, silent); + } + }; + + triggerUpdatedEvent = function (silent) { + !silent && this.trigger('updated'); + }; + /** + * Event `rendered` is triggered when zr + * rendered. It is useful for realtime + * snapshot (reflect animation). + * + * Event `finished` is triggered when: + * (1) zrender rendering finished. + * (2) initial animation finished. + * (3) progressive rendering finished. + * (4) no pending action. + * (5) no delayed setOption needs to be processed. + */ + + + bindRenderedEvent = function (zr, ecIns) { + zr.on('rendered', function (params) { + ecIns.trigger('rendered', params); // The `finished` event should not be triggered repeatedly, + // so it should only be triggered when rendering indeed happens + // in zrender. (Consider the case that dipatchAction is keep + // triggering when mouse move). + + if ( // Although zr is dirty if initial animation is not finished + // and this checking is called on frame, we also check + // animation finished for robustness. + zr.animation.isFinished() && !ecIns[PENDING_UPDATE] && !ecIns._scheduler.unfinished && !ecIns._pendingActions.length) { + ecIns.trigger('finished'); + } + }); + }; + + bindMouseEvent = function (zr, ecIns) { + zr.on('mouseover', function (e) { + var el = e.target; + var dispatcher = findEventDispatcher(el, isHighDownDispatcher); + + if (dispatcher) { + handleGlobalMouseOverForHighDown(dispatcher, e, ecIns._api); + markStatusToUpdate(ecIns); + } + }).on('mouseout', function (e) { + var el = e.target; + var dispatcher = findEventDispatcher(el, isHighDownDispatcher); + + if (dispatcher) { + handleGlobalMouseOutForHighDown(dispatcher, e, ecIns._api); + markStatusToUpdate(ecIns); + } + }).on('click', function (e) { + var el = e.target; + var dispatcher = findEventDispatcher(el, function (target) { + return getECData(target).dataIndex != null; + }, true); + + if (dispatcher) { + var actionType = dispatcher.selected ? 'unselect' : 'select'; + var ecData = getECData(dispatcher); + + ecIns._api.dispatchAction({ + type: actionType, + dataType: ecData.dataType, + dataIndexInside: ecData.dataIndex, + seriesIndex: ecData.seriesIndex, + isFromClick: true + }); + } + }); + }; + + function clearColorPalette(ecModel) { + ecModel.clearColorPalette(); + ecModel.eachSeries(function (seriesModel) { + seriesModel.clearColorPalette(); + }); + } // Allocate zlevels for series and components + + + function allocateZlevels(ecModel) { + var componentZLevels = []; + var seriesZLevels = []; + var hasSeparateZLevel = false; + ecModel.eachComponent(function (componentType, componentModel) { + var zlevel = componentModel.get('zlevel') || 0; + var z = componentModel.get('z') || 0; + var zlevelKey = componentModel.getZLevelKey(); + hasSeparateZLevel = hasSeparateZLevel || !!zlevelKey; + (componentType === 'series' ? seriesZLevels : componentZLevels).push({ + zlevel: zlevel, + z: z, + idx: componentModel.componentIndex, + type: componentType, + key: zlevelKey + }); + }); + + if (hasSeparateZLevel) { + // Series after component + var zLevels = componentZLevels.concat(seriesZLevels); + var lastSeriesZLevel_1; + var lastSeriesKey_1; + sort(zLevels, function (a, b) { + if (a.zlevel === b.zlevel) { + return a.z - b.z; + } + + return a.zlevel - b.zlevel; + }); + each$4(zLevels, function (item) { + var componentModel = ecModel.getComponent(item.type, item.idx); + var zlevel = item.zlevel; + var key = item.key; + + if (lastSeriesZLevel_1 != null) { + zlevel = Math.max(lastSeriesZLevel_1, zlevel); + } + + if (key) { + if (zlevel === lastSeriesZLevel_1 && key !== lastSeriesKey_1) { + zlevel++; + } + + lastSeriesKey_1 = key; + } else if (lastSeriesKey_1) { + if (zlevel === lastSeriesZLevel_1) { + zlevel++; + } + + lastSeriesKey_1 = ''; + } + + lastSeriesZLevel_1 = zlevel; + componentModel.setZLevel(zlevel); + }); + } + } + + render = function (ecIns, ecModel, api, payload, updateParams) { + allocateZlevels(ecModel); + renderComponents(ecIns, ecModel, api, payload, updateParams); + each$4(ecIns._chartsViews, function (chart) { + chart.__alive = false; + }); + renderSeries(ecIns, ecModel, api, payload, updateParams); // Remove groups of unrendered charts + + each$4(ecIns._chartsViews, function (chart) { + if (!chart.__alive) { + chart.remove(ecModel, api); + } + }); + }; + + renderComponents = function (ecIns, ecModel, api, payload, updateParams, dirtyList) { + each$4(dirtyList || ecIns._componentsViews, function (componentView) { + var componentModel = componentView.__model; + clearStates(componentModel, componentView); + componentView.render(componentModel, ecModel, api, payload); + updateZ(componentModel, componentView); + updateStates(componentModel, componentView); + }); + }; + /** + * Render each chart and component + */ + + + renderSeries = function (ecIns, ecModel, api, payload, updateParams, dirtyMap) { + // Render all charts + var scheduler = ecIns._scheduler; + updateParams = extend(updateParams || {}, { + updatedSeries: ecModel.getSeries() + }); // TODO progressive? + + lifecycle.trigger('series:beforeupdate', ecModel, api, updateParams); + var unfinished = false; + ecModel.eachSeries(function (seriesModel) { + var chartView = ecIns._chartsMap[seriesModel.__viewId]; + chartView.__alive = true; + var renderTask = chartView.renderTask; + scheduler.updatePayload(renderTask, payload); // TODO states on marker. + + clearStates(seriesModel, chartView); + + if (dirtyMap && dirtyMap.get(seriesModel.uid)) { + renderTask.dirty(); + } + + if (renderTask.perform(scheduler.getPerformArgs(renderTask))) { + unfinished = true; + } + + chartView.group.silent = !!seriesModel.get('silent'); // Should not call markRedraw on group, because it will disable zrender + // incremental render (always render from the __startIndex each frame) + // chartView.group.markRedraw(); + + updateBlend(seriesModel, chartView); + updateSeriesElementSelection(seriesModel); + }); + scheduler.unfinished = unfinished || scheduler.unfinished; + lifecycle.trigger('series:layoutlabels', ecModel, api, updateParams); // transition after label is layouted. + + lifecycle.trigger('series:transition', ecModel, api, updateParams); + ecModel.eachSeries(function (seriesModel) { + var chartView = ecIns._chartsMap[seriesModel.__viewId]; // Update Z after labels updated. Before applying states. + + updateZ(seriesModel, chartView); // NOTE: Update states after label is updated. + // label should be in normal status when layouting. + + updateStates(seriesModel, chartView); + }); // If use hover layer + + updateHoverLayerStatus(ecIns, ecModel); + lifecycle.trigger('series:afterupdate', ecModel, api, updateParams); + }; + + markStatusToUpdate = function (ecIns) { + ecIns[STATUS_NEEDS_UPDATE_KEY] = true; // Wake up zrender if it's sleep. Let it update states in the next frame. + + ecIns.getZr().wakeUp(); + }; + + updateMainProcessVersion = function (ecIns) { + ecIns[MAIN_PROCESS_VERSION_KEY] = (ecIns[MAIN_PROCESS_VERSION_KEY] + 1) % 1000; + }; + + applyChangedStates = function (ecIns) { + if (!ecIns[STATUS_NEEDS_UPDATE_KEY]) { + return; + } + + ecIns.getZr().storage.traverse(function (el) { + // Not applied on removed elements, it may still in fading. + if (isElementRemoved(el)) { + return; + } + + applyElementStates(el); + }); + ecIns[STATUS_NEEDS_UPDATE_KEY] = false; + }; + + function applyElementStates(el) { + var newStates = []; + var oldStates = el.currentStates; // Keep other states. + + for (var i = 0; i < oldStates.length; i++) { + var stateName = oldStates[i]; + + if (!(stateName === 'emphasis' || stateName === 'blur' || stateName === 'select')) { + newStates.push(stateName); + } + } // Only use states when it's exists. + + + if (el.selected && el.states.select) { + newStates.push('select'); + } + + if (el.hoverState === HOVER_STATE_EMPHASIS && el.states.emphasis) { + newStates.push('emphasis'); + } else if (el.hoverState === HOVER_STATE_BLUR && el.states.blur) { + newStates.push('blur'); + } + + el.useStates(newStates); + } + + function updateHoverLayerStatus(ecIns, ecModel) { + var zr = ecIns._zr; + var storage = zr.storage; + var elCount = 0; + storage.traverse(function (el) { + if (!el.isGroup) { + elCount++; + } + }); + + if (elCount > ecModel.get('hoverLayerThreshold') && !env.node && !env.worker) { + ecModel.eachSeries(function (seriesModel) { + if (seriesModel.preventUsingHoverLayer) { + return; + } + + var chartView = ecIns._chartsMap[seriesModel.__viewId]; + + if (chartView.__alive) { + chartView.eachRendered(function (el) { + if (el.states.emphasis) { + el.states.emphasis.hoverLayer = true; + } + }); + } + }); + } + } + /** + * Update chart and blend. + */ + + + function updateBlend(seriesModel, chartView) { + var blendMode = seriesModel.get('blendMode') || null; + chartView.eachRendered(function (el) { + // FIXME marker and other components + if (!el.isGroup) { + // DON'T mark the element dirty. In case element is incremental and don't want to rerender. + el.style.blend = blendMode; + } + }); + } + + function updateZ(model, view) { + if (model.preventAutoZ) { + return; + } + + var zInfo = retrieveZInfo(model); // Set z and zlevel + + view.eachRendered(function (el) { + traverseUpdateZ(el, zInfo.z, zInfo.zlevel); // Don't traverse the children because it has been traversed in _updateZ. + + return true; + }); + } // Clear states without animation. + // TODO States on component. + + + function clearStates(model, view) { + view.eachRendered(function (el) { + // Not applied on removed elements, it may still in fading. + if (isElementRemoved(el)) { + return; + } + + var textContent = el.getTextContent(); + var textGuide = el.getTextGuideLine(); + + if (el.stateTransition) { + el.stateTransition = null; + } + + if (textContent && textContent.stateTransition) { + textContent.stateTransition = null; + } + + if (textGuide && textGuide.stateTransition) { + textGuide.stateTransition = null; + } // TODO If el is incremental. + + + if (el.hasState()) { + el.prevStates = el.currentStates; + el.clearStates(); + } else if (el.prevStates) { + el.prevStates = null; + } + }); + } + + function updateStates(model, view) { + var stateAnimationModel = model.getModel('stateAnimation'); + var enableAnimation = model.isAnimationEnabled(); + var duration = stateAnimationModel.get('duration'); + var stateTransition = duration > 0 ? { + duration: duration, + delay: stateAnimationModel.get('delay'), + easing: stateAnimationModel.get('easing') // additive: stateAnimationModel.get('additive') + + } : null; + view.eachRendered(function (el) { + if (el.states && el.states.emphasis) { + // Not applied on removed elements, it may still in fading. + if (isElementRemoved(el)) { + return; + } + + if (el instanceof Path) { + savePathStates(el); + } // Only updated on changed element. In case element is incremental and don't want to rerender. + // TODO, a more proper way? + + + if (el.__dirty) { + var prevStates = el.prevStates; // Restore states without animation + + if (prevStates) { + el.useStates(prevStates); + } + } // Update state transition and enable animation again. + + + if (enableAnimation) { + el.stateTransition = stateTransition; + var textContent = el.getTextContent(); + var textGuide = el.getTextGuideLine(); // TODO Is it necessary to animate label? + + if (textContent) { + textContent.stateTransition = stateTransition; + } + + if (textGuide) { + textGuide.stateTransition = stateTransition; + } + } // Use highlighted and selected flag to toggle states. + + + if (el.__dirty) { + applyElementStates(el); + } + } + }); + } + + createExtensionAPI = function (ecIns) { + return new ( + /** @class */ + function (_super) { + __extends(class_1, _super); + + function class_1() { + return _super !== null && _super.apply(this, arguments) || this; + } + + class_1.prototype.getCoordinateSystems = function () { + return ecIns._coordSysMgr.getCoordinateSystems(); + }; + + class_1.prototype.getComponentByElement = function (el) { + while (el) { + var modelInfo = el.__ecComponentInfo; + + if (modelInfo != null) { + return ecIns._model.getComponent(modelInfo.mainType, modelInfo.index); + } + + el = el.parent; + } + }; + + class_1.prototype.enterEmphasis = function (el, highlightDigit) { + enterEmphasis(el, highlightDigit); + markStatusToUpdate(ecIns); + }; + + class_1.prototype.leaveEmphasis = function (el, highlightDigit) { + leaveEmphasis(el, highlightDigit); + markStatusToUpdate(ecIns); + }; + + class_1.prototype.enterBlur = function (el) { + enterBlur(el); + markStatusToUpdate(ecIns); + }; + + class_1.prototype.leaveBlur = function (el) { + leaveBlur(el); + markStatusToUpdate(ecIns); + }; + + class_1.prototype.enterSelect = function (el) { + enterSelect(el); + markStatusToUpdate(ecIns); + }; + + class_1.prototype.leaveSelect = function (el) { + leaveSelect(el); + markStatusToUpdate(ecIns); + }; + + class_1.prototype.getModel = function () { + return ecIns.getModel(); + }; + + class_1.prototype.getViewOfComponentModel = function (componentModel) { + return ecIns.getViewOfComponentModel(componentModel); + }; + + class_1.prototype.getViewOfSeriesModel = function (seriesModel) { + return ecIns.getViewOfSeriesModel(seriesModel); + }; + + class_1.prototype.getMainProcessVersion = function () { + return ecIns[MAIN_PROCESS_VERSION_KEY]; + }; + + return class_1; + }(ExtensionAPI))(ecIns); + }; + + enableConnect = function (chart) { + function updateConnectedChartsStatus(charts, status) { + for (var i = 0; i < charts.length; i++) { + var otherChart = charts[i]; + otherChart[CONNECT_STATUS_KEY] = status; + } + } + + each$4(connectionEventRevertMap, function (_, eventType) { + chart._messageCenter.on(eventType, function (event) { + if (connectedGroups[chart.group] && chart[CONNECT_STATUS_KEY] !== CONNECT_STATUS_PENDING) { + if (event && event.escapeConnect) { + return; + } + + var action_1 = chart.makeActionFromEvent(event); + var otherCharts_1 = []; + each$4(instances, function (otherChart) { + if (otherChart !== chart && otherChart.group === chart.group) { + otherCharts_1.push(otherChart); + } + }); + updateConnectedChartsStatus(otherCharts_1, CONNECT_STATUS_PENDING); + each$4(otherCharts_1, function (otherChart) { + if (otherChart[CONNECT_STATUS_KEY] !== CONNECT_STATUS_UPDATING) { + otherChart.dispatchAction(action_1); + } + }); + updateConnectedChartsStatus(otherCharts_1, CONNECT_STATUS_UPDATED); + } + }); + }); + }; + }(); + + return ECharts; + }(Eventful); + + var echartsProto = ECharts.prototype; + echartsProto.on = createRegisterEventWithLowercaseECharts('on'); + echartsProto.off = createRegisterEventWithLowercaseECharts('off'); + /** + * @deprecated + */ + // @ts-ignore + + echartsProto.one = function (eventName, cb, ctx) { + var self = this; + deprecateLog('ECharts#one is deprecated.'); + + function wrapped() { + var args2 = []; + + for (var _i = 0; _i < arguments.length; _i++) { + args2[_i] = arguments[_i]; + } + + cb && cb.apply && cb.apply(this, args2); // @ts-ignore + + self.off(eventName, wrapped); + } // @ts-ignore + + + this.on.call(this, eventName, wrapped, ctx); + }; + + var MOUSE_EVENT_NAMES = ['click', 'dblclick', 'mouseover', 'mouseout', 'mousemove', 'mousedown', 'mouseup', 'globalout', 'contextmenu']; + + function disposedWarning(id) { + { + warn('Instance ' + id + ' has been disposed'); + } + } + + var actions = {}; + /** + * Map event type to action type for reproducing action from event for `connect`. + */ + + var connectionEventRevertMap = {}; + /** + * To remove duplication. + */ + + var publicEventTypeMap = {}; + var dataProcessorFuncs = []; + var optionPreprocessorFuncs = []; + var visualFuncs = []; + var themeStorage = {}; + var loadingEffects = {}; + var instances = {}; + var connectedGroups = {}; + var idBase = +new Date() - 0; + var groupIdBase = +new Date() - 0; + var DOM_ATTRIBUTE_KEY = '_echarts_instance_'; + /** + * @param opts.devicePixelRatio Use window.devicePixelRatio by default + * @param opts.renderer Can choose 'canvas' or 'svg' to render the chart. + * @param opts.width Use clientWidth of the input `dom` by default. + * Can be 'auto' (the same as null/undefined) + * @param opts.height Use clientHeight of the input `dom` by default. + * Can be 'auto' (the same as null/undefined) + * @param opts.locale Specify the locale. + * @param opts.useDirtyRect Enable dirty rectangle rendering or not. + */ + + function init(dom, theme, opts) { + var isClient = !(opts && opts.ssr); + + if (isClient) { + { + if (!dom) { + throw new Error('Initialize failed: invalid dom.'); + } + } + var existInstance = getInstanceByDom(dom); + + if (existInstance) { + { + warn('There is a chart instance already initialized on the dom.'); + } + return existInstance; + } + + { + if (isDom(dom) && dom.nodeName.toUpperCase() !== 'CANVAS' && (!dom.clientWidth && (!opts || opts.width == null) || !dom.clientHeight && (!opts || opts.height == null))) { + warn('Can\'t get DOM width or height. Please check ' + 'dom.clientWidth and dom.clientHeight. They should not be 0.' + 'For example, you may need to call this in the callback ' + 'of window.onload.'); + } + } + } + + var chart = new ECharts(dom, theme, opts); + chart.id = 'ec_' + idBase++; + instances[chart.id] = chart; + isClient && setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id); + enableConnect(chart); + lifecycle.trigger('afterinit', chart); + return chart; + } + /** + * @usage + * (A) + * ```js + * let chart1 = echarts.init(dom1); + * let chart2 = echarts.init(dom2); + * chart1.group = 'xxx'; + * chart2.group = 'xxx'; + * echarts.connect('xxx'); + * ``` + * (B) + * ```js + * let chart1 = echarts.init(dom1); + * let chart2 = echarts.init(dom2); + * echarts.connect('xxx', [chart1, chart2]); + * ``` + */ + + + function connect(groupId) { + // Is array of charts + if (isArray(groupId)) { + var charts = groupId; + groupId = null; // If any chart has group + + each$4(charts, function (chart) { + if (chart.group != null) { + groupId = chart.group; + } + }); + groupId = groupId || 'g_' + groupIdBase++; + each$4(charts, function (chart) { + chart.group = groupId; + }); + } + + connectedGroups[groupId] = true; + return groupId; + } + + function disconnect(groupId) { + connectedGroups[groupId] = false; + } + /** + * Alias and backward compatibility + * @deprecated + */ + + + var disConnect = disconnect; + /** + * Dispose a chart instance + */ + + function dispose(chart) { + if (isString(chart)) { + chart = instances[chart]; + } else if (!(chart instanceof ECharts)) { + // Try to treat as dom + chart = getInstanceByDom(chart); + } + + if (chart instanceof ECharts && !chart.isDisposed()) { + chart.dispose(); + } + } + + function getInstanceByDom(dom) { + return instances[getAttribute(dom, DOM_ATTRIBUTE_KEY)]; + } + + function getInstanceById(key) { + return instances[key]; + } + /** + * Register theme + */ + + + function registerTheme(name, theme) { + themeStorage[name] = theme; + } + /** + * Register option preprocessor + */ + + + function registerPreprocessor(preprocessorFunc) { + if (indexOf(optionPreprocessorFuncs, preprocessorFunc) < 0) { + optionPreprocessorFuncs.push(preprocessorFunc); + } + } + + function registerProcessor(priority, processor) { + normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_DEFAULT); + } + /** + * Register postIniter + * @param {Function} postInitFunc + */ + + + function registerPostInit(postInitFunc) { + registerUpdateLifecycle('afterinit', postInitFunc); + } + /** + * Register postUpdater + * @param {Function} postUpdateFunc + */ + + + function registerPostUpdate(postUpdateFunc) { + registerUpdateLifecycle('afterupdate', postUpdateFunc); + } + + function registerUpdateLifecycle(name, cb) { + lifecycle.on(name, cb); + } + + function registerAction(arg0, arg1, action) { + var actionType; + var publicEventType; + var refineEvent; + var update; + var publishNonRefinedEvent; + + if (isFunction(arg1)) { + action = arg1; + arg1 = ''; + } + + if (isObject$2(arg0)) { + actionType = arg0.type; + publicEventType = arg0.event; + update = arg0.update; + publishNonRefinedEvent = arg0.publishNonRefinedEvent; + + if (!action) { + action = arg0.action; + } + + refineEvent = arg0.refineEvent; + } else { + actionType = arg0; + publicEventType = arg1; + } + + function createEventType(actionOrEventType) { + // Event type should be all lowercase + return actionOrEventType.toLowerCase(); + } + + publicEventType = createEventType(publicEventType || actionType); // See comments on {ActionInfo} for the reason. + + var nonRefinedEventType = refineEvent ? createEventType(actionType) : publicEventType; // Support calling `registerAction` multiple times with the same action + // type; subsequent calls have no effect. + + if (actions[actionType]) { + return; + } // Validate action type and event name. + + + assert(ACTION_REG.test(actionType) && ACTION_REG.test(publicEventType)); + + if (refineEvent) { + // An event replicated from the action will be triggered internally for `connect` in this case. + assert(publicEventType !== actionType); + } + + actions[actionType] = { + actionType: actionType, + refinedEventType: publicEventType, + nonRefinedEventType: nonRefinedEventType, + update: update, + action: action, + refineEvent: refineEvent + }; + publicEventTypeMap[publicEventType] = 1; + + if (refineEvent && publishNonRefinedEvent) { + publicEventTypeMap[nonRefinedEventType] = 1; + } + + if (connectionEventRevertMap[nonRefinedEventType]) { + error(nonRefinedEventType + " must not be shared; use \"refineEvent\" if you intend to share an event name."); + } + + connectionEventRevertMap[nonRefinedEventType] = actionType; + } + + function registerCoordinateSystem(type, coordSysCreator) { + CoordinateSystemManager.register(type, coordSysCreator); + } + /** + * Get dimensions of specified coordinate system. + * @param {string} type + * @return {Array.} + */ + + + function getCoordinateSystemDimensions(type) { + var coordSysCreator = CoordinateSystemManager.get(type); + + if (coordSysCreator) { + return coordSysCreator.getDimensionsInfo ? coordSysCreator.getDimensionsInfo() : coordSysCreator.dimensions.slice(); + } + } + + function registerCustomSeries(seriesType, renderItem) {} + + function registerLayout(priority, layoutTask) { + normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout'); + } + + function registerVisual(priority, visualTask) { + normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual'); + } + + var registeredTasks = []; + + function normalizeRegister(targetList, priority, fn, defaultPriority, visualType) { + if (isFunction(priority) || isObject$2(priority)) { + fn = priority; + priority = defaultPriority; + } + + { + if (isNaN(priority) || priority == null) { + throw new Error('Illegal priority'); + } // Check duplicate + + + each$4(targetList, function (wrap) { + assert(wrap.__raw !== fn); + }); + } // Already registered + + if (indexOf(registeredTasks, fn) >= 0) { + return; + } + + registeredTasks.push(fn); + var stageHandler = Scheduler.wrapStageHandler(fn, visualType); + stageHandler.__prio = priority; + stageHandler.__raw = fn; + targetList.push(stageHandler); + } + + function registerLoading(name, loadingFx) { + loadingEffects[name] = loadingFx; + } + /** + * ZRender need a canvas context to do measureText. + * But in node environment canvas may be created by node-canvas. + * So we need to specify how to create a canvas instead of using document.createElement('canvas') + * + * + * @deprecated use setPlatformAPI({ createCanvas }) instead. + * + * @example + * let Canvas = require('canvas'); + * let echarts = require('echarts'); + * echarts.setCanvasCreator(function () { + * // Small size is enough. + * return new Canvas(32, 32); + * }); + */ + + + function setCanvasCreator(creator) { + { + deprecateLog('setCanvasCreator is deprecated. Use setPlatformAPI({ createCanvas }) instead.'); + } + setPlatformAPI({ + createCanvas: creator + }); + } + /** + * The parameters and usage: see `geoSourceManager.registerMap`. + * Compatible with previous `echarts.registerMap`. + */ + + + function registerMap(mapName, geoJson, specialAreas) { + var registerMap = getImpl('registerMap'); + registerMap && registerMap(mapName, geoJson, specialAreas); + } + + function getMap(mapName) { + var getMap = getImpl('getMap'); + return getMap && getMap(mapName); + } + + var registerTransform = registerExternalTransform; + /** + * Globa dispatchAction to a specified chart instance. + */ + // export function dispatchAction(payload: { chartId: string } & Payload, opt?: Parameters[1]) { + // if (!payload || !payload.chartId) { + // // Must have chartId to find chart + // return; + // } + // const chart = instances[payload.chartId]; + // if (chart) { + // chart.dispatchAction(payload, opt); + // } + // } + // Builtin global visual + + registerVisual(PRIORITY_VISUAL_GLOBAL, seriesStyleTask); + registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataStyleTask); + registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataColorPaletteTask); + registerVisual(PRIORITY_VISUAL_GLOBAL, seriesSymbolTask); + registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataSymbolTask); + registerVisual(PRIORITY_VISUAL_DECAL, decalVisual); + registerPreprocessor(globalBackwardCompat); + registerProcessor(PRIORITY_PROCESSOR_DATASTACK, dataStack$1); + registerLoading('default', defaultLoading); // Default actions + + registerAction({ + type: HIGHLIGHT_ACTION_TYPE, + event: HIGHLIGHT_ACTION_TYPE, + update: HIGHLIGHT_ACTION_TYPE + }, noop); + registerAction({ + type: DOWNPLAY_ACTION_TYPE, + event: DOWNPLAY_ACTION_TYPE, + update: DOWNPLAY_ACTION_TYPE + }, noop); + registerAction({ + type: SELECT_ACTION_TYPE, + event: SELECT_CHANGED_EVENT_TYPE, + update: SELECT_ACTION_TYPE, + action: noop, + refineEvent: makeSelectChangedEvent, + publishNonRefinedEvent: true + }); + registerAction({ + type: UNSELECT_ACTION_TYPE, + event: SELECT_CHANGED_EVENT_TYPE, + update: UNSELECT_ACTION_TYPE, + action: noop, + refineEvent: makeSelectChangedEvent, + publishNonRefinedEvent: true + }); + registerAction({ + type: TOGGLE_SELECT_ACTION_TYPE, + event: SELECT_CHANGED_EVENT_TYPE, + update: TOGGLE_SELECT_ACTION_TYPE, + action: noop, + refineEvent: makeSelectChangedEvent, + publishNonRefinedEvent: true + }); + + function makeSelectChangedEvent(actionResultBatch, payload, ecModel, api) { + return { + eventContent: { + selected: getAllSelectedIndices(ecModel), + isFromClick: payload.isFromClick || false + } + }; + } // Default theme, so that we can use `chart.setTheme('default')` to revert to + // the default theme after changing to other themes. + + + registerTheme('default', {}); + registerTheme('dark', theme); // For backward compatibility, where the namespace `dataTool` will + // be mounted on `echarts` is the extension `dataTool` is imported. + + var dataTool = {}; + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + function dataIndexMapValueLength(valNumOrArrLengthMoreThan2) { + return valNumOrArrLengthMoreThan2 == null ? 0 : valNumOrArrLengthMoreThan2.length || 1; + } + + function defaultKeyGetter(item) { + return item; + } + + var DataDiffer = + /** @class */ + function () { + /** + * @param context Can be visited by this.context in callback. + */ + function DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter, context, // By default: 'oneToOne'. + diffMode) { + this._old = oldArr; + this._new = newArr; + this._oldKeyGetter = oldKeyGetter || defaultKeyGetter; + this._newKeyGetter = newKeyGetter || defaultKeyGetter; // Visible in callback via `this.context`; + + this.context = context; + this._diffModeMultiple = diffMode === 'multiple'; + } + /** + * Callback function when add a data + */ + + + DataDiffer.prototype.add = function (func) { + this._add = func; + return this; + }; + /** + * Callback function when update a data + */ + + + DataDiffer.prototype.update = function (func) { + this._update = func; + return this; + }; + /** + * Callback function when update a data and only work in `cbMode: 'byKey'`. + */ + + + DataDiffer.prototype.updateManyToOne = function (func) { + this._updateManyToOne = func; + return this; + }; + /** + * Callback function when update a data and only work in `cbMode: 'byKey'`. + */ + + + DataDiffer.prototype.updateOneToMany = function (func) { + this._updateOneToMany = func; + return this; + }; + /** + * Callback function when update a data and only work in `cbMode: 'byKey'`. + */ + + + DataDiffer.prototype.updateManyToMany = function (func) { + this._updateManyToMany = func; + return this; + }; + /** + * Callback function when remove a data + */ + + + DataDiffer.prototype.remove = function (func) { + this._remove = func; + return this; + }; + + DataDiffer.prototype.execute = function () { + this[this._diffModeMultiple ? '_executeMultiple' : '_executeOneToOne'](); + }; + + DataDiffer.prototype._executeOneToOne = function () { + var oldArr = this._old; + var newArr = this._new; + var newDataIndexMap = {}; + var oldDataKeyArr = new Array(oldArr.length); + var newDataKeyArr = new Array(newArr.length); + + this._initIndexMap(oldArr, null, oldDataKeyArr, '_oldKeyGetter'); + + this._initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter'); + + for (var i = 0; i < oldArr.length; i++) { + var oldKey = oldDataKeyArr[i]; + var newIdxMapVal = newDataIndexMap[oldKey]; + var newIdxMapValLen = dataIndexMapValueLength(newIdxMapVal); // idx can never be empty array here. see 'set null' logic below. + + if (newIdxMapValLen > 1) { + // Consider there is duplicate key (for example, use dataItem.name as key). + // We should make sure every item in newArr and oldArr can be visited. + var newIdx = newIdxMapVal.shift(); + + if (newIdxMapVal.length === 1) { + newDataIndexMap[oldKey] = newIdxMapVal[0]; + } + + this._update && this._update(newIdx, i); + } else if (newIdxMapValLen === 1) { + newDataIndexMap[oldKey] = null; + this._update && this._update(newIdxMapVal, i); + } else { + this._remove && this._remove(i); + } + } + + this._performRestAdd(newDataKeyArr, newDataIndexMap); + }; + /** + * For example, consider the case: + * oldData: [o0, o1, o2, o3, o4, o5, o6, o7], + * newData: [n0, n1, n2, n3, n4, n5, n6, n7, n8], + * Where: + * o0, o1, n0 has key 'a' (many to one) + * o5, n4, n5, n6 has key 'b' (one to many) + * o2, n1 has key 'c' (one to one) + * n2, n3 has key 'd' (add) + * o3, o4 has key 'e' (remove) + * o6, o7, n7, n8 has key 'f' (many to many, treated as add and remove) + * Then: + * (The order of the following directives are not ensured.) + * this._updateManyToOne(n0, [o0, o1]); + * this._updateOneToMany([n4, n5, n6], o5); + * this._update(n1, o2); + * this._remove(o3); + * this._remove(o4); + * this._remove(o6); + * this._remove(o7); + * this._add(n2); + * this._add(n3); + * this._add(n7); + * this._add(n8); + */ + + + DataDiffer.prototype._executeMultiple = function () { + var oldArr = this._old; + var newArr = this._new; + var oldDataIndexMap = {}; + var newDataIndexMap = {}; + var oldDataKeyArr = []; + var newDataKeyArr = []; + + this._initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter'); + + this._initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter'); + + for (var i = 0; i < oldDataKeyArr.length; i++) { + var oldKey = oldDataKeyArr[i]; + var oldIdxMapVal = oldDataIndexMap[oldKey]; + var newIdxMapVal = newDataIndexMap[oldKey]; + var oldIdxMapValLen = dataIndexMapValueLength(oldIdxMapVal); + var newIdxMapValLen = dataIndexMapValueLength(newIdxMapVal); + + if (oldIdxMapValLen > 1 && newIdxMapValLen === 1) { + this._updateManyToOne && this._updateManyToOne(newIdxMapVal, oldIdxMapVal); + newDataIndexMap[oldKey] = null; + } else if (oldIdxMapValLen === 1 && newIdxMapValLen > 1) { + this._updateOneToMany && this._updateOneToMany(newIdxMapVal, oldIdxMapVal); + newDataIndexMap[oldKey] = null; + } else if (oldIdxMapValLen === 1 && newIdxMapValLen === 1) { + this._update && this._update(newIdxMapVal, oldIdxMapVal); + newDataIndexMap[oldKey] = null; + } else if (oldIdxMapValLen > 1 && newIdxMapValLen > 1) { + this._updateManyToMany && this._updateManyToMany(newIdxMapVal, oldIdxMapVal); + newDataIndexMap[oldKey] = null; + } else if (oldIdxMapValLen > 1) { + for (var i_1 = 0; i_1 < oldIdxMapValLen; i_1++) { + this._remove && this._remove(oldIdxMapVal[i_1]); + } + } else { + this._remove && this._remove(oldIdxMapVal); + } + } + + this._performRestAdd(newDataKeyArr, newDataIndexMap); + }; + + DataDiffer.prototype._performRestAdd = function (newDataKeyArr, newDataIndexMap) { + for (var i = 0; i < newDataKeyArr.length; i++) { + var newKey = newDataKeyArr[i]; + var newIdxMapVal = newDataIndexMap[newKey]; + var idxMapValLen = dataIndexMapValueLength(newIdxMapVal); + + if (idxMapValLen > 1) { + for (var j = 0; j < idxMapValLen; j++) { + this._add && this._add(newIdxMapVal[j]); + } + } else if (idxMapValLen === 1) { + this._add && this._add(newIdxMapVal); + } // Support both `newDataKeyArr` are duplication removed or not removed. + + + newDataIndexMap[newKey] = null; + } + }; + + DataDiffer.prototype._initIndexMap = function (arr, // Can be null. + map, // In 'byKey', the output `keyArr` is duplication removed. + // In 'byIndex', the output `keyArr` is not duplication removed and + // its indices are accurately corresponding to `arr`. + keyArr, keyGetterName) { + var cbModeMultiple = this._diffModeMultiple; + + for (var i = 0; i < arr.length; i++) { + // Add prefix to avoid conflict with Object.prototype. + var key = '_ec_' + this[keyGetterName](arr[i], i); + + if (!cbModeMultiple) { + keyArr[i] = key; + } + + if (!map) { + continue; + } + + var idxMapVal = map[key]; + var idxMapValLen = dataIndexMapValueLength(idxMapVal); + + if (idxMapValLen === 0) { + // Simple optimize: in most cases, one index has one key, + // do not need array. + map[key] = i; + + if (cbModeMultiple) { + keyArr.push(key); + } + } else if (idxMapValLen === 1) { + map[key] = [idxMapVal, i]; + } else { + idxMapVal.push(i); + } + } + }; + + return DataDiffer; + }(); + + var DimensionUserOuput = + /** @class */ + function () { + function DimensionUserOuput(encode, dimRequest) { + this._encode = encode; + this._schema = dimRequest; + } + + DimensionUserOuput.prototype.get = function () { + return { + // Do not generate full dimension name until fist used. + fullDimensions: this._getFullDimensionNames(), + encode: this._encode + }; + }; + /** + * Get all data store dimension names. + * Theoretically a series data store is defined both by series and used dataset (if any). + * If some dimensions are omitted for performance reason in `this.dimensions`, + * the dimension name may not be auto-generated if user does not specify a dimension name. + * In this case, the dimension name is `null`/`undefined`. + */ + + + DimensionUserOuput.prototype._getFullDimensionNames = function () { + if (!this._cachedDimNames) { + this._cachedDimNames = this._schema ? this._schema.makeOutputDimensionNames() : []; + } + + return this._cachedDimNames; + }; + + return DimensionUserOuput; + }(); + + function summarizeDimensions(data, schema) { + var summary = {}; + var encode = summary.encode = {}; + var notExtraCoordDimMap = createHashMap(); + var defaultedLabel = []; + var defaultedTooltip = []; + var userOutputEncode = {}; + each$4(data.dimensions, function (dimName) { + var dimItem = data.getDimensionInfo(dimName); + var coordDim = dimItem.coordDim; + + if (coordDim) { + { + assert(VISUAL_DIMENSIONS.get(coordDim) == null); + } + var coordDimIndex = dimItem.coordDimIndex; + getOrCreateEncodeArr(encode, coordDim)[coordDimIndex] = dimName; + + if (!dimItem.isExtraCoord) { + notExtraCoordDimMap.set(coordDim, 1); // Use the last coord dim (and label friendly) as default label, + // because when dataset is used, it is hard to guess which dimension + // can be value dimension. If both show x, y on label is not look good, + // and conventionally y axis is focused more. + + if (mayLabelDimType(dimItem.type)) { + defaultedLabel[0] = dimName; + } // User output encode do not contain generated coords. + // And it only has index. User can use index to retrieve value from the raw item array. + + + getOrCreateEncodeArr(userOutputEncode, coordDim)[coordDimIndex] = data.getDimensionIndex(dimItem.name); + } + + if (dimItem.defaultTooltip) { + defaultedTooltip.push(dimName); + } + } + + VISUAL_DIMENSIONS.each(function (v, otherDim) { + var encodeArr = getOrCreateEncodeArr(encode, otherDim); + var dimIndex = dimItem.otherDims[otherDim]; + + if (dimIndex != null && dimIndex !== false) { + encodeArr[dimIndex] = dimItem.name; + } + }); + }); + var dataDimsOnCoord = []; + var encodeFirstDimNotExtra = {}; + notExtraCoordDimMap.each(function (v, coordDim) { + var dimArr = encode[coordDim]; + encodeFirstDimNotExtra[coordDim] = dimArr[0]; // Not necessary to remove duplicate, because a data + // dim canot on more than one coordDim. + + dataDimsOnCoord = dataDimsOnCoord.concat(dimArr); + }); + summary.dataDimsOnCoord = dataDimsOnCoord; + summary.dataDimIndicesOnCoord = map$1(dataDimsOnCoord, function (dimName) { + return data.getDimensionInfo(dimName).storeDimIndex; + }); + summary.encodeFirstDimNotExtra = encodeFirstDimNotExtra; + var encodeLabel = encode.label; // FIXME `encode.label` is not recommended, because formatter cannot be set + // in this way. Use label.formatter instead. Maybe remove this approach someday. + + if (encodeLabel && encodeLabel.length) { + defaultedLabel = encodeLabel.slice(); + } + + var encodeTooltip = encode.tooltip; + + if (encodeTooltip && encodeTooltip.length) { + defaultedTooltip = encodeTooltip.slice(); + } else if (!defaultedTooltip.length) { + defaultedTooltip = defaultedLabel.slice(); + } + + encode.defaultedLabel = defaultedLabel; + encode.defaultedTooltip = defaultedTooltip; + summary.userOutput = new DimensionUserOuput(userOutputEncode, schema); + return summary; + } + + function getOrCreateEncodeArr(encode, dim) { + if (!encode.hasOwnProperty(dim)) { + encode[dim] = []; + } + + return encode[dim]; + } // FIXME:TS should be type `AxisType` + + + function getDimensionTypeByAxis(axisType) { + return axisType === 'category' ? 'ordinal' : axisType === 'time' ? 'time' : 'float'; + } + + function mayLabelDimType(dimType) { + // In most cases, ordinal and time do not suitable for label. + // Ordinal info can be displayed on axis. Time is too long. + return !(dimType === 'ordinal' || dimType === 'time'); + } // function findTheLastDimMayLabel(data) { + // // Get last value dim + // let dimensions = data.dimensions.slice(); + // let valueType; + // let valueDim; + // while (dimensions.length && ( + // valueDim = dimensions.pop(), + // valueType = data.getDimensionInfo(valueDim).type, + // valueType === 'ordinal' || valueType === 'time' + // )) {} // jshint ignore:line + // return valueDim; + // } + + + var SeriesDimensionDefine = + /** @class */ + function () { + /** + * @param opt All of the fields will be shallow copied. + */ + function SeriesDimensionDefine(opt) { + /** + * The format of `otherDims` is: + * ```js + * { + * tooltip?: number + * label?: number + * itemName?: number + * seriesName?: number + * } + * ``` + * + * A `series.encode` can specified these fields: + * ```js + * encode: { + * // "3, 1, 5" is the index of data dimension. + * tooltip: [3, 1, 5], + * label: [0, 3], + * ... + * } + * ``` + * `otherDims` is the parse result of the `series.encode` above, like: + * ```js + * // Suppose the index of this data dimension is `3`. + * this.otherDims = { + * // `3` is at the index `0` of the `encode.tooltip` + * tooltip: 0, + * // `3` is at the index `1` of the `encode.label` + * label: 1 + * }; + * ``` + * + * This prop should never be `null`/`undefined` after initialized. + */ + this.otherDims = {}; + + if (opt != null) { + extend(this, opt); + } + } + + return SeriesDimensionDefine; + }(); + + var inner$7 = makeInner(); + var dimTypeShort = { + float: 'f', + int: 'i', + ordinal: 'o', + number: 'n', + time: 't' + }; + /** + * Represents the dimension requirement of a series. + * + * NOTICE: + * When there are too many dimensions in dataset and many series, only the used dimensions + * (i.e., used by coord sys and declared in `series.encode`) are add to `dimensionDefineList`. + * But users may query data by other unused dimension names. + * In this case, users can only query data if and only if they have defined dimension names + * via ec option, so we provide `getDimensionIndexFromSource`, which only query them from + * `source` dimensions. + */ + + var SeriesDataSchema = + /** @class */ + function () { + function SeriesDataSchema(opt) { + this.dimensions = opt.dimensions; + this._dimOmitted = opt.dimensionOmitted; + this.source = opt.source; + this._fullDimCount = opt.fullDimensionCount; + + this._updateDimOmitted(opt.dimensionOmitted); + } + + SeriesDataSchema.prototype.isDimensionOmitted = function () { + return this._dimOmitted; + }; + + SeriesDataSchema.prototype._updateDimOmitted = function (dimensionOmitted) { + this._dimOmitted = dimensionOmitted; + + if (!dimensionOmitted) { + return; + } + + if (!this._dimNameMap) { + this._dimNameMap = ensureSourceDimNameMap(this.source); + } + }; + /** + * @caution Can only be used when `dimensionOmitted: true`. + * + * Get index by user defined dimension name (i.e., not internal generate name). + * That is, get index from `dimensionsDefine`. + * If no `dimensionsDefine`, or no name get, return -1. + */ + + + SeriesDataSchema.prototype.getSourceDimensionIndex = function (dimName) { + return retrieve2(this._dimNameMap.get(dimName), -1); + }; + /** + * @caution Can only be used when `dimensionOmitted: true`. + * + * Notice: may return `null`/`undefined` if user not specify dimension names. + */ + + + SeriesDataSchema.prototype.getSourceDimension = function (dimIndex) { + var dimensionsDefine = this.source.dimensionsDefine; + + if (dimensionsDefine) { + return dimensionsDefine[dimIndex]; + } + }; + + SeriesDataSchema.prototype.makeStoreSchema = function () { + var dimCount = this._fullDimCount; + var willRetrieveDataByName = shouldRetrieveDataByName(this.source); + var makeHashStrict = !shouldOmitUnusedDimensions(dimCount); // If source don't have dimensions or series don't omit unsed dimensions. + // Generate from seriesDimList directly + + var dimHash = ''; + var dims = []; + + for (var fullDimIdx = 0, seriesDimIdx = 0; fullDimIdx < dimCount; fullDimIdx++) { + var property = void 0; + var type = void 0; + var ordinalMeta = void 0; + var seriesDimDef = this.dimensions[seriesDimIdx]; // The list has been sorted by `storeDimIndex` asc. + + if (seriesDimDef && seriesDimDef.storeDimIndex === fullDimIdx) { + property = willRetrieveDataByName ? seriesDimDef.name : null; + type = seriesDimDef.type; + ordinalMeta = seriesDimDef.ordinalMeta; + seriesDimIdx++; + } else { + var sourceDimDef = this.getSourceDimension(fullDimIdx); + + if (sourceDimDef) { + property = willRetrieveDataByName ? sourceDimDef.name : null; + type = sourceDimDef.type; + } + } + + dims.push({ + property: property, + type: type, + ordinalMeta: ordinalMeta + }); // If retrieving data by index, + // use to determine whether data can be shared. + // (Because in this case there might be no dimension name defined in dataset, but indices always exists). + // (Indices are always 0, 1, 2, ..., so we can ignore them to shorten the hash). + // Otherwise if retrieving data by property name (like `data: [{aa: 123, bb: 765}, ...]`), + // use in hash. + + if (willRetrieveDataByName && property != null // For data stack, we have make sure each series has its own dim on this store. + // So we do not add property to hash to make sure they can share this store. + && (!seriesDimDef || !seriesDimDef.isCalculationCoord)) { + dimHash += makeHashStrict // Use escape character '`' in case that property name contains '$'. + ? property.replace(/\`/g, '`1').replace(/\$/g, '`2') // For better performance, when there are large dimensions, tolerant this defects that hardly meet. + : property; + } + + dimHash += '$'; + dimHash += dimTypeShort[type] || 'f'; + + if (ordinalMeta) { + dimHash += ordinalMeta.uid; + } + + dimHash += '$'; + } // Source from endpoint(usually series) will be read differently + // when seriesLayoutBy or startIndex(which is affected by sourceHeader) are different. + // So we use this three props as key. + + + var source = this.source; + var hash = [source.seriesLayoutBy, source.startIndex, dimHash].join('$$'); + return { + dimensions: dims, + hash: hash + }; + }; + + SeriesDataSchema.prototype.makeOutputDimensionNames = function () { + var result = []; + + for (var fullDimIdx = 0, seriesDimIdx = 0; fullDimIdx < this._fullDimCount; fullDimIdx++) { + var name_1 = void 0; + var seriesDimDef = this.dimensions[seriesDimIdx]; // The list has been sorted by `storeDimIndex` asc. + + if (seriesDimDef && seriesDimDef.storeDimIndex === fullDimIdx) { + if (!seriesDimDef.isCalculationCoord) { + name_1 = seriesDimDef.name; + } + + seriesDimIdx++; + } else { + var sourceDimDef = this.getSourceDimension(fullDimIdx); + + if (sourceDimDef) { + name_1 = sourceDimDef.name; + } + } + + result.push(name_1); + } + + return result; + }; + + SeriesDataSchema.prototype.appendCalculationDimension = function (dimDef) { + this.dimensions.push(dimDef); + dimDef.isCalculationCoord = true; + this._fullDimCount++; // If append dimension on a data store, consider the store + // might be shared by different series, series dimensions not + // really map to store dimensions. + + this._updateDimOmitted(true); + }; + + return SeriesDataSchema; + }(); + + function isSeriesDataSchema(schema) { + return schema instanceof SeriesDataSchema; + } + + function createDimNameMap(dimsDef) { + var dataDimNameMap = createHashMap(); + + for (var i = 0; i < (dimsDef || []).length; i++) { + var dimDefItemRaw = dimsDef[i]; + var userDimName = isObject$2(dimDefItemRaw) ? dimDefItemRaw.name : dimDefItemRaw; + + if (userDimName != null && dataDimNameMap.get(userDimName) == null) { + dataDimNameMap.set(userDimName, i); + } + } + + return dataDimNameMap; + } + + function ensureSourceDimNameMap(source) { + var innerSource = inner$7(source); + return innerSource.dimNameMap || (innerSource.dimNameMap = createDimNameMap(source.dimensionsDefine)); + } + + function shouldOmitUnusedDimensions(dimCount) { + return dimCount > 30; + } + + var isObject = isObject$2; + var map = map$1; + var CtorInt32Array = typeof Int32Array === 'undefined' ? Array : Int32Array; // Use prefix to avoid index to be the same as otherIdList[idx], + // which will cause weird update animation. + + var ID_PREFIX = 'e\0\0'; + var INDEX_NOT_FOUND = -1; // type SeriesDimensionIndex = DimensionIndex; + + var TRANSFERABLE_PROPERTIES = ['hasItemOption', '_nameList', '_idList', '_invertedIndicesMap', '_dimSummary', 'userOutput', '_rawData', '_dimValueGetter', '_nameDimIdx', '_idDimIdx', '_nameRepeatCount']; + var CLONE_PROPERTIES = ['_approximateExtent']; // ----------------------------- + // Internal method declarations: + // ----------------------------- + + var prepareInvertedIndex; + var getId; + var getIdNameFromStore; + var normalizeDimensions; + var transferProperties; + var cloneListForMapAndSample; + var makeIdFromName; + + var SeriesData = + /** @class */ + function () { + /** + * @param dimensionsInput.dimensions + * For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...]. + * Dimensions should be concrete names like x, y, z, lng, lat, angle, radius + */ + function SeriesData(dimensionsInput, hostModel) { + this.type = 'list'; + this._dimOmitted = false; + this._nameList = []; + this._idList = []; // Models of data option is stored sparse for optimizing memory cost + // Never used yet (not used yet). + // private _optionModels: Model[] = []; + // Global visual properties after visual coding + + this._visual = {}; // Global layout properties. + + this._layout = {}; // Item visual properties after visual coding + + this._itemVisuals = []; // Item layout properties after layout + + this._itemLayouts = []; // Graphic elements + + this._graphicEls = []; // key: dim, value: extent + + this._approximateExtent = {}; + this._calculationInfo = {}; // Having detected that there is data item is non primitive type + // (in type `OptionDataItemObject`). + // Like `data: [ { value: xx, itemStyle: {...} }, ...]` + // At present it only happen in `SOURCE_FORMAT_ORIGINAL`. + + this.hasItemOption = false; // Methods that create a new list based on this list should be listed here. + // Notice that those method should `RETURN` the new list. + + this.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'minmaxDownSample', 'lttbDownSample', 'map']; // Methods that change indices of this list should be listed here. + + this.CHANGABLE_METHODS = ['filterSelf', 'selectRange']; + this.DOWNSAMPLE_METHODS = ['downSample', 'minmaxDownSample', 'lttbDownSample']; + var dimensions; + var assignStoreDimIdx = false; + + if (isSeriesDataSchema(dimensionsInput)) { + dimensions = dimensionsInput.dimensions; + this._dimOmitted = dimensionsInput.isDimensionOmitted(); + this._schema = dimensionsInput; + } else { + assignStoreDimIdx = true; + dimensions = dimensionsInput; + } + + dimensions = dimensions || ['x', 'y']; + var dimensionInfos = {}; + var dimensionNames = []; + var invertedIndicesMap = {}; + var needsHasOwn = false; + var emptyObj = {}; + + for (var i = 0; i < dimensions.length; i++) { + // Use the original dimensions[i], where other flag props may exists. + var dimInfoInput = dimensions[i]; + var dimensionInfo = isString(dimInfoInput) ? new SeriesDimensionDefine({ + name: dimInfoInput + }) : !(dimInfoInput instanceof SeriesDimensionDefine) ? new SeriesDimensionDefine(dimInfoInput) : dimInfoInput; + var dimensionName = dimensionInfo.name; + dimensionInfo.type = dimensionInfo.type || 'float'; + + if (!dimensionInfo.coordDim) { + dimensionInfo.coordDim = dimensionName; + dimensionInfo.coordDimIndex = 0; + } + + var otherDims = dimensionInfo.otherDims = dimensionInfo.otherDims || {}; + dimensionNames.push(dimensionName); + dimensionInfos[dimensionName] = dimensionInfo; + + if (emptyObj[dimensionName] != null) { + needsHasOwn = true; + } + + if (dimensionInfo.createInvertedIndices) { + invertedIndicesMap[dimensionName] = []; + } + + var dimIdx = i; + + if (isNumber(dimensionInfo.storeDimIndex)) { + dimIdx = dimensionInfo.storeDimIndex; + } + + if (otherDims.itemName === 0) { + this._nameDimIdx = dimIdx; + } + + if (otherDims.itemId === 0) { + this._idDimIdx = dimIdx; + } + + { + assert(assignStoreDimIdx || dimensionInfo.storeDimIndex >= 0); + } + + if (assignStoreDimIdx) { + dimensionInfo.storeDimIndex = i; + } + } + + this.dimensions = dimensionNames; + this._dimInfos = dimensionInfos; + + this._initGetDimensionInfo(needsHasOwn); + + this.hostModel = hostModel; + this._invertedIndicesMap = invertedIndicesMap; + + if (this._dimOmitted) { + var dimIdxToName_1 = this._dimIdxToName = createHashMap(); + each$4(dimensionNames, function (dimName) { + dimIdxToName_1.set(dimensionInfos[dimName].storeDimIndex, dimName); + }); + } + } + /** + * + * Get concrete dimension name by dimension name or dimension index. + * If input a dimension name, do not validate whether the dimension name exits. + * + * @caution + * @param dim Must make sure the dimension is `SeriesDimensionLoose`. + * Because only those dimensions will have auto-generated dimension names if not + * have a user-specified name, and other dimensions will get a return of null/undefined. + * + * @notice Because of this reason, should better use `getDimensionIndex` instead, for examples: + * ```js + * const val = data.getStore().get(data.getDimensionIndex(dim), dataIdx); + * ``` + * + * @return Concrete dim name. + */ + + + SeriesData.prototype.getDimension = function (dim) { + var dimIdx = this._recognizeDimIndex(dim); + + if (dimIdx == null) { + return dim; + } + + dimIdx = dim; + + if (!this._dimOmitted) { + return this.dimensions[dimIdx]; + } // Retrieve from series dimension definition because it probably contains + // generated dimension name (like 'x', 'y'). + + + var dimName = this._dimIdxToName.get(dimIdx); + + if (dimName != null) { + return dimName; + } + + var sourceDimDef = this._schema.getSourceDimension(dimIdx); + + if (sourceDimDef) { + return sourceDimDef.name; + } + }; + /** + * Get dimension index in data store. Return -1 if not found. + * Can be used to index value from getRawValue. + */ + + + SeriesData.prototype.getDimensionIndex = function (dim) { + var dimIdx = this._recognizeDimIndex(dim); + + if (dimIdx != null) { + return dimIdx; + } + + if (dim == null) { + return -1; + } + + var dimInfo = this._getDimInfo(dim); + + return dimInfo ? dimInfo.storeDimIndex : this._dimOmitted ? this._schema.getSourceDimensionIndex(dim) : -1; + }; + /** + * The meanings of the input parameter `dim`: + * + * + If dim is a number (e.g., `1`), it means the index of the dimension. + * For example, `getDimension(0)` will return 'x' or 'lng' or 'radius'. + * + If dim is a number-like string (e.g., `"1"`): + * + If there is the same concrete dim name defined in `series.dimensions` or `dataset.dimensions`, + * it means that concrete name. + * + If not, it will be converted to a number, which means the index of the dimension. + * (why? because of the backward compatibility. We have been tolerating number-like string in + * dimension setting, although now it seems that it is not a good idea.) + * For example, `visualMap[i].dimension: "1"` is the same meaning as `visualMap[i].dimension: 1`, + * if no dimension name is defined as `"1"`. + * + If dim is a not-number-like string, it means the concrete dim name. + * For example, it can be be default name `"x"`, `"y"`, `"z"`, `"lng"`, `"lat"`, `"angle"`, `"radius"`, + * or customized in `dimensions` property of option like `"age"`. + * + * @return recognized `DimensionIndex`. Otherwise return null/undefined (means that dim is `DimensionName`). + */ + + + SeriesData.prototype._recognizeDimIndex = function (dim) { + if (isNumber(dim) // If being a number-like string but not being defined as a dimension name. + || dim != null && !isNaN(dim) && !this._getDimInfo(dim) && (!this._dimOmitted || this._schema.getSourceDimensionIndex(dim) < 0)) { + return +dim; + } + }; + + SeriesData.prototype._getStoreDimIndex = function (dim) { + var dimIdx = this.getDimensionIndex(dim); + { + if (dimIdx == null) { + throw new Error('Unknown dimension ' + dim); + } + } + return dimIdx; + }; + /** + * Get type and calculation info of particular dimension + * @param dim + * Dimension can be concrete names like x, y, z, lng, lat, angle, radius + * Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius' + */ + + + SeriesData.prototype.getDimensionInfo = function (dim) { + // Do not clone, because there may be categories in dimInfo. + return this._getDimInfo(this.getDimension(dim)); + }; + + SeriesData.prototype._initGetDimensionInfo = function (needsHasOwn) { + var dimensionInfos = this._dimInfos; + this._getDimInfo = needsHasOwn ? function (dimName) { + return dimensionInfos.hasOwnProperty(dimName) ? dimensionInfos[dimName] : undefined; + } : function (dimName) { + return dimensionInfos[dimName]; + }; + }; + /** + * concrete dimension name list on coord. + */ + + + SeriesData.prototype.getDimensionsOnCoord = function () { + return this._dimSummary.dataDimsOnCoord.slice(); + }; + + SeriesData.prototype.mapDimension = function (coordDim, idx) { + var dimensionsSummary = this._dimSummary; + + if (idx == null) { + return dimensionsSummary.encodeFirstDimNotExtra[coordDim]; + } + + var dims = dimensionsSummary.encode[coordDim]; + return dims ? dims[idx] : null; + }; + + SeriesData.prototype.mapDimensionsAll = function (coordDim) { + var dimensionsSummary = this._dimSummary; + var dims = dimensionsSummary.encode[coordDim]; + return (dims || []).slice(); + }; + + SeriesData.prototype.getStore = function () { + return this._store; + }; + /** + * Initialize from data + * @param data source or data or data store. + * @param nameList The name of a datum is used on data diff and + * default label/tooltip. + * A name can be specified in encode.itemName, + * or dataItem.name (only for series option data), + * or provided in nameList from outside. + */ + + + SeriesData.prototype.initData = function (data, nameList, dimValueGetter) { + var _this = this; + + var store; + + if (data instanceof DataStore) { + store = data; + } + + if (!store) { + var dimensions = this.dimensions; + var provider = isSourceInstance(data) || isArrayLike(data) ? new DefaultDataProvider(data, dimensions.length) : data; + store = new DataStore(); + var dimensionInfos = map(dimensions, function (dimName) { + return { + type: _this._dimInfos[dimName].type, + property: dimName + }; + }); + store.initData(provider, dimensionInfos, dimValueGetter); + } + + this._store = store; // Reset + + this._nameList = (nameList || []).slice(); + this._idList = []; + this._nameRepeatCount = {}; + + this._doInit(0, store.count()); // Cache summary info for fast visit. See "dimensionHelper". + // Needs to be initialized after store is prepared. + + + this._dimSummary = summarizeDimensions(this, this._schema); + this.userOutput = this._dimSummary.userOutput; + }; + /** + * Caution: Can be only called on raw data (before `this._indices` created). + */ + + + SeriesData.prototype.appendData = function (data) { + var range = this._store.appendData(data); + + this._doInit(range[0], range[1]); + }; + /** + * Caution: Can be only called on raw data (before `this._indices` created). + * This method does not modify `rawData` (`dataProvider`), but only + * add values to store. + * + * The final count will be increased by `Math.max(values.length, names.length)`. + * + * @param values That is the SourceType: 'arrayRows', like + * [ + * [12, 33, 44], + * [NaN, 43, 1], + * ['-', 'asdf', 0] + * ] + * Each item is exactly corresponding to a dimension. + */ + + + SeriesData.prototype.appendValues = function (values, names) { + var _a = this._store.appendValues(values, names && names.length), + start = _a.start, + end = _a.end; + + var shouldMakeIdFromName = this._shouldMakeIdFromName(); + + this._updateOrdinalMeta(); + + if (names) { + for (var idx = start; idx < end; idx++) { + var sourceIdx = idx - start; + this._nameList[idx] = names[sourceIdx]; + + if (shouldMakeIdFromName) { + makeIdFromName(this, idx); + } + } + } + }; + + SeriesData.prototype._updateOrdinalMeta = function () { + var store = this._store; + var dimensions = this.dimensions; + + for (var i = 0; i < dimensions.length; i++) { + var dimInfo = this._dimInfos[dimensions[i]]; + + if (dimInfo.ordinalMeta) { + store.collectOrdinalMeta(dimInfo.storeDimIndex, dimInfo.ordinalMeta); + } + } + }; + + SeriesData.prototype._shouldMakeIdFromName = function () { + var provider = this._store.getProvider(); + + return this._idDimIdx == null && provider.getSource().sourceFormat !== SOURCE_FORMAT_TYPED_ARRAY && !provider.fillStorage; + }; + + SeriesData.prototype._doInit = function (start, end) { + if (start >= end) { + return; + } + + var store = this._store; + var provider = store.getProvider(); + + this._updateOrdinalMeta(); + + var nameList = this._nameList; + var idList = this._idList; + var sourceFormat = provider.getSource().sourceFormat; + var isFormatOriginal = sourceFormat === SOURCE_FORMAT_ORIGINAL; // Each data item is value + // [1, 2] + // 2 + // Bar chart, line chart which uses category axis + // only gives the 'y' value. 'x' value is the indices of category + // Use a tempValue to normalize the value to be a (x, y) value + // If dataItem is {name: ...} or {id: ...}, it has highest priority. + // This kind of ids and names are always stored `_nameList` and `_idList`. + + if (isFormatOriginal && !provider.pure) { + var sharedDataItem = []; + + for (var idx = start; idx < end; idx++) { + // NOTICE: Try not to write things into dataItem + var dataItem = provider.getItem(idx, sharedDataItem); + + if (!this.hasItemOption && isDataItemOption(dataItem)) { + this.hasItemOption = true; + } + + if (dataItem) { + var itemName = dataItem.name; + + if (nameList[idx] == null && itemName != null) { + nameList[idx] = convertOptionIdName(itemName, null); + } + + var itemId = dataItem.id; + + if (idList[idx] == null && itemId != null) { + idList[idx] = convertOptionIdName(itemId, null); + } + } + } + } + + if (this._shouldMakeIdFromName()) { + for (var idx = start; idx < end; idx++) { + makeIdFromName(this, idx); + } + } + + prepareInvertedIndex(this); + }; + /** + * PENDING: In fact currently this function is only used to short-circuit + * the calling of `scale.unionExtentFromData` when data have been filtered by modules + * like "dataZoom". `scale.unionExtentFromData` is used to calculate data extent for series on + * an axis, but if a "axis related data filter module" is used, the extent of the axis have + * been fixed and no need to calling `scale.unionExtentFromData` actually. + * But if we add "custom data filter" in future, which is not "axis related", this method may + * be still needed. + * + * Optimize for the scenario that data is filtered by a given extent. + * Consider that if data amount is more than hundreds of thousand, + * extent calculation will cost more than 10ms and the cache will + * be erased because of the filtering. + */ + + + SeriesData.prototype.getApproximateExtent = function (dim) { + return this._approximateExtent[dim] || this._store.getDataExtent(this._getStoreDimIndex(dim)); + }; + /** + * Calculate extent on a filtered data might be time consuming. + * Approximate extent is only used for: calculate extent of filtered data outside. + */ + + + SeriesData.prototype.setApproximateExtent = function (extent, dim) { + dim = this.getDimension(dim); + this._approximateExtent[dim] = extent.slice(); + }; + + SeriesData.prototype.getCalculationInfo = function (key) { + return this._calculationInfo[key]; + }; + + SeriesData.prototype.setCalculationInfo = function (key, value) { + isObject(key) ? extend(this._calculationInfo, key) : this._calculationInfo[key] = value; + }; + /** + * @return Never be null/undefined. `number` will be converted to string. Because: + * In most cases, name is used in display, where returning a string is more convenient. + * In other cases, name is used in query (see `indexOfName`), where we can keep the + * rule that name `2` equals to name `'2'`. + */ + + + SeriesData.prototype.getName = function (idx) { + var rawIndex = this.getRawIndex(idx); + var name = this._nameList[rawIndex]; + + if (name == null && this._nameDimIdx != null) { + name = getIdNameFromStore(this, this._nameDimIdx, rawIndex); + } + + if (name == null) { + name = ''; + } + + return name; + }; + + SeriesData.prototype._getCategory = function (dimIdx, idx) { + var ordinal = this._store.get(dimIdx, idx); + + var ordinalMeta = this._store.getOrdinalMeta(dimIdx); + + if (ordinalMeta) { + return ordinalMeta.categories[ordinal]; + } + + return ordinal; + }; + /** + * @return Never null/undefined. `number` will be converted to string. Because: + * In all cases having encountered at present, id is used in making diff comparison, which + * are usually based on hash map. We can keep the rule that the internal id are always string + * (treat `2` is the same as `'2'`) to make the related logic simple. + */ + + + SeriesData.prototype.getId = function (idx) { + return getId(this, this.getRawIndex(idx)); + }; + + SeriesData.prototype.count = function () { + return this._store.count(); + }; + /** + * Get value. Return NaN if idx is out of range. + * + * @notice Should better to use `data.getStore().get(dimIndex, dataIdx)` instead. + */ + + + SeriesData.prototype.get = function (dim, idx) { + var store = this._store; + var dimInfo = this._dimInfos[dim]; + + if (dimInfo) { + return store.get(dimInfo.storeDimIndex, idx); + } + }; + /** + * @notice Should better to use `data.getStore().getByRawIndex(dimIndex, dataIdx)` instead. + */ + + + SeriesData.prototype.getByRawIndex = function (dim, rawIdx) { + var store = this._store; + var dimInfo = this._dimInfos[dim]; + + if (dimInfo) { + return store.getByRawIndex(dimInfo.storeDimIndex, rawIdx); + } + }; + + SeriesData.prototype.getIndices = function () { + return this._store.getIndices(); + }; + + SeriesData.prototype.getDataExtent = function (dim) { + return this._store.getDataExtent(this._getStoreDimIndex(dim)); + }; + + SeriesData.prototype.getSum = function (dim) { + return this._store.getSum(this._getStoreDimIndex(dim)); + }; + + SeriesData.prototype.getMedian = function (dim) { + return this._store.getMedian(this._getStoreDimIndex(dim)); + }; + + SeriesData.prototype.getValues = function (dimensions, idx) { + var _this = this; + + var store = this._store; + return isArray(dimensions) ? store.getValues(map(dimensions, function (dim) { + return _this._getStoreDimIndex(dim); + }), idx) : store.getValues(dimensions); + }; + /** + * If value is NaN. Including '-' + * Only check the coord dimensions. + */ + + + SeriesData.prototype.hasValue = function (idx) { + var dataDimIndicesOnCoord = this._dimSummary.dataDimIndicesOnCoord; + + for (var i = 0, len = dataDimIndicesOnCoord.length; i < len; i++) { + // Ordinal type originally can be string or number. + // But when an ordinal type is used on coord, it can + // not be string but only number. So we can also use isNaN. + if (isNaN(this._store.get(dataDimIndicesOnCoord[i], idx))) { + return false; + } + } + + return true; + }; + /** + * Retrieve the index with given name + */ + + + SeriesData.prototype.indexOfName = function (name) { + for (var i = 0, len = this._store.count(); i < len; i++) { + if (this.getName(i) === name) { + return i; + } + } + + return -1; + }; + + SeriesData.prototype.getRawIndex = function (idx) { + return this._store.getRawIndex(idx); + }; + + SeriesData.prototype.indexOfRawIndex = function (rawIndex) { + return this._store.indexOfRawIndex(rawIndex); + }; + /** + * Only support the dimension which inverted index created. + * Do not support other cases until required. + * @param dim concrete dim + * @param value ordinal index + * @return rawIndex + */ + + + SeriesData.prototype.rawIndexOf = function (dim, value) { + var invertedIndices = dim && this._invertedIndicesMap[dim]; + { + if (!invertedIndices) { + throw new Error('Do not supported yet'); + } + } + var rawIndex = invertedIndices && invertedIndices[value]; + + if (rawIndex == null || isNaN(rawIndex)) { + return INDEX_NOT_FOUND; + } + + return rawIndex; + }; + + SeriesData.prototype.each = function (dims, cb, ctx) { + if (isFunction(dims)) { + ctx = cb; + cb = dims; + dims = []; + } // ctxCompat just for compat echarts3 + + + var fCtx = ctx || this; + var dimIndices = map(normalizeDimensions(dims), this._getStoreDimIndex, this); + + this._store.each(dimIndices, fCtx ? bind$1(cb, fCtx) : cb); + }; + + SeriesData.prototype.filterSelf = function (dims, cb, ctx) { + if (isFunction(dims)) { + ctx = cb; + cb = dims; + dims = []; + } // ctxCompat just for compat echarts3 + + + var fCtx = ctx || this; + var dimIndices = map(normalizeDimensions(dims), this._getStoreDimIndex, this); + this._store = this._store.filter(dimIndices, fCtx ? bind$1(cb, fCtx) : cb); + return this; + }; + /** + * Select data in range. (For optimization of filter) + * (Manually inline code, support 5 million data filtering in data zoom.) + */ + + + SeriesData.prototype.selectRange = function (range) { + var _this = this; + + var innerRange = {}; + var dims = keys(range); + each$4(dims, function (dim) { + var dimIdx = _this._getStoreDimIndex(dim); + + innerRange[dimIdx] = range[dim]; + }); + this._store = this._store.selectRange(innerRange); + return this; + }; + /* eslint-enable max-len */ + + + SeriesData.prototype.mapArray = function (dims, cb, ctx) { + if (isFunction(dims)) { + ctx = cb; + cb = dims; + dims = []; + } // ctxCompat just for compat echarts3 + + + ctx = ctx || this; + var result = []; + this.each(dims, function () { + result.push(cb && cb.apply(this, arguments)); + }, ctx); + return result; + }; + + SeriesData.prototype.map = function (dims, cb, ctx, ctxCompat) { + // ctxCompat just for compat echarts3 + var fCtx = ctx || ctxCompat || this; + var dimIndices = map(normalizeDimensions(dims), this._getStoreDimIndex, this); + var list = cloneListForMapAndSample(this); + list._store = this._store.map(dimIndices, fCtx ? bind$1(cb, fCtx) : cb); + return list; + }; + + SeriesData.prototype.modify = function (dims, cb, ctx, ctxCompat) { + var _this = this; // ctxCompat just for compat echarts3 + + + var fCtx = ctx || ctxCompat || this; + { + each$4(normalizeDimensions(dims), function (dim) { + var dimInfo = _this.getDimensionInfo(dim); + + if (!dimInfo.isCalculationCoord) { + console.error('Danger: only stack dimension can be modified'); + } + }); + } + var dimIndices = map(normalizeDimensions(dims), this._getStoreDimIndex, this); // If do shallow clone here, if there are too many stacked series, + // it still cost lots of memory, because `_store.dimensions` are not shared. + // We should consider there probably be shallow clone happen in each series + // in consequent filter/map. + + this._store.modify(dimIndices, fCtx ? bind$1(cb, fCtx) : cb); + }; + /** + * Large data down sampling on given dimension + * @param sampleIndex Sample index for name and id + */ + + + SeriesData.prototype.downSample = function (dimension, rate, sampleValue, sampleIndex) { + var list = cloneListForMapAndSample(this); + list._store = this._store.downSample(this._getStoreDimIndex(dimension), rate, sampleValue, sampleIndex); + return list; + }; + /** + * Large data down sampling using min-max + * @param {string} valueDimension + * @param {number} rate + */ + + + SeriesData.prototype.minmaxDownSample = function (valueDimension, rate) { + var list = cloneListForMapAndSample(this); + list._store = this._store.minmaxDownSample(this._getStoreDimIndex(valueDimension), rate); + return list; + }; + /** + * Large data down sampling using largest-triangle-three-buckets + * @param {string} valueDimension + * @param {number} targetCount + */ + + + SeriesData.prototype.lttbDownSample = function (valueDimension, rate) { + var list = cloneListForMapAndSample(this); + list._store = this._store.lttbDownSample(this._getStoreDimIndex(valueDimension), rate); + return list; + }; + + SeriesData.prototype.getRawDataItem = function (idx) { + return this._store.getRawDataItem(idx); + }; + /** + * Get model of one data item. + */ + // TODO: Type of data item + + + SeriesData.prototype.getItemModel = function (idx) { + var hostModel = this.hostModel; + var dataItem = this.getRawDataItem(idx); + return new Model(dataItem, hostModel, hostModel && hostModel.ecModel); + }; + /** + * Create a data differ + */ + + + SeriesData.prototype.diff = function (otherList) { + var thisList = this; + return new DataDiffer(otherList ? otherList.getStore().getIndices() : [], this.getStore().getIndices(), function (idx) { + return getId(otherList, idx); + }, function (idx) { + return getId(thisList, idx); + }); + }; + /** + * Get visual property. + */ + + + SeriesData.prototype.getVisual = function (key) { + var visual = this._visual; + return visual && visual[key]; + }; + + SeriesData.prototype.setVisual = function (kvObj, val) { + this._visual = this._visual || {}; + + if (isObject(kvObj)) { + extend(this._visual, kvObj); + } else { + this._visual[kvObj] = val; + } + }; + /** + * Get visual property of single data item + */ + // eslint-disable-next-line + + + SeriesData.prototype.getItemVisual = function (idx, key) { + var itemVisual = this._itemVisuals[idx]; + var val = itemVisual && itemVisual[key]; + + if (val == null) { + // Use global visual property + return this.getVisual(key); + } + + return val; + }; + /** + * If exists visual property of single data item + */ + + + SeriesData.prototype.hasItemVisual = function () { + return this._itemVisuals.length > 0; + }; + /** + * Make sure itemVisual property is unique + */ + // TODO: use key to save visual to reduce memory. + + + SeriesData.prototype.ensureUniqueItemVisual = function (idx, key) { + var itemVisuals = this._itemVisuals; + var itemVisual = itemVisuals[idx]; + + if (!itemVisual) { + itemVisual = itemVisuals[idx] = {}; + } + + var val = itemVisual[key]; + + if (val == null) { + val = this.getVisual(key); // TODO Performance? + + if (isArray(val)) { + val = val.slice(); + } else if (isObject(val)) { + val = extend({}, val); + } + + itemVisual[key] = val; + } + + return val; + }; // eslint-disable-next-line + + + SeriesData.prototype.setItemVisual = function (idx, key, value) { + var itemVisual = this._itemVisuals[idx] || {}; + this._itemVisuals[idx] = itemVisual; + + if (isObject(key)) { + extend(itemVisual, key); + } else { + itemVisual[key] = value; + } + }; + /** + * Clear itemVisuals and list visual. + */ + + + SeriesData.prototype.clearAllVisual = function () { + this._visual = {}; + this._itemVisuals = []; + }; + + SeriesData.prototype.setLayout = function (key, val) { + isObject(key) ? extend(this._layout, key) : this._layout[key] = val; + }; + /** + * Get layout property. + */ + + + SeriesData.prototype.getLayout = function (key) { + return this._layout[key]; + }; + /** + * Get layout of single data item + */ + + + SeriesData.prototype.getItemLayout = function (idx) { + return this._itemLayouts[idx]; + }; + /** + * Set layout of single data item + */ + + + SeriesData.prototype.setItemLayout = function (idx, layout, merge) { + this._itemLayouts[idx] = merge ? extend(this._itemLayouts[idx] || {}, layout) : layout; + }; + /** + * Clear all layout of single data item + */ + + + SeriesData.prototype.clearItemLayouts = function () { + this._itemLayouts.length = 0; + }; + /** + * Set graphic element relative to data. It can be set as null + */ + + + SeriesData.prototype.setItemGraphicEl = function (idx, el) { + var seriesIndex = this.hostModel && this.hostModel.seriesIndex; + setCommonECData(seriesIndex, this.dataType, idx, el); + this._graphicEls[idx] = el; + }; + + SeriesData.prototype.getItemGraphicEl = function (idx) { + return this._graphicEls[idx]; + }; + + SeriesData.prototype.eachItemGraphicEl = function (cb, context) { + each$4(this._graphicEls, function (el, idx) { + if (el) { + cb && cb.call(context, el, idx); + } + }); + }; + /** + * Shallow clone a new list except visual and layout properties, and graph elements. + * New list only change the indices. + */ + + + SeriesData.prototype.cloneShallow = function (list) { + if (!list) { + list = new SeriesData(this._schema ? this._schema : map(this.dimensions, this._getDimInfo, this), this.hostModel); + } + + transferProperties(list, this); + list._store = this._store; + return list; + }; + /** + * Wrap some method to add more feature + */ + + + SeriesData.prototype.wrapMethod = function (methodName, injectFunction) { + var originalMethod = this[methodName]; + + if (!isFunction(originalMethod)) { + return; + } + + this.__wrappedMethods = this.__wrappedMethods || []; + + this.__wrappedMethods.push(methodName); + + this[methodName] = function () { + var res = originalMethod.apply(this, arguments); + return injectFunction.apply(this, [res].concat(slice(arguments))); + }; + }; // ---------------------------------------------------------- + // A work around for internal method visiting private member. + // ---------------------------------------------------------- + + + SeriesData.internalField = function () { + prepareInvertedIndex = function (data) { + var invertedIndicesMap = data._invertedIndicesMap; + each$4(invertedIndicesMap, function (invertedIndices, dim) { + var dimInfo = data._dimInfos[dim]; // Currently, only dimensions that has ordinalMeta can create inverted indices. + + var ordinalMeta = dimInfo.ordinalMeta; + var store = data._store; + + if (ordinalMeta) { + invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array(ordinalMeta.categories.length); // The default value of TypedArray is 0. To avoid miss + // mapping to 0, we should set it as INDEX_NOT_FOUND. + + for (var i = 0; i < invertedIndices.length; i++) { + invertedIndices[i] = INDEX_NOT_FOUND; + } + + for (var i = 0; i < store.count(); i++) { + // Only support the case that all values are distinct. + invertedIndices[store.get(dimInfo.storeDimIndex, i)] = i; + } + } + }); + }; + + getIdNameFromStore = function (data, dimIdx, idx) { + return convertOptionIdName(data._getCategory(dimIdx, idx), null); + }; + /** + * @see the comment of `List['getId']`. + */ + + + getId = function (data, rawIndex) { + var id = data._idList[rawIndex]; + + if (id == null && data._idDimIdx != null) { + id = getIdNameFromStore(data, data._idDimIdx, rawIndex); + } + + if (id == null) { + id = ID_PREFIX + rawIndex; + } + + return id; + }; + + normalizeDimensions = function (dimensions) { + if (!isArray(dimensions)) { + dimensions = dimensions != null ? [dimensions] : []; + } + + return dimensions; + }; + /** + * Data in excludeDimensions is copied, otherwise transferred. + */ + + + cloneListForMapAndSample = function (original) { + var list = new SeriesData(original._schema ? original._schema : map(original.dimensions, original._getDimInfo, original), original.hostModel); // FIXME If needs stackedOn, value may already been stacked + + transferProperties(list, original); + return list; + }; + + transferProperties = function (target, source) { + each$4(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) { + if (source.hasOwnProperty(propName)) { + target[propName] = source[propName]; + } + }); + target.__wrappedMethods = source.__wrappedMethods; + each$4(CLONE_PROPERTIES, function (propName) { + target[propName] = clone$3(source[propName]); + }); + target._calculationInfo = extend({}, source._calculationInfo); + }; + + makeIdFromName = function (data, idx) { + var nameList = data._nameList; + var idList = data._idList; + var nameDimIdx = data._nameDimIdx; + var idDimIdx = data._idDimIdx; + var name = nameList[idx]; + var id = idList[idx]; + + if (name == null && nameDimIdx != null) { + nameList[idx] = name = getIdNameFromStore(data, nameDimIdx, idx); + } + + if (id == null && idDimIdx != null) { + idList[idx] = id = getIdNameFromStore(data, idDimIdx, idx); + } + + if (id == null && name != null) { + var nameRepeatCount = data._nameRepeatCount; + var nmCnt = nameRepeatCount[name] = (nameRepeatCount[name] || 0) + 1; + id = name; + + if (nmCnt > 1) { + id += '__ec__' + nmCnt; + } + + idList[idx] = id; + } + }; + }(); + + return SeriesData; + }(); + /** + * For outside usage compat (like echarts-gl are using it). + */ + + + function createDimensions(source, opt) { + return prepareSeriesDataSchema(source, opt).dimensions; + } + /** + * This method builds the relationship between: + * + "what the coord sys or series requires (see `coordDimensions`)", + * + "what the user defines (in `encode` and `dimensions`, see `opt.dimensionsDefine` and `opt.encodeDefine`)" + * + "what the data source provids (see `source`)". + * + * Some guess strategy will be adapted if user does not define something. + * If no 'value' dimension specified, the first no-named dimension will be + * named as 'value'. + * + * @return The results are always sorted by `storeDimIndex` asc. + */ + + + function prepareSeriesDataSchema( // TODO: TYPE completeDimensions type + source, opt) { + if (!isSourceInstance(source)) { + source = createSourceFromSeriesDataOption(source); + } + + opt = opt || {}; + var sysDims = opt.coordDimensions || []; + var dimsDef = opt.dimensionsDefine || source.dimensionsDefine || []; + var coordDimNameMap = createHashMap(); + var resultList = []; + var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimensionsCount); // Try to ignore unused dimensions if sharing a high dimension datastore + // 30 is an experience value. + + var omitUnusedDimensions = opt.canOmitUnusedDimensions && shouldOmitUnusedDimensions(dimCount); + var isUsingSourceDimensionsDef = dimsDef === source.dimensionsDefine; + var dataDimNameMap = isUsingSourceDimensionsDef ? ensureSourceDimNameMap(source) : createDimNameMap(dimsDef); + var encodeDef = opt.encodeDefine; + + if (!encodeDef && opt.encodeDefaulter) { + encodeDef = opt.encodeDefaulter(source, dimCount); + } + + var encodeDefMap = createHashMap(encodeDef); + var indicesMap = new CtorInt32Array$1(dimCount); + + for (var i = 0; i < indicesMap.length; i++) { + indicesMap[i] = -1; + } + + function getResultItem(dimIdx) { + var idx = indicesMap[dimIdx]; + + if (idx < 0) { + var dimDefItemRaw = dimsDef[dimIdx]; + var dimDefItem = isObject$2(dimDefItemRaw) ? dimDefItemRaw : { + name: dimDefItemRaw + }; + var resultItem = new SeriesDimensionDefine(); + var userDimName = dimDefItem.name; + + if (userDimName != null && dataDimNameMap.get(userDimName) != null) { + // Only if `series.dimensions` is defined in option + // displayName, will be set, and dimension will be displayed vertically in + // tooltip by default. + resultItem.name = resultItem.displayName = userDimName; + } + + dimDefItem.type != null && (resultItem.type = dimDefItem.type); + dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName); + var newIdx = resultList.length; + indicesMap[dimIdx] = newIdx; + resultItem.storeDimIndex = dimIdx; + resultList.push(resultItem); + return resultItem; + } + + return resultList[idx]; + } + + if (!omitUnusedDimensions) { + for (var i = 0; i < dimCount; i++) { + getResultItem(i); + } + } // Set `coordDim` and `coordDimIndex` by `encodeDefMap` and normalize `encodeDefMap`. + + + encodeDefMap.each(function (dataDimsRaw, coordDim) { + var dataDims = normalizeToArray(dataDimsRaw).slice(); // Note: It is allowed that `dataDims.length` is `0`, e.g., options is + // `{encode: {x: -1, y: 1}}`. Should not filter anything in + // this case. + + if (dataDims.length === 1 && !isString(dataDims[0]) && dataDims[0] < 0) { + encodeDefMap.set(coordDim, false); + return; + } + + var validDataDims = encodeDefMap.set(coordDim, []); + each$4(dataDims, function (resultDimIdxOrName, idx) { + // The input resultDimIdx can be dim name or index. + var resultDimIdx = isString(resultDimIdxOrName) ? dataDimNameMap.get(resultDimIdxOrName) : resultDimIdxOrName; + + if (resultDimIdx != null && resultDimIdx < dimCount) { + validDataDims[idx] = resultDimIdx; + applyDim(getResultItem(resultDimIdx), coordDim, idx); + } + }); + }); // Apply templates and default order from `sysDims`. + + var availDimIdx = 0; + each$4(sysDims, function (sysDimItemRaw) { + var coordDim; + var sysDimItemDimsDef; + var sysDimItemOtherDims; + var sysDimItem; + + if (isString(sysDimItemRaw)) { + coordDim = sysDimItemRaw; + sysDimItem = {}; + } else { + sysDimItem = sysDimItemRaw; + coordDim = sysDimItem.name; + var ordinalMeta = sysDimItem.ordinalMeta; + sysDimItem.ordinalMeta = null; + sysDimItem = extend({}, sysDimItem); + sysDimItem.ordinalMeta = ordinalMeta; // `coordDimIndex` should not be set directly. + + sysDimItemDimsDef = sysDimItem.dimsDef; + sysDimItemOtherDims = sysDimItem.otherDims; + sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex = sysDimItem.dimsDef = sysDimItem.otherDims = null; + } + + var dataDims = encodeDefMap.get(coordDim); // negative resultDimIdx means no need to mapping. + + if (dataDims === false) { + return; + } + + dataDims = normalizeToArray(dataDims); // dimensions provides default dim sequences. + + if (!dataDims.length) { + for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) { + while (availDimIdx < dimCount && getResultItem(availDimIdx).coordDim != null) { + availDimIdx++; + } + + availDimIdx < dimCount && dataDims.push(availDimIdx++); + } + } // Apply templates. + + + each$4(dataDims, function (resultDimIdx, coordDimIndex) { + var resultItem = getResultItem(resultDimIdx); // Coordinate system has a higher priority on dim type than source. + + if (isUsingSourceDimensionsDef && sysDimItem.type != null) { + resultItem.type = sysDimItem.type; + } + + applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex); + + if (resultItem.name == null && sysDimItemDimsDef) { + var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex]; + !isObject$2(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = { + name: sysDimItemDimsDefItem + }); + resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name; + resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip; + } // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}} + + + sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims); + }); + }); + + function applyDim(resultItem, coordDim, coordDimIndex) { + if (VISUAL_DIMENSIONS.get(coordDim) != null) { + resultItem.otherDims[coordDim] = coordDimIndex; + } else { + resultItem.coordDim = coordDim; + resultItem.coordDimIndex = coordDimIndex; + coordDimNameMap.set(coordDim, true); + } + } // Make sure the first extra dim is 'value'. + + + var generateCoord = opt.generateCoord; + var generateCoordCount = opt.generateCoordCount; + var fromZero = generateCoordCount != null; + generateCoordCount = generateCoord ? generateCoordCount || 1 : 0; + var extra = generateCoord || 'value'; + + function ifNoNameFillWithCoordName(resultItem) { + if (resultItem.name == null) { + // Duplication will be removed in the next step. + resultItem.name = resultItem.coordDim; + } + } // Set dim `name` and other `coordDim` and other props. + + + if (!omitUnusedDimensions) { + for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) { + var resultItem = getResultItem(resultDimIdx); + var coordDim = resultItem.coordDim; + + if (coordDim == null) { + // TODO no need to generate coordDim for isExtraCoord? + resultItem.coordDim = genCoordDimName(extra, coordDimNameMap, fromZero); + resultItem.coordDimIndex = 0; // Series specified generateCoord is using out. + + if (!generateCoord || generateCoordCount <= 0) { + resultItem.isExtraCoord = true; + } + + generateCoordCount--; + } + + ifNoNameFillWithCoordName(resultItem); + + if (resultItem.type == null && (guessOrdinal(source, resultDimIdx) === BE_ORDINAL.Must // Consider the case: + // { + // dataset: {source: [ + // ['2001', 123], + // ['2002', 456], + // ... + // ['The others', 987], + // ]}, + // series: {type: 'pie'} + // } + // The first column should better be treated as a "ordinal" although it + // might not be detected as an "ordinal" by `guessOrdinal`. + || resultItem.isExtraCoord && (resultItem.otherDims.itemName != null || resultItem.otherDims.seriesName != null))) { + resultItem.type = 'ordinal'; + } + } + } else { + each$4(resultList, function (resultItem) { + // PENDING: guessOrdinal or let user specify type: 'ordinal' manually? + ifNoNameFillWithCoordName(resultItem); + }); // Sort dimensions: there are some rule that use the last dim as label, + // and for some latter travel process easier. + + resultList.sort(function (item0, item1) { + return item0.storeDimIndex - item1.storeDimIndex; + }); + } + + removeDuplication(resultList); + return new SeriesDataSchema({ + source: source, + dimensions: resultList, + fullDimensionCount: dimCount, + dimensionOmitted: omitUnusedDimensions + }); + } + + function removeDuplication(result) { + var duplicationMap = createHashMap(); + + for (var i = 0; i < result.length; i++) { + var dim = result[i]; + var dimOriginalName = dim.name; + var count = duplicationMap.get(dimOriginalName) || 0; + + if (count > 0) { + // Starts from 0. + dim.name = dimOriginalName + (count - 1); + } + + count++; + duplicationMap.set(dimOriginalName, count); + } + } // ??? TODO + // Originally detect dimCount by data[0]. Should we + // optimize it to only by sysDims and dimensions and encode. + // So only necessary dims will be initialized. + // But + // (1) custom series should be considered. where other dims + // may be visited. + // (2) sometimes user need to calculate bubble size or use visualMap + // on other dimensions besides coordSys needed. + // So, dims that is not used by system, should be shared in data store? + + + function getDimCount(source, sysDims, dimsDef, optDimCount) { + // Note that the result dimCount should not small than columns count + // of data, otherwise `dataDimNameMap` checking will be incorrect. + var dimCount = Math.max(source.dimensionsDetectedCount || 1, sysDims.length, dimsDef.length, optDimCount || 0); + each$4(sysDims, function (sysDimItem) { + var sysDimItemDimsDef; + + if (isObject$2(sysDimItem) && (sysDimItemDimsDef = sysDimItem.dimsDef)) { + dimCount = Math.max(dimCount, sysDimItemDimsDef.length); + } + }); + return dimCount; + } + + function genCoordDimName(name, map, fromZero) { + if (fromZero || map.hasKey(name)) { + var i = 0; + + while (map.hasKey(name + i)) { + i++; + } + + name += i; + } + + map.set(name, true); + return name; + } + /** + * @class + * For example: + * { + * coordSysName: 'cartesian2d', + * coordSysDims: ['x', 'y', ...], + * axisMap: HashMap({ + * x: xAxisModel, + * y: yAxisModel + * }), + * categoryAxisMap: HashMap({ + * x: xAxisModel, + * y: undefined + * }), + * // The index of the first category axis in `coordSysDims`. + * // `null/undefined` means no category axis exists. + * firstCategoryDimIndex: 1, + * // To replace user specified encode. + * } + */ + + + var CoordSysInfo = + /** @class */ + function () { + function CoordSysInfo(coordSysName) { + this.coordSysDims = []; + this.axisMap = createHashMap(); + this.categoryAxisMap = createHashMap(); + this.coordSysName = coordSysName; + } + + return CoordSysInfo; + }(); + + function getCoordSysInfoBySeries(seriesModel) { + var coordSysName = seriesModel.get('coordinateSystem'); + var result = new CoordSysInfo(coordSysName); + var fetch = fetchers[coordSysName]; + + if (fetch) { + fetch(seriesModel, result, result.axisMap, result.categoryAxisMap); + return result; + } + } // TODO: refactor them to static member of each coord sys, rather than hard code here. + + + var fetchers = { + cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) { + var xAxisModel = seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0]; + var yAxisModel = seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[0]; + { + if (!xAxisModel) { + throw new Error('xAxis "' + retrieve(seriesModel.get('xAxisIndex'), seriesModel.get('xAxisId'), 0) + '" not found'); + } + + if (!yAxisModel) { + throw new Error('yAxis "' + retrieve(seriesModel.get('xAxisIndex'), seriesModel.get('yAxisId'), 0) + '" not found'); + } + } + result.coordSysDims = ['x', 'y']; + axisMap.set('x', xAxisModel); + axisMap.set('y', yAxisModel); + + if (isCategory(xAxisModel)) { + categoryAxisMap.set('x', xAxisModel); + result.firstCategoryDimIndex = 0; + } + + if (isCategory(yAxisModel)) { + categoryAxisMap.set('y', yAxisModel); + result.firstCategoryDimIndex == null && (result.firstCategoryDimIndex = 1); + } + }, + singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) { + var singleAxisModel = seriesModel.getReferringComponents('singleAxis', SINGLE_REFERRING).models[0]; + { + if (!singleAxisModel) { + throw new Error('singleAxis should be specified.'); + } + } + result.coordSysDims = ['single']; + axisMap.set('single', singleAxisModel); + + if (isCategory(singleAxisModel)) { + categoryAxisMap.set('single', singleAxisModel); + result.firstCategoryDimIndex = 0; + } + }, + polar: function (seriesModel, result, axisMap, categoryAxisMap) { + var polarModel = seriesModel.getReferringComponents('polar', SINGLE_REFERRING).models[0]; + var radiusAxisModel = polarModel.findAxisModel('radiusAxis'); + var angleAxisModel = polarModel.findAxisModel('angleAxis'); + { + if (!angleAxisModel) { + throw new Error('angleAxis option not found'); + } + + if (!radiusAxisModel) { + throw new Error('radiusAxis option not found'); + } + } + result.coordSysDims = ['radius', 'angle']; + axisMap.set('radius', radiusAxisModel); + axisMap.set('angle', angleAxisModel); + + if (isCategory(radiusAxisModel)) { + categoryAxisMap.set('radius', radiusAxisModel); + result.firstCategoryDimIndex = 0; + } + + if (isCategory(angleAxisModel)) { + categoryAxisMap.set('angle', angleAxisModel); + result.firstCategoryDimIndex == null && (result.firstCategoryDimIndex = 1); + } + }, + geo: function (seriesModel, result, axisMap, categoryAxisMap) { + result.coordSysDims = ['lng', 'lat']; + }, + parallel: function (seriesModel, result, axisMap, categoryAxisMap) { + var ecModel = seriesModel.ecModel; + var parallelModel = ecModel.getComponent('parallel', seriesModel.get('parallelIndex')); + var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice(); + each$4(parallelModel.parallelAxisIndex, function (axisIndex, index) { + var axisModel = ecModel.getComponent('parallelAxis', axisIndex); + var axisDim = coordSysDims[index]; + axisMap.set(axisDim, axisModel); + + if (isCategory(axisModel)) { + categoryAxisMap.set(axisDim, axisModel); + + if (result.firstCategoryDimIndex == null) { + result.firstCategoryDimIndex = index; + } + } + }); + }, + matrix: function (seriesModel, result, axisMap, categoryAxisMap) { + var matrixModel = seriesModel.getReferringComponents('matrix', SINGLE_REFERRING).models[0]; + { + if (!matrixModel) { + throw new Error('matrix coordinate system should be specified.'); + } + } + result.coordSysDims = ['x', 'y']; + var xModel = matrixModel.getDimensionModel('x'); + var yModel = matrixModel.getDimensionModel('y'); + axisMap.set('x', xModel); + axisMap.set('y', yModel); + categoryAxisMap.set('x', xModel); + categoryAxisMap.set('y', yModel); + } + }; + + function isCategory(axisModel) { + return axisModel.get('type') === 'category'; + } + /** + * Note that it is too complicated to support 3d stack by value + * (have to create two-dimension inverted index), so in 3d case + * we just support that stacked by index. + * + * @param seriesModel + * @param dimensionsInput The same as the input of . + * The input will be modified. + * @param opt + * @param opt.stackedCoordDimension Specify a coord dimension if needed. + * @param opt.byIndex=false + * @return calculationInfo + * { + * stackedDimension: string + * stackedByDimension: string + * isStackedByIndex: boolean + * stackedOverDimension: string + * stackResultDimension: string + * } + */ + + + function enableDataStack(seriesModel, dimensionsInput, opt) { + opt = opt || {}; + var byIndex = opt.byIndex; + var stackedCoordDimension = opt.stackedCoordDimension; + var dimensionDefineList; + var schema; + var store; + + if (isLegacyDimensionsInput(dimensionsInput)) { + dimensionDefineList = dimensionsInput; + } else { + schema = dimensionsInput.schema; + dimensionDefineList = schema.dimensions; + store = dimensionsInput.store; + } // Compatibal: when `stack` is set as '', do not stack. + + + var mayStack = !!(seriesModel && seriesModel.get('stack')); + var stackedByDimInfo; + var stackedDimInfo; + var stackResultDimension; + var stackedOverDimension; + each$4(dimensionDefineList, function (dimensionInfo, index) { + if (isString(dimensionInfo)) { + dimensionDefineList[index] = dimensionInfo = { + name: dimensionInfo + }; + } + + if (mayStack && !dimensionInfo.isExtraCoord) { + // Find the first ordinal dimension as the stackedByDimInfo. + if (!byIndex && !stackedByDimInfo && dimensionInfo.ordinalMeta) { + stackedByDimInfo = dimensionInfo; + } // Find the first stackable dimension as the stackedDimInfo. + + + if (!stackedDimInfo && dimensionInfo.type !== 'ordinal' && dimensionInfo.type !== 'time' && (!stackedCoordDimension || stackedCoordDimension === dimensionInfo.coordDim)) { + stackedDimInfo = dimensionInfo; + } + } + }); + + if (stackedDimInfo && !byIndex && !stackedByDimInfo) { + // Compatible with previous design, value axis (time axis) only stack by index. + // It may make sense if the user provides elaborately constructed data. + byIndex = true; + } // Add stack dimension, they can be both calculated by coordinate system in `unionExtent`. + // That put stack logic in List is for using conveniently in echarts extensions, but it + // might not be a good way. + + + if (stackedDimInfo) { + // Use a weird name that not duplicated with other names. + // Also need to use seriesModel.id as postfix because different + // series may share same data store. The stack dimension needs to be distinguished. + stackResultDimension = '__\0ecstackresult_' + seriesModel.id; + stackedOverDimension = '__\0ecstackedover_' + seriesModel.id; // Create inverted index to fast query index by value. + + if (stackedByDimInfo) { + stackedByDimInfo.createInvertedIndices = true; + } + + var stackedDimCoordDim_1 = stackedDimInfo.coordDim; + var stackedDimType = stackedDimInfo.type; + var stackedDimCoordIndex_1 = 0; + each$4(dimensionDefineList, function (dimensionInfo) { + if (dimensionInfo.coordDim === stackedDimCoordDim_1) { + stackedDimCoordIndex_1++; + } + }); + var stackedOverDimensionDefine = { + name: stackResultDimension, + coordDim: stackedDimCoordDim_1, + coordDimIndex: stackedDimCoordIndex_1, + type: stackedDimType, + isExtraCoord: true, + isCalculationCoord: true, + storeDimIndex: dimensionDefineList.length + }; + var stackResultDimensionDefine = { + name: stackedOverDimension, + // This dimension contains stack base (generally, 0), so do not set it as + // `stackedDimCoordDim` to avoid extent calculation, consider log scale. + coordDim: stackedOverDimension, + coordDimIndex: stackedDimCoordIndex_1 + 1, + type: stackedDimType, + isExtraCoord: true, + isCalculationCoord: true, + storeDimIndex: dimensionDefineList.length + 1 + }; + + if (schema) { + if (store) { + stackedOverDimensionDefine.storeDimIndex = store.ensureCalculationDimension(stackedOverDimension, stackedDimType); + stackResultDimensionDefine.storeDimIndex = store.ensureCalculationDimension(stackResultDimension, stackedDimType); + } + + schema.appendCalculationDimension(stackedOverDimensionDefine); + schema.appendCalculationDimension(stackResultDimensionDefine); + } else { + dimensionDefineList.push(stackedOverDimensionDefine); + dimensionDefineList.push(stackResultDimensionDefine); + } + } + + return { + stackedDimension: stackedDimInfo && stackedDimInfo.name, + stackedByDimension: stackedByDimInfo && stackedByDimInfo.name, + isStackedByIndex: byIndex, + stackedOverDimension: stackedOverDimension, + stackResultDimension: stackResultDimension + }; + } + + function isLegacyDimensionsInput(dimensionsInput) { + return !isSeriesDataSchema(dimensionsInput.schema); + } + + function isDimensionStacked(data, stackedDim) { + // Each single series only maps to one pair of axis. So we do not need to + // check stackByDim, whatever stacked by a dimension or stacked by index. + return !!stackedDim && stackedDim === data.getCalculationInfo('stackedDimension'); + } + + function getStackedDimension(data, targetDim) { + return isDimensionStacked(data, targetDim) ? data.getCalculationInfo('stackResultDimension') : targetDim; + } + + function getCoordSysDimDefs(seriesModel, coordSysInfo) { + var coordSysName = seriesModel.get('coordinateSystem'); + var registeredCoordSys = CoordinateSystemManager.get(coordSysName); + var coordSysDimDefs; + + if (coordSysInfo && coordSysInfo.coordSysDims) { + coordSysDimDefs = map$1(coordSysInfo.coordSysDims, function (dim) { + var dimInfo = { + name: dim + }; + var axisModel = coordSysInfo.axisMap.get(dim); + + if (axisModel) { + var axisType = axisModel.get('type'); + dimInfo.type = getDimensionTypeByAxis(axisType); + } + + return dimInfo; + }); + } + + if (!coordSysDimDefs) { + // Get dimensions from registered coordinate system + coordSysDimDefs = registeredCoordSys && (registeredCoordSys.getDimensionsInfo ? registeredCoordSys.getDimensionsInfo() : registeredCoordSys.dimensions.slice()) || ['x', 'y']; + } + + return coordSysDimDefs; + } + + function injectOrdinalMeta(dimInfoList, createInvertedIndices, coordSysInfo) { + var firstCategoryDimIndex; + var hasNameEncode; + coordSysInfo && each$4(dimInfoList, function (dimInfo, dimIndex) { + var coordDim = dimInfo.coordDim; + var categoryAxisModel = coordSysInfo.categoryAxisMap.get(coordDim); + + if (categoryAxisModel) { + if (firstCategoryDimIndex == null) { + firstCategoryDimIndex = dimIndex; + } + + dimInfo.ordinalMeta = categoryAxisModel.getOrdinalMeta(); + + if (createInvertedIndices) { + dimInfo.createInvertedIndices = true; + } + } + + if (dimInfo.otherDims.itemName != null) { + hasNameEncode = true; + } + }); + + if (!hasNameEncode && firstCategoryDimIndex != null) { + dimInfoList[firstCategoryDimIndex].otherDims.itemName = 0; + } + + return firstCategoryDimIndex; + } + /** + * Caution: there are side effects to `sourceManager` in this method. + * Should better only be called in `Series['getInitialData']`. + */ + + + function createSeriesData(sourceRaw, seriesModel, opt) { + opt = opt || {}; + var sourceManager = seriesModel.getSourceManager(); + var source; + var isOriginalSource = false; + + if (sourceRaw) { + isOriginalSource = true; + source = createSourceFromSeriesDataOption(sourceRaw); + } else { + source = sourceManager.getSource(); // Is series.data. not dataset. + + isOriginalSource = source.sourceFormat === SOURCE_FORMAT_ORIGINAL; + } + + var coordSysInfo = getCoordSysInfoBySeries(seriesModel); + var coordSysDimDefs = getCoordSysDimDefs(seriesModel, coordSysInfo); + var useEncodeDefaulter = opt.useEncodeDefaulter; + var encodeDefaulter = isFunction(useEncodeDefaulter) ? useEncodeDefaulter : useEncodeDefaulter ? curry$1(makeSeriesEncodeForAxisCoordSys, coordSysDimDefs, seriesModel) : null; + var createDimensionOptions = { + coordDimensions: coordSysDimDefs, + generateCoord: opt.generateCoord, + encodeDefine: seriesModel.getEncode(), + encodeDefaulter: encodeDefaulter, + canOmitUnusedDimensions: !isOriginalSource + }; + var schema = prepareSeriesDataSchema(source, createDimensionOptions); + var firstCategoryDimIndex = injectOrdinalMeta(schema.dimensions, opt.createInvertedIndices, coordSysInfo); + var store = !isOriginalSource ? sourceManager.getSharedDataStore(schema) : null; + var stackCalculationInfo = enableDataStack(seriesModel, { + schema: schema, + store: store + }); + var data = new SeriesData(schema, seriesModel); + data.setCalculationInfo(stackCalculationInfo); + var dimValueGetter = firstCategoryDimIndex != null && isNeedCompleteOrdinalData(source) + /** + * This serves this case: + * var echarts_option = { + * xAxis: { data: ['a', 'b', 'c'] }, + * yAxis: {} + * series: { data: [555, 666, 777] } + * }; + * The `series.data` is completed to: + * [[0, 555], [1, 666], [2, 777]] + */ + ? function (itemOpt, dimName, dataIndex, dimIndex) { + // Use dataIndex as ordinal value in categoryAxis + return dimIndex === firstCategoryDimIndex ? dataIndex : this.defaultDimValueGetter(itemOpt, dimName, dataIndex, dimIndex); + } : null; + data.hasItemOption = false; + data.initData( // Try to reuse the data store in sourceManager if using dataset. + isOriginalSource ? source : store, null, dimValueGetter); + return data; + } + + function isNeedCompleteOrdinalData(source) { + if (source.sourceFormat === SOURCE_FORMAT_ORIGINAL) { + var sampleItem = firstDataNotNull(source.data || []); + return !isArray(getDataItemValue(sampleItem)); + } + } + + function firstDataNotNull(arr) { + var i = 0; + + while (i < arr.length && arr[i] == null) { + i++; + } + + return arr[i]; + } + + function isValueNice(val) { + var exp10 = Math.pow(10, quantityExponent(Math.abs(val))); + var f = Math.abs(val / exp10); + return f === 0 || f === 1 || f === 2 || f === 3 || f === 5; + } + + function isIntervalOrLogScale(scale) { + return scale.type === 'interval' || scale.type === 'log'; + } + /** + * @param extent Both extent[0] and extent[1] should be valid number. + * Should be extent[0] < extent[1]. + * @param splitNumber splitNumber should be >= 1. + */ + + + function intervalScaleNiceTicks(extent, spanWithBreaks, splitNumber, minInterval, maxInterval) { + var result = {}; + var interval = result.interval = nice(spanWithBreaks / splitNumber, true); + + if (minInterval != null && interval < minInterval) { + interval = result.interval = minInterval; + } + + if (maxInterval != null && interval > maxInterval) { + interval = result.interval = maxInterval; + } // Tow more digital for tick. + + + var precision = result.intervalPrecision = getIntervalPrecision(interval); // Niced extent inside original extent + + var niceTickExtent = result.niceTickExtent = [round$1(Math.ceil(extent[0] / interval) * interval, precision), round$1(Math.floor(extent[1] / interval) * interval, precision)]; + fixExtent(niceTickExtent, extent); + return result; + } + + function increaseInterval(interval) { + var exp10 = Math.pow(10, quantityExponent(interval)); // Increase interval + + var f = interval / exp10; + + if (!f) { + f = 1; + } else if (f === 2) { + f = 3; + } else if (f === 3) { + f = 5; + } else { + // f is 1 or 5 + f *= 2; + } + + return round$1(f * exp10); + } + /** + * @return interval precision + */ + + + function getIntervalPrecision(interval) { + // Tow more digital for tick. + return getPrecision(interval) + 2; + } + + function clamp(niceTickExtent, idx, extent) { + niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]); + } // In some cases (e.g., splitNumber is 1), niceTickExtent may be out of extent. + + + function fixExtent(niceTickExtent, extent) { + !isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]); + !isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]); + clamp(niceTickExtent, 0, extent); + clamp(niceTickExtent, 1, extent); + + if (niceTickExtent[0] > niceTickExtent[1]) { + niceTickExtent[0] = niceTickExtent[1]; + } + } + + function contain$1(val, extent) { + return val >= extent[0] && val <= extent[1]; + } + + var ScaleCalculator = + /** @class */ + function () { + function ScaleCalculator() { + this.normalize = normalize; + this.scale = scale; + } + + ScaleCalculator.prototype.updateMethods = function (brkCtx) { + if (brkCtx.hasBreaks()) { + this.normalize = bind$1(brkCtx.normalize, brkCtx); + this.scale = bind$1(brkCtx.scale, brkCtx); + } else { + this.normalize = normalize; + this.scale = scale; + } + }; + + return ScaleCalculator; + }(); + + function normalize(val, extent) { + if (extent[1] === extent[0]) { + return 0.5; + } + + return (val - extent[0]) / (extent[1] - extent[0]); + } + + function scale(val, extent) { + return val * (extent[1] - extent[0]) + extent[0]; + } + + function logTransform(base, extent, noClampNegative) { + var loggedBase = Math.log(base); + return [// log(negative) is NaN, so safe guard here. + // PENDING: But even getting a -Infinity still does not make sense in extent. + // Just keep it as is, getting a NaN to make some previous cases works by coincidence. + Math.log(noClampNegative ? extent[0] : Math.max(0, extent[0])) / loggedBase, Math.log(noClampNegative ? extent[1] : Math.max(0, extent[1])) / loggedBase]; + } + + var Scale = + /** @class */ + function () { + function Scale(setting) { + this._calculator = new ScaleCalculator(); + this._setting = setting || {}; + this._extent = [Infinity, -Infinity]; + } + + Scale.prototype.getSetting = function (name) { + return this._setting[name]; + }; + /** + * [CAVEAT]: It should not be overridden! + */ + + + Scale.prototype._innerUnionExtent = function (other) { + var extent = this._extent; // Considered that number could be NaN and should not write into the extent. + + this._innerSetExtent(other[0] < extent[0] ? other[0] : extent[0], other[1] > extent[1] ? other[1] : extent[1]); + }; + /** + * Set extent from data + */ + + + Scale.prototype.unionExtentFromData = function (data, dim) { + this._innerUnionExtent(data.getApproximateExtent(dim)); + }; + /** + * Get a new slice of extent. + * Extent is always in increase order. + */ + + + Scale.prototype.getExtent = function () { + return this._extent.slice(); + }; + + Scale.prototype.setExtent = function (start, end) { + this._innerSetExtent(start, end); + }; + /** + * [CAVEAT]: It should not be overridden! + */ + + + Scale.prototype._innerSetExtent = function (start, end) { + var thisExtent = this._extent; + + if (!isNaN(start)) { + thisExtent[0] = start; + } + + if (!isNaN(end)) { + thisExtent[1] = end; + } + + this._brkCtx && this._brkCtx.update(thisExtent); + }; + /** + * Prerequisite: Scale#parse is ready. + */ + + + Scale.prototype.setBreaksFromOption = function (breakOptionList) {}; + /** + * [CAVEAT]: It should not be overridden! + */ + + + Scale.prototype._innerSetBreak = function (parsed) { + if (this._brkCtx) { + this._brkCtx.setBreaks(parsed); + + this._calculator.updateMethods(this._brkCtx); + + this._brkCtx.update(this._extent); + } + }; + /** + * [CAVEAT]: It should not be overridden! + */ + + + Scale.prototype._innerGetBreaks = function () { + return this._brkCtx ? this._brkCtx.breaks : []; + }; + /** + * Do not expose the internal `_breaks` unless necessary. + */ + + + Scale.prototype.hasBreaks = function () { + return this._brkCtx ? this._brkCtx.hasBreaks() : false; + }; + + Scale.prototype._getExtentSpanWithBreaks = function () { + return this._brkCtx && this._brkCtx.hasBreaks() ? this._brkCtx.getExtentSpan() : this._extent[1] - this._extent[0]; + }; + /** + * If value is in extent range + */ + + + Scale.prototype.isInExtentRange = function (value) { + return this._extent[0] <= value && this._extent[1] >= value; + }; + /** + * When axis extent depends on data and no data exists, + * axis ticks should not be drawn, which is named 'blank'. + */ + + + Scale.prototype.isBlank = function () { + return this._isBlank; + }; + /** + * When axis extent depends on data and no data exists, + * axis ticks should not be drawn, which is named 'blank'. + */ + + + Scale.prototype.setBlank = function (isBlank) { + this._isBlank = isBlank; + }; + + return Scale; + }(); + + enableClassManagement(Scale); + var uidBase = 0; + + var OrdinalMeta = + /** @class */ + function () { + /** + * PENDING - Regarding forcibly converting to string: + * In the early days, the underlying hash map impl used JS plain object and converted the key to + * string; later in https://github.com/ecomfe/zrender/pull/966 it was changed to a JS Map (in supported + * platforms), which does not require string keys. But consider any input that `scale/Ordinal['parse']` + * is involved, a number input represents an `OrdinalNumber` (i.e., an index), and affect the query + * behavior: + * - If forcbily converting to string: + * pros: users can use numeric string (such as, '123') to query the raw data (123), tho it's probably + * still confusing. + * cons: NaN/null/undefined in data will be equals to 'NaN'/'null'/'undefined', if simply using + * `val + ''` to convert them, like currently `getName` does. + * - Otherwise: + * pros: see NaN/null/undefined case above. + * cons: users cannot query the raw data (123) any more. + * There are two inconsistent behaviors in the current impl: + * - Force conversion is applied on the case `xAxis{data: ['aaa', 'bbb', ...]}`, + * but no conversion applied to the case `xAxis{data: [{value: 'aaa'}, ...]}` and + * the case `dataset: {source: [['aaa', 123], ['bbb', 234], ...]}`. + * - behaves differently according to whether JS Map is supported (the polyfill is simply using JS + * plain object) (tho it seems rare platform that do not support it). + * Since there's no sufficient good solution to offset cost of the breaking change, we preserve the + * current behavior, until real issues is reported. + */ + function OrdinalMeta(opt) { + this.categories = opt.categories || []; + this._needCollect = opt.needCollect; + this._deduplication = opt.deduplication; + this.uid = ++uidBase; + this._onCollect = opt.onCollect; + } + + OrdinalMeta.createByAxisModel = function (axisModel) { + var option = axisModel.option; + var data = option.data; + var categories = data && map$1(data, getName); + return new OrdinalMeta({ + categories: categories, + needCollect: !categories, + // deduplication is default in axis. + deduplication: option.dedplication !== false + }); + }; + + OrdinalMeta.prototype.getOrdinal = function (category) { + return this._getOrCreateMap().get(category); + }; + /** + * @return The ordinal. If not found, return NaN. + */ + + + OrdinalMeta.prototype.parseAndCollect = function (category) { + var index; + var needCollect = this._needCollect; // The value of category dim can be the index of the given category set. + // This feature is only supported when !needCollect, because we should + // consider a common case: a value is 2017, which is a number but is + // expected to be tread as a category. This case usually happen in dataset, + // where it happent to be no need of the index feature. + + if (!isString(category) && !needCollect) { + return category; + } // Optimize for the scenario: + // category is ['2012-01-01', '2012-01-02', ...], where the input + // data has been ensured not duplicate and is large data. + // Notice, if a dataset dimension provide categroies, usually echarts + // should remove duplication except user tell echarts dont do that + // (set axis.deduplication = false), because echarts do not know whether + // the values in the category dimension has duplication (consider the + // parallel-aqi example) + + + if (needCollect && !this._deduplication) { + index = this.categories.length; + this.categories[index] = category; + this._onCollect && this._onCollect(category, index); + return index; + } + + var map = this._getOrCreateMap(); + + index = map.get(category); + + if (index == null) { + if (needCollect) { + index = this.categories.length; + this.categories[index] = category; + map.set(category, index); + this._onCollect && this._onCollect(category, index); + } else { + index = NaN; + } + } + + return index; + }; // Consider big data, do not create map until needed. + + + OrdinalMeta.prototype._getOrCreateMap = function () { + return this._map || (this._map = createHashMap(this.categories)); + }; + + return OrdinalMeta; + }(); + + function getName(obj) { + if (isObject$2(obj) && obj.value != null) { + return obj.value; + } else { + return obj + ''; + } + } + + var OrdinalScale = + /** @class */ + function (_super) { + __extends(OrdinalScale, _super); + + function OrdinalScale(setting) { + var _this = _super.call(this, setting) || this; + + _this.type = 'ordinal'; + + var ordinalMeta = _this.getSetting('ordinalMeta'); // Caution: Should not use instanceof, consider ec-extensions using + // import approach to get OrdinalMeta class. + + + if (!ordinalMeta) { + ordinalMeta = new OrdinalMeta({}); + } + + if (isArray(ordinalMeta)) { + ordinalMeta = new OrdinalMeta({ + categories: map$1(ordinalMeta, function (item) { + return isObject$2(item) ? item.value : item; + }) + }); + } + + _this._ordinalMeta = ordinalMeta; + _this._extent = _this.getSetting('extent') || [0, ordinalMeta.categories.length - 1]; + return _this; + } + + OrdinalScale.prototype.parse = function (val) { + // Caution: Math.round(null) will return `0` rather than `NaN` + if (val == null) { + return NaN; + } + + return isString(val) ? this._ordinalMeta.getOrdinal(val) // val might be float. + : Math.round(val); + }; + + OrdinalScale.prototype.contain = function (val) { + return contain$1(val, this._extent) && val >= 0 && val < this._ordinalMeta.categories.length; + }; + /** + * Normalize given rank or name to linear [0, 1] + * @param val raw ordinal number. + * @return normalized value in [0, 1]. + */ + + + OrdinalScale.prototype.normalize = function (val) { + val = this._getTickNumber(val); + return this._calculator.normalize(val, this._extent); + }; + /** + * @param val normalized value in [0, 1]. + * @return raw ordinal number. + */ + + + OrdinalScale.prototype.scale = function (val) { + val = Math.round(this._calculator.scale(val, this._extent)); + return this.getRawOrdinalNumber(val); + }; + + OrdinalScale.prototype.getTicks = function () { + var ticks = []; + var extent = this._extent; + var rank = extent[0]; + + while (rank <= extent[1]) { + ticks.push({ + value: rank + }); + rank++; + } + + return ticks; + }; + + OrdinalScale.prototype.getMinorTicks = function (splitNumber) { + // Not support. + return; + }; + /** + * @see `Ordinal['_ordinalNumbersByTick']` + */ + + + OrdinalScale.prototype.setSortInfo = function (info) { + if (info == null) { + this._ordinalNumbersByTick = this._ticksByOrdinalNumber = null; + return; + } + + var infoOrdinalNumbers = info.ordinalNumbers; + var ordinalsByTick = this._ordinalNumbersByTick = []; + var ticksByOrdinal = this._ticksByOrdinalNumber = []; // Unnecessary support negative tick in `realtimeSort`. + + var tickNum = 0; + var allCategoryLen = this._ordinalMeta.categories.length; + + for (var len = Math.min(allCategoryLen, infoOrdinalNumbers.length); tickNum < len; ++tickNum) { + var ordinalNumber = infoOrdinalNumbers[tickNum]; + ordinalsByTick[tickNum] = ordinalNumber; + ticksByOrdinal[ordinalNumber] = tickNum; + } // Handle that `series.data` only covers part of the `axis.category.data`. + + + var unusedOrdinal = 0; + + for (; tickNum < allCategoryLen; ++tickNum) { + while (ticksByOrdinal[unusedOrdinal] != null) { + unusedOrdinal++; + } + + ordinalsByTick.push(unusedOrdinal); + ticksByOrdinal[unusedOrdinal] = tickNum; + } + }; + + OrdinalScale.prototype._getTickNumber = function (ordinal) { + var ticksByOrdinalNumber = this._ticksByOrdinalNumber; // also support ordinal out of range of `ordinalMeta.categories.length`, + // where ordinal numbers are used as tick value directly. + + return ticksByOrdinalNumber && ordinal >= 0 && ordinal < ticksByOrdinalNumber.length ? ticksByOrdinalNumber[ordinal] : ordinal; + }; + /** + * @usage + * ```js + * const ordinalNumber = ordinalScale.getRawOrdinalNumber(tickVal); + * + * // case0 + * const rawOrdinalValue = axisModel.getCategories()[ordinalNumber]; + * // case1 + * const rawOrdinalValue = this._ordinalMeta.categories[ordinalNumber]; + * // case2 + * const coord = axis.dataToCoord(ordinalNumber); + * ``` + * + * @param {OrdinalNumber} tickNumber index of display + */ + + + OrdinalScale.prototype.getRawOrdinalNumber = function (tickNumber) { + var ordinalNumbersByTick = this._ordinalNumbersByTick; // tickNumber may be out of range, e.g., when axis max is larger than `ordinalMeta.categories.length`., + // where ordinal numbers are used as tick value directly. + + return ordinalNumbersByTick && tickNumber >= 0 && tickNumber < ordinalNumbersByTick.length ? ordinalNumbersByTick[tickNumber] : tickNumber; + }; + /** + * Get item on tick + */ + + + OrdinalScale.prototype.getLabel = function (tick) { + if (!this.isBlank()) { + var ordinalNumber = this.getRawOrdinalNumber(tick.value); + var cateogry = this._ordinalMeta.categories[ordinalNumber]; // Note that if no data, ordinalMeta.categories is an empty array. + // Return empty if it's not exist. + + return cateogry == null ? '' : cateogry + ''; + } + }; + + OrdinalScale.prototype.count = function () { + return this._extent[1] - this._extent[0] + 1; + }; + /** + * @override + * If value is in extent range + */ + + + OrdinalScale.prototype.isInExtentRange = function (value) { + value = this._getTickNumber(value); + return this._extent[0] <= value && this._extent[1] >= value; + }; + + OrdinalScale.prototype.getOrdinalMeta = function () { + return this._ordinalMeta; + }; + + OrdinalScale.prototype.calcNiceTicks = function () {}; + + OrdinalScale.prototype.calcNiceExtent = function () {}; + + OrdinalScale.type = 'ordinal'; + return OrdinalScale; + }(Scale); + + Scale.registerClass(OrdinalScale); + var roundNumber = round$1; + + var IntervalScale = + /** @class */ + function (_super) { + __extends(IntervalScale, _super); + + function IntervalScale() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'interval'; // Step is calculated in adjustExtent. + + _this._interval = 0; + _this._intervalPrecision = 2; + return _this; + } + + IntervalScale.prototype.parse = function (val) { + // `Scale#parse` (and its overrids) are typically applied at the axis values input + // in echarts option. e.g., `axis.min/max`, `dataZoom.min/max`, etc. + // but `series.data` is not included, which uses `dataValueHelper.ts`#`parseDataValue`. + // `Scale#parse` originally introduced in fb8c813215098b9d2458966229bb95c510883d5e + // at 2016 for dataZoom start/end settings (See `parseAxisModelMinMax`). + // + // Historically `scale/Interval.ts` returns the input value directly. But numeric + // values (such as a number-like string '123') effectively passed through here and + // were involved in calculations, which was error-prone and inconsistent with the + // declared TS return type. Previously such issues are fixed separately in different + // places case by case (such as #2475). + // + // Now, we perform actual parse to ensure its `number` type here. The parsing rule + // follows the series data parsing rule (`dataValueHelper.ts`#`parseDataValue`) + // and maintains compatibility as much as possible (thus a more strict parsing + // `number.ts`#`numericToNumber` is not used here.) + // + // FIXME: `ScaleDataValue` also need to be modified to include numeric string type, + // since it effectively does. + return val == null || val === '' ? NaN // If string (like '-'), using '+' parse to NaN + // If object, also parse to NaN + : Number(val); + }; + + IntervalScale.prototype.contain = function (val) { + return contain$1(val, this._extent); + }; + + IntervalScale.prototype.normalize = function (val) { + return this._calculator.normalize(val, this._extent); + }; + + IntervalScale.prototype.scale = function (val) { + return this._calculator.scale(val, this._extent); + }; + + IntervalScale.prototype.getInterval = function () { + return this._interval; + }; + + IntervalScale.prototype.setInterval = function (interval) { + this._interval = interval; // Dropped auto calculated niceExtent and use user-set extent. + // We assume user wants to set both interval, min, max to get a better result. + + this._niceExtent = this._extent.slice(); + this._intervalPrecision = getIntervalPrecision(interval); + }; + /** + * @override + */ + + + IntervalScale.prototype.getTicks = function (opt) { + opt = opt || {}; + var interval = this._interval; + var extent = this._extent; + var niceTickExtent = this._niceExtent; + var intervalPrecision = this._intervalPrecision; + var scaleBreakHelper = getScaleBreakHelper(); + var ticks = []; // If interval is 0, return []; + + if (!interval) { + return ticks; + } + + if (opt.breakTicks === 'only_break' && scaleBreakHelper) { + scaleBreakHelper.addBreaksToTicks(ticks, this._brkCtx.breaks, this._extent); + return ticks; + } // Consider this case: using dataZoom toolbox, zoom and zoom. + + + var safeLimit = 10000; + + if (extent[0] < niceTickExtent[0]) { + if (opt.expandToNicedExtent) { + ticks.push({ + value: roundNumber(niceTickExtent[0] - interval, intervalPrecision) + }); + } else { + ticks.push({ + value: extent[0] + }); + } + } + + var estimateNiceMultiple = function (tickVal, targetTick) { + return Math.round((targetTick - tickVal) / interval); + }; + + var tick = niceTickExtent[0]; + + while (tick <= niceTickExtent[1]) { + ticks.push({ + value: tick + }); // Avoid rounding error + + tick = roundNumber(tick + interval, intervalPrecision); + + if (this._brkCtx) { + var moreMultiple = this._brkCtx.calcNiceTickMultiple(tick, estimateNiceMultiple); + + if (moreMultiple >= 0) { + tick = roundNumber(tick + moreMultiple * interval, intervalPrecision); + } + } + + if (ticks.length > 0 && tick === ticks[ticks.length - 1].value) { + // Consider out of safe float point, e.g., + // -3711126.9907707 + 2e-10 === -3711126.9907707 + break; + } + + if (ticks.length > safeLimit) { + return []; + } + } // Consider this case: the last item of ticks is smaller + // than niceTickExtent[1] and niceTickExtent[1] === extent[1]. + + + var lastNiceTick = ticks.length ? ticks[ticks.length - 1].value : niceTickExtent[1]; + + if (extent[1] > lastNiceTick) { + if (opt.expandToNicedExtent) { + ticks.push({ + value: roundNumber(lastNiceTick + interval, intervalPrecision) + }); + } else { + ticks.push({ + value: extent[1] + }); + } + } + + if (opt.breakTicks !== 'none' && scaleBreakHelper) { + scaleBreakHelper.addBreaksToTicks(ticks, this._brkCtx.breaks, this._extent); + } + + return ticks; + }; + + IntervalScale.prototype.getMinorTicks = function (splitNumber) { + var ticks = this.getTicks({ + expandToNicedExtent: true + }); // NOTE: In log-scale, do not support minor ticks when breaks exist. + // because currently log-scale minor ticks is calculated based on raw values + // rather than log-transformed value, due to an odd effect when breaks exist. + + var minorTicks = []; + var extent = this.getExtent(); + + for (var i = 1; i < ticks.length; i++) { + var nextTick = ticks[i]; + var prevTick = ticks[i - 1]; + + if (prevTick["break"] || nextTick["break"]) { + // Do not build minor ticks to the adjacent ticks to breaks ticks, + // since the interval might be irregular. + continue; + } + + var count = 0; + var minorTicksGroup = []; + var interval = nextTick.value - prevTick.value; + var minorInterval = interval / splitNumber; + var minorIntervalPrecision = getIntervalPrecision(minorInterval); + + while (count < splitNumber - 1) { + var minorTick = roundNumber(prevTick.value + (count + 1) * minorInterval, minorIntervalPrecision); // For the first and last interval. The count may be less than splitNumber. + + if (minorTick > extent[0] && minorTick < extent[1]) { + minorTicksGroup.push(minorTick); + } + + count++; + } + + var scaleBreakHelper = getScaleBreakHelper(); + scaleBreakHelper && scaleBreakHelper.pruneTicksByBreak('auto', minorTicksGroup, this._getNonTransBreaks(), function (value) { + return value; + }, this._interval, extent); + minorTicks.push(minorTicksGroup); + } + + return minorTicks; + }; + + IntervalScale.prototype._getNonTransBreaks = function () { + return this._brkCtx ? this._brkCtx.breaks : []; + }; + /** + * @param opt.precision If 'auto', use nice presision. + * @param opt.pad returns 1.50 but not 1.5 if precision is 2. + */ + + + IntervalScale.prototype.getLabel = function (data, opt) { + if (data == null) { + return ''; + } + + var precision = opt && opt.precision; + + if (precision == null) { + precision = getPrecision(data.value) || 0; + } else if (precision === 'auto') { + // Should be more precise then tick. + precision = this._intervalPrecision; + } // (1) If `precision` is set, 12.005 should be display as '12.00500'. + // (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'. + + + var dataNum = roundNumber(data.value, precision, true); + return addCommas(dataNum); + }; + /** + * FIXME: refactor - disallow override, use composition instead. + * + * The override of `calcNiceTicks` should ensure these members are provided: + * this._intervalPrecision + * this._interval + * + * @param splitNumber By default `5`. + */ + + + IntervalScale.prototype.calcNiceTicks = function (splitNumber, minInterval, maxInterval) { + splitNumber = splitNumber || 5; + + var extent = this._extent.slice(); + + var span = this._getExtentSpanWithBreaks(); + + if (!isFinite(span)) { + return; + } // User may set axis min 0 and data are all negative + // FIXME If it needs to reverse ? + + + if (span < 0) { + span = -span; + extent.reverse(); + + this._innerSetExtent(extent[0], extent[1]); + + extent = this._extent.slice(); + } + + var result = intervalScaleNiceTicks(extent, span, splitNumber, minInterval, maxInterval); + this._intervalPrecision = result.intervalPrecision; + this._interval = result.interval; + this._niceExtent = result.niceTickExtent; + }; + + IntervalScale.prototype.calcNiceExtent = function (opt) { + var extent = this._extent.slice(); // If extent start and end are same, expand them + + + if (extent[0] === extent[1]) { + if (extent[0] !== 0) { + // Expand extent + // Note that extents can be both negative. See #13154 + var expandSize = Math.abs(extent[0]); // In the fowllowing case + // Axis has been fixed max 100 + // Plus data are all 100 and axis extent are [100, 100]. + // Extend to the both side will cause expanded max is larger than fixed max. + // So only expand to the smaller side. + + if (!opt.fixMax) { + extent[1] += expandSize / 2; + extent[0] -= expandSize / 2; + } else { + extent[0] -= expandSize / 2; + } + } else { + extent[1] = 1; + } + } + + var span = extent[1] - extent[0]; // If there are no data and extent are [Infinity, -Infinity] + + if (!isFinite(span)) { + extent[0] = 0; + extent[1] = 1; + } + + this._innerSetExtent(extent[0], extent[1]); + + extent = this._extent.slice(); + this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval); + var interval = this._interval; + var intervalPrecition = this._intervalPrecision; + + if (!opt.fixMin) { + extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval, intervalPrecition); + } + + if (!opt.fixMax) { + extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval, intervalPrecition); + } + + this._innerSetExtent(extent[0], extent[1]); + }; + + IntervalScale.prototype.setNiceExtent = function (min, max) { + this._niceExtent = [min, max]; + }; + + IntervalScale.type = 'interval'; + return IntervalScale; + }(Scale); + + Scale.registerClass(IntervalScale); + /* global Float32Array */ + + var supportFloat32Array = typeof Float32Array !== 'undefined'; + var Float32ArrayCtor = !supportFloat32Array ? Array : Float32Array; + + function createFloat32Array(arg) { + if (isArray(arg)) { + // Return self directly if don't support TypedArray. + return supportFloat32Array ? new Float32Array(arg) : arg; + } // Else is number + + + return new Float32ArrayCtor(arg); + } + + var STACK_PREFIX = '__ec_stack_'; + + function getSeriesStackId(seriesModel) { + return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex; + } + + function getAxisKey(axis) { + return axis.dim + axis.index; + } + + function prepareLayoutBarSeries(seriesType, ecModel) { + var seriesModels = []; + ecModel.eachSeriesByType(seriesType, function (seriesModel) { + // Check series coordinate, do layout for cartesian2d only + if (isOnCartesian(seriesModel)) { + seriesModels.push(seriesModel); + } + }); + return seriesModels; + } + /** + * Map from (baseAxis.dim + '_' + baseAxis.index) to min gap of two adjacent + * values. + * This works for time axes, value axes, and log axes. + * For a single time axis, return value is in the form like + * {'x_0': [1000000]}. + * The value of 1000000 is in milliseconds. + */ + + + function getValueAxesMinGaps(barSeries) { + /** + * Map from axis.index to values. + * For a single time axis, axisValues is in the form like + * {'x_0': [1495555200000, 1495641600000, 1495728000000]}. + * Items in axisValues[x], e.g. 1495555200000, are time values of all + * series. + */ + var axisValues = {}; + each$4(barSeries, function (seriesModel) { + var cartesian = seriesModel.coordinateSystem; + var baseAxis = cartesian.getBaseAxis(); + + if (baseAxis.type !== 'time' && baseAxis.type !== 'value') { + return; + } + + var data = seriesModel.getData(); + var key = baseAxis.dim + '_' + baseAxis.index; + var dimIdx = data.getDimensionIndex(data.mapDimension(baseAxis.dim)); + var store = data.getStore(); + + for (var i = 0, cnt = store.count(); i < cnt; ++i) { + var value = store.get(dimIdx, i); + + if (!axisValues[key]) { + // No previous data for the axis + axisValues[key] = [value]; + } else { + // No value in previous series + axisValues[key].push(value); + } // Ignore duplicated time values in the same axis + + } + }); + var axisMinGaps = {}; + + for (var key in axisValues) { + if (axisValues.hasOwnProperty(key)) { + var valuesInAxis = axisValues[key]; + + if (valuesInAxis) { + // Sort axis values into ascending order to calculate gaps + valuesInAxis.sort(function (a, b) { + return a - b; + }); + var min = null; + + for (var j = 1; j < valuesInAxis.length; ++j) { + var delta = valuesInAxis[j] - valuesInAxis[j - 1]; + + if (delta > 0) { + // Ignore 0 delta because they are of the same axis value + min = min === null ? delta : Math.min(min, delta); + } + } // Set to null if only have one data + + + axisMinGaps[key] = min; + } + } + } + + return axisMinGaps; + } + + function makeColumnLayout(barSeries) { + var axisMinGaps = getValueAxesMinGaps(barSeries); + var seriesInfoList = []; + each$4(barSeries, function (seriesModel) { + var cartesian = seriesModel.coordinateSystem; + var baseAxis = cartesian.getBaseAxis(); + var axisExtent = baseAxis.getExtent(); + var bandWidth; + + if (baseAxis.type === 'category') { + bandWidth = baseAxis.getBandWidth(); + } else if (baseAxis.type === 'value' || baseAxis.type === 'time') { + var key = baseAxis.dim + '_' + baseAxis.index; + var minGap = axisMinGaps[key]; + var extentSpan = Math.abs(axisExtent[1] - axisExtent[0]); + var scale = baseAxis.scale.getExtent(); + var scaleSpan = Math.abs(scale[1] - scale[0]); + bandWidth = minGap ? extentSpan / scaleSpan * minGap : extentSpan; // When there is only one data value + } else { + var data = seriesModel.getData(); + bandWidth = Math.abs(axisExtent[1] - axisExtent[0]) / data.count(); + } + + var barWidth = parsePercent(seriesModel.get('barWidth'), bandWidth); + var barMaxWidth = parsePercent(seriesModel.get('barMaxWidth'), bandWidth); + var barMinWidth = parsePercent( // barMinWidth by default is 0.5 / 1 in cartesian. Because in value axis, + // the auto-calculated bar width might be less than 0.5 / 1. + seriesModel.get('barMinWidth') || (isInLargeMode(seriesModel) ? 0.5 : 1), bandWidth); + var barGap = seriesModel.get('barGap'); + var barCategoryGap = seriesModel.get('barCategoryGap'); + var defaultBarGap = seriesModel.get('defaultBarGap'); + seriesInfoList.push({ + bandWidth: bandWidth, + barWidth: barWidth, + barMaxWidth: barMaxWidth, + barMinWidth: barMinWidth, + barGap: barGap, + barCategoryGap: barCategoryGap, + defaultBarGap: defaultBarGap, + axisKey: getAxisKey(baseAxis), + stackId: getSeriesStackId(seriesModel) + }); + }); + return doCalBarWidthAndOffset(seriesInfoList); + } + + function doCalBarWidthAndOffset(seriesInfoList) { + // Columns info on each category axis. Key is cartesian name + var columnsMap = {}; + each$4(seriesInfoList, function (seriesInfo, idx) { + var axisKey = seriesInfo.axisKey; + var bandWidth = seriesInfo.bandWidth; + var columnsOnAxis = columnsMap[axisKey] || { + bandWidth: bandWidth, + remainedWidth: bandWidth, + autoWidthCount: 0, + categoryGap: null, + gap: seriesInfo.defaultBarGap || 0, + stacks: {} + }; + var stacks = columnsOnAxis.stacks; + columnsMap[axisKey] = columnsOnAxis; + var stackId = seriesInfo.stackId; + + if (!stacks[stackId]) { + columnsOnAxis.autoWidthCount++; + } + + stacks[stackId] = stacks[stackId] || { + width: 0, + maxWidth: 0 + }; // Caution: In a single coordinate system, these barGrid attributes + // will be shared by series. Consider that they have default values, + // only the attributes set on the last series will work. + // Do not change this fact unless there will be a break change. + + var barWidth = seriesInfo.barWidth; + + if (barWidth && !stacks[stackId].width) { + // See #6312, do not restrict width. + stacks[stackId].width = barWidth; + barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth); + columnsOnAxis.remainedWidth -= barWidth; + } + + var barMaxWidth = seriesInfo.barMaxWidth; + barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth); + var barMinWidth = seriesInfo.barMinWidth; + barMinWidth && (stacks[stackId].minWidth = barMinWidth); + var barGap = seriesInfo.barGap; + barGap != null && (columnsOnAxis.gap = barGap); + var barCategoryGap = seriesInfo.barCategoryGap; + barCategoryGap != null && (columnsOnAxis.categoryGap = barCategoryGap); + }); + var result = {}; + each$4(columnsMap, function (columnsOnAxis, coordSysName) { + result[coordSysName] = {}; + var stacks = columnsOnAxis.stacks; + var bandWidth = columnsOnAxis.bandWidth; + var categoryGapPercent = columnsOnAxis.categoryGap; + + if (categoryGapPercent == null) { + var columnCount = keys(stacks).length; // More columns in one group + // the spaces between group is smaller. Or the column will be too thin. + + categoryGapPercent = Math.max(35 - columnCount * 4, 15) + '%'; + } + + var categoryGap = parsePercent(categoryGapPercent, bandWidth); + var barGapPercent = parsePercent(columnsOnAxis.gap, 1); + var remainedWidth = columnsOnAxis.remainedWidth; + var autoWidthCount = columnsOnAxis.autoWidthCount; + var autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent); + autoWidth = Math.max(autoWidth, 0); // Find if any auto calculated bar exceeded maxBarWidth + + each$4(stacks, function (column) { + var maxWidth = column.maxWidth; + var minWidth = column.minWidth; + + if (!column.width) { + var finalWidth = autoWidth; + + if (maxWidth && maxWidth < finalWidth) { + finalWidth = Math.min(maxWidth, remainedWidth); + } // `minWidth` has higher priority. `minWidth` decide that whether the + // bar is able to be visible. So `minWidth` should not be restricted + // by `maxWidth` or `remainedWidth` (which is from `bandWidth`). In + // the extreme cases for `value` axis, bars are allowed to overlap + // with each other if `minWidth` specified. + + + if (minWidth && minWidth > finalWidth) { + finalWidth = minWidth; + } + + if (finalWidth !== autoWidth) { + column.width = finalWidth; + remainedWidth -= finalWidth + barGapPercent * finalWidth; + autoWidthCount--; + } + } else { + // `barMinWidth/barMaxWidth` has higher priority than `barWidth`, as + // CSS does. Because barWidth can be a percent value, where + // `barMaxWidth` can be used to restrict the final width. + var finalWidth = column.width; + + if (maxWidth) { + finalWidth = Math.min(finalWidth, maxWidth); + } // `minWidth` has higher priority, as described above + + + if (minWidth) { + finalWidth = Math.max(finalWidth, minWidth); + } + + column.width = finalWidth; + remainedWidth -= finalWidth + barGapPercent * finalWidth; + autoWidthCount--; + } + }); // Recalculate width again + + autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent); + autoWidth = Math.max(autoWidth, 0); + var widthSum = 0; + var lastColumn; + each$4(stacks, function (column, idx) { + if (!column.width) { + column.width = autoWidth; + } + + lastColumn = column; + widthSum += column.width * (1 + barGapPercent); + }); + + if (lastColumn) { + widthSum -= lastColumn.width * barGapPercent; + } + + var offset = -widthSum / 2; + each$4(stacks, function (column, stackId) { + result[coordSysName][stackId] = result[coordSysName][stackId] || { + bandWidth: bandWidth, + offset: offset, + width: column.width + }; + offset += column.width * (1 + barGapPercent); + }); + }); + return result; + } + + function retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) { + if (barWidthAndOffset && axis) { + var result = barWidthAndOffset[getAxisKey(axis)]; + + if (result != null && seriesModel != null) { + return result[getSeriesStackId(seriesModel)]; + } + + return result; + } + } + + function layout$1(seriesType, ecModel) { + var seriesModels = prepareLayoutBarSeries(seriesType, ecModel); + var barWidthAndOffset = makeColumnLayout(seriesModels); + each$4(seriesModels, function (seriesModel) { + var data = seriesModel.getData(); + var cartesian = seriesModel.coordinateSystem; + var baseAxis = cartesian.getBaseAxis(); + var stackId = getSeriesStackId(seriesModel); + var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId]; + var columnOffset = columnLayoutInfo.offset; + var columnWidth = columnLayoutInfo.width; + data.setLayout({ + bandWidth: columnLayoutInfo.bandWidth, + offset: columnOffset, + size: columnWidth + }); + }); + } // TODO: Do not support stack in large mode yet. + + + function createProgressiveLayout(seriesType) { + return { + seriesType: seriesType, + plan: createRenderPlanner(), + reset: function (seriesModel) { + if (!isOnCartesian(seriesModel)) { + return; + } + + var data = seriesModel.getData(); + var cartesian = seriesModel.coordinateSystem; + var baseAxis = cartesian.getBaseAxis(); + var valueAxis = cartesian.getOtherAxis(baseAxis); + var valueDimIdx = data.getDimensionIndex(data.mapDimension(valueAxis.dim)); + var baseDimIdx = data.getDimensionIndex(data.mapDimension(baseAxis.dim)); + var drawBackground = seriesModel.get('showBackground', true); + var valueDim = data.mapDimension(valueAxis.dim); + var stackResultDim = data.getCalculationInfo('stackResultDimension'); + var stacked = isDimensionStacked(data, valueDim) && !!data.getCalculationInfo('stackedOnSeries'); + var isValueAxisH = valueAxis.isHorizontal(); + var valueAxisStart = getValueAxisStart(baseAxis, valueAxis); + var isLarge = isInLargeMode(seriesModel); + var barMinHeight = seriesModel.get('barMinHeight') || 0; + var stackedDimIdx = stackResultDim && data.getDimensionIndex(stackResultDim); // Layout info. + + var columnWidth = data.getLayout('size'); + var columnOffset = data.getLayout('offset'); + return { + progress: function (params, data) { + var count = params.count; + var largePoints = isLarge && createFloat32Array(count * 3); + var largeBackgroundPoints = isLarge && drawBackground && createFloat32Array(count * 3); + var largeDataIndices = isLarge && createFloat32Array(count); + var coordLayout = cartesian.master.getRect(); + var bgSize = isValueAxisH ? coordLayout.width : coordLayout.height; + var dataIndex; + var store = data.getStore(); + var idxOffset = 0; + + while ((dataIndex = params.next()) != null) { + var value = store.get(stacked ? stackedDimIdx : valueDimIdx, dataIndex); + var baseValue = store.get(baseDimIdx, dataIndex); + var baseCoord = valueAxisStart; + var stackStartValue = void 0; // Because of the barMinHeight, we can not use the value in + // stackResultDimension directly. + + if (stacked) { + stackStartValue = +value - store.get(valueDimIdx, dataIndex); + } + + var x = void 0; + var y = void 0; + var width = void 0; + var height = void 0; + + if (isValueAxisH) { + var coord = cartesian.dataToPoint([value, baseValue]); + + if (stacked) { + var startCoord = cartesian.dataToPoint([stackStartValue, baseValue]); + baseCoord = startCoord[0]; + } + + x = baseCoord; + y = coord[1] + columnOffset; + width = coord[0] - baseCoord; + height = columnWidth; + + if (Math.abs(width) < barMinHeight) { + width = (width < 0 ? -1 : 1) * barMinHeight; + } + } else { + var coord = cartesian.dataToPoint([baseValue, value]); + + if (stacked) { + var startCoord = cartesian.dataToPoint([baseValue, stackStartValue]); + baseCoord = startCoord[1]; + } + + x = coord[0] + columnOffset; + y = baseCoord; + width = columnWidth; + height = coord[1] - baseCoord; + + if (Math.abs(height) < barMinHeight) { + // Include zero to has a positive bar + height = (height <= 0 ? -1 : 1) * barMinHeight; + } + } + + if (!isLarge) { + data.setItemLayout(dataIndex, { + x: x, + y: y, + width: width, + height: height + }); + } else { + largePoints[idxOffset] = x; + largePoints[idxOffset + 1] = y; + largePoints[idxOffset + 2] = isValueAxisH ? width : height; + + if (largeBackgroundPoints) { + largeBackgroundPoints[idxOffset] = isValueAxisH ? coordLayout.x : x; + largeBackgroundPoints[idxOffset + 1] = isValueAxisH ? y : coordLayout.y; + largeBackgroundPoints[idxOffset + 2] = bgSize; + } + + largeDataIndices[dataIndex] = dataIndex; + } + + idxOffset += 3; + } + + if (isLarge) { + data.setLayout({ + largePoints: largePoints, + largeDataIndices: largeDataIndices, + largeBackgroundPoints: largeBackgroundPoints, + valueAxisHorizontal: isValueAxisH + }); + } + } + }; + } + }; + } + + function isOnCartesian(seriesModel) { + return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d'; + } + + function isInLargeMode(seriesModel) { + return seriesModel.pipelineContext && seriesModel.pipelineContext.large; + } // See cases in `test/bar-start.html` and `#7412`, `#8747`. + + + function getValueAxisStart(baseAxis, valueAxis) { + var startValue = valueAxis.model.get('startValue'); + + if (!startValue) { + startValue = 0; + } + + return valueAxis.toGlobalCoord(valueAxis.dataToCoord(valueAxis.type === 'log' ? startValue > 0 ? startValue : 1 : startValue)); + } // FIXME 公用? + + + var bisect = function (a, x, lo, hi) { + while (lo < hi) { + var mid = lo + hi >>> 1; + + if (a[mid][1] < x) { + lo = mid + 1; + } else { + hi = mid; + } + } + + return lo; + }; + + var TimeScale = + /** @class */ + function (_super) { + __extends(TimeScale, _super); + + function TimeScale(settings) { + var _this = _super.call(this, settings) || this; + + _this.type = 'time'; + return _this; + } + /** + * Get label is mainly for other components like dataZoom, tooltip. + */ + + + TimeScale.prototype.getLabel = function (tick) { + var useUTC = this.getSetting('useUTC'); + return format$1(tick.value, fullLeveledFormatter[getDefaultFormatPrecisionOfInterval(getPrimaryTimeUnit(this._minLevelUnit))] || fullLeveledFormatter.second, useUTC, this.getSetting('locale')); + }; + + TimeScale.prototype.getFormattedLabel = function (tick, idx, labelFormatter) { + var isUTC = this.getSetting('useUTC'); + var lang = this.getSetting('locale'); + return leveledFormat(tick, idx, labelFormatter, lang, isUTC); + }; + /** + * @override + */ + + + TimeScale.prototype.getTicks = function (opt) { + var interval = this._interval; + var extent = this._extent; + var ticks = []; // If interval is 0, return []; + + if (!interval) { + return ticks; + } + + var useUTC = this.getSetting('useUTC'); + var extent0Unit = getUnitFromValue(extent[1], useUTC); + ticks.push({ + value: extent[0], + time: { + level: 0, + upperTimeUnit: extent0Unit, + lowerTimeUnit: extent0Unit + } + }); + var innerTicks = getIntervalTicks(this._minLevelUnit, this._approxInterval, useUTC, extent, this._getExtentSpanWithBreaks(), this._brkCtx); + ticks = ticks.concat(innerTicks); + var extent1Unit = getUnitFromValue(extent[1], useUTC); + ticks.push({ + value: extent[1], + time: { + level: 0, + upperTimeUnit: extent1Unit, + lowerTimeUnit: extent1Unit + } + }); + this.getSetting('useUTC'); + var upperUnitIndex = primaryTimeUnits.length - 1; + var maxLevel = 0; + each$4(ticks, function (tick) { + upperUnitIndex = Math.min(upperUnitIndex, indexOf(primaryTimeUnits, tick.time.upperTimeUnit)); + maxLevel = Math.max(maxLevel, tick.time.level); + }); + return ticks; + }; + + TimeScale.prototype.calcNiceExtent = function (opt) { + var extent = this.getExtent(); // If extent start and end are same, expand them + + if (extent[0] === extent[1]) { + // Expand extent + extent[0] -= ONE_DAY; + extent[1] += ONE_DAY; + } // If there are no data and extent are [Infinity, -Infinity] + + + if (extent[1] === -Infinity && extent[0] === Infinity) { + var d = new Date(); + extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate()); + extent[0] = extent[1] - ONE_DAY; + } + + this._innerSetExtent(extent[0], extent[1]); + + this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval); + }; + + TimeScale.prototype.calcNiceTicks = function (approxTickNum, minInterval, maxInterval) { + approxTickNum = approxTickNum || 10; + + var span = this._getExtentSpanWithBreaks(); + + this._approxInterval = span / approxTickNum; + + if (minInterval != null && this._approxInterval < minInterval) { + this._approxInterval = minInterval; + } + + if (maxInterval != null && this._approxInterval > maxInterval) { + this._approxInterval = maxInterval; + } + + var scaleIntervalsLen = scaleIntervals.length; + var idx = Math.min(bisect(scaleIntervals, this._approxInterval, 0, scaleIntervalsLen), scaleIntervalsLen - 1); // Interval that can be used to calculate ticks + + this._interval = scaleIntervals[idx][1]; + this._intervalPrecision = getIntervalPrecision(this._interval); // Min level used when picking ticks from top down. + // We check one more level to avoid the ticks are to sparse in some case. + + this._minLevelUnit = scaleIntervals[Math.max(idx - 1, 0)][0]; + }; + + TimeScale.prototype.parse = function (val) { + // val might be float. + return isNumber(val) ? val : +parseDate(val); + }; + + TimeScale.prototype.contain = function (val) { + return contain$1(val, this._extent); + }; + + TimeScale.prototype.normalize = function (val) { + return this._calculator.normalize(val, this._extent); + }; + + TimeScale.prototype.scale = function (val) { + return this._calculator.scale(val, this._extent); + }; + + TimeScale.type = 'time'; + return TimeScale; + }(IntervalScale); + /** + * This implementation was originally copied from "d3.js" + * + * with some modifications made for this program. + * See the license statement at the head of this file. + */ + + + var scaleIntervals = [// Format interval + ['second', ONE_SECOND], ['minute', ONE_MINUTE], ['hour', ONE_HOUR], ['quarter-day', ONE_HOUR * 6], ['half-day', ONE_HOUR * 12], ['day', ONE_DAY * 1.2], ['half-week', ONE_DAY * 3.5], ['week', ONE_DAY * 7], ['month', ONE_DAY * 31], ['quarter', ONE_DAY * 95], ['half-year', ONE_YEAR / 2], ['year', ONE_YEAR] // 1Y + ]; + + function isPrimaryUnitValueAndGreaterSame(unit, valueA, valueB, isUTC) { + return roundTime(new Date(valueA), unit, isUTC).getTime() === roundTime(new Date(valueB), unit, isUTC).getTime(); + } // function isUnitValueSame( + // unit: PrimaryTimeUnit, + // valueA: number, + // valueB: number, + // isUTC: boolean + // ): boolean { + // const dateA = numberUtil.parseDate(valueA) as any; + // const dateB = numberUtil.parseDate(valueB) as any; + // const isSame = (unit: PrimaryTimeUnit) => { + // return getUnitValue(dateA, unit, isUTC) + // === getUnitValue(dateB, unit, isUTC); + // }; + // const isSameYear = () => isSame('year'); + // // const isSameHalfYear = () => isSameYear() && isSame('half-year'); + // // const isSameQuater = () => isSameYear() && isSame('quarter'); + // const isSameMonth = () => isSameYear() && isSame('month'); + // const isSameDay = () => isSameMonth() && isSame('day'); + // // const isSameHalfDay = () => isSameDay() && isSame('half-day'); + // const isSameHour = () => isSameDay() && isSame('hour'); + // const isSameMinute = () => isSameHour() && isSame('minute'); + // const isSameSecond = () => isSameMinute() && isSame('second'); + // const isSameMilliSecond = () => isSameSecond() && isSame('millisecond'); + // switch (unit) { + // case 'year': + // return isSameYear(); + // case 'month': + // return isSameMonth(); + // case 'day': + // return isSameDay(); + // case 'hour': + // return isSameHour(); + // case 'minute': + // return isSameMinute(); + // case 'second': + // return isSameSecond(); + // case 'millisecond': + // return isSameMilliSecond(); + // } + // } + // const primaryUnitGetters = { + // year: fullYearGetterName(), + // month: monthGetterName(), + // day: dateGetterName(), + // hour: hoursGetterName(), + // minute: minutesGetterName(), + // second: secondsGetterName(), + // millisecond: millisecondsGetterName() + // }; + // const primaryUnitUTCGetters = { + // year: fullYearGetterName(true), + // month: monthGetterName(true), + // day: dateGetterName(true), + // hour: hoursGetterName(true), + // minute: minutesGetterName(true), + // second: secondsGetterName(true), + // millisecond: millisecondsGetterName(true) + // }; + // function moveTick(date: Date, unitName: TimeUnit, step: number, isUTC: boolean) { + // step = step || 1; + // switch (getPrimaryTimeUnit(unitName)) { + // case 'year': + // date[fullYearSetterName(isUTC)](date[fullYearGetterName(isUTC)]() + step); + // break; + // case 'month': + // date[monthSetterName(isUTC)](date[monthGetterName(isUTC)]() + step); + // break; + // case 'day': + // date[dateSetterName(isUTC)](date[dateGetterName(isUTC)]() + step); + // break; + // case 'hour': + // date[hoursSetterName(isUTC)](date[hoursGetterName(isUTC)]() + step); + // break; + // case 'minute': + // date[minutesSetterName(isUTC)](date[minutesGetterName(isUTC)]() + step); + // break; + // case 'second': + // date[secondsSetterName(isUTC)](date[secondsGetterName(isUTC)]() + step); + // break; + // case 'millisecond': + // date[millisecondsSetterName(isUTC)](date[millisecondsGetterName(isUTC)]() + step); + // break; + // } + // return date.getTime(); + // } + // const DATE_INTERVALS = [[8, 7.5], [4, 3.5], [2, 1.5]]; + // const MONTH_INTERVALS = [[6, 5.5], [3, 2.5], [2, 1.5]]; + // const MINUTES_SECONDS_INTERVALS = [[30, 30], [20, 20], [15, 15], [10, 10], [5, 5], [2, 2]]; + + + function getDateInterval(approxInterval, daysInMonth) { + approxInterval /= ONE_DAY; + return approxInterval > 16 ? 16 // Math.floor(daysInMonth / 2) + 1 // In this case we only want one tick between two months. + : approxInterval > 7.5 ? 7 // TODO week 7 or day 8? + : approxInterval > 3.5 ? 4 : approxInterval > 1.5 ? 2 : 1; + } + + function getMonthInterval(approxInterval) { + var APPROX_ONE_MONTH = 30 * ONE_DAY; + approxInterval /= APPROX_ONE_MONTH; + return approxInterval > 6 ? 6 : approxInterval > 3 ? 3 : approxInterval > 2 ? 2 : 1; + } + + function getHourInterval(approxInterval) { + approxInterval /= ONE_HOUR; + return approxInterval > 12 ? 12 : approxInterval > 6 ? 6 : approxInterval > 3.5 ? 4 : approxInterval > 2 ? 2 : 1; + } + + function getMinutesAndSecondsInterval(approxInterval, isMinutes) { + approxInterval /= isMinutes ? ONE_MINUTE : ONE_SECOND; + return approxInterval > 30 ? 30 : approxInterval > 20 ? 20 : approxInterval > 15 ? 15 : approxInterval > 10 ? 10 : approxInterval > 5 ? 5 : approxInterval > 2 ? 2 : 1; + } + + function getMillisecondsInterval(approxInterval) { + return nice(approxInterval, true); + } // e.g., if the input unit is 'day', start calculate ticks from the first day of + // that month to make ticks "nice". + + + function getFirstTimestampOfUnit(timestamp, unitName, isUTC) { + var upperUnitIdx = Math.max(0, indexOf(primaryTimeUnits, unitName) - 1); + return roundTime(new Date(timestamp), primaryTimeUnits[upperUnitIdx], isUTC).getTime(); + } + + function createEstimateNiceMultiple(setMethodName, dateMethodInterval) { + var tmpDate = new Date(0); + tmpDate[setMethodName](1); + var tmpTime = tmpDate.getTime(); + tmpDate[setMethodName](1 + dateMethodInterval); + var approxTimeInterval = tmpDate.getTime() - tmpTime; + return function (tickVal, targetValue) { + // Only in month that accurate result can not get by division of + // timestamp interval, but no need accurate here. + return Math.max(0, Math.round((targetValue - tickVal) / approxTimeInterval)); + }; + } + + function getIntervalTicks(bottomUnitName, approxInterval, isUTC, extent, extentSpanWithBreaks, brkCtx) { + var safeLimit = 10000; + var unitNames = timeUnits; + var iter = 0; + + function addTicksInSpan(interval, minTimestamp, maxTimestamp, getMethodName, setMethodName, isDate, out) { + var estimateNiceMultiple = createEstimateNiceMultiple(setMethodName, interval); + var dateTime = minTimestamp; + var date = new Date(dateTime); // if (isDate) { + // d -= 1; // Starts with 0; PENDING + // } + + while (dateTime < maxTimestamp && dateTime <= extent[1]) { + out.push({ + value: dateTime + }); + + if (iter++ > safeLimit) { + { + warn('Exceed safe limit in time scale.'); + } + break; + } + + date[setMethodName](date[getMethodName]() + interval); + dateTime = date.getTime(); + + if (brkCtx) { + var moreMultiple = brkCtx.calcNiceTickMultiple(dateTime, estimateNiceMultiple); + + if (moreMultiple > 0) { + date[setMethodName](date[getMethodName]() + moreMultiple * interval); + dateTime = date.getTime(); + } + } + } // This extra tick is for calcuating ticks of next level. Will not been added to the final result + + + out.push({ + value: dateTime, + notAdd: true + }); + } + + function addLevelTicks(unitName, lastLevelTicks, levelTicks) { + var newAddedTicks = []; + var isFirstLevel = !lastLevelTicks.length; + + if (isPrimaryUnitValueAndGreaterSame(getPrimaryTimeUnit(unitName), extent[0], extent[1], isUTC)) { + return; + } + + if (isFirstLevel) { + lastLevelTicks = [{ + value: getFirstTimestampOfUnit(extent[0], unitName, isUTC) + }, { + value: extent[1] + }]; + } + + for (var i = 0; i < lastLevelTicks.length - 1; i++) { + var startTick = lastLevelTicks[i].value; + var endTick = lastLevelTicks[i + 1].value; + + if (startTick === endTick) { + continue; + } + + var interval = void 0; + var getterName = void 0; + var setterName = void 0; + var isDate = false; + + switch (unitName) { + case 'year': + interval = Math.max(1, Math.round(approxInterval / ONE_DAY / 365)); + getterName = fullYearGetterName(isUTC); + setterName = fullYearSetterName(isUTC); + break; + + case 'half-year': + case 'quarter': + case 'month': + interval = getMonthInterval(approxInterval); + getterName = monthGetterName(isUTC); + setterName = monthSetterName(isUTC); + break; + + case 'week': // PENDING If week is added. Ignore day. + + case 'half-week': + case 'day': + interval = getDateInterval(approxInterval); // Use 32 days and let interval been 16 + + getterName = dateGetterName(isUTC); + setterName = dateSetterName(isUTC); + isDate = true; + break; + + case 'half-day': + case 'quarter-day': + case 'hour': + interval = getHourInterval(approxInterval); + getterName = hoursGetterName(isUTC); + setterName = hoursSetterName(isUTC); + break; + + case 'minute': + interval = getMinutesAndSecondsInterval(approxInterval, true); + getterName = minutesGetterName(isUTC); + setterName = minutesSetterName(isUTC); + break; + + case 'second': + interval = getMinutesAndSecondsInterval(approxInterval, false); + getterName = secondsGetterName(isUTC); + setterName = secondsSetterName(isUTC); + break; + + case 'millisecond': + interval = getMillisecondsInterval(approxInterval); + getterName = millisecondsGetterName(isUTC); + setterName = millisecondsSetterName(isUTC); + break; + } // Notice: This expansion by `getFirstTimestampOfUnit` may cause too many ticks and + // iteration. e.g., when three levels of ticks is displayed, which can be caused by + // data zoom and axis breaks. Thus trim them here. + + + if (endTick >= extent[0] && startTick <= extent[1]) { + addTicksInSpan(interval, startTick, endTick, getterName, setterName, isDate, newAddedTicks); + } + + if (unitName === 'year' && levelTicks.length > 1 && i === 0) { + // Add nearest years to the left extent. + levelTicks.unshift({ + value: levelTicks[0].value - interval + }); + } + } + + for (var i = 0; i < newAddedTicks.length; i++) { + levelTicks.push(newAddedTicks[i]); + } + } + + var levelsTicks = []; + var currentLevelTicks = []; + var tickCount = 0; + var lastLevelTickCount = 0; + + for (var i = 0; i < unitNames.length; ++i) { + var primaryTimeUnit = getPrimaryTimeUnit(unitNames[i]); + + if (!isPrimaryTimeUnit(unitNames[i])) { + // TODO + continue; + } + + addLevelTicks(unitNames[i], levelsTicks[levelsTicks.length - 1] || [], currentLevelTicks); + var nextPrimaryTimeUnit = unitNames[i + 1] ? getPrimaryTimeUnit(unitNames[i + 1]) : null; + + if (primaryTimeUnit !== nextPrimaryTimeUnit) { + if (currentLevelTicks.length) { + lastLevelTickCount = tickCount; // Remove the duplicate so the tick count can be precisely. + + currentLevelTicks.sort(function (a, b) { + return a.value - b.value; + }); + var levelTicksRemoveDuplicated = []; + + for (var i_1 = 0; i_1 < currentLevelTicks.length; ++i_1) { + var tickValue = currentLevelTicks[i_1].value; + + if (i_1 === 0 || currentLevelTicks[i_1 - 1].value !== tickValue) { + levelTicksRemoveDuplicated.push(currentLevelTicks[i_1]); + + if (tickValue >= extent[0] && tickValue <= extent[1]) { + tickCount++; + } + } + } + + var targetTickNum = extentSpanWithBreaks / approxInterval; // Added too much in this level and not too less in last level + + if (tickCount > targetTickNum * 1.5 && lastLevelTickCount > targetTickNum / 1.5) { + break; + } // Only treat primary time unit as one level. + + + levelsTicks.push(levelTicksRemoveDuplicated); + + if (tickCount > targetTickNum || bottomUnitName === unitNames[i]) { + break; + } + } // Reset if next unitName is primary + + + currentLevelTicks = []; + } + } + + var levelsTicksInExtent = filter(map$1(levelsTicks, function (levelTicks) { + return filter(levelTicks, function (tick) { + return tick.value >= extent[0] && tick.value <= extent[1] && !tick.notAdd; + }); + }), function (levelTicks) { + return levelTicks.length > 0; + }); + var ticks = []; + var maxLevel = levelsTicksInExtent.length - 1; + + for (var i = 0; i < levelsTicksInExtent.length; ++i) { + var levelTicks = levelsTicksInExtent[i]; + + for (var k = 0; k < levelTicks.length; ++k) { + var unit = getUnitFromValue(levelTicks[k].value, isUTC); + ticks.push({ + value: levelTicks[k].value, + time: { + level: maxLevel - i, + upperTimeUnit: unit, + lowerTimeUnit: unit + } + }); + } + } + + ticks.sort(function (a, b) { + return a.value - b.value; + }); // Remove duplicates + + var result = []; + + for (var i = 0; i < ticks.length; ++i) { + if (i === 0 || ticks[i].value !== ticks[i - 1].value) { + result.push(ticks[i]); + } + } + + return result; + } + + Scale.registerClass(TimeScale); + var fixRound = round$1; + var mathFloor = Math.floor; + var mathCeil = Math.ceil; + var mathPow = Math.pow; + var mathLog = Math.log; + + var LogScale = + /** @class */ + function (_super) { + __extends(LogScale, _super); + + function LogScale() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'log'; + _this.base = 10; + _this._originalScale = new IntervalScale(); + return _this; + } + /** + * @param Whether expand the ticks to niced extent. + */ + + + LogScale.prototype.getTicks = function (opt) { + opt = opt || {}; + + var extent = this._extent.slice(); + + var originalExtent = this._originalScale.getExtent(); + + var ticks = _super.prototype.getTicks.call(this, opt); + + var base = this.base; + + this._originalScale._innerGetBreaks(); + + return map$1(ticks, function (tick) { + var val = tick.value; + var roundingCriterion = null; + var powVal = mathPow(base, val); // Fix #4158 + + if (val === extent[0] && this._fixMin) { + roundingCriterion = originalExtent[0]; + } else if (val === extent[1] && this._fixMax) { + roundingCriterion = originalExtent[1]; + } + + var vBreak; + + if (roundingCriterion != null) { + powVal = fixRoundingError(powVal, roundingCriterion); + } + + return { + value: powVal, + "break": vBreak + }; + }, this); + }; + + LogScale.prototype._getNonTransBreaks = function () { + return this._originalScale._innerGetBreaks(); + }; + + LogScale.prototype.setExtent = function (start, end) { + this._originalScale.setExtent(start, end); + + var loggedExtent = logTransform(this.base, [start, end]); + + _super.prototype.setExtent.call(this, loggedExtent[0], loggedExtent[1]); + }; + /** + * @return {number} end + */ + + + LogScale.prototype.getExtent = function () { + var base = this.base; + + var extent = _super.prototype.getExtent.call(this); + + extent[0] = mathPow(base, extent[0]); + extent[1] = mathPow(base, extent[1]); // Fix #4158 + + var originalExtent = this._originalScale.getExtent(); + + this._fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0])); + this._fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1])); + return extent; + }; + + LogScale.prototype.unionExtentFromData = function (data, dim) { + this._originalScale.unionExtentFromData(data, dim); + + var loggedOther = logTransform(this.base, data.getApproximateExtent(dim), true); + + this._innerUnionExtent(loggedOther); + }; + /** + * Update interval and extent of intervals for nice ticks + * @param approxTickNum default 10 Given approx tick number + */ + + + LogScale.prototype.calcNiceTicks = function (approxTickNum) { + approxTickNum = approxTickNum || 10; + + var extent = this._extent.slice(); + + var span = this._getExtentSpanWithBreaks(); + + if (!isFinite(span) || span <= 0) { + return; + } + + var interval = quantity(span); + var err = approxTickNum / span * interval; // Filter ticks to get closer to the desired count. + + if (err <= 0.5) { + interval *= 10; + } // Interval should be integer + + + while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) { + interval *= 10; + } + + var niceExtent = [fixRound(mathCeil(extent[0] / interval) * interval), fixRound(mathFloor(extent[1] / interval) * interval)]; + this._interval = interval; + this._intervalPrecision = getIntervalPrecision(interval); + this._niceExtent = niceExtent; + }; + + LogScale.prototype.calcNiceExtent = function (opt) { + _super.prototype.calcNiceExtent.call(this, opt); + + this._fixMin = opt.fixMin; + this._fixMax = opt.fixMax; + }; + + LogScale.prototype.contain = function (val) { + val = mathLog(val) / mathLog(this.base); + return _super.prototype.contain.call(this, val); + }; + + LogScale.prototype.normalize = function (val) { + val = mathLog(val) / mathLog(this.base); + return _super.prototype.normalize.call(this, val); + }; + + LogScale.prototype.scale = function (val) { + val = _super.prototype.scale.call(this, val); + return mathPow(this.base, val); + }; + + LogScale.prototype.setBreaksFromOption = function (breakOptionList) { + { + return; + } + }; + + LogScale.type = 'log'; + return LogScale; + }(IntervalScale); + + function fixRoundingError(val, originalVal) { + return fixRound(val, getPrecision(originalVal)); + } + + Scale.registerClass(LogScale); + + var ScaleRawExtentInfo = + /** @class */ + function () { + function ScaleRawExtentInfo(scale, model, // Usually: data extent from all series on this axis. + originalExtent) { + this._prepareParams(scale, model, originalExtent); + } + /** + * Parameters depending on outside (like model, user callback) + * are prepared and fixed here. + */ + + + ScaleRawExtentInfo.prototype._prepareParams = function (scale, model, // Usually: data extent from all series on this axis. + dataExtent) { + if (dataExtent[1] < dataExtent[0]) { + dataExtent = [NaN, NaN]; + } + + this._dataMin = dataExtent[0]; + this._dataMax = dataExtent[1]; + var isOrdinal = this._isOrdinal = scale.type === 'ordinal'; + this._needCrossZero = scale.type === 'interval' && model.getNeedCrossZero && model.getNeedCrossZero(); + var axisMinValue = model.get('min', true); + + if (axisMinValue == null) { + axisMinValue = model.get('startValue', true); + } + + var modelMinRaw = this._modelMinRaw = axisMinValue; + + if (isFunction(modelMinRaw)) { + // This callback always provides users the full data extent (before data is filtered). + this._modelMinNum = parseAxisModelMinMax(scale, modelMinRaw({ + min: dataExtent[0], + max: dataExtent[1] + })); + } else if (modelMinRaw !== 'dataMin') { + this._modelMinNum = parseAxisModelMinMax(scale, modelMinRaw); + } + + var modelMaxRaw = this._modelMaxRaw = model.get('max', true); + + if (isFunction(modelMaxRaw)) { + // This callback always provides users the full data extent (before data is filtered). + this._modelMaxNum = parseAxisModelMinMax(scale, modelMaxRaw({ + min: dataExtent[0], + max: dataExtent[1] + })); + } else if (modelMaxRaw !== 'dataMax') { + this._modelMaxNum = parseAxisModelMinMax(scale, modelMaxRaw); + } + + if (isOrdinal) { + // FIXME: there is a flaw here: if there is no "block" data processor like `dataZoom`, + // and progressive rendering is using, here the category result might just only contain + // the processed chunk rather than the entire result. + this._axisDataLen = model.getCategories().length; + } else { + var boundaryGap = model.get('boundaryGap'); + var boundaryGapArr = isArray(boundaryGap) ? boundaryGap : [boundaryGap || 0, boundaryGap || 0]; + + if (typeof boundaryGapArr[0] === 'boolean' || typeof boundaryGapArr[1] === 'boolean') { + { + console.warn('Boolean type for boundaryGap is only ' + 'allowed for ordinal axis. Please use string in ' + 'percentage instead, e.g., "20%". Currently, ' + 'boundaryGap is set to be 0.'); + } + this._boundaryGapInner = [0, 0]; + } else { + this._boundaryGapInner = [parsePercent$1(boundaryGapArr[0], 1), parsePercent$1(boundaryGapArr[1], 1)]; + } + } + }; + /** + * Calculate extent by prepared parameters. + * This method has no external dependency and can be called duplicatedly, + * getting the same result. + * If parameters changed, should call this method to recalcuate. + */ + + + ScaleRawExtentInfo.prototype.calculate = function () { + // Notice: When min/max is not set (that is, when there are null/undefined, + // which is the most common case), these cases should be ensured: + // (1) For 'ordinal', show all axis.data. + // (2) For others: + // + `boundaryGap` is applied (if min/max set, boundaryGap is + // disabled). + // + If `needCrossZero`, min/max should be zero, otherwise, min/max should + // be the result that originalExtent enlarged by boundaryGap. + // (3) If no data, it should be ensured that `scale.setBlank` is set. + var isOrdinal = this._isOrdinal; + var dataMin = this._dataMin; + var dataMax = this._dataMax; + var axisDataLen = this._axisDataLen; + var boundaryGapInner = this._boundaryGapInner; + var span = !isOrdinal ? dataMax - dataMin || Math.abs(dataMin) : null; // Currently if a `'value'` axis model min is specified as 'dataMin'/'dataMax', + // `boundaryGap` will not be used. It's the different from specifying as `null`/`undefined`. + + var min = this._modelMinRaw === 'dataMin' ? dataMin : this._modelMinNum; + var max = this._modelMaxRaw === 'dataMax' ? dataMax : this._modelMaxNum; // If `_modelMinNum`/`_modelMaxNum` is `null`/`undefined`, should not be fixed. + + var minFixed = min != null; + var maxFixed = max != null; + + if (min == null) { + min = isOrdinal ? axisDataLen ? 0 : NaN : dataMin - boundaryGapInner[0] * span; + } + + if (max == null) { + max = isOrdinal ? axisDataLen ? axisDataLen - 1 : NaN : dataMax + boundaryGapInner[1] * span; + } + + (min == null || !isFinite(min)) && (min = NaN); + (max == null || !isFinite(max)) && (max = NaN); + var isBlank = eqNaN(min) || eqNaN(max) || isOrdinal && !axisDataLen; // If data extent modified, need to recalculated to ensure cross zero. + + if (this._needCrossZero) { + // Axis is over zero and min is not set + if (min > 0 && max > 0 && !minFixed) { + min = 0; // minFixed = true; + } // Axis is under zero and max is not set + + + if (min < 0 && max < 0 && !maxFixed) { + max = 0; // maxFixed = true; + } // PENDING: + // When `needCrossZero` and all data is positive/negative, should it be ensured + // that the results processed by boundaryGap are positive/negative? + // If so, here `minFixed`/`maxFixed` need to be set. + + } + + var determinedMin = this._determinedMin; + var determinedMax = this._determinedMax; + + if (determinedMin != null) { + min = determinedMin; + minFixed = true; + } + + if (determinedMax != null) { + max = determinedMax; + maxFixed = true; + } // Ensure min/max be finite number or NaN here. (not to be null/undefined) + // `NaN` means min/max axis is blank. + + + return { + min: min, + max: max, + minFixed: minFixed, + maxFixed: maxFixed, + isBlank: isBlank + }; + }; + + ScaleRawExtentInfo.prototype.modifyDataMinMax = function (minMaxName, val) { + { + assert(!this.frozen); + } + this[DATA_MIN_MAX_ATTR[minMaxName]] = val; + }; + + ScaleRawExtentInfo.prototype.setDeterminedMinMax = function (minMaxName, val) { + var attr = DETERMINED_MIN_MAX_ATTR[minMaxName]; + { + assert(!this.frozen // Earse them usually means logic flaw. + && this[attr] == null); + } + this[attr] = val; + }; + + ScaleRawExtentInfo.prototype.freeze = function () { + // @ts-ignore + this.frozen = true; + }; + + return ScaleRawExtentInfo; + }(); + + var DETERMINED_MIN_MAX_ATTR = { + min: '_determinedMin', + max: '_determinedMax' + }; + var DATA_MIN_MAX_ATTR = { + min: '_dataMin', + max: '_dataMax' + }; + /** + * Get scale min max and related info only depends on model settings. + * This method can be called after coordinate system created. + * For example, in data processing stage. + * + * Scale extent info probably be required multiple times during a workflow. + * For example: + * (1) `dataZoom` depends it to get the axis extent in "100%" state. + * (2) `processor/extentCalculator` depends it to make sure whether axis extent is specified. + * (3) `coordSys.update` use it to finally decide the scale extent. + * But the callback of `min`/`max` should not be called multiple times. + * The code below should not be implemented repeatedly either. + * So we cache the result in the scale instance, which will be recreated at the beginning + * of the workflow (because `scale` instance will be recreated each round of the workflow). + */ + + function ensureScaleRawExtentInfo(scale, model, // Usually: data extent from all series on this axis. + originalExtent) { + // Do not permit to recreate. + var rawExtentInfo = scale.rawExtentInfo; + + if (rawExtentInfo) { + return rawExtentInfo; + } + + rawExtentInfo = new ScaleRawExtentInfo(scale, model, originalExtent); // @ts-ignore + + scale.rawExtentInfo = rawExtentInfo; + return rawExtentInfo; + } + + function parseAxisModelMinMax(scale, minMax) { + return minMax == null ? null : eqNaN(minMax) ? NaN : scale.parse(minMax); + } + /** + * Get axis scale extent before niced. + * Item of returned array can only be number (including Infinity and NaN). + * + * Caution: + * Precondition of calling this method: + * The scale extent has been initialized using series data extent via + * `scale.setExtent` or `scale.unionExtentFromData`; + */ + + + function getScaleExtent(scale, model) { + var scaleType = scale.type; + var rawExtentResult = ensureScaleRawExtentInfo(scale, model, scale.getExtent()).calculate(); + scale.setBlank(rawExtentResult.isBlank); + var min = rawExtentResult.min; + var max = rawExtentResult.max; // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis + // is base axis + // FIXME + // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly. + // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent? + // Should not depend on series type `bar`? + // (3) Fix that might overlap when using dataZoom. + // (4) Consider other chart types using `barGrid`? + // See #6728, #4862, `test/bar-overflow-time-plot.html` + + var ecModel = model.ecModel; + + if (ecModel && scaleType === 'time' + /* || scaleType === 'interval' */ + ) { + var barSeriesModels = prepareLayoutBarSeries('bar', ecModel); + var isBaseAxisAndHasBarSeries_1 = false; + each$4(barSeriesModels, function (seriesModel) { + isBaseAxisAndHasBarSeries_1 = isBaseAxisAndHasBarSeries_1 || seriesModel.getBaseAxis() === model.axis; + }); + + if (isBaseAxisAndHasBarSeries_1) { + // Calculate placement of bars on axis. TODO should be decoupled + // with barLayout + var barWidthAndOffset = makeColumnLayout(barSeriesModels); // Adjust axis min and max to account for overflow + + var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset); + min = adjustedScale.min; + max = adjustedScale.max; + } + } + + return { + extent: [min, max], + // "fix" means "fixed", the value should not be + // changed in the subsequent steps. + fixMin: rawExtentResult.minFixed, + fixMax: rawExtentResult.maxFixed + }; + } + + function adjustScaleForOverflow(min, max, model, // Only support cartesian coord yet. + barWidthAndOffset) { + // Get Axis Length + var axisExtent = model.axis.getExtent(); + var axisLength = Math.abs(axisExtent[1] - axisExtent[0]); // Get bars on current base axis and calculate min and max overflow + + var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis); + + if (barsOnCurrentAxis === undefined) { + return { + min: min, + max: max + }; + } + + var minOverflow = Infinity; + each$4(barsOnCurrentAxis, function (item) { + minOverflow = Math.min(item.offset, minOverflow); + }); + var maxOverflow = -Infinity; + each$4(barsOnCurrentAxis, function (item) { + maxOverflow = Math.max(item.offset + item.width, maxOverflow); + }); + minOverflow = Math.abs(minOverflow); + maxOverflow = Math.abs(maxOverflow); + var totalOverFlow = minOverflow + maxOverflow; // Calculate required buffer based on old range and overflow + + var oldRange = max - min; + var oldRangePercentOfNew = 1 - (minOverflow + maxOverflow) / axisLength; + var overflowBuffer = oldRange / oldRangePercentOfNew - oldRange; + max += overflowBuffer * (maxOverflow / totalOverFlow); + min -= overflowBuffer * (minOverflow / totalOverFlow); + return { + min: min, + max: max + }; + } // Precondition of calling this method: + // The scale extent has been initialized using series data extent via + // `scale.setExtent` or `scale.unionExtentFromData`; + + + function niceScaleExtent(scale, inModel) { + var model = inModel; + var extentInfo = getScaleExtent(scale, model); + var extent = extentInfo.extent; + var splitNumber = model.get('splitNumber'); + + if (scale instanceof LogScale) { + scale.base = model.get('logBase'); + } + + var scaleType = scale.type; + var interval = model.get('interval'); + var isIntervalOrTime = scaleType === 'interval' || scaleType === 'time'; + scale.setBreaksFromOption(retrieveAxisBreaksOption(model)); + scale.setExtent(extent[0], extent[1]); + scale.calcNiceExtent({ + splitNumber: splitNumber, + fixMin: extentInfo.fixMin, + fixMax: extentInfo.fixMax, + minInterval: isIntervalOrTime ? model.get('minInterval') : null, + maxInterval: isIntervalOrTime ? model.get('maxInterval') : null + }); // If some one specified the min, max. And the default calculated interval + // is not good enough. He can specify the interval. It is often appeared + // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard + // to be 60. + // FIXME + + if (interval != null) { + scale.setInterval && scale.setInterval(interval); + } + } + /** + * @param axisType Default retrieve from model.type + */ + + + function createScaleByModel(model, axisType) { + axisType = axisType || model.get('type'); + + if (axisType) { + switch (axisType) { + // Buildin scale + case 'category': + return new OrdinalScale({ + ordinalMeta: model.getOrdinalMeta ? model.getOrdinalMeta() : model.getCategories(), + extent: [Infinity, -Infinity] + }); + + case 'time': + return new TimeScale({ + locale: model.ecModel.getLocaleModel(), + useUTC: model.ecModel.get('useUTC') + }); + + default: + // case 'value'/'interval', 'log', or others. + return new (Scale.getClass(axisType) || IntervalScale)(); + } + } + } + /** + * Check if the axis cross 0 + */ + + + function ifAxisCrossZero(axis) { + var dataExtent = axis.scale.getExtent(); + var min = dataExtent[0]; + var max = dataExtent[1]; + return !(min > 0 && max > 0 || min < 0 && max < 0); + } + /** + * @param axis + * @return Label formatter function. + * param: {number} tickValue, + * param: {number} idx, the index in all ticks. + * If category axis, this param is not required. + * return: {string} label string. + */ + + + function makeLabelFormatter(axis) { + var labelFormatter = axis.getLabelModel().get('formatter'); + + if (axis.type === 'time') { + var parsed_1 = parseTimeAxisLabelFormatter(labelFormatter); + return function (tick, idx) { + return axis.scale.getFormattedLabel(tick, idx, parsed_1); + }; + } else if (isString(labelFormatter)) { + return function (tick) { + // For category axis, get raw value; for numeric axis, + // get formatted label like '1,333,444'. + var label = axis.scale.getLabel(tick); + var text = labelFormatter.replace('{value}', label != null ? label : ''); + return text; + }; + } else if (isFunction(labelFormatter)) { + if (axis.type === 'category') { + return function (tick, idx) { + // The original intention of `idx` is "the index of the tick in all ticks". + // But the previous implementation of category axis do not consider the + // `axisLabel.interval`, which cause that, for example, the `interval` is + // `1`, then the ticks "name5", "name7", "name9" are displayed, where the + // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep + // the definition here for back compatibility. + return labelFormatter(getAxisRawValue(axis, tick), tick.value - axis.scale.getExtent()[0], null // Using `null` just for backward compat. + ); + }; + } + + var scaleBreakHelper_1 = getScaleBreakHelper(); + return function (tick, idx) { + // Using `null` just for backward compat. It's been found that in the `test/axis-customTicks.html`, + // there is a formatter `function (value, index, revers = true) { ... }`. Although the third param + // `revers` is incorrect and always `null`, changing it might introduce a breaking change. + var extra = null; + + if (scaleBreakHelper_1) { + extra = scaleBreakHelper_1.makeAxisLabelFormatterParamBreak(extra, tick["break"]); + } + + return labelFormatter(getAxisRawValue(axis, tick), idx, extra); + }; + } else { + return function (tick) { + return axis.scale.getLabel(tick); + }; + } + } + + function getAxisRawValue(axis, tick) { + // In category axis with data zoom, tick is not the original + // index of axis.data. So tick should not be exposed to user + // in category axis. + return axis.type === 'category' ? axis.scale.getLabel(tick) : tick.value; + } + /** + * @param model axisLabelModel or axisTickModel + * @return {number|String} Can be null|'auto'|number|function + */ + + + function getOptionCategoryInterval(model) { + var interval = model.get('interval'); + return interval == null ? 'auto' : interval; + } + /** + * Set `categoryInterval` as 0 implicitly indicates that + * show all labels regardless of overlap. + * @param {Object} axis axisModel.axis + */ + + + function shouldShowAllLabels(axis) { + return axis.type === 'category' && getOptionCategoryInterval(axis.getLabelModel()) === 0; + } + + function getDataDimensionsOnAxis(data, axisDim) { + // Remove duplicated dat dimensions caused by `getStackedDimension`. + var dataDimMap = {}; // Currently `mapDimensionsAll` will contain stack result dimension ('__\0ecstackresult'). + // PENDING: is it reasonable? Do we need to remove the original dim from "coord dim" since + // there has been stacked result dim? + + each$4(data.mapDimensionsAll(axisDim), function (dataDim) { + // For example, the extent of the original dimension + // is [0.1, 0.5], the extent of the `stackResultDimension` + // is [7, 9], the final extent should NOT include [0.1, 0.5], + // because there is no graphic corresponding to [0.1, 0.5]. + // See the case in `test/area-stack.html` `main1`, where area line + // stack needs `yAxis` not start from 0. + dataDimMap[getStackedDimension(data, dataDim)] = true; + }); + return keys(dataDimMap); + } + + function isNameLocationCenter(nameLocation) { + return nameLocation === 'middle' || nameLocation === 'center'; + } + + function shouldAxisShow(axisModel) { + return axisModel.getShallow('show'); + } + + function retrieveAxisBreaksOption(model) { + var option = model.get('breaks', true); + + if (option != null) { + { + { + error('Must `import {AxisBreak} from "echarts/features.js"; use(AxisBreak);` first if using breaks option.'); + } + return undefined; + } + } + } + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + + + var AxisModelCommonMixin = + /** @class */ + function () { + function AxisModelCommonMixin() {} + + AxisModelCommonMixin.prototype.getNeedCrossZero = function () { + var option = this.option; + return !option.scale; + }; + /** + * Should be implemented by each axis model if necessary. + * @return coordinate system model + */ + + + AxisModelCommonMixin.prototype.getCoordSysModel = function () { + return; + }; + + return AxisModelCommonMixin; + }(); + /** + * Create a multi dimension List structure from seriesModel. + */ + + + function createList$1(seriesModel) { + return createSeriesData(null, seriesModel); + } + + var dataStack = { + isDimensionStacked: isDimensionStacked, + enableDataStack: enableDataStack, + getStackedDimension: getStackedDimension + }; + /** + * Create scale + * @param {Array.} dataExtent + * @param {Object|module:echarts/Model} option If `optoin.type` + * is secified, it can only be `'value'` currently. + */ + + function createScale(dataExtent, option) { + var axisModel = option; + + if (!(option instanceof Model)) { + axisModel = new Model(option); // FIXME + // Currently AxisModelCommonMixin has nothing to do with the + // the requirements of `axisHelper.createScaleByModel`. For + // example the methods `getCategories` and `getOrdinalMeta` + // are required for `'category'` axis, and ecModel is required + // for `'time'` axis. But occasionally echarts-gl happened + // to only use `'value'` axis. + // zrUtil.mixin(axisModel, AxisModelCommonMixin); + } + + var scale = createScaleByModel(axisModel); + scale.setExtent(dataExtent[0], dataExtent[1]); + niceScaleExtent(scale, axisModel); + return scale; + } + /** + * Mixin common methods to axis model, + * + * Include methods + * `getFormattedLabels() => Array.` + * `getCategories() => Array.` + * `getMin(origin: boolean) => number` + * `getMax(origin: boolean) => number` + * `getNeedCrossZero() => boolean` + */ + + + function mixinAxisModelCommonMethods(Model) { + mixin(Model, AxisModelCommonMixin); + } + + function createTextStyle(textStyleModel, opts) { + opts = opts || {}; + return createTextStyle$1(textStyleModel, null, null, opts.state !== 'normal'); + } + + var helper = /*#__PURE__*/Object.freeze({ + __proto__: null, + createDimensions: createDimensions, + createList: createList$1, + createScale: createScale, + createSymbol: createSymbol, + createTextStyle: createTextStyle, + dataStack: dataStack, + enableHoverEmphasis: enableHoverEmphasis, + getECData: getECData, + getLayoutRect: getLayoutRect, + mixinAxisModelCommonMethods: mixinAxisModelCommonMethods + }); + var extensions = []; + var extensionRegisters = { + registerPreprocessor: registerPreprocessor, + registerProcessor: registerProcessor, + registerPostInit: registerPostInit, + registerPostUpdate: registerPostUpdate, + registerUpdateLifecycle: registerUpdateLifecycle, + registerAction: registerAction, + registerCoordinateSystem: registerCoordinateSystem, + registerLayout: registerLayout, + registerVisual: registerVisual, + registerTransform: registerTransform, + registerLoading: registerLoading, + registerMap: registerMap, + registerImpl: registerImpl, + PRIORITY: PRIORITY, + ComponentModel: ComponentModel, + ComponentView: ComponentView, + SeriesModel: SeriesModel, + ChartView: ChartView, + // TODO Use ComponentModel and SeriesModel instead of Constructor + registerComponentModel: function (ComponentModelClass) { + ComponentModel.registerClass(ComponentModelClass); + }, + registerComponentView: function (ComponentViewClass) { + ComponentView.registerClass(ComponentViewClass); + }, + registerSeriesModel: function (SeriesModelClass) { + SeriesModel.registerClass(SeriesModelClass); + }, + registerChartView: function (ChartViewClass) { + ChartView.registerClass(ChartViewClass); + }, + registerCustomSeries: function (seriesType, renderItem) {}, + registerSubTypeDefaulter: function (componentType, defaulter) { + ComponentModel.registerSubTypeDefaulter(componentType, defaulter); + }, + registerPainter: function (painterType, PainterCtor) { + registerPainter(painterType, PainterCtor); + } + }; + + function use(ext) { + if (isArray(ext)) { + // use([ChartLine, ChartBar]); + each$4(ext, function (singleExt) { + use(singleExt); + }); + return; + } + + if (indexOf(extensions, ext) >= 0) { + return; + } + + extensions.push(ext); + + if (isFunction(ext)) { + ext = { + install: ext + }; + } + + ext.install(extensionRegisters); + } + + var EPSILON = 1e-8; + + function isAroundEqual(a, b) { + return Math.abs(a - b) < EPSILON; + } + + function contain(points, x, y) { + var w = 0; + var p = points[0]; + + if (!p) { + return false; + } + + for (var i = 1; i < points.length; i++) { + var p2 = points[i]; + w += windingLine(p[0], p[1], p2[0], p2[1], x, y); + p = p2; + } + + var p0 = points[0]; + + if (!isAroundEqual(p[0], p0[0]) || !isAroundEqual(p[1], p0[1])) { + w += windingLine(p[0], p[1], p0[0], p0[1], x, y); + } + + return w !== 0; + } + + var TMP_TRANSFORM = []; + + function transformPoints(points, transform) { + for (var p = 0; p < points.length; p++) { + applyTransform$1(points[p], points[p], transform); + } + } + + function updateBBoxFromPoints(points, min, max, projection) { + for (var i = 0; i < points.length; i++) { + var p = points[i]; + + if (projection) { + // projection may return null point. + p = projection.project(p); + } + + if (p && isFinite(p[0]) && isFinite(p[1])) { + min$1(min, min, p); + max$1(max, max, p); + } + } + } + + function centroid(points) { + var signedArea = 0; + var cx = 0; + var cy = 0; + var len = points.length; + var x0 = points[len - 1][0]; + var y0 = points[len - 1][1]; // Polygon should been closed. + + for (var i = 0; i < len; i++) { + var x1 = points[i][0]; + var y1 = points[i][1]; + var a = x0 * y1 - x1 * y0; + signedArea += a; + cx += (x0 + x1) * a; + cy += (y0 + y1) * a; + x0 = x1; + y0 = y1; + } + + return signedArea ? [cx / signedArea / 3, cy / signedArea / 3, signedArea] : [points[0][0] || 0, points[0][1] || 0]; + } + + var Region = + /** @class */ + function () { + function Region(name) { + this.name = name; + } + + Region.prototype.setCenter = function (center) { + this._center = center; + }; + /** + * Get center point in data unit. That is, + * for GeoJSONRegion, the unit is lat/lng, + * for GeoSVGRegion, the unit is SVG local coord. + */ + + + Region.prototype.getCenter = function () { + var center = this._center; + + if (!center) { + // In most cases there are no need to calculate this center. + // So calculate only when called. + center = this._center = this.calcCenter(); + } + + return center; + }; + + return Region; + }(); + + var GeoJSONPolygonGeometry = + /** @class */ + function () { + function GeoJSONPolygonGeometry(exterior, interiors) { + this.type = 'polygon'; + this.exterior = exterior; + this.interiors = interiors; + } + + return GeoJSONPolygonGeometry; + }(); + + var GeoJSONLineStringGeometry = + /** @class */ + function () { + function GeoJSONLineStringGeometry(points) { + this.type = 'linestring'; + this.points = points; + } + + return GeoJSONLineStringGeometry; + }(); + + var GeoJSONRegion = + /** @class */ + function (_super) { + __extends(GeoJSONRegion, _super); + + function GeoJSONRegion(name, geometries, cp) { + var _this = _super.call(this, name) || this; + + _this.type = 'geoJSON'; + _this.geometries = geometries; + _this._center = cp && [cp[0], cp[1]]; + return _this; + } + + GeoJSONRegion.prototype.calcCenter = function () { + var geometries = this.geometries; + var largestGeo; + var largestGeoSize = 0; + + for (var i = 0; i < geometries.length; i++) { + var geo = geometries[i]; + var exterior = geo.exterior; // Simple trick to use points count instead of polygon area as region size. + // Ignore linestring + + var size = exterior && exterior.length; + + if (size > largestGeoSize) { + largestGeo = geo; + largestGeoSize = size; + } + } + + if (largestGeo) { + return centroid(largestGeo.exterior); + } // from bounding rect by default. + + + var rect = this.getBoundingRect(); + return [rect.x + rect.width / 2, rect.y + rect.height / 2]; + }; + + GeoJSONRegion.prototype.getBoundingRect = function (projection) { + var rect = this._rect; // Always recalculate if using projection. + + if (rect && !projection) { + return rect; + } + + var min = [Infinity, Infinity]; + var max = [-Infinity, -Infinity]; + var geometries = this.geometries; + each$4(geometries, function (geo) { + if (geo.type === 'polygon') { + // Doesn't consider hole + updateBBoxFromPoints(geo.exterior, min, max, projection); + } else { + each$4(geo.points, function (points) { + updateBBoxFromPoints(points, min, max, projection); + }); + } + }); // Normalie invalid bounding. + + if (!(isFinite(min[0]) && isFinite(min[1]) && isFinite(max[0]) && isFinite(max[1]))) { + min[0] = min[1] = max[0] = max[1] = 0; + } + + rect = new BoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]); + + if (!projection) { + this._rect = rect; + } + + return rect; + }; + + GeoJSONRegion.prototype.contain = function (coord) { + var rect = this.getBoundingRect(); + var geometries = this.geometries; + + if (!rect.contain(coord[0], coord[1])) { + return false; + } + + loopGeo: for (var i = 0, len = geometries.length; i < len; i++) { + var geo = geometries[i]; // Only support polygon. + + if (geo.type !== 'polygon') { + continue; + } + + var exterior = geo.exterior; + var interiors = geo.interiors; + + if (contain(exterior, coord[0], coord[1])) { + // Not in the region if point is in the hole. + for (var k = 0; k < (interiors ? interiors.length : 0); k++) { + if (contain(interiors[k], coord[0], coord[1])) { + continue loopGeo; + } + } + + return true; + } + } + + return false; + }; + /** + * Transform the raw coords to target bounding. + * @param x + * @param y + * @param width + * @param height + */ + + + GeoJSONRegion.prototype.transformTo = function (x, y, width, height) { + var rect = this.getBoundingRect(); + var aspect = rect.width / rect.height; + + if (!width) { + width = aspect * height; + } else if (!height) { + height = width / aspect; + } + + var target = new BoundingRect(x, y, width, height); + var transform = rect.calculateTransform(target); + var geometries = this.geometries; + + for (var i = 0; i < geometries.length; i++) { + var geo = geometries[i]; + + if (geo.type === 'polygon') { + transformPoints(geo.exterior, transform); + each$4(geo.interiors, function (interior) { + transformPoints(interior, transform); + }); + } else { + each$4(geo.points, function (points) { + transformPoints(points, transform); + }); + } + } + + rect = this._rect; + rect.copy(target); // Update center + + this._center = [rect.x + rect.width / 2, rect.y + rect.height / 2]; + }; + + GeoJSONRegion.prototype.cloneShallow = function (name) { + name == null && (name = this.name); + var newRegion = new GeoJSONRegion(name, this.geometries, this._center); + newRegion._rect = this._rect; + newRegion.transformTo = null; // Simply avoid to be called. + + return newRegion; + }; + + return GeoJSONRegion; + }(Region); + /** @class */ + + + (function (_super) { + __extends(GeoSVGRegion, _super); + + function GeoSVGRegion(name, elOnlyForCalculate) { + var _this = _super.call(this, name) || this; + + _this.type = 'geoSVG'; + _this._elOnlyForCalculate = elOnlyForCalculate; + return _this; + } + + GeoSVGRegion.prototype.calcCenter = function () { + var el = this._elOnlyForCalculate; + var rect = el.getBoundingRect(); + var center = [rect.x + rect.width / 2, rect.y + rect.height / 2]; + var mat = identity(TMP_TRANSFORM); + var target = el; + + while (target && !target.isGeoSVGGraphicRoot) { + mul(mat, target.getLocalTransform(), mat); + target = target.parent; + } + + invert(mat, mat); + applyTransform$1(center, center, mat); + return center; + }; + + return GeoSVGRegion; + })(Region); + + function decode(json) { + if (!json.UTF8Encoding) { + return json; + } + + var jsonCompressed = json; + var encodeScale = jsonCompressed.UTF8Scale; + + if (encodeScale == null) { + encodeScale = 1024; + } + + var features = jsonCompressed.features; + each$4(features, function (feature) { + var geometry = feature.geometry; + var encodeOffsets = geometry.encodeOffsets; + var coordinates = geometry.coordinates; // Geometry may be appeded manually in the script after json loaded. + // In this case this geometry is usually not encoded. + + if (!encodeOffsets) { + return; + } + + switch (geometry.type) { + case 'LineString': + geometry.coordinates = decodeRing(coordinates, encodeOffsets, encodeScale); + break; + + case 'Polygon': + decodeRings(coordinates, encodeOffsets, encodeScale); + break; + + case 'MultiLineString': + decodeRings(coordinates, encodeOffsets, encodeScale); + break; + + case 'MultiPolygon': + each$4(coordinates, function (rings, idx) { + return decodeRings(rings, encodeOffsets[idx], encodeScale); + }); + } + }); // Has been decoded + + jsonCompressed.UTF8Encoding = false; + return jsonCompressed; + } + + function decodeRings(rings, encodeOffsets, encodeScale) { + for (var c = 0; c < rings.length; c++) { + rings[c] = decodeRing(rings[c], encodeOffsets[c], encodeScale); + } + } + + function decodeRing(coordinate, encodeOffsets, encodeScale) { + var result = []; + var prevX = encodeOffsets[0]; + var prevY = encodeOffsets[1]; + + for (var i = 0; i < coordinate.length; i += 2) { + var x = coordinate.charCodeAt(i) - 64; + var y = coordinate.charCodeAt(i + 1) - 64; // ZigZag decoding + + x = x >> 1 ^ -(x & 1); + y = y >> 1 ^ -(y & 1); // Delta deocding + + x += prevX; + y += prevY; + prevX = x; + prevY = y; // Dequantize + + result.push([x / encodeScale, y / encodeScale]); + } + + return result; + } + + function parseGeoJSON(geoJson, nameProperty) { + geoJson = decode(geoJson); + return map$1(filter(geoJson.features, function (featureObj) { + // Output of mapshaper may have geometry null + return featureObj.geometry && featureObj.properties && featureObj.geometry.coordinates.length > 0; + }), function (featureObj) { + var properties = featureObj.properties; + var geo = featureObj.geometry; + var geometries = []; + + switch (geo.type) { + case 'Polygon': + var coordinates = geo.coordinates; // According to the GeoJSON specification. + // First must be exterior, and the rest are all interior(holes). + + geometries.push(new GeoJSONPolygonGeometry(coordinates[0], coordinates.slice(1))); + break; + + case 'MultiPolygon': + each$4(geo.coordinates, function (item) { + if (item[0]) { + geometries.push(new GeoJSONPolygonGeometry(item[0], item.slice(1))); + } + }); + break; + + case 'LineString': + geometries.push(new GeoJSONLineStringGeometry([geo.coordinates])); + break; + + case 'MultiLineString': + geometries.push(new GeoJSONLineStringGeometry(geo.coordinates)); + } + + var region = new GeoJSONRegion(properties[nameProperty || 'name'], geometries, properties.cp); + region.properties = properties; + return region; + }); + } + + var number = /*#__PURE__*/Object.freeze({ + __proto__: null, + MAX_SAFE_INTEGER: MAX_SAFE_INTEGER, + asc: asc, + getPercentWithPrecision: getPercentWithPrecision, + getPixelPrecision: getPixelPrecision, + getPrecision: getPrecision, + getPrecisionSafe: getPrecisionSafe, + isNumeric: isNumeric, + isRadianAroundZero: isRadianAroundZero, + linearMap: linearMap, + nice: nice, + numericToNumber: numericToNumber, + parseDate: parseDate, + parsePercent: parsePercent, + quantile: quantile, + quantity: quantity, + quantityExponent: quantityExponent, + reformIntervals: reformIntervals, + remRadian: remRadian, + round: round$1 + }); + var time = /*#__PURE__*/Object.freeze({ + __proto__: null, + format: format$1, + parse: parseDate, + roundTime: roundTime + }); + var graphic = /*#__PURE__*/Object.freeze({ + __proto__: null, + Arc: Arc, + BezierCurve: BezierCurve, + BoundingRect: BoundingRect, + Circle: Circle, + CompoundPath: CompoundPath, + Ellipse: Ellipse, + Group: Group$2, + Image: ZRImage, + IncrementalDisplayable: IncrementalDisplayable, + Line: Line, + LinearGradient: LinearGradient, + Polygon: Polygon, + Polyline: Polyline, + RadialGradient: RadialGradient, + Rect: Rect, + Ring: Ring, + Sector: Sector, + Text: ZRText, + clipPointsByRect: clipPointsByRect, + clipRectByRect: clipRectByRect, + createIcon: createIcon, + extendPath: extendPath, + extendShape: extendShape, + getShapeClass: getShapeClass, + getTransform: getTransform, + initProps: initProps, + makeImage: makeImage, + makePath: makePath, + mergePath: mergePath, + registerShape: registerShape, + resizePath: resizePath, + updateProps: updateProps$1 + }); + var format = /*#__PURE__*/Object.freeze({ + __proto__: null, + addCommas: addCommas, + capitalFirst: capitalFirst, + encodeHTML: encodeHTML, + formatTime: formatTime, + formatTpl: formatTpl, + getTextRect: getTextRect, + getTooltipMarker: getTooltipMarker, + normalizeCssArray: normalizeCssArray, + toCamelCase: toCamelCase, + truncateText: truncateText + }); + var util = /*#__PURE__*/Object.freeze({ + __proto__: null, + bind: bind$1, + clone: clone$3, + curry: curry$1, + defaults: defaults, + each: each$4, + extend: extend, + filter: filter, + indexOf: indexOf, + inherits: inherits, + isArray: isArray, + isFunction: isFunction, + isObject: isObject$2, + isString: isString, + map: map$1, + merge: merge, + reduce: reduce + }); + var modelInner = makeInner(); + var axisInner = makeInner(); + var AxisTickLabelComputingKind = { + estimate: 1, + determine: 2 + }; + + function createAxisLabelsComputingContext(kind) { + return { + out: { + noPxChangeTryDetermine: [] + }, + kind: kind + }; + } + + function tickValuesToNumbers(axis, values) { + var nums = map$1(values, function (val) { + return axis.scale.parse(val); + }); + + if (axis.type === 'time' && nums.length > 0) { + // Time axis needs duplicate first/last tick (see TimeScale.getTicks()) + // The first and last tick/label don't get drawn + nums.sort(); + nums.unshift(nums[0]); + nums.push(nums[nums.length - 1]); + } + + return nums; + } + + function createAxisLabels(axis, ctx) { + var custom = axis.getLabelModel().get('customValues'); + + if (custom) { + var labelFormatter_1 = makeLabelFormatter(axis); + var extent_1 = axis.scale.getExtent(); + var tickNumbers = tickValuesToNumbers(axis, custom); + var ticks = filter(tickNumbers, function (val) { + return val >= extent_1[0] && val <= extent_1[1]; + }); + return { + labels: map$1(ticks, function (numval) { + var tick = { + value: numval + }; + return { + formattedLabel: labelFormatter_1(tick), + rawLabel: axis.scale.getLabel(tick), + tickValue: numval, + time: undefined, + "break": undefined + }; + }) + }; + } // Only ordinal scale support tick interval + + + return axis.type === 'category' ? makeCategoryLabels(axis, ctx) : makeRealNumberLabels(axis); + } + /** + * @param tickModel For example, can be axisTick, splitLine, splitArea. + */ + + + function createAxisTicks(axis, tickModel, opt) { + var custom = axis.getTickModel().get('customValues'); + + if (custom) { + var extent_2 = axis.scale.getExtent(); + var tickNumbers = tickValuesToNumbers(axis, custom); + return { + ticks: filter(tickNumbers, function (val) { + return val >= extent_2[0] && val <= extent_2[1]; + }) + }; + } // Only ordinal scale support tick interval + + + return axis.type === 'category' ? makeCategoryTicks(axis, tickModel) : { + ticks: map$1(axis.scale.getTicks(opt), function (tick) { + return tick.value; + }) + }; + } + + function makeCategoryLabels(axis, ctx) { + var labelModel = axis.getLabelModel(); + var result = makeCategoryLabelsActually(axis, labelModel, ctx); + return !labelModel.get('show') || axis.scale.isBlank() ? { + labels: [] + } : result; + } + + function makeCategoryLabelsActually(axis, labelModel, ctx) { + var labelsCache = ensureCategoryLabelCache(axis); + var optionLabelInterval = getOptionCategoryInterval(labelModel); + var isEstimate = ctx.kind === AxisTickLabelComputingKind.estimate; // In AxisTickLabelComputingKind.estimate, the result likely varies during a single + // pass of ec main process,due to the change of axisExtent, and will not be shared with + // splitLine. Therefore no cache is used. + + if (!isEstimate) { + // PENDING: check necessary? + var result_1 = axisCacheGet(labelsCache, optionLabelInterval); + + if (result_1) { + return result_1; + } + } + + var labels; + var numericLabelInterval; + + if (isFunction(optionLabelInterval)) { + labels = makeLabelsByCustomizedCategoryInterval(axis, optionLabelInterval); + } else { + numericLabelInterval = optionLabelInterval === 'auto' ? makeAutoCategoryInterval(axis, ctx) : optionLabelInterval; + labels = makeLabelsByNumericCategoryInterval(axis, numericLabelInterval); + } + + var result = { + labels: labels, + labelCategoryInterval: numericLabelInterval + }; + + if (!isEstimate) { + axisCacheSet(labelsCache, optionLabelInterval, result); + } else { + ctx.out.noPxChangeTryDetermine.push(function () { + axisCacheSet(labelsCache, optionLabelInterval, result); + return true; + }); + } + + return result; + } + + function makeCategoryTicks(axis, tickModel) { + var ticksCache = ensureCategoryTickCache(axis); + var optionTickInterval = getOptionCategoryInterval(tickModel); + var result = axisCacheGet(ticksCache, optionTickInterval); + + if (result) { + return result; + } + + var ticks; + var tickCategoryInterval; // Optimize for the case that large category data and no label displayed, + // we should not return all ticks. + + if (!tickModel.get('show') || axis.scale.isBlank()) { + ticks = []; + } + + if (isFunction(optionTickInterval)) { + ticks = makeLabelsByCustomizedCategoryInterval(axis, optionTickInterval, true); + } // Always use label interval by default despite label show. Consider this + // scenario, Use multiple grid with the xAxis sync, and only one xAxis shows + // labels. `splitLine` and `axisTick` should be consistent in this case. + else if (optionTickInterval === 'auto') { + var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel(), createAxisLabelsComputingContext(AxisTickLabelComputingKind.determine)); + tickCategoryInterval = labelsResult.labelCategoryInterval; + ticks = map$1(labelsResult.labels, function (labelItem) { + return labelItem.tickValue; + }); + } else { + tickCategoryInterval = optionTickInterval; + ticks = makeLabelsByNumericCategoryInterval(axis, tickCategoryInterval, true); + } // Cache to avoid calling interval function repeatedly. + + + return axisCacheSet(ticksCache, optionTickInterval, { + ticks: ticks, + tickCategoryInterval: tickCategoryInterval + }); + } + + function makeRealNumberLabels(axis) { + var ticks = axis.scale.getTicks(); + var labelFormatter = makeLabelFormatter(axis); + return { + labels: map$1(ticks, function (tick, idx) { + return { + formattedLabel: labelFormatter(tick, idx), + rawLabel: axis.scale.getLabel(tick), + tickValue: tick.value, + time: tick.time, + "break": tick["break"] + }; + }) + }; + } // Large category data calculation is performance sensitive, and ticks and label probably will + // be fetched multiple times (e.g. shared by splitLine and axisTick). So we cache the result. + // axis is created each time during a ec process, so we do not need to clear cache. + + + var ensureCategoryTickCache = initAxisCacheMethod('axisTick'); + var ensureCategoryLabelCache = initAxisCacheMethod('axisLabel'); + /** + * PENDING: refactor to JS Map? Because key can be a function or more complicated object, and + * cache size always is small, and currently no JS Map object key polyfill, we use a simple + * array cache instead of plain object hash. + */ + + function initAxisCacheMethod(prop) { + return function ensureCache(axis) { + return axisInner(axis)[prop] || (axisInner(axis)[prop] = { + list: [] + }); + }; + } + + function axisCacheGet(cache, key) { + for (var i = 0; i < cache.list.length; i++) { + if (cache.list[i].key === key) { + return cache.list[i].value; + } + } + } + + function axisCacheSet(cache, key, value) { + cache.list.push({ + key: key, + value: value + }); + return value; + } + + function makeAutoCategoryInterval(axis, ctx) { + if (ctx.kind === AxisTickLabelComputingKind.estimate) { + // Currently axisTick is not involved in estimate kind, and the result likely varies during a + // single pass of ec main process, due to the change of axisExtent. Therefore no cache is used. + var result_2 = axis.calculateCategoryInterval(ctx); + ctx.out.noPxChangeTryDetermine.push(function () { + axisInner(axis).autoInterval = result_2; + return true; + }); + return result_2; + } // Both tick and label uses this result, cacah it to avoid recompute. + + + var result = axisInner(axis).autoInterval; + return result != null ? result : axisInner(axis).autoInterval = axis.calculateCategoryInterval(ctx); + } + /** + * Calculate interval for category axis ticks and labels. + * Use a stretegy to try to avoid overlapping. + * To get precise result, at least one of `getRotate` and `isHorizontal` + * should be implemented in axis. + */ + + + function calculateCategoryInterval(axis, ctx) { + var kind = ctx.kind; + var params = fetchAutoCategoryIntervalCalculationParams(axis); + var labelFormatter = makeLabelFormatter(axis); + var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI; + var ordinalScale = axis.scale; + var ordinalExtent = ordinalScale.getExtent(); // Providing this method is for optimization: + // avoid generating a long array by `getTicks` + // in large category data case. + + var tickCount = ordinalScale.count(); + + if (ordinalExtent[1] - ordinalExtent[0] < 1) { + return 0; + } + + var step = 1; // Simple optimization. Arbitrary value. + + var maxCount = 40; + + if (tickCount > maxCount) { + step = Math.max(1, Math.floor(tickCount / maxCount)); + } + + var tickValue = ordinalExtent[0]; + var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue); + var unitW = Math.abs(unitSpan * Math.cos(rotation)); + var unitH = Math.abs(unitSpan * Math.sin(rotation)); + var maxW = 0; + var maxH = 0; // Caution: Performance sensitive for large category data. + // Consider dataZoom, we should make appropriate step to avoid O(n) loop. + + for (; tickValue <= ordinalExtent[1]; tickValue += step) { + var width = 0; + var height = 0; // Not precise, do not consider align and vertical align + // and each distance from axis line yet. + + var rect = getBoundingRect(labelFormatter({ + value: tickValue + }), params.font, 'center', 'top'); // Magic number + + width = rect.width * 1.3; + height = rect.height * 1.3; // Min size, void long loop. + + maxW = Math.max(maxW, width, 7); + maxH = Math.max(maxH, height, 7); + } + + var dw = maxW / unitW; + var dh = maxH / unitH; // 0/0 is NaN, 1/0 is Infinity. + + isNaN(dw) && (dw = Infinity); + isNaN(dh) && (dh = Infinity); + var interval = Math.max(0, Math.floor(Math.min(dw, dh))); + + if (kind === AxisTickLabelComputingKind.estimate) { + // In estimate kind, the inteval likely varies, thus do not erase the cache. + ctx.out.noPxChangeTryDetermine.push(bind$1(calculateCategoryIntervalTryDetermine, null, axis, interval, tickCount)); + return interval; + } + + var lastInterval = calculateCategoryIntervalDealCache(axis, interval, tickCount); + return lastInterval != null ? lastInterval : interval; + } + + function calculateCategoryIntervalTryDetermine(axis, interval, tickCount) { + return calculateCategoryIntervalDealCache(axis, interval, tickCount) == null; + } // Return the lastInterval if need to use it, otherwise return NullUndefined and save cache. + + + function calculateCategoryIntervalDealCache(axis, interval, tickCount) { + var cache = modelInner(axis.model); + var axisExtent = axis.getExtent(); + var lastAutoInterval = cache.lastAutoInterval; + var lastTickCount = cache.lastTickCount; // Use cache to keep interval stable while moving zoom window, + // otherwise the calculated interval might jitter when the zoom + // window size is close to the interval-changing size. + // For example, if all of the axis labels are `a, b, c, d, e, f, g`. + // The jitter will cause that sometimes the displayed labels are + // `a, d, g` (interval: 2) sometimes `a, c, e`(interval: 1). + + if (lastAutoInterval != null && lastTickCount != null && Math.abs(lastAutoInterval - interval) <= 1 && Math.abs(lastTickCount - tickCount) <= 1 // Always choose the bigger one, otherwise the critical + // point is not the same when zooming in or zooming out. + && lastAutoInterval > interval // If the axis change is caused by chart resize, the cache should not + // be used. Otherwise some hidden labels might not be shown again. + && cache.axisExtent0 === axisExtent[0] && cache.axisExtent1 === axisExtent[1]) { + return lastAutoInterval; + } // Only update cache if cache not used, otherwise the + // changing of interval is too insensitive. + else { + cache.lastTickCount = tickCount; + cache.lastAutoInterval = interval; + cache.axisExtent0 = axisExtent[0]; + cache.axisExtent1 = axisExtent[1]; + } + } + + function fetchAutoCategoryIntervalCalculationParams(axis) { + var labelModel = axis.getLabelModel(); + return { + axisRotate: axis.getRotate ? axis.getRotate() : axis.isHorizontal && !axis.isHorizontal() ? 90 : 0, + labelRotate: labelModel.get('rotate') || 0, + font: labelModel.getFont() + }; + } + + function makeLabelsByNumericCategoryInterval(axis, categoryInterval, onlyTick) { + var labelFormatter = makeLabelFormatter(axis); + var ordinalScale = axis.scale; + var ordinalExtent = ordinalScale.getExtent(); + var labelModel = axis.getLabelModel(); + var result = []; // TODO: axisType: ordinalTime, pick the tick from each month/day/year/... + + var step = Math.max((categoryInterval || 0) + 1, 1); + var startTick = ordinalExtent[0]; + var tickCount = ordinalScale.count(); // Calculate start tick based on zero if possible to keep label consistent + // while zooming and moving while interval > 0. Otherwise the selection + // of displayable ticks and symbols probably keep changing. + // 3 is empirical value. + + if (startTick !== 0 && step > 1 && tickCount / step > 2) { + startTick = Math.round(Math.ceil(startTick / step) * step); + } // (1) Only add min max label here but leave overlap checking + // to render stage, which also ensure the returned list + // suitable for splitLine and splitArea rendering. + // (2) Scales except category always contain min max label so + // do not need to perform this process. + + + var showAllLabel = shouldShowAllLabels(axis); + var includeMinLabel = labelModel.get('showMinLabel') || showAllLabel; + var includeMaxLabel = labelModel.get('showMaxLabel') || showAllLabel; + + if (includeMinLabel && startTick !== ordinalExtent[0]) { + addItem(ordinalExtent[0]); + } // Optimize: avoid generating large array by `ordinalScale.getTicks()`. + + + var tickValue = startTick; + + for (; tickValue <= ordinalExtent[1]; tickValue += step) { + addItem(tickValue); + } + + if (includeMaxLabel && tickValue - step !== ordinalExtent[1]) { + addItem(ordinalExtent[1]); + } + + function addItem(tickValue) { + var tickObj = { + value: tickValue + }; + result.push(onlyTick ? tickValue : { + formattedLabel: labelFormatter(tickObj), + rawLabel: ordinalScale.getLabel(tickObj), + tickValue: tickValue, + time: undefined, + "break": undefined + }); + } + + return result; + } + + function makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) { + var ordinalScale = axis.scale; + var labelFormatter = makeLabelFormatter(axis); + var result = []; + each$4(ordinalScale.getTicks(), function (tick) { + var rawLabel = ordinalScale.getLabel(tick); + var tickValue = tick.value; + + if (categoryInterval(tick.value, rawLabel)) { + result.push(onlyTick ? tickValue : { + formattedLabel: labelFormatter(tick), + rawLabel: rawLabel, + tickValue: tickValue, + time: undefined, + "break": undefined + }); + } + }); + return result; + } + + var NORMALIZED_EXTENT = [0, 1]; + /** + * Base class of Axis. + * + * Lifetime: recreate for each main process. + * [NOTICE]: Some caches is stored on the axis instance (see `axisTickLabelBuilder.ts`) + * which is based on this lifetime. + */ + + var Axis = + /** @class */ + function () { + function Axis(dim, scale, extent) { + this.onBand = false; // Make sure that `extent[0] > extent[1]` only if `inverse: true`. + // `inverse` can be inferred by `extent` unless `extent[0] === extent[1]`. + + this.inverse = false; + this.dim = dim; + this.scale = scale; + this._extent = extent || [0, 0]; + } + /** + * If axis extent contain given coord + */ + + + Axis.prototype.contain = function (coord) { + var extent = this._extent; + var min = Math.min(extent[0], extent[1]); + var max = Math.max(extent[0], extent[1]); + return coord >= min && coord <= max; + }; + /** + * If axis extent contain given data + */ + + + Axis.prototype.containData = function (data) { + return this.scale.contain(this.scale.parse(data)); + }; + /** + * Get coord extent. + */ + + + Axis.prototype.getExtent = function () { + return this._extent.slice(); + }; + /** + * Get precision used for formatting + */ + + + Axis.prototype.getPixelPrecision = function (dataExtent) { + return getPixelPrecision(dataExtent || this.scale.getExtent(), this._extent); + }; + /** + * Set coord extent + */ + + + Axis.prototype.setExtent = function (start, end) { + var extent = this._extent; + extent[0] = start; + extent[1] = end; + }; + /** + * Convert data to coord. Data is the rank if it has an ordinal scale + */ + + + Axis.prototype.dataToCoord = function (data, clamp) { + var extent = this._extent; + var scale = this.scale; + data = scale.normalize(scale.parse(data)); + + if (this.onBand && scale.type === 'ordinal') { + extent = extent.slice(); + fixExtentWithBands(extent, scale.count()); + } + + return linearMap(data, NORMALIZED_EXTENT, extent, clamp); + }; + /** + * Convert coord to data. Data is the rank if it has an ordinal scale + */ + + + Axis.prototype.coordToData = function (coord, clamp) { + var extent = this._extent; + var scale = this.scale; + + if (this.onBand && scale.type === 'ordinal') { + extent = extent.slice(); + fixExtentWithBands(extent, scale.count()); + } + + var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp); + return this.scale.scale(t); + }; + /** + * Convert pixel point to data in axis + */ + + + Axis.prototype.pointToData = function (point, clamp) { + // Should be implemented in derived class if necessary. + return; + }; + /** + * Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`, + * `axis.getTicksCoords` considers `onBand`, which is used by + * `boundaryGap:true` of category axis and splitLine and splitArea. + * @param opt.tickModel default: axis.model.getModel('axisTick') + * @param opt.clamp If `true`, the first and the last + * tick must be at the axis end points. Otherwise, clip ticks + * that outside the axis extent. + */ + + + Axis.prototype.getTicksCoords = function (opt) { + opt = opt || {}; + var tickModel = opt.tickModel || this.getTickModel(); + var result = createAxisTicks(this, tickModel, { + breakTicks: opt.breakTicks, + pruneByBreak: opt.pruneByBreak + }); + var ticks = result.ticks; + var ticksCoords = map$1(ticks, function (tickVal) { + return { + coord: this.dataToCoord(this.scale.type === 'ordinal' ? this.scale.getRawOrdinalNumber(tickVal) : tickVal), + tickValue: tickVal + }; + }, this); + var alignWithLabel = tickModel.get('alignWithLabel'); + fixOnBandTicksCoords(this, ticksCoords, alignWithLabel, opt.clamp); + return ticksCoords; + }; + + Axis.prototype.getMinorTicksCoords = function () { + if (this.scale.type === 'ordinal') { + // Category axis doesn't support minor ticks + return []; + } + + var minorTickModel = this.model.getModel('minorTick'); + var splitNumber = minorTickModel.get('splitNumber'); // Protection. + + if (!(splitNumber > 0 && splitNumber < 100)) { + splitNumber = 5; + } + + var minorTicks = this.scale.getMinorTicks(splitNumber); + var minorTicksCoords = map$1(minorTicks, function (minorTicksGroup) { + return map$1(minorTicksGroup, function (minorTick) { + return { + coord: this.dataToCoord(minorTick), + tickValue: minorTick + }; + }, this); + }, this); + return minorTicksCoords; + }; + + Axis.prototype.getViewLabels = function (ctx) { + ctx = ctx || createAxisLabelsComputingContext(AxisTickLabelComputingKind.determine); + return createAxisLabels(this, ctx).labels; + }; + + Axis.prototype.getLabelModel = function () { + return this.model.getModel('axisLabel'); + }; + /** + * Notice here we only get the default tick model. For splitLine + * or splitArea, we should pass the splitLineModel or splitAreaModel + * manually when calling `getTicksCoords`. + * In GL, this method may be overridden to: + * `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));` + */ + + + Axis.prototype.getTickModel = function () { + return this.model.getModel('axisTick'); + }; + /** + * Get width of band + */ + + + Axis.prototype.getBandWidth = function () { + var axisExtent = this._extent; + var dataExtent = this.scale.getExtent(); + var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0); // Fix #2728, avoid NaN when only one data. + + len === 0 && (len = 1); + var size = Math.abs(axisExtent[1] - axisExtent[0]); + return Math.abs(size) / len; + }; + /** + * Only be called in category axis. + * Can be overridden, consider other axes like in 3D. + * @return Auto interval for cateogry axis tick and label + */ + + + Axis.prototype.calculateCategoryInterval = function (ctx) { + ctx = ctx || createAxisLabelsComputingContext(AxisTickLabelComputingKind.determine); + return calculateCategoryInterval(this, ctx); + }; + + return Axis; + }(); + + function fixExtentWithBands(extent, nTick) { + var size = extent[1] - extent[0]; + var len = nTick; + var margin = size / len / 2; + extent[0] += margin; + extent[1] -= margin; + } // If axis has labels [1, 2, 3, 4]. Bands on the axis are + // |---1---|---2---|---3---|---4---|. + // So the displayed ticks and splitLine/splitArea should between + // each data item, otherwise cause misleading (e.g., split tow bars + // of a single data item when there are two bar series). + // Also consider if tickCategoryInterval > 0 and onBand, ticks and + // splitLine/spliteArea should layout appropriately corresponding + // to displayed labels. (So we should not use `getBandWidth` in this + // case). + + + function fixOnBandTicksCoords(axis, ticksCoords, alignWithLabel, clamp) { + var ticksLen = ticksCoords.length; + + if (!axis.onBand || alignWithLabel || !ticksLen) { + return; + } + + var axisExtent = axis.getExtent(); + var last; + var diffSize; + + if (ticksLen === 1) { + ticksCoords[0].coord = axisExtent[0]; + ticksCoords[0].onBand = true; + last = ticksCoords[1] = { + coord: axisExtent[1], + tickValue: ticksCoords[0].tickValue, + onBand: true + }; + } else { + var crossLen = ticksCoords[ticksLen - 1].tickValue - ticksCoords[0].tickValue; + var shift_1 = (ticksCoords[ticksLen - 1].coord - ticksCoords[0].coord) / crossLen; + each$4(ticksCoords, function (ticksItem) { + ticksItem.coord -= shift_1 / 2; + ticksItem.onBand = true; + }); + var dataExtent = axis.scale.getExtent(); + diffSize = 1 + dataExtent[1] - ticksCoords[ticksLen - 1].tickValue; + last = { + coord: ticksCoords[ticksLen - 1].coord + shift_1 * diffSize, + tickValue: dataExtent[1] + 1, + onBand: true + }; + ticksCoords.push(last); + } + + var inverse = axisExtent[0] > axisExtent[1]; // Handling clamp. + + if (littleThan(ticksCoords[0].coord, axisExtent[0])) { + clamp ? ticksCoords[0].coord = axisExtent[0] : ticksCoords.shift(); + } + + if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) { + ticksCoords.unshift({ + coord: axisExtent[0], + onBand: true + }); + } + + if (littleThan(axisExtent[1], last.coord)) { + clamp ? last.coord = axisExtent[1] : ticksCoords.pop(); + } + + if (clamp && littleThan(last.coord, axisExtent[1])) { + ticksCoords.push({ + coord: axisExtent[1], + onBand: true + }); + } + + function littleThan(a, b) { + // Avoid rounding error cause calculated tick coord different with extent. + // It may cause an extra unnecessary tick added. + a = round$1(a); + b = round$1(b); + return inverse ? a > b : a < b; + } + } // --------------------- Deprecated Extension Methods --------------------- + // Should use `ComponentModel.extend` or `class XXXX extend ComponentModel` to create class. + // Then use `registerComponentModel` in `install` parameter when `use` this extension. For example: + // class Bar3DModel extends ComponentModel {} + // export function install(registers) { registers.registerComponentModel(Bar3DModel); } + // echarts.use(install); + + + function extendComponentModel(proto) { + var Model = ComponentModel.extend(proto); + ComponentModel.registerClass(Model); + return Model; + } + + function extendComponentView(proto) { + var View = ComponentView.extend(proto); + ComponentView.registerClass(View); + return View; + } + + function extendSeriesModel(proto) { + var Model = SeriesModel.extend(proto); + SeriesModel.registerClass(Model); + return Model; + } + + function extendChartView(proto) { + var View = ChartView.extend(proto); + ChartView.registerClass(View); + return View; + } + + var PI2 = Math.PI * 2; + var CMD = PathProxy.CMD; + var DEFAULT_SEARCH_SPACE = ['top', 'right', 'bottom', 'left']; + + function getCandidateAnchor(pos, distance, rect, outPt, outDir) { + var width = rect.width; + var height = rect.height; + + switch (pos) { + case 'top': + outPt.set(rect.x + width / 2, rect.y - distance); + outDir.set(0, -1); + break; + + case 'bottom': + outPt.set(rect.x + width / 2, rect.y + height + distance); + outDir.set(0, 1); + break; + + case 'left': + outPt.set(rect.x - distance, rect.y + height / 2); + outDir.set(-1, 0); + break; + + case 'right': + outPt.set(rect.x + width + distance, rect.y + height / 2); + outDir.set(1, 0); + break; + } + } + + function projectPointToArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y, out) { + x -= cx; + y -= cy; + var d = Math.sqrt(x * x + y * y); + x /= d; + y /= d; // Intersect point. + + var ox = x * r + cx; + var oy = y * r + cy; + + if (Math.abs(startAngle - endAngle) % PI2 < 1e-4) { + // Is a circle + out[0] = ox; + out[1] = oy; + return d - r; + } + + if (anticlockwise) { + var tmp = startAngle; + startAngle = normalizeRadian(endAngle); + endAngle = normalizeRadian(tmp); + } else { + startAngle = normalizeRadian(startAngle); + endAngle = normalizeRadian(endAngle); + } + + if (startAngle > endAngle) { + endAngle += PI2; + } + + var angle = Math.atan2(y, x); + + if (angle < 0) { + angle += PI2; + } + + if (angle >= startAngle && angle <= endAngle || angle + PI2 >= startAngle && angle + PI2 <= endAngle) { + // Project point is on the arc. + out[0] = ox; + out[1] = oy; + return d - r; + } + + var x1 = r * Math.cos(startAngle) + cx; + var y1 = r * Math.sin(startAngle) + cy; + var x2 = r * Math.cos(endAngle) + cx; + var y2 = r * Math.sin(endAngle) + cy; + var d1 = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y); + var d2 = (x2 - x) * (x2 - x) + (y2 - y) * (y2 - y); + + if (d1 < d2) { + out[0] = x1; + out[1] = y1; + return Math.sqrt(d1); + } else { + out[0] = x2; + out[1] = y2; + return Math.sqrt(d2); + } + } + + function projectPointToLine(x1, y1, x2, y2, x, y, out, limitToEnds) { + var dx = x - x1; + var dy = y - y1; + var dx1 = x2 - x1; + var dy1 = y2 - y1; + var lineLen = Math.sqrt(dx1 * dx1 + dy1 * dy1); + dx1 /= lineLen; + dy1 /= lineLen; // dot product + + var projectedLen = dx * dx1 + dy * dy1; + var t = projectedLen / lineLen; + + if (limitToEnds) { + t = Math.min(Math.max(t, 0), 1); + } + + t *= lineLen; + var ox = out[0] = x1 + t * dx1; + var oy = out[1] = y1 + t * dy1; + return Math.sqrt((ox - x) * (ox - x) + (oy - y) * (oy - y)); + } + + function projectPointToRect(x1, y1, width, height, x, y, out) { + if (width < 0) { + x1 = x1 + width; + width = -width; + } + + if (height < 0) { + y1 = y1 + height; + height = -height; + } + + var x2 = x1 + width; + var y2 = y1 + height; + var ox = out[0] = Math.min(Math.max(x, x1), x2); + var oy = out[1] = Math.min(Math.max(y, y1), y2); + return Math.sqrt((ox - x) * (ox - x) + (oy - y) * (oy - y)); + } + + var tmpPt = []; + + function nearestPointOnRect(pt, rect, out) { + var dist = projectPointToRect(rect.x, rect.y, rect.width, rect.height, pt.x, pt.y, tmpPt); + out.set(tmpPt[0], tmpPt[1]); + return dist; + } + /** + * Calculate min distance corresponding point. + * This method won't evaluate if point is in the path. + */ + + + function nearestPointOnPath(pt, path, out) { + var xi = 0; + var yi = 0; + var x0 = 0; + var y0 = 0; + var x1; + var y1; + var minDist = Infinity; + var data = path.data; + var x = pt.x; + var y = pt.y; + + for (var i = 0; i < data.length;) { + var cmd = data[i++]; + + if (i === 1) { + xi = data[i]; + yi = data[i + 1]; + x0 = xi; + y0 = yi; + } + + var d = minDist; + + switch (cmd) { + case CMD.M: + // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点 + // 在 closePath 的时候使用 + x0 = data[i++]; + y0 = data[i++]; + xi = x0; + yi = y0; + break; + + case CMD.L: + d = projectPointToLine(xi, yi, data[i], data[i + 1], x, y, tmpPt, true); + xi = data[i++]; + yi = data[i++]; + break; + + case CMD.C: + d = cubicProjectPoint(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y, tmpPt); + xi = data[i++]; + yi = data[i++]; + break; + + case CMD.Q: + d = quadraticProjectPoint(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y, tmpPt); + xi = data[i++]; + yi = data[i++]; + break; + + case CMD.A: + // TODO Arc 判断的开销比较大 + var cx = data[i++]; + var cy = data[i++]; + var rx = data[i++]; + var ry = data[i++]; + var theta = data[i++]; + var dTheta = data[i++]; // TODO Arc 旋转 + + i += 1; + var anticlockwise = !!(1 - data[i++]); + x1 = Math.cos(theta) * rx + cx; + y1 = Math.sin(theta) * ry + cy; // 不是直接使用 arc 命令 + + if (i <= 1) { + // 第一个命令起点还未定义 + x0 = x1; + y0 = y1; + } // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放 + + + var _x = (x - cx) * ry / rx + cx; + + d = projectPointToArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y, tmpPt); + xi = Math.cos(theta + dTheta) * rx + cx; + yi = Math.sin(theta + dTheta) * ry + cy; + break; + + case CMD.R: + x0 = xi = data[i++]; + y0 = yi = data[i++]; + var width = data[i++]; + var height = data[i++]; + d = projectPointToRect(x0, y0, width, height, x, y, tmpPt); + break; + + case CMD.Z: + d = projectPointToLine(xi, yi, x0, y0, x, y, tmpPt, true); + xi = x0; + yi = y0; + break; + } + + if (d < minDist) { + minDist = d; + out.set(tmpPt[0], tmpPt[1]); + } + } + + return minDist; + } // Temporal variable for intermediate usage. + + + var pt0 = new Point(); + var pt1 = new Point(); + var pt2 = new Point(); + var dir = new Point(); + var dir2 = new Point(); + /** + * Calculate a proper guide line based on the label position and graphic element definition + * @param label + * @param labelRect + * @param target + * @param targetRect + */ + + function updateLabelLinePoints(target, labelLineModel) { + if (!target) { + return; + } + + var labelLine = target.getTextGuideLine(); + var label = target.getTextContent(); // Needs to create text guide in each charts. + + if (!(label && labelLine)) { + return; + } + + var labelGuideConfig = target.textGuideLineConfig || {}; + var points = [[0, 0], [0, 0], [0, 0]]; + var searchSpace = labelGuideConfig.candidates || DEFAULT_SEARCH_SPACE; + var labelRect = label.getBoundingRect().clone(); + labelRect.applyTransform(label.getComputedTransform()); + var minDist = Infinity; + var anchorPoint = labelGuideConfig.anchor; + var targetTransform = target.getComputedTransform(); + var targetInversedTransform = targetTransform && invert([], targetTransform); + var len = labelLineModel.get('length2') || 0; + + if (anchorPoint) { + pt2.copy(anchorPoint); + } + + for (var i = 0; i < searchSpace.length; i++) { + var candidate = searchSpace[i]; + getCandidateAnchor(candidate, 0, labelRect, pt0, dir); + Point.scaleAndAdd(pt1, pt0, dir, len); // Transform to target coord space. + + pt1.transform(targetInversedTransform); // Note: getBoundingRect will ensure the `path` being created. + + var boundingRect = target.getBoundingRect(); + var dist = anchorPoint ? anchorPoint.distance(pt1) : target instanceof Path ? nearestPointOnPath(pt1, target.path, pt2) : nearestPointOnRect(pt1, boundingRect, pt2); // TODO pt2 is in the path + + if (dist < minDist) { + minDist = dist; // Transform back to global space. + + pt1.transform(targetTransform); + pt2.transform(targetTransform); + pt2.toArray(points[0]); + pt1.toArray(points[1]); + pt0.toArray(points[2]); + } + } + + limitTurnAngle(points, labelLineModel.get('minTurnAngle')); + labelLine.setShape({ + points: points + }); + } // Temporal variable for the limitTurnAngle function + + + var tmpArr = []; + var tmpProjPoint = new Point(); + /** + * Reduce the line segment attached to the label to limit the turn angle between two segments. + * @param linePoints + * @param minTurnAngle Radian of minimum turn angle. 0 - 180 + */ + + function limitTurnAngle(linePoints, minTurnAngle) { + if (!(minTurnAngle <= 180 && minTurnAngle > 0)) { + return; + } + + minTurnAngle = minTurnAngle / 180 * Math.PI; // The line points can be + // /pt1----pt2 (label) + // / + // pt0/ + + pt0.fromArray(linePoints[0]); + pt1.fromArray(linePoints[1]); + pt2.fromArray(linePoints[2]); + Point.sub(dir, pt0, pt1); + Point.sub(dir2, pt2, pt1); + var len1 = dir.len(); + var len2 = dir2.len(); + + if (len1 < 1e-3 || len2 < 1e-3) { + return; + } + + dir.scale(1 / len1); + dir2.scale(1 / len2); + var angleCos = dir.dot(dir2); + var minTurnAngleCos = Math.cos(minTurnAngle); + + if (minTurnAngleCos < angleCos) { + // Smaller than minTurnAngle + // Calculate project point of pt0 on pt1-pt2 + var d = projectPointToLine(pt1.x, pt1.y, pt2.x, pt2.y, pt0.x, pt0.y, tmpArr, false); + tmpProjPoint.fromArray(tmpArr); // Calculate new projected length with limited minTurnAngle and get the new connect point + + tmpProjPoint.scaleAndAdd(dir2, d / Math.tan(Math.PI - minTurnAngle)); // Limit the new calculated connect point between pt1 and pt2. + + var t = pt2.x !== pt1.x ? (tmpProjPoint.x - pt1.x) / (pt2.x - pt1.x) : (tmpProjPoint.y - pt1.y) / (pt2.y - pt1.y); + + if (isNaN(t)) { + return; + } + + if (t < 0) { + Point.copy(tmpProjPoint, pt1); + } else if (t > 1) { + Point.copy(tmpProjPoint, pt2); + } + + tmpProjPoint.toArray(linePoints[1]); + } + } + + function setLabelLineState(labelLine, ignore, stateName, stateModel) { + var isNormal = stateName === 'normal'; + var stateObj = isNormal ? labelLine : labelLine.ensureState(stateName); // Make sure display. + + stateObj.ignore = ignore; // Set smooth + + var smooth = stateModel.get('smooth'); + + if (smooth && smooth === true) { + smooth = 0.3; + } + + stateObj.shape = stateObj.shape || {}; + + if (smooth > 0) { + stateObj.shape.smooth = smooth; + } + + var styleObj = stateModel.getModel('lineStyle').getLineStyle(); + isNormal ? labelLine.useStyle(styleObj) : stateObj.style = styleObj; + } + + function buildLabelLinePath(path, shape) { + var smooth = shape.smooth; + var points = shape.points; + + if (!points) { + return; + } + + path.moveTo(points[0][0], points[0][1]); + + if (smooth > 0 && points.length >= 3) { + var len1 = dist$1(points[0], points[1]); + var len2 = dist$1(points[1], points[2]); + + if (!len1 || !len2) { + path.lineTo(points[1][0], points[1][1]); + path.lineTo(points[2][0], points[2][1]); + return; + } + + var moveLen = Math.min(len1, len2) * smooth; + var midPoint0 = lerp$1([], points[1], points[0], moveLen / len1); + var midPoint2 = lerp$1([], points[1], points[2], moveLen / len2); + var midPoint1 = lerp$1([], midPoint0, midPoint2, 0.5); + path.bezierCurveTo(midPoint0[0], midPoint0[1], midPoint0[0], midPoint0[1], midPoint1[0], midPoint1[1]); + path.bezierCurveTo(midPoint2[0], midPoint2[1], midPoint2[0], midPoint2[1], points[2][0], points[2][1]); + } else { + for (var i = 1; i < points.length; i++) { + path.lineTo(points[i][0], points[i][1]); + } + } + } + /** + * Create a label line if necessary and set it's style. + */ + + + function setLabelLineStyle(targetEl, statesModels, defaultStyle) { + var labelLine = targetEl.getTextGuideLine(); + var label = targetEl.getTextContent(); + + if (!label) { + // Not show label line if there is no label. + if (labelLine) { + targetEl.removeTextGuideLine(); + } + + return; + } + + var normalModel = statesModels.normal; + var showNormal = normalModel.get('show'); + var labelIgnoreNormal = label.ignore; + + for (var i = 0; i < DISPLAY_STATES.length; i++) { + var stateName = DISPLAY_STATES[i]; + var stateModel = statesModels[stateName]; + var isNormal = stateName === 'normal'; + + if (stateModel) { + var stateShow = stateModel.get('show'); + var isLabelIgnored = isNormal ? labelIgnoreNormal : retrieve2(label.states[stateName] && label.states[stateName].ignore, labelIgnoreNormal); + + if (isLabelIgnored // Not show when label is not shown in this state. + || !retrieve2(stateShow, showNormal) // Use normal state by default if not set. + ) { + var stateObj = isNormal ? labelLine : labelLine && labelLine.states[stateName]; + + if (stateObj) { + stateObj.ignore = true; + } + + if (!!labelLine) { + setLabelLineState(labelLine, true, stateName, stateModel); + } + + continue; + } // Create labelLine if not exists + + + if (!labelLine) { + labelLine = new Polyline(); + targetEl.setTextGuideLine(labelLine); // Reset state of normal because it's new created. + // NOTE: NORMAL should always been the first! + + if (!isNormal && (labelIgnoreNormal || !showNormal)) { + setLabelLineState(labelLine, true, 'normal', statesModels.normal); + } // Use same state proxy. + + + if (targetEl.stateProxy) { + labelLine.stateProxy = targetEl.stateProxy; + } + } + + setLabelLineState(labelLine, false, stateName, stateModel); + } + } + + if (labelLine) { + defaults(labelLine.style, defaultStyle); // Not fill. + + labelLine.style.fill = null; + var showAbove = normalModel.get('showAbove'); + var labelLineConfig = targetEl.textGuideLineConfig = targetEl.textGuideLineConfig || {}; + labelLineConfig.showAbove = showAbove || false; // Custom the buildPath. + + labelLine.buildPath = buildLabelLinePath; + } + } + + function getLabelLineStatesModels(itemModel, labelLineName) { + labelLineName = labelLineName || 'labelLine'; + var statesModels = { + normal: itemModel.getModel(labelLineName) + }; + + for (var i = 0; i < SPECIAL_STATES.length; i++) { + var stateName = SPECIAL_STATES[i]; + statesModels[stateName] = itemModel.getModel([stateName, labelLineName]); + } + + return statesModels; + } + + var LABEL_LAYOUT_BASE_PROPS = ['label', 'labelLine', 'layoutOption', 'priority', 'defaultAttr', 'marginForce', 'minMarginForce', 'marginDefault', 'suggestIgnore']; + var LABEL_LAYOUT_DIRTY_BIT_OTHERS = 1; + var LABEL_LAYOUT_DIRTY_BIT_OBB = 2; + var LABEL_LAYOUT_DIRTY_ALL = LABEL_LAYOUT_DIRTY_BIT_OTHERS | LABEL_LAYOUT_DIRTY_BIT_OBB; + + function setLabelLayoutDirty(labelGeometry, dirtyOrClear, dirtyBits) { + dirtyBits = dirtyBits || LABEL_LAYOUT_DIRTY_ALL; + dirtyOrClear ? labelGeometry.dirty |= dirtyBits : labelGeometry.dirty &= ~dirtyBits; + } + + function isLabelLayoutDirty(labelGeometry, dirtyBits) { + dirtyBits = dirtyBits || LABEL_LAYOUT_DIRTY_ALL; + return labelGeometry.dirty == null || !!(labelGeometry.dirty & dirtyBits); + } + /** + * [CAUTION] + * - No auto dirty propagation mechanism yet. If the transform of the raw label or any of its ancestors is + * changed, must sync the changes to the props of `LabelGeometry` by: + * either explicitly call: + * `setLabelLayoutDirty(labelLayout, true); ensureLabelLayoutWithGeometry(labelLayout);` + * or call (if only translation is performed): + * `labelLayoutApplyTranslation(labelLayout);` + * - `label.ignore` is not necessarily falsy, and not considered in computing `LabelGeometry`, + * since it might be modified by some overlap resolving handling. + * - To duplicate or make a variation: + * use `newLabelLayoutWithGeometry`. + * + * The result can also be the input of this method. + * @return `NullUndefined` if and only if `labelLayout` is `NullUndefined`. + */ + + + function ensureLabelLayoutWithGeometry(labelLayout) { + if (!labelLayout) { + return; + } + + if (isLabelLayoutDirty(labelLayout)) { + computeLabelGeometry(labelLayout, labelLayout.label, labelLayout); + } + + return labelLayout; + } + /** + * The props in `out` will be filled if existing, or created. + */ + + + function computeLabelGeometry(out, label, opt) { + // [CAUTION] These props may be modified directly for performance consideration, + // therefore, do not output the internal data structure of zrender Element. + var rawTransform = label.getComputedTransform(); + out.transform = ensureCopyTransform(out.transform, rawTransform); // NOTE: should call `getBoundingRect` after `getComputedTransform`, or may get an inaccurate bounding rect. + // The reason is that `getComputedTransform` calls `__host.updateInnerText()` internally, which updates the label + // by `textConfig` mounted on the host. + // PENDING: add a dirty bit for that in zrender? + + var outLocalRect = out.localRect = ensureCopyRect(out.localRect, label.getBoundingRect()); + var labelStyleExt = label.style; + var margin = labelStyleExt.margin; + var marginForce = opt && opt.marginForce; + var minMarginForce = opt && opt.minMarginForce; + var marginDefault = opt && opt.marginDefault; + var marginType = labelStyleExt.__marginType; + + if (marginType == null && marginDefault) { + margin = marginDefault; + marginType = LabelMarginType.textMargin; + } // `textMargin` and `minMargin` can not exist both. + + + for (var i = 0; i < 4; i++) { + _tmpLabelMargin[i] = marginType === LabelMarginType.minMargin && minMarginForce && minMarginForce[i] != null ? minMarginForce[i] : marginForce && marginForce[i] != null ? marginForce[i] : margin ? margin[i] : 0; + } + + if (marginType === LabelMarginType.textMargin) { + expandOrShrinkRect(outLocalRect, _tmpLabelMargin, false, false); + } + + var outGlobalRect = out.rect = ensureCopyRect(out.rect, outLocalRect); + + if (rawTransform) { + outGlobalRect.applyTransform(rawTransform); + } // Notice: label.style.margin is actually `minMargin / 2`, handled by `setTextStyleCommon`. + + + if (marginType === LabelMarginType.minMargin) { + expandOrShrinkRect(outGlobalRect, _tmpLabelMargin, false, false); + } + + out.axisAligned = isBoundingRectAxisAligned(rawTransform); + (out.label = out.label || {}).ignore = label.ignore; + setLabelLayoutDirty(out, false); + setLabelLayoutDirty(out, true, LABEL_LAYOUT_DIRTY_BIT_OBB); // Do not remove `obb` (if existing) for reuse, just reset the dirty bit. + + return out; + } + + var _tmpLabelMargin = [0, 0, 0, 0]; + /** + * The props in `out` will be filled if existing, or created. + */ + + function computeLabelGeometry2(out, rawLocalRect, rawTransform) { + out.transform = ensureCopyTransform(out.transform, rawTransform); + out.localRect = ensureCopyRect(out.localRect, rawLocalRect); + out.rect = ensureCopyRect(out.rect, rawLocalRect); + + if (rawTransform) { + out.rect.applyTransform(rawTransform); + } + + out.axisAligned = isBoundingRectAxisAligned(rawTransform); + out.obb = undefined; // Reset to undefined, will be created by `ensureOBB` when using. + + (out.label = out.label || {}).ignore = false; + return out; + } + /** + * This is a shortcut of + * ```js + * labelLayout.label.x = newX; + * labelLayout.label.y = newY; + * setLabelLayoutDirty(labelLayout, true); + * ensureLabelLayoutWithGeometry(labelLayout); + * ``` + * and provide better performance in this common case. + */ + + + function labelLayoutApplyTranslation(labelLayout, offset) { + if (!labelLayout) { + return; + } + + labelLayout.label.x += offset.x; + labelLayout.label.y += offset.y; + labelLayout.label.markRedraw(); + var transform = labelLayout.transform; + + if (transform) { + transform[4] += offset.x; + transform[5] += offset.y; + } + + var globalRect = labelLayout.rect; + + if (globalRect) { + globalRect.x += offset.x; + globalRect.y += offset.y; + } + + var obb = labelLayout.obb; + + if (obb) { + obb.fromBoundingRect(labelLayout.localRect, transform); + } + } + /** + * To duplicate or make a variation of a label layout. + * Copy the only relevant properties to avoid the conflict or wrongly reuse of the props of `LabelLayoutWithGeometry`. + */ + + + function newLabelLayoutWithGeometry(newBaseWithDefaults, source) { + for (var i = 0; i < LABEL_LAYOUT_BASE_PROPS.length; i++) { + var prop = LABEL_LAYOUT_BASE_PROPS[i]; + + if (newBaseWithDefaults[prop] == null) { + newBaseWithDefaults[prop] = source[prop]; + } + } + + return ensureLabelLayoutWithGeometry(newBaseWithDefaults); + } + /** + * Create obb if no one, can cache it. + */ + + + function ensureOBB(labelGeometry) { + var obb = labelGeometry.obb; + + if (!obb || isLabelLayoutDirty(labelGeometry, LABEL_LAYOUT_DIRTY_BIT_OBB)) { + labelGeometry.obb = obb = obb || new OrientedBoundingRect(); + obb.fromBoundingRect(labelGeometry.localRect, labelGeometry.transform); + setLabelLayoutDirty(labelGeometry, false, LABEL_LAYOUT_DIRTY_BIT_OBB); + } + + return obb; + } + /** + * Adjust labels on x/y direction to avoid overlap. + * + * PENDING: the current implementation is based on the global bounding rect rather than the local rect, + * which may be not preferable in some edge cases when the label has rotation, but works for most cases, + * since rotation is unnecessary when there is sufficient space, while squeezing is applied regardless + * of overlapping when there is no enough space. + * + * NOTICE: + * - The input `list` and its content will be modified (sort, label.x/y, rect). + * - The caller should sync the modifications to the other parts by + * `setLabelLayoutDirty` and `ensureLabelLayoutWithGeometry` if needed. + * + * @return adjusted + */ + + + function shiftLayoutOnXY(list, xyDimIdx, // 0 for x, 1 for y + minBound, // for x, leftBound; for y, topBound + maxBound, // for x, rightBound; for y, bottomBound + // If average the shifts on all labels and add them to 0 + // TODO: Not sure if should enable it. + // Pros: The angle of lines will distribute more equally + // Cons: In some layout. It may not what user wanted. like in pie. the label of last sector is usually changed unexpectedly. + balanceShift) { + var len = list.length; + var xyDim = XY$1[xyDimIdx]; + var sizeDim = WH$1[xyDimIdx]; + + if (len < 2) { + return false; + } + + list.sort(function (a, b) { + return a.rect[xyDim] - b.rect[xyDim]; + }); + var lastPos = 0; + var delta; + var adjusted = false; // const shifts = []; + + var totalShifts = 0; + + for (var i = 0; i < len; i++) { + var item = list[i]; + var rect = item.rect; + delta = rect[xyDim] - lastPos; + + if (delta < 0) { + // shiftForward(i, len, -delta); + rect[xyDim] -= delta; + item.label[xyDim] -= delta; + adjusted = true; + } + + var shift = Math.max(-delta, 0); // shifts.push(shift); + + totalShifts += shift; + lastPos = rect[xyDim] + rect[sizeDim]; + } + + if (totalShifts > 0 && balanceShift) { + // Shift back to make the distribution more equally. + shiftList(-totalShifts / len, 0, len); + } // TODO bleedMargin? + + + var first = list[0]; + var last = list[len - 1]; + var minGap; + var maxGap; + updateMinMaxGap(); // If ends exceed two bounds, squeeze at most 80%, then take the gap of two bounds. + + minGap < 0 && squeezeGaps(-minGap, 0.8); + maxGap < 0 && squeezeGaps(maxGap, 0.8); + updateMinMaxGap(); + takeBoundsGap(minGap, maxGap, 1); + takeBoundsGap(maxGap, minGap, -1); // Handle bailout when there is not enough space. + + updateMinMaxGap(); + + if (minGap < 0) { + squeezeWhenBailout(-minGap); + } + + if (maxGap < 0) { + squeezeWhenBailout(maxGap); + } + + function updateMinMaxGap() { + minGap = first.rect[xyDim] - minBound; + maxGap = maxBound - last.rect[xyDim] - last.rect[sizeDim]; + } + + function takeBoundsGap(gapThisBound, gapOtherBound, moveDir) { + if (gapThisBound < 0) { + // Move from other gap if can. + var moveFromMaxGap = Math.min(gapOtherBound, -gapThisBound); + + if (moveFromMaxGap > 0) { + shiftList(moveFromMaxGap * moveDir, 0, len); + var remained = moveFromMaxGap + gapThisBound; + + if (remained < 0) { + squeezeGaps(-remained * moveDir, 1); + } + } else { + squeezeGaps(-gapThisBound * moveDir, 1); + } + } + } + + function shiftList(delta, start, end) { + if (delta !== 0) { + adjusted = true; + } + + for (var i = start; i < end; i++) { + var item = list[i]; + var rect = item.rect; + rect[xyDim] += delta; + item.label[xyDim] += delta; + } + } // Squeeze gaps if the labels exceed margin. + + + function squeezeGaps(delta, maxSqeezePercent) { + var gaps = []; + var totalGaps = 0; + + for (var i = 1; i < len; i++) { + var prevItemRect = list[i - 1].rect; + var gap = Math.max(list[i].rect[xyDim] - prevItemRect[xyDim] - prevItemRect[sizeDim], 0); + gaps.push(gap); + totalGaps += gap; + } + + if (!totalGaps) { + return; + } + + var squeezePercent = Math.min(Math.abs(delta) / totalGaps, maxSqeezePercent); + + if (delta > 0) { + for (var i = 0; i < len - 1; i++) { + // Distribute the shift delta to all gaps. + var movement = gaps[i] * squeezePercent; // Forward + + shiftList(movement, 0, i + 1); + } + } else { + // Backward + for (var i = len - 1; i > 0; i--) { + // Distribute the shift delta to all gaps. + var movement = gaps[i - 1] * squeezePercent; + shiftList(-movement, i, len); + } + } + } + /** + * Squeeze to allow overlap if there is no more space available. + * Let other overlapping strategy like hideOverlap do the job instead of keep exceeding the bounds. + */ + + + function squeezeWhenBailout(delta) { + var dir = delta < 0 ? -1 : 1; + delta = Math.abs(delta); + var moveForEachLabel = Math.ceil(delta / (len - 1)); + + for (var i = 0; i < len - 1; i++) { + if (dir > 0) { + // Forward + shiftList(moveForEachLabel, 0, i + 1); + } else { + // Backward + shiftList(-moveForEachLabel, len - i - 1, len); + } + + delta -= moveForEachLabel; + + if (delta <= 0) { + return; + } + } + } + + return adjusted; + } + /** + * @see `SavedLabelAttr` in `LabelManager.ts` + * @see `hideOverlap` + */ + + + function restoreIgnore(labelList) { + for (var i = 0; i < labelList.length; i++) { + var labelItem = labelList[i]; + var defaultAttr = labelItem.defaultAttr; + var labelLine = labelItem.labelLine; + labelItem.label.attr('ignore', defaultAttr.ignore); + labelLine && labelLine.attr('ignore', defaultAttr.labelGuideIgnore); + } + } + /** + * [NOTICE - restore]: + * 'series:layoutlabels' may be triggered during some shortcut passes, such as zooming in series.graph/geo + * (`updateLabelLayout`), where the modified `Element` props should be restorable from `defaultAttr`. + * @see `SavedLabelAttr` in `LabelManager.ts` + * `restoreIgnore` can be called to perform the restore, if needed. + * + * [NOTICE - state]: + * Regarding Element's states, this method is only designed for the normal state. + * PENDING: although currently this method is effectively called in other states in `updateLabelLayout` case, + * the bad case is not noticeable in the zooming scenario. + */ + + + function hideOverlap(labelList) { + var displayedLabels = []; // TODO, render overflow visible first, put in the displayedLabels. + + labelList.sort(function (a, b) { + return (b.suggestIgnore ? 1 : 0) - (a.suggestIgnore ? 1 : 0) || b.priority - a.priority; + }); + + function hideEl(el) { + if (!el.ignore) { + // Show on emphasis. + var emphasisState = el.ensureState('emphasis'); + + if (emphasisState.ignore == null) { + emphasisState.ignore = false; + } + } + + el.ignore = true; + } + + for (var i = 0; i < labelList.length; i++) { + var labelItem = ensureLabelLayoutWithGeometry(labelList[i]); // The current `el.ignore` is involved, since some previous overlap + // resolving strategies may have set `el.ignore` to true. + + if (labelItem.label.ignore) { + continue; + } + + var label = labelItem.label; + var labelLine = labelItem.labelLine; // NOTICE: even when the with/height of globalRect of a label is 0, the label line should + // still be displayed, since we should follow the concept of "truncation", meaning that + // something exists even if it cannot be fully displayed. A visible label line is necessary + // to allow users to get a tooltip with label info on hover. + + var overlapped = false; + + for (var j = 0; j < displayedLabels.length; j++) { + if (labelIntersect(labelItem, displayedLabels[j], null, { + touchThreshold: 0.05 + })) { + overlapped = true; + break; + } + } // TODO Callback to determine if this overlap should be handled? + + + if (overlapped) { + hideEl(label); + labelLine && hideEl(labelLine); + } else { + displayedLabels.push(labelItem); + } + } + } + /** + * Enable fast check for performance; use obb if inevitable. + * If `mtv` is used, `targetLayoutInfo` can be moved based on the values filled into `mtv`. + * + * This method is based only on the current `Element` states (regardless of other states). + * Typically this method (and the entire layout process) is performed in normal state. + */ + + + function labelIntersect(baseLayoutInfo, targetLayoutInfo, mtv, intersectOpt) { + if (!baseLayoutInfo || !targetLayoutInfo) { + return false; + } + + if (baseLayoutInfo.label && baseLayoutInfo.label.ignore || targetLayoutInfo.label && targetLayoutInfo.label.ignore) { + return false; + } // Fast rejection. + + + if (!baseLayoutInfo.rect.intersect(targetLayoutInfo.rect, mtv, intersectOpt)) { + return false; + } + + if (baseLayoutInfo.axisAligned && targetLayoutInfo.axisAligned) { + return true; // obb is the same as the normal bounding rect. + } + + return ensureOBB(baseLayoutInfo).intersect(ensureOBB(targetLayoutInfo), mtv, intersectOpt); + } + + function cloneArr(points) { + if (points) { + var newPoints = []; + + for (var i = 0; i < points.length; i++) { + newPoints.push(points[i].slice()); + } + + return newPoints; + } + } + + function prepareLayoutCallbackParams(labelItem, hostEl) { + var label = labelItem.label; + var labelLine = hostEl && hostEl.getTextGuideLine(); + return { + dataIndex: labelItem.dataIndex, + dataType: labelItem.dataType, + seriesIndex: labelItem.seriesModel.seriesIndex, + text: labelItem.label.style.text, + rect: labelItem.hostRect, + labelRect: labelItem.rect, + // x: labelAttr.x, + // y: labelAttr.y, + align: label.style.align, + verticalAlign: label.style.verticalAlign, + labelLinePoints: cloneArr(labelLine && labelLine.shape.points) + }; + } + + var LABEL_OPTION_TO_STYLE_KEYS = ['align', 'verticalAlign', 'width', 'height', 'fontSize']; + var dummyTransformable = new Transformable(); + var labelLayoutInnerStore = makeInner(); + var labelLineAnimationStore = makeInner(); + + function extendWithKeys(target, source, keys) { + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + + if (source[key] != null) { + target[key] = source[key]; + } + } + } + + var LABEL_LAYOUT_PROPS = ['x', 'y', 'rotation']; + + var LabelManager = + /** @class */ + function () { + function LabelManager() { + this._labelList = []; + this._chartViewList = []; + } + + LabelManager.prototype.clearLabels = function () { + this._labelList = []; + this._chartViewList = []; + }; + /** + * Add label to manager + */ + + + LabelManager.prototype._addLabel = function (dataIndex, dataType, seriesModel, label, layoutOptionOrCb) { + var labelStyle = label.style; + var hostEl = label.__hostTarget; + var textConfig = hostEl.textConfig || {}; // TODO: If label is in other state. + + var labelTransform = label.getComputedTransform(); + var labelRect = label.getBoundingRect().plain(); + BoundingRect.applyTransform(labelRect, labelRect, labelTransform); + + if (labelTransform) { + dummyTransformable.setLocalTransform(labelTransform); + } else { + // Identity transform. + dummyTransformable.x = dummyTransformable.y = dummyTransformable.rotation = dummyTransformable.originX = dummyTransformable.originY = 0; + dummyTransformable.scaleX = dummyTransformable.scaleY = 1; + } + + dummyTransformable.rotation = normalizeRadian(dummyTransformable.rotation); + var host = label.__hostTarget; + var hostRect; + + if (host) { + hostRect = host.getBoundingRect().plain(); + var transform = host.getComputedTransform(); + BoundingRect.applyTransform(hostRect, hostRect, transform); + } + + var labelGuide = hostRect && host.getTextGuideLine(); + + this._labelList.push({ + label: label, + labelLine: labelGuide, + seriesModel: seriesModel, + dataIndex: dataIndex, + dataType: dataType, + layoutOptionOrCb: layoutOptionOrCb, + layoutOption: null, + rect: labelRect, + hostRect: hostRect, + // Label with lower priority will be hidden when overlapped + // Use rect size as default priority + priority: hostRect ? hostRect.width * hostRect.height : 0, + // Save default label attributes. + // For restore if developers want get back to default value in callback. + defaultAttr: { + ignore: label.ignore, + labelGuideIgnore: labelGuide && labelGuide.ignore, + x: dummyTransformable.x, + y: dummyTransformable.y, + scaleX: dummyTransformable.scaleX, + scaleY: dummyTransformable.scaleY, + rotation: dummyTransformable.rotation, + style: { + x: labelStyle.x, + y: labelStyle.y, + align: labelStyle.align, + verticalAlign: labelStyle.verticalAlign, + width: labelStyle.width, + height: labelStyle.height, + fontSize: labelStyle.fontSize + }, + cursor: label.cursor, + attachedPos: textConfig.position, + attachedRot: textConfig.rotation + } + }); + }; + + LabelManager.prototype.addLabelsOfSeries = function (chartView) { + var _this = this; + + this._chartViewList.push(chartView); + + var seriesModel = chartView.__model; + var layoutOption = seriesModel.get('labelLayout'); + /** + * Ignore layouting if it's not specified anything. + */ + + if (!(isFunction(layoutOption) || keys(layoutOption).length)) { + return; + } + + chartView.group.traverse(function (child) { + if (child.ignore) { + return true; // Stop traverse descendants. + } // Only support label being hosted on graphic elements. + + + var textEl = child.getTextContent(); + var ecData = getECData(child); // Can only attach the text on the element with dataIndex + + if (textEl && !textEl.disableLabelLayout) { + _this._addLabel(ecData.dataIndex, ecData.dataType, seriesModel, textEl, layoutOption); + } + }); + }; + + LabelManager.prototype.updateLayoutConfig = function (api) { + var width = api.getWidth(); + var height = api.getHeight(); + + function createDragHandler(el, labelLineModel) { + return function () { + updateLabelLinePoints(el, labelLineModel); + }; + } + + for (var i = 0; i < this._labelList.length; i++) { + var labelItem = this._labelList[i]; + var label = labelItem.label; + var hostEl = label.__hostTarget; + var defaultLabelAttr = labelItem.defaultAttr; + var layoutOption = void 0; // TODO A global layout option? + + if (isFunction(labelItem.layoutOptionOrCb)) { + layoutOption = labelItem.layoutOptionOrCb(prepareLayoutCallbackParams(labelItem, hostEl)); + } else { + layoutOption = labelItem.layoutOptionOrCb; + } + + layoutOption = layoutOption || {}; + labelItem.layoutOption = layoutOption; + var degreeToRadian = Math.PI / 180; // TODO hostEl should always exists. + // Or label should not have parent because the x, y is all in global space. + + if (hostEl) { + hostEl.setTextConfig({ + // Force to set local false. + local: false, + // Ignore position and rotation config on the host el if x or y is changed. + position: layoutOption.x != null || layoutOption.y != null ? null : defaultLabelAttr.attachedPos, + // Ignore rotation config on the host el if rotation is changed. + rotation: layoutOption.rotate != null ? layoutOption.rotate * degreeToRadian : defaultLabelAttr.attachedRot, + offset: [layoutOption.dx || 0, layoutOption.dy || 0] + }); + } + + var needsUpdateLabelLine = false; + + if (layoutOption.x != null) { + // TODO width of chart view. + label.x = parsePercent(layoutOption.x, width); + label.setStyle('x', 0); // Ignore movement in style. TODO: origin. + + needsUpdateLabelLine = true; + } else { + label.x = defaultLabelAttr.x; + label.setStyle('x', defaultLabelAttr.style.x); + } + + if (layoutOption.y != null) { + // TODO height of chart view. + label.y = parsePercent(layoutOption.y, height); + label.setStyle('y', 0); // Ignore movement in style. + + needsUpdateLabelLine = true; + } else { + label.y = defaultLabelAttr.y; + label.setStyle('y', defaultLabelAttr.style.y); + } + + if (layoutOption.labelLinePoints) { + var guideLine = hostEl.getTextGuideLine(); + + if (guideLine) { + guideLine.setShape({ + points: layoutOption.labelLinePoints + }); // Not update + + needsUpdateLabelLine = false; + } + } + + var labelLayoutStore = labelLayoutInnerStore(label); + labelLayoutStore.needsUpdateLabelLine = needsUpdateLabelLine; + label.rotation = layoutOption.rotate != null ? layoutOption.rotate * degreeToRadian : defaultLabelAttr.rotation; + label.scaleX = defaultLabelAttr.scaleX; + label.scaleY = defaultLabelAttr.scaleY; + + for (var k = 0; k < LABEL_OPTION_TO_STYLE_KEYS.length; k++) { + var key = LABEL_OPTION_TO_STYLE_KEYS[k]; + label.setStyle(key, layoutOption[key] != null ? layoutOption[key] : defaultLabelAttr.style[key]); + } + + if (layoutOption.draggable) { + label.draggable = true; + label.cursor = 'move'; + + if (hostEl) { + var hostModel = labelItem.seriesModel; + + if (labelItem.dataIndex != null) { + var data = labelItem.seriesModel.getData(labelItem.dataType); + hostModel = data.getItemModel(labelItem.dataIndex); + } + + label.on('drag', createDragHandler(hostEl, hostModel.getModel('labelLine'))); + } + } else { + // TODO Other drag functions? + label.off('drag'); + label.cursor = defaultLabelAttr.cursor; + } + } + }; + + LabelManager.prototype.layout = function (api) { + var width = api.getWidth(); + var height = api.getHeight(); + var labelList = []; + each$4(this._labelList, function (inputItem) { + if (!inputItem.defaultAttr.ignore) { + labelList.push(newLabelLayoutWithGeometry({}, inputItem)); + } + }); + var labelsNeedsAdjustOnX = filter(labelList, function (item) { + return item.layoutOption.moveOverlap === 'shiftX'; + }); + var labelsNeedsAdjustOnY = filter(labelList, function (item) { + return item.layoutOption.moveOverlap === 'shiftY'; + }); + shiftLayoutOnXY(labelsNeedsAdjustOnX, 0, 0, width); + shiftLayoutOnXY(labelsNeedsAdjustOnY, 1, 0, height); + var labelsNeedsHideOverlap = filter(labelList, function (item) { + return item.layoutOption.hideOverlap; + }); + restoreIgnore(labelsNeedsHideOverlap); + hideOverlap(labelsNeedsHideOverlap); + }; + /** + * Process all labels. Not only labels with layoutOption. + */ + + + LabelManager.prototype.processLabelsOverall = function () { + var _this = this; + + each$4(this._chartViewList, function (chartView) { + var seriesModel = chartView.__model; + var ignoreLabelLineUpdate = chartView.ignoreLabelLineUpdate; + var animationEnabled = seriesModel.isAnimationEnabled(); + chartView.group.traverse(function (child) { + if (child.ignore && !child.forceLabelAnimation) { + return true; // Stop traverse descendants. + } + + var needsUpdateLabelLine = !ignoreLabelLineUpdate; + var label = child.getTextContent(); + + if (!needsUpdateLabelLine && label) { + needsUpdateLabelLine = labelLayoutInnerStore(label).needsUpdateLabelLine; + } + + if (needsUpdateLabelLine) { + _this._updateLabelLine(child, seriesModel); + } + + if (animationEnabled) { + _this._animateLabels(child, seriesModel); + } + }); + }); + }; + + LabelManager.prototype._updateLabelLine = function (el, seriesModel) { + // Only support label being hosted on graphic elements. + var textEl = el.getTextContent(); // Update label line style. + + var ecData = getECData(el); + var dataIndex = ecData.dataIndex; // Only support labelLine on the labels represent data. + + if (textEl && dataIndex != null) { + var data = seriesModel.getData(ecData.dataType); + var itemModel = data.getItemModel(dataIndex); + var defaultStyle = {}; + var visualStyle = data.getItemVisual(dataIndex, 'style'); + + if (visualStyle) { + var visualType = data.getVisual('drawType'); // Default to be same with main color + + defaultStyle.stroke = visualStyle[visualType]; + } + + var labelLineModel = itemModel.getModel('labelLine'); + setLabelLineStyle(el, getLabelLineStatesModels(itemModel), defaultStyle); + updateLabelLinePoints(el, labelLineModel); + } + }; + + LabelManager.prototype._animateLabels = function (el, seriesModel) { + var textEl = el.getTextContent(); + var guideLine = el.getTextGuideLine(); // Animate + + if (textEl // `forceLabelAnimation` has the highest priority + && (el.forceLabelAnimation || !textEl.ignore && !textEl.invisible && !el.disableLabelAnimation && !isElementRemoved(el))) { + var layoutStore = labelLayoutInnerStore(textEl); + var oldLayout = layoutStore.oldLayout; + var ecData = getECData(el); + var dataIndex = ecData.dataIndex; + var newProps = { + x: textEl.x, + y: textEl.y, + rotation: textEl.rotation + }; + var data = seriesModel.getData(ecData.dataType); + + if (!oldLayout) { + textEl.attr(newProps); // Disable fade in animation if value animation is enabled. + + if (!labelInner(textEl).valueAnimation) { + var oldOpacity = retrieve2(textEl.style.opacity, 1); // Fade in animation + + textEl.style.opacity = 0; + initProps(textEl, { + style: { + opacity: oldOpacity + } + }, seriesModel, dataIndex); + } + } else { + textEl.attr(oldLayout); // Make sure the animation from is in the right status. + + var prevStates = el.prevStates; + + if (prevStates) { + if (indexOf(prevStates, 'select') >= 0) { + textEl.attr(layoutStore.oldLayoutSelect); + } + + if (indexOf(prevStates, 'emphasis') >= 0) { + textEl.attr(layoutStore.oldLayoutEmphasis); + } + } + + updateProps$1(textEl, newProps, seriesModel, dataIndex); + } + + layoutStore.oldLayout = newProps; + + if (textEl.states.select) { + var layoutSelect = layoutStore.oldLayoutSelect = {}; + extendWithKeys(layoutSelect, newProps, LABEL_LAYOUT_PROPS); + extendWithKeys(layoutSelect, textEl.states.select, LABEL_LAYOUT_PROPS); + } + + if (textEl.states.emphasis) { + var layoutEmphasis = layoutStore.oldLayoutEmphasis = {}; + extendWithKeys(layoutEmphasis, newProps, LABEL_LAYOUT_PROPS); + extendWithKeys(layoutEmphasis, textEl.states.emphasis, LABEL_LAYOUT_PROPS); + } + + animateLabelValue(textEl, dataIndex, data, seriesModel, seriesModel); + } + + if (guideLine && !guideLine.ignore && !guideLine.invisible) { + var layoutStore = labelLineAnimationStore(guideLine); + var oldLayout = layoutStore.oldLayout; + var newLayout = { + points: guideLine.shape.points + }; + + if (!oldLayout) { + guideLine.setShape(newLayout); + guideLine.style.strokePercent = 0; + initProps(guideLine, { + style: { + strokePercent: 1 + } + }, seriesModel); + } else { + guideLine.attr({ + shape: oldLayout + }); + updateProps$1(guideLine, { + shape: newLayout + }, seriesModel); + } + + layoutStore.oldLayout = newLayout; + } + }; + + return LabelManager; + }(); + + var getLabelManager = makeInner(); + + function installLabelLayout(registers) { + registers.registerUpdateLifecycle('series:beforeupdate', function (ecModel, api, params) { + // TODO api provide an namespace that can save stuff per instance + var labelManager = getLabelManager(api).labelManager; + + if (!labelManager) { + labelManager = getLabelManager(api).labelManager = new LabelManager(); + } + + labelManager.clearLabels(); + }); + registers.registerUpdateLifecycle('series:layoutlabels', function (ecModel, api, params) { + var labelManager = getLabelManager(api).labelManager; + params.updatedSeries.forEach(function (series) { + labelManager.addLabelsOfSeries(api.getViewOfSeriesModel(series)); + }); + labelManager.updateLayoutConfig(api); + labelManager.layout(api); + labelManager.processLabelsOverall(); + }); + } + + use(installLabelLayout); + + function createDom(id, painter, dpr) { + var newDom = platformApi.createCanvas(); + var width = painter.getWidth(); + var height = painter.getHeight(); + var newDomStyle = newDom.style; + + if (newDomStyle) { + newDomStyle.position = 'absolute'; + newDomStyle.left = '0'; + newDomStyle.top = '0'; + newDomStyle.width = width + 'px'; + newDomStyle.height = height + 'px'; + newDom.setAttribute('data-zr-dom-id', id); + } + + newDom.width = width * dpr; + newDom.height = height * dpr; + return newDom; + } + + var Layer = function (_super) { + __extends(Layer, _super); + + function Layer(id, painter, dpr) { + var _this = _super.call(this) || this; + + _this.motionBlur = false; + _this.lastFrameAlpha = 0.7; + _this.dpr = 1; + _this.virtual = false; + _this.config = {}; + _this.incremental = false; + _this.zlevel = 0; + _this.maxRepaintRectCount = 5; + _this.__dirty = true; + _this.__firstTimePaint = true; + _this.__used = false; + _this.__drawIndex = 0; + _this.__startIndex = 0; + _this.__endIndex = 0; + _this.__prevStartIndex = null; + _this.__prevEndIndex = null; + var dom; + dpr = dpr || devicePixelRatio; + + if (typeof id === 'string') { + dom = createDom(id, painter, dpr); + } else if (isObject$2(id)) { + dom = id; + id = dom.id; + } + + _this.id = id; + _this.dom = dom; + var domStyle = dom.style; + + if (domStyle) { + disableUserSelect(dom); + + dom.onselectstart = function () { + return false; + }; + + domStyle.padding = '0'; + domStyle.margin = '0'; + domStyle.borderWidth = '0'; + } + + _this.painter = painter; + _this.dpr = dpr; + return _this; + } + + Layer.prototype.getElementCount = function () { + return this.__endIndex - this.__startIndex; + }; + + Layer.prototype.afterBrush = function () { + this.__prevStartIndex = this.__startIndex; + this.__prevEndIndex = this.__endIndex; + }; + + Layer.prototype.initContext = function () { + this.ctx = this.dom.getContext('2d'); + this.ctx.dpr = this.dpr; + }; + + Layer.prototype.setUnpainted = function () { + this.__firstTimePaint = true; + }; + + Layer.prototype.createBackBuffer = function () { + var dpr = this.dpr; + this.domBack = createDom('back-' + this.id, this.painter, dpr); + this.ctxBack = this.domBack.getContext('2d'); + + if (dpr !== 1) { + this.ctxBack.scale(dpr, dpr); + } + }; + + Layer.prototype.createRepaintRects = function (displayList, prevList, viewWidth, viewHeight) { + if (this.__firstTimePaint) { + this.__firstTimePaint = false; + return null; + } + + var mergedRepaintRects = []; + var maxRepaintRectCount = this.maxRepaintRectCount; + var full = false; + var pendingRect = new BoundingRect(0, 0, 0, 0); + + function addRectToMergePool(rect) { + if (!rect.isFinite() || rect.isZero()) { + return; + } + + if (mergedRepaintRects.length === 0) { + var boundingRect = new BoundingRect(0, 0, 0, 0); + boundingRect.copy(rect); + mergedRepaintRects.push(boundingRect); + } else { + var isMerged = false; + var minDeltaArea = Infinity; + var bestRectToMergeIdx = 0; + + for (var i = 0; i < mergedRepaintRects.length; ++i) { + var mergedRect = mergedRepaintRects[i]; + + if (mergedRect.intersect(rect)) { + var pendingRect_1 = new BoundingRect(0, 0, 0, 0); + pendingRect_1.copy(mergedRect); + pendingRect_1.union(rect); + mergedRepaintRects[i] = pendingRect_1; + isMerged = true; + break; + } else if (full) { + pendingRect.copy(rect); + pendingRect.union(mergedRect); + var aArea = rect.width * rect.height; + var bArea = mergedRect.width * mergedRect.height; + var pendingArea = pendingRect.width * pendingRect.height; + var deltaArea = pendingArea - aArea - bArea; + + if (deltaArea < minDeltaArea) { + minDeltaArea = deltaArea; + bestRectToMergeIdx = i; + } + } + } + + if (full) { + mergedRepaintRects[bestRectToMergeIdx].union(rect); + isMerged = true; + } + + if (!isMerged) { + var boundingRect = new BoundingRect(0, 0, 0, 0); + boundingRect.copy(rect); + mergedRepaintRects.push(boundingRect); + } + + if (!full) { + full = mergedRepaintRects.length >= maxRepaintRectCount; + } + } + } + + for (var i = this.__startIndex; i < this.__endIndex; ++i) { + var el = displayList[i]; + + if (el) { + var shouldPaint = el.shouldBePainted(viewWidth, viewHeight, true, true); + var prevRect = el.__isRendered && (el.__dirty & REDRAW_BIT || !shouldPaint) ? el.getPrevPaintRect() : null; + + if (prevRect) { + addRectToMergePool(prevRect); + } + + var curRect = shouldPaint && (el.__dirty & REDRAW_BIT || !el.__isRendered) ? el.getPaintRect() : null; + + if (curRect) { + addRectToMergePool(curRect); + } + } + } + + for (var i = this.__prevStartIndex; i < this.__prevEndIndex; ++i) { + var el = prevList[i]; + var shouldPaint = el && el.shouldBePainted(viewWidth, viewHeight, true, true); + + if (el && (!shouldPaint || !el.__zr) && el.__isRendered) { + var prevRect = el.getPrevPaintRect(); + + if (prevRect) { + addRectToMergePool(prevRect); + } + } + } + + var hasIntersections; + + do { + hasIntersections = false; + + for (var i = 0; i < mergedRepaintRects.length;) { + if (mergedRepaintRects[i].isZero()) { + mergedRepaintRects.splice(i, 1); + continue; + } + + for (var j = i + 1; j < mergedRepaintRects.length;) { + if (mergedRepaintRects[i].intersect(mergedRepaintRects[j])) { + hasIntersections = true; + mergedRepaintRects[i].union(mergedRepaintRects[j]); + mergedRepaintRects.splice(j, 1); + } else { + j++; + } + } + + i++; + } + } while (hasIntersections); + + this._paintRects = mergedRepaintRects; + return mergedRepaintRects; + }; + + Layer.prototype.debugGetPaintRects = function () { + return (this._paintRects || []).slice(); + }; + + Layer.prototype.resize = function (width, height) { + var dpr = this.dpr; + var dom = this.dom; + var domStyle = dom.style; + var domBack = this.domBack; + + if (domStyle) { + domStyle.width = width + 'px'; + domStyle.height = height + 'px'; + } + + dom.width = width * dpr; + dom.height = height * dpr; + + if (domBack) { + domBack.width = width * dpr; + domBack.height = height * dpr; + + if (dpr !== 1) { + this.ctxBack.scale(dpr, dpr); + } + } + }; + + Layer.prototype.clear = function (clearAll, clearColor, repaintRects) { + var dom = this.dom; + var ctx = this.ctx; + var width = dom.width; + var height = dom.height; + clearColor = clearColor || this.clearColor; + var haveMotionBLur = this.motionBlur && !clearAll; + var lastFrameAlpha = this.lastFrameAlpha; + var dpr = this.dpr; + var self = this; + + if (haveMotionBLur) { + if (!this.domBack) { + this.createBackBuffer(); + } + + this.ctxBack.globalCompositeOperation = 'copy'; + this.ctxBack.drawImage(dom, 0, 0, width / dpr, height / dpr); + } + + var domBack = this.domBack; + + function doClear(x, y, width, height) { + ctx.clearRect(x, y, width, height); + + if (clearColor && clearColor !== 'transparent') { + var clearColorGradientOrPattern = void 0; + + if (isGradientObject(clearColor)) { + var shouldCache = clearColor.global || clearColor.__width === width && clearColor.__height === height; + clearColorGradientOrPattern = shouldCache && clearColor.__canvasGradient || getCanvasGradient(ctx, clearColor, { + x: 0, + y: 0, + width: width, + height: height + }); + clearColor.__canvasGradient = clearColorGradientOrPattern; + clearColor.__width = width; + clearColor.__height = height; + } else if (isImagePatternObject(clearColor)) { + clearColor.scaleX = clearColor.scaleX || dpr; + clearColor.scaleY = clearColor.scaleY || dpr; + clearColorGradientOrPattern = createCanvasPattern(ctx, clearColor, { + dirty: function () { + self.setUnpainted(); + self.painter.refresh(); + } + }); + } + + ctx.save(); + ctx.fillStyle = clearColorGradientOrPattern || clearColor; + ctx.fillRect(x, y, width, height); + ctx.restore(); + } + + if (haveMotionBLur) { + ctx.save(); + ctx.globalAlpha = lastFrameAlpha; + ctx.drawImage(domBack, x, y, width, height); + ctx.restore(); + } + } + + if (!repaintRects || haveMotionBLur) { + doClear(0, 0, width, height); + } else if (repaintRects.length) { + each$4(repaintRects, function (rect) { + doClear(rect.x * dpr, rect.y * dpr, rect.width * dpr, rect.height * dpr); + }); + } + }; + + return Layer; + }(Eventful); + + var HOVER_LAYER_ZLEVEL = 1e5; + var CANVAS_ZLEVEL = 314159; + var EL_AFTER_INCREMENTAL_INC = 0.01; + var INCREMENTAL_INC = 0.001; + + function isLayerValid(layer) { + if (!layer) { + return false; + } + + if (layer.__builtin__) { + return true; + } + + if (typeof layer.resize !== 'function' || typeof layer.refresh !== 'function') { + return false; + } + + return true; + } + + function createRoot(width, height) { + var domRoot = document.createElement('div'); + domRoot.style.cssText = ['position:relative', 'width:' + width + 'px', 'height:' + height + 'px', 'padding:0', 'margin:0', 'border-width:0'].join(';') + ';'; + return domRoot; + } + + var CanvasPainter = function () { + function CanvasPainter(root, storage, opts, id) { + this.type = 'canvas'; + this._zlevelList = []; + this._prevDisplayList = []; + this._layers = {}; + this._layerConfig = {}; + this._needsManuallyCompositing = false; + this.type = 'canvas'; + var singleCanvas = !root.nodeName || root.nodeName.toUpperCase() === 'CANVAS'; + this._opts = opts = extend({}, opts || {}); + this.dpr = opts.devicePixelRatio || devicePixelRatio; + this._singleCanvas = singleCanvas; + this.root = root; + var rootStyle = root.style; + + if (rootStyle) { + disableUserSelect(root); + root.innerHTML = ''; + } + + this.storage = storage; + var zlevelList = this._zlevelList; + this._prevDisplayList = []; + var layers = this._layers; + + if (!singleCanvas) { + this._width = getSize(root, 0, opts); + this._height = getSize(root, 1, opts); + var domRoot = this._domRoot = createRoot(this._width, this._height); + root.appendChild(domRoot); + } else { + var rootCanvas = root; + var width = rootCanvas.width; + var height = rootCanvas.height; + + if (opts.width != null) { + width = opts.width; + } + + if (opts.height != null) { + height = opts.height; + } + + this.dpr = opts.devicePixelRatio || 1; + rootCanvas.width = width * this.dpr; + rootCanvas.height = height * this.dpr; + this._width = width; + this._height = height; + var mainLayer = new Layer(rootCanvas, this, this.dpr); + mainLayer.__builtin__ = true; + mainLayer.initContext(); + layers[CANVAS_ZLEVEL] = mainLayer; + mainLayer.zlevel = CANVAS_ZLEVEL; + zlevelList.push(CANVAS_ZLEVEL); + this._domRoot = root; + } + } + + CanvasPainter.prototype.getType = function () { + return 'canvas'; + }; + + CanvasPainter.prototype.isSingleCanvas = function () { + return this._singleCanvas; + }; + + CanvasPainter.prototype.getViewportRoot = function () { + return this._domRoot; + }; + + CanvasPainter.prototype.getViewportRootOffset = function () { + var viewportRoot = this.getViewportRoot(); + + if (viewportRoot) { + return { + offsetLeft: viewportRoot.offsetLeft || 0, + offsetTop: viewportRoot.offsetTop || 0 + }; + } + }; + + CanvasPainter.prototype.refresh = function (paintAll) { + var list = this.storage.getDisplayList(true); + var prevList = this._prevDisplayList; + var zlevelList = this._zlevelList; + this._redrawId = Math.random(); + + this._paintList(list, prevList, paintAll, this._redrawId); + + for (var i = 0; i < zlevelList.length; i++) { + var z = zlevelList[i]; + var layer = this._layers[z]; + + if (!layer.__builtin__ && layer.refresh) { + var clearColor = i === 0 ? this._backgroundColor : null; + layer.refresh(clearColor); + } + } + + if (this._opts.useDirtyRect) { + this._prevDisplayList = list.slice(); + } + + return this; + }; + + CanvasPainter.prototype.refreshHover = function () { + this._paintHoverList(this.storage.getDisplayList(false)); + }; + + CanvasPainter.prototype._paintHoverList = function (list) { + var len = list.length; + var hoverLayer = this._hoverlayer; + hoverLayer && hoverLayer.clear(); + + if (!len) { + return; + } + + var scope = { + inHover: true, + viewWidth: this._width, + viewHeight: this._height + }; + var ctx; + + for (var i = 0; i < len; i++) { + var el = list[i]; + + if (el.__inHover) { + if (!hoverLayer) { + hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL); + } + + if (!ctx) { + ctx = hoverLayer.ctx; + ctx.save(); + } + + brush(ctx, el, scope, i === len - 1); + } + } + + if (ctx) { + ctx.restore(); + } + }; + + CanvasPainter.prototype.getHoverLayer = function () { + return this.getLayer(HOVER_LAYER_ZLEVEL); + }; + + CanvasPainter.prototype.paintOne = function (ctx, el) { + brushSingle(ctx, el); + }; + + CanvasPainter.prototype._paintList = function (list, prevList, paintAll, redrawId) { + if (this._redrawId !== redrawId) { + return; + } + + paintAll = paintAll || false; + + this._updateLayerStatus(list); + + var _a = this._doPaintList(list, prevList, paintAll), + finished = _a.finished, + needsRefreshHover = _a.needsRefreshHover; + + if (this._needsManuallyCompositing) { + this._compositeManually(); + } + + if (needsRefreshHover) { + this._paintHoverList(list); + } + + if (!finished) { + var self_1 = this; + requestAnimationFrame$1(function () { + self_1._paintList(list, prevList, paintAll, redrawId); + }); + } else { + this.eachLayer(function (layer) { + layer.afterBrush && layer.afterBrush(); + }); + } + }; + + CanvasPainter.prototype._compositeManually = function () { + var ctx = this.getLayer(CANVAS_ZLEVEL).ctx; + var width = this._domRoot.width; + var height = this._domRoot.height; + ctx.clearRect(0, 0, width, height); + this.eachBuiltinLayer(function (layer) { + if (layer.virtual) { + ctx.drawImage(layer.dom, 0, 0, width, height); + } + }); + }; + + CanvasPainter.prototype._doPaintList = function (list, prevList, paintAll) { + var _this = this; + + var layerList = []; + var useDirtyRect = this._opts.useDirtyRect; + + for (var zi = 0; zi < this._zlevelList.length; zi++) { + var zlevel = this._zlevelList[zi]; + var layer = this._layers[zlevel]; + + if (layer.__builtin__ && layer !== this._hoverlayer && (layer.__dirty || paintAll)) { + layerList.push(layer); + } + } + + var finished = true; + var needsRefreshHover = false; + + var _loop_1 = function (k) { + var layer = layerList[k]; + var ctx = layer.ctx; + var repaintRects = useDirtyRect && layer.createRepaintRects(list, prevList, this_1._width, this_1._height); + var start = paintAll ? layer.__startIndex : layer.__drawIndex; + var useTimer = !paintAll && layer.incremental && Date.now; + var startTime = useTimer && Date.now(); + var clearColor = layer.zlevel === this_1._zlevelList[0] ? this_1._backgroundColor : null; + + if (layer.__startIndex === layer.__endIndex) { + layer.clear(false, clearColor, repaintRects); + } else if (start === layer.__startIndex) { + var firstEl = list[start]; + + if (!firstEl.incremental || !firstEl.notClear || paintAll) { + layer.clear(false, clearColor, repaintRects); + } + } + + if (start === -1) { + console.error('For some unknown reason. drawIndex is -1'); + start = layer.__startIndex; + } + + var i; + + var repaint = function (repaintRect) { + var scope = { + inHover: false, + allClipped: false, + prevEl: null, + viewWidth: _this._width, + viewHeight: _this._height + }; + + for (i = start; i < layer.__endIndex; i++) { + var el = list[i]; + + if (el.__inHover) { + needsRefreshHover = true; + } + + _this._doPaintEl(el, layer, useDirtyRect, repaintRect, scope, i === layer.__endIndex - 1); + + if (useTimer) { + var dTime = Date.now() - startTime; + + if (dTime > 15) { + break; + } + } + } + + if (scope.prevElClipPaths) { + ctx.restore(); + } + }; + + if (repaintRects) { + if (repaintRects.length === 0) { + i = layer.__endIndex; + } else { + var dpr = this_1.dpr; + + for (var r = 0; r < repaintRects.length; ++r) { + var rect = repaintRects[r]; + ctx.save(); + ctx.beginPath(); + ctx.rect(rect.x * dpr, rect.y * dpr, rect.width * dpr, rect.height * dpr); + ctx.clip(); + repaint(rect); + ctx.restore(); + } + } + } else { + ctx.save(); + repaint(); + ctx.restore(); + } + + layer.__drawIndex = i; + + if (layer.__drawIndex < layer.__endIndex) { + finished = false; + } + }; + + var this_1 = this; + + for (var k = 0; k < layerList.length; k++) { + _loop_1(k); + } + + if (env.wxa) { + each$4(this._layers, function (layer) { + if (layer && layer.ctx && layer.ctx.draw) { + layer.ctx.draw(); + } + }); + } + + return { + finished: finished, + needsRefreshHover: needsRefreshHover + }; + }; + + CanvasPainter.prototype._doPaintEl = function (el, currentLayer, useDirtyRect, repaintRect, scope, isLast) { + var ctx = currentLayer.ctx; + + if (useDirtyRect) { + var paintRect = el.getPaintRect(); + + if (!repaintRect || paintRect && paintRect.intersect(repaintRect)) { + brush(ctx, el, scope, isLast); + el.setPrevPaintRect(paintRect); + } + } else { + brush(ctx, el, scope, isLast); + } + }; + + CanvasPainter.prototype.getLayer = function (zlevel, virtual) { + if (this._singleCanvas && !this._needsManuallyCompositing) { + zlevel = CANVAS_ZLEVEL; + } + + var layer = this._layers[zlevel]; + + if (!layer) { + layer = new Layer('zr_' + zlevel, this, this.dpr); + layer.zlevel = zlevel; + layer.__builtin__ = true; + + if (this._layerConfig[zlevel]) { + merge(layer, this._layerConfig[zlevel], true); + } else if (this._layerConfig[zlevel - EL_AFTER_INCREMENTAL_INC]) { + merge(layer, this._layerConfig[zlevel - EL_AFTER_INCREMENTAL_INC], true); + } + + if (virtual) { + layer.virtual = virtual; + } + + this.insertLayer(zlevel, layer); + layer.initContext(); + } + + return layer; + }; + + CanvasPainter.prototype.insertLayer = function (zlevel, layer) { + var layersMap = this._layers; + var zlevelList = this._zlevelList; + var len = zlevelList.length; + var domRoot = this._domRoot; + var prevLayer = null; + var i = -1; + + if (layersMap[zlevel]) { + { + logError('ZLevel ' + zlevel + ' has been used already'); + } + return; + } + + if (!isLayerValid(layer)) { + { + logError('Layer of zlevel ' + zlevel + ' is not valid'); + } + return; + } + + if (len > 0 && zlevel > zlevelList[0]) { + for (i = 0; i < len - 1; i++) { + if (zlevelList[i] < zlevel && zlevelList[i + 1] > zlevel) { + break; + } + } + + prevLayer = layersMap[zlevelList[i]]; + } + + zlevelList.splice(i + 1, 0, zlevel); + layersMap[zlevel] = layer; + + if (!layer.virtual) { + if (prevLayer) { + var prevDom = prevLayer.dom; + + if (prevDom.nextSibling) { + domRoot.insertBefore(layer.dom, prevDom.nextSibling); + } else { + domRoot.appendChild(layer.dom); + } + } else { + if (domRoot.firstChild) { + domRoot.insertBefore(layer.dom, domRoot.firstChild); + } else { + domRoot.appendChild(layer.dom); + } + } + } + + layer.painter || (layer.painter = this); + }; + + CanvasPainter.prototype.eachLayer = function (cb, context) { + var zlevelList = this._zlevelList; + + for (var i = 0; i < zlevelList.length; i++) { + var z = zlevelList[i]; + cb.call(context, this._layers[z], z); + } + }; + + CanvasPainter.prototype.eachBuiltinLayer = function (cb, context) { + var zlevelList = this._zlevelList; + + for (var i = 0; i < zlevelList.length; i++) { + var z = zlevelList[i]; + var layer = this._layers[z]; + + if (layer.__builtin__) { + cb.call(context, layer, z); + } + } + }; + + CanvasPainter.prototype.eachOtherLayer = function (cb, context) { + var zlevelList = this._zlevelList; + + for (var i = 0; i < zlevelList.length; i++) { + var z = zlevelList[i]; + var layer = this._layers[z]; + + if (!layer.__builtin__) { + cb.call(context, layer, z); + } + } + }; + + CanvasPainter.prototype.getLayers = function () { + return this._layers; + }; + + CanvasPainter.prototype._updateLayerStatus = function (list) { + this.eachBuiltinLayer(function (layer, z) { + layer.__dirty = layer.__used = false; + }); + + function updatePrevLayer(idx) { + if (prevLayer) { + if (prevLayer.__endIndex !== idx) { + prevLayer.__dirty = true; + } + + prevLayer.__endIndex = idx; + } + } + + if (this._singleCanvas) { + for (var i_1 = 1; i_1 < list.length; i_1++) { + var el = list[i_1]; + + if (el.zlevel !== list[i_1 - 1].zlevel || el.incremental) { + this._needsManuallyCompositing = true; + break; + } + } + } + + var prevLayer = null; + var incrementalLayerCount = 0; + var prevZlevel; + var i; + + for (i = 0; i < list.length; i++) { + var el = list[i]; + var zlevel = el.zlevel; + var layer = void 0; + + if (prevZlevel !== zlevel) { + prevZlevel = zlevel; + incrementalLayerCount = 0; + } + + if (el.incremental) { + layer = this.getLayer(zlevel + INCREMENTAL_INC, this._needsManuallyCompositing); + layer.incremental = true; + incrementalLayerCount = 1; + } else { + layer = this.getLayer(zlevel + (incrementalLayerCount > 0 ? EL_AFTER_INCREMENTAL_INC : 0), this._needsManuallyCompositing); + } + + if (!layer.__builtin__) { + logError('ZLevel ' + zlevel + ' has been used by unkown layer ' + layer.id); + } + + if (layer !== prevLayer) { + layer.__used = true; + + if (layer.__startIndex !== i) { + layer.__dirty = true; + } + + layer.__startIndex = i; + + if (!layer.incremental) { + layer.__drawIndex = i; + } else { + layer.__drawIndex = -1; + } + + updatePrevLayer(i); + prevLayer = layer; + } + + if (el.__dirty & REDRAW_BIT && !el.__inHover) { + layer.__dirty = true; + + if (layer.incremental && layer.__drawIndex < 0) { + layer.__drawIndex = i; + } + } + } + + updatePrevLayer(i); + this.eachBuiltinLayer(function (layer, z) { + if (!layer.__used && layer.getElementCount() > 0) { + layer.__dirty = true; + layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0; + } + + if (layer.__dirty && layer.__drawIndex < 0) { + layer.__drawIndex = layer.__startIndex; + } + }); + }; + + CanvasPainter.prototype.clear = function () { + this.eachBuiltinLayer(this._clearLayer); + return this; + }; + + CanvasPainter.prototype._clearLayer = function (layer) { + layer.clear(); + }; + + CanvasPainter.prototype.setBackgroundColor = function (backgroundColor) { + this._backgroundColor = backgroundColor; + each$4(this._layers, function (layer) { + layer.setUnpainted(); + }); + }; + + CanvasPainter.prototype.configLayer = function (zlevel, config) { + if (config) { + var layerConfig = this._layerConfig; + + if (!layerConfig[zlevel]) { + layerConfig[zlevel] = config; + } else { + merge(layerConfig[zlevel], config, true); + } + + for (var i = 0; i < this._zlevelList.length; i++) { + var _zlevel = this._zlevelList[i]; + + if (_zlevel === zlevel || _zlevel === zlevel + EL_AFTER_INCREMENTAL_INC) { + var layer = this._layers[_zlevel]; + merge(layer, layerConfig[zlevel], true); + } + } + } + }; + + CanvasPainter.prototype.delLayer = function (zlevel) { + var layers = this._layers; + var zlevelList = this._zlevelList; + var layer = layers[zlevel]; + + if (!layer) { + return; + } + + layer.dom.parentNode.removeChild(layer.dom); + delete layers[zlevel]; + zlevelList.splice(indexOf(zlevelList, zlevel), 1); + }; + + CanvasPainter.prototype.resize = function (width, height) { + if (!this._domRoot.style) { + if (width == null || height == null) { + return; + } + + this._width = width; + this._height = height; + this.getLayer(CANVAS_ZLEVEL).resize(width, height); + } else { + var domRoot = this._domRoot; + domRoot.style.display = 'none'; + var opts = this._opts; + var root = this.root; + width != null && (opts.width = width); + height != null && (opts.height = height); + width = getSize(root, 0, opts); + height = getSize(root, 1, opts); + domRoot.style.display = ''; + + if (this._width !== width || height !== this._height) { + domRoot.style.width = width + 'px'; + domRoot.style.height = height + 'px'; + + for (var id in this._layers) { + if (this._layers.hasOwnProperty(id)) { + this._layers[id].resize(width, height); + } + } + + this.refresh(true); + } + + this._width = width; + this._height = height; + } + + return this; + }; + + CanvasPainter.prototype.clearLayer = function (zlevel) { + var layer = this._layers[zlevel]; + + if (layer) { + layer.clear(); + } + }; + + CanvasPainter.prototype.dispose = function () { + this.root.innerHTML = ''; + this.root = this.storage = this._domRoot = this._layers = null; + }; + + CanvasPainter.prototype.getRenderedCanvas = function (opts) { + opts = opts || {}; + + if (this._singleCanvas && !this._compositeManually) { + return this._layers[CANVAS_ZLEVEL].dom; + } + + var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr); + imageLayer.initContext(); + imageLayer.clear(false, opts.backgroundColor || this._backgroundColor); + var ctx = imageLayer.ctx; + + if (opts.pixelRatio <= this.dpr) { + this.refresh(); + var width_1 = imageLayer.dom.width; + var height_1 = imageLayer.dom.height; + this.eachLayer(function (layer) { + if (layer.__builtin__) { + ctx.drawImage(layer.dom, 0, 0, width_1, height_1); + } else if (layer.renderToCanvas) { + ctx.save(); + layer.renderToCanvas(ctx); + ctx.restore(); + } + }); + } else { + var scope = { + inHover: false, + viewWidth: this._width, + viewHeight: this._height + }; + var displayList = this.storage.getDisplayList(true); + + for (var i = 0, len = displayList.length; i < len; i++) { + var el = displayList[i]; + brush(ctx, el, scope, i === len - 1); + } + } + + return imageLayer.dom; + }; + + CanvasPainter.prototype.getWidth = function () { + return this._width; + }; + + CanvasPainter.prototype.getHeight = function () { + return this._height; + }; + + return CanvasPainter; + }(); + + function install$b(registers) { + registers.registerPainter('canvas', CanvasPainter); + } + + var DatasetModel = + /** @class */ + function (_super) { + __extends(DatasetModel, _super); + + function DatasetModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'dataset'; + return _this; + } + + DatasetModel.prototype.init = function (option, parentModel, ecModel) { + _super.prototype.init.call(this, option, parentModel, ecModel); + + this._sourceManager = new SourceManager(this); + disableTransformOptionMerge(this); + }; + + DatasetModel.prototype.mergeOption = function (newOption, ecModel) { + _super.prototype.mergeOption.call(this, newOption, ecModel); + + disableTransformOptionMerge(this); + }; + + DatasetModel.prototype.optionUpdated = function () { + this._sourceManager.dirty(); + }; + + DatasetModel.prototype.getSourceManager = function () { + return this._sourceManager; + }; + + DatasetModel.type = 'dataset'; + DatasetModel.defaultOption = { + seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN + }; + return DatasetModel; + }(ComponentModel); + + var DatasetView = + /** @class */ + function (_super) { + __extends(DatasetView, _super); + + function DatasetView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'dataset'; + return _this; + } + + DatasetView.type = 'dataset'; + return DatasetView; + }(ComponentView); + + function install$a(registers) { + registers.registerComponentModel(DatasetModel); + registers.registerComponentView(DatasetView); + } // Default to have canvas renderer and dataset for compitatble reason. + + + use([install$b, install$a]); + use(installLabelLayout); + var samplers = { + average: function (frame) { + var sum = 0; + var count = 0; + + for (var i = 0; i < frame.length; i++) { + if (!isNaN(frame[i])) { + sum += frame[i]; + count++; + } + } // Return NaN if count is 0 + + + return count === 0 ? NaN : sum / count; + }, + sum: function (frame) { + var sum = 0; + + for (var i = 0; i < frame.length; i++) { + // Ignore NaN + sum += frame[i] || 0; + } + + return sum; + }, + max: function (frame) { + var max = -Infinity; + + for (var i = 0; i < frame.length; i++) { + frame[i] > max && (max = frame[i]); + } // NaN will cause illegal axis extent. + + + return isFinite(max) ? max : NaN; + }, + min: function (frame) { + var min = Infinity; + + for (var i = 0; i < frame.length; i++) { + frame[i] < min && (min = frame[i]); + } // NaN will cause illegal axis extent. + + + return isFinite(min) ? min : NaN; + }, + // TODO + // Median + nearest: function (frame) { + return frame[0]; + } + }; + + var indexSampler = function (frame) { + return Math.round(frame.length / 2); + }; + + function dataSample(seriesType) { + return { + seriesType: seriesType, + // FIXME:TS never used, so comment it + // modifyOutputEnd: true, + reset: function (seriesModel, ecModel, api) { + var data = seriesModel.getData(); + var sampling = seriesModel.get('sampling'); + var coordSys = seriesModel.coordinateSystem; + var count = data.count(); // Only cartesian2d support down sampling. Disable it when there is few data. + + if (count > 10 && coordSys.type === 'cartesian2d' && sampling) { + var baseAxis = coordSys.getBaseAxis(); + var valueAxis = coordSys.getOtherAxis(baseAxis); + var extent = baseAxis.getExtent(); + var dpr = api.getDevicePixelRatio(); // Coordinste system has been resized + + var size = Math.abs(extent[1] - extent[0]) * (dpr || 1); + var rate = Math.round(count / size); + + if (isFinite(rate) && rate > 1) { + if (sampling === 'lttb') { + seriesModel.setData(data.lttbDownSample(data.mapDimension(valueAxis.dim), 1 / rate)); + } else if (sampling === 'minmax') { + seriesModel.setData(data.minmaxDownSample(data.mapDimension(valueAxis.dim), 1 / rate)); + } + + var sampler = void 0; + + if (isString(sampling)) { + sampler = samplers[sampling]; + } else if (isFunction(sampling)) { + sampler = sampling; + } + + if (sampler) { + // Only support sample the first dim mapped from value axis. + seriesModel.setData(data.downSample(data.mapDimension(valueAxis.dim), 1 / rate, sampler, indexSampler)); + } + } + } + } + }; + } + + var BaseBarSeriesModel = + /** @class */ + function (_super) { + __extends(BaseBarSeriesModel, _super); + + function BaseBarSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = BaseBarSeriesModel.type; + return _this; + } + + BaseBarSeriesModel.prototype.getInitialData = function (option, ecModel) { + return createSeriesData(null, this, { + useEncodeDefaulter: true + }); + }; + + BaseBarSeriesModel.prototype.getMarkerPosition = function (value, dims, startingAtTick) { + var coordSys = this.coordinateSystem; + + if (coordSys && coordSys.clampData) { + // PENDING if clamp ? + var clampData_1 = coordSys.clampData(value); + var pt_1 = coordSys.dataToPoint(clampData_1); + + if (startingAtTick) { + each$4(coordSys.getAxes(), function (axis, idx) { + // If axis type is category, use tick coords instead + if (axis.type === 'category' && dims != null) { + var tickCoords = axis.getTicksCoords(); + var alignTicksWithLabel = axis.getTickModel().get('alignWithLabel'); + var targetTickId = clampData_1[idx]; // The index of rightmost tick of markArea is 1 larger than x1/y1 index + + var isEnd = dims[idx] === 'x1' || dims[idx] === 'y1'; + + if (isEnd && !alignTicksWithLabel) { + targetTickId += 1; + } // The only contains one tick, tickCoords is + // like [{coord: 0, tickValue: 0}, {coord: 0}] + // to the length should always be larger than 1 + + + if (tickCoords.length < 2) { + return; + } else if (tickCoords.length === 2) { + // The left value and right value of the axis are + // the same. coord is 0 in both items. Use the max + // value of the axis as the coord + pt_1[idx] = axis.toGlobalCoord(axis.getExtent()[isEnd ? 1 : 0]); + return; + } + + var leftCoord = void 0; + var coord = void 0; + var stepTickValue = 1; + + for (var i = 0; i < tickCoords.length; i++) { + var tickCoord = tickCoords[i].coord; // The last item of tickCoords doesn't contain + // tickValue + + var tickValue = i === tickCoords.length - 1 ? tickCoords[i - 1].tickValue + stepTickValue : tickCoords[i].tickValue; + + if (tickValue === targetTickId) { + coord = tickCoord; + break; + } else if (tickValue < targetTickId) { + leftCoord = tickCoord; + } else if (leftCoord != null && tickValue > targetTickId) { + coord = (tickCoord + leftCoord) / 2; + break; + } + + if (i === 1) { + // Here we assume the step of category axes is + // the same + stepTickValue = tickValue - tickCoords[0].tickValue; + } + } + + if (coord == null) { + if (!leftCoord) { + // targetTickId is smaller than all tick ids in the + // visible area, use the leftmost tick coord + coord = tickCoords[0].coord; + } else if (leftCoord) { + // targetTickId is larger than all tick ids in the + // visible area, use the rightmost tick coord + coord = tickCoords[tickCoords.length - 1].coord; + } + } + + pt_1[idx] = axis.toGlobalCoord(coord); + } + }); + } else { + var data = this.getData(); + var offset = data.getLayout('offset'); + var size = data.getLayout('size'); + var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1; + pt_1[offsetIndex] += offset + size / 2; + } + + return pt_1; + } + + return [NaN, NaN]; + }; + + BaseBarSeriesModel.type = 'series.__base_bar__'; + BaseBarSeriesModel.defaultOption = { + // zlevel: 0, + z: 2, + coordinateSystem: 'cartesian2d', + legendHoverLink: true, + // stack: null + // Cartesian coordinate system + // xAxisIndex: 0, + // yAxisIndex: 0, + barMinHeight: 0, + barMinAngle: 0, + // cursor: null, + large: false, + largeThreshold: 400, + progressive: 3e3, + progressiveChunkMode: 'mod', + defaultBarGap: '10%' + }; + return BaseBarSeriesModel; + }(SeriesModel); + + SeriesModel.registerClass(BaseBarSeriesModel); + + var BarSeriesModel = + /** @class */ + function (_super) { + __extends(BarSeriesModel, _super); + + function BarSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = BarSeriesModel.type; + return _this; + } + + BarSeriesModel.prototype.getInitialData = function () { + return createSeriesData(null, this, { + useEncodeDefaulter: true, + createInvertedIndices: !!this.get('realtimeSort', true) || null + }); + }; + /** + * @override + */ + + + BarSeriesModel.prototype.getProgressive = function () { + // Do not support progressive in normal mode. + return this.get('large') ? this.get('progressive') : false; + }; + /** + * @override + */ + + + BarSeriesModel.prototype.getProgressiveThreshold = function () { + // Do not support progressive in normal mode. + var progressiveThreshold = this.get('progressiveThreshold'); + var largeThreshold = this.get('largeThreshold'); + + if (largeThreshold > progressiveThreshold) { + progressiveThreshold = largeThreshold; + } + + return progressiveThreshold; + }; + + BarSeriesModel.prototype.brushSelector = function (dataIndex, data, selectors) { + return selectors.rect(data.getItemLayout(dataIndex)); + }; + + BarSeriesModel.type = 'series.bar'; + BarSeriesModel.dependencies = ['grid', 'polar']; + BarSeriesModel.defaultOption = inheritDefaultOption(BaseBarSeriesModel.defaultOption, { + // If clipped + // Only available on cartesian2d + clip: true, + roundCap: false, + showBackground: false, + backgroundStyle: { + color: 'rgba(180, 180, 180, 0.2)', + borderColor: null, + borderWidth: 0, + borderType: 'solid', + borderRadius: 0, + shadowBlur: 0, + shadowColor: null, + shadowOffsetX: 0, + shadowOffsetY: 0, + opacity: 1 + }, + select: { + itemStyle: { + borderColor: tokens.color.primary, + borderWidth: 2 + } + }, + realtimeSort: false + }); + return BarSeriesModel; + }(BaseBarSeriesModel); + + function createGridClipPath(cartesian, hasAnimation, seriesModel, done, during) { + var rect = cartesian.getArea(); + var x = rect.x; + var y = rect.y; + var width = rect.width; + var height = rect.height; + var lineWidth = seriesModel.get(['lineStyle', 'width']) || 0; // Expand the clip path a bit to avoid the border is clipped and looks thinner + + x -= lineWidth / 2; + y -= lineWidth / 2; + width += lineWidth; + height += lineWidth; // fix: https://github.com/apache/incubator-echarts/issues/11369 + + width = Math.ceil(width); + + if (x !== Math.floor(x)) { + x = Math.floor(x); // if no extra 1px on `width`, it will still be clipped since `x` is floored + + width++; + } + + var clipPath = new Rect({ + shape: { + x: x, + y: y, + width: width, + height: height + } + }); + + if (hasAnimation) { + var baseAxis = cartesian.getBaseAxis(); + var isHorizontal = baseAxis.isHorizontal(); + var isAxisInversed = baseAxis.inverse; + + if (isHorizontal) { + if (isAxisInversed) { + clipPath.shape.x += width; + } + + clipPath.shape.width = 0; + } else { + if (!isAxisInversed) { + clipPath.shape.y += height; + } + + clipPath.shape.height = 0; + } + + var duringCb = isFunction(during) ? function (percent) { + during(percent, clipPath); + } : null; + initProps(clipPath, { + shape: { + width: width, + height: height, + x: x, + y: y + } + }, seriesModel, null, done, duringCb); + } + + return clipPath; + } + + function createPolarClipPath(polar, hasAnimation, seriesModel) { + var sectorArea = polar.getArea(); // Avoid float number rounding error for symbol on the edge of axis extent. + + var r0 = round$1(sectorArea.r0, 1); + var r = round$1(sectorArea.r, 1); + var clipPath = new Sector({ + shape: { + cx: round$1(polar.cx, 1), + cy: round$1(polar.cy, 1), + r0: r0, + r: r, + startAngle: sectorArea.startAngle, + endAngle: sectorArea.endAngle, + clockwise: sectorArea.clockwise + } + }); + + if (hasAnimation) { + var isRadial = polar.getBaseAxis().dim === 'angle'; + + if (isRadial) { + clipPath.shape.endAngle = sectorArea.startAngle; + } else { + clipPath.shape.r = r0; + } + + initProps(clipPath, { + shape: { + endAngle: sectorArea.endAngle, + r: r + } + }, seriesModel); + } + + return clipPath; + } + + function createClipPath(coordSys, hasAnimation, seriesModel, done, during) { + if (!coordSys) { + return null; + } else if (coordSys.type === 'polar') { + return createPolarClipPath(coordSys, hasAnimation, seriesModel); + } else if (coordSys.type === 'cartesian2d') { + return createGridClipPath(coordSys, hasAnimation, seriesModel, done, during); + } + + return null; + } + /** + * Sausage: similar to sector, but have half circle on both sides + */ + + + var SausageShape = + /** @class */ + function () { + function SausageShape() { + this.cx = 0; + this.cy = 0; + this.r0 = 0; + this.r = 0; + this.startAngle = 0; + this.endAngle = Math.PI * 2; + this.clockwise = true; + } + + return SausageShape; + }(); + + var SausagePath = + /** @class */ + function (_super) { + __extends(SausagePath, _super); + + function SausagePath(opts) { + var _this = _super.call(this, opts) || this; + + _this.type = 'sausage'; + return _this; + } + + SausagePath.prototype.getDefaultShape = function () { + return new SausageShape(); + }; + + SausagePath.prototype.buildPath = function (ctx, shape) { + var cx = shape.cx; + var cy = shape.cy; + var r0 = Math.max(shape.r0 || 0, 0); + var r = Math.max(shape.r, 0); + var dr = (r - r0) * 0.5; + var rCenter = r0 + dr; + var startAngle = shape.startAngle; + var endAngle = shape.endAngle; + var clockwise = shape.clockwise; + var PI2 = Math.PI * 2; + var lessThanCircle = clockwise ? endAngle - startAngle < PI2 : startAngle - endAngle < PI2; + + if (!lessThanCircle) { + // Normalize angles + startAngle = endAngle - (clockwise ? PI2 : -PI2); + } + + var unitStartX = Math.cos(startAngle); + var unitStartY = Math.sin(startAngle); + var unitEndX = Math.cos(endAngle); + var unitEndY = Math.sin(endAngle); + + if (lessThanCircle) { + ctx.moveTo(unitStartX * r0 + cx, unitStartY * r0 + cy); + ctx.arc(unitStartX * rCenter + cx, unitStartY * rCenter + cy, dr, -Math.PI + startAngle, startAngle, !clockwise); + } else { + ctx.moveTo(unitStartX * r + cx, unitStartY * r + cy); + } + + ctx.arc(cx, cy, r, startAngle, endAngle, !clockwise); + ctx.arc(unitEndX * rCenter + cx, unitEndY * rCenter + cy, dr, endAngle - Math.PI * 2, endAngle - Math.PI, !clockwise); + + if (r0 !== 0) { + ctx.arc(cx, cy, r0, endAngle, startAngle, clockwise); + } // ctx.closePath(); + + }; + + return SausagePath; + }(Path); + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + function isCoordinateSystemType(coordSys, type) { + return coordSys.type === type; + } + /** + * @return label string. Not null/undefined + */ + + + function getDefaultLabel(data, dataIndex) { + var labelDims = data.mapDimensionsAll('defaultedLabel'); + var len = labelDims.length; // Simple optimization (in lots of cases, label dims length is 1) + + if (len === 1) { + var rawVal = retrieveRawValue(data, dataIndex, labelDims[0]); + return rawVal != null ? rawVal + '' : null; + } else if (len) { + var vals = []; + + for (var i = 0; i < labelDims.length; i++) { + vals.push(retrieveRawValue(data, dataIndex, labelDims[i])); + } + + return vals.join(' '); + } + } + + function getDefaultInterpolatedLabel(data, interpolatedValue) { + var labelDims = data.mapDimensionsAll('defaultedLabel'); + + if (!isArray(interpolatedValue)) { + return interpolatedValue + ''; + } + + var vals = []; + + for (var i = 0; i < labelDims.length; i++) { + var dimIndex = data.getDimensionIndex(labelDims[i]); + + if (dimIndex >= 0) { + vals.push(interpolatedValue[dimIndex]); + } + } + + return vals.join(' '); + } + + function createSectorCalculateTextPosition(positionMapping, opts) { + opts = opts || {}; + var isRoundCap = opts.isRoundCap; + return function (out, opts, boundingRect) { + var textPosition = opts.position; + + if (!textPosition || textPosition instanceof Array) { + return calculateTextPosition(out, opts, boundingRect); + } + + var mappedSectorPosition = positionMapping(textPosition); + var distance = opts.distance != null ? opts.distance : 5; + var sector = this.shape; + var cx = sector.cx; + var cy = sector.cy; + var r = sector.r; + var r0 = sector.r0; + var middleR = (r + r0) / 2; + var startAngle = sector.startAngle; + var endAngle = sector.endAngle; + var middleAngle = (startAngle + endAngle) / 2; + var extraDist = isRoundCap ? Math.abs(r - r0) / 2 : 0; + var mathCos = Math.cos; + var mathSin = Math.sin; // base position: top-left + + var x = cx + r * mathCos(startAngle); + var y = cy + r * mathSin(startAngle); + var textAlign = 'left'; + var textVerticalAlign = 'top'; + + switch (mappedSectorPosition) { + case 'startArc': + x = cx + (r0 - distance) * mathCos(middleAngle); + y = cy + (r0 - distance) * mathSin(middleAngle); + textAlign = 'center'; + textVerticalAlign = 'top'; + break; + + case 'insideStartArc': + x = cx + (r0 + distance) * mathCos(middleAngle); + y = cy + (r0 + distance) * mathSin(middleAngle); + textAlign = 'center'; + textVerticalAlign = 'bottom'; + break; + + case 'startAngle': + x = cx + middleR * mathCos(startAngle) + adjustAngleDistanceX(startAngle, distance + extraDist, false); + y = cy + middleR * mathSin(startAngle) + adjustAngleDistanceY(startAngle, distance + extraDist, false); + textAlign = 'right'; + textVerticalAlign = 'middle'; + break; + + case 'insideStartAngle': + x = cx + middleR * mathCos(startAngle) + adjustAngleDistanceX(startAngle, -distance + extraDist, false); + y = cy + middleR * mathSin(startAngle) + adjustAngleDistanceY(startAngle, -distance + extraDist, false); + textAlign = 'left'; + textVerticalAlign = 'middle'; + break; + + case 'middle': + x = cx + middleR * mathCos(middleAngle); + y = cy + middleR * mathSin(middleAngle); + textAlign = 'center'; + textVerticalAlign = 'middle'; + break; + + case 'endArc': + x = cx + (r + distance) * mathCos(middleAngle); + y = cy + (r + distance) * mathSin(middleAngle); + textAlign = 'center'; + textVerticalAlign = 'bottom'; + break; + + case 'insideEndArc': + x = cx + (r - distance) * mathCos(middleAngle); + y = cy + (r - distance) * mathSin(middleAngle); + textAlign = 'center'; + textVerticalAlign = 'top'; + break; + + case 'endAngle': + x = cx + middleR * mathCos(endAngle) + adjustAngleDistanceX(endAngle, distance + extraDist, true); + y = cy + middleR * mathSin(endAngle) + adjustAngleDistanceY(endAngle, distance + extraDist, true); + textAlign = 'left'; + textVerticalAlign = 'middle'; + break; + + case 'insideEndAngle': + x = cx + middleR * mathCos(endAngle) + adjustAngleDistanceX(endAngle, -distance + extraDist, true); + y = cy + middleR * mathSin(endAngle) + adjustAngleDistanceY(endAngle, -distance + extraDist, true); + textAlign = 'right'; + textVerticalAlign = 'middle'; + break; + + default: + return calculateTextPosition(out, opts, boundingRect); + } + + out = out || {}; + out.x = x; + out.y = y; + out.align = textAlign; + out.verticalAlign = textVerticalAlign; + return out; + }; + } + + function setSectorTextRotation(sector, textPosition, positionMapping, rotateType) { + if (isNumber(rotateType)) { + // user-set rotation + sector.setTextConfig({ + rotation: rotateType + }); + return; + } else if (isArray(textPosition)) { + // user-set position, use 0 as auto rotation + sector.setTextConfig({ + rotation: 0 + }); + return; + } + + var shape = sector.shape; + var startAngle = shape.clockwise ? shape.startAngle : shape.endAngle; + var endAngle = shape.clockwise ? shape.endAngle : shape.startAngle; + var middleAngle = (startAngle + endAngle) / 2; + var anchorAngle; + var mappedSectorPosition = positionMapping(textPosition); + + switch (mappedSectorPosition) { + case 'startArc': + case 'insideStartArc': + case 'middle': + case 'insideEndArc': + case 'endArc': + anchorAngle = middleAngle; + break; + + case 'startAngle': + case 'insideStartAngle': + anchorAngle = startAngle; + break; + + case 'endAngle': + case 'insideEndAngle': + anchorAngle = endAngle; + break; + + default: + sector.setTextConfig({ + rotation: 0 + }); + return; + } + + var rotate = Math.PI * 1.5 - anchorAngle; + /** + * TODO: labels with rotate > Math.PI / 2 should be rotate another + * half round flipped to increase readability. However, only middle + * position supports this for now, because in other positions, the + * anchor point is not at the center of the text, so the positions + * after rotating is not as expected. + */ + + if (mappedSectorPosition === 'middle' && rotate > Math.PI / 2 && rotate < Math.PI * 1.5) { + rotate -= Math.PI; + } + + sector.setTextConfig({ + rotation: rotate + }); + } + + function adjustAngleDistanceX(angle, distance, isEnd) { + return distance * Math.sin(angle) * (isEnd ? -1 : 1); + } + + function adjustAngleDistanceY(angle, distance, isEnd) { + return distance * Math.cos(angle) * (isEnd ? 1 : -1); + } + + function getSectorCornerRadius(model, shape, zeroIfNull) { + var cornerRadius = model.get('borderRadius'); + + if (cornerRadius == null) { + return zeroIfNull ? { + cornerRadius: 0 + } : null; + } + + if (!isArray(cornerRadius)) { + cornerRadius = [cornerRadius, cornerRadius, cornerRadius, cornerRadius]; + } + + var dr = Math.abs(shape.r || 0 - shape.r0 || 0); + return { + cornerRadius: map$1(cornerRadius, function (cr) { + return parsePercent$1(cr, dr); + }) + }; + } + + var mathMax$1 = Math.max; + var mathMin$1 = Math.min; + + function getClipArea(coord, data) { + var coordSysClipArea = coord.getArea && coord.getArea(); + + if (isCoordinateSystemType(coord, 'cartesian2d')) { + var baseAxis = coord.getBaseAxis(); // When boundaryGap is false or using time axis. bar may exceed the grid. + // We should not clip this part. + // See test/bar2.html + + if (baseAxis.type !== 'category' || !baseAxis.onBand) { + var expandWidth = data.getLayout('bandWidth'); + + if (baseAxis.isHorizontal()) { + coordSysClipArea.x -= expandWidth; + coordSysClipArea.width += expandWidth * 2; + } else { + coordSysClipArea.y -= expandWidth; + coordSysClipArea.height += expandWidth * 2; + } + } + } + + return coordSysClipArea; + } + + var BarView = + /** @class */ + function (_super) { + __extends(BarView, _super); + + function BarView() { + var _this = _super.call(this) || this; + + _this.type = BarView.type; + _this._isFirstFrame = true; + return _this; + } + + BarView.prototype.render = function (seriesModel, ecModel, api, payload) { + this._model = seriesModel; + + this._removeOnRenderedListener(api); + + this._updateDrawMode(seriesModel); + + var coordinateSystemType = seriesModel.get('coordinateSystem'); + + if (coordinateSystemType === 'cartesian2d' || coordinateSystemType === 'polar') { + // Clear previously rendered progressive elements. + this._progressiveEls = null; + this._isLargeDraw ? this._renderLarge(seriesModel, ecModel, api) : this._renderNormal(seriesModel, ecModel, api, payload); + } else { + warn('Only cartesian2d and polar supported for bar.'); + } + }; + + BarView.prototype.incrementalPrepareRender = function (seriesModel) { + this._clear(); + + this._updateDrawMode(seriesModel); // incremental also need to clip, otherwise might be overlow. + // But must not set clip in each frame, otherwise all of the children will be marked redraw. + + + this._updateLargeClip(seriesModel); + }; + + BarView.prototype.incrementalRender = function (params, seriesModel) { + // Reset + this._progressiveEls = []; // Do not support progressive in normal mode. + + this._incrementalRenderLarge(params, seriesModel); + }; + + BarView.prototype.eachRendered = function (cb) { + traverseElements(this._progressiveEls || this.group, cb); + }; + + BarView.prototype._updateDrawMode = function (seriesModel) { + var isLargeDraw = seriesModel.pipelineContext.large; + + if (this._isLargeDraw == null || isLargeDraw !== this._isLargeDraw) { + this._isLargeDraw = isLargeDraw; + + this._clear(); + } + }; + + BarView.prototype._renderNormal = function (seriesModel, ecModel, api, payload) { + var group = this.group; + var data = seriesModel.getData(); + var oldData = this._data; + var coord = seriesModel.coordinateSystem; + var baseAxis = coord.getBaseAxis(); + var isHorizontalOrRadial; + + if (coord.type === 'cartesian2d') { + isHorizontalOrRadial = baseAxis.isHorizontal(); + } else if (coord.type === 'polar') { + isHorizontalOrRadial = baseAxis.dim === 'angle'; + } + + var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null; + var realtimeSortCfg = shouldRealtimeSort(seriesModel, coord); + + if (realtimeSortCfg) { + this._enableRealtimeSort(realtimeSortCfg, data, api); + } + + var needsClip = seriesModel.get('clip', true) || realtimeSortCfg; + var coordSysClipArea = getClipArea(coord, data); // If there is clipPath created in large mode. Remove it. + + group.removeClipPath(); // We don't use clipPath in normal mode because we needs a perfect animation + // And don't want the label are clipped. + + var roundCap = seriesModel.get('roundCap', true); + var drawBackground = seriesModel.get('showBackground', true); + var backgroundModel = seriesModel.getModel('backgroundStyle'); + var barBorderRadius = backgroundModel.get('borderRadius') || 0; + var bgEls = []; + var oldBgEls = this._backgroundEls; + var isInitSort = payload && payload.isInitSort; + var isChangeOrder = payload && payload.type === 'changeAxisOrder'; + + function createBackground(dataIndex) { + var bgLayout = getLayout[coord.type](data, dataIndex); + + if (!bgLayout) { + return null; + } + + var bgEl = createBackgroundEl(coord, isHorizontalOrRadial, bgLayout); + bgEl.useStyle(backgroundModel.getItemStyle()); // Only cartesian2d support borderRadius. + + if (coord.type === 'cartesian2d') { + bgEl.setShape('r', barBorderRadius); + } else { + bgEl.setShape('cornerRadius', barBorderRadius); + } + + bgEls[dataIndex] = bgEl; + return bgEl; + } + + data.diff(oldData).add(function (dataIndex) { + var itemModel = data.getItemModel(dataIndex); + var layout = getLayout[coord.type](data, dataIndex, itemModel); + + if (!layout) { + return; + } + + if (drawBackground) { + createBackground(dataIndex); + } // If dataZoom in filteMode: 'empty', the baseValue can be set as NaN in "axisProxy". + + + if (!data.hasValue(dataIndex) || !isValidLayout[coord.type](layout)) { + return; + } + + var isClipped = false; + + if (needsClip) { + // Clip will modify the layout params. + // And return a boolean to determine if the shape are fully clipped. + isClipped = clip[coord.type](coordSysClipArea, layout); + } + + var el = elementCreator[coord.type](seriesModel, data, dataIndex, layout, isHorizontalOrRadial, animationModel, baseAxis.model, false, roundCap); + + if (realtimeSortCfg) { + /** + * Force label animation because even if the element is + * ignored because it's clipped, it may not be clipped after + * changing order. Then, if not using forceLabelAnimation, + * the label animation was never started, in which case, + * the label will be the final value and doesn't have label + * animation. + */ + el.forceLabelAnimation = true; + } + + updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar'); + + if (isInitSort) { + el.attr({ + shape: layout + }); + } else if (realtimeSortCfg) { + updateRealtimeAnimation(realtimeSortCfg, animationModel, el, layout, dataIndex, isHorizontalOrRadial, false, false); + } else { + initProps(el, { + shape: layout + }, seriesModel, dataIndex); + } + + data.setItemGraphicEl(dataIndex, el); + group.add(el); + el.ignore = isClipped; + }).update(function (newIndex, oldIndex) { + var itemModel = data.getItemModel(newIndex); + var layout = getLayout[coord.type](data, newIndex, itemModel); + + if (!layout) { + return; + } + + if (drawBackground) { + var bgEl = void 0; + + if (oldBgEls.length === 0) { + bgEl = createBackground(oldIndex); + } else { + bgEl = oldBgEls[oldIndex]; + bgEl.useStyle(backgroundModel.getItemStyle()); // Only cartesian2d support borderRadius. + + if (coord.type === 'cartesian2d') { + bgEl.setShape('r', barBorderRadius); + } else { + bgEl.setShape('cornerRadius', barBorderRadius); + } + + bgEls[newIndex] = bgEl; + } + + var bgLayout = getLayout[coord.type](data, newIndex); + var shape = createBackgroundShape(isHorizontalOrRadial, bgLayout, coord); + updateProps$1(bgEl, { + shape: shape + }, animationModel, newIndex); + } + + var el = oldData.getItemGraphicEl(oldIndex); + + if (!data.hasValue(newIndex) || !isValidLayout[coord.type](layout)) { + group.remove(el); + return; + } + + var isClipped = false; + + if (needsClip) { + isClipped = clip[coord.type](coordSysClipArea, layout); + + if (isClipped) { + group.remove(el); + } + } + + var roundCapChanged = el && (el.type === 'sector' && roundCap || el.type === 'sausage' && !roundCap); + + if (roundCapChanged) { + // roundCap changed, there is no way to use animation from a `sector` to a `sausage` shape, + // so remove the old one and create a new shape + el && removeElementWithFadeOut(el, seriesModel, oldIndex); + el = null; + } + + if (!el) { + el = elementCreator[coord.type](seriesModel, data, newIndex, layout, isHorizontalOrRadial, animationModel, baseAxis.model, true, roundCap); + } else { + saveOldStyle(el); + } + + if (realtimeSortCfg) { + el.forceLabelAnimation = true; + } + + if (isChangeOrder) { + var textEl = el.getTextContent(); + + if (textEl) { + var labelInnerStore = labelInner(textEl); + + if (labelInnerStore.prevValue != null) { + /** + * Set preValue to be value so that no new label + * should be started, otherwise, it will take a full + * `animationDurationUpdate` time to finish the + * animation, which is not expected. + */ + labelInnerStore.prevValue = labelInnerStore.value; + } + } + } // Not change anything if only order changed. + // Especially not change label. + else { + updateStyle(el, data, newIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar'); + } + + if (isInitSort) { + el.attr({ + shape: layout + }); + } else if (realtimeSortCfg) { + updateRealtimeAnimation(realtimeSortCfg, animationModel, el, layout, newIndex, isHorizontalOrRadial, true, isChangeOrder); + } else { + updateProps$1(el, { + shape: layout + }, seriesModel, newIndex, null); + } + + data.setItemGraphicEl(newIndex, el); + el.ignore = isClipped; + group.add(el); + }).remove(function (dataIndex) { + var el = oldData.getItemGraphicEl(dataIndex); + el && removeElementWithFadeOut(el, seriesModel, dataIndex); + }).execute(); + var bgGroup = this._backgroundGroup || (this._backgroundGroup = new Group$2()); + bgGroup.removeAll(); + + for (var i = 0; i < bgEls.length; ++i) { + bgGroup.add(bgEls[i]); + } + + group.add(bgGroup); + this._backgroundEls = bgEls; + this._data = data; + }; + + BarView.prototype._renderLarge = function (seriesModel, ecModel, api) { + this._clear(); + + createLarge(seriesModel, this.group); + + this._updateLargeClip(seriesModel); + }; + + BarView.prototype._incrementalRenderLarge = function (params, seriesModel) { + this._removeBackground(); + + createLarge(seriesModel, this.group, this._progressiveEls, true); + }; + + BarView.prototype._updateLargeClip = function (seriesModel) { + // Use clipPath in large mode. + var clipPath = seriesModel.get('clip', true) && createClipPath(seriesModel.coordinateSystem, false, seriesModel); + var group = this.group; + + if (clipPath) { + group.setClipPath(clipPath); + } else { + group.removeClipPath(); + } + }; + + BarView.prototype._enableRealtimeSort = function (realtimeSortCfg, data, api) { + var _this = this; // If no data in the first frame, wait for data to initSort + + + if (!data.count()) { + return; + } + + var baseAxis = realtimeSortCfg.baseAxis; + + if (this._isFirstFrame) { + this._dispatchInitSort(data, realtimeSortCfg, api); + + this._isFirstFrame = false; + } else { + var orderMapping_1 = function (idx) { + var el = data.getItemGraphicEl(idx); + var shape = el && el.shape; + return shape && // The result should be consistent with the initial sort by data value. + // Do not support the case that both positive and negative exist. + Math.abs(baseAxis.isHorizontal() ? shape.height : shape.width) // If data is NaN, shape.xxx may be NaN, so use || 0 here in case + || 0; + }; + + this._onRendered = function () { + _this._updateSortWithinSameData(data, orderMapping_1, baseAxis, api); + }; + + api.getZr().on('rendered', this._onRendered); + } + }; + + BarView.prototype._dataSort = function (data, baseAxis, orderMapping) { + var info = []; + data.each(data.mapDimension(baseAxis.dim), function (ordinalNumber, dataIdx) { + var mappedValue = orderMapping(dataIdx); + mappedValue = mappedValue == null ? NaN : mappedValue; + info.push({ + dataIndex: dataIdx, + mappedValue: mappedValue, + ordinalNumber: ordinalNumber + }); + }); + info.sort(function (a, b) { + // If NaN, it will be treated as min val. + return b.mappedValue - a.mappedValue; + }); + return { + ordinalNumbers: map$1(info, function (item) { + return item.ordinalNumber; + }) + }; + }; + + BarView.prototype._isOrderChangedWithinSameData = function (data, orderMapping, baseAxis) { + var scale = baseAxis.scale; + var ordinalDataDim = data.mapDimension(baseAxis.dim); + var lastValue = Number.MAX_VALUE; + + for (var tickNum = 0, len = scale.getOrdinalMeta().categories.length; tickNum < len; ++tickNum) { + var rawIdx = data.rawIndexOf(ordinalDataDim, scale.getRawOrdinalNumber(tickNum)); + var value = rawIdx < 0 // If some tick have no bar, the tick will be treated as min. + ? Number.MIN_VALUE // PENDING: if dataZoom on baseAxis exits, is it a performance issue? + : orderMapping(data.indexOfRawIndex(rawIdx)); + + if (value > lastValue) { + return true; + } + + lastValue = value; + } + + return false; + }; + /* + * Consider the case when A and B changed order, whose representing + * bars are both out of sight, we don't wish to trigger reorder action + * as long as the order in the view doesn't change. + */ + + + BarView.prototype._isOrderDifferentInView = function (orderInfo, baseAxis) { + var scale = baseAxis.scale; + var extent = scale.getExtent(); + var tickNum = Math.max(0, extent[0]); + var tickMax = Math.min(extent[1], scale.getOrdinalMeta().categories.length - 1); + + for (; tickNum <= tickMax; ++tickNum) { + if (orderInfo.ordinalNumbers[tickNum] !== scale.getRawOrdinalNumber(tickNum)) { + return true; + } + } + }; + + BarView.prototype._updateSortWithinSameData = function (data, orderMapping, baseAxis, api) { + if (!this._isOrderChangedWithinSameData(data, orderMapping, baseAxis)) { + return; + } + + var sortInfo = this._dataSort(data, baseAxis, orderMapping); + + if (this._isOrderDifferentInView(sortInfo, baseAxis)) { + this._removeOnRenderedListener(api); + + api.dispatchAction({ + type: 'changeAxisOrder', + componentType: baseAxis.dim + 'Axis', + axisId: baseAxis.index, + sortInfo: sortInfo + }); + } + }; + + BarView.prototype._dispatchInitSort = function (data, realtimeSortCfg, api) { + var baseAxis = realtimeSortCfg.baseAxis; + + var sortResult = this._dataSort(data, baseAxis, function (dataIdx) { + return data.get(data.mapDimension(realtimeSortCfg.otherAxis.dim), dataIdx); + }); + + api.dispatchAction({ + type: 'changeAxisOrder', + componentType: baseAxis.dim + 'Axis', + isInitSort: true, + axisId: baseAxis.index, + sortInfo: sortResult + }); + }; + + BarView.prototype.remove = function (ecModel, api) { + this._clear(this._model); + + this._removeOnRenderedListener(api); + }; + + BarView.prototype.dispose = function (ecModel, api) { + this._removeOnRenderedListener(api); + }; + + BarView.prototype._removeOnRenderedListener = function (api) { + if (this._onRendered) { + api.getZr().off('rendered', this._onRendered); + this._onRendered = null; + } + }; + + BarView.prototype._clear = function (model) { + var group = this.group; + var data = this._data; + + if (model && model.isAnimationEnabled() && data && !this._isLargeDraw) { + this._removeBackground(); + + this._backgroundEls = []; + data.eachItemGraphicEl(function (el) { + removeElementWithFadeOut(el, model, getECData(el).dataIndex); + }); + } else { + group.removeAll(); + } + + this._data = null; + this._isFirstFrame = true; + }; + + BarView.prototype._removeBackground = function () { + this.group.remove(this._backgroundGroup); + this._backgroundGroup = null; + }; + + BarView.type = 'bar'; + return BarView; + }(ChartView); + + var clip = { + cartesian2d: function (coordSysBoundingRect, layout) { + var signWidth = layout.width < 0 ? -1 : 1; + var signHeight = layout.height < 0 ? -1 : 1; // Needs positive width and height + + if (signWidth < 0) { + layout.x += layout.width; + layout.width = -layout.width; + } + + if (signHeight < 0) { + layout.y += layout.height; + layout.height = -layout.height; + } + + var coordSysX2 = coordSysBoundingRect.x + coordSysBoundingRect.width; + var coordSysY2 = coordSysBoundingRect.y + coordSysBoundingRect.height; + var x = mathMax$1(layout.x, coordSysBoundingRect.x); + var x2 = mathMin$1(layout.x + layout.width, coordSysX2); + var y = mathMax$1(layout.y, coordSysBoundingRect.y); + var y2 = mathMin$1(layout.y + layout.height, coordSysY2); + var xClipped = x2 < x; + var yClipped = y2 < y; // When xClipped or yClipped, the element will be marked as `ignore`. + // But we should also place the element at the edge of the coord sys bounding rect. + // Because if data changed and the bar shows again, its transition animation + // will begin at this place. + + layout.x = xClipped && x > coordSysX2 ? x2 : x; + layout.y = yClipped && y > coordSysY2 ? y2 : y; + layout.width = xClipped ? 0 : x2 - x; + layout.height = yClipped ? 0 : y2 - y; // Reverse back + + if (signWidth < 0) { + layout.x += layout.width; + layout.width = -layout.width; + } + + if (signHeight < 0) { + layout.y += layout.height; + layout.height = -layout.height; + } + + return xClipped || yClipped; + }, + polar: function (coordSysClipArea, layout) { + var signR = layout.r0 <= layout.r ? 1 : -1; // Make sure r is larger than r0 + + if (signR < 0) { + var tmp = layout.r; + layout.r = layout.r0; + layout.r0 = tmp; + } + + var r = mathMin$1(layout.r, coordSysClipArea.r); + var r0 = mathMax$1(layout.r0, coordSysClipArea.r0); + layout.r = r; + layout.r0 = r0; + var clipped = r - r0 < 0; // Reverse back + + if (signR < 0) { + var tmp = layout.r; + layout.r = layout.r0; + layout.r0 = tmp; + } + + return clipped; + } + }; + var elementCreator = { + cartesian2d: function (seriesModel, data, newIndex, layout, isHorizontal, animationModel, axisModel, isUpdate, roundCap) { + var rect = new Rect({ + shape: extend({}, layout), + z2: 1 + }); + rect.__dataIndex = newIndex; + rect.name = 'item'; + + if (animationModel) { + var rectShape = rect.shape; + var animateProperty = isHorizontal ? 'height' : 'width'; + rectShape[animateProperty] = 0; + } + + return rect; + }, + polar: function (seriesModel, data, newIndex, layout, isRadial, animationModel, axisModel, isUpdate, roundCap) { + var ShapeClass = !isRadial && roundCap ? SausagePath : Sector; + var sector = new ShapeClass({ + shape: layout, + z2: 1 + }); + sector.name = 'item'; + var positionMap = createPolarPositionMapping(isRadial); + sector.calculateTextPosition = createSectorCalculateTextPosition(positionMap, { + isRoundCap: ShapeClass === SausagePath + }); // Animation + + if (animationModel) { + var sectorShape = sector.shape; + var animateProperty = isRadial ? 'r' : 'endAngle'; + var animateTarget = {}; + sectorShape[animateProperty] = isRadial ? layout.r0 : layout.startAngle; + animateTarget[animateProperty] = layout[animateProperty]; + (isUpdate ? updateProps$1 : initProps)(sector, { + shape: animateTarget // __value: typeof dataValue === 'string' ? parseInt(dataValue, 10) : dataValue + + }, animationModel); + } + + return sector; + } + }; + + function shouldRealtimeSort(seriesModel, coordSys) { + var realtimeSortOption = seriesModel.get('realtimeSort', true); + var baseAxis = coordSys.getBaseAxis(); + { + if (realtimeSortOption) { + if (baseAxis.type !== 'category') { + warn('`realtimeSort` will not work because this bar series is not based on a category axis.'); + } + + if (coordSys.type !== 'cartesian2d') { + warn('`realtimeSort` will not work because this bar series is not on cartesian2d.'); + } + } + } + + if (realtimeSortOption && baseAxis.type === 'category' && coordSys.type === 'cartesian2d') { + return { + baseAxis: baseAxis, + otherAxis: coordSys.getOtherAxis(baseAxis) + }; + } + } + + function updateRealtimeAnimation(realtimeSortCfg, seriesAnimationModel, el, layout, newIndex, isHorizontal, isUpdate, isChangeOrder) { + var seriesTarget; + var axisTarget; + + if (isHorizontal) { + axisTarget = { + x: layout.x, + width: layout.width + }; + seriesTarget = { + y: layout.y, + height: layout.height + }; + } else { + axisTarget = { + y: layout.y, + height: layout.height + }; + seriesTarget = { + x: layout.x, + width: layout.width + }; + } + + if (!isChangeOrder) { + // Keep the original growth animation if only axis order changed. + // Not start a new animation. + (isUpdate ? updateProps$1 : initProps)(el, { + shape: seriesTarget + }, seriesAnimationModel, newIndex, null); + } + + var axisAnimationModel = seriesAnimationModel ? realtimeSortCfg.baseAxis.model : null; + (isUpdate ? updateProps$1 : initProps)(el, { + shape: axisTarget + }, axisAnimationModel, newIndex); + } + + function checkPropertiesNotValid(obj, props) { + for (var i = 0; i < props.length; i++) { + if (!isFinite(obj[props[i]])) { + return true; + } + } + + return false; + } + + var rectPropties = ['x', 'y', 'width', 'height']; + var polarPropties = ['cx', 'cy', 'r', 'startAngle', 'endAngle']; + var isValidLayout = { + cartesian2d: function (layout) { + return !checkPropertiesNotValid(layout, rectPropties); + }, + polar: function (layout) { + return !checkPropertiesNotValid(layout, polarPropties); + } + }; + var getLayout = { + // itemModel is only used to get borderWidth, which is not needed + // when calculating bar background layout. + cartesian2d: function (data, dataIndex, itemModel) { + var layout = data.getItemLayout(dataIndex); + + if (!layout) { + return null; + } + + var fixedLineWidth = itemModel ? getLineWidth(itemModel, layout) : 0; // fix layout with lineWidth + + var signX = layout.width > 0 ? 1 : -1; + var signY = layout.height > 0 ? 1 : -1; + return { + x: layout.x + signX * fixedLineWidth / 2, + y: layout.y + signY * fixedLineWidth / 2, + width: layout.width - signX * fixedLineWidth, + height: layout.height - signY * fixedLineWidth + }; + }, + polar: function (data, dataIndex, itemModel) { + var layout = data.getItemLayout(dataIndex); + return { + cx: layout.cx, + cy: layout.cy, + r0: layout.r0, + r: layout.r, + startAngle: layout.startAngle, + endAngle: layout.endAngle, + clockwise: layout.clockwise + }; + } + }; + + function isZeroOnPolar(layout) { + return layout.startAngle != null && layout.endAngle != null && layout.startAngle === layout.endAngle; + } + + function createPolarPositionMapping(isRadial) { + return function (isRadial) { + var arcOrAngle = isRadial ? 'Arc' : 'Angle'; + return function (position) { + switch (position) { + case 'start': + case 'insideStart': + case 'end': + case 'insideEnd': + return position + arcOrAngle; + + default: + return position; + } + }; + }(isRadial); + } + + function updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, isPolar) { + var style = data.getItemVisual(dataIndex, 'style'); + + if (!isPolar) { + var borderRadius = itemModel.get(['itemStyle', 'borderRadius']) || 0; + el.setShape('r', borderRadius); + } else if (!seriesModel.get('roundCap')) { + var sectorShape = el.shape; + var cornerRadius = getSectorCornerRadius(itemModel.getModel('itemStyle'), sectorShape, true); + extend(sectorShape, cornerRadius); + el.setShape(sectorShape); + } + + el.useStyle(style); + var cursorStyle = itemModel.getShallow('cursor'); + cursorStyle && el.attr('cursor', cursorStyle); + var labelPositionOutside = isPolar ? isHorizontalOrRadial ? layout.r >= layout.r0 ? 'endArc' : 'startArc' : layout.endAngle >= layout.startAngle ? 'endAngle' : 'startAngle' : isHorizontalOrRadial ? layout.height >= 0 ? 'bottom' : 'top' : layout.width >= 0 ? 'right' : 'left'; + var labelStatesModels = getLabelStatesModels(itemModel); + setLabelStyle(el, labelStatesModels, { + labelFetcher: seriesModel, + labelDataIndex: dataIndex, + defaultText: getDefaultLabel(seriesModel.getData(), dataIndex), + inheritColor: style.fill, + defaultOpacity: style.opacity, + defaultOutsidePosition: labelPositionOutside + }); + var label = el.getTextContent(); + + if (isPolar && label) { + var position = itemModel.get(['label', 'position']); + el.textConfig.inside = position === 'middle' ? true : null; + setSectorTextRotation(el, position === 'outside' ? labelPositionOutside : position, createPolarPositionMapping(isHorizontalOrRadial), itemModel.get(['label', 'rotate'])); + } + + setLabelValueAnimation(label, labelStatesModels, seriesModel.getRawValue(dataIndex), function (value) { + return getDefaultInterpolatedLabel(data, value); + }); + var emphasisModel = itemModel.getModel(['emphasis']); + toggleHoverEmphasis(el, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled')); + setStatesStylesFromModel(el, itemModel); + + if (isZeroOnPolar(layout)) { + el.style.fill = 'none'; + el.style.stroke = 'none'; + each$4(el.states, function (state) { + if (state.style) { + state.style.fill = state.style.stroke = 'none'; + } + }); + } + } // In case width or height are too small. + + + function getLineWidth(itemModel, rawLayout) { + // Has no border. + var borderColor = itemModel.get(['itemStyle', 'borderColor']); + + if (!borderColor || borderColor === 'none') { + return 0; + } + + var lineWidth = itemModel.get(['itemStyle', 'borderWidth']) || 0; // width or height may be NaN for empty data + + var width = isNaN(rawLayout.width) ? Number.MAX_VALUE : Math.abs(rawLayout.width); + var height = isNaN(rawLayout.height) ? Number.MAX_VALUE : Math.abs(rawLayout.height); + return Math.min(lineWidth, width, height); + } + + var LagePathShape = + /** @class */ + function () { + function LagePathShape() {} + + return LagePathShape; + }(); + + var LargePath = + /** @class */ + function (_super) { + __extends(LargePath, _super); + + function LargePath(opts) { + var _this = _super.call(this, opts) || this; + + _this.type = 'largeBar'; + return _this; + } + + LargePath.prototype.getDefaultShape = function () { + return new LagePathShape(); + }; + + LargePath.prototype.buildPath = function (ctx, shape) { + // Drawing lines is more efficient than drawing + // a whole line or drawing rects. + var points = shape.points; + var baseDimIdx = this.baseDimIdx; + var valueDimIdx = 1 - this.baseDimIdx; + var startPoint = []; + var size = []; + var barWidth = this.barWidth; + + for (var i = 0; i < points.length; i += 3) { + size[baseDimIdx] = barWidth; + size[valueDimIdx] = points[i + 2]; + startPoint[baseDimIdx] = points[i + baseDimIdx]; + startPoint[valueDimIdx] = points[i + valueDimIdx]; + ctx.rect(startPoint[0], startPoint[1], size[0], size[1]); + } + }; + + return LargePath; + }(Path); + + function createLarge(seriesModel, group, progressiveEls, incremental) { + // TODO support polar + var data = seriesModel.getData(); + var baseDimIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0; + var largeDataIndices = data.getLayout('largeDataIndices'); + var barWidth = data.getLayout('size'); + var backgroundModel = seriesModel.getModel('backgroundStyle'); + var bgPoints = data.getLayout('largeBackgroundPoints'); + + if (bgPoints) { + var bgEl = new LargePath({ + shape: { + points: bgPoints + }, + incremental: !!incremental, + silent: true, + z2: 0 + }); + bgEl.baseDimIdx = baseDimIdx; + bgEl.largeDataIndices = largeDataIndices; + bgEl.barWidth = barWidth; + bgEl.useStyle(backgroundModel.getItemStyle()); + group.add(bgEl); + progressiveEls && progressiveEls.push(bgEl); + } + + var el = new LargePath({ + shape: { + points: data.getLayout('largePoints') + }, + incremental: !!incremental, + ignoreCoarsePointer: true, + z2: 1 + }); + el.baseDimIdx = baseDimIdx; + el.largeDataIndices = largeDataIndices; + el.barWidth = barWidth; + group.add(el); + el.useStyle(data.getVisual('style')); // Stroke is rendered first to avoid overlapping with fill + + el.style.stroke = null; // Enable tooltip and user mouse/touch event handlers. + + getECData(el).seriesIndex = seriesModel.seriesIndex; + + if (!seriesModel.get('silent')) { + el.on('mousedown', largePathUpdateDataIndex); + el.on('mousemove', largePathUpdateDataIndex); + } + + progressiveEls && progressiveEls.push(el); + } // Use throttle to avoid frequently traverse to find dataIndex. + + + var largePathUpdateDataIndex = throttle(function (event) { + var largePath = this; + var dataIndex = largePathFindDataIndex(largePath, event.offsetX, event.offsetY); + getECData(largePath).dataIndex = dataIndex >= 0 ? dataIndex : null; + }, 30, false); + + function largePathFindDataIndex(largePath, x, y) { + var baseDimIdx = largePath.baseDimIdx; + var valueDimIdx = 1 - baseDimIdx; + var points = largePath.shape.points; + var largeDataIndices = largePath.largeDataIndices; + var startPoint = []; + var size = []; + var barWidth = largePath.barWidth; + + for (var i = 0, len = points.length / 3; i < len; i++) { + var ii = i * 3; + size[baseDimIdx] = barWidth; + size[valueDimIdx] = points[ii + 2]; + startPoint[baseDimIdx] = points[ii + baseDimIdx]; + startPoint[valueDimIdx] = points[ii + valueDimIdx]; + + if (size[valueDimIdx] < 0) { + startPoint[valueDimIdx] += size[valueDimIdx]; + size[valueDimIdx] = -size[valueDimIdx]; + } + + if (x >= startPoint[0] && x <= startPoint[0] + size[0] && y >= startPoint[1] && y <= startPoint[1] + size[1]) { + return largeDataIndices[i]; + } + } + + return -1; + } + + function createBackgroundShape(isHorizontalOrRadial, layout, coord) { + if (isCoordinateSystemType(coord, 'cartesian2d')) { + var rectShape = layout; + var coordLayout = coord.getArea(); + return { + x: isHorizontalOrRadial ? rectShape.x : coordLayout.x, + y: isHorizontalOrRadial ? coordLayout.y : rectShape.y, + width: isHorizontalOrRadial ? rectShape.width : coordLayout.width, + height: isHorizontalOrRadial ? coordLayout.height : rectShape.height + }; + } else { + var coordLayout = coord.getArea(); + var sectorShape = layout; + return { + cx: coordLayout.cx, + cy: coordLayout.cy, + r0: isHorizontalOrRadial ? coordLayout.r0 : sectorShape.r0, + r: isHorizontalOrRadial ? coordLayout.r : sectorShape.r, + startAngle: isHorizontalOrRadial ? sectorShape.startAngle : 0, + endAngle: isHorizontalOrRadial ? sectorShape.endAngle : Math.PI * 2 + }; + } + } + + function createBackgroundEl(coord, isHorizontalOrRadial, layout) { + var ElementClz = coord.type === 'polar' ? Sector : Rect; + return new ElementClz({ + shape: createBackgroundShape(isHorizontalOrRadial, layout, coord), + silent: true, + z2: 0 + }); + } + + function install$9(registers) { + registers.registerChartView(BarView); + registers.registerSeriesModel(BarSeriesModel); + registers.registerLayout(registers.PRIORITY.VISUAL.LAYOUT, curry$1(layout$1, 'bar')); // Do layout after other overall layout, which can prepare some information. + + registers.registerLayout(registers.PRIORITY.VISUAL.PROGRESSIVE_LAYOUT, createProgressiveLayout('bar')); // Down sample after filter + + registers.registerProcessor(registers.PRIORITY.PROCESSOR.STATISTIC, dataSample('bar')); + /** + * @payload + * @property {string} [componentType=series] + * @property {number} [dx] + * @property {number} [dy] + * @property {number} [zoom] + * @property {number} [originX] + * @property {number} [originY] + */ + + registers.registerAction({ + type: 'changeAxisOrder', + event: 'changeAxisOrder', + update: 'update' + }, function (payload, ecModel) { + var componentType = payload.componentType || 'series'; + ecModel.eachComponent({ + mainType: componentType, + query: payload + }, function (componentModel) { + if (payload.sortInfo) { + componentModel.axis.setCategorySortInfo(payload.sortInfo); + } + }); + }); + } + + use(install$9); + + var LineSeriesModel = + /** @class */ + function (_super) { + __extends(LineSeriesModel, _super); + + function LineSeriesModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = LineSeriesModel.type; + _this.hasSymbolVisual = true; + return _this; + } + + LineSeriesModel.prototype.getInitialData = function (option) { + { + var coordSys = option.coordinateSystem; + + if (coordSys !== 'polar' && coordSys !== 'cartesian2d') { + throw new Error('Line not support coordinateSystem besides cartesian and polar'); + } + } + return createSeriesData(null, this, { + useEncodeDefaulter: true + }); + }; + + LineSeriesModel.prototype.getLegendIcon = function (opt) { + var group = new Group$2(); + var line = createSymbol('line', 0, opt.itemHeight / 2, opt.itemWidth, 0, opt.lineStyle.stroke, false); + group.add(line); + line.setStyle(opt.lineStyle); + var visualType = this.getData().getVisual('symbol'); + var visualRotate = this.getData().getVisual('symbolRotate'); + var symbolType = visualType === 'none' ? 'circle' : visualType; // Symbol size is 80% when there is a line + + var size = opt.itemHeight * 0.8; + var symbol = createSymbol(symbolType, (opt.itemWidth - size) / 2, (opt.itemHeight - size) / 2, size, size, opt.itemStyle.fill); + group.add(symbol); + symbol.setStyle(opt.itemStyle); + var symbolRotate = opt.iconRotate === 'inherit' ? visualRotate : opt.iconRotate || 0; + symbol.rotation = symbolRotate * Math.PI / 180; + symbol.setOrigin([opt.itemWidth / 2, opt.itemHeight / 2]); + + if (symbolType.indexOf('empty') > -1) { + symbol.style.stroke = symbol.style.fill; + symbol.style.fill = tokens.color.neutral00; + symbol.style.lineWidth = 2; + } + + return group; + }; + + LineSeriesModel.type = 'series.line'; + LineSeriesModel.dependencies = ['grid', 'polar']; + LineSeriesModel.defaultOption = { + // zlevel: 0, + z: 3, + coordinateSystem: 'cartesian2d', + legendHoverLink: true, + clip: true, + label: { + position: 'top' + }, + // itemStyle: { + // }, + endLabel: { + show: false, + valueAnimation: true, + distance: 8 + }, + lineStyle: { + width: 2, + type: 'solid' + }, + emphasis: { + scale: true + }, + // areaStyle: { + // origin of areaStyle. Valid values: + // `'auto'/null/undefined`: from axisLine to data + // `'start'`: from min to data + // `'end'`: from data to max + // origin: 'auto' + // }, + // false, 'start', 'end', 'middle' + step: false, + // Disabled if step is true + smooth: false, + smoothMonotone: null, + symbol: 'emptyCircle', + symbolSize: 6, + symbolRotate: null, + showSymbol: true, + // `false`: follow the label interval strategy. + // `true`: show all symbols. + // `'auto'`: If possible, show all symbols, otherwise + // follow the label interval strategy. + showAllSymbol: 'auto', + // Whether to connect break point. + connectNulls: false, + // Sampling for large data. Can be: 'average', 'max', 'min', 'sum', 'lttb'. + sampling: 'none', + animationEasing: 'linear', + // Disable progressive + progressive: 0, + hoverLayerThreshold: Infinity, + universalTransition: { + divideShape: 'clone' + }, + triggerLineEvent: false + }; + return LineSeriesModel; + }(SeriesModel); + + var Symbol = + /** @class */ + function (_super) { + __extends(Symbol, _super); + + function Symbol(data, idx, seriesScope, opts) { + var _this = _super.call(this) || this; + + _this.updateData(data, idx, seriesScope, opts); + + return _this; + } + + Symbol.prototype._createSymbol = function (symbolType, data, idx, symbolSize, z2, keepAspect) { + // Remove paths created before + this.removeAll(); // let symbolPath = createSymbol( + // symbolType, -0.5, -0.5, 1, 1, color + // ); + // If width/height are set too small (e.g., set to 1) on ios10 + // and macOS Sierra, a circle stroke become a rect, no matter what + // the scale is set. So we set width/height as 2. See #4150. + + var symbolPath = createSymbol(symbolType, -1, -1, 2, 2, null, keepAspect); + symbolPath.attr({ + z2: retrieve2(z2, 100), + culling: true, + scaleX: symbolSize[0] / 2, + scaleY: symbolSize[1] / 2 + }); // Rewrite drift method + + symbolPath.drift = driftSymbol; + this._symbolType = symbolType; + this.add(symbolPath); + }; + /** + * Stop animation + * @param {boolean} toLastFrame + */ + + + Symbol.prototype.stopSymbolAnimation = function (toLastFrame) { + this.childAt(0).stopAnimation(null, toLastFrame); + }; + + Symbol.prototype.getSymbolType = function () { + return this._symbolType; + }; + /** + * FIXME: + * Caution: This method breaks the encapsulation of this module, + * but it indeed brings convenience. So do not use the method + * unless you detailedly know all the implements of `Symbol`, + * especially animation. + * + * Get symbol path element. + */ + + + Symbol.prototype.getSymbolPath = function () { + return this.childAt(0); + }; + /** + * Highlight symbol + */ + + + Symbol.prototype.highlight = function () { + enterEmphasis(this.childAt(0)); + }; + /** + * Downplay symbol + */ + + + Symbol.prototype.downplay = function () { + leaveEmphasis(this.childAt(0)); + }; + /** + * @param {number} zlevel + * @param {number} z + */ + + + Symbol.prototype.setZ = function (zlevel, z) { + var symbolPath = this.childAt(0); + symbolPath.zlevel = zlevel; + symbolPath.z = z; + }; + + Symbol.prototype.setDraggable = function (draggable, hasCursorOption) { + var symbolPath = this.childAt(0); + symbolPath.draggable = draggable; + symbolPath.cursor = !hasCursorOption && draggable ? 'move' : symbolPath.cursor; + }; + /** + * Update symbol properties + */ + + + Symbol.prototype.updateData = function (data, idx, seriesScope, opts) { + this.silent = false; + var symbolType = data.getItemVisual(idx, 'symbol') || 'circle'; + var seriesModel = data.hostModel; + var symbolSize = Symbol.getSymbolSize(data, idx); + var z2 = Symbol.getSymbolZ2(data, idx); + var isInit = symbolType !== this._symbolType; + var disableAnimation = opts && opts.disableAnimation; + + if (isInit) { + var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect'); + + this._createSymbol(symbolType, data, idx, symbolSize, z2, keepAspect); + } else { + var symbolPath = this.childAt(0); + symbolPath.silent = false; + var target = { + scaleX: symbolSize[0] / 2, + scaleY: symbolSize[1] / 2 + }; + disableAnimation ? symbolPath.attr(target) : updateProps$1(symbolPath, target, seriesModel, idx); + saveOldStyle(symbolPath); + } + + this._updateCommon(data, idx, symbolSize, seriesScope, opts); + + if (isInit) { + var symbolPath = this.childAt(0); + + if (!disableAnimation) { + var target = { + scaleX: this._sizeX, + scaleY: this._sizeY, + style: { + // Always fadeIn. Because it has fadeOut animation when symbol is removed.. + opacity: symbolPath.style.opacity + } + }; + symbolPath.scaleX = symbolPath.scaleY = 0; + symbolPath.style.opacity = 0; + initProps(symbolPath, target, seriesModel, idx); + } + } + + if (disableAnimation) { + // Must stop leave transition manually if don't call initProps or updateProps. + this.childAt(0).stopAnimation('leave'); + } + }; + + Symbol.prototype._updateCommon = function (data, idx, symbolSize, seriesScope, opts) { + var symbolPath = this.childAt(0); + var seriesModel = data.hostModel; + var emphasisItemStyle; + var blurItemStyle; + var selectItemStyle; + var focus; + var blurScope; + var emphasisDisabled; + var labelStatesModels; + var hoverScale; + var cursorStyle; + + if (seriesScope) { + emphasisItemStyle = seriesScope.emphasisItemStyle; + blurItemStyle = seriesScope.blurItemStyle; + selectItemStyle = seriesScope.selectItemStyle; + focus = seriesScope.focus; + blurScope = seriesScope.blurScope; + labelStatesModels = seriesScope.labelStatesModels; + hoverScale = seriesScope.hoverScale; + cursorStyle = seriesScope.cursorStyle; + emphasisDisabled = seriesScope.emphasisDisabled; + } + + if (!seriesScope || data.hasItemOption) { + var itemModel = seriesScope && seriesScope.itemModel ? seriesScope.itemModel : data.getItemModel(idx); + var emphasisModel = itemModel.getModel('emphasis'); + emphasisItemStyle = emphasisModel.getModel('itemStyle').getItemStyle(); + selectItemStyle = itemModel.getModel(['select', 'itemStyle']).getItemStyle(); + blurItemStyle = itemModel.getModel(['blur', 'itemStyle']).getItemStyle(); + focus = emphasisModel.get('focus'); + blurScope = emphasisModel.get('blurScope'); + emphasisDisabled = emphasisModel.get('disabled'); + labelStatesModels = getLabelStatesModels(itemModel); + hoverScale = emphasisModel.getShallow('scale'); + cursorStyle = itemModel.getShallow('cursor'); + } + + var symbolRotate = data.getItemVisual(idx, 'symbolRotate'); + symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0); + var symbolOffset = normalizeSymbolOffset(data.getItemVisual(idx, 'symbolOffset'), symbolSize); + + if (symbolOffset) { + symbolPath.x = symbolOffset[0]; + symbolPath.y = symbolOffset[1]; + } + + cursorStyle && symbolPath.attr('cursor', cursorStyle); + var symbolStyle = data.getItemVisual(idx, 'style'); + var visualColor = symbolStyle.fill; + + if (symbolPath instanceof ZRImage) { + var pathStyle = symbolPath.style; + symbolPath.useStyle(extend({ + // TODO other properties like x, y ? + image: pathStyle.image, + x: pathStyle.x, + y: pathStyle.y, + width: pathStyle.width, + height: pathStyle.height + }, symbolStyle)); + } else { + if (symbolPath.__isEmptyBrush) { + // fill and stroke will be swapped if it's empty. + // So we cloned a new style to avoid it affecting the original style in visual storage. + // TODO Better implementation. No empty logic! + symbolPath.useStyle(extend({}, symbolStyle)); + } else { + symbolPath.useStyle(symbolStyle); + } // Disable decal because symbol scale will been applied on the decal. + + + symbolPath.style.decal = null; + symbolPath.setColor(visualColor, opts && opts.symbolInnerColor); + symbolPath.style.strokeNoScale = true; + } + + var liftZ = data.getItemVisual(idx, 'liftZ'); + var z2Origin = this._z2; + + if (liftZ != null) { + if (z2Origin == null) { + this._z2 = symbolPath.z2; + symbolPath.z2 += liftZ; + } + } else if (z2Origin != null) { + symbolPath.z2 = z2Origin; + this._z2 = null; + } + + var useNameLabel = opts && opts.useNameLabel; + setLabelStyle(symbolPath, labelStatesModels, { + labelFetcher: seriesModel, + labelDataIndex: idx, + defaultText: getLabelDefaultText, + inheritColor: visualColor, + defaultOpacity: symbolStyle.opacity + }); // Do not execute util needed. + + function getLabelDefaultText(idx) { + return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx); + } + + this._sizeX = symbolSize[0] / 2; + this._sizeY = symbolSize[1] / 2; + var emphasisState = symbolPath.ensureState('emphasis'); + emphasisState.style = emphasisItemStyle; + symbolPath.ensureState('select').style = selectItemStyle; + symbolPath.ensureState('blur').style = blurItemStyle; // null / undefined / true means to use default strategy. + // 0 / false / negative number / NaN / Infinity means no scale. + + var scaleRatio = hoverScale == null || hoverScale === true ? Math.max(1.1, 3 / this._sizeY) // PENDING: restrict hoverScale > 1? It seems unreasonable to scale down + : isFinite(hoverScale) && hoverScale > 0 ? +hoverScale : 1; // always set scale to allow resetting + + emphasisState.scaleX = this._sizeX * scaleRatio; + emphasisState.scaleY = this._sizeY * scaleRatio; + this.setSymbolScale(1); + toggleHoverEmphasis(this, focus, blurScope, emphasisDisabled); + }; + + Symbol.prototype.setSymbolScale = function (scale) { + this.scaleX = this.scaleY = scale; + }; + + Symbol.prototype.fadeOut = function (cb, seriesModel, opt) { + var symbolPath = this.childAt(0); + var dataIndex = getECData(this).dataIndex; + var animationOpt = opt && opt.animation; // Avoid mistaken hover when fading out + + this.silent = symbolPath.silent = true; // Not show text when animating + + if (opt && opt.fadeLabel) { + var textContent = symbolPath.getTextContent(); + + if (textContent) { + removeElement(textContent, { + style: { + opacity: 0 + } + }, seriesModel, { + dataIndex: dataIndex, + removeOpt: animationOpt, + cb: function () { + symbolPath.removeTextContent(); + } + }); + } + } else { + symbolPath.removeTextContent(); + } + + removeElement(symbolPath, { + style: { + opacity: 0 + }, + scaleX: 0, + scaleY: 0 + }, seriesModel, { + dataIndex: dataIndex, + cb: cb, + removeOpt: animationOpt + }); + }; + + Symbol.getSymbolSize = function (data, idx) { + return normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize')); + }; + + Symbol.getSymbolZ2 = function (data, idx) { + return data.getItemVisual(idx, 'z2'); + }; + + return Symbol; + }(Group$2); + + function driftSymbol(dx, dy) { + this.parent.drift(dx, dy); + } + + function symbolNeedsDraw(data, point, idx, opt) { + return point && !isNaN(point[0]) && !isNaN(point[1]) && !(opt.isIgnore && opt.isIgnore(idx)) // We do not set clipShape on group, because it will cut part of + // the symbol element shape. We use the same clip shape here as + // the line clip. + && !(opt.clipShape && !opt.clipShape.contain(point[0], point[1])) && data.getItemVisual(idx, 'symbol') !== 'none'; + } + + function normalizeUpdateOpt(opt) { + if (opt != null && !isObject$2(opt)) { + opt = { + isIgnore: opt + }; + } + + return opt || {}; + } + + function makeSeriesScope(data) { + var seriesModel = data.hostModel; + var emphasisModel = seriesModel.getModel('emphasis'); + return { + emphasisItemStyle: emphasisModel.getModel('itemStyle').getItemStyle(), + blurItemStyle: seriesModel.getModel(['blur', 'itemStyle']).getItemStyle(), + selectItemStyle: seriesModel.getModel(['select', 'itemStyle']).getItemStyle(), + focus: emphasisModel.get('focus'), + blurScope: emphasisModel.get('blurScope'), + emphasisDisabled: emphasisModel.get('disabled'), + hoverScale: emphasisModel.get('scale'), + labelStatesModels: getLabelStatesModels(seriesModel), + cursorStyle: seriesModel.get('cursor') + }; + } + + var SymbolDraw = + /** @class */ + function () { + function SymbolDraw(SymbolCtor) { + this.group = new Group$2(); + this._SymbolCtor = SymbolCtor || Symbol; + } + /** + * Update symbols draw by new data + */ + + + SymbolDraw.prototype.updateData = function (data, opt) { + // Remove progressive els. + this._progressiveEls = null; + opt = normalizeUpdateOpt(opt); + var group = this.group; + var seriesModel = data.hostModel; + var oldData = this._data; + var SymbolCtor = this._SymbolCtor; + var disableAnimation = opt.disableAnimation; + var seriesScope = makeSeriesScope(data); + var symbolUpdateOpt = { + disableAnimation: disableAnimation + }; + + var getSymbolPoint = opt.getSymbolPoint || function (idx) { + return data.getItemLayout(idx); + }; // There is no oldLineData only when first rendering or switching from + // stream mode to normal mode, where previous elements should be removed. + + + if (!oldData) { + group.removeAll(); + } + + data.diff(oldData).add(function (newIdx) { + var point = getSymbolPoint(newIdx); + + if (symbolNeedsDraw(data, point, newIdx, opt)) { + var symbolEl = new SymbolCtor(data, newIdx, seriesScope, symbolUpdateOpt); + symbolEl.setPosition(point); + data.setItemGraphicEl(newIdx, symbolEl); + group.add(symbolEl); + } + }).update(function (newIdx, oldIdx) { + var symbolEl = oldData.getItemGraphicEl(oldIdx); + var point = getSymbolPoint(newIdx); + + if (!symbolNeedsDraw(data, point, newIdx, opt)) { + group.remove(symbolEl); + return; + } + + var newSymbolType = data.getItemVisual(newIdx, 'symbol') || 'circle'; + var oldSymbolType = symbolEl && symbolEl.getSymbolType && symbolEl.getSymbolType(); + + if (!symbolEl // Create a new if symbol type changed. + || oldSymbolType && oldSymbolType !== newSymbolType) { + group.remove(symbolEl); + symbolEl = new SymbolCtor(data, newIdx, seriesScope, symbolUpdateOpt); + symbolEl.setPosition(point); + } else { + symbolEl.updateData(data, newIdx, seriesScope, symbolUpdateOpt); + var target = { + x: point[0], + y: point[1] + }; + disableAnimation ? symbolEl.attr(target) : updateProps$1(symbolEl, target, seriesModel); + } // Add back + + + group.add(symbolEl); + data.setItemGraphicEl(newIdx, symbolEl); + }).remove(function (oldIdx) { + var el = oldData.getItemGraphicEl(oldIdx); + el && el.fadeOut(function () { + group.remove(el); + }, seriesModel); + }).execute(); + this._getSymbolPoint = getSymbolPoint; + this._data = data; + }; + + SymbolDraw.prototype.updateLayout = function () { + var _this = this; + + var data = this._data; + + if (data) { + // Not use animation + data.eachItemGraphicEl(function (el, idx) { + var point = _this._getSymbolPoint(idx); + + el.setPosition(point); + el.markRedraw(); + }); + } + }; + + SymbolDraw.prototype.incrementalPrepareUpdate = function (data) { + this._seriesScope = makeSeriesScope(data); + this._data = null; + this.group.removeAll(); + }; + /** + * Update symbols draw by new data + */ + + + SymbolDraw.prototype.incrementalUpdate = function (taskParams, data, opt) { + // Clear + this._progressiveEls = []; + opt = normalizeUpdateOpt(opt); + + function updateIncrementalAndHover(el) { + if (!el.isGroup) { + el.incremental = true; + el.ensureState('emphasis').hoverLayer = true; + } + } + + for (var idx = taskParams.start; idx < taskParams.end; idx++) { + var point = data.getItemLayout(idx); + + if (symbolNeedsDraw(data, point, idx, opt)) { + var el = new this._SymbolCtor(data, idx, this._seriesScope); + el.traverse(updateIncrementalAndHover); + el.setPosition(point); + this.group.add(el); + data.setItemGraphicEl(idx, el); + + this._progressiveEls.push(el); + } + } + }; + + SymbolDraw.prototype.eachRendered = function (cb) { + traverseElements(this._progressiveEls || this.group, cb); + }; + + SymbolDraw.prototype.remove = function (enableAnimation) { + var group = this.group; + var data = this._data; // Incremental model do not have this._data. + + if (data && enableAnimation) { + data.eachItemGraphicEl(function (el) { + el.fadeOut(function () { + group.remove(el); + }, data.hostModel); + }); + } else { + group.removeAll(); + } + }; + + return SymbolDraw; + }(); + + function prepareDataCoordInfo(coordSys, data, valueOrigin) { + var baseAxis = coordSys.getBaseAxis(); + var valueAxis = coordSys.getOtherAxis(baseAxis); + var valueStart = getValueStart(valueAxis, valueOrigin); + var baseAxisDim = baseAxis.dim; + var valueAxisDim = valueAxis.dim; + var valueDim = data.mapDimension(valueAxisDim); + var baseDim = data.mapDimension(baseAxisDim); + var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0; + var dims = map$1(coordSys.dimensions, function (coordDim) { + return data.mapDimension(coordDim); + }); + var stacked = false; + var stackResultDim = data.getCalculationInfo('stackResultDimension'); + + if (isDimensionStacked(data, dims[0] + /* , dims[1] */ + )) { + // jshint ignore:line + stacked = true; + dims[0] = stackResultDim; + } + + if (isDimensionStacked(data, dims[1] + /* , dims[0] */ + )) { + // jshint ignore:line + stacked = true; + dims[1] = stackResultDim; + } + + return { + dataDimsForPoint: dims, + valueStart: valueStart, + valueAxisDim: valueAxisDim, + baseAxisDim: baseAxisDim, + stacked: !!stacked, + valueDim: valueDim, + baseDim: baseDim, + baseDataOffset: baseDataOffset, + stackedOverDimension: data.getCalculationInfo('stackedOverDimension') + }; + } + + function getValueStart(valueAxis, valueOrigin) { + var valueStart = 0; + var extent = valueAxis.scale.getExtent(); + + if (valueOrigin === 'start') { + valueStart = extent[0]; + } else if (valueOrigin === 'end') { + valueStart = extent[1]; + } // If origin is specified as a number, use it as + // valueStart directly + else if (isNumber(valueOrigin) && !isNaN(valueOrigin)) { + valueStart = valueOrigin; + } // auto + else { + // Both positive + if (extent[0] > 0) { + valueStart = extent[0]; + } // Both negative + else if (extent[1] < 0) { + valueStart = extent[1]; + } // If is one positive, and one negative, onZero shall be true + + } + + return valueStart; + } + + function getStackedOnPoint(dataCoordInfo, coordSys, data, idx) { + var value = NaN; + + if (dataCoordInfo.stacked) { + value = data.get(data.getCalculationInfo('stackedOverDimension'), idx); + } + + if (isNaN(value)) { + value = dataCoordInfo.valueStart; + } + + var baseDataOffset = dataCoordInfo.baseDataOffset; + var stackedData = []; + stackedData[baseDataOffset] = data.get(dataCoordInfo.baseDim, idx); + stackedData[1 - baseDataOffset] = value; + return coordSys.dataToPoint(stackedData); + } + + function diffData(oldData, newData) { + var diffResult = []; + newData.diff(oldData).add(function (idx) { + diffResult.push({ + cmd: '+', + idx: idx + }); + }).update(function (newIdx, oldIdx) { + diffResult.push({ + cmd: '=', + idx: oldIdx, + idx1: newIdx + }); + }).remove(function (idx) { + diffResult.push({ + cmd: '-', + idx: idx + }); + }).execute(); + return diffResult; + } + + function lineAnimationDiff(oldData, newData, oldStackedOnPoints, newStackedOnPoints, oldCoordSys, newCoordSys, oldValueOrigin, newValueOrigin) { + var diff = diffData(oldData, newData); // let newIdList = newData.mapArray(newData.getId); + // let oldIdList = oldData.mapArray(oldData.getId); + // convertToIntId(newIdList, oldIdList); + // // FIXME One data ? + // diff = arrayDiff(oldIdList, newIdList); + + var currPoints = []; + var nextPoints = []; // Points for stacking base line + + var currStackedPoints = []; + var nextStackedPoints = []; + var status = []; + var sortedIndices = []; + var rawIndices = []; + var newDataOldCoordInfo = prepareDataCoordInfo(oldCoordSys, newData, oldValueOrigin); // const oldDataNewCoordInfo = prepareDataCoordInfo(newCoordSys, oldData, newValueOrigin); + + var oldPoints = oldData.getLayout('points') || []; + var newPoints = newData.getLayout('points') || []; + + for (var i = 0; i < diff.length; i++) { + var diffItem = diff[i]; + var pointAdded = true; + var oldIdx2 = void 0; + var newIdx2 = void 0; // FIXME, animation is not so perfect when dataZoom window moves fast + // Which is in case remvoing or add more than one data in the tail or head + + switch (diffItem.cmd) { + case '=': + oldIdx2 = diffItem.idx * 2; + newIdx2 = diffItem.idx1 * 2; + var currentX = oldPoints[oldIdx2]; + var currentY = oldPoints[oldIdx2 + 1]; + var nextX = newPoints[newIdx2]; + var nextY = newPoints[newIdx2 + 1]; // If previous data is NaN, use next point directly + + if (isNaN(currentX) || isNaN(currentY)) { + currentX = nextX; + currentY = nextY; + } + + currPoints.push(currentX, currentY); + nextPoints.push(nextX, nextY); + currStackedPoints.push(oldStackedOnPoints[oldIdx2], oldStackedOnPoints[oldIdx2 + 1]); + nextStackedPoints.push(newStackedOnPoints[newIdx2], newStackedOnPoints[newIdx2 + 1]); + rawIndices.push(newData.getRawIndex(diffItem.idx1)); + break; + + case '+': + var newIdx = diffItem.idx; + var newDataDimsForPoint = newDataOldCoordInfo.dataDimsForPoint; + var oldPt = oldCoordSys.dataToPoint([newData.get(newDataDimsForPoint[0], newIdx), newData.get(newDataDimsForPoint[1], newIdx)]); + newIdx2 = newIdx * 2; + currPoints.push(oldPt[0], oldPt[1]); + nextPoints.push(newPoints[newIdx2], newPoints[newIdx2 + 1]); + var stackedOnPoint = getStackedOnPoint(newDataOldCoordInfo, oldCoordSys, newData, newIdx); + currStackedPoints.push(stackedOnPoint[0], stackedOnPoint[1]); + nextStackedPoints.push(newStackedOnPoints[newIdx2], newStackedOnPoints[newIdx2 + 1]); + rawIndices.push(newData.getRawIndex(newIdx)); + break; + + case '-': + pointAdded = false; + } // Original indices + + + if (pointAdded) { + status.push(diffItem); + sortedIndices.push(sortedIndices.length); + } + } // Diff result may be crossed if all items are changed + // Sort by data index + + + sortedIndices.sort(function (a, b) { + return rawIndices[a] - rawIndices[b]; + }); + var len = currPoints.length; + var sortedCurrPoints = createFloat32Array(len); + var sortedNextPoints = createFloat32Array(len); + var sortedCurrStackedPoints = createFloat32Array(len); + var sortedNextStackedPoints = createFloat32Array(len); + var sortedStatus = []; + + for (var i = 0; i < sortedIndices.length; i++) { + var idx = sortedIndices[i]; + var i2 = i * 2; + var idx2 = idx * 2; + sortedCurrPoints[i2] = currPoints[idx2]; + sortedCurrPoints[i2 + 1] = currPoints[idx2 + 1]; + sortedNextPoints[i2] = nextPoints[idx2]; + sortedNextPoints[i2 + 1] = nextPoints[idx2 + 1]; + sortedCurrStackedPoints[i2] = currStackedPoints[idx2]; + sortedCurrStackedPoints[i2 + 1] = currStackedPoints[idx2 + 1]; + sortedNextStackedPoints[i2] = nextStackedPoints[idx2]; + sortedNextStackedPoints[i2 + 1] = nextStackedPoints[idx2 + 1]; + sortedStatus[i] = status[idx]; + } + + return { + current: sortedCurrPoints, + next: sortedNextPoints, + stackedOnCurrent: sortedCurrStackedPoints, + stackedOnNext: sortedNextStackedPoints, + status: sortedStatus + }; + } + + var mathMin = Math.min; + var mathMax = Math.max; + + function isPointNull$1(x, y) { + return isNaN(x) || isNaN(y); + } + /** + * Draw smoothed line in non-monotone, in may cause undesired curve in extreme + * situations. This should be used when points are non-monotone neither in x or + * y dimension. + */ + + + function drawSegment(ctx, points, start, segLen, allLen, dir, smooth, smoothMonotone, connectNulls) { + var prevX; + var prevY; + var cpx0; + var cpy0; + var cpx1; + var cpy1; + var idx = start; + var k = 0; + + for (; k < segLen; k++) { + var x = points[idx * 2]; + var y = points[idx * 2 + 1]; + + if (idx >= allLen || idx < 0) { + break; + } + + if (isPointNull$1(x, y)) { + if (connectNulls) { + idx += dir; + continue; + } + + break; + } + + if (idx === start) { + ctx[dir > 0 ? 'moveTo' : 'lineTo'](x, y); + cpx0 = x; + cpy0 = y; + } else { + var dx = x - prevX; + var dy = y - prevY; // Ignore tiny segment. + + if (dx * dx + dy * dy < 0.5) { + idx += dir; + continue; + } + + if (smooth > 0) { + var nextIdx = idx + dir; + var nextX = points[nextIdx * 2]; + var nextY = points[nextIdx * 2 + 1]; // Ignore duplicate point + + while (nextX === x && nextY === y && k < segLen) { + k++; + nextIdx += dir; + idx += dir; + nextX = points[nextIdx * 2]; + nextY = points[nextIdx * 2 + 1]; + x = points[idx * 2]; + y = points[idx * 2 + 1]; + dx = x - prevX; + dy = y - prevY; + } + + var tmpK = k + 1; + + if (connectNulls) { + // Find next point not null + while (isPointNull$1(nextX, nextY) && tmpK < segLen) { + tmpK++; + nextIdx += dir; + nextX = points[nextIdx * 2]; + nextY = points[nextIdx * 2 + 1]; + } + } + + var ratioNextSeg = 0.5; + var vx = 0; + var vy = 0; + var nextCpx0 = void 0; + var nextCpy0 = void 0; // Is last point + + if (tmpK >= segLen || isPointNull$1(nextX, nextY)) { + cpx1 = x; + cpy1 = y; + } else { + vx = nextX - prevX; + vy = nextY - prevY; + var dx0 = x - prevX; + var dx1 = nextX - x; + var dy0 = y - prevY; + var dy1 = nextY - y; + var lenPrevSeg = void 0; + var lenNextSeg = void 0; + + if (smoothMonotone === 'x') { + lenPrevSeg = Math.abs(dx0); + lenNextSeg = Math.abs(dx1); + var dir_1 = vx > 0 ? 1 : -1; + cpx1 = x - dir_1 * lenPrevSeg * smooth; + cpy1 = y; + nextCpx0 = x + dir_1 * lenNextSeg * smooth; + nextCpy0 = y; + } else if (smoothMonotone === 'y') { + lenPrevSeg = Math.abs(dy0); + lenNextSeg = Math.abs(dy1); + var dir_2 = vy > 0 ? 1 : -1; + cpx1 = x; + cpy1 = y - dir_2 * lenPrevSeg * smooth; + nextCpx0 = x; + nextCpy0 = y + dir_2 * lenNextSeg * smooth; + } else { + lenPrevSeg = Math.sqrt(dx0 * dx0 + dy0 * dy0); + lenNextSeg = Math.sqrt(dx1 * dx1 + dy1 * dy1); // Use ratio of seg length + + ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg); + cpx1 = x - vx * smooth * (1 - ratioNextSeg); + cpy1 = y - vy * smooth * (1 - ratioNextSeg); // cp0 of next segment + + nextCpx0 = x + vx * smooth * ratioNextSeg; + nextCpy0 = y + vy * smooth * ratioNextSeg; // Smooth constraint between point and next point. + // Avoid exceeding extreme after smoothing. + + nextCpx0 = mathMin(nextCpx0, mathMax(nextX, x)); + nextCpy0 = mathMin(nextCpy0, mathMax(nextY, y)); + nextCpx0 = mathMax(nextCpx0, mathMin(nextX, x)); + nextCpy0 = mathMax(nextCpy0, mathMin(nextY, y)); // Reclaculate cp1 based on the adjusted cp0 of next seg. + + vx = nextCpx0 - x; + vy = nextCpy0 - y; + cpx1 = x - vx * lenPrevSeg / lenNextSeg; + cpy1 = y - vy * lenPrevSeg / lenNextSeg; // Smooth constraint between point and prev point. + // Avoid exceeding extreme after smoothing. + + cpx1 = mathMin(cpx1, mathMax(prevX, x)); + cpy1 = mathMin(cpy1, mathMax(prevY, y)); + cpx1 = mathMax(cpx1, mathMin(prevX, x)); + cpy1 = mathMax(cpy1, mathMin(prevY, y)); // Adjust next cp0 again. + + vx = x - cpx1; + vy = y - cpy1; + nextCpx0 = x + vx * lenNextSeg / lenPrevSeg; + nextCpy0 = y + vy * lenNextSeg / lenPrevSeg; + } + } + + ctx.bezierCurveTo(cpx0, cpy0, cpx1, cpy1, x, y); + cpx0 = nextCpx0; + cpy0 = nextCpy0; + } else { + ctx.lineTo(x, y); + } + } + + prevX = x; + prevY = y; + idx += dir; + } + + return k; + } + + var ECPolylineShape = + /** @class */ + function () { + function ECPolylineShape() { + this.smooth = 0; + this.smoothConstraint = true; + } + + return ECPolylineShape; + }(); + + var ECPolyline = + /** @class */ + function (_super) { + __extends(ECPolyline, _super); + + function ECPolyline(opts) { + var _this = _super.call(this, opts) || this; + + _this.type = 'ec-polyline'; + return _this; + } + + ECPolyline.prototype.getDefaultStyle = function () { + return { + stroke: tokens.color.neutral99, + fill: null + }; + }; + + ECPolyline.prototype.getDefaultShape = function () { + return new ECPolylineShape(); + }; + + ECPolyline.prototype.buildPath = function (ctx, shape) { + var points = shape.points; + var i = 0; + var len = points.length / 2; // const result = getBoundingBox(points, shape.smoothConstraint); + + if (shape.connectNulls) { + // Must remove first and last null values avoid draw error in polygon + for (; len > 0; len--) { + if (!isPointNull$1(points[len * 2 - 2], points[len * 2 - 1])) { + break; + } + } + + for (; i < len; i++) { + if (!isPointNull$1(points[i * 2], points[i * 2 + 1])) { + break; + } + } + } + + while (i < len) { + i += drawSegment(ctx, points, i, len, len, 1, shape.smooth, shape.smoothMonotone, shape.connectNulls) + 1; + } + }; + + ECPolyline.prototype.getPointOn = function (xOrY, dim) { + if (!this.path) { + this.createPathProxy(); + this.buildPath(this.path, this.shape); + } + + var path = this.path; + var data = path.data; + var CMD = PathProxy.CMD; + var x0; + var y0; + var isDimX = dim === 'x'; + var roots = []; + + for (var i = 0; i < data.length;) { + var cmd = data[i++]; + var x = void 0; + var y = void 0; + var x2 = void 0; + var y2 = void 0; + var x3 = void 0; + var y3 = void 0; + var t = void 0; + + switch (cmd) { + case CMD.M: + x0 = data[i++]; + y0 = data[i++]; + break; + + case CMD.L: + x = data[i++]; + y = data[i++]; + t = isDimX ? (xOrY - x0) / (x - x0) : (xOrY - y0) / (y - y0); + + if (t <= 1 && t >= 0) { + var val = isDimX ? (y - y0) * t + y0 : (x - x0) * t + x0; + return isDimX ? [xOrY, val] : [val, xOrY]; + } + + x0 = x; + y0 = y; + break; + + case CMD.C: + x = data[i++]; + y = data[i++]; + x2 = data[i++]; + y2 = data[i++]; + x3 = data[i++]; + y3 = data[i++]; + var nRoot = isDimX ? cubicRootAt(x0, x, x2, x3, xOrY, roots) : cubicRootAt(y0, y, y2, y3, xOrY, roots); + + if (nRoot > 0) { + for (var i_1 = 0; i_1 < nRoot; i_1++) { + var t_1 = roots[i_1]; + + if (t_1 <= 1 && t_1 >= 0) { + var val = isDimX ? cubicAt(y0, y, y2, y3, t_1) : cubicAt(x0, x, x2, x3, t_1); + return isDimX ? [xOrY, val] : [val, xOrY]; + } + } + } + + x0 = x3; + y0 = y3; + break; + } + } + }; + + return ECPolyline; + }(Path); + + var ECPolygonShape = + /** @class */ + function (_super) { + __extends(ECPolygonShape, _super); + + function ECPolygonShape() { + return _super !== null && _super.apply(this, arguments) || this; + } + + return ECPolygonShape; + }(ECPolylineShape); + + var ECPolygon = + /** @class */ + function (_super) { + __extends(ECPolygon, _super); + + function ECPolygon(opts) { + var _this = _super.call(this, opts) || this; + + _this.type = 'ec-polygon'; + return _this; + } + + ECPolygon.prototype.getDefaultShape = function () { + return new ECPolygonShape(); + }; + + ECPolygon.prototype.buildPath = function (ctx, shape) { + var points = shape.points; + var stackedOnPoints = shape.stackedOnPoints; + var i = 0; + var len = points.length / 2; + var smoothMonotone = shape.smoothMonotone; + + if (shape.connectNulls) { + // Must remove first and last null values avoid draw error in polygon + for (; len > 0; len--) { + if (!isPointNull$1(points[len * 2 - 2], points[len * 2 - 1])) { + break; + } + } + + for (; i < len; i++) { + if (!isPointNull$1(points[i * 2], points[i * 2 + 1])) { + break; + } + } + } + + while (i < len) { + var k = drawSegment(ctx, points, i, len, len, 1, shape.smooth, smoothMonotone, shape.connectNulls); + drawSegment(ctx, stackedOnPoints, i + k - 1, k, len, -1, shape.stackedOnSmooth, smoothMonotone, shape.connectNulls); + i += k + 1; + ctx.closePath(); + } + }; + + return ECPolygon; + }(Path); + + function isPointsSame(points1, points2) { + if (points1.length !== points2.length) { + return; + } + + for (var i = 0; i < points1.length; i++) { + if (points1[i] !== points2[i]) { + return; + } + } + + return true; + } + + function bboxFromPoints(points) { + var minX = Infinity; + var minY = Infinity; + var maxX = -Infinity; + var maxY = -Infinity; + + for (var i = 0; i < points.length;) { + var x = points[i++]; + var y = points[i++]; + + if (!isNaN(x)) { + minX = Math.min(x, minX); + maxX = Math.max(x, maxX); + } + + if (!isNaN(y)) { + minY = Math.min(y, minY); + maxY = Math.max(y, maxY); + } + } + + return [[minX, minY], [maxX, maxY]]; + } + + function getBoundingDiff(points1, points2) { + var _a = bboxFromPoints(points1), + min1 = _a[0], + max1 = _a[1]; + + var _b = bboxFromPoints(points2), + min2 = _b[0], + max2 = _b[1]; // Get a max value from each corner of two boundings. + + + return Math.max(Math.abs(min1[0] - min2[0]), Math.abs(min1[1] - min2[1]), Math.abs(max1[0] - max2[0]), Math.abs(max1[1] - max2[1])); + } + + function getSmooth(smooth) { + return isNumber(smooth) ? smooth : smooth ? 0.5 : 0; + } + + function getStackedOnPoints(coordSys, data, dataCoordInfo) { + if (!dataCoordInfo.valueDim) { + return []; + } + + var len = data.count(); + var points = createFloat32Array(len * 2); + + for (var idx = 0; idx < len; idx++) { + var pt = getStackedOnPoint(dataCoordInfo, coordSys, data, idx); + points[idx * 2] = pt[0]; + points[idx * 2 + 1] = pt[1]; + } + + return points; + } + /** + * Filter the null data and extend data for step considering `stepTurnAt` + * + * @param points data to convert, that may containing null + * @param basePoints base data to reference, used only for areaStyle points + * @param coordSys coordinate system + * @param stepTurnAt 'start' | 'end' | 'middle' | true + * @param connectNulls whether to connect nulls + * @returns converted point positions + */ + + + function turnPointsIntoStep(points, basePoints, coordSys, stepTurnAt, connectNulls) { + var baseAxis = coordSys.getBaseAxis(); + var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1; + var stepPoints = []; + var i = 0; + var stepPt = []; + var pt = []; + var nextPt = []; + var filteredPoints = []; + + if (connectNulls) { + for (i = 0; i < points.length; i += 2) { + /** + * For areaStyle of stepped lines, `stackedOnPoints` should be + * filtered the same as `points` so that the base axis values + * should stay the same as the lines above. See #20021 + */ + var reference = basePoints || points; + + if (!isNaN(reference[i]) && !isNaN(reference[i + 1])) { + filteredPoints.push(points[i], points[i + 1]); + } + } + + points = filteredPoints; + } + + for (i = 0; i < points.length - 2; i += 2) { + nextPt[0] = points[i + 2]; + nextPt[1] = points[i + 3]; + pt[0] = points[i]; + pt[1] = points[i + 1]; + stepPoints.push(pt[0], pt[1]); + + switch (stepTurnAt) { + case 'end': + stepPt[baseIndex] = nextPt[baseIndex]; + stepPt[1 - baseIndex] = pt[1 - baseIndex]; + stepPoints.push(stepPt[0], stepPt[1]); + break; + + case 'middle': + var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2; + var stepPt2 = []; + stepPt[baseIndex] = stepPt2[baseIndex] = middle; + stepPt[1 - baseIndex] = pt[1 - baseIndex]; + stepPt2[1 - baseIndex] = nextPt[1 - baseIndex]; + stepPoints.push(stepPt[0], stepPt[1]); + stepPoints.push(stepPt2[0], stepPt2[1]); + break; + + default: + // default is start + stepPt[baseIndex] = pt[baseIndex]; + stepPt[1 - baseIndex] = nextPt[1 - baseIndex]; + stepPoints.push(stepPt[0], stepPt[1]); + } + } // Last points + + + stepPoints.push(points[i++], points[i++]); + return stepPoints; + } + /** + * Clip color stops to edge. Avoid creating too large gradients. + * Which may lead to blurry when GPU acceleration is enabled. See #15680 + * + * The stops has been sorted from small to large. + */ + + + function clipColorStops(colorStops, maxSize) { + var newColorStops = []; + var len = colorStops.length; // coord will always < 0 in prevOutOfRangeColorStop. + + var prevOutOfRangeColorStop; + var prevInRangeColorStop; + + function lerpStop(stop0, stop1, clippedCoord) { + var coord0 = stop0.coord; + var p = (clippedCoord - coord0) / (stop1.coord - coord0); + var color = lerp(p, [stop0.color, stop1.color]); + return { + coord: clippedCoord, + color: color + }; + } + + for (var i = 0; i < len; i++) { + var stop_1 = colorStops[i]; + var coord = stop_1.coord; + + if (coord < 0) { + prevOutOfRangeColorStop = stop_1; + } else if (coord > maxSize) { + if (prevInRangeColorStop) { + newColorStops.push(lerpStop(prevInRangeColorStop, stop_1, maxSize)); + } else if (prevOutOfRangeColorStop) { + // If there are two stops and coord range is between these two stops + newColorStops.push(lerpStop(prevOutOfRangeColorStop, stop_1, 0), lerpStop(prevOutOfRangeColorStop, stop_1, maxSize)); + } // All following stop will be out of range. So just ignore them. + + + break; + } else { + if (prevOutOfRangeColorStop) { + newColorStops.push(lerpStop(prevOutOfRangeColorStop, stop_1, 0)); // Reset + + prevOutOfRangeColorStop = null; + } + + newColorStops.push(stop_1); + prevInRangeColorStop = stop_1; + } + } + + return newColorStops; + } + + function getVisualGradient(data, coordSys, api) { + var visualMetaList = data.getVisual('visualMeta'); + + if (!visualMetaList || !visualMetaList.length || !data.count()) { + // When data.count() is 0, gradient range can not be calculated. + return; + } + + if (coordSys.type !== 'cartesian2d') { + { + console.warn('Visual map on line style is only supported on cartesian2d.'); + } + return; + } + + var coordDim; + var visualMeta; + + for (var i = visualMetaList.length - 1; i >= 0; i--) { + var dimInfo = data.getDimensionInfo(visualMetaList[i].dimension); + coordDim = dimInfo && dimInfo.coordDim; // Can only be x or y + + if (coordDim === 'x' || coordDim === 'y') { + visualMeta = visualMetaList[i]; + break; + } + } + + if (!visualMeta) { + { + console.warn('Visual map on line style only support x or y dimension.'); + } + return; + } // If the area to be rendered is bigger than area defined by LinearGradient, + // the canvas spec prescribes that the color of the first stop and the last + // stop should be used. But if two stops are added at offset 0, in effect + // browsers use the color of the second stop to render area outside + // LinearGradient. So we can only infinitesimally extend area defined in + // LinearGradient to render `outerColors`. + + + var axis = coordSys.getAxis(coordDim); // dataToCoord mapping may not be linear, but must be monotonic. + + var colorStops = map$1(visualMeta.stops, function (stop) { + // offset will be calculated later. + return { + coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)), + color: stop.color + }; + }); + var stopLen = colorStops.length; + var outerColors = visualMeta.outerColors.slice(); + + if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) { + colorStops.reverse(); + outerColors.reverse(); + } + + var colorStopsInRange = clipColorStops(colorStops, coordDim === 'x' ? api.getWidth() : api.getHeight()); + var inRangeStopLen = colorStopsInRange.length; + + if (!inRangeStopLen && stopLen) { + // All stops are out of range. All will be the same color. + return colorStops[0].coord < 0 ? outerColors[1] ? outerColors[1] : colorStops[stopLen - 1].color : outerColors[0] ? outerColors[0] : colorStops[0].color; + } + + var tinyExtent = 10; // Arbitrary value: 10px + + var minCoord = colorStopsInRange[0].coord - tinyExtent; + var maxCoord = colorStopsInRange[inRangeStopLen - 1].coord + tinyExtent; + var coordSpan = maxCoord - minCoord; + + if (coordSpan < 1e-3) { + return 'transparent'; + } + + each$4(colorStopsInRange, function (stop) { + stop.offset = (stop.coord - minCoord) / coordSpan; + }); + colorStopsInRange.push({ + // NOTE: inRangeStopLen may still be 0 if stoplen is zero. + offset: inRangeStopLen ? colorStopsInRange[inRangeStopLen - 1].offset : 0.5, + color: outerColors[1] || 'transparent' + }); + colorStopsInRange.unshift({ + offset: inRangeStopLen ? colorStopsInRange[0].offset : 0.5, + color: outerColors[0] || 'transparent' + }); + var gradient = new LinearGradient(0, 0, 0, 0, colorStopsInRange, true); + gradient[coordDim] = minCoord; + gradient[coordDim + '2'] = maxCoord; + return gradient; + } + + function getIsIgnoreFunc(seriesModel, data, coordSys) { + var showAllSymbol = seriesModel.get('showAllSymbol'); + var isAuto = showAllSymbol === 'auto'; + + if (showAllSymbol && !isAuto) { + return; + } + + var categoryAxis = coordSys.getAxesByScale('ordinal')[0]; + + if (!categoryAxis) { + return; + } // Note that category label interval strategy might bring some weird effect + // in some scenario: users may wonder why some of the symbols are not + // displayed. So we show all symbols as possible as we can. + + + if (isAuto // Simplify the logic, do not determine label overlap here. + && canShowAllSymbolForCategory(categoryAxis, data)) { + return; + } // Otherwise follow the label interval strategy on category axis. + + + var categoryDataDim = data.mapDimension(categoryAxis.dim); + var labelMap = {}; + each$4(categoryAxis.getViewLabels(), function (labelItem) { + var ordinalNumber = categoryAxis.scale.getRawOrdinalNumber(labelItem.tickValue); + labelMap[ordinalNumber] = 1; + }); + return function (dataIndex) { + return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex)); + }; + } + + function canShowAllSymbolForCategory(categoryAxis, data) { + // In most cases, line is monotonous on category axis, and the label size + // is close with each other. So we check the symbol size and some of the + // label size alone with the category axis to estimate whether all symbol + // can be shown without overlap. + var axisExtent = categoryAxis.getExtent(); + var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count(); + isNaN(availSize) && (availSize = 0); // 0/0 is NaN. + // Sampling some points, max 5. + + var dataLen = data.count(); + var step = Math.max(1, Math.round(dataLen / 5)); + + for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) { + if (Symbol.getSymbolSize(data, dataIndex // Only for cartesian, where `isHorizontal` exists. + )[categoryAxis.isHorizontal() ? 1 : 0] // Empirical number + * 1.5 > availSize) { + return false; + } + } + + return true; + } + + function isPointNull(x, y) { + return isNaN(x) || isNaN(y); + } + + function getLastIndexNotNull(points) { + var len = points.length / 2; + + for (; len > 0; len--) { + if (!isPointNull(points[len * 2 - 2], points[len * 2 - 1])) { + break; + } + } + + return len - 1; + } + + function getPointAtIndex(points, idx) { + return [points[idx * 2], points[idx * 2 + 1]]; + } + + function getIndexRange(points, xOrY, dim) { + var len = points.length / 2; + var dimIdx = dim === 'x' ? 0 : 1; + var a; + var b; + var prevIndex = 0; + var nextIndex = -1; + + for (var i = 0; i < len; i++) { + b = points[i * 2 + dimIdx]; + + if (isNaN(b) || isNaN(points[i * 2 + 1 - dimIdx])) { + continue; + } + + if (i === 0) { + a = b; + continue; + } + + if (a <= xOrY && b >= xOrY || a >= xOrY && b <= xOrY) { + nextIndex = i; + break; + } + + prevIndex = i; + a = b; + } + + return { + range: [prevIndex, nextIndex], + t: (xOrY - a) / (b - a) + }; + } + + function anyStateShowEndLabel(seriesModel) { + if (seriesModel.get(['endLabel', 'show'])) { + return true; + } + + for (var i = 0; i < SPECIAL_STATES.length; i++) { + if (seriesModel.get([SPECIAL_STATES[i], 'endLabel', 'show'])) { + return true; + } + } + + return false; + } + + function createLineClipPath(lineView, coordSys, hasAnimation, seriesModel) { + if (isCoordinateSystemType(coordSys, 'cartesian2d')) { + var endLabelModel_1 = seriesModel.getModel('endLabel'); + var valueAnimation_1 = endLabelModel_1.get('valueAnimation'); + var data_1 = seriesModel.getData(); + var labelAnimationRecord_1 = { + lastFrameIndex: 0 + }; + var during = anyStateShowEndLabel(seriesModel) ? function (percent, clipRect) { + lineView._endLabelOnDuring(percent, clipRect, data_1, labelAnimationRecord_1, valueAnimation_1, endLabelModel_1, coordSys); + } : null; + var isHorizontal = coordSys.getBaseAxis().isHorizontal(); + var clipPath = createGridClipPath(coordSys, hasAnimation, seriesModel, function () { + var endLabel = lineView._endLabel; + + if (endLabel && hasAnimation) { + if (labelAnimationRecord_1.originalX != null) { + endLabel.attr({ + x: labelAnimationRecord_1.originalX, + y: labelAnimationRecord_1.originalY + }); + } + } + }, during); // Expand clip shape to avoid clipping when line value exceeds axis + + if (!seriesModel.get('clip', true)) { + var rectShape = clipPath.shape; + var expandSize = Math.max(rectShape.width, rectShape.height); + + if (isHorizontal) { + rectShape.y -= expandSize; + rectShape.height += expandSize * 2; + } else { + rectShape.x -= expandSize; + rectShape.width += expandSize * 2; + } + } // Set to the final frame. To make sure label layout is right. + + + if (during) { + during(1, clipPath); + } + + return clipPath; + } else { + { + if (seriesModel.get(['endLabel', 'show'])) { + console.warn('endLabel is not supported for lines in polar systems.'); + } + } + return createPolarClipPath(coordSys, hasAnimation, seriesModel); + } + } + + function getEndLabelStateSpecified(endLabelModel, coordSys) { + var baseAxis = coordSys.getBaseAxis(); + var isHorizontal = baseAxis.isHorizontal(); + var isBaseInversed = baseAxis.inverse; + var align = isHorizontal ? isBaseInversed ? 'right' : 'left' : 'center'; + var verticalAlign = isHorizontal ? 'middle' : isBaseInversed ? 'top' : 'bottom'; + return { + normal: { + align: endLabelModel.get('align') || align, + verticalAlign: endLabelModel.get('verticalAlign') || verticalAlign + } + }; + } + + var LineView = + /** @class */ + function (_super) { + __extends(LineView, _super); + + function LineView() { + return _super !== null && _super.apply(this, arguments) || this; + } + + LineView.prototype.init = function () { + var lineGroup = new Group$2(); + var symbolDraw = new SymbolDraw(); + this.group.add(symbolDraw.group); + this._symbolDraw = symbolDraw; + this._lineGroup = lineGroup; + this._changePolyState = bind$1(this._changePolyState, this); + }; + + LineView.prototype.render = function (seriesModel, ecModel, api) { + var coordSys = seriesModel.coordinateSystem; + var group = this.group; + var data = seriesModel.getData(); + var lineStyleModel = seriesModel.getModel('lineStyle'); + var areaStyleModel = seriesModel.getModel('areaStyle'); + var points = data.getLayout('points') || []; + var isCoordSysPolar = coordSys.type === 'polar'; + var prevCoordSys = this._coordSys; + var symbolDraw = this._symbolDraw; + var polyline = this._polyline; + var polygon = this._polygon; + var lineGroup = this._lineGroup; + var hasAnimation = !ecModel.ssr && seriesModel.get('animation'); + var isAreaChart = !areaStyleModel.isEmpty(); + var valueOrigin = areaStyleModel.get('origin'); + var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin); + var stackedOnPoints = isAreaChart && getStackedOnPoints(coordSys, data, dataCoordInfo); + var showSymbol = seriesModel.get('showSymbol'); + var connectNulls = seriesModel.get('connectNulls'); + var isIgnoreFunc = showSymbol && !isCoordSysPolar && getIsIgnoreFunc(seriesModel, data, coordSys); // Remove temporary symbols + + var oldData = this._data; + oldData && oldData.eachItemGraphicEl(function (el, idx) { + if (el.__temp) { + group.remove(el); + oldData.setItemGraphicEl(idx, null); + } + }); // Remove previous created symbols if showSymbol changed to false + + if (!showSymbol) { + symbolDraw.remove(); + } + + group.add(lineGroup); // FIXME step not support polar + + var step = !isCoordSysPolar ? seriesModel.get('step') : false; + var clipShapeForSymbol; + + if (coordSys && coordSys.getArea && seriesModel.get('clip', true)) { + clipShapeForSymbol = coordSys.getArea(); // Avoid float number rounding error for symbol on the edge of axis extent. + // See #7913 and `test/dataZoom-clip.html`. + + if (clipShapeForSymbol.width != null) { + clipShapeForSymbol.x -= 0.1; + clipShapeForSymbol.y -= 0.1; + clipShapeForSymbol.width += 0.2; + clipShapeForSymbol.height += 0.2; + } else if (clipShapeForSymbol.r0) { + clipShapeForSymbol.r0 -= 0.5; + clipShapeForSymbol.r += 0.5; + } + } + + this._clipShapeForSymbol = clipShapeForSymbol; + var visualColor = getVisualGradient(data, coordSys, api) || data.getVisual('style')[data.getVisual('drawType')]; // Initialization animation or coordinate system changed + + if (!(polyline && prevCoordSys.type === coordSys.type && step === this._step)) { + showSymbol && symbolDraw.updateData(data, { + isIgnore: isIgnoreFunc, + clipShape: clipShapeForSymbol, + disableAnimation: true, + getSymbolPoint: function (idx) { + return [points[idx * 2], points[idx * 2 + 1]]; + } + }); + hasAnimation && this._initSymbolLabelAnimation(data, coordSys, clipShapeForSymbol); + + if (step) { + if (stackedOnPoints) { + stackedOnPoints = turnPointsIntoStep(stackedOnPoints, points, coordSys, step, connectNulls); + } // TODO If stacked series is not step + + + points = turnPointsIntoStep(points, null, coordSys, step, connectNulls); + } + + polyline = this._newPolyline(points); + + if (isAreaChart) { + polygon = this._newPolygon(points, stackedOnPoints); + } // If areaStyle is removed + else if (polygon) { + lineGroup.remove(polygon); + polygon = this._polygon = null; + } // NOTE: Must update _endLabel before setClipPath. + + + if (!isCoordSysPolar) { + this._initOrUpdateEndLabel(seriesModel, coordSys, convertToColorString(visualColor)); + } + + lineGroup.setClipPath(createLineClipPath(this, coordSys, true, seriesModel)); + } else { + if (isAreaChart && !polygon) { + // If areaStyle is added + polygon = this._newPolygon(points, stackedOnPoints); + } else if (polygon && !isAreaChart) { + // If areaStyle is removed + lineGroup.remove(polygon); + polygon = this._polygon = null; + } // NOTE: Must update _endLabel before setClipPath. + + + if (!isCoordSysPolar) { + this._initOrUpdateEndLabel(seriesModel, coordSys, convertToColorString(visualColor)); + } // Update clipPath + + + var oldClipPath = lineGroup.getClipPath(); + + if (oldClipPath) { + var newClipPath = createLineClipPath(this, coordSys, false, seriesModel); + initProps(oldClipPath, { + shape: newClipPath.shape + }, seriesModel); + } else { + lineGroup.setClipPath(createLineClipPath(this, coordSys, true, seriesModel)); + } // Always update, or it is wrong in the case turning on legend + // because points are not changed. + + + showSymbol && symbolDraw.updateData(data, { + isIgnore: isIgnoreFunc, + clipShape: clipShapeForSymbol, + disableAnimation: true, + getSymbolPoint: function (idx) { + return [points[idx * 2], points[idx * 2 + 1]]; + } + }); // In the case data zoom triggered refreshing frequently + // Data may not change if line has a category axis. So it should animate nothing. + + if (!isPointsSame(this._stackedOnPoints, stackedOnPoints) || !isPointsSame(this._points, points)) { + if (hasAnimation) { + this._doUpdateAnimation(data, stackedOnPoints, coordSys, api, step, valueOrigin, connectNulls); + } else { + // Not do it in update with animation + if (step) { + if (stackedOnPoints) { + stackedOnPoints = turnPointsIntoStep(stackedOnPoints, points, coordSys, step, connectNulls); + } // TODO If stacked series is not step + + + points = turnPointsIntoStep(points, null, coordSys, step, connectNulls); + } + + polyline.setShape({ + points: points + }); + polygon && polygon.setShape({ + points: points, + stackedOnPoints: stackedOnPoints + }); + } + } + } + + var emphasisModel = seriesModel.getModel('emphasis'); + var focus = emphasisModel.get('focus'); + var blurScope = emphasisModel.get('blurScope'); + var emphasisDisabled = emphasisModel.get('disabled'); + polyline.useStyle(defaults( // Use color in lineStyle first + lineStyleModel.getLineStyle(), { + fill: 'none', + stroke: visualColor, + lineJoin: 'bevel' + })); + setStatesStylesFromModel(polyline, seriesModel, 'lineStyle'); + + if (polyline.style.lineWidth > 0 && seriesModel.get(['emphasis', 'lineStyle', 'width']) === 'bolder') { + var emphasisLineStyle = polyline.getState('emphasis').style; + emphasisLineStyle.lineWidth = +polyline.style.lineWidth + 1; + } // Needs seriesIndex for focus + + + getECData(polyline).seriesIndex = seriesModel.seriesIndex; + toggleHoverEmphasis(polyline, focus, blurScope, emphasisDisabled); + var smooth = getSmooth(seriesModel.get('smooth')); + var smoothMonotone = seriesModel.get('smoothMonotone'); + polyline.setShape({ + smooth: smooth, + smoothMonotone: smoothMonotone, + connectNulls: connectNulls + }); + + if (polygon) { + var stackedOnSeries = data.getCalculationInfo('stackedOnSeries'); + var stackedOnSmooth = 0; + polygon.useStyle(defaults(areaStyleModel.getAreaStyle(), { + fill: visualColor, + opacity: 0.7, + lineJoin: 'bevel', + decal: data.getVisual('style').decal + })); + + if (stackedOnSeries) { + stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth')); + } + + polygon.setShape({ + smooth: smooth, + stackedOnSmooth: stackedOnSmooth, + smoothMonotone: smoothMonotone, + connectNulls: connectNulls + }); + setStatesStylesFromModel(polygon, seriesModel, 'areaStyle'); // Needs seriesIndex for focus + + getECData(polygon).seriesIndex = seriesModel.seriesIndex; + toggleHoverEmphasis(polygon, focus, blurScope, emphasisDisabled); + } + + var changePolyState = this._changePolyState; + data.eachItemGraphicEl(function (el) { + // Switch polyline / polygon state if element changed its state. + el && (el.onHoverStateChange = changePolyState); + }); + this._polyline.onHoverStateChange = changePolyState; + this._data = data; // Save the coordinate system for transition animation when data changed + + this._coordSys = coordSys; + this._stackedOnPoints = stackedOnPoints; + this._points = points; + this._step = step; + this._valueOrigin = valueOrigin; + + if (seriesModel.get('triggerLineEvent')) { + this.packEventData(seriesModel, polyline); + polygon && this.packEventData(seriesModel, polygon); + } + }; + + LineView.prototype.packEventData = function (seriesModel, el) { + getECData(el).eventData = { + componentType: 'series', + componentSubType: 'line', + componentIndex: seriesModel.componentIndex, + seriesIndex: seriesModel.seriesIndex, + seriesName: seriesModel.name, + seriesType: 'line' + }; + }; + + LineView.prototype.highlight = function (seriesModel, ecModel, api, payload) { + var data = seriesModel.getData(); + var dataIndex = queryDataIndex(data, payload); + + this._changePolyState('emphasis'); + + if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) { + var points = data.getLayout('points'); + var symbol = data.getItemGraphicEl(dataIndex); + + if (!symbol) { + // Create a temporary symbol if it is not exists + var x = points[dataIndex * 2]; + var y = points[dataIndex * 2 + 1]; + + if (isNaN(x) || isNaN(y)) { + // Null data + return; + } // fix #11360: shouldn't draw symbol outside clipShapeForSymbol + + + if (this._clipShapeForSymbol && !this._clipShapeForSymbol.contain(x, y)) { + return; + } + + var zlevel = seriesModel.get('zlevel') || 0; + var z = seriesModel.get('z') || 0; + symbol = new Symbol(data, dataIndex); + symbol.x = x; + symbol.y = y; + symbol.setZ(zlevel, z); // ensure label text of the temporary symbol is in front of line and area polygon + + var symbolLabel = symbol.getSymbolPath().getTextContent(); + + if (symbolLabel) { + symbolLabel.zlevel = zlevel; + symbolLabel.z = z; + symbolLabel.z2 = this._polyline.z2 + 1; + } + + symbol.__temp = true; + data.setItemGraphicEl(dataIndex, symbol); // Stop scale animation + + symbol.stopSymbolAnimation(true); + this.group.add(symbol); + } + + symbol.highlight(); + } else { + // Highlight whole series + ChartView.prototype.highlight.call(this, seriesModel, ecModel, api, payload); + } + }; + + LineView.prototype.downplay = function (seriesModel, ecModel, api, payload) { + var data = seriesModel.getData(); + var dataIndex = queryDataIndex(data, payload); + + this._changePolyState('normal'); + + if (dataIndex != null && dataIndex >= 0) { + var symbol = data.getItemGraphicEl(dataIndex); + + if (symbol) { + if (symbol.__temp) { + data.setItemGraphicEl(dataIndex, null); + this.group.remove(symbol); + } else { + symbol.downplay(); + } + } + } else { + // FIXME + // can not downplay completely. + // Downplay whole series + ChartView.prototype.downplay.call(this, seriesModel, ecModel, api, payload); + } + }; + + LineView.prototype._changePolyState = function (toState) { + var polygon = this._polygon; + setStatesFlag(this._polyline, toState); + polygon && setStatesFlag(polygon, toState); + }; + + LineView.prototype._newPolyline = function (points) { + var polyline = this._polyline; // Remove previous created polyline + + if (polyline) { + this._lineGroup.remove(polyline); + } + + polyline = new ECPolyline({ + shape: { + points: points + }, + segmentIgnoreThreshold: 2, + z2: 10 + }); + + this._lineGroup.add(polyline); + + this._polyline = polyline; + return polyline; + }; + + LineView.prototype._newPolygon = function (points, stackedOnPoints) { + var polygon = this._polygon; // Remove previous created polygon + + if (polygon) { + this._lineGroup.remove(polygon); + } + + polygon = new ECPolygon({ + shape: { + points: points, + stackedOnPoints: stackedOnPoints + }, + segmentIgnoreThreshold: 2 + }); + + this._lineGroup.add(polygon); + + this._polygon = polygon; + return polygon; + }; + + LineView.prototype._initSymbolLabelAnimation = function (data, coordSys, clipShape) { + var isHorizontalOrRadial; + var isCoordSysPolar; + var baseAxis = coordSys.getBaseAxis(); + var isAxisInverse = baseAxis.inverse; + + if (coordSys.type === 'cartesian2d') { + isHorizontalOrRadial = baseAxis.isHorizontal(); + isCoordSysPolar = false; + } else if (coordSys.type === 'polar') { + isHorizontalOrRadial = baseAxis.dim === 'angle'; + isCoordSysPolar = true; + } + + var seriesModel = data.hostModel; + var seriesDuration = seriesModel.get('animationDuration'); + + if (isFunction(seriesDuration)) { + seriesDuration = seriesDuration(null); + } + + var seriesDelay = seriesModel.get('animationDelay') || 0; + var seriesDelayValue = isFunction(seriesDelay) ? seriesDelay(null) : seriesDelay; + data.eachItemGraphicEl(function (symbol, idx) { + var el = symbol; + + if (el) { + var point = [symbol.x, symbol.y]; + var start = void 0; + var end = void 0; + var current = void 0; + + if (clipShape) { + if (isCoordSysPolar) { + var polarClip = clipShape; + var coord = coordSys.pointToCoord(point); + + if (isHorizontalOrRadial) { + start = polarClip.startAngle; + end = polarClip.endAngle; + current = -coord[1] / 180 * Math.PI; + } else { + start = polarClip.r0; + end = polarClip.r; + current = coord[0]; + } + } else { + var gridClip = clipShape; + + if (isHorizontalOrRadial) { + start = gridClip.x; + end = gridClip.x + gridClip.width; + current = symbol.x; + } else { + start = gridClip.y + gridClip.height; + end = gridClip.y; + current = symbol.y; + } + } + } + + var ratio = end === start ? 0 : (current - start) / (end - start); + + if (isAxisInverse) { + ratio = 1 - ratio; + } + + var delay = isFunction(seriesDelay) ? seriesDelay(idx) : seriesDuration * ratio + seriesDelayValue; + var symbolPath = el.getSymbolPath(); + var text = symbolPath.getTextContent(); + el.attr({ + scaleX: 0, + scaleY: 0 + }); + el.animateTo({ + scaleX: 1, + scaleY: 1 + }, { + duration: 200, + setToFinal: true, + delay: delay + }); + + if (text) { + text.animateFrom({ + style: { + opacity: 0 + } + }, { + duration: 300, + delay: delay + }); + } + + symbolPath.disableLabelAnimation = true; + } + }); + }; + + LineView.prototype._initOrUpdateEndLabel = function (seriesModel, coordSys, inheritColor) { + var endLabelModel = seriesModel.getModel('endLabel'); + + if (anyStateShowEndLabel(seriesModel)) { + var data_2 = seriesModel.getData(); + var polyline = this._polyline; // series may be filtered. + + var points = data_2.getLayout('points'); + + if (!points) { + polyline.removeTextContent(); + this._endLabel = null; + return; + } + + var endLabel = this._endLabel; + + if (!endLabel) { + endLabel = this._endLabel = new ZRText({ + z2: 200 // should be higher than item symbol + + }); + endLabel.ignoreClip = true; + polyline.setTextContent(this._endLabel); + polyline.disableLabelAnimation = true; + } // Find last non-NaN data to display data + + + var dataIndex = getLastIndexNotNull(points); + + if (dataIndex >= 0) { + setLabelStyle(polyline, getLabelStatesModels(seriesModel, 'endLabel'), { + inheritColor: inheritColor, + labelFetcher: seriesModel, + labelDataIndex: dataIndex, + defaultText: function (dataIndex, opt, interpolatedValue) { + return interpolatedValue != null ? getDefaultInterpolatedLabel(data_2, interpolatedValue) : getDefaultLabel(data_2, dataIndex); + }, + enableTextSetter: true + }, getEndLabelStateSpecified(endLabelModel, coordSys)); + polyline.textConfig.position = null; + } + } else if (this._endLabel) { + this._polyline.removeTextContent(); + + this._endLabel = null; + } + }; + + LineView.prototype._endLabelOnDuring = function (percent, clipRect, data, animationRecord, valueAnimation, endLabelModel, coordSys) { + var endLabel = this._endLabel; + var polyline = this._polyline; + + if (endLabel) { + // NOTE: Don't remove percent < 1. percent === 1 means the first frame during render. + // The label is not prepared at this time. + if (percent < 1 && animationRecord.originalX == null) { + animationRecord.originalX = endLabel.x; + animationRecord.originalY = endLabel.y; + } + + var points = data.getLayout('points'); + var seriesModel = data.hostModel; + var connectNulls = seriesModel.get('connectNulls'); + var precision = endLabelModel.get('precision'); + var distance = endLabelModel.get('distance') || 0; + var baseAxis = coordSys.getBaseAxis(); + var isHorizontal = baseAxis.isHorizontal(); + var isBaseInversed = baseAxis.inverse; + var clipShape = clipRect.shape; + var xOrY = isBaseInversed ? isHorizontal ? clipShape.x : clipShape.y + clipShape.height : isHorizontal ? clipShape.x + clipShape.width : clipShape.y; + var distanceX = (isHorizontal ? distance : 0) * (isBaseInversed ? -1 : 1); + var distanceY = (isHorizontal ? 0 : -distance) * (isBaseInversed ? -1 : 1); + var dim = isHorizontal ? 'x' : 'y'; + var dataIndexRange = getIndexRange(points, xOrY, dim); + var indices = dataIndexRange.range; + var diff = indices[1] - indices[0]; + var value = void 0; + + if (diff >= 1) { + // diff > 1 && connectNulls, which is on the null data. + if (diff > 1 && !connectNulls) { + var pt = getPointAtIndex(points, indices[0]); + endLabel.attr({ + x: pt[0] + distanceX, + y: pt[1] + distanceY + }); + valueAnimation && (value = seriesModel.getRawValue(indices[0])); + } else { + var pt = polyline.getPointOn(xOrY, dim); + pt && endLabel.attr({ + x: pt[0] + distanceX, + y: pt[1] + distanceY + }); + var startValue = seriesModel.getRawValue(indices[0]); + var endValue = seriesModel.getRawValue(indices[1]); + valueAnimation && (value = interpolateRawValues(data, precision, startValue, endValue, dataIndexRange.t)); + } + + animationRecord.lastFrameIndex = indices[0]; + } else { + // If diff <= 0, which is the range is not found(Include NaN) + // Choose the first point or last point. + var idx = percent === 1 || animationRecord.lastFrameIndex > 0 ? indices[0] : 0; + var pt = getPointAtIndex(points, idx); + valueAnimation && (value = seriesModel.getRawValue(idx)); + endLabel.attr({ + x: pt[0] + distanceX, + y: pt[1] + distanceY + }); + } + + if (valueAnimation) { + var inner = labelInner(endLabel); + + if (typeof inner.setLabelText === 'function') { + inner.setLabelText(value); + } + } + } + }; + /** + * @private + */ + // FIXME Two value axis + + + LineView.prototype._doUpdateAnimation = function (data, stackedOnPoints, coordSys, api, step, valueOrigin, connectNulls) { + var polyline = this._polyline; + var polygon = this._polygon; + var seriesModel = data.hostModel; + var diff = lineAnimationDiff(this._data, data, this._stackedOnPoints, stackedOnPoints, this._coordSys, coordSys, this._valueOrigin); + var current = diff.current; + var stackedOnCurrent = diff.stackedOnCurrent; + var next = diff.next; + var stackedOnNext = diff.stackedOnNext; + + if (step) { + // TODO If stacked series is not step + stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, diff.current, coordSys, step, connectNulls); + current = turnPointsIntoStep(diff.current, null, coordSys, step, connectNulls); + stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, diff.next, coordSys, step, connectNulls); + next = turnPointsIntoStep(diff.next, null, coordSys, step, connectNulls); + } // Don't apply animation if diff is large. + // For better result and avoid memory explosion problems like + // https://github.com/apache/incubator-echarts/issues/12229 + + + if (getBoundingDiff(current, next) > 3000 || polygon && getBoundingDiff(stackedOnCurrent, stackedOnNext) > 3000) { + polyline.stopAnimation(); + polyline.setShape({ + points: next + }); + + if (polygon) { + polygon.stopAnimation(); + polygon.setShape({ + points: next, + stackedOnPoints: stackedOnNext + }); + } + + return; + } + + polyline.shape.__points = diff.current; + polyline.shape.points = current; + var target = { + shape: { + points: next + } + }; // Also animate the original points. + // If points reference is changed when turning into step line. + + if (diff.current !== current) { + target.shape.__points = diff.next; + } // Stop previous animation. + + + polyline.stopAnimation(); + updateProps$1(polyline, target, seriesModel); + + if (polygon) { + polygon.setShape({ + // Reuse the points with polyline. + points: current, + stackedOnPoints: stackedOnCurrent + }); + polygon.stopAnimation(); + updateProps$1(polygon, { + shape: { + stackedOnPoints: stackedOnNext + } + }, seriesModel); // If use attr directly in updateProps. + + if (polyline.shape.points !== polygon.shape.points) { + polygon.shape.points = polyline.shape.points; + } + } + + var updatedDataInfo = []; + var diffStatus = diff.status; + + for (var i = 0; i < diffStatus.length; i++) { + var cmd = diffStatus[i].cmd; + + if (cmd === '=') { + var el = data.getItemGraphicEl(diffStatus[i].idx1); + + if (el) { + updatedDataInfo.push({ + el: el, + ptIdx: i // Index of points + + }); + } + } + } + + if (polyline.animators && polyline.animators.length) { + polyline.animators[0].during(function () { + polygon && polygon.dirtyShape(); + var points = polyline.shape.__points; + + for (var i = 0; i < updatedDataInfo.length; i++) { + var el = updatedDataInfo[i].el; + var offset = updatedDataInfo[i].ptIdx * 2; + el.x = points[offset]; + el.y = points[offset + 1]; + el.markRedraw(); + } + }); + } + }; + + LineView.prototype.remove = function (ecModel) { + var group = this.group; + var oldData = this._data; + + this._lineGroup.removeAll(); + + this._symbolDraw.remove(true); // Remove temporary created elements when highlighting + + + oldData && oldData.eachItemGraphicEl(function (el, idx) { + if (el.__temp) { + group.remove(el); + oldData.setItemGraphicEl(idx, null); + } + }); + this._polyline = this._polygon = this._coordSys = this._points = this._stackedOnPoints = this._endLabel = this._data = null; + }; + + LineView.type = 'line'; + return LineView; + }(ChartView); + + function pointsLayout(seriesType, forceStoreInTypedArray) { + return { + seriesType: seriesType, + plan: createRenderPlanner(), + reset: function (seriesModel) { + var data = seriesModel.getData(); + var coordSys = seriesModel.coordinateSystem; + var pipelineContext = seriesModel.pipelineContext; + var useTypedArray = forceStoreInTypedArray || pipelineContext.large; + + if (!coordSys) { + return; + } + + var dims = map$1(coordSys.dimensions, function (dim) { + return data.mapDimension(dim); + }).slice(0, 2); + var dimLen = dims.length; + var stackResultDim = data.getCalculationInfo('stackResultDimension'); + + if (isDimensionStacked(data, dims[0])) { + dims[0] = stackResultDim; + } + + if (isDimensionStacked(data, dims[1])) { + dims[1] = stackResultDim; + } + + var store = data.getStore(); + var dimIdx0 = data.getDimensionIndex(dims[0]); + var dimIdx1 = data.getDimensionIndex(dims[1]); + return dimLen && { + progress: function (params, data) { + var segCount = params.end - params.start; + var points = useTypedArray && createFloat32Array(segCount * dimLen); + var tmpIn = []; + var tmpOut = []; + + for (var i = params.start, offset = 0; i < params.end; i++) { + var point = void 0; + + if (dimLen === 1) { + var x = store.get(dimIdx0, i); // NOTE: Make sure the second parameter is null to use default strategy. + + point = coordSys.dataToPoint(x, null, tmpOut); + } else { + tmpIn[0] = store.get(dimIdx0, i); + tmpIn[1] = store.get(dimIdx1, i); // Let coordinate system to handle the NaN data. + + point = coordSys.dataToPoint(tmpIn, null, tmpOut); + } + + if (useTypedArray) { + points[offset++] = point[0]; + points[offset++] = point[1]; + } else { + data.setItemLayout(i, point.slice()); + } + } + + useTypedArray && data.setLayout('points', points); + } + }; + } + }; + } + + function install$8(registers) { + registers.registerChartView(LineView); + registers.registerSeriesModel(LineSeriesModel); + registers.registerLayout(pointsLayout('line', true)); + registers.registerVisual({ + seriesType: 'line', + reset: function (seriesModel) { + var data = seriesModel.getData(); // Visual coding for legend + + var lineStyle = seriesModel.getModel('lineStyle').getLineStyle(); + + if (lineStyle && !lineStyle.stroke) { + // Fill in visual should be palette color if + // has color callback + lineStyle.stroke = data.getVisual('style').fill; + } + + data.setVisual('legendLineStyle', lineStyle); + } + }); // Down sample after filter + + registers.registerProcessor(registers.PRIORITY.PROCESSOR.STATISTIC, dataSample('line')); + } + + use(install$8); // For backward compatibility, do not use a margin. Although the labels might touch the edge of + // the canvas, the chart canvas probably does not have an border or a different background color within a page. + + var OUTER_BOUNDS_DEFAULT = { + left: 0, + right: 0, + top: 0, + bottom: 0 + }; + var OUTER_BOUNDS_CLAMP_DEFAULT = ['25%', '25%']; + + var GridModel = + /** @class */ + function (_super) { + __extends(GridModel, _super); + + function GridModel() { + return _super !== null && _super.apply(this, arguments) || this; + } + + GridModel.prototype.mergeDefaultAndTheme = function (option, ecModel) { + var outerBoundsCp = getLayoutParams(option.outerBounds); + + _super.prototype.mergeDefaultAndTheme.apply(this, arguments); + + if (outerBoundsCp && option.outerBounds) { + mergeLayoutParam(option.outerBounds, outerBoundsCp); + } + }; + + GridModel.prototype.mergeOption = function (newOption, ecModel) { + _super.prototype.mergeOption.apply(this, arguments); + + if (this.option.outerBounds && newOption.outerBounds) { + mergeLayoutParam(this.option.outerBounds, newOption.outerBounds); + } + }; + + GridModel.type = 'grid'; + GridModel.dependencies = ['xAxis', 'yAxis']; + GridModel.layoutMode = 'box'; + GridModel.defaultOption = { + show: false, + // zlevel: 0, + z: 0, + left: '15%', + top: 65, + right: '10%', + bottom: 80, + // If grid size contain label + containLabel: false, + outerBoundsMode: 'auto', + outerBounds: OUTER_BOUNDS_DEFAULT, + outerBoundsContain: 'all', + outerBoundsClampWidth: OUTER_BOUNDS_CLAMP_DEFAULT[0], + outerBoundsClampHeight: OUTER_BOUNDS_CLAMP_DEFAULT[1], + // width: {totalWidth} - left - right, + // height: {totalHeight} - top - bottom, + backgroundColor: tokens.color.transparent, + borderWidth: 1, + borderColor: tokens.color.neutral30 + }; + return GridModel; + }(ComponentModel); + + var CartesianAxisModel = + /** @class */ + function (_super) { + __extends(CartesianAxisModel, _super); + + function CartesianAxisModel() { + return _super !== null && _super.apply(this, arguments) || this; + } + + CartesianAxisModel.prototype.getCoordSysModel = function () { + return this.getReferringComponents('grid', SINGLE_REFERRING).models[0]; + }; + + CartesianAxisModel.type = 'cartesian2dAxis'; + return CartesianAxisModel; + }(ComponentModel); + + mixin(CartesianAxisModel, AxisModelCommonMixin); + var defaultOption = { + show: true, + // zlevel: 0, + z: 0, + // Inverse the axis. + inverse: false, + // Axis name displayed. + name: '', + // 'start' | 'middle' | 'end' + nameLocation: 'end', + // By degree. By default auto rotate by nameLocation. + nameRotate: null, + nameTruncate: { + maxWidth: null, + ellipsis: '...', + placeholder: '.' + }, + // Use global text style by default. + nameTextStyle: {// textMargin: never, // The default value will be specified based on `nameLocation`. + }, + // The gap between axisName and axisLine. + nameGap: 15, + // Default `false` to support tooltip. + silent: false, + // Default `false` to avoid legacy user event listener fail. + triggerEvent: false, + tooltip: { + show: false + }, + axisPointer: {}, + axisLine: { + show: true, + onZero: true, + onZeroAxisIndex: null, + lineStyle: { + color: tokens.color.axisLine, + width: 1, + type: 'solid' + }, + // The arrow at both ends the the axis. + symbol: ['none', 'none'], + symbolSize: [10, 15], + breakLine: true + }, + axisTick: { + show: true, + // Whether axisTick is inside the grid or outside the grid. + inside: false, + // The length of axisTick. + length: 5, + lineStyle: { + width: 1 + } + }, + axisLabel: { + show: true, + // Whether axisLabel is inside the grid or outside the grid. + inside: false, + rotate: 0, + // true | false | null/undefined (auto) + showMinLabel: null, + // true | false | null/undefined (auto) + showMaxLabel: null, + margin: 8, + // formatter: null, + fontSize: 12, + color: tokens.color.axisLabel, + // In scenarios like axis labels, when labels text's progression direction matches the label + // layout direction (e.g., when all letters are in a single line), extra start/end margin is + // needed to prevent the text from appearing visually joined. In the other case, when lables + // are stacked (e.g., having rotation or horizontal labels on yAxis), the layout needs to be + // compact, so NO extra top/bottom margin should be applied. + textMargin: [0, 3] + }, + splitLine: { + show: true, + showMinLine: true, + showMaxLine: true, + lineStyle: { + color: tokens.color.axisSplitLine, + width: 1, + type: 'solid' + } + }, + splitArea: { + show: false, + areaStyle: { + color: [tokens.color.backgroundTint, tokens.color.backgroundTransparent] + } + }, + breakArea: { + show: true, + itemStyle: { + color: tokens.color.neutral00, + // Break border color should be darker than the splitLine + // because it has opacity and should be more prominent + borderColor: tokens.color.border, + borderWidth: 1, + borderType: [3, 3], + opacity: 0.6 + }, + zigzagAmplitude: 4, + zigzagMinSpan: 4, + zigzagMaxSpan: 20, + zigzagZ: 100, + expandOnClick: true + }, + breakLabelLayout: { + moveOverlap: 'auto' + } + }; + var categoryAxis = merge({ + // The gap at both ends of the axis. For categoryAxis, boolean. + boundaryGap: true, + // Set false to faster category collection. + deduplication: null, + jitter: 0, + jitterOverlap: true, + jitterMargin: 2, + // splitArea: { + // show: false + // }, + splitLine: { + show: false + }, + axisTick: { + // If tick is align with label when boundaryGap is true + alignWithLabel: false, + interval: 'auto', + show: 'auto' + }, + axisLabel: { + interval: 'auto' + } + }, defaultOption); + var valueAxis = merge({ + boundaryGap: [0, 0], + axisLine: { + // Not shown when other axis is categoryAxis in cartesian + show: 'auto' + }, + axisTick: { + // Not shown when other axis is categoryAxis in cartesian + show: 'auto' + }, + // TODO + // min/max: [30, datamin, 60] or [20, datamin] or [datamin, 60] + splitNumber: 5, + minorTick: { + // Minor tick, not available for cateogry axis. + show: false, + // Split number of minor ticks. The value should be in range of (0, 100) + splitNumber: 5, + // Length of minor tick + length: 3, + // Line style + lineStyle: {// Default to be same with axisTick + } + }, + minorSplitLine: { + show: false, + lineStyle: { + color: tokens.color.axisMinorSplitLine, + width: 1 + } + } + }, defaultOption); + var timeAxis = merge({ + splitNumber: 6, + axisLabel: { + // To eliminate labels that are not nice + showMinLabel: false, + showMaxLabel: false, + rich: { + primary: { + fontWeight: 'bold' + } + } + }, + splitLine: { + show: false + } + }, valueAxis); + var logAxis = defaults({ + logBase: 10 + }, valueAxis); + var axisDefault = { + category: categoryAxis, + value: valueAxis, + time: timeAxis, + log: logAxis + }; + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + var AXIS_TYPES = { + value: 1, + category: 1, + time: 1, + log: 1 + }; + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + var _impl = null; + + function getAxisBreakHelper() { + return _impl; + } + /** + * Generate sub axis model class + * @param axisName 'x' 'y' 'radius' 'angle' 'parallel' ... + */ + + + function axisModelCreator(registers, axisName, BaseAxisModelClass, extraDefaultOption) { + each$4(AXIS_TYPES, function (v, axisType) { + var defaultOption = merge(merge({}, axisDefault[axisType], true), extraDefaultOption, true); + + var AxisModel = + /** @class */ + function (_super) { + __extends(AxisModel, _super); + + function AxisModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = axisName + 'Axis.' + axisType; + return _this; + } + + AxisModel.prototype.mergeDefaultAndTheme = function (option, ecModel) { + var layoutMode = fetchLayoutMode(this); + var inputPositionParams = layoutMode ? getLayoutParams(option) : {}; + var themeModel = ecModel.getTheme(); + merge(option, themeModel.get(axisType + 'Axis')); + merge(option, this.getDefaultOption()); + option.type = getAxisType(option); + + if (layoutMode) { + mergeLayoutParam(option, inputPositionParams, layoutMode); + } + }; + + AxisModel.prototype.optionUpdated = function () { + var thisOption = this.option; + + if (thisOption.type === 'category') { + this.__ordinalMeta = OrdinalMeta.createByAxisModel(this); + } + }; + /** + * Should not be called before all of 'getInitailData' finished. + * Because categories are collected during initializing data. + */ + + + AxisModel.prototype.getCategories = function (rawData) { + var option = this.option; // FIXME + // warning if called before all of 'getInitailData' finished. + + if (option.type === 'category') { + if (rawData) { + return option.data; + } + + return this.__ordinalMeta.categories; + } + }; + + AxisModel.prototype.getOrdinalMeta = function () { + return this.__ordinalMeta; + }; + + AxisModel.prototype.updateAxisBreaks = function (payload) { + var axisBreakHelper = getAxisBreakHelper(); + return axisBreakHelper ? axisBreakHelper.updateModelAxisBreak(this, payload) : { + breaks: [] + }; + }; + + AxisModel.type = axisName + 'Axis.' + axisType; + AxisModel.defaultOption = defaultOption; + return AxisModel; + }(BaseAxisModelClass); + + registers.registerComponentModel(AxisModel); + }); + registers.registerSubTypeDefaulter(axisName + 'Axis', getAxisType); + } + + function getAxisType(option) { + // Default axis with data is category axis + return option.type || (option.data ? 'category' : 'value'); + } + + var Cartesian = + /** @class */ + function () { + function Cartesian(name) { + this.type = 'cartesian'; + this._dimList = []; + this._axes = {}; + this.name = name || ''; + } + + Cartesian.prototype.getAxis = function (dim) { + return this._axes[dim]; + }; + + Cartesian.prototype.getAxes = function () { + return map$1(this._dimList, function (dim) { + return this._axes[dim]; + }, this); + }; + + Cartesian.prototype.getAxesByScale = function (scaleType) { + scaleType = scaleType.toLowerCase(); + return filter(this.getAxes(), function (axis) { + return axis.scale.type === scaleType; + }); + }; + + Cartesian.prototype.addAxis = function (axis) { + var dim = axis.dim; + this._axes[dim] = axis; + + this._dimList.push(dim); + }; + + return Cartesian; + }(); + + var cartesian2DDimensions = ['x', 'y']; + + function canCalculateAffineTransform(scale) { + return (scale.type === 'interval' || scale.type === 'time') && !scale.hasBreaks(); + } + + var Cartesian2D = + /** @class */ + function (_super) { + __extends(Cartesian2D, _super); + + function Cartesian2D() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'cartesian2d'; + _this.dimensions = cartesian2DDimensions; + return _this; + } + /** + * Calculate an affine transform matrix if two axes are time or value. + * It's mainly for accelartion on the large time series data. + */ + + + Cartesian2D.prototype.calcAffineTransform = function () { + this._transform = this._invTransform = null; + var xAxisScale = this.getAxis('x').scale; + var yAxisScale = this.getAxis('y').scale; + + if (!canCalculateAffineTransform(xAxisScale) || !canCalculateAffineTransform(yAxisScale)) { + return; + } + + var xScaleExtent = xAxisScale.getExtent(); + var yScaleExtent = yAxisScale.getExtent(); + var start = this.dataToPoint([xScaleExtent[0], yScaleExtent[0]]); + var end = this.dataToPoint([xScaleExtent[1], yScaleExtent[1]]); + var xScaleSpan = xScaleExtent[1] - xScaleExtent[0]; + var yScaleSpan = yScaleExtent[1] - yScaleExtent[0]; + + if (!xScaleSpan || !yScaleSpan) { + return; + } // Accelerate data to point calculation on the special large time series data. + + + var scaleX = (end[0] - start[0]) / xScaleSpan; + var scaleY = (end[1] - start[1]) / yScaleSpan; + var translateX = start[0] - xScaleExtent[0] * scaleX; + var translateY = start[1] - yScaleExtent[0] * scaleY; + var m = this._transform = [scaleX, 0, 0, scaleY, translateX, translateY]; + this._invTransform = invert([], m); + }; + /** + * Base axis will be used on stacking. + */ + + + Cartesian2D.prototype.getBaseAxis = function () { + return this.getAxesByScale('ordinal')[0] || this.getAxesByScale('time')[0] || this.getAxis('x'); + }; + + Cartesian2D.prototype.containPoint = function (point) { + var axisX = this.getAxis('x'); + var axisY = this.getAxis('y'); + return axisX.contain(axisX.toLocalCoord(point[0])) && axisY.contain(axisY.toLocalCoord(point[1])); + }; + + Cartesian2D.prototype.containData = function (data) { + return this.getAxis('x').containData(data[0]) && this.getAxis('y').containData(data[1]); + }; + + Cartesian2D.prototype.containZone = function (data1, data2) { + var zoneDiag1 = this.dataToPoint(data1); + var zoneDiag2 = this.dataToPoint(data2); + var area = this.getArea(); + var zone = new BoundingRect(zoneDiag1[0], zoneDiag1[1], zoneDiag2[0] - zoneDiag1[0], zoneDiag2[1] - zoneDiag1[1]); + return area.intersect(zone); + }; + + Cartesian2D.prototype.dataToPoint = function (data, clamp, out) { + out = out || []; + var xVal = data[0]; + var yVal = data[1]; // [CAVEAT]: Do not add time consuming operation within and before fast path. + // Fast path. + + if (this._transform // It's supported that if data is like `[Inifity, 123]`, where only Y pixel calculated. + && xVal != null && isFinite(xVal) && yVal != null && isFinite(yVal)) { + return applyTransform$1(out, data, this._transform); + } + + var xAxis = this.getAxis('x'); + var yAxis = this.getAxis('y'); + out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(xVal, clamp)); + out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(yVal, clamp)); + return out; + }; + + Cartesian2D.prototype.clampData = function (data, out) { + var xScale = this.getAxis('x').scale; + var yScale = this.getAxis('y').scale; + var xAxisExtent = xScale.getExtent(); + var yAxisExtent = yScale.getExtent(); + var x = xScale.parse(data[0]); + var y = yScale.parse(data[1]); + out = out || []; + out[0] = Math.min(Math.max(Math.min(xAxisExtent[0], xAxisExtent[1]), x), Math.max(xAxisExtent[0], xAxisExtent[1])); + out[1] = Math.min(Math.max(Math.min(yAxisExtent[0], yAxisExtent[1]), y), Math.max(yAxisExtent[0], yAxisExtent[1])); + return out; + }; + + Cartesian2D.prototype.pointToData = function (point, clamp, out) { + out = out || []; + + if (this._invTransform) { + return applyTransform$1(out, point, this._invTransform); + } + + var xAxis = this.getAxis('x'); + var yAxis = this.getAxis('y'); + out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0]), clamp); + out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1]), clamp); + return out; + }; + + Cartesian2D.prototype.getOtherAxis = function (axis) { + return this.getAxis(axis.dim === 'x' ? 'y' : 'x'); + }; + /** + * Get rect area of cartesian. + * Area will have a contain function to determine if a point is in the coordinate system. + */ + + + Cartesian2D.prototype.getArea = function (tolerance) { + tolerance = tolerance || 0; + var xExtent = this.getAxis('x').getGlobalExtent(); + var yExtent = this.getAxis('y').getGlobalExtent(); + var x = Math.min(xExtent[0], xExtent[1]) - tolerance; + var y = Math.min(yExtent[0], yExtent[1]) - tolerance; + var width = Math.max(xExtent[0], xExtent[1]) - x + tolerance; + var height = Math.max(yExtent[0], yExtent[1]) - y + tolerance; + return new BoundingRect(x, y, width, height); + }; + + return Cartesian2D; + }(Cartesian); + + var Axis2D = + /** @class */ + function (_super) { + __extends(Axis2D, _super); + + function Axis2D(dim, scale, coordExtent, axisType, position) { + var _this = _super.call(this, dim, scale, coordExtent) || this; + /** + * Index of axis, can be used as key + * Injected outside. + */ + + + _this.index = 0; + _this.type = axisType || 'value'; + _this.position = position || 'bottom'; + return _this; + } + + Axis2D.prototype.isHorizontal = function () { + var position = this.position; + return position === 'top' || position === 'bottom'; + }; + /** + * Each item cooresponds to this.getExtent(), which + * means globalExtent[0] may greater than globalExtent[1], + * unless `asc` is input. + * + * @param {boolean} [asc] + * @return {Array.} + */ + + + Axis2D.prototype.getGlobalExtent = function (asc) { + var ret = this.getExtent(); + ret[0] = this.toGlobalCoord(ret[0]); + ret[1] = this.toGlobalCoord(ret[1]); + asc && ret[0] > ret[1] && ret.reverse(); + return ret; + }; + + Axis2D.prototype.pointToData = function (point, clamp) { + return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp); + }; + /** + * Set ordinalSortInfo + * @param info new OrdinalSortInfo + */ + + + Axis2D.prototype.setCategorySortInfo = function (info) { + if (this.type !== 'category') { + return false; + } + + this.model.option.categorySortInfo = info; + this.scale.setSortInfo(info); + }; + + return Axis2D; + }(Axis); + + var AXIS_BREAK_EXPAND_ACTION_TYPE = 'expandAxisBreak'; + var PI = Math.PI; + var DEFAULT_CENTER_NAME_MARGIN_LEVELS = [[1, 2, 1, 2], [5, 3, 5, 3], [8, 3, 8, 3]]; + var DEFAULT_ENDS_NAME_MARGIN_LEVELS = [[0, 1, 0, 1], [0, 3, 0, 3], [0, 3, 0, 3]]; + var getLabelInner = makeInner(); + var getTickInner = makeInner(); + /** + * A context shared by difference axisBuilder instances. + * For cross-axes overlap resolving. + * + * Lifecycle constraint: should not over a pass of ec main process. + * If model is changed, the context must be disposed. + * + * @see AxisBuilderLocalContext + */ + + var AxisBuilderSharedContext = + /** @class */ + function () { + function AxisBuilderSharedContext(resolveAxisNameOverlap) { + /** + * [CAUTION] Do not modify this data structure outside this class. + */ + this.recordMap = {}; + this.resolveAxisNameOverlap = resolveAxisNameOverlap; + } + + AxisBuilderSharedContext.prototype.ensureRecord = function (axisModel) { + var dim = axisModel.axis.dim; + var idx = axisModel.componentIndex; + var recordMap = this.recordMap; + var records = recordMap[dim] || (recordMap[dim] = []); + return records[idx] || (records[idx] = { + ready: {} + }); + }; + + return AxisBuilderSharedContext; + }(); + /** + * [CAUTION] + * 1. The call of this function must be after axisLabel overlap handlings + * (such as `hideOverlap`, `fixMinMaxLabelShow`) and after transform calculating. + * 2. Can be called multiple times and should be idempotent. + */ + + + function resetOverlapRecordToShared(cfg, shared, axisModel, labelLayoutList) { + var axis = axisModel.axis; + var record = shared.ensureRecord(axisModel); + var labelInfoList = []; + var stOccupiedRect; + var useStOccupiedRect = hasAxisName(cfg.axisName) && isNameLocationCenter(cfg.nameLocation); + each$4(labelLayoutList, function (layout) { + var layoutInfo = ensureLabelLayoutWithGeometry(layout); + + if (!layoutInfo || layoutInfo.label.ignore) { + return; + } + + labelInfoList.push(layoutInfo); + var transGroup = record.transGroup; + + if (useStOccupiedRect) { + // Transform to "standard axis" for creating stOccupiedRect (the label rects union). + transGroup.transform ? invert(_stTransTmp, transGroup.transform) : identity(_stTransTmp); + + if (layoutInfo.transform) { + mul(_stTransTmp, _stTransTmp, layoutInfo.transform); + } + + BoundingRect.copy(_stLabelRectTmp, layoutInfo.localRect); + + _stLabelRectTmp.applyTransform(_stTransTmp); + + stOccupiedRect ? stOccupiedRect.union(_stLabelRectTmp) : BoundingRect.copy(stOccupiedRect = new BoundingRect(0, 0, 0, 0), _stLabelRectTmp); + } + }); + var sortByDim = Math.abs(record.dirVec.x) > 0.1 ? 'x' : 'y'; + var sortByValue = record.transGroup[sortByDim]; + labelInfoList.sort(function (info1, info2) { + return Math.abs(info1.label[sortByDim] - sortByValue) - Math.abs(info2.label[sortByDim] - sortByValue); + }); + + if (useStOccupiedRect && stOccupiedRect) { + var extent = axis.getExtent(); + var axisLineX = Math.min(extent[0], extent[1]); + var axisLineWidth = Math.max(extent[0], extent[1]) - axisLineX; // If `nameLocation` is 'middle', enlarge axis labels boundingRect to axisLine to avoid bad + // case like that axis name is placed in the gap between axis labels and axis line. + // If only one label exists, the entire band should be occupied for + // visual consistency, so extent it to [0, canvas width]. + + stOccupiedRect.union(new BoundingRect(axisLineX, 0, axisLineWidth, 1)); + } + + record.stOccupiedRect = stOccupiedRect; + record.labelInfoList = labelInfoList; + } + + var _stTransTmp = create(); + + var _stLabelRectTmp = new BoundingRect(0, 0, 0, 0); + /** + * The default resolver does not involve other axes within the same coordinate system. + */ + + + var resolveAxisNameOverlapDefault = function (cfg, ctx, axisModel, nameLayoutInfo, nameMoveDirVec, thisRecord) { + if (isNameLocationCenter(cfg.nameLocation)) { + var stOccupiedRect = thisRecord.stOccupiedRect; + + if (stOccupiedRect) { + moveIfOverlap(computeLabelGeometry2({}, stOccupiedRect, thisRecord.transGroup.transform), nameLayoutInfo, nameMoveDirVec); + } + } else { + moveIfOverlapByLinearLabels(thisRecord.labelInfoList, thisRecord.dirVec, nameLayoutInfo, nameMoveDirVec); + } + }; // [NOTICE] not consider ignore. + + + function moveIfOverlap(basedLayoutInfo, movableLayoutInfo, moveDirVec) { + var mtv = new Point(); + + if (labelIntersect(basedLayoutInfo, movableLayoutInfo, mtv, { + direction: Math.atan2(moveDirVec.y, moveDirVec.x), + bidirectional: false, + touchThreshold: 0.05 + })) { + labelLayoutApplyTranslation(movableLayoutInfo, mtv); + } + } + + function moveIfOverlapByLinearLabels(baseLayoutInfoList, baseDirVec, movableLayoutInfo, moveDirVec) { + // Detect and move from far to close. + var sameDir = Point.dot(moveDirVec, baseDirVec) >= 0; + + for (var idx = 0, len = baseLayoutInfoList.length; idx < len; idx++) { + var labelInfo = baseLayoutInfoList[sameDir ? idx : len - 1 - idx]; + + if (!labelInfo.label.ignore) { + moveIfOverlap(labelInfo, movableLayoutInfo, moveDirVec); + } + } + } + /** + * @caution + * - Ensure it is called after the data processing stage finished. + * - It might be called before `CahrtView#render`, sush as called at `CoordinateSystem#update`, + * thus ensure the result the same whenever it is called. + * + * A builder for a straight-line axis. + * + * A final axis is translated and rotated from a "standard axis". + * So opt.position and opt.rotation is required. + * + * A "standard axis" is the axis [0,0]-->[abs(axisExtent[1]-axisExtent[0]),0] + * for example: [0,0]-->[50,0] + */ + + + var AxisBuilder = + /** @class */ + function () { + /** + * [CAUTION]: axisModel.axis.extent/scale must be ready to use. + */ + function AxisBuilder(axisModel, api, opt, shared) { + this.group = new Group$2(); + this._axisModel = axisModel; + this._api = api; + this._local = {}; + this._shared = shared || new AxisBuilderSharedContext(resolveAxisNameOverlapDefault); + + this._resetCfgDetermined(opt); + } + /** + * Regarding axis label related configurations, only the change of label.x/y is supported; other + * changes are not necessary and not performant. To be specific, only `axis.position` + * (and consequently `labelOffset`) and `axis.extent` can be changed, and assume everything in + * `axisModel` are not changed. + * Axis line related configurations can be changed since this method can only be called + * before they are created. + */ + + + AxisBuilder.prototype.updateCfg = function (opt) { + { + var ready = this._shared.ensureRecord(this._axisModel).ready; // After that, changing cfg is not supported; avoid unnecessary complexity. + + + assert(!ready.axisLine && !ready.axisTickLabelDetermine); // Have to be called again if cfg changed. + + ready.axisName = ready.axisTickLabelEstimate = false; + } + var raw = this._cfg.raw; + raw.position = opt.position; + raw.labelOffset = opt.labelOffset; + + this._resetCfgDetermined(raw); + }; + /** + * [CAUTION] For debug usage. Never change it outside! + */ + + + AxisBuilder.prototype.__getRawCfg = function () { + return this._cfg.raw; + }; + + AxisBuilder.prototype._resetCfgDetermined = function (raw) { + var axisModel = this._axisModel; // FIXME: + // Currently there is no uniformed way to set default values if an option + // is specified null/undefined by user (intentionally or unintentionally), + // e.g. null/undefined is not a illegal value for `nameLocation`. + // Try to use `getDefaultOption` to address it. But radar has no `getDefaultOption`. + + var axisModelDefaultOption = axisModel.getDefaultOption ? axisModel.getDefaultOption() : {}; // Default value + + var axisName = retrieve2(raw.axisName, axisModel.get('name')); + var nameMoveOverlapOption = axisModel.get('nameMoveOverlap'); + + if (nameMoveOverlapOption == null || nameMoveOverlapOption === 'auto') { + nameMoveOverlapOption = retrieve2(raw.defaultNameMoveOverlap, true); + } + + var cfg = { + raw: raw, + position: raw.position, + rotation: raw.rotation, + nameDirection: retrieve2(raw.nameDirection, 1), + tickDirection: retrieve2(raw.tickDirection, 1), + labelDirection: retrieve2(raw.labelDirection, 1), + labelOffset: retrieve2(raw.labelOffset, 0), + silent: retrieve2(raw.silent, true), + axisName: axisName, + nameLocation: retrieve3(axisModel.get('nameLocation'), axisModelDefaultOption.nameLocation, 'end'), + shouldNameMoveOverlap: hasAxisName(axisName) && nameMoveOverlapOption, + optionHideOverlap: axisModel.get(['axisLabel', 'hideOverlap']), + showMinorTicks: axisModel.get(['minorTick', 'show']) + }; + { + assert(cfg.position != null); + assert(cfg.rotation != null); + } + this._cfg = cfg; // FIXME Not use a separate text group? + + var transformGroup = new Group$2({ + x: cfg.position[0], + y: cfg.position[1], + rotation: cfg.rotation + }); + transformGroup.updateTransform(); + this._transformGroup = transformGroup; + + var record = this._shared.ensureRecord(axisModel); + + record.transGroup = this._transformGroup; + record.dirVec = new Point(Math.cos(-cfg.rotation), Math.sin(-cfg.rotation)); + }; + + AxisBuilder.prototype.build = function (axisPartNameMap, extraParams) { + var _this = this; + + if (!axisPartNameMap) { + axisPartNameMap = { + axisLine: true, + axisTickLabelEstimate: false, + axisTickLabelDetermine: true, + axisName: true + }; + } + + each$4(AXIS_BUILDER_AXIS_PART_NAMES, function (partName) { + if (axisPartNameMap[partName]) { + builders[partName](_this._cfg, _this._local, _this._shared, _this._axisModel, _this.group, _this._transformGroup, _this._api, extraParams || {}); + } + }); + return this; + }; + /** + * Currently only get text align/verticalAlign by rotation. + * NO `position` is involved, otherwise it have to be performed for each `updateAxisLabelChangableProps`. + */ + + + AxisBuilder.innerTextLayout = function (axisRotation, textRotation, direction) { + var rotationDiff = remRadian(textRotation - axisRotation); + var textAlign; + var textVerticalAlign; + + if (isRadianAroundZero(rotationDiff)) { + // Label is parallel with axis line. + textVerticalAlign = direction > 0 ? 'top' : 'bottom'; + textAlign = 'center'; + } else if (isRadianAroundZero(rotationDiff - PI)) { + // Label is inverse parallel with axis line. + textVerticalAlign = direction > 0 ? 'bottom' : 'top'; + textAlign = 'center'; + } else { + textVerticalAlign = 'middle'; + + if (rotationDiff > 0 && rotationDiff < PI) { + textAlign = direction > 0 ? 'right' : 'left'; + } else { + textAlign = direction > 0 ? 'left' : 'right'; + } + } + + return { + rotation: rotationDiff, + textAlign: textAlign, + textVerticalAlign: textVerticalAlign + }; + }; + + AxisBuilder.makeAxisEventDataBase = function (axisModel) { + var eventData = { + componentType: axisModel.mainType, + componentIndex: axisModel.componentIndex + }; + eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex; + return eventData; + }; + + AxisBuilder.isLabelSilent = function (axisModel) { + var tooltipOpt = axisModel.get('tooltip'); + return axisModel.get('silent') // Consider mouse cursor, add these restrictions. + || !(axisModel.get('triggerEvent') || tooltipOpt && tooltipOpt.show); + }; + + return AxisBuilder; + }(); // Sorted by dependency order. + + + var AXIS_BUILDER_AXIS_PART_NAMES = ['axisLine', 'axisTickLabelEstimate', 'axisTickLabelDetermine', 'axisName']; + var builders = { + axisLine: function (cfg, local, shared, axisModel, group, transformGroup, api) { + { + var ready = shared.ensureRecord(axisModel).ready; + assert(!ready.axisLine); + ready.axisLine = true; + } + var shown = axisModel.get(['axisLine', 'show']); + + if (shown === 'auto') { + shown = true; + + if (cfg.raw.axisLineAutoShow != null) { + shown = !!cfg.raw.axisLineAutoShow; + } + } + + if (!shown) { + return; + } + + var extent = axisModel.axis.getExtent(); + var matrix = transformGroup.transform; + var pt1 = [extent[0], 0]; + var pt2 = [extent[1], 0]; + var inverse = pt1[0] > pt2[0]; + + if (matrix) { + applyTransform$1(pt1, pt1, matrix); + applyTransform$1(pt2, pt2, matrix); + } + + var lineStyle = extend({ + lineCap: 'round' + }, axisModel.getModel(['axisLine', 'lineStyle']).getLineStyle()); + var pathBaseProp = { + strokeContainThreshold: cfg.raw.strokeContainThreshold || 5, + silent: true, + z2: 1, + style: lineStyle + }; + + if (axisModel.get(['axisLine', 'breakLine']) && axisModel.axis.scale.hasBreaks()) { + getAxisBreakHelper().buildAxisBreakLine(axisModel, group, transformGroup, pathBaseProp); + } else { + var line = new Line(extend({ + shape: { + x1: pt1[0], + y1: pt1[1], + x2: pt2[0], + y2: pt2[1] + } + }, pathBaseProp)); + subPixelOptimizeLine(line.shape, line.style.lineWidth); + line.anid = 'line'; + group.add(line); + } + + var arrows = axisModel.get(['axisLine', 'symbol']); + + if (arrows != null) { + var arrowSize = axisModel.get(['axisLine', 'symbolSize']); + + if (isString(arrows)) { + // Use the same arrow for start and end point + arrows = [arrows, arrows]; + } + + if (isString(arrowSize) || isNumber(arrowSize)) { + // Use the same size for width and height + arrowSize = [arrowSize, arrowSize]; + } + + var arrowOffset = normalizeSymbolOffset(axisModel.get(['axisLine', 'symbolOffset']) || 0, arrowSize); + var symbolWidth_1 = arrowSize[0]; + var symbolHeight_1 = arrowSize[1]; + each$4([{ + rotate: cfg.rotation + Math.PI / 2, + offset: arrowOffset[0], + r: 0 + }, { + rotate: cfg.rotation - Math.PI / 2, + offset: arrowOffset[1], + r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0]) + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1])) + }], function (point, index) { + if (arrows[index] !== 'none' && arrows[index] != null) { + var symbol = createSymbol(arrows[index], -symbolWidth_1 / 2, -symbolHeight_1 / 2, symbolWidth_1, symbolHeight_1, lineStyle.stroke, true); // Calculate arrow position with offset + + var r = point.r + point.offset; + var pt = inverse ? pt2 : pt1; + symbol.attr({ + rotation: point.rotate, + x: pt[0] + r * Math.cos(cfg.rotation), + y: pt[1] - r * Math.sin(cfg.rotation), + silent: true, + z2: 11 + }); + group.add(symbol); + } + }); + } + }, + + /** + * [CAUTION] This method can be called multiple times, following the change due to `resetCfg` called + * in size measurement. Thus this method should be idempotent, and should be performant. + */ + axisTickLabelEstimate: function (cfg, local, shared, axisModel, group, transformGroup, api, extraParams) { + { + var ready = shared.ensureRecord(axisModel).ready; + assert(!ready.axisTickLabelDetermine); + ready.axisTickLabelEstimate = true; + } + var needCallLayout = dealLastTickLabelResultReusable(local, group, extraParams); + + if (needCallLayout) { + layOutAxisTickLabel(cfg, local, shared, axisModel, group, transformGroup, api, AxisTickLabelComputingKind.estimate); + } + }, + + /** + * Finish axis tick label build. + * Can be only called once. + */ + axisTickLabelDetermine: function (cfg, local, shared, axisModel, group, transformGroup, api, extraParams) { + { + var ready = shared.ensureRecord(axisModel).ready; + ready.axisTickLabelDetermine = true; + } + var needCallLayout = dealLastTickLabelResultReusable(local, group, extraParams); + + if (needCallLayout) { + layOutAxisTickLabel(cfg, local, shared, axisModel, group, transformGroup, api, AxisTickLabelComputingKind.determine); + } + + var ticksEls = buildAxisMajorTicks(cfg, group, transformGroup, axisModel); + syncLabelIgnoreToMajorTicks(cfg, local.labelLayoutList, ticksEls); + buildAxisMinorTicks(cfg, group, transformGroup, axisModel, cfg.tickDirection); + }, + + /** + * [CAUTION] This method can be called multiple times, following the change due to `resetCfg` called + * in size measurement. Thus this method should be idempotent, and should be performant. + */ + axisName: function (cfg, local, shared, axisModel, group, transformGroup, api, extraParams) { + var sharedRecord = shared.ensureRecord(axisModel); + { + var ready = sharedRecord.ready; + assert(ready.axisTickLabelEstimate || ready.axisTickLabelDetermine); + ready.axisName = true; + } // Remove the existing name result created in estimation phase. + + if (local.nameEl) { + group.remove(local.nameEl); + local.nameEl = sharedRecord.nameLayout = sharedRecord.nameLocation = null; + } + + var name = cfg.axisName; + + if (!hasAxisName(name)) { + return; + } + + var nameLocation = cfg.nameLocation; + var nameDirection = cfg.nameDirection; + var textStyleModel = axisModel.getModel('nameTextStyle'); + var gap = axisModel.get('nameGap') || 0; + var extent = axisModel.axis.getExtent(); + var gapStartEndSignal = axisModel.axis.inverse ? -1 : 1; + var pos = new Point(0, 0); + var nameMoveDirVec = new Point(0, 0); + + if (nameLocation === 'start') { + pos.x = extent[0] - gapStartEndSignal * gap; + nameMoveDirVec.x = -gapStartEndSignal; + } else if (nameLocation === 'end') { + pos.x = extent[1] + gapStartEndSignal * gap; + nameMoveDirVec.x = gapStartEndSignal; + } else { + // 'middle' or 'center' + pos.x = (extent[0] + extent[1]) / 2; + pos.y = cfg.labelOffset + nameDirection * gap; + nameMoveDirVec.y = nameDirection; + } + + var mt = create(); + nameMoveDirVec.transform(rotate(mt, mt, cfg.rotation)); + var nameRotation = axisModel.get('nameRotate'); + + if (nameRotation != null) { + nameRotation = nameRotation * PI / 180; // To radian. + } + + var labelLayout; + var axisNameAvailableWidth; + + if (isNameLocationCenter(nameLocation)) { + labelLayout = AxisBuilder.innerTextLayout(cfg.rotation, nameRotation != null ? nameRotation : cfg.rotation, // Adapt to axis. + nameDirection); + } else { + labelLayout = endTextLayout(cfg.rotation, nameLocation, nameRotation || 0, extent); + axisNameAvailableWidth = cfg.raw.axisNameAvailableWidth; + + if (axisNameAvailableWidth != null) { + axisNameAvailableWidth = Math.abs(axisNameAvailableWidth / Math.sin(labelLayout.rotation)); + !isFinite(axisNameAvailableWidth) && (axisNameAvailableWidth = null); + } + } + + var textFont = textStyleModel.getFont(); + var truncateOpt = axisModel.get('nameTruncate', true) || {}; + var ellipsis = truncateOpt.ellipsis; + var maxWidth = retrieve(cfg.raw.nameTruncateMaxWidth, truncateOpt.maxWidth, axisNameAvailableWidth); + var nameMarginLevel = extraParams.nameMarginLevel || 0; + var textEl = new ZRText({ + x: pos.x, + y: pos.y, + rotation: labelLayout.rotation, + silent: AxisBuilder.isLabelSilent(axisModel), + style: createTextStyle$1(textStyleModel, { + text: name, + font: textFont, + overflow: 'truncate', + width: maxWidth, + ellipsis: ellipsis, + fill: textStyleModel.getTextColor() || axisModel.get(['axisLine', 'lineStyle', 'color']), + align: textStyleModel.get('align') || labelLayout.textAlign, + verticalAlign: textStyleModel.get('verticalAlign') || labelLayout.textVerticalAlign + }), + z2: 1 + }); + setTooltipConfig({ + el: textEl, + componentModel: axisModel, + itemName: name + }); + textEl.__fullText = name; // Id for animation + + textEl.anid = 'name'; + + if (axisModel.get('triggerEvent')) { + var eventData = AxisBuilder.makeAxisEventDataBase(axisModel); + eventData.targetType = 'axisName'; + eventData.name = name; + getECData(textEl).eventData = eventData; + } + + transformGroup.add(textEl); + textEl.updateTransform(); + local.nameEl = textEl; + var nameLayout = sharedRecord.nameLayout = ensureLabelLayoutWithGeometry({ + label: textEl, + priority: textEl.z2, + defaultAttr: { + ignore: textEl.ignore + }, + marginDefault: isNameLocationCenter(nameLocation) // Make axis name visually far from axis labels. + // (but not too aggressive, consider multiple small charts) + ? DEFAULT_CENTER_NAME_MARGIN_LEVELS[nameMarginLevel] // top/button margin is set to `0` to inserted the xAxis name into the indention + // above the axis labels to save space. (see example below.) + : DEFAULT_ENDS_NAME_MARGIN_LEVELS[nameMarginLevel] + }); + sharedRecord.nameLocation = nameLocation; + group.add(textEl); + textEl.decomposeTransform(); + + if (cfg.shouldNameMoveOverlap && nameLayout) { + var record = shared.ensureRecord(axisModel); + { + assert(record.labelInfoList); + } + shared.resolveAxisNameOverlap(cfg, shared, axisModel, nameLayout, nameMoveDirVec, record); + } + } + }; + + function layOutAxisTickLabel(cfg, local, shared, axisModel, group, transformGroup, api, kind) { + if (!axisLabelBuildResultExists(local)) { + buildAxisLabel(cfg, local, group, kind, axisModel, api); + } + + var labelLayoutList = local.labelLayoutList; + updateAxisLabelChangableProps(cfg, axisModel, labelLayoutList, transformGroup); + adjustBreakLabels(axisModel, cfg.rotation); + var optionHideOverlap = cfg.optionHideOverlap; + fixMinMaxLabelShow(axisModel, labelLayoutList, optionHideOverlap); + + if (optionHideOverlap) { + // This bit fixes the label overlap issue for the time chart. + // See https://github.com/apache/echarts/issues/14266 for more. + hideOverlap( // Filter the already ignored labels by the previous overlap resolving methods. + filter(labelLayoutList, function (layout) { + return layout && !layout.label.ignore; + })); + } // Always call it even this axis has no name, since it serves in overlapping detection + // and grid outerBounds on other axis. + + + resetOverlapRecordToShared(cfg, shared, axisModel, labelLayoutList); + } + + function endTextLayout(rotation, textPosition, textRotate, extent) { + var rotationDiff = remRadian(textRotate - rotation); + var textAlign; + var textVerticalAlign; + var inverse = extent[0] > extent[1]; + var onLeft = textPosition === 'start' && !inverse || textPosition !== 'start' && inverse; + + if (isRadianAroundZero(rotationDiff - PI / 2)) { + textVerticalAlign = onLeft ? 'bottom' : 'top'; + textAlign = 'center'; + } else if (isRadianAroundZero(rotationDiff - PI * 1.5)) { + textVerticalAlign = onLeft ? 'top' : 'bottom'; + textAlign = 'center'; + } else { + textVerticalAlign = 'middle'; + + if (rotationDiff < PI * 1.5 && rotationDiff > PI / 2) { + textAlign = onLeft ? 'left' : 'right'; + } else { + textAlign = onLeft ? 'right' : 'left'; + } + } + + return { + rotation: rotationDiff, + textAlign: textAlign, + textVerticalAlign: textVerticalAlign + }; + } + /** + * Assume `labelLayoutList` has no `label.ignore: true`. + * Assume `labelLayoutList` have been sorted by value ascending order. + */ + + + function fixMinMaxLabelShow(axisModel, labelLayoutList, optionHideOverlap) { + if (shouldShowAllLabels(axisModel.axis)) { + return; + } // FIXME + // Have not consider onBand yet, where tick els is more than label els. + // Assert no ignore in labels. + + + function deal(showMinMaxLabel, outmostLabelIdx, innerLabelIdx) { + var outmostLabelLayout = ensureLabelLayoutWithGeometry(labelLayoutList[outmostLabelIdx]); + var innerLabelLayout = ensureLabelLayoutWithGeometry(labelLayoutList[innerLabelIdx]); + + if (!outmostLabelLayout || !innerLabelLayout) { + return; + } + + if (showMinMaxLabel === false || outmostLabelLayout.suggestIgnore) { + ignoreEl(outmostLabelLayout.label); + return; + } + + if (innerLabelLayout.suggestIgnore) { + ignoreEl(innerLabelLayout.label); + return; + } // PENDING: Originally we thought `optionHideOverlap === false` means do not hide anything, + // since currently the bounding rect of text might not accurate enough and might slightly bigger, + // which causes false positive. But `optionHideOverlap: null/undfined` is falsy and likely + // be treated as false. + // In most fonts the glyph does not reach the boundary of the bounding rect. + // This is needed to avoid too aggressive to hide two elements that meet at the edge + // due to compact layout by the same bounding rect or OBB. + + + var touchThreshold = 0.1; // This treatment is for backward compatibility. And `!optionHideOverlap` implies that + // the user accepts the visual touch between adjacent labels, thus "hide min/max label" + // should be conservative, since the space might be sufficient in this case. + + if (!optionHideOverlap) { + var marginForce = [0, 0, 0, 0]; // Make a copy to apply `ignoreMargin`. + + outmostLabelLayout = newLabelLayoutWithGeometry({ + marginForce: marginForce + }, outmostLabelLayout); + innerLabelLayout = newLabelLayoutWithGeometry({ + marginForce: marginForce + }, innerLabelLayout); + } + + if (labelIntersect(outmostLabelLayout, innerLabelLayout, null, { + touchThreshold: touchThreshold + })) { + if (showMinMaxLabel) { + ignoreEl(innerLabelLayout.label); + } else { + ignoreEl(outmostLabelLayout.label); + } + } + } // If min or max are user set, we need to check + // If the tick on min(max) are overlap on their neighbour tick + // If they are overlapped, we need to hide the min(max) tick label + + + var showMinLabel = axisModel.get(['axisLabel', 'showMinLabel']); + var showMaxLabel = axisModel.get(['axisLabel', 'showMaxLabel']); + var labelsLen = labelLayoutList.length; + deal(showMinLabel, 0, 1); + deal(showMaxLabel, labelsLen - 1, labelsLen - 2); + } // PENDING: Is it necessary to display a tick while the corresponding label is ignored? + + + function syncLabelIgnoreToMajorTicks(cfg, labelLayoutList, tickEls) { + if (cfg.showMinorTicks) { + // It probably unreaasonable to hide major ticks when show minor ticks. + return; + } + + each$4(labelLayoutList, function (labelLayout) { + if (labelLayout && labelLayout.label.ignore) { + for (var idx = 0; idx < tickEls.length; idx++) { + var tickEl = tickEls[idx]; // Assume small array, linear search is fine for performance. + // PENDING: measure? + + var tickInner = getTickInner(tickEl); + var labelInner = getLabelInner(labelLayout.label); + + if (tickInner.tickValue != null && !tickInner.onBand && tickInner.tickValue === labelInner.tickValue) { + ignoreEl(tickEl); + return; + } + } + } + }); + } + + function ignoreEl(el) { + el && (el.ignore = true); + } + + function createTicks(ticksCoords, tickTransform, tickEndCoord, tickLineStyle, anidPrefix) { + var tickEls = []; + var pt1 = []; + var pt2 = []; + + for (var i = 0; i < ticksCoords.length; i++) { + var tickCoord = ticksCoords[i].coord; + pt1[0] = tickCoord; + pt1[1] = 0; + pt2[0] = tickCoord; + pt2[1] = tickEndCoord; + + if (tickTransform) { + applyTransform$1(pt1, pt1, tickTransform); + applyTransform$1(pt2, pt2, tickTransform); + } // Tick line, Not use group transform to have better line draw + + + var tickEl = new Line({ + shape: { + x1: pt1[0], + y1: pt1[1], + x2: pt2[0], + y2: pt2[1] + }, + style: tickLineStyle, + z2: 2, + autoBatch: true, + silent: true + }); + subPixelOptimizeLine(tickEl.shape, tickEl.style.lineWidth); + tickEl.anid = anidPrefix + '_' + ticksCoords[i].tickValue; + tickEls.push(tickEl); + var inner = getTickInner(tickEl); + inner.onBand = !!ticksCoords[i].onBand; + inner.tickValue = ticksCoords[i].tickValue; + } + + return tickEls; + } + + function buildAxisMajorTicks(cfg, group, transformGroup, axisModel) { + var axis = axisModel.axis; + var tickModel = axisModel.getModel('axisTick'); + var shown = tickModel.get('show'); + + if (shown === 'auto') { + shown = true; + + if (cfg.raw.axisTickAutoShow != null) { + shown = !!cfg.raw.axisTickAutoShow; + } + } + + if (!shown || axis.scale.isBlank()) { + return []; + } + + var lineStyleModel = tickModel.getModel('lineStyle'); + var tickEndCoord = cfg.tickDirection * tickModel.get('length'); + var ticksCoords = axis.getTicksCoords(); + var ticksEls = createTicks(ticksCoords, transformGroup.transform, tickEndCoord, defaults(lineStyleModel.getLineStyle(), { + stroke: axisModel.get(['axisLine', 'lineStyle', 'color']) + }), 'ticks'); + + for (var i = 0; i < ticksEls.length; i++) { + group.add(ticksEls[i]); + } + + return ticksEls; + } + + function buildAxisMinorTicks(cfg, group, transformGroup, axisModel, tickDirection) { + var axis = axisModel.axis; + var minorTickModel = axisModel.getModel('minorTick'); + + if (!cfg.showMinorTicks || axis.scale.isBlank()) { + return; + } + + var minorTicksCoords = axis.getMinorTicksCoords(); + + if (!minorTicksCoords.length) { + return; + } + + var lineStyleModel = minorTickModel.getModel('lineStyle'); + var tickEndCoord = tickDirection * minorTickModel.get('length'); + var minorTickLineStyle = defaults(lineStyleModel.getLineStyle(), defaults(axisModel.getModel('axisTick').getLineStyle(), { + stroke: axisModel.get(['axisLine', 'lineStyle', 'color']) + })); + + for (var i = 0; i < minorTicksCoords.length; i++) { + var minorTicksEls = createTicks(minorTicksCoords[i], transformGroup.transform, tickEndCoord, minorTickLineStyle, 'minorticks_' + i); + + for (var k = 0; k < minorTicksEls.length; k++) { + group.add(minorTicksEls[k]); + } + } + } // Return whether need to call `layOutAxisTickLabel` again. + + + function dealLastTickLabelResultReusable(local, group, extraParams) { + if (axisLabelBuildResultExists(local)) { + var axisLabelsCreationContext = local.axisLabelsCreationContext; + { + assert(local.labelGroup && axisLabelsCreationContext); + } + var noPxChangeTryDetermine = axisLabelsCreationContext.out.noPxChangeTryDetermine; + + if (extraParams.noPxChange) { + var canDetermine = true; + + for (var idx = 0; idx < noPxChangeTryDetermine.length; idx++) { + canDetermine = canDetermine && noPxChangeTryDetermine[idx](); + } + + if (canDetermine) { + return false; + } + } + + if (noPxChangeTryDetermine.length) { + // Remove the result of `buildAxisLabel` + group.remove(local.labelGroup); + axisLabelBuildResultSet(local, null, null, null); + } + } + + return true; + } + + function buildAxisLabel(cfg, local, group, kind, axisModel, api) { + var axis = axisModel.axis; + var show = retrieve(cfg.raw.axisLabelShow, axisModel.get(['axisLabel', 'show'])); + var labelGroup = new Group$2(); + group.add(labelGroup); + var axisLabelCreationCtx = createAxisLabelsComputingContext(kind); + + if (!show || axis.scale.isBlank()) { + axisLabelBuildResultSet(local, [], labelGroup, axisLabelCreationCtx); + return; + } + + var labelModel = axisModel.getModel('axisLabel'); + var labels = axis.getViewLabels(axisLabelCreationCtx); // Special label rotate. + + var labelRotation = (retrieve(cfg.raw.labelRotate, labelModel.get('rotate')) || 0) * PI / 180; + var labelLayout = AxisBuilder.innerTextLayout(cfg.rotation, labelRotation, cfg.labelDirection); + var rawCategoryData = axisModel.getCategories && axisModel.getCategories(true); + var labelEls = []; + var triggerEvent = axisModel.get('triggerEvent'); + var z2Min = Infinity; + var z2Max = -Infinity; + each$4(labels, function (labelItem, index) { + var _a; + + var tickValue = axis.scale.type === 'ordinal' ? axis.scale.getRawOrdinalNumber(labelItem.tickValue) : labelItem.tickValue; + var formattedLabel = labelItem.formattedLabel; + var rawLabel = labelItem.rawLabel; + var itemLabelModel = labelModel; + + if (rawCategoryData && rawCategoryData[tickValue]) { + var rawCategoryItem = rawCategoryData[tickValue]; + + if (isObject$2(rawCategoryItem) && rawCategoryItem.textStyle) { + itemLabelModel = new Model(rawCategoryItem.textStyle, labelModel, axisModel.ecModel); + } + } + + var textColor = itemLabelModel.getTextColor() || axisModel.get(['axisLine', 'lineStyle', 'color']); + var align = itemLabelModel.getShallow('align', true) || labelLayout.textAlign; + var alignMin = retrieve2(itemLabelModel.getShallow('alignMinLabel', true), align); + var alignMax = retrieve2(itemLabelModel.getShallow('alignMaxLabel', true), align); + var verticalAlign = itemLabelModel.getShallow('verticalAlign', true) || itemLabelModel.getShallow('baseline', true) || labelLayout.textVerticalAlign; + var verticalAlignMin = retrieve2(itemLabelModel.getShallow('verticalAlignMinLabel', true), verticalAlign); + var verticalAlignMax = retrieve2(itemLabelModel.getShallow('verticalAlignMaxLabel', true), verticalAlign); + var z2 = 10 + (((_a = labelItem.time) === null || _a === void 0 ? void 0 : _a.level) || 0); + z2Min = Math.min(z2Min, z2); + z2Max = Math.max(z2Max, z2); + var textEl = new ZRText({ + // --- transform props start --- + // All of the transform props MUST not be set here, but should be set in + // `updateAxisLabelChangableProps`, because they may change in estimation, + // and need to calculate based on global coord sys by `decomposeTransform`. + x: 0, + y: 0, + rotation: 0, + // --- transform props end --- + silent: AxisBuilder.isLabelSilent(axisModel), + z2: z2, + style: createTextStyle$1(itemLabelModel, { + text: formattedLabel, + align: index === 0 ? alignMin : index === labels.length - 1 ? alignMax : align, + verticalAlign: index === 0 ? verticalAlignMin : index === labels.length - 1 ? verticalAlignMax : verticalAlign, + fill: isFunction(textColor) ? textColor( // (1) In category axis with data zoom, tick is not the original + // index of axis.data. So tick should not be exposed to user + // in category axis. + // (2) Compatible with previous version, which always use formatted label as + // input. But in interval scale the formatted label is like '223,445', which + // maked user replace ','. So we modify it to return original val but remain + // it as 'string' to avoid error in replacing. + axis.type === 'category' ? rawLabel : axis.type === 'value' ? tickValue + '' : tickValue, index) : textColor + }) + }); + textEl.anid = 'label_' + tickValue; + var inner = getLabelInner(textEl); + inner["break"] = labelItem["break"]; + inner.tickValue = tickValue; + inner.layoutRotation = labelLayout.rotation; + setTooltipConfig({ + el: textEl, + componentModel: axisModel, + itemName: formattedLabel, + formatterParamsExtra: { + isTruncated: function () { + return textEl.isTruncated; + }, + value: rawLabel, + tickIndex: index + } + }); // Pack data for mouse event + + if (triggerEvent) { + var eventData = AxisBuilder.makeAxisEventDataBase(axisModel); + eventData.targetType = 'axisLabel'; + eventData.value = rawLabel; + eventData.tickIndex = index; + + if (labelItem["break"]) { + eventData["break"] = { + // type: labelItem.break.type, + start: labelItem["break"].parsedBreak.vmin, + end: labelItem["break"].parsedBreak.vmax + }; + } + + if (axis.type === 'category') { + eventData.dataIndex = tickValue; + } + + getECData(textEl).eventData = eventData; + + if (labelItem["break"]) { + addBreakEventHandler(axisModel, api, textEl, labelItem["break"]); + } + } + + labelEls.push(textEl); + labelGroup.add(textEl); + }); + var labelLayoutList = map$1(labelEls, function (label) { + return { + label: label, + priority: getLabelInner(label)["break"] ? label.z2 + (z2Max - z2Min + 1) // Make break labels be highest priority. + : label.z2, + defaultAttr: { + ignore: label.ignore + } + }; + }); + axisLabelBuildResultSet(local, labelLayoutList, labelGroup, axisLabelCreationCtx); + } // Indicate that `layOutAxisTickLabel` has been called. + + + function axisLabelBuildResultExists(local) { + return !!local.labelLayoutList; + } + + function axisLabelBuildResultSet(local, labelLayoutList, labelGroup, axisLabelsCreationContext) { + // Ensure the same lifetime. + local.labelLayoutList = labelLayoutList; + local.labelGroup = labelGroup; + local.axisLabelsCreationContext = axisLabelsCreationContext; + } + + function updateAxisLabelChangableProps(cfg, axisModel, labelLayoutList, transformGroup) { + var labelMargin = axisModel.get(['axisLabel', 'margin']); + each$4(labelLayoutList, function (layout, idx) { + var geometry = ensureLabelLayoutWithGeometry(layout); + + if (!geometry) { + return; + } + + var labelEl = geometry.label; + var inner = getLabelInner(labelEl); // See the comment in `suggestIgnore`. + + geometry.suggestIgnore = labelEl.ignore; // Currently no `ignore:true` is set in `buildAxisLabel` + // But `ignore:true` may be set subsequently for overlap handling, thus reset it here. + + labelEl.ignore = false; + copyTransform(_tmpLayoutEl, _tmpLayoutElReset); + _tmpLayoutEl.x = axisModel.axis.dataToCoord(inner.tickValue); + _tmpLayoutEl.y = cfg.labelOffset + cfg.labelDirection * labelMargin; + _tmpLayoutEl.rotation = inner.layoutRotation; + transformGroup.add(_tmpLayoutEl); + + _tmpLayoutEl.updateTransform(); + + transformGroup.remove(_tmpLayoutEl); + + _tmpLayoutEl.decomposeTransform(); + + copyTransform(labelEl, _tmpLayoutEl); + labelEl.markRedraw(); + setLabelLayoutDirty(geometry, true); + ensureLabelLayoutWithGeometry(geometry); + }); + } + + var _tmpLayoutEl = new Rect(); + + var _tmpLayoutElReset = new Rect(); + + function hasAxisName(axisName) { + return !!axisName; + } + + function addBreakEventHandler(axisModel, api, textEl, visualBreak) { + textEl.on('click', function (params) { + var payload = { + type: AXIS_BREAK_EXPAND_ACTION_TYPE, + breaks: [{ + start: visualBreak.parsedBreak.breakOption.start, + end: visualBreak.parsedBreak.breakOption.end + }] + }; + payload[axisModel.axis.dim + "AxisIndex"] = axisModel.componentIndex; + api.dispatchAction(payload); + }); + } + + function adjustBreakLabels(axisModel, axisRotation, labelLayoutList) { + { + return; + } + } + /** + * [__CAUTION__] + * MUST guarantee: if only the input `rect` and `axis.extent` changed, + * only `layout.position` changes. + * This character is replied on `grid.contain` calculation in `AxisBuilder`. + * @see updateCartesianAxisViewCommonPartBuilder + * + * Can only be called after coordinate system creation stage. + * (Can be called before coordinate system update stage). + */ + + + function layout(rect, axisModel, opt) { + opt = opt || {}; + var axis = axisModel.axis; + var layout = {}; + var otherAxisOnZeroOf = axis.getAxesOnZeroOf()[0]; + var rawAxisPosition = axis.position; + var axisPosition = otherAxisOnZeroOf ? 'onZero' : rawAxisPosition; + var axisDim = axis.dim; + var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height]; + var idx = { + left: 0, + right: 1, + top: 0, + bottom: 1, + onZero: 2 + }; + var axisOffset = axisModel.get('offset') || 0; + var posBound = axisDim === 'x' ? [rectBound[2] - axisOffset, rectBound[3] + axisOffset] : [rectBound[0] - axisOffset, rectBound[1] + axisOffset]; + + if (otherAxisOnZeroOf) { + var onZeroCoord = otherAxisOnZeroOf.toGlobalCoord(otherAxisOnZeroOf.dataToCoord(0)); + posBound[idx.onZero] = Math.max(Math.min(onZeroCoord, posBound[1]), posBound[0]); + } // Axis position + + + layout.position = [axisDim === 'y' ? posBound[idx[axisPosition]] : rectBound[0], axisDim === 'x' ? posBound[idx[axisPosition]] : rectBound[3]]; // Axis rotation + + layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1); // Tick and label direction, x y is axisDim + + var dirMap = { + top: -1, + bottom: 1, + left: -1, + right: 1 + }; + layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition]; + layout.labelOffset = otherAxisOnZeroOf ? posBound[idx[rawAxisPosition]] - posBound[idx.onZero] : 0; + + if (axisModel.get(['axisTick', 'inside'])) { + layout.tickDirection = -layout.tickDirection; + } + + if (retrieve(opt.labelInside, axisModel.get(['axisLabel', 'inside']))) { + layout.labelDirection = -layout.labelDirection; + } // Special label rotation + + + var labelRotate = axisModel.get(['axisLabel', 'rotate']); + layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate; // Over splitLine and splitArea + + layout.z2 = 1; + return layout; + } + /** + * Note: If pie (or other similar series) use cartesian2d, here + * option `seriesModel.get('coordinateSystem') === 'cartesian2d'` + * and `seriesModel.coordinateSystem !== cartesian2dCoordSysInstance` + * and `seriesModel.boxCoordinateSystem === cartesian2dCoordSysInstance`, + * the logic below is probably wrong, therefore skip it temporarily. + */ + + + function isCartesian2DInjectedAsDataCoordSys(seriesModel) { + return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d'; + } + + function findAxisModels(seriesModel) { + var axisModelMap = { + xAxisModel: null, + yAxisModel: null + }; + each$4(axisModelMap, function (v, key) { + var axisType = key.replace(/Model$/, ''); + var axisModel = seriesModel.getReferringComponents(axisType, SINGLE_REFERRING).models[0]; + { + if (!axisModel) { + throw new Error(axisType + ' "' + retrieve3(seriesModel.get(axisType + 'Index'), seriesModel.get(axisType + 'Id'), 0) + '" not found'); + } + } + axisModelMap[key] = axisModel; + }); + return axisModelMap; + } + + function createCartesianAxisViewCommonPartBuilder(gridRect, cartesians, axisModel, api, ctx, defaultNameMoveOverlap) { + var layoutResult = layout(gridRect, axisModel); + var axisLineAutoShow = false; + var axisTickAutoShow = false; // Not show axisTick or axisLine if other axis is category / time + + for (var i = 0; i < cartesians.length; i++) { + if (isIntervalOrLogScale(cartesians[i].getOtherAxis(axisModel.axis).scale)) { + // Still show axis tick or axisLine if other axis is value / log + axisLineAutoShow = axisTickAutoShow = true; + + if (axisModel.axis.type === 'category' && axisModel.axis.onBand) { + axisTickAutoShow = false; + } + } + } + + layoutResult.axisLineAutoShow = axisLineAutoShow; + layoutResult.axisTickAutoShow = axisTickAutoShow; + layoutResult.defaultNameMoveOverlap = defaultNameMoveOverlap; + return new AxisBuilder(axisModel, api, layoutResult, ctx); + } + + function updateCartesianAxisViewCommonPartBuilder(axisBuilder, gridRect, axisModel) { + var newRaw = layout(gridRect, axisModel); + { + var oldRaw_1 = axisBuilder.__getRawCfg(); + + each$4(keys(newRaw), function (prop) { + if (prop !== 'position' && prop !== 'labelOffset') { + assert(newRaw[prop] === oldRaw_1[prop]); + } + }); + } + axisBuilder.updateCfg(newRaw); + } + + function alignScaleTicks(scale, axisModel, alignToScale) { + var _a; + + var intervalScaleProto = IntervalScale.prototype; // NOTE: There is a precondition for log scale here: + // In log scale we store _interval and _extent of exponent value. + // So if we use the method of InternalScale to set/get these data. + // It process the exponent value, which is linear and what we want here. + + var alignToTicks = intervalScaleProto.getTicks.call(alignToScale); + var alignToNicedTicks = intervalScaleProto.getTicks.call(alignToScale, { + expandToNicedExtent: true + }); + var alignToSplitNumber = alignToTicks.length - 1; + var alignToInterval = intervalScaleProto.getInterval.call(alignToScale); + var scaleExtent = getScaleExtent(scale, axisModel); + var rawExtent = scaleExtent.extent; + var isMinFixed = scaleExtent.fixMin; + var isMaxFixed = scaleExtent.fixMax; + + if (scale.type === 'log') { + rawExtent = logTransform(scale.base, rawExtent, true); + } + + scale.setBreaksFromOption(retrieveAxisBreaksOption(axisModel)); + scale.setExtent(rawExtent[0], rawExtent[1]); + scale.calcNiceExtent({ + splitNumber: alignToSplitNumber, + fixMin: isMinFixed, + fixMax: isMaxFixed + }); + var extent = intervalScaleProto.getExtent.call(scale); // Need to update the rawExtent. + // Because value in rawExtent may be not parsed. e.g. 'dataMin', 'dataMax' + + if (isMinFixed) { + rawExtent[0] = extent[0]; + } + + if (isMaxFixed) { + rawExtent[1] = extent[1]; + } + + var interval = intervalScaleProto.getInterval.call(scale); + var min = rawExtent[0]; + var max = rawExtent[1]; + + if (isMinFixed && isMaxFixed) { + // User set min, max, divide to get new interval + interval = (max - min) / alignToSplitNumber; + } else if (isMinFixed) { + max = rawExtent[0] + interval * alignToSplitNumber; // User set min, expand extent on the other side + + while (max < rawExtent[1] && isFinite(max) && isFinite(rawExtent[1])) { + interval = increaseInterval(interval); + max = rawExtent[0] + interval * alignToSplitNumber; + } + } else if (isMaxFixed) { + // User set max, expand extent on the other side + min = rawExtent[1] - interval * alignToSplitNumber; + + while (min > rawExtent[0] && isFinite(min) && isFinite(rawExtent[0])) { + interval = increaseInterval(interval); + min = rawExtent[1] - interval * alignToSplitNumber; + } + } else { + var nicedSplitNumber = scale.getTicks().length - 1; + + if (nicedSplitNumber > alignToSplitNumber) { + interval = increaseInterval(interval); + } + + var range = interval * alignToSplitNumber; + max = Math.ceil(rawExtent[1] / interval) * interval; + min = round$1(max - range); // Not change the result that crossing zero. + + if (min < 0 && rawExtent[0] >= 0) { + min = 0; + max = round$1(range); + } else if (max > 0 && rawExtent[1] <= 0) { + max = 0; + min = -round$1(range); + } + } // Adjust min, max based on the extent of alignTo. When min or max is set in alignTo scale + + + var t0 = (alignToTicks[0].value - alignToNicedTicks[0].value) / alignToInterval; + var t1 = (alignToTicks[alignToSplitNumber].value - alignToNicedTicks[alignToSplitNumber].value) / alignToInterval; // NOTE: Must in setExtent -> setInterval -> setNiceExtent order. + + intervalScaleProto.setExtent.call(scale, min + interval * t0, max + interval * t1); + intervalScaleProto.setInterval.call(scale, interval); + + if (t0 || t1) { + intervalScaleProto.setNiceExtent.call(scale, min + interval, max - interval); + } + + { + var ticks = intervalScaleProto.getTicks.call(scale); + + if (ticks[1] && (!isValueNice(interval) || getPrecisionSafe(ticks[1].value) > getPrecisionSafe(interval))) { + warn("The ticks may be not readable when set min: " + axisModel.get('min') + ", max: " + axisModel.get('max') + (" and alignTicks: true. (" + ((_a = axisModel.axis) === null || _a === void 0 ? void 0 : _a.dim) + "AxisIndex: " + axisModel.componentIndex + ")"), true); + } + } + } // margin is [top, right, bottom, left] + + + var XY_TO_MARGIN_IDX = [[3, 1], [0, 2] // xyIdx 1 => 'y' + ]; + + var Grid = + /** @class */ + function () { + function Grid(gridModel, ecModel, api) { + // FIXME:TS where used (different from registered type 'cartesian2d')? + this.type = 'grid'; + this._coordsMap = {}; + this._coordsList = []; + this._axesMap = {}; + this._axesList = []; + this.axisPointerEnabled = true; + this.dimensions = cartesian2DDimensions; + + this._initCartesian(gridModel, ecModel, api); + + this.model = gridModel; + } + + Grid.prototype.getRect = function () { + return this._rect; + }; + + Grid.prototype.update = function (ecModel, api) { + var axesMap = this._axesMap; + + this._updateScale(ecModel, this.model); + + function updateAxisTicks(axes) { + var alignTo; // Axis is added in order of axisIndex. + + var axesIndices = keys(axes); + var len = axesIndices.length; + + if (!len) { + return; + } + + var axisNeedsAlign = []; // Process once and calculate the ticks for those don't use alignTicks. + + for (var i = len - 1; i >= 0; i--) { + var idx = +axesIndices[i]; // Convert to number. + + var axis = axes[idx]; + var model = axis.model; + var scale = axis.scale; + + if ( // Only value and log axis without interval support alignTicks. + isIntervalOrLogScale(scale) && model.get('alignTicks') && model.get('interval') == null) { + axisNeedsAlign.push(axis); + } else { + niceScaleExtent(scale, model); + + if (isIntervalOrLogScale(scale)) { + // Can only align to interval or log axis. + alignTo = axis; + } + } + } // All axes has set alignTicks. Pick the first one. + // PENDING. Should we find the axis that both set interval, min, max and align to this one? + + + if (axisNeedsAlign.length) { + if (!alignTo) { + alignTo = axisNeedsAlign.pop(); + niceScaleExtent(alignTo.scale, alignTo.model); + } + + each$4(axisNeedsAlign, function (axis) { + alignScaleTicks(axis.scale, axis.model, alignTo.scale); + }); + } + } + + updateAxisTicks(axesMap.x); + updateAxisTicks(axesMap.y); // Key: axisDim_axisIndex, value: boolean, whether onZero target. + + var onZeroRecords = {}; + each$4(axesMap.x, function (xAxis) { + fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords); + }); + each$4(axesMap.y, function (yAxis) { + fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords); + }); // Resize again if containLabel is enabled + // FIXME It may cause getting wrong grid size in data processing stage + + this.resize(this.model, api); + }; + /** + * Resize the grid. + * + * [NOTE] + * If both "grid.containLabel/grid.contain" and pixel-required-data-processing (such as, "dataSampling") + * exist, circular dependency occurs in logic. + * The final compromised sequence is: + * 1. Calculate "axis.extent" (pixel extent) and AffineTransform based on only "grid layout options". + * Not accurate if "grid.containLabel/grid.contain" is required, but it is a compromise to avoid + * circular dependency. + * 2. Perform "series data processing" (where "dataSampling" requires "axis.extent"). + * 3. Calculate "scale.extent" (data extent) based on "processed series data". + * 4. Modify "axis.extent" for "grid.containLabel/grid.contain": + * 4.1. Calculate "axis labels" based on "scale.extent". + * 4.2. Modify "axis.extent" by the bounding rects of "axis labels and names". + */ + + + Grid.prototype.resize = function (gridModel, api, beforeDataProcessing) { + var layoutRef = createBoxLayoutReference(gridModel, api); + var gridRect = this._rect = getLayoutRect(gridModel.getBoxLayoutParams(), layoutRef.refContainer); // PENDING: whether to support that if the input `coord` is out of the base coord sys, + // do not render anything. At present, the behavior is undefined. + + var axesMap = this._axesMap; + var coordsList = this._coordsList; + var optionContainLabel = gridModel.get('containLabel'); // No `.get(, true)` for backward compat. + + updateAllAxisExtentTransByGridRect(axesMap, gridRect); + + if (!beforeDataProcessing) { + var axisBuilderSharedCtx = createAxisBiulders(gridRect, coordsList, axesMap, optionContainLabel, api); + var noPxChange = void 0; + + if (optionContainLabel) { + { + { + log('Specified `grid.containLabel` but no `use(LegacyGridContainLabel)`;' + 'use `grid.outerBounds` instead.', true); + } + noPxChange = layOutGridByOuterBounds(gridRect.clone(), 'axisLabel', null, gridRect, axesMap, axisBuilderSharedCtx, layoutRef); + } + } else { + var _a = prepareOuterBounds(gridModel, gridRect, layoutRef), + outerBoundsRect = _a.outerBoundsRect, + parsedOuterBoundsContain = _a.parsedOuterBoundsContain, + outerBoundsClamp = _a.outerBoundsClamp; + + if (outerBoundsRect) { + // console.time('layOutGridByOuterBounds'); + noPxChange = layOutGridByOuterBounds(outerBoundsRect, parsedOuterBoundsContain, outerBoundsClamp, gridRect, axesMap, axisBuilderSharedCtx, layoutRef); // console.timeEnd('layOutGridByOuterBounds'); + } + } // console.time('buildAxesView_determine'); + + + createOrUpdateAxesView(gridRect, axesMap, AxisTickLabelComputingKind.determine, null, noPxChange, layoutRef); // console.timeEnd('buildAxesView_determine'); + } // End of beforeDataProcessing + + + each$4(this._coordsList, function (coord) { + // Calculate affine matrix to accelerate the data to point transform. + // If all the axes scales are time or value. + coord.calcAffineTransform(); + }); + }; + + Grid.prototype.getAxis = function (dim, axisIndex) { + var axesMapOnDim = this._axesMap[dim]; + + if (axesMapOnDim != null) { + return axesMapOnDim[axisIndex || 0]; + } + }; + + Grid.prototype.getAxes = function () { + return this._axesList.slice(); + }; + + Grid.prototype.getCartesian = function (xAxisIndex, yAxisIndex) { + if (xAxisIndex != null && yAxisIndex != null) { + var key = 'x' + xAxisIndex + 'y' + yAxisIndex; + return this._coordsMap[key]; + } + + if (isObject$2(xAxisIndex)) { + yAxisIndex = xAxisIndex.yAxisIndex; + xAxisIndex = xAxisIndex.xAxisIndex; + } + + for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) { + if (coordList[i].getAxis('x').index === xAxisIndex || coordList[i].getAxis('y').index === yAxisIndex) { + return coordList[i]; + } + } + }; + + Grid.prototype.getCartesians = function () { + return this._coordsList.slice(); + }; + /** + * @implements + */ + + + Grid.prototype.convertToPixel = function (ecModel, finder, value) { + var target = this._findConvertTarget(finder); + + return target.cartesian ? target.cartesian.dataToPoint(value) : target.axis ? target.axis.toGlobalCoord(target.axis.dataToCoord(value)) : null; + }; + /** + * @implements + */ + + + Grid.prototype.convertFromPixel = function (ecModel, finder, value) { + var target = this._findConvertTarget(finder); + + return target.cartesian ? target.cartesian.pointToData(value) : target.axis ? target.axis.coordToData(target.axis.toLocalCoord(value)) : null; + }; + + Grid.prototype._findConvertTarget = function (finder) { + var seriesModel = finder.seriesModel; + var xAxisModel = finder.xAxisModel || seriesModel && seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0]; + var yAxisModel = finder.yAxisModel || seriesModel && seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[0]; + var gridModel = finder.gridModel; + var coordsList = this._coordsList; + var cartesian; + var axis; + + if (seriesModel) { + cartesian = seriesModel.coordinateSystem; + indexOf(coordsList, cartesian) < 0 && (cartesian = null); + } else if (xAxisModel && yAxisModel) { + cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex); + } else if (xAxisModel) { + axis = this.getAxis('x', xAxisModel.componentIndex); + } else if (yAxisModel) { + axis = this.getAxis('y', yAxisModel.componentIndex); + } // Lowest priority. + else if (gridModel) { + var grid = gridModel.coordinateSystem; + + if (grid === this) { + cartesian = this._coordsList[0]; + } + } + + return { + cartesian: cartesian, + axis: axis + }; + }; + /** + * @implements + */ + + + Grid.prototype.containPoint = function (point) { + var coord = this._coordsList[0]; + + if (coord) { + return coord.containPoint(point); + } + }; + /** + * Initialize cartesian coordinate systems + */ + + + Grid.prototype._initCartesian = function (gridModel, ecModel, api) { + var _this = this; + + var grid = this; + var axisPositionUsed = { + left: false, + right: false, + top: false, + bottom: false + }; + var axesMap = { + x: {}, + y: {} + }; + var axesCount = { + x: 0, + y: 0 + }; // Create axis + + ecModel.eachComponent('xAxis', createAxisCreator('x'), this); + ecModel.eachComponent('yAxis', createAxisCreator('y'), this); + + if (!axesCount.x || !axesCount.y) { + // Roll back when there no either x or y axis + this._axesMap = {}; + this._axesList = []; + return; + } + + this._axesMap = axesMap; // Create cartesian2d + + each$4(axesMap.x, function (xAxis, xAxisIndex) { + each$4(axesMap.y, function (yAxis, yAxisIndex) { + var key = 'x' + xAxisIndex + 'y' + yAxisIndex; + var cartesian = new Cartesian2D(key); + cartesian.master = _this; + cartesian.model = gridModel; + _this._coordsMap[key] = cartesian; + + _this._coordsList.push(cartesian); + + cartesian.addAxis(xAxis); + cartesian.addAxis(yAxis); + }); + }); + + function createAxisCreator(dimName) { + return function (axisModel, idx) { + if (!isAxisUsedInTheGrid(axisModel, gridModel)) { + return; + } + + var axisPosition = axisModel.get('position'); + + if (dimName === 'x') { + // Fix position + if (axisPosition !== 'top' && axisPosition !== 'bottom') { + // Default bottom of X + axisPosition = axisPositionUsed.bottom ? 'top' : 'bottom'; + } + } else { + // Fix position + if (axisPosition !== 'left' && axisPosition !== 'right') { + // Default left of Y + axisPosition = axisPositionUsed.left ? 'right' : 'left'; + } + } + + axisPositionUsed[axisPosition] = true; + var axis = new Axis2D(dimName, createScaleByModel(axisModel), [0, 0], axisModel.get('type'), axisPosition); + var isCategory = axis.type === 'category'; + axis.onBand = isCategory && axisModel.get('boundaryGap'); + axis.inverse = axisModel.get('inverse'); // Inject axis into axisModel + + axisModel.axis = axis; // Inject axisModel into axis + + axis.model = axisModel; // Inject grid info axis + + axis.grid = grid; // Index of axis, can be used as key + + axis.index = idx; + + grid._axesList.push(axis); + + axesMap[dimName][idx] = axis; + axesCount[dimName]++; + }; + } + }; + /** + * Update cartesian properties from series. + */ + + + Grid.prototype._updateScale = function (ecModel, gridModel) { + // Reset scale + each$4(this._axesList, function (axis) { + axis.scale.setExtent(Infinity, -Infinity); + + if (axis.type === 'category') { + var categorySortInfo = axis.model.get('categorySortInfo'); + axis.scale.setSortInfo(categorySortInfo); + } + }); + ecModel.eachSeries(function (seriesModel) { + // If pie (or other similar series) use cartesian2d, the unionExtent logic below is + // wrong, therefore skip it temporarily. See also in `defaultAxisExtentFromData.ts`. + // TODO: support union extent in this case. + if (isCartesian2DInjectedAsDataCoordSys(seriesModel)) { + var axesModelMap = findAxisModels(seriesModel); + var xAxisModel = axesModelMap.xAxisModel; + var yAxisModel = axesModelMap.yAxisModel; + + if (!isAxisUsedInTheGrid(xAxisModel, gridModel) || !isAxisUsedInTheGrid(yAxisModel, gridModel)) { + return; + } + + var cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex); + var data = seriesModel.getData(); + var xAxis = cartesian.getAxis('x'); + var yAxis = cartesian.getAxis('y'); + unionExtent(data, xAxis); + unionExtent(data, yAxis); + } + }, this); + + function unionExtent(data, axis) { + each$4(getDataDimensionsOnAxis(data, axis.dim), function (dim) { + axis.scale.unionExtentFromData(data, dim); + }); + } + }; + /** + * @param dim 'x' or 'y' or 'auto' or null/undefined + */ + + + Grid.prototype.getTooltipAxes = function (dim) { + var baseAxes = []; + var otherAxes = []; + each$4(this.getCartesians(), function (cartesian) { + var baseAxis = dim != null && dim !== 'auto' ? cartesian.getAxis(dim) : cartesian.getBaseAxis(); + var otherAxis = cartesian.getOtherAxis(baseAxis); + indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis); + indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis); + }); + return { + baseAxes: baseAxes, + otherAxes: otherAxes + }; + }; + + Grid.create = function (ecModel, api) { + var grids = []; + ecModel.eachComponent('grid', function (gridModel, idx) { + var grid = new Grid(gridModel, ecModel, api); + grid.name = 'grid_' + idx; // dataSampling requires axis extent, so resize + // should be performed in create stage. + + grid.resize(gridModel, api, true); + gridModel.coordinateSystem = grid; + grids.push(grid); + }); // Inject the coordinateSystems into seriesModel + + ecModel.eachSeries(function (seriesModel) { + injectCoordSysByOption({ + targetModel: seriesModel, + coordSysType: 'cartesian2d', + coordSysProvider: coordSysProvider + }); + + function coordSysProvider() { + var axesModelMap = findAxisModels(seriesModel); + var xAxisModel = axesModelMap.xAxisModel; + var yAxisModel = axesModelMap.yAxisModel; + var gridModel = xAxisModel.getCoordSysModel(); + { + if (!gridModel) { + throw new Error('Grid "' + retrieve3(xAxisModel.get('gridIndex'), xAxisModel.get('gridId'), 0) + '" not found'); + } + + if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) { + throw new Error('xAxis and yAxis must use the same grid'); + } + } + var grid = gridModel.coordinateSystem; + return grid.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex); + } + }); + return grids; + }; // For deciding which dimensions to use when creating list data + + + Grid.dimensions = cartesian2DDimensions; + return Grid; + }(); + /** + * Check if the axis is used in the specified grid. + */ + + + function isAxisUsedInTheGrid(axisModel, gridModel) { + return axisModel.getCoordSysModel() === gridModel; + } + + function fixAxisOnZero(axesMap, otherAxisDim, axis, // Key: see `getOnZeroRecordKey` + onZeroRecords) { + axis.getAxesOnZeroOf = function () { + // TODO: onZero of multiple axes. + return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : []; + }; // onZero can not be enabled in these two situations: + // 1. When any other axis is a category axis. + // 2. When no axis is cross 0 point. + + + var otherAxes = axesMap[otherAxisDim]; + var otherAxisOnZeroOf; + var axisModel = axis.model; + var onZero = axisModel.get(['axisLine', 'onZero']); + var onZeroAxisIndex = axisModel.get(['axisLine', 'onZeroAxisIndex']); + + if (!onZero) { + return; + } // If target axis is specified. + + + if (onZeroAxisIndex != null) { + if (canOnZeroToAxis(otherAxes[onZeroAxisIndex])) { + otherAxisOnZeroOf = otherAxes[onZeroAxisIndex]; + } + } else { + // Find the first available other axis. + for (var idx in otherAxes) { + if (otherAxes.hasOwnProperty(idx) && canOnZeroToAxis(otherAxes[idx]) // Consider that two Y axes on one value axis, + // if both onZero, the two Y axes overlap. + && !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]) { + otherAxisOnZeroOf = otherAxes[idx]; + break; + } + } + } + + if (otherAxisOnZeroOf) { + onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true; + } + + function getOnZeroRecordKey(axis) { + return axis.dim + '_' + axis.index; + } + } + + function canOnZeroToAxis(axis) { + return axis && axis.type !== 'category' && axis.type !== 'time' && ifAxisCrossZero(axis); + } + + function updateAxisTransform(axis, coordBase) { + var axisExtent = axis.getExtent(); + var axisExtentSum = axisExtent[0] + axisExtent[1]; // Fast transform + + axis.toGlobalCoord = axis.dim === 'x' ? function (coord) { + return coord + coordBase; + } : function (coord) { + return axisExtentSum - coord + coordBase; + }; + axis.toLocalCoord = axis.dim === 'x' ? function (coord) { + return coord - coordBase; + } : function (coord) { + return axisExtentSum - coord + coordBase; + }; + } + + function updateAllAxisExtentTransByGridRect(axesMap, gridRect) { + each$4(axesMap.x, function (axis) { + return updateAxisExtentTransByGridRect(axis, gridRect.x, gridRect.width); + }); + each$4(axesMap.y, function (axis) { + return updateAxisExtentTransByGridRect(axis, gridRect.y, gridRect.height); + }); + } + + function updateAxisExtentTransByGridRect(axis, gridXY, gridWH) { + var extent = [0, gridWH]; + var idx = axis.inverse ? 1 : 0; + axis.setExtent(extent[idx], extent[1 - idx]); + updateAxisTransform(axis, gridXY); + } // Return noPxChange. + + + function layOutGridByOuterBounds(outerBoundsRect, outerBoundsContain, outerBoundsClamp, gridRect, axesMap, axisBuilderSharedCtx, layoutRef) { + { + assert(outerBoundsContain === 'all' || outerBoundsContain === 'axisLabel'); + } // Assume `updateAllAxisExtentTransByGridRect` has been performed once before this call. + // [NOTE]: + // - The bounding rect of the axis elements might be sensitve to variations in `axis.extent` due to strategies + // like hideOverlap/moveOverlap. @see the comment in `LabelLayoutBase['suggestIgnore']`. + // - The final `gridRect` might be slightly smaller than the ideally expected result if labels are giant and + // get hidden due to overlapping. More iterations could improve precision, but not performant. We consider + // the current result acceptable, since no alignment among charts can be guaranteed when using this feature. + + createOrUpdateAxesView(gridRect, axesMap, AxisTickLabelComputingKind.estimate, outerBoundsContain, false, layoutRef); + var margin = [0, 0, 0, 0]; + fillLabelNameOverflowOnOneDimension(0); + fillLabelNameOverflowOnOneDimension(1); // If axis is blank, no label can be used to detect overflow. + // gridRect itself should not overflow. + + fillMarginOnOneDimension(gridRect, 0, NaN); + fillMarginOnOneDimension(gridRect, 1, NaN); + var noPxChange = find(margin, function (item) { + return item > 0; + }) == null; + expandOrShrinkRect(gridRect, margin, true, true, outerBoundsClamp); + updateAllAxisExtentTransByGridRect(axesMap, gridRect); + return noPxChange; + + function fillLabelNameOverflowOnOneDimension(xyIdx) { + each$4(axesMap[XY$1[xyIdx]], function (axis) { + if (!shouldAxisShow(axis.model)) { + return; + } // FIXME: zr Group.union may wrongly union (0, 0, 0, 0) and not performant. + // unionRect.union(axis.axisBuilder.group.getBoundingRect()); + // If ussing Group.getBoundingRect to calculate shrink space, it is not strictly accurate when + // the outermost label is ignored and the secondary label is very long and contribute to the + // union extension: + // -|---|---|---| + // 1,000,000,000 + // Therefore we calculate them one by one. + // Also considered axis may be blank or no labels. + + + var sharedRecord = axisBuilderSharedCtx.ensureRecord(axis.model); + var labelInfoList = sharedRecord.labelInfoList; + + if (labelInfoList) { + for (var idx = 0; idx < labelInfoList.length; idx++) { + var labelInfo = labelInfoList[idx]; + var proportion = axis.scale.normalize(getLabelInner(labelInfo.label).tickValue); + proportion = xyIdx === 1 ? 1 - proportion : proportion; // xAxis use proportion on x, yAxis use proprotion on y, otherwise not. + + fillMarginOnOneDimension(labelInfo.rect, xyIdx, proportion); + fillMarginOnOneDimension(labelInfo.rect, 1 - xyIdx, NaN); + } + } + + var nameLayout = sharedRecord.nameLayout; + + if (nameLayout) { + var proportion = isNameLocationCenter(sharedRecord.nameLocation) ? 0.5 : NaN; + fillMarginOnOneDimension(nameLayout.rect, xyIdx, proportion); + fillMarginOnOneDimension(nameLayout.rect, 1 - xyIdx, NaN); + } + }); + } + + function fillMarginOnOneDimension(itemRect, xyIdx, proportion // NaN mean no use proportion + ) { + var overflow1 = outerBoundsRect[XY$1[xyIdx]] - itemRect[XY$1[xyIdx]]; + var overflow2 = itemRect[WH$1[xyIdx]] + itemRect[XY$1[xyIdx]] - (outerBoundsRect[WH$1[xyIdx]] + outerBoundsRect[XY$1[xyIdx]]); + overflow1 = applyProportion(overflow1, 1 - proportion); + overflow2 = applyProportion(overflow2, proportion); + var minIdx = XY_TO_MARGIN_IDX[xyIdx][0]; + var maxIdx = XY_TO_MARGIN_IDX[xyIdx][1]; + margin[minIdx] = mathMax$6(margin[minIdx], overflow1); + margin[maxIdx] = mathMax$6(margin[maxIdx], overflow2); + } + + function applyProportion(overflow, proportion) { + // proportion is not likely to near zero. If so, give up shrink + if (overflow > 0 && !eqNaN(proportion) && proportion > 1e-4) { + overflow /= proportion; + } + + return overflow; + } + } + + function createAxisBiulders(gridRect, cartesians, axesMap, optionContainLabel, api) { + var axisBuilderSharedCtx = new AxisBuilderSharedContext(resolveAxisNameOverlapForGrid); + each$4(axesMap, function (axisList) { + return each$4(axisList, function (axis) { + if (shouldAxisShow(axis.model)) { + // See `AxisBaseOptionCommon['nameMoveOverlap']`. + var defaultNameMoveOverlap = !optionContainLabel; + axis.axisBuilder = createCartesianAxisViewCommonPartBuilder(gridRect, cartesians, axis.model, api, axisBuilderSharedCtx, defaultNameMoveOverlap); + } + }); + }); + return axisBuilderSharedCtx; + } + /** + * Promote the axis-elements-building from "view render" stage to "coordinate system resize" stage. + * This is aimed to resovle overlap across multiple axes, since currently it's hard to reconcile + * multiple axes in "view render" stage. + * + * [CAUTION] But this promotion assumes that the subsequent "visual mapping" stage does not affect + * this axis-elements-building; otherwise we have to refactor it again. + */ + + + function createOrUpdateAxesView(gridRect, axesMap, kind, outerBoundsContain, noPxChange, layoutRef) { + var isDetermine = kind === AxisTickLabelComputingKind.determine; + each$4(axesMap, function (axisList) { + return each$4(axisList, function (axis) { + if (shouldAxisShow(axis.model)) { + updateCartesianAxisViewCommonPartBuilder(axis.axisBuilder, gridRect, axis.model); + axis.axisBuilder.build(isDetermine ? { + axisTickLabelDetermine: true + } : { + axisTickLabelEstimate: true + }, { + noPxChange: noPxChange + }); + } + }); + }); + var nameMarginLevelMap = { + x: 0, + y: 0 + }; + calcNameMarginLevel(0); + calcNameMarginLevel(1); + + function calcNameMarginLevel(xyIdx) { + nameMarginLevelMap[XY$1[1 - xyIdx]] = gridRect[WH$1[xyIdx]] <= layoutRef.refContainer[WH$1[xyIdx]] * 0.5 ? 0 : 1 - xyIdx === 1 ? 2 : 1; + } + + each$4(axesMap, function (axisList, xy) { + return each$4(axisList, function (axis) { + if (shouldAxisShow(axis.model)) { + if (outerBoundsContain === 'all' || isDetermine) { + // To resolve overlap, `axisName` layout depends on `axisTickLabel` layout result + // (all of the axes of the same `grid`; consider multiple x or y axes). + axis.axisBuilder.build({ + axisName: true + }, { + nameMarginLevel: nameMarginLevelMap[xy] + }); + } + + if (isDetermine) { + axis.axisBuilder.build({ + axisLine: true + }); + } + } + }); + }); + } + + function prepareOuterBounds(gridModel, rawRridRect, layoutRef) { + var outerBoundsRect; + var optionOuterBoundsMode = gridModel.get('outerBoundsMode', true); + + if (optionOuterBoundsMode === 'same') { + outerBoundsRect = rawRridRect.clone(); + } else if (optionOuterBoundsMode == null || optionOuterBoundsMode === 'auto') { + outerBoundsRect = getLayoutRect(gridModel.get('outerBounds', true) || OUTER_BOUNDS_DEFAULT, layoutRef.refContainer); + } else if (optionOuterBoundsMode !== 'none') { + { + error("Invalid grid[" + gridModel.componentIndex + "].outerBoundsMode."); + } + } + + var optionOuterBoundsContain = gridModel.get('outerBoundsContain', true); + var parsedOuterBoundsContain; + + if (optionOuterBoundsContain == null || optionOuterBoundsContain === 'auto') { + parsedOuterBoundsContain = 'all'; + } else if (indexOf(['all', 'axisLabel'], optionOuterBoundsContain) < 0) { + { + error("Invalid grid[" + gridModel.componentIndex + "].outerBoundsContain."); + } + parsedOuterBoundsContain = 'all'; + } else { + parsedOuterBoundsContain = optionOuterBoundsContain; + } + + var outerBoundsClamp = [parsePositionSizeOption(retrieve2(gridModel.get('outerBoundsClampWidth', true), OUTER_BOUNDS_CLAMP_DEFAULT[0]), rawRridRect.width), parsePositionSizeOption(retrieve2(gridModel.get('outerBoundsClampHeight', true), OUTER_BOUNDS_CLAMP_DEFAULT[1]), rawRridRect.height)]; + return { + outerBoundsRect: outerBoundsRect, + parsedOuterBoundsContain: parsedOuterBoundsContain, + outerBoundsClamp: outerBoundsClamp + }; + } + + var resolveAxisNameOverlapForGrid = function (cfg, ctx, axisModel, nameLayoutInfo, nameMoveDirVec, thisRecord) { + var perpendicularDim = axisModel.axis.dim === 'x' ? 'y' : 'x'; + resolveAxisNameOverlapDefault(cfg, ctx, axisModel, nameLayoutInfo, nameMoveDirVec, thisRecord); // If nameLocation 'center', and there are multiple axes parallel to this axis, do not adjust by + // other axes, because the axis name should be close to its axis line as much as possible even + // if overlapping; otherwise it might cause misleading. + // If nameLocation 'center', do not adjust by perpendicular axes, since they are not likely to overlap. + // If nameLocation 'start'/'end', move name within the same direction to escape overlap with the + // perpendicular axes. + + if (!isNameLocationCenter(cfg.nameLocation)) { + each$4(ctx.recordMap[perpendicularDim], function (perpenRecord) { + // perpendicular axis may be no name. + if (perpenRecord && perpenRecord.labelInfoList && perpenRecord.dirVec) { + moveIfOverlapByLinearLabels(perpenRecord.labelInfoList, perpenRecord.dirVec, nameLayoutInfo, nameMoveDirVec); + } + }); + } + }; // Build axisPointerModel, mergin tooltip.axisPointer model for each axis. + // allAxesInfo should be updated when setOption performed. + + + function collect(ecModel, api) { + var result = { + /** + * key: makeKey(axis.model) + * value: { + * axis, + * coordSys, + * axisPointerModel, + * triggerTooltip, + * triggerEmphasis, + * involveSeries, + * snap, + * seriesModels, + * seriesDataCount + * } + */ + axesInfo: {}, + seriesInvolved: false, + + /** + * key: makeKey(coordSys.model) + * value: Object: key makeKey(axis.model), value: axisInfo + */ + coordSysAxesInfo: {}, + coordSysMap: {} + }; + collectAxesInfo(result, ecModel, api); // Check seriesInvolved for performance, in case too many series in some chart. + + result.seriesInvolved && collectSeriesInfo(result, ecModel); + return result; + } + + function collectAxesInfo(result, ecModel, api) { + var globalTooltipModel = ecModel.getComponent('tooltip'); + var globalAxisPointerModel = ecModel.getComponent('axisPointer'); // links can only be set on global. + + var linksOption = globalAxisPointerModel.get('link', true) || []; + var linkGroups = []; // Collect axes info. + + each$4(api.getCoordinateSystems(), function (coordSys) { + // Some coordinate system do not support axes, like geo. + if (!coordSys.axisPointerEnabled) { + return; + } + + var coordSysKey = makeKey(coordSys.model); + var axesInfoInCoordSys = result.coordSysAxesInfo[coordSysKey] = {}; + result.coordSysMap[coordSysKey] = coordSys; // Set tooltip (like 'cross') is a convenient way to show axisPointer + // for user. So we enable setting tooltip on coordSys model. + + var coordSysModel = coordSys.model; + var baseTooltipModel = coordSysModel.getModel('tooltip', globalTooltipModel); + each$4(coordSys.getAxes(), curry$1(saveTooltipAxisInfo, false, null)); // If axis tooltip used, choose tooltip axis for each coordSys. + // Notice this case: coordSys is `grid` but not `cartesian2D` here. + + if (coordSys.getTooltipAxes && globalTooltipModel // If tooltip.showContent is set as false, tooltip will not + // show but axisPointer will show as normal. + && baseTooltipModel.get('show')) { + // Compatible with previous logic. But series.tooltip.trigger: 'axis' + // or series.data[n].tooltip.trigger: 'axis' are not support any more. + var triggerAxis = baseTooltipModel.get('trigger') === 'axis'; + var cross = baseTooltipModel.get(['axisPointer', 'type']) === 'cross'; + var tooltipAxes = coordSys.getTooltipAxes(baseTooltipModel.get(['axisPointer', 'axis'])); + + if (triggerAxis || cross) { + each$4(tooltipAxes.baseAxes, curry$1(saveTooltipAxisInfo, cross ? 'cross' : true, triggerAxis)); + } + + if (cross) { + each$4(tooltipAxes.otherAxes, curry$1(saveTooltipAxisInfo, 'cross', false)); + } + } // fromTooltip: true | false | 'cross' + // triggerTooltip: true | false | null + + + function saveTooltipAxisInfo(fromTooltip, triggerTooltip, axis) { + var axisPointerModel = axis.model.getModel('axisPointer', globalAxisPointerModel); + var axisPointerShow = axisPointerModel.get('show'); + + if (!axisPointerShow || axisPointerShow === 'auto' && !fromTooltip && !isHandleTrigger(axisPointerModel)) { + return; + } + + if (triggerTooltip == null) { + triggerTooltip = axisPointerModel.get('triggerTooltip'); + } + + axisPointerModel = fromTooltip ? makeAxisPointerModel(axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip) : axisPointerModel; + var snap = axisPointerModel.get('snap'); + var triggerEmphasis = axisPointerModel.get('triggerEmphasis'); + var axisKey = makeKey(axis.model); + var involveSeries = triggerTooltip || snap || axis.type === 'category'; // If result.axesInfo[key] exist, override it (tooltip has higher priority). + + var axisInfo = result.axesInfo[axisKey] = { + key: axisKey, + axis: axis, + coordSys: coordSys, + axisPointerModel: axisPointerModel, + triggerTooltip: triggerTooltip, + triggerEmphasis: triggerEmphasis, + involveSeries: involveSeries, + snap: snap, + useHandle: isHandleTrigger(axisPointerModel), + seriesModels: [], + linkGroup: null + }; + axesInfoInCoordSys[axisKey] = axisInfo; + result.seriesInvolved = result.seriesInvolved || involveSeries; + var groupIndex = getLinkGroupIndex(linksOption, axis); + + if (groupIndex != null) { + var linkGroup = linkGroups[groupIndex] || (linkGroups[groupIndex] = { + axesInfo: {} + }); + linkGroup.axesInfo[axisKey] = axisInfo; + linkGroup.mapper = linksOption[groupIndex].mapper; + axisInfo.linkGroup = linkGroup; + } + } + }); + } + + function makeAxisPointerModel(axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip) { + var tooltipAxisPointerModel = baseTooltipModel.getModel('axisPointer'); + var fields = ['type', 'snap', 'lineStyle', 'shadowStyle', 'label', 'animation', 'animationDurationUpdate', 'animationEasingUpdate', 'z']; + var volatileOption = {}; + each$4(fields, function (field) { + volatileOption[field] = clone$3(tooltipAxisPointerModel.get(field)); + }); // category axis do not auto snap, otherwise some tick that do not + // has value can not be hovered. value/time/log axis default snap if + // triggered from tooltip and trigger tooltip. + + volatileOption.snap = axis.type !== 'category' && !!triggerTooltip; // Compatible with previous behavior, tooltip axis does not show label by default. + // Only these properties can be overridden from tooltip to axisPointer. + + if (tooltipAxisPointerModel.get('type') === 'cross') { + volatileOption.type = 'line'; + } + + var labelOption = volatileOption.label || (volatileOption.label = {}); // Follow the convention, do not show label when triggered by tooltip by default. + + labelOption.show == null && (labelOption.show = false); + + if (fromTooltip === 'cross') { + // When 'cross', both axes show labels. + var tooltipAxisPointerLabelShow = tooltipAxisPointerModel.get(['label', 'show']); + labelOption.show = tooltipAxisPointerLabelShow != null ? tooltipAxisPointerLabelShow : true; // If triggerTooltip, this is a base axis, which should better not use cross style + // (cross style is dashed by default) + + if (!triggerTooltip) { + var crossStyle = volatileOption.lineStyle = tooltipAxisPointerModel.get('crossStyle'); + crossStyle && defaults(labelOption, crossStyle.textStyle); + } + } + + return axis.model.getModel('axisPointer', new Model(volatileOption, globalAxisPointerModel, ecModel)); + } + + function collectSeriesInfo(result, ecModel) { + // Prepare data for axis trigger + ecModel.eachSeries(function (seriesModel) { + // Notice this case: this coordSys is `cartesian2D` but not `grid`. + var coordSys = seriesModel.coordinateSystem; + var seriesTooltipTrigger = seriesModel.get(['tooltip', 'trigger'], true); + var seriesTooltipShow = seriesModel.get(['tooltip', 'show'], true); + + if (!coordSys || !coordSys.model // PENDING: radar do not have a model. + || seriesTooltipTrigger === 'none' || seriesTooltipTrigger === false || seriesTooltipTrigger === 'item' || seriesTooltipShow === false || seriesModel.get(['axisPointer', 'show'], true) === false) { + return; + } + + each$4(result.coordSysAxesInfo[makeKey(coordSys.model)], function (axisInfo) { + var axis = axisInfo.axis; + + if (coordSys.getAxis(axis.dim) === axis) { + axisInfo.seriesModels.push(seriesModel); + axisInfo.seriesDataCount == null && (axisInfo.seriesDataCount = 0); + axisInfo.seriesDataCount += seriesModel.getData().count(); + } + }); + }); + } + /** + * For example: + * { + * axisPointer: { + * links: [{ + * xAxisIndex: [2, 4], + * yAxisIndex: 'all' + * }, { + * xAxisId: ['a5', 'a7'], + * xAxisName: 'xxx' + * }] + * } + * } + */ + + + function getLinkGroupIndex(linksOption, axis) { + var axisModel = axis.model; + var dim = axis.dim; + + for (var i = 0; i < linksOption.length; i++) { + var linkOption = linksOption[i] || {}; + + if (checkPropInLink(linkOption[dim + 'AxisId'], axisModel.id) || checkPropInLink(linkOption[dim + 'AxisIndex'], axisModel.componentIndex) || checkPropInLink(linkOption[dim + 'AxisName'], axisModel.name)) { + return i; + } + } + } + + function checkPropInLink(linkPropValue, axisPropValue) { + return linkPropValue === 'all' || isArray(linkPropValue) && indexOf(linkPropValue, axisPropValue) >= 0 || linkPropValue === axisPropValue; + } + + function fixValue(axisModel) { + var axisInfo = getAxisInfo$1(axisModel); + + if (!axisInfo) { + return; + } + + var axisPointerModel = axisInfo.axisPointerModel; + var scale = axisInfo.axis.scale; + var option = axisPointerModel.option; + var status = axisPointerModel.get('status'); + var value = axisPointerModel.get('value'); // Parse init value for category and time axis. + + if (value != null) { + value = scale.parse(value); + } + + var useHandle = isHandleTrigger(axisPointerModel); // If `handle` used, `axisPointer` will always be displayed, so value + // and status should be initialized. + + if (status == null) { + option.status = useHandle ? 'show' : 'hide'; + } + + var extent = scale.getExtent().slice(); + extent[0] > extent[1] && extent.reverse(); + + if ( // Pick a value on axis when initializing. + value == null // If both `handle` and `dataZoom` are used, value may be out of axis extent, + // where we should re-pick a value to keep `handle` displaying normally. + || value > extent[1]) { + // Make handle displayed on the end of the axis when init, which looks better. + value = extent[1]; + } + + if (value < extent[0]) { + value = extent[0]; + } + + option.value = value; + + if (useHandle) { + option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show'; + } + } + + function getAxisInfo$1(axisModel) { + var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo; + return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)]; + } + + function getAxisPointerModel(axisModel) { + var axisInfo = getAxisInfo$1(axisModel); + return axisInfo && axisInfo.axisPointerModel; + } + + function isHandleTrigger(axisPointerModel) { + return !!axisPointerModel.get(['handle', 'show']); + } + /** + * @param {module:echarts/model/Model} model + * @return {string} unique key + */ + + + function makeKey(model) { + return model.type + '||' + model.id; + } + + var axisPointerClazz = {}; + /** + * Base class of AxisView. + */ + + var AxisView = + /** @class */ + function (_super) { + __extends(AxisView, _super); + + function AxisView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = AxisView.type; + return _this; + } + /** + * @override + */ + + + AxisView.prototype.render = function (axisModel, ecModel, api, payload) { + // FIXME + // This process should proformed after coordinate systems updated + // (axis scale updated), and should be performed each time update. + // So put it here temporarily, although it is not appropriate to + // put a model-writing procedure in `view`. + this.axisPointerClass && fixValue(axisModel); + + _super.prototype.render.apply(this, arguments); + + this._doUpdateAxisPointerClass(axisModel, api, true); + }; + /** + * Action handler. + */ + + + AxisView.prototype.updateAxisPointer = function (axisModel, ecModel, api, payload) { + this._doUpdateAxisPointerClass(axisModel, api, false); + }; + /** + * @override + */ + + + AxisView.prototype.remove = function (ecModel, api) { + var axisPointer = this._axisPointer; + axisPointer && axisPointer.remove(api); + }; + /** + * @override + */ + + + AxisView.prototype.dispose = function (ecModel, api) { + this._disposeAxisPointer(api); + + _super.prototype.dispose.apply(this, arguments); + }; + + AxisView.prototype._doUpdateAxisPointerClass = function (axisModel, api, forceRender) { + var Clazz = AxisView.getAxisPointerClass(this.axisPointerClass); + + if (!Clazz) { + return; + } + + var axisPointerModel = getAxisPointerModel(axisModel); + axisPointerModel ? (this._axisPointer || (this._axisPointer = new Clazz())).render(axisModel, axisPointerModel, api, forceRender) : this._disposeAxisPointer(api); + }; + + AxisView.prototype._disposeAxisPointer = function (api) { + this._axisPointer && this._axisPointer.dispose(api); + this._axisPointer = null; + }; + + AxisView.registerAxisPointerClass = function (type, clazz) { + { + if (axisPointerClazz[type]) { + throw new Error('axisPointer ' + type + ' exists'); + } + } + axisPointerClazz[type] = clazz; + }; + + AxisView.getAxisPointerClass = function (type) { + return type && axisPointerClazz[type]; + }; + + AxisView.type = 'axis'; + return AxisView; + }(ComponentView); + + var inner$6 = makeInner(); + + function rectCoordAxisBuildSplitArea(axisView, axisGroup, axisModel, gridModel) { + var axis = axisModel.axis; + + if (axis.scale.isBlank()) { + return; + } // TODO: TYPE + + + var splitAreaModel = axisModel.getModel('splitArea'); + var areaStyleModel = splitAreaModel.getModel('areaStyle'); + var areaColors = areaStyleModel.get('color'); + var gridRect = gridModel.coordinateSystem.getRect(); + var ticksCoords = axis.getTicksCoords({ + tickModel: splitAreaModel, + clamp: true, + breakTicks: 'none', + pruneByBreak: 'preserve_extent_bound' + }); + + if (!ticksCoords.length) { + return; + } // For Making appropriate splitArea animation, the color and anid + // should be corresponding to previous one if possible. + + + var areaColorsLen = areaColors.length; + var lastSplitAreaColors = inner$6(axisView).splitAreaColors; + var newSplitAreaColors = createHashMap(); + var colorIndex = 0; + + if (lastSplitAreaColors) { + for (var i = 0; i < ticksCoords.length; i++) { + var cIndex = lastSplitAreaColors.get(ticksCoords[i].tickValue); + + if (cIndex != null) { + colorIndex = (cIndex + (areaColorsLen - 1) * i) % areaColorsLen; + break; + } + } + } + + var prev = axis.toGlobalCoord(ticksCoords[0].coord); + var areaStyle = areaStyleModel.getAreaStyle(); + areaColors = isArray(areaColors) ? areaColors : [areaColors]; + + for (var i = 1; i < ticksCoords.length; i++) { + var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord); + var x = void 0; + var y = void 0; + var width = void 0; + var height = void 0; + + if (axis.isHorizontal()) { + x = prev; + y = gridRect.y; + width = tickCoord - x; + height = gridRect.height; + prev = x + width; + } else { + x = gridRect.x; + y = prev; + width = gridRect.width; + height = tickCoord - y; + prev = y + height; + } + + var tickValue = ticksCoords[i - 1].tickValue; + tickValue != null && newSplitAreaColors.set(tickValue, colorIndex); + axisGroup.add(new Rect({ + anid: tickValue != null ? 'area_' + tickValue : null, + shape: { + x: x, + y: y, + width: width, + height: height + }, + style: defaults({ + fill: areaColors[colorIndex] + }, areaStyle), + autoBatch: true, + silent: true + })); + colorIndex = (colorIndex + 1) % areaColorsLen; + } + + inner$6(axisView).splitAreaColors = newSplitAreaColors; + } + + function rectCoordAxisHandleRemove(axisView) { + inner$6(axisView).splitAreaColors = null; + } + + var selfBuilderAttrs = ['splitArea', 'splitLine', 'minorSplitLine', 'breakArea']; + + var CartesianAxisView = + /** @class */ + function (_super) { + __extends(CartesianAxisView, _super); + + function CartesianAxisView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = CartesianAxisView.type; + _this.axisPointerClass = 'CartesianAxisPointer'; + return _this; + } + /** + * @override + */ + + + CartesianAxisView.prototype.render = function (axisModel, ecModel, api, payload) { + this.group.removeAll(); + var oldAxisGroup = this._axisGroup; + this._axisGroup = new Group$2(); + this.group.add(this._axisGroup); + + if (!shouldAxisShow(axisModel)) { + return; + } + + this._axisGroup.add(axisModel.axis.axisBuilder.group); + + each$4(selfBuilderAttrs, function (name) { + if (axisModel.get([name, 'show'])) { + axisElementBuilders[name](this, this._axisGroup, axisModel, axisModel.getCoordSysModel(), api); + } + }, this); // THIS is a special case for bar racing chart. + // Update the axis label from the natural initial layout to + // sorted layout should has no animation. + + var isInitialSortFromBarRacing = payload && payload.type === 'changeAxisOrder' && payload.isInitSort; + + if (!isInitialSortFromBarRacing) { + groupTransition(oldAxisGroup, this._axisGroup, axisModel); + } + + _super.prototype.render.call(this, axisModel, ecModel, api, payload); + }; + + CartesianAxisView.prototype.remove = function () { + rectCoordAxisHandleRemove(this); + }; + + CartesianAxisView.type = 'cartesianAxis'; + return CartesianAxisView; + }(AxisView); + + var axisElementBuilders = { + splitLine: function (axisView, axisGroup, axisModel, gridModel, api) { + var axis = axisModel.axis; + + if (axis.scale.isBlank()) { + return; + } + + var splitLineModel = axisModel.getModel('splitLine'); + var lineStyleModel = splitLineModel.getModel('lineStyle'); + var lineColors = lineStyleModel.get('color'); + var showMinLine = splitLineModel.get('showMinLine') !== false; + var showMaxLine = splitLineModel.get('showMaxLine') !== false; + lineColors = isArray(lineColors) ? lineColors : [lineColors]; + var gridRect = gridModel.coordinateSystem.getRect(); + var isHorizontal = axis.isHorizontal(); + var lineCount = 0; + var ticksCoords = axis.getTicksCoords({ + tickModel: splitLineModel, + breakTicks: 'none', + pruneByBreak: 'preserve_extent_bound' + }); + var p1 = []; + var p2 = []; + var lineStyle = lineStyleModel.getLineStyle(); + + for (var i = 0; i < ticksCoords.length; i++) { + var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord); + + if (i === 0 && !showMinLine || i === ticksCoords.length - 1 && !showMaxLine) { + continue; + } + + var tickValue = ticksCoords[i].tickValue; + + if (isHorizontal) { + p1[0] = tickCoord; + p1[1] = gridRect.y; + p2[0] = tickCoord; + p2[1] = gridRect.y + gridRect.height; + } else { + p1[0] = gridRect.x; + p1[1] = tickCoord; + p2[0] = gridRect.x + gridRect.width; + p2[1] = tickCoord; + } + + var colorIndex = lineCount++ % lineColors.length; + var line = new Line({ + anid: tickValue != null ? 'line_' + tickValue : null, + autoBatch: true, + shape: { + x1: p1[0], + y1: p1[1], + x2: p2[0], + y2: p2[1] + }, + style: defaults({ + stroke: lineColors[colorIndex] + }, lineStyle), + silent: true + }); + subPixelOptimizeLine(line.shape, lineStyle.lineWidth); + axisGroup.add(line); + } + }, + minorSplitLine: function (axisView, axisGroup, axisModel, gridModel, api) { + var axis = axisModel.axis; + var minorSplitLineModel = axisModel.getModel('minorSplitLine'); + var lineStyleModel = minorSplitLineModel.getModel('lineStyle'); + var gridRect = gridModel.coordinateSystem.getRect(); + var isHorizontal = axis.isHorizontal(); + var minorTicksCoords = axis.getMinorTicksCoords(); + + if (!minorTicksCoords.length) { + return; + } + + var p1 = []; + var p2 = []; + var lineStyle = lineStyleModel.getLineStyle(); + + for (var i = 0; i < minorTicksCoords.length; i++) { + for (var k = 0; k < minorTicksCoords[i].length; k++) { + var tickCoord = axis.toGlobalCoord(minorTicksCoords[i][k].coord); + + if (isHorizontal) { + p1[0] = tickCoord; + p1[1] = gridRect.y; + p2[0] = tickCoord; + p2[1] = gridRect.y + gridRect.height; + } else { + p1[0] = gridRect.x; + p1[1] = tickCoord; + p2[0] = gridRect.x + gridRect.width; + p2[1] = tickCoord; + } + + var line = new Line({ + anid: 'minor_line_' + minorTicksCoords[i][k].tickValue, + autoBatch: true, + shape: { + x1: p1[0], + y1: p1[1], + x2: p2[0], + y2: p2[1] + }, + style: lineStyle, + silent: true + }); + subPixelOptimizeLine(line.shape, lineStyle.lineWidth); + axisGroup.add(line); + } + } + }, + splitArea: function (axisView, axisGroup, axisModel, gridModel, api) { + rectCoordAxisBuildSplitArea(axisView, axisGroup, axisModel, gridModel); + }, + breakArea: function (axisView, axisGroup, axisModel, gridModel, api) { + axisModel.axis.scale; + } + }; + + var CartesianXAxisView = + /** @class */ + function (_super) { + __extends(CartesianXAxisView, _super); + + function CartesianXAxisView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = CartesianXAxisView.type; + return _this; + } + + CartesianXAxisView.type = 'xAxis'; + return CartesianXAxisView; + }(CartesianAxisView); + + var CartesianYAxisView = + /** @class */ + function (_super) { + __extends(CartesianYAxisView, _super); + + function CartesianYAxisView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = CartesianXAxisView.type; + return _this; + } + + CartesianYAxisView.type = 'yAxis'; + return CartesianYAxisView; + }(CartesianAxisView); // Grid view + + + var GridView = + /** @class */ + function (_super) { + __extends(GridView, _super); + + function GridView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = 'grid'; + return _this; + } + + GridView.prototype.render = function (gridModel, ecModel) { + this.group.removeAll(); + + if (gridModel.get('show')) { + this.group.add(new Rect({ + shape: gridModel.coordinateSystem.getRect(), + style: defaults({ + fill: gridModel.get('backgroundColor') + }, gridModel.getItemStyle()), + silent: true, + z2: -1 + })); + } + }; + + GridView.type = 'grid'; + return GridView; + }(ComponentView); + + var extraOption = { + // gridIndex: 0, + // gridId: '', + offset: 0 + }; + + function install$7(registers) { + registers.registerComponentView(GridView); + registers.registerComponentModel(GridModel); + registers.registerCoordinateSystem('cartesian2d', Grid); + axisModelCreator(registers, 'x', CartesianAxisModel, extraOption); + axisModelCreator(registers, 'y', CartesianAxisModel, extraOption); + registers.registerComponentView(CartesianXAxisView); + registers.registerComponentView(CartesianYAxisView); + registers.registerPreprocessor(function (option) { + // Only create grid when need + if (option.xAxis && option.yAxis && !option.grid) { + option.grid = {}; + } + }); + } + + use(install$7); + + var TitleModel = + /** @class */ + function (_super) { + __extends(TitleModel, _super); + + function TitleModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = TitleModel.type; + _this.layoutMode = { + type: 'box', + ignoreSize: true + }; + return _this; + } + + TitleModel.type = 'title'; + TitleModel.defaultOption = { + // zlevel: 0, + z: 6, + show: true, + text: '', + target: 'blank', + subtext: '', + subtarget: 'blank', + left: 'center', + top: tokens.size.m, + backgroundColor: tokens.color.transparent, + borderColor: tokens.color.primary, + borderWidth: 0, + padding: 5, + itemGap: 10, + textStyle: { + fontSize: 18, + fontWeight: 'bold', + color: tokens.color.primary + }, + subtextStyle: { + fontSize: 12, + color: tokens.color.quaternary + } + }; + return TitleModel; + }(ComponentModel); // View + + + var TitleView = + /** @class */ + function (_super) { + __extends(TitleView, _super); + + function TitleView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = TitleView.type; + return _this; + } + + TitleView.prototype.render = function (titleModel, ecModel, api) { + this.group.removeAll(); + + if (!titleModel.get('show')) { + return; + } + + var group = this.group; + var textStyleModel = titleModel.getModel('textStyle'); + var subtextStyleModel = titleModel.getModel('subtextStyle'); + var textAlign = titleModel.get('textAlign'); + var textVerticalAlign = retrieve2(titleModel.get('textBaseline'), titleModel.get('textVerticalAlign')); + var textEl = new ZRText({ + style: createTextStyle$1(textStyleModel, { + text: titleModel.get('text'), + fill: textStyleModel.getTextColor() + }, { + disableBox: true + }), + z2: 10 + }); + var textRect = textEl.getBoundingRect(); + var subText = titleModel.get('subtext'); + var subTextEl = new ZRText({ + style: createTextStyle$1(subtextStyleModel, { + text: subText, + fill: subtextStyleModel.getTextColor(), + y: textRect.height + titleModel.get('itemGap'), + verticalAlign: 'top' + }, { + disableBox: true + }), + z2: 10 + }); + var link = titleModel.get('link'); + var sublink = titleModel.get('sublink'); + var triggerEvent = titleModel.get('triggerEvent', true); + textEl.silent = !link && !triggerEvent; + subTextEl.silent = !sublink && !triggerEvent; + + if (link) { + textEl.on('click', function () { + windowOpen(link, '_' + titleModel.get('target')); + }); + } + + if (sublink) { + subTextEl.on('click', function () { + windowOpen(sublink, '_' + titleModel.get('subtarget')); + }); + } + + getECData(textEl).eventData = getECData(subTextEl).eventData = triggerEvent ? { + componentType: 'title', + componentIndex: titleModel.componentIndex + } : null; + group.add(textEl); + subText && group.add(subTextEl); // If no subText, but add subTextEl, there will be an empty line. + + var groupRect = group.getBoundingRect(); + var layoutOption = titleModel.getBoxLayoutParams(); + layoutOption.width = groupRect.width; + layoutOption.height = groupRect.height; + var layoutRef = createBoxLayoutReference(titleModel, api); + var layoutRect = getLayoutRect(layoutOption, layoutRef.refContainer, titleModel.get('padding')); // Adjust text align based on position + + if (!textAlign) { + // Align left if title is on the left. center and right is same + textAlign = titleModel.get('left') || titleModel.get('right'); // @ts-ignore + + if (textAlign === 'middle') { + textAlign = 'center'; + } // Adjust layout by text align + + + if (textAlign === 'right') { + layoutRect.x += layoutRect.width; + } else if (textAlign === 'center') { + layoutRect.x += layoutRect.width / 2; + } + } + + if (!textVerticalAlign) { + textVerticalAlign = titleModel.get('top') || titleModel.get('bottom'); // @ts-ignore + + if (textVerticalAlign === 'center') { + textVerticalAlign = 'middle'; + } + + if (textVerticalAlign === 'bottom') { + layoutRect.y += layoutRect.height; + } else if (textVerticalAlign === 'middle') { + layoutRect.y += layoutRect.height / 2; + } + + textVerticalAlign = textVerticalAlign || 'top'; + } + + group.x = layoutRect.x; + group.y = layoutRect.y; + group.markRedraw(); + var alignStyle = { + align: textAlign, + verticalAlign: textVerticalAlign + }; + textEl.setStyle(alignStyle); + subTextEl.setStyle(alignStyle); // Render background + // Get groupRect again because textAlign has been changed + + groupRect = group.getBoundingRect(); + var padding = layoutRect.margin; + var style = titleModel.getItemStyle(['color', 'opacity']); + style.fill = titleModel.get('backgroundColor'); + var rect = new Rect({ + shape: { + x: groupRect.x - padding[3], + y: groupRect.y - padding[0], + width: groupRect.width + padding[1] + padding[3], + height: groupRect.height + padding[0] + padding[2], + r: titleModel.get('borderRadius') + }, + style: style, + subPixelOptimize: true, + silent: true + }); + group.add(rect); + }; + + TitleView.type = 'title'; + return TitleView; + }(ComponentView); + + function install$6(registers) { + registers.registerComponentModel(TitleModel); + registers.registerComponentView(TitleView); + } + + use(install$6); + + var getDefaultSelectorOptions = function (ecModel, type) { + if (type === 'all') { + return { + type: 'all', + title: ecModel.getLocaleModel().get(['legend', 'selector', 'all']) + }; + } else if (type === 'inverse') { + return { + type: 'inverse', + title: ecModel.getLocaleModel().get(['legend', 'selector', 'inverse']) + }; + } + }; + + var LegendModel = + /** @class */ + function (_super) { + __extends(LegendModel, _super); + + function LegendModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = LegendModel.type; + _this.layoutMode = { + type: 'box', + // legend.width/height are maxWidth/maxHeight actually, + // whereas real width/height is calculated by its content. + // (Setting {left: 10, right: 10} does not make sense). + // So consider the case: + // `setOption({legend: {left: 10});` + // then `setOption({legend: {right: 10});` + // The previous `left` should be cleared by setting `ignoreSize`. + ignoreSize: true + }; + return _this; + } + + LegendModel.prototype.init = function (option, parentModel, ecModel) { + this.mergeDefaultAndTheme(option, ecModel); + option.selected = option.selected || {}; + + this._updateSelector(option); + }; + + LegendModel.prototype.mergeOption = function (option, ecModel) { + _super.prototype.mergeOption.call(this, option, ecModel); + + this._updateSelector(option); + }; + + LegendModel.prototype._updateSelector = function (option) { + var selector = option.selector; + var ecModel = this.ecModel; + + if (selector === true) { + selector = option.selector = ['all', 'inverse']; + } + + if (isArray(selector)) { + each$4(selector, function (item, index) { + isString(item) && (item = { + type: item + }); + selector[index] = merge(item, getDefaultSelectorOptions(ecModel, item.type)); + }); + } + }; + + LegendModel.prototype.optionUpdated = function () { + this._updateData(this.ecModel); + + var legendData = this._data; // If selectedMode is single, try to select one + + if (legendData[0] && this.get('selectedMode') === 'single') { + var hasSelected = false; // If has any selected in option.selected + + for (var i = 0; i < legendData.length; i++) { + var name_1 = legendData[i].get('name'); + + if (this.isSelected(name_1)) { + // Force to unselect others + this.select(name_1); + hasSelected = true; + break; + } + } // Try select the first if selectedMode is single + + + !hasSelected && this.select(legendData[0].get('name')); + } + }; + + LegendModel.prototype._updateData = function (ecModel) { + var potentialData = []; + var availableNames = []; + ecModel.eachRawSeries(function (seriesModel) { + var seriesName = seriesModel.name; + availableNames.push(seriesName); + var isPotential; + + if (seriesModel.legendVisualProvider) { + var provider = seriesModel.legendVisualProvider; + var names = provider.getAllNames(); + + if (!ecModel.isSeriesFiltered(seriesModel)) { + availableNames = availableNames.concat(names); + } + + if (names.length) { + potentialData = potentialData.concat(names); + } else { + isPotential = true; + } + } else { + isPotential = true; + } + + if (isPotential && isNameSpecified(seriesModel)) { + potentialData.push(seriesModel.name); + } + }); + /** + * @type {Array.} + * @private + */ + + this._availableNames = availableNames; // If legend.data is not specified in option, use availableNames as data, + // which is convenient for user preparing option. + + var rawData = this.get('data') || potentialData; + var legendNameMap = createHashMap(); + var legendData = map$1(rawData, function (dataItem) { + // Can be string or number + if (isString(dataItem) || isNumber(dataItem)) { + dataItem = { + name: dataItem + }; + } + + if (legendNameMap.get(dataItem.name)) { + // remove legend name duplicate + return null; + } + + legendNameMap.set(dataItem.name, true); + return new Model(dataItem, this, this.ecModel); + }, this); + /** + * @type {Array.} + * @private + */ + + this._data = filter(legendData, function (item) { + return !!item; + }); + }; + + LegendModel.prototype.getData = function () { + return this._data; + }; + + LegendModel.prototype.select = function (name) { + var selected = this.option.selected; + var selectedMode = this.get('selectedMode'); + + if (selectedMode === 'single') { + var data = this._data; + each$4(data, function (dataItem) { + selected[dataItem.get('name')] = false; + }); + } + + selected[name] = true; + }; + + LegendModel.prototype.unSelect = function (name) { + if (this.get('selectedMode') !== 'single') { + this.option.selected[name] = false; + } + }; + + LegendModel.prototype.toggleSelected = function (name) { + var selected = this.option.selected; // Default is true + + if (!selected.hasOwnProperty(name)) { + selected[name] = true; + } + + this[selected[name] ? 'unSelect' : 'select'](name); + }; + + LegendModel.prototype.allSelect = function () { + var data = this._data; + var selected = this.option.selected; + each$4(data, function (dataItem) { + selected[dataItem.get('name', true)] = true; + }); + }; + + LegendModel.prototype.inverseSelect = function () { + var data = this._data; + var selected = this.option.selected; + each$4(data, function (dataItem) { + var name = dataItem.get('name', true); // Initially, default value is true + + if (!selected.hasOwnProperty(name)) { + selected[name] = true; + } + + selected[name] = !selected[name]; + }); + }; + + LegendModel.prototype.isSelected = function (name) { + var selected = this.option.selected; + return !(selected.hasOwnProperty(name) && !selected[name]) && indexOf(this._availableNames, name) >= 0; + }; + + LegendModel.prototype.getOrient = function () { + return this.get('orient') === 'vertical' ? { + index: 1, + name: 'vertical' + } : { + index: 0, + name: 'horizontal' + }; + }; + + LegendModel.type = 'legend.plain'; + LegendModel.dependencies = ['series']; + LegendModel.defaultOption = { + // zlevel: 0, + z: 4, + show: true, + orient: 'horizontal', + left: 'center', + // right: 'center', + // top: 0, + bottom: tokens.size.m, + align: 'auto', + backgroundColor: tokens.color.transparent, + borderColor: tokens.color.border, + borderRadius: 0, + borderWidth: 0, + padding: 5, + itemGap: 8, + itemWidth: 25, + itemHeight: 14, + symbolRotate: 'inherit', + symbolKeepAspect: true, + inactiveColor: tokens.color.disabled, + inactiveBorderColor: tokens.color.disabled, + inactiveBorderWidth: 'auto', + itemStyle: { + color: 'inherit', + opacity: 'inherit', + borderColor: 'inherit', + borderWidth: 'auto', + borderCap: 'inherit', + borderJoin: 'inherit', + borderDashOffset: 'inherit', + borderMiterLimit: 'inherit' + }, + lineStyle: { + width: 'auto', + color: 'inherit', + inactiveColor: tokens.color.disabled, + inactiveWidth: 2, + opacity: 'inherit', + type: 'inherit', + cap: 'inherit', + join: 'inherit', + dashOffset: 'inherit', + miterLimit: 'inherit' + }, + textStyle: { + color: tokens.color.secondary + }, + selectedMode: true, + selector: false, + selectorLabel: { + show: true, + borderRadius: 10, + padding: [3, 5, 3, 5], + fontSize: 12, + fontFamily: 'sans-serif', + color: tokens.color.tertiary, + borderWidth: 1, + borderColor: tokens.color.border + }, + emphasis: { + selectorLabel: { + show: true, + color: tokens.color.quaternary + } + }, + selectorPosition: 'auto', + selectorItemGap: 7, + selectorButtonGap: 10, + tooltip: { + show: false + }, + triggerEvent: false + }; + return LegendModel; + }(ComponentModel); + + function makeBackground(rect, componentModel) { + var padding = normalizeCssArray(componentModel.get('padding')); + var style = componentModel.getItemStyle(['color', 'opacity']); + style.fill = componentModel.get('backgroundColor'); + var bgRect = new Rect({ + shape: { + x: rect.x - padding[3], + y: rect.y - padding[0], + width: rect.width + padding[1] + padding[3], + height: rect.height + padding[0] + padding[2], + r: componentModel.get('borderRadius') + }, + style: style, + silent: true, + z2: -1 + }); // FIXME + // `subPixelOptimizeRect` may bring some gap between edge of viewpart + // and background rect when setting like `left: 0`, `top: 0`. + // graphic.subPixelOptimizeRect(rect); + + return bgRect; + } + + var curry = curry$1; + var each$1 = each$4; + var Group$1 = Group$2; + + var LegendView = + /** @class */ + function (_super) { + __extends(LegendView, _super); + + function LegendView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = LegendView.type; + _this.newlineDisabled = false; + return _this; + } + + LegendView.prototype.init = function () { + this.group.add(this._contentGroup = new Group$1()); + this.group.add(this._selectorGroup = new Group$1()); + this._isFirstRender = true; + }; + /** + * @protected + */ + + + LegendView.prototype.getContentGroup = function () { + return this._contentGroup; + }; + /** + * @protected + */ + + + LegendView.prototype.getSelectorGroup = function () { + return this._selectorGroup; + }; + /** + * @override + */ + + + LegendView.prototype.render = function (legendModel, ecModel, api) { + var isFirstRender = this._isFirstRender; + this._isFirstRender = false; + this.resetInner(); + + if (!legendModel.get('show', true)) { + return; + } + + var itemAlign = legendModel.get('align'); + var orient = legendModel.get('orient'); + + if (!itemAlign || itemAlign === 'auto') { + itemAlign = legendModel.get('left') === 'right' && orient === 'vertical' ? 'right' : 'left'; + } // selector has been normalized to an array in model + + + var selector = legendModel.get('selector', true); + var selectorPosition = legendModel.get('selectorPosition', true); + + if (selector && (!selectorPosition || selectorPosition === 'auto')) { + selectorPosition = orient === 'horizontal' ? 'end' : 'start'; + } + + this.renderInner(itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition); // Perform layout. + + var refContainer = createBoxLayoutReference(legendModel, api).refContainer; + var positionInfo = legendModel.getBoxLayoutParams(); + var padding = legendModel.get('padding'); + var maxSize = getLayoutRect(positionInfo, refContainer, padding); + var mainRect = this.layoutInner(legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition); // Place mainGroup, based on the calculated `mainRect`. + + var layoutRect = getLayoutRect(defaults({ + width: mainRect.width, + height: mainRect.height + }, positionInfo), refContainer, padding); + this.group.x = layoutRect.x - mainRect.x; + this.group.y = layoutRect.y - mainRect.y; + this.group.markRedraw(); // Render background after group is layout. + + this.group.add(this._backgroundEl = makeBackground(mainRect, // FXIME: most itemStyle options does not work in background because inherit is not handled yet. + legendModel)); + }; + + LegendView.prototype.resetInner = function () { + this.getContentGroup().removeAll(); + this._backgroundEl && this.group.remove(this._backgroundEl); + this.getSelectorGroup().removeAll(); + }; + + LegendView.prototype.renderInner = function (itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition) { + var contentGroup = this.getContentGroup(); + var legendDrawnMap = createHashMap(); + var selectMode = legendModel.get('selectedMode'); + var triggerEvent = legendModel.get('triggerEvent'); + var excludeSeriesId = []; + ecModel.eachRawSeries(function (seriesModel) { + !seriesModel.get('legendHoverLink') && excludeSeriesId.push(seriesModel.id); + }); + each$1(legendModel.getData(), function (legendItemModel, dataIndex) { + var _this = this; + + var name = legendItemModel.get('name'); // Use empty string or \n as a newline string + + if (!this.newlineDisabled && (name === '' || name === '\n')) { + var g = new Group$1(); // @ts-ignore + + g.newline = true; + contentGroup.add(g); + return; + } // Representitive series. + + + var seriesModel = ecModel.getSeriesByName(name)[0]; + + if (legendDrawnMap.get(name)) { + // Have been drawn + return; + } // Legend to control series. + + + if (seriesModel) { + var data = seriesModel.getData(); + var lineVisualStyle = data.getVisual('legendLineStyle') || {}; + var legendIcon = data.getVisual('legendIcon'); + /** + * `data.getVisual('style')` may be the color from the register + * in series. For example, for line series, + */ + + var style = data.getVisual('style'); + + var itemGroup = this._createItem(seriesModel, name, dataIndex, legendItemModel, legendModel, itemAlign, lineVisualStyle, style, legendIcon, selectMode, api); + + itemGroup.on('click', curry(dispatchSelectAction, name, null, api, excludeSeriesId)).on('mouseover', curry(dispatchHighlightAction, seriesModel.name, null, api, excludeSeriesId)).on('mouseout', curry(dispatchDownplayAction, seriesModel.name, null, api, excludeSeriesId)); + + if (ecModel.ssr) { + itemGroup.eachChild(function (child) { + var ecData = getECData(child); + ecData.seriesIndex = seriesModel.seriesIndex; + ecData.dataIndex = dataIndex; + ecData.ssrType = 'legend'; + }); + } + + if (triggerEvent) { + itemGroup.eachChild(function (child) { + _this.packEventData(child, legendModel, seriesModel, dataIndex, name); + }); + } + + legendDrawnMap.set(name, true); + } else { + // Legend to control data. In pie and funnel. + ecModel.eachRawSeries(function (seriesModel) { + var _this = this; // In case multiple series has same data name + + + if (legendDrawnMap.get(name)) { + return; + } + + if (seriesModel.legendVisualProvider) { + var provider = seriesModel.legendVisualProvider; + + if (!provider.containName(name)) { + return; + } + + var idx = provider.indexOfName(name); + var style = provider.getItemVisual(idx, 'style'); + var legendIcon = provider.getItemVisual(idx, 'legendIcon'); + var colorArr = parse(style.fill); // Color may be set to transparent in visualMap when data is out of range. + // Do not show nothing. + + if (colorArr && colorArr[3] === 0) { + colorArr[3] = 0.2; // TODO color is set to 0, 0, 0, 0. Should show correct RGBA + + style = extend(extend({}, style), { + fill: stringify(colorArr, 'rgba') + }); + } + + var itemGroup = this._createItem(seriesModel, name, dataIndex, legendItemModel, legendModel, itemAlign, {}, style, legendIcon, selectMode, api); // FIXME: consider different series has items with the same name. + + + itemGroup.on('click', curry(dispatchSelectAction, null, name, api, excludeSeriesId)) // Should not specify the series name, consider legend controls + // more than one pie series. + .on('mouseover', curry(dispatchHighlightAction, null, name, api, excludeSeriesId)).on('mouseout', curry(dispatchDownplayAction, null, name, api, excludeSeriesId)); + + if (ecModel.ssr) { + itemGroup.eachChild(function (child) { + var ecData = getECData(child); + ecData.seriesIndex = seriesModel.seriesIndex; + ecData.dataIndex = dataIndex; + ecData.ssrType = 'legend'; + }); + } + + if (triggerEvent) { + itemGroup.eachChild(function (child) { + _this.packEventData(child, legendModel, seriesModel, dataIndex, name); + }); + } + + legendDrawnMap.set(name, true); + } + }, this); + } + + { + if (!legendDrawnMap.get(name)) { + console.warn(name + ' series not exists. Legend data should be same with series name or data name.'); + } + } + }, this); + + if (selector) { + this._createSelector(selector, legendModel, api, orient, selectorPosition); + } + }; + + LegendView.prototype.packEventData = function (el, legendModel, seriesModel, dataIndex, name) { + var eventData = { + componentType: 'legend', + componentIndex: legendModel.componentIndex, + dataIndex: dataIndex, + value: name, + seriesIndex: seriesModel.seriesIndex + }; + getECData(el).eventData = eventData; + }; + + LegendView.prototype._createSelector = function (selector, legendModel, api, orient, selectorPosition) { + var selectorGroup = this.getSelectorGroup(); + each$1(selector, function createSelectorButton(selectorItem) { + var type = selectorItem.type; + var labelText = new ZRText({ + style: { + x: 0, + y: 0, + align: 'center', + verticalAlign: 'middle' + }, + onclick: function () { + api.dispatchAction({ + type: type === 'all' ? 'legendAllSelect' : 'legendInverseSelect', + legendId: legendModel.id + }); + } + }); + selectorGroup.add(labelText); + var labelModel = legendModel.getModel('selectorLabel'); + var emphasisLabelModel = legendModel.getModel(['emphasis', 'selectorLabel']); + setLabelStyle(labelText, { + normal: labelModel, + emphasis: emphasisLabelModel + }, { + defaultText: selectorItem.title + }); + enableHoverEmphasis(labelText); + }); + }; + + LegendView.prototype._createItem = function (seriesModel, name, dataIndex, legendItemModel, legendModel, itemAlign, lineVisualStyle, itemVisualStyle, legendIcon, selectMode, api) { + var drawType = seriesModel.visualDrawType; + var itemWidth = legendModel.get('itemWidth'); + var itemHeight = legendModel.get('itemHeight'); + var isSelected = legendModel.isSelected(name); + var iconRotate = legendItemModel.get('symbolRotate'); + var symbolKeepAspect = legendItemModel.get('symbolKeepAspect'); + var legendIconType = legendItemModel.get('icon'); + legendIcon = legendIconType || legendIcon || 'roundRect'; + var style = getLegendStyle(legendIcon, legendItemModel, lineVisualStyle, itemVisualStyle, drawType, isSelected, api); + var itemGroup = new Group$1(); + var textStyleModel = legendItemModel.getModel('textStyle'); + + if (isFunction(seriesModel.getLegendIcon) && (!legendIconType || legendIconType === 'inherit')) { + // Series has specific way to define legend icon + itemGroup.add(seriesModel.getLegendIcon({ + itemWidth: itemWidth, + itemHeight: itemHeight, + icon: legendIcon, + iconRotate: iconRotate, + itemStyle: style.itemStyle, + lineStyle: style.lineStyle, + symbolKeepAspect: symbolKeepAspect + })); + } else { + // Use default legend icon policy for most series + var rotate = legendIconType === 'inherit' && seriesModel.getData().getVisual('symbol') ? iconRotate === 'inherit' ? seriesModel.getData().getVisual('symbolRotate') : iconRotate : 0; // No rotation for no icon + + itemGroup.add(getDefaultLegendIcon({ + itemWidth: itemWidth, + itemHeight: itemHeight, + icon: legendIcon, + iconRotate: rotate, + itemStyle: style.itemStyle, + lineStyle: style.lineStyle, + symbolKeepAspect: symbolKeepAspect + })); + } + + var textX = itemAlign === 'left' ? itemWidth + 5 : -5; + var textAlign = itemAlign; + var formatter = legendModel.get('formatter'); + var content = name; + + if (isString(formatter) && formatter) { + content = formatter.replace('{name}', name != null ? name : ''); + } else if (isFunction(formatter)) { + content = formatter(name); + } + + var textColor = isSelected ? textStyleModel.getTextColor() : legendItemModel.get('inactiveColor'); + itemGroup.add(new ZRText({ + style: createTextStyle$1(textStyleModel, { + text: content, + x: textX, + y: itemHeight / 2, + fill: textColor, + align: textAlign, + verticalAlign: 'middle' + }, { + inheritColor: textColor + }) + })); // Add a invisible rect to increase the area of mouse hover + + var hitRect = new Rect({ + shape: itemGroup.getBoundingRect(), + style: { + // Cannot use 'invisible' because SVG SSR will miss the node + fill: 'transparent' + } + }); + var tooltipModel = legendItemModel.getModel('tooltip'); + + if (tooltipModel.get('show')) { + setTooltipConfig({ + el: hitRect, + componentModel: legendModel, + itemName: name, + itemTooltipOption: tooltipModel.option + }); + } + + itemGroup.add(hitRect); + itemGroup.eachChild(function (child) { + child.silent = true; + }); + hitRect.silent = !selectMode; + this.getContentGroup().add(itemGroup); + enableHoverEmphasis(itemGroup); // @ts-ignore + + itemGroup.__legendDataIndex = dataIndex; + return itemGroup; + }; + + LegendView.prototype.layoutInner = function (legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition) { + var contentGroup = this.getContentGroup(); + var selectorGroup = this.getSelectorGroup(); // Place items in contentGroup. + + box(legendModel.get('orient'), contentGroup, legendModel.get('itemGap'), maxSize.width, maxSize.height); + var contentRect = contentGroup.getBoundingRect(); + var contentPos = [-contentRect.x, -contentRect.y]; + selectorGroup.markRedraw(); + contentGroup.markRedraw(); + + if (selector) { + // Place buttons in selectorGroup + box( // Buttons in selectorGroup always layout horizontally + 'horizontal', selectorGroup, legendModel.get('selectorItemGap', true)); + var selectorRect = selectorGroup.getBoundingRect(); + var selectorPos = [-selectorRect.x, -selectorRect.y]; + var selectorButtonGap = legendModel.get('selectorButtonGap', true); + var orientIdx = legendModel.getOrient().index; + var wh = orientIdx === 0 ? 'width' : 'height'; + var hw = orientIdx === 0 ? 'height' : 'width'; + var yx = orientIdx === 0 ? 'y' : 'x'; + + if (selectorPosition === 'end') { + selectorPos[orientIdx] += contentRect[wh] + selectorButtonGap; + } else { + contentPos[orientIdx] += selectorRect[wh] + selectorButtonGap; + } // Always align selector to content as 'middle' + + + selectorPos[1 - orientIdx] += contentRect[hw] / 2 - selectorRect[hw] / 2; + selectorGroup.x = selectorPos[0]; + selectorGroup.y = selectorPos[1]; + contentGroup.x = contentPos[0]; + contentGroup.y = contentPos[1]; + var mainRect = { + x: 0, + y: 0 + }; + mainRect[wh] = contentRect[wh] + selectorButtonGap + selectorRect[wh]; + mainRect[hw] = Math.max(contentRect[hw], selectorRect[hw]); + mainRect[yx] = Math.min(0, selectorRect[yx] + selectorPos[1 - orientIdx]); + return mainRect; + } else { + contentGroup.x = contentPos[0]; + contentGroup.y = contentPos[1]; + return this.group.getBoundingRect(); + } + }; + /** + * @protected + */ + + + LegendView.prototype.remove = function () { + this.getContentGroup().removeAll(); + this._isFirstRender = true; + }; + + LegendView.type = 'legend.plain'; + return LegendView; + }(ComponentView); + + function getLegendStyle(iconType, legendItemModel, lineVisualStyle, itemVisualStyle, drawType, isSelected, api) { + /** + * Use series style if is inherit; + * elsewise, use legend style + */ + function handleCommonProps(style, visualStyle) { + // If lineStyle.width is 'auto', it is set to be 2 if series has border + if (style.lineWidth === 'auto') { + style.lineWidth = visualStyle.lineWidth > 0 ? 2 : 0; + } + + each$1(style, function (propVal, propName) { + style[propName] === 'inherit' && (style[propName] = visualStyle[propName]); + }); + } // itemStyle + + + var itemStyleModel = legendItemModel.getModel('itemStyle'); + var itemStyle = itemStyleModel.getItemStyle(); + var iconBrushType = iconType.lastIndexOf('empty', 0) === 0 ? 'fill' : 'stroke'; + var decalStyle = itemStyleModel.getShallow('decal'); + itemStyle.decal = !decalStyle || decalStyle === 'inherit' ? itemVisualStyle.decal : createOrUpdatePatternFromDecal(decalStyle, api); + + if (itemStyle.fill === 'inherit') { + /** + * Series with visualDrawType as 'stroke' should have + * series stroke as legend fill + */ + itemStyle.fill = itemVisualStyle[drawType]; + } + + if (itemStyle.stroke === 'inherit') { + /** + * icon type with "emptyXXX" should use fill color + * in visual style + */ + itemStyle.stroke = itemVisualStyle[iconBrushType]; + } + + if (itemStyle.opacity === 'inherit') { + /** + * Use lineStyle.opacity if drawType is stroke + */ + itemStyle.opacity = (drawType === 'fill' ? itemVisualStyle : lineVisualStyle).opacity; + } + + handleCommonProps(itemStyle, itemVisualStyle); // lineStyle + + var legendLineModel = legendItemModel.getModel('lineStyle'); + var lineStyle = legendLineModel.getLineStyle(); + handleCommonProps(lineStyle, lineVisualStyle); // Fix auto color to real color + + itemStyle.fill === 'auto' && (itemStyle.fill = itemVisualStyle.fill); + itemStyle.stroke === 'auto' && (itemStyle.stroke = itemVisualStyle.fill); + lineStyle.stroke === 'auto' && (lineStyle.stroke = itemVisualStyle.fill); + + if (!isSelected) { + var borderWidth = legendItemModel.get('inactiveBorderWidth'); + /** + * Since stroke is set to be inactiveBorderColor, it may occur that + * there is no border in series but border in legend, so we need to + * use border only when series has border if is set to be auto + */ + + var visualHasBorder = itemStyle[iconBrushType]; + itemStyle.lineWidth = borderWidth === 'auto' ? itemVisualStyle.lineWidth > 0 && visualHasBorder ? 2 : 0 : itemStyle.lineWidth; + itemStyle.fill = legendItemModel.get('inactiveColor'); + itemStyle.stroke = legendItemModel.get('inactiveBorderColor'); + lineStyle.stroke = legendLineModel.get('inactiveColor'); + lineStyle.lineWidth = legendLineModel.get('inactiveWidth'); + } + + return { + itemStyle: itemStyle, + lineStyle: lineStyle + }; + } + + function getDefaultLegendIcon(opt) { + var symboType = opt.icon || 'roundRect'; + var icon = createSymbol(symboType, 0, 0, opt.itemWidth, opt.itemHeight, opt.itemStyle.fill, opt.symbolKeepAspect); + icon.setStyle(opt.itemStyle); + icon.rotation = (opt.iconRotate || 0) * Math.PI / 180; + icon.setOrigin([opt.itemWidth / 2, opt.itemHeight / 2]); + + if (symboType.indexOf('empty') > -1) { + icon.style.stroke = icon.style.fill; + icon.style.fill = tokens.color.neutral00; + icon.style.lineWidth = 2; + } + + return icon; + } + + function dispatchSelectAction(seriesName, dataName, api, excludeSeriesId) { + // downplay before unselect + dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId); + api.dispatchAction({ + type: 'legendToggleSelect', + name: seriesName != null ? seriesName : dataName + }); // highlight after select + // TODO highlight immediately may cause animation loss. + + dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId); + } + + function isUseHoverLayer(api) { + var list = api.getZr().storage.getDisplayList(); + var emphasisState; + var i = 0; + var len = list.length; + + while (i < len && !(emphasisState = list[i].states.emphasis)) { + i++; + } + + return emphasisState && emphasisState.hoverLayer; + } + + function dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId) { + // If element hover will move to a hoverLayer. + if (!isUseHoverLayer(api)) { + api.dispatchAction({ + type: 'highlight', + seriesName: seriesName, + name: dataName, + excludeSeriesId: excludeSeriesId + }); + } + } + + function dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId) { + // If element hover will move to a hoverLayer. + if (!isUseHoverLayer(api)) { + api.dispatchAction({ + type: 'downplay', + seriesName: seriesName, + name: dataName, + excludeSeriesId: excludeSeriesId + }); + } + } + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + function legendFilter(ecModel) { + var legendModels = ecModel.findComponents({ + mainType: 'legend' + }); + + if (legendModels && legendModels.length) { + ecModel.filterSeries(function (series) { + // If in any legend component the status is not selected. + // Because in legend series is assumed selected when it is not in the legend data. + for (var i = 0; i < legendModels.length; i++) { + if (!legendModels[i].isSelected(series.name)) { + return false; + } + } + + return true; + }); + } + } + + function legendSelectActionHandler(methodName, payload, ecModel) { + var isAllSelect = methodName === 'allSelect' || methodName === 'inverseSelect'; + var selectedMap = {}; + var actionLegendIndices = []; + ecModel.eachComponent({ + mainType: 'legend', + query: payload + }, function (legendModel) { + if (isAllSelect) { + legendModel[methodName](); + } else { + legendModel[methodName](payload.name); + } + + makeSelectedMap(legendModel, selectedMap); + actionLegendIndices.push(legendModel.componentIndex); + }); + var allSelectedMap = {}; // make selectedMap from all legend components + + ecModel.eachComponent('legend', function (legendModel) { + each$4(selectedMap, function (isSelected, name) { + // Force other legend has same selected status + // Or the first is toggled to true and other are toggled to false + // In the case one legend has some item unSelected in option. And if other legend + // doesn't has the item, they will assume it is selected. + legendModel[isSelected ? 'select' : 'unSelect'](name); + }); + makeSelectedMap(legendModel, allSelectedMap); + }); // Return the event explicitly + + return isAllSelect ? { + selected: allSelectedMap, + // return legendIndex array to tell the developers which legends are allSelect / inverseSelect + legendIndex: actionLegendIndices + } : { + name: payload.name, + selected: allSelectedMap + }; + } + + function makeSelectedMap(legendModel, out) { + var selectedMap = out || {}; + each$4(legendModel.getData(), function (model) { + var name = model.get('name'); // Wrap element + + if (name === '\n' || name === '') { + return; + } + + var isItemSelected = legendModel.isSelected(name); + + if (hasOwn(selectedMap, name)) { + // Unselected if any legend is unselected + selectedMap[name] = selectedMap[name] && isItemSelected; + } else { + selectedMap[name] = isItemSelected; + } + }); + return selectedMap; + } + + function installLegendAction(registers) { + /** + * @event legendToggleSelect + * @type {Object} + * @property {string} type 'legendToggleSelect' + * @property {string} [from] + * @property {string} name Series name or data item name + */ + registers.registerAction('legendToggleSelect', 'legendselectchanged', curry$1(legendSelectActionHandler, 'toggleSelected')); + registers.registerAction('legendAllSelect', 'legendselectall', curry$1(legendSelectActionHandler, 'allSelect')); + registers.registerAction('legendInverseSelect', 'legendinverseselect', curry$1(legendSelectActionHandler, 'inverseSelect')); + /** + * @event legendSelect + * @type {Object} + * @property {string} type 'legendSelect' + * @property {string} name Series name or data item name + */ + + registers.registerAction('legendSelect', 'legendselected', curry$1(legendSelectActionHandler, 'select')); + /** + * @event legendUnSelect + * @type {Object} + * @property {string} type 'legendUnSelect' + * @property {string} name Series name or data item name + */ + + registers.registerAction('legendUnSelect', 'legendunselected', curry$1(legendSelectActionHandler, 'unSelect')); + } + + function install$5(registers) { + registers.registerComponentModel(LegendModel); + registers.registerComponentView(LegendView); + registers.registerProcessor(registers.PRIORITY.PROCESSOR.SERIES_FILTER, legendFilter); + registers.registerSubTypeDefaulter('legend', function () { + return 'plain'; + }); + installLegendAction(registers); + } + + var ScrollableLegendModel = + /** @class */ + function (_super) { + __extends(ScrollableLegendModel, _super); + + function ScrollableLegendModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ScrollableLegendModel.type; + return _this; + } + /** + * @param {number} scrollDataIndex + */ + + + ScrollableLegendModel.prototype.setScrollDataIndex = function (scrollDataIndex) { + this.option.scrollDataIndex = scrollDataIndex; + }; + + ScrollableLegendModel.prototype.init = function (option, parentModel, ecModel) { + var inputPositionParams = getLayoutParams(option); + + _super.prototype.init.call(this, option, parentModel, ecModel); + + mergeAndNormalizeLayoutParams(this, option, inputPositionParams); + }; + /** + * @override + */ + + + ScrollableLegendModel.prototype.mergeOption = function (option, ecModel) { + _super.prototype.mergeOption.call(this, option, ecModel); + + mergeAndNormalizeLayoutParams(this, this.option, option); + }; + + ScrollableLegendModel.type = 'legend.scroll'; + ScrollableLegendModel.defaultOption = inheritDefaultOption(LegendModel.defaultOption, { + scrollDataIndex: 0, + pageButtonItemGap: 5, + pageButtonGap: null, + pageButtonPosition: 'end', + pageFormatter: '{current}/{total}', + pageIcons: { + horizontal: ['M0,0L12,-10L12,10z', 'M0,0L-12,-10L-12,10z'], + vertical: ['M0,0L20,0L10,-20z', 'M0,0L20,0L10,20z'] + }, + pageIconColor: tokens.color.accent50, + pageIconInactiveColor: tokens.color.accent10, + pageIconSize: 15, + pageTextStyle: { + color: tokens.color.tertiary + }, + animationDurationUpdate: 800 + }); + return ScrollableLegendModel; + }(LegendModel); // Do not `ignoreSize` to enable setting {left: 10, right: 10}. + + + function mergeAndNormalizeLayoutParams(legendModel, target, raw) { + var orient = legendModel.getOrient(); + var ignoreSize = [1, 1]; + ignoreSize[orient.index] = 0; + mergeLayoutParam(target, raw, { + type: 'box', + ignoreSize: !!ignoreSize + }); + } + + var Group = Group$2; + var WH = ['width', 'height']; + var XY = ['x', 'y']; + + var ScrollableLegendView = + /** @class */ + function (_super) { + __extends(ScrollableLegendView, _super); + + function ScrollableLegendView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = ScrollableLegendView.type; + _this.newlineDisabled = true; + _this._currentIndex = 0; + return _this; + } + + ScrollableLegendView.prototype.init = function () { + _super.prototype.init.call(this); + + this.group.add(this._containerGroup = new Group()); + + this._containerGroup.add(this.getContentGroup()); + + this.group.add(this._controllerGroup = new Group()); + }; + /** + * @override + */ + + + ScrollableLegendView.prototype.resetInner = function () { + _super.prototype.resetInner.call(this); + + this._controllerGroup.removeAll(); + + this._containerGroup.removeClipPath(); + + this._containerGroup.__rectSize = null; + }; + /** + * @override + */ + + + ScrollableLegendView.prototype.renderInner = function (itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition) { + var self = this; // Render content items. + + _super.prototype.renderInner.call(this, itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition); + + var controllerGroup = this._controllerGroup; // FIXME: support be 'auto' adapt to size number text length, + // e.g., '3/12345' should not overlap with the control arrow button. + + var pageIconSize = legendModel.get('pageIconSize', true); + var pageIconSizeArr = isArray(pageIconSize) ? pageIconSize : [pageIconSize, pageIconSize]; + createPageButton('pagePrev', 0); + var pageTextStyleModel = legendModel.getModel('pageTextStyle'); + controllerGroup.add(new ZRText({ + name: 'pageText', + style: { + // Placeholder to calculate a proper layout. + text: 'xx/xx', + fill: pageTextStyleModel.getTextColor(), + font: pageTextStyleModel.getFont(), + verticalAlign: 'middle', + align: 'center' + }, + silent: true + })); + createPageButton('pageNext', 1); + + function createPageButton(name, iconIdx) { + var pageDataIndexName = name + 'DataIndex'; + var icon = createIcon(legendModel.get('pageIcons', true)[legendModel.getOrient().name][iconIdx], { + // Buttons will be created in each render, so we do not need + // to worry about avoiding using legendModel kept in scope. + onclick: bind$1(self._pageGo, self, pageDataIndexName, legendModel, api) + }, { + x: -pageIconSizeArr[0] / 2, + y: -pageIconSizeArr[1] / 2, + width: pageIconSizeArr[0], + height: pageIconSizeArr[1] + }); + icon.name = name; + controllerGroup.add(icon); + } + }; + /** + * @override + */ + + + ScrollableLegendView.prototype.layoutInner = function (legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition) { + var selectorGroup = this.getSelectorGroup(); + var orientIdx = legendModel.getOrient().index; + var wh = WH[orientIdx]; + var xy = XY[orientIdx]; + var hw = WH[1 - orientIdx]; + var yx = XY[1 - orientIdx]; + selector && box( // Buttons in selectorGroup always layout horizontally + 'horizontal', selectorGroup, legendModel.get('selectorItemGap', true)); + var selectorButtonGap = legendModel.get('selectorButtonGap', true); + var selectorRect = selectorGroup.getBoundingRect(); + var selectorPos = [-selectorRect.x, -selectorRect.y]; + var processMaxSize = clone$3(maxSize); + selector && (processMaxSize[wh] = maxSize[wh] - selectorRect[wh] - selectorButtonGap); + + var mainRect = this._layoutContentAndController(legendModel, isFirstRender, processMaxSize, orientIdx, wh, hw, yx, xy); + + if (selector) { + if (selectorPosition === 'end') { + selectorPos[orientIdx] += mainRect[wh] + selectorButtonGap; + } else { + var offset = selectorRect[wh] + selectorButtonGap; + selectorPos[orientIdx] -= offset; + mainRect[xy] -= offset; + } + + mainRect[wh] += selectorRect[wh] + selectorButtonGap; + selectorPos[1 - orientIdx] += mainRect[yx] + mainRect[hw] / 2 - selectorRect[hw] / 2; + mainRect[hw] = Math.max(mainRect[hw], selectorRect[hw]); + mainRect[yx] = Math.min(mainRect[yx], selectorRect[yx] + selectorPos[1 - orientIdx]); + selectorGroup.x = selectorPos[0]; + selectorGroup.y = selectorPos[1]; + selectorGroup.markRedraw(); + } + + return mainRect; + }; + + ScrollableLegendView.prototype._layoutContentAndController = function (legendModel, isFirstRender, maxSize, orientIdx, wh, hw, yx, xy) { + var contentGroup = this.getContentGroup(); + var containerGroup = this._containerGroup; + var controllerGroup = this._controllerGroup; // Place items in contentGroup. + + box(legendModel.get('orient'), contentGroup, legendModel.get('itemGap'), !orientIdx ? null : maxSize.width, orientIdx ? null : maxSize.height); + box( // Buttons in controller are layout always horizontally. + 'horizontal', controllerGroup, legendModel.get('pageButtonItemGap', true)); + var contentRect = contentGroup.getBoundingRect(); + var controllerRect = controllerGroup.getBoundingRect(); + var showController = this._showController = contentRect[wh] > maxSize[wh]; // In case that the inner elements of contentGroup layout do not based on [0, 0] + + var contentPos = [-contentRect.x, -contentRect.y]; // Remain contentPos when scroll animation perfroming. + // If first rendering, `contentGroup.position` is [0, 0], which + // does not make sense and may cause unexepcted animation if adopted. + + if (!isFirstRender) { + contentPos[orientIdx] = contentGroup[xy]; + } // Layout container group based on 0. + + + var containerPos = [0, 0]; + var controllerPos = [-controllerRect.x, -controllerRect.y]; + var pageButtonGap = retrieve2(legendModel.get('pageButtonGap', true), legendModel.get('itemGap', true)); // Place containerGroup and controllerGroup and contentGroup. + + if (showController) { + var pageButtonPosition = legendModel.get('pageButtonPosition', true); // controller is on the right / bottom. + + if (pageButtonPosition === 'end') { + controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh]; + } // controller is on the left / top. + else { + containerPos[orientIdx] += controllerRect[wh] + pageButtonGap; + } + } // Always align controller to content as 'middle'. + + + controllerPos[1 - orientIdx] += contentRect[hw] / 2 - controllerRect[hw] / 2; + contentGroup.setPosition(contentPos); + containerGroup.setPosition(containerPos); + controllerGroup.setPosition(controllerPos); // Calculate `mainRect` and set `clipPath`. + // mainRect should not be calculated by `this.group.getBoundingRect()` + // for sake of the overflow. + + var mainRect = { + x: 0, + y: 0 + }; // Consider content may be overflow (should be clipped). + + mainRect[wh] = showController ? maxSize[wh] : contentRect[wh]; + mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw]); // `containerRect[yx] + containerPos[1 - orientIdx]` is 0. + + mainRect[yx] = Math.min(0, controllerRect[yx] + controllerPos[1 - orientIdx]); + containerGroup.__rectSize = maxSize[wh]; + + if (showController) { + var clipShape = { + x: 0, + y: 0 + }; + clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap, 0); + clipShape[hw] = mainRect[hw]; + containerGroup.setClipPath(new Rect({ + shape: clipShape + })); // Consider content may be larger than container, container rect + // can not be obtained from `containerGroup.getBoundingRect()`. + + containerGroup.__rectSize = clipShape[wh]; + } else { + // Do not remove or ignore controller. Keep them set as placeholders. + controllerGroup.eachChild(function (child) { + child.attr({ + invisible: true, + silent: true + }); + }); + } // Content translate animation. + + + var pageInfo = this._getPageInfo(legendModel); + + pageInfo.pageIndex != null && updateProps$1(contentGroup, { + x: pageInfo.contentPosition[0], + y: pageInfo.contentPosition[1] + }, // When switch from "show controller" to "not show controller", view should be + // updated immediately without animation, otherwise causes weird effect. + showController ? legendModel : null); + + this._updatePageInfoView(legendModel, pageInfo); + + return mainRect; + }; + + ScrollableLegendView.prototype._pageGo = function (to, legendModel, api) { + var scrollDataIndex = this._getPageInfo(legendModel)[to]; + + scrollDataIndex != null && api.dispatchAction({ + type: 'legendScroll', + scrollDataIndex: scrollDataIndex, + legendId: legendModel.id + }); + }; + + ScrollableLegendView.prototype._updatePageInfoView = function (legendModel, pageInfo) { + var controllerGroup = this._controllerGroup; + each$4(['pagePrev', 'pageNext'], function (name) { + var key = name + 'DataIndex'; + var canJump = pageInfo[key] != null; + var icon = controllerGroup.childOfName(name); + + if (icon) { + icon.setStyle('fill', canJump ? legendModel.get('pageIconColor', true) : legendModel.get('pageIconInactiveColor', true)); + icon.cursor = canJump ? 'pointer' : 'default'; + } + }); + var pageText = controllerGroup.childOfName('pageText'); + var pageFormatter = legendModel.get('pageFormatter'); + var pageIndex = pageInfo.pageIndex; + var current = pageIndex != null ? pageIndex + 1 : 0; + var total = pageInfo.pageCount; + pageText && pageFormatter && pageText.setStyle('text', isString(pageFormatter) ? pageFormatter.replace('{current}', current == null ? '' : current + '').replace('{total}', total == null ? '' : total + '') : pageFormatter({ + current: current, + total: total + })); + }; + /** + * contentPosition: Array., null when data item not found. + * pageIndex: number, null when data item not found. + * pageCount: number, always be a number, can be 0. + * pagePrevDataIndex: number, null when no previous page. + * pageNextDataIndex: number, null when no next page. + * } + */ + + + ScrollableLegendView.prototype._getPageInfo = function (legendModel) { + var scrollDataIndex = legendModel.get('scrollDataIndex', true); + var contentGroup = this.getContentGroup(); + var containerRectSize = this._containerGroup.__rectSize; + var orientIdx = legendModel.getOrient().index; + var wh = WH[orientIdx]; + var xy = XY[orientIdx]; + + var targetItemIndex = this._findTargetItemIndex(scrollDataIndex); + + var children = contentGroup.children(); + var targetItem = children[targetItemIndex]; + var itemCount = children.length; + var pCount = !itemCount ? 0 : 1; + var result = { + contentPosition: [contentGroup.x, contentGroup.y], + pageCount: pCount, + pageIndex: pCount - 1, + pagePrevDataIndex: null, + pageNextDataIndex: null + }; + + if (!targetItem) { + return result; + } + + var targetItemInfo = getItemInfo(targetItem); + result.contentPosition[orientIdx] = -targetItemInfo.s; // Strategy: + // (1) Always align based on the left/top most item. + // (2) It is user-friendly that the last item shown in the + // current window is shown at the begining of next window. + // Otherwise if half of the last item is cut by the window, + // it will have no chance to display entirely. + // (3) Consider that item size probably be different, we + // have calculate pageIndex by size rather than item index, + // and we can not get page index directly by division. + // (4) The window is to narrow to contain more than + // one item, we should make sure that the page can be fliped. + + for (var i = targetItemIndex + 1, winStartItemInfo = targetItemInfo, winEndItemInfo = targetItemInfo, currItemInfo = null; i <= itemCount; ++i) { + currItemInfo = getItemInfo(children[i]); + + if ( // Half of the last item is out of the window. + !currItemInfo && winEndItemInfo.e > winStartItemInfo.s + containerRectSize // If the current item does not intersect with the window, the new page + // can be started at the current item or the last item. + || currItemInfo && !intersect(currItemInfo, winStartItemInfo.s)) { + if (winEndItemInfo.i > winStartItemInfo.i) { + winStartItemInfo = winEndItemInfo; + } else { + // e.g., when page size is smaller than item size. + winStartItemInfo = currItemInfo; + } + + if (winStartItemInfo) { + if (result.pageNextDataIndex == null) { + result.pageNextDataIndex = winStartItemInfo.i; + } + + ++result.pageCount; + } + } + + winEndItemInfo = currItemInfo; + } + + for (var i = targetItemIndex - 1, winStartItemInfo = targetItemInfo, winEndItemInfo = targetItemInfo, currItemInfo = null; i >= -1; --i) { + currItemInfo = getItemInfo(children[i]); + + if ( // If the the end item does not intersect with the window started + // from the current item, a page can be settled. + (!currItemInfo || !intersect(winEndItemInfo, currItemInfo.s) // e.g., when page size is smaller than item size. + ) && winStartItemInfo.i < winEndItemInfo.i) { + winEndItemInfo = winStartItemInfo; + + if (result.pagePrevDataIndex == null) { + result.pagePrevDataIndex = winStartItemInfo.i; + } + + ++result.pageCount; + ++result.pageIndex; + } + + winStartItemInfo = currItemInfo; + } + + return result; + + function getItemInfo(el) { + if (el) { + var itemRect = el.getBoundingRect(); + var start = itemRect[xy] + el[xy]; + return { + s: start, + e: start + itemRect[wh], + i: el.__legendDataIndex + }; + } + } + + function intersect(itemInfo, winStart) { + return itemInfo.e >= winStart && itemInfo.s <= winStart + containerRectSize; + } + }; + + ScrollableLegendView.prototype._findTargetItemIndex = function (targetDataIndex) { + if (!this._showController) { + return 0; + } + + var index; + var contentGroup = this.getContentGroup(); + var defaultIndex; + contentGroup.eachChild(function (child, idx) { + var legendDataIdx = child.__legendDataIndex; // FIXME + // If the given targetDataIndex (from model) is illegal, + // we use defaultIndex. But the index on the legend model and + // action payload is still illegal. That case will not be + // changed until some scenario requires. + + if (defaultIndex == null && legendDataIdx != null) { + defaultIndex = idx; + } + + if (legendDataIdx === targetDataIndex) { + index = idx; + } + }); + return index != null ? index : defaultIndex; + }; + + ScrollableLegendView.type = 'legend.scroll'; + return ScrollableLegendView; + }(LegendView); + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + /** + * AUTO-GENERATED FILE. DO NOT MODIFY. + */ + + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + + function installScrollableLegendAction(registers) { + /** + * @event legendScroll + * @type {Object} + * @property {string} type 'legendScroll' + * @property {string} scrollDataIndex + */ + registers.registerAction('legendScroll', 'legendscroll', function (payload, ecModel) { + var scrollDataIndex = payload.scrollDataIndex; + scrollDataIndex != null && ecModel.eachComponent({ + mainType: 'legend', + subType: 'scroll', + query: payload + }, function (legendModel) { + legendModel.setScrollDataIndex(scrollDataIndex); + }); + }); + } + + function install$4(registers) { + use(install$5); + registers.registerComponentModel(ScrollableLegendModel); + registers.registerComponentView(ScrollableLegendView); + installScrollableLegendAction(registers); + } + + use(install$4); + var inner$5 = makeInner(); + var clone = clone$3; + var bind = bind$1; + /** + * Base axis pointer class in 2D. + */ + + var BaseAxisPointer = + /** @class */ + function () { + function BaseAxisPointer() { + this._dragging = false; + /** + * In px, arbitrary value. Do not set too small, + * no animation is ok for most cases. + */ + + this.animationThreshold = 15; + } + /** + * @implement + */ + + + BaseAxisPointer.prototype.render = function (axisModel, axisPointerModel, api, forceRender) { + var value = axisPointerModel.get('value'); + var status = axisPointerModel.get('status'); // Bind them to `this`, not in closure, otherwise they will not + // be replaced when user calling setOption in not merge mode. + + this._axisModel = axisModel; + this._axisPointerModel = axisPointerModel; + this._api = api; // Optimize: `render` will be called repeatedly during mouse move. + // So it is power consuming if performing `render` each time, + // especially on mobile device. + + if (!forceRender && this._lastValue === value && this._lastStatus === status) { + return; + } + + this._lastValue = value; + this._lastStatus = status; + var group = this._group; + var handle = this._handle; + + if (!status || status === 'hide') { + // Do not clear here, for animation better. + group && group.hide(); + handle && handle.hide(); + return; + } + + group && group.show(); + handle && handle.show(); // Otherwise status is 'show' + + var elOption = {}; + this.makeElOption(elOption, value, axisModel, axisPointerModel, api); // Enable change axis pointer type. + + var graphicKey = elOption.graphicKey; + + if (graphicKey !== this._lastGraphicKey) { + this.clear(api); + } + + this._lastGraphicKey = graphicKey; + var moveAnimation = this._moveAnimation = this.determineAnimation(axisModel, axisPointerModel); + + if (!group) { + group = this._group = new Group$2(); + this.createPointerEl(group, elOption, axisModel, axisPointerModel); + this.createLabelEl(group, elOption, axisModel, axisPointerModel); + api.getZr().add(group); + } else { + var doUpdateProps = curry$1(updateProps, axisPointerModel, moveAnimation); + this.updatePointerEl(group, elOption, doUpdateProps); + this.updateLabelEl(group, elOption, doUpdateProps, axisPointerModel); + } + + updateMandatoryProps(group, axisPointerModel, true); + + this._renderHandle(value); + }; + /** + * @implement + */ + + + BaseAxisPointer.prototype.remove = function (api) { + this.clear(api); + }; + /** + * @implement + */ + + + BaseAxisPointer.prototype.dispose = function (api) { + this.clear(api); + }; + /** + * @protected + */ + + + BaseAxisPointer.prototype.determineAnimation = function (axisModel, axisPointerModel) { + var animation = axisPointerModel.get('animation'); + var axis = axisModel.axis; + var isCategoryAxis = axis.type === 'category'; + var useSnap = axisPointerModel.get('snap'); // Value axis without snap always do not snap. + + if (!useSnap && !isCategoryAxis) { + return false; + } + + if (animation === 'auto' || animation == null) { + var animationThreshold = this.animationThreshold; + + if (isCategoryAxis && axis.getBandWidth() > animationThreshold) { + return true; + } // It is important to auto animation when snap used. Consider if there is + // a dataZoom, animation will be disabled when too many points exist, while + // it will be enabled for better visual effect when little points exist. + + + if (useSnap) { + var seriesDataCount = getAxisInfo$1(axisModel).seriesDataCount; + var axisExtent = axis.getExtent(); // Approximate band width + + return Math.abs(axisExtent[0] - axisExtent[1]) / seriesDataCount > animationThreshold; + } + + return false; + } + + return animation === true; + }; + /** + * add {pointer, label, graphicKey} to elOption + * @protected + */ + + + BaseAxisPointer.prototype.makeElOption = function (elOption, value, axisModel, axisPointerModel, api) {// Should be implemenented by sub-class. + }; + /** + * @protected + */ + + + BaseAxisPointer.prototype.createPointerEl = function (group, elOption, axisModel, axisPointerModel) { + var pointerOption = elOption.pointer; + + if (pointerOption) { + var pointerEl = inner$5(group).pointerEl = new graphic$1[pointerOption.type](clone(elOption.pointer)); + group.add(pointerEl); + } + }; + /** + * @protected + */ + + + BaseAxisPointer.prototype.createLabelEl = function (group, elOption, axisModel, axisPointerModel) { + if (elOption.label) { + var labelEl = inner$5(group).labelEl = new ZRText(clone(elOption.label)); + group.add(labelEl); + updateLabelShowHide(labelEl, axisPointerModel); + } + }; + /** + * @protected + */ + + + BaseAxisPointer.prototype.updatePointerEl = function (group, elOption, updateProps) { + var pointerEl = inner$5(group).pointerEl; + + if (pointerEl && elOption.pointer) { + pointerEl.setStyle(elOption.pointer.style); + updateProps(pointerEl, { + shape: elOption.pointer.shape + }); + } + }; + /** + * @protected + */ + + + BaseAxisPointer.prototype.updateLabelEl = function (group, elOption, updateProps, axisPointerModel) { + var labelEl = inner$5(group).labelEl; + + if (labelEl) { + labelEl.setStyle(elOption.label.style); + updateProps(labelEl, { + // Consider text length change in vertical axis, animation should + // be used on shape, otherwise the effect will be weird. + // TODOTODO + // shape: elOption.label.shape, + x: elOption.label.x, + y: elOption.label.y + }); + updateLabelShowHide(labelEl, axisPointerModel); + } + }; + /** + * @private + */ + + + BaseAxisPointer.prototype._renderHandle = function (value) { + if (this._dragging || !this.updateHandleTransform) { + return; + } + + var axisPointerModel = this._axisPointerModel; + + var zr = this._api.getZr(); + + var handle = this._handle; + var handleModel = axisPointerModel.getModel('handle'); + var status = axisPointerModel.get('status'); + + if (!handleModel.get('show') || !status || status === 'hide') { + handle && zr.remove(handle); + this._handle = null; + return; + } + + var isInit; + + if (!this._handle) { + isInit = true; + handle = this._handle = createIcon(handleModel.get('icon'), { + cursor: 'move', + draggable: true, + onmousemove: function (e) { + // For mobile device, prevent screen slider on the button. + stop(e.event); + }, + onmousedown: bind(this._onHandleDragMove, this, 0, 0), + drift: bind(this._onHandleDragMove, this), + ondragend: bind(this._onHandleDragEnd, this) + }); + zr.add(handle); + } + + updateMandatoryProps(handle, axisPointerModel, false); // update style + + handle.setStyle(handleModel.getItemStyle(null, ['color', 'borderColor', 'borderWidth', 'opacity', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'])); // update position + + var handleSize = handleModel.get('size'); + + if (!isArray(handleSize)) { + handleSize = [handleSize, handleSize]; + } + + handle.scaleX = handleSize[0] / 2; + handle.scaleY = handleSize[1] / 2; + createOrUpdate(this, '_doDispatchAxisPointer', handleModel.get('throttle') || 0, 'fixRate'); + + this._moveHandleToValue(value, isInit); + }; + + BaseAxisPointer.prototype._moveHandleToValue = function (value, isInit) { + updateProps(this._axisPointerModel, !isInit && this._moveAnimation, this._handle, getHandleTransProps(this.getHandleTransform(value, this._axisModel, this._axisPointerModel))); + }; + + BaseAxisPointer.prototype._onHandleDragMove = function (dx, dy) { + var handle = this._handle; + + if (!handle) { + return; + } + + this._dragging = true; // Persistent for throttle. + + var trans = this.updateHandleTransform(getHandleTransProps(handle), [dx, dy], this._axisModel, this._axisPointerModel); + this._payloadInfo = trans; + handle.stopAnimation(); + handle.attr(getHandleTransProps(trans)); + inner$5(handle).lastProp = null; + + this._doDispatchAxisPointer(); + }; + /** + * Throttled method. + */ + + + BaseAxisPointer.prototype._doDispatchAxisPointer = function () { + var handle = this._handle; + + if (!handle) { + return; + } + + var payloadInfo = this._payloadInfo; + var axisModel = this._axisModel; + + this._api.dispatchAction({ + type: 'updateAxisPointer', + x: payloadInfo.cursorPoint[0], + y: payloadInfo.cursorPoint[1], + tooltipOption: payloadInfo.tooltipOption, + axesInfo: [{ + axisDim: axisModel.axis.dim, + axisIndex: axisModel.componentIndex + }] + }); + }; + + BaseAxisPointer.prototype._onHandleDragEnd = function () { + this._dragging = false; + var handle = this._handle; + + if (!handle) { + return; + } + + var value = this._axisPointerModel.get('value'); // Consider snap or categroy axis, handle may be not consistent with + // axisPointer. So move handle to align the exact value position when + // drag ended. + + + this._moveHandleToValue(value); // For the effect: tooltip will be shown when finger holding on handle + // button, and will be hidden after finger left handle button. + + + this._api.dispatchAction({ + type: 'hideTip' + }); + }; + /** + * @private + */ + + + BaseAxisPointer.prototype.clear = function (api) { + this._lastValue = null; + this._lastStatus = null; + var zr = api.getZr(); + var group = this._group; + var handle = this._handle; + + if (zr && group) { + this._lastGraphicKey = null; + group && zr.remove(group); + handle && zr.remove(handle); + this._group = null; + this._handle = null; + this._payloadInfo = null; + } + + clear(this, '_doDispatchAxisPointer'); + }; + /** + * @protected + */ + + + BaseAxisPointer.prototype.doClear = function () {// Implemented by sub-class if necessary. + }; + + BaseAxisPointer.prototype.buildLabel = function (xy, wh, xDimIndex) { + xDimIndex = xDimIndex || 0; + return { + x: xy[xDimIndex], + y: xy[1 - xDimIndex], + width: wh[xDimIndex], + height: wh[1 - xDimIndex] + }; + }; + + return BaseAxisPointer; + }(); + + function updateProps(animationModel, moveAnimation, el, props) { + // Animation optimize. + if (!propsEqual(inner$5(el).lastProp, props)) { + inner$5(el).lastProp = props; + moveAnimation ? updateProps$1(el, props, animationModel) : (el.stopAnimation(), el.attr(props)); + } + } + + function propsEqual(lastProps, newProps) { + if (isObject$2(lastProps) && isObject$2(newProps)) { + var equals_1 = true; + each$4(newProps, function (item, key) { + equals_1 = equals_1 && propsEqual(lastProps[key], item); + }); + return !!equals_1; + } else { + return lastProps === newProps; + } + } + + function updateLabelShowHide(labelEl, axisPointerModel) { + labelEl[axisPointerModel.get(['label', 'show']) ? 'show' : 'hide'](); + } + + function getHandleTransProps(trans) { + return { + x: trans.x || 0, + y: trans.y || 0, + rotation: trans.rotation || 0 + }; + } + + function updateMandatoryProps(group, axisPointerModel, silent) { + var z = axisPointerModel.get('z'); + var zlevel = axisPointerModel.get('zlevel'); + group && group.traverse(function (el) { + if (el.type !== 'group') { + z != null && (el.z = z); + zlevel != null && (el.zlevel = zlevel); + el.silent = silent; + } + }); + } + + function buildElStyle(axisPointerModel) { + var axisPointerType = axisPointerModel.get('type'); + var styleModel = axisPointerModel.getModel(axisPointerType + 'Style'); + var style; + + if (axisPointerType === 'line') { + style = styleModel.getLineStyle(); + style.fill = null; + } else if (axisPointerType === 'shadow') { + style = styleModel.getAreaStyle(); + style.stroke = null; + } + + return style; + } + /** + * @param {Function} labelPos {align, verticalAlign, position} + */ + + + function buildLabelElOption(elOption, axisModel, axisPointerModel, api, labelPos) { + var value = axisPointerModel.get('value'); + var text = getValueLabel(value, axisModel.axis, axisModel.ecModel, axisPointerModel.get('seriesDataIndices'), { + precision: axisPointerModel.get(['label', 'precision']), + formatter: axisPointerModel.get(['label', 'formatter']) + }); + var labelModel = axisPointerModel.getModel('label'); + var paddings = normalizeCssArray(labelModel.get('padding') || 0); + var font = labelModel.getFont(); + var textRect = getBoundingRect(text, font); + var position = labelPos.position; + var width = textRect.width + paddings[1] + paddings[3]; + var height = textRect.height + paddings[0] + paddings[2]; // Adjust by align. + + var align = labelPos.align; + align === 'right' && (position[0] -= width); + align === 'center' && (position[0] -= width / 2); + var verticalAlign = labelPos.verticalAlign; + verticalAlign === 'bottom' && (position[1] -= height); + verticalAlign === 'middle' && (position[1] -= height / 2); // Not overflow ec container + + confineInContainer(position, width, height, api); + var bgColor = labelModel.get('backgroundColor'); + + if (!bgColor || bgColor === 'auto') { + bgColor = axisModel.get(['axisLine', 'lineStyle', 'color']); + } + + elOption.label = { + // shape: {x: 0, y: 0, width: width, height: height, r: labelModel.get('borderRadius')}, + x: position[0], + y: position[1], + style: createTextStyle$1(labelModel, { + text: text, + font: font, + fill: labelModel.getTextColor(), + padding: paddings, + backgroundColor: bgColor + }), + // Label should be over axisPointer. + z2: 10 + }; + } // Do not overflow ec container + + + function confineInContainer(position, width, height, api) { + var viewWidth = api.getWidth(); + var viewHeight = api.getHeight(); + position[0] = Math.min(position[0] + width, viewWidth) - width; + position[1] = Math.min(position[1] + height, viewHeight) - height; + position[0] = Math.max(position[0], 0); + position[1] = Math.max(position[1], 0); + } + + function getValueLabel(value, axis, ecModel, seriesDataIndices, opt) { + value = axis.scale.parse(value); + var text = axis.scale.getLabel({ + value: value + }, { + // If `precision` is set, width can be fixed (like '12.00500'), which + // helps to debounce when when moving label. + precision: opt.precision + }); + var formatter = opt.formatter; + + if (formatter) { + var params_1 = { + value: getAxisRawValue(axis, { + value: value + }), + axisDimension: axis.dim, + axisIndex: axis.index, + seriesData: [] + }; + each$4(seriesDataIndices, function (idxItem) { + var series = ecModel.getSeriesByIndex(idxItem.seriesIndex); + var dataIndex = idxItem.dataIndexInside; + var dataParams = series && series.getDataParams(dataIndex); + dataParams && params_1.seriesData.push(dataParams); + }); + + if (isString(formatter)) { + text = formatter.replace('{value}', text); + } else if (isFunction(formatter)) { + text = formatter(params_1); + } + } + + return text; + } + + function getTransformedPosition(axis, value, layoutInfo) { + var transform = create(); + rotate(transform, transform, layoutInfo.rotation); + translate(transform, transform, layoutInfo.position); + return applyTransform([axis.dataToCoord(value), (layoutInfo.labelOffset || 0) + (layoutInfo.labelDirection || 1) * (layoutInfo.labelMargin || 0)], transform); + } + + function buildCartesianSingleLabelElOption(value, elOption, layoutInfo, axisModel, axisPointerModel, api) { + var textLayout = AxisBuilder.innerTextLayout(layoutInfo.rotation, 0, layoutInfo.labelDirection); + layoutInfo.labelMargin = axisPointerModel.get(['label', 'margin']); + buildLabelElOption(elOption, axisModel, axisPointerModel, api, { + position: getTransformedPosition(axisModel.axis, value, layoutInfo), + align: textLayout.textAlign, + verticalAlign: textLayout.textVerticalAlign + }); + } + + function makeLineShape(p1, p2, xDimIndex) { + xDimIndex = xDimIndex || 0; + return { + x1: p1[xDimIndex], + y1: p1[1 - xDimIndex], + x2: p2[xDimIndex], + y2: p2[1 - xDimIndex] + }; + } + + function makeRectShape(xy, wh, xDimIndex) { + xDimIndex = xDimIndex || 0; + return { + x: xy[xDimIndex], + y: xy[1 - xDimIndex], + width: wh[xDimIndex], + height: wh[1 - xDimIndex] + }; + } + + var CartesianAxisPointer = + /** @class */ + function (_super) { + __extends(CartesianAxisPointer, _super); + + function CartesianAxisPointer() { + return _super !== null && _super.apply(this, arguments) || this; + } + /** + * @override + */ + + + CartesianAxisPointer.prototype.makeElOption = function (elOption, value, axisModel, axisPointerModel, api) { + var axis = axisModel.axis; + var grid = axis.grid; + var axisPointerType = axisPointerModel.get('type'); + var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent(); + var pixelValue = axis.toGlobalCoord(axis.dataToCoord(value, true)); + + if (axisPointerType && axisPointerType !== 'none') { + var elStyle = buildElStyle(axisPointerModel); + var pointerOption = pointerShapeBuilder[axisPointerType](axis, pixelValue, otherExtent); + pointerOption.style = elStyle; + elOption.graphicKey = pointerOption.type; + elOption.pointer = pointerOption; + } + + var layoutInfo = layout(grid.getRect(), axisModel); + buildCartesianSingleLabelElOption(value, elOption, layoutInfo, axisModel, axisPointerModel, api); + }; + /** + * @override + */ + + + CartesianAxisPointer.prototype.getHandleTransform = function (value, axisModel, axisPointerModel) { + var layoutInfo = layout(axisModel.axis.grid.getRect(), axisModel, { + labelInside: false + }); + layoutInfo.labelMargin = axisPointerModel.get(['handle', 'margin']); + var pos = getTransformedPosition(axisModel.axis, value, layoutInfo); + return { + x: pos[0], + y: pos[1], + rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0) + }; + }; + /** + * @override + */ + + + CartesianAxisPointer.prototype.updateHandleTransform = function (transform, delta, axisModel, axisPointerModel) { + var axis = axisModel.axis; + var grid = axis.grid; + var axisExtent = axis.getGlobalExtent(true); + var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent(); + var dimIndex = axis.dim === 'x' ? 0 : 1; + var currPosition = [transform.x, transform.y]; + currPosition[dimIndex] += delta[dimIndex]; + currPosition[dimIndex] = Math.min(axisExtent[1], currPosition[dimIndex]); + currPosition[dimIndex] = Math.max(axisExtent[0], currPosition[dimIndex]); + var cursorOtherValue = (otherExtent[1] + otherExtent[0]) / 2; + var cursorPoint = [cursorOtherValue, cursorOtherValue]; + cursorPoint[dimIndex] = currPosition[dimIndex]; // Make tooltip do not overlap axisPointer and in the middle of the grid. + + var tooltipOptions = [{ + verticalAlign: 'middle' + }, { + align: 'center' + }]; + return { + x: currPosition[0], + y: currPosition[1], + rotation: transform.rotation, + cursorPoint: cursorPoint, + tooltipOption: tooltipOptions[dimIndex] + }; + }; + + return CartesianAxisPointer; + }(BaseAxisPointer); + + function getCartesian(grid, axis) { + var opt = {}; + opt[axis.dim + 'AxisIndex'] = axis.index; + return grid.getCartesian(opt); + } + + var pointerShapeBuilder = { + line: function (axis, pixelValue, otherExtent) { + var targetShape = makeLineShape([pixelValue, otherExtent[0]], [pixelValue, otherExtent[1]], getAxisDimIndex(axis)); + return { + type: 'Line', + subPixelOptimize: true, + shape: targetShape + }; + }, + shadow: function (axis, pixelValue, otherExtent) { + var bandWidth = Math.max(1, axis.getBandWidth()); + var span = otherExtent[1] - otherExtent[0]; + return { + type: 'Rect', + shape: makeRectShape([pixelValue - bandWidth / 2, otherExtent[0]], [bandWidth, span], getAxisDimIndex(axis)) + }; + } + }; + + function getAxisDimIndex(axis) { + return axis.dim === 'x' ? 0 : 1; + } + + var AxisPointerModel = + /** @class */ + function (_super) { + __extends(AxisPointerModel, _super); + + function AxisPointerModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = AxisPointerModel.type; + return _this; + } + + AxisPointerModel.type = 'axisPointer'; + AxisPointerModel.defaultOption = { + // 'auto' means that show when triggered by tooltip or handle. + show: 'auto', + // zlevel: 0, + z: 50, + type: 'line', + // axispointer triggered by tootip determine snap automatically, + // see `modelHelper`. + snap: false, + triggerTooltip: true, + triggerEmphasis: true, + value: null, + status: null, + link: [], + // Do not set 'auto' here, otherwise global animation: false + // will not effect at this axispointer. + animation: null, + animationDurationUpdate: 200, + lineStyle: { + color: tokens.color.border, + width: 1, + type: 'dashed' + }, + shadowStyle: { + color: tokens.color.shadowTint + }, + label: { + show: true, + formatter: null, + precision: 'auto', + margin: 3, + color: tokens.color.neutral00, + padding: [5, 7, 5, 7], + backgroundColor: tokens.color.accent60, + borderColor: null, + borderWidth: 0, + borderRadius: 3 + }, + handle: { + show: false, + // eslint-disable-next-line + icon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z', + size: 45, + // handle margin is from symbol center to axis, which is stable when circular move. + margin: 50, + // color: '#1b8bbd' + // color: '#2f4554' + color: tokens.color.accent40, + // For mobile performance + throttle: 40 + } + }; + return AxisPointerModel; + }(ComponentModel); + + var inner$4 = makeInner(); + var each = each$4; + /** + * @param {string} key + * @param {module:echarts/ExtensionAPI} api + * @param {Function} handler + * param: {string} currTrigger + * param: {Array.} point + */ + + function register(key, api, handler) { + if (env.node) { + return; + } + + var zr = api.getZr(); + inner$4(zr).records || (inner$4(zr).records = {}); + initGlobalListeners(zr, api); + var record = inner$4(zr).records[key] || (inner$4(zr).records[key] = {}); + record.handler = handler; + } + + function initGlobalListeners(zr, api) { + if (inner$4(zr).initialized) { + return; + } + + inner$4(zr).initialized = true; + useHandler('click', curry$1(doEnter, 'click')); + useHandler('mousemove', curry$1(doEnter, 'mousemove')); // useHandler('mouseout', onLeave); + + useHandler('globalout', onLeave); + + function useHandler(eventType, cb) { + zr.on(eventType, function (e) { + var dis = makeDispatchAction$1(api); + each(inner$4(zr).records, function (record) { + record && cb(record, e, dis.dispatchAction); + }); + dispatchTooltipFinally(dis.pendings, api); + }); + } + } + + function dispatchTooltipFinally(pendings, api) { + var showLen = pendings.showTip.length; + var hideLen = pendings.hideTip.length; + var actuallyPayload; + + if (showLen) { + actuallyPayload = pendings.showTip[showLen - 1]; + } else if (hideLen) { + actuallyPayload = pendings.hideTip[hideLen - 1]; + } + + if (actuallyPayload) { + actuallyPayload.dispatchAction = null; + api.dispatchAction(actuallyPayload); + } + } + + function onLeave(record, e, dispatchAction) { + record.handler('leave', null, dispatchAction); + } + + function doEnter(currTrigger, record, e, dispatchAction) { + record.handler(currTrigger, e, dispatchAction); + } + + function makeDispatchAction$1(api) { + var pendings = { + showTip: [], + hideTip: [] + }; // FIXME + // better approach? + // 'showTip' and 'hideTip' can be triggered by axisPointer and tooltip, + // which may be conflict, (axisPointer call showTip but tooltip call hideTip); + // So we have to add "final stage" to merge those dispatched actions. + + var dispatchAction = function (payload) { + var pendingList = pendings[payload.type]; + + if (pendingList) { + pendingList.push(payload); + } else { + payload.dispatchAction = dispatchAction; + api.dispatchAction(payload); + } + }; + + return { + dispatchAction: dispatchAction, + pendings: pendings + }; + } + + function unregister(key, api) { + if (env.node) { + return; + } + + var zr = api.getZr(); + var record = (inner$4(zr).records || {})[key]; + + if (record) { + inner$4(zr).records[key] = null; + } + } + + var AxisPointerView = + /** @class */ + function (_super) { + __extends(AxisPointerView, _super); + + function AxisPointerView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = AxisPointerView.type; + return _this; + } + + AxisPointerView.prototype.render = function (globalAxisPointerModel, ecModel, api) { + var globalTooltipModel = ecModel.getComponent('tooltip'); + var triggerOn = globalAxisPointerModel.get('triggerOn') || globalTooltipModel && globalTooltipModel.get('triggerOn') || 'mousemove|click'; // Register global listener in AxisPointerView to enable + // AxisPointerView to be independent to Tooltip. + + register('axisPointer', api, function (currTrigger, e, dispatchAction) { + // If 'none', it is not controlled by mouse totally. + if (triggerOn !== 'none' && (currTrigger === 'leave' || triggerOn.indexOf(currTrigger) >= 0)) { + dispatchAction({ + type: 'updateAxisPointer', + currTrigger: currTrigger, + x: e && e.offsetX, + y: e && e.offsetY + }); + } + }); + }; + + AxisPointerView.prototype.remove = function (ecModel, api) { + unregister('axisPointer', api); + }; + + AxisPointerView.prototype.dispose = function (ecModel, api) { + unregister('axisPointer', api); + }; + + AxisPointerView.type = 'axisPointer'; + return AxisPointerView; + }(ComponentView); + /** + * @param finder contains {seriesIndex, dataIndex, dataIndexInside} + * @param ecModel + * @return {point: [x, y], el: ...} point Will not be null. + */ + + + function findPointFromSeries(finder, ecModel) { + var point = []; + var seriesIndex = finder.seriesIndex; + var seriesModel; + + if (seriesIndex == null || !(seriesModel = ecModel.getSeriesByIndex(seriesIndex))) { + return { + point: [] + }; + } + + var data = seriesModel.getData(); + var dataIndex = queryDataIndex(data, finder); + + if (dataIndex == null || dataIndex < 0 || isArray(dataIndex)) { + return { + point: [] + }; + } + + var el = data.getItemGraphicEl(dataIndex); + var coordSys = seriesModel.coordinateSystem; + + if (seriesModel.getTooltipPosition) { + point = seriesModel.getTooltipPosition(dataIndex) || []; + } else if (coordSys && coordSys.dataToPoint) { + if (finder.isStacked) { + var baseAxis = coordSys.getBaseAxis(); + var valueAxis = coordSys.getOtherAxis(baseAxis); + var valueAxisDim = valueAxis.dim; + var baseAxisDim = baseAxis.dim; + var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0; + var baseDim = data.mapDimension(baseAxisDim); + var stackedData = []; + stackedData[baseDataOffset] = data.get(baseDim, dataIndex); + stackedData[1 - baseDataOffset] = data.get(data.getCalculationInfo('stackResultDimension'), dataIndex); + point = coordSys.dataToPoint(stackedData) || []; + } else { + point = coordSys.dataToPoint(data.getValues(map$1(coordSys.dimensions, function (dim) { + return data.mapDimension(dim); + }), dataIndex)) || []; + } + } else if (el) { + // Use graphic bounding rect + var rect = el.getBoundingRect().clone(); + rect.applyTransform(el.transform); + point = [rect.x + rect.width / 2, rect.y + rect.height / 2]; + } + + return { + point: point, + el: el + }; + } + + var inner$3 = makeInner(); + /** + * Basic logic: check all axis, if they do not demand show/highlight, + * then hide/downplay them. + * + * @return content of event obj for echarts.connect. + */ + + function axisTrigger(payload, ecModel, api) { + var currTrigger = payload.currTrigger; + var point = [payload.x, payload.y]; + var finder = payload; + var dispatchAction = payload.dispatchAction || bind$1(api.dispatchAction, api); + var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo; // Pending + // See #6121. But we are not able to reproduce it yet. + + if (!coordSysAxesInfo) { + return; + } + + if (illegalPoint(point)) { + // Used in the default behavior of `connection`: use the sample seriesIndex + // and dataIndex. And also used in the tooltipView trigger. + point = findPointFromSeries({ + seriesIndex: finder.seriesIndex, + // Do not use dataIndexInside from other ec instance. + // FIXME: auto detect it? + dataIndex: finder.dataIndex + }, ecModel).point; + } + + var isIllegalPoint = illegalPoint(point); // Axis and value can be specified when calling dispatchAction({type: 'updateAxisPointer'}). + // Notice: In this case, it is difficult to get the `point` (which is necessary to show + // tooltip, so if point is not given, we just use the point found by sample seriesIndex + // and dataIndex. + + var inputAxesInfo = finder.axesInfo; + var axesInfo = coordSysAxesInfo.axesInfo; + var shouldHide = currTrigger === 'leave' || illegalPoint(point); + var outputPayload = {}; + var showValueMap = {}; + var dataByCoordSys = { + list: [], + map: {} + }; + var updaters = { + showPointer: curry$1(showPointer, showValueMap), + showTooltip: curry$1(showTooltip, dataByCoordSys) + }; // Process for triggered axes. + + each$4(coordSysAxesInfo.coordSysMap, function (coordSys, coordSysKey) { + // If a point given, it must be contained by the coordinate system. + var coordSysContainsPoint = isIllegalPoint || coordSys.containPoint(point); + each$4(coordSysAxesInfo.coordSysAxesInfo[coordSysKey], function (axisInfo, key) { + var axis = axisInfo.axis; + var inputAxisInfo = findInputAxisInfo(inputAxesInfo, axisInfo); // If no inputAxesInfo, no axis is restricted. + + if (!shouldHide && coordSysContainsPoint && (!inputAxesInfo || inputAxisInfo)) { + var val = inputAxisInfo && inputAxisInfo.value; + + if (val == null && !isIllegalPoint) { + val = axis.pointToData(point); + } + + val != null && processOnAxis(axisInfo, val, updaters, false, outputPayload); + } + }); + }); // Process for linked axes. + + var linkTriggers = {}; + each$4(axesInfo, function (tarAxisInfo, tarKey) { + var linkGroup = tarAxisInfo.linkGroup; // If axis has been triggered in the previous stage, it should not be triggered by link. + + if (linkGroup && !showValueMap[tarKey]) { + each$4(linkGroup.axesInfo, function (srcAxisInfo, srcKey) { + var srcValItem = showValueMap[srcKey]; // If srcValItem exist, source axis is triggered, so link to target axis. + + if (srcAxisInfo !== tarAxisInfo && srcValItem) { + var val = srcValItem.value; + linkGroup.mapper && (val = tarAxisInfo.axis.scale.parse(linkGroup.mapper(val, makeMapperParam(srcAxisInfo), makeMapperParam(tarAxisInfo)))); + linkTriggers[tarAxisInfo.key] = val; + } + }); + } + }); + each$4(linkTriggers, function (val, tarKey) { + processOnAxis(axesInfo[tarKey], val, updaters, true, outputPayload); + }); + updateModelActually(showValueMap, axesInfo, outputPayload); + dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction); + dispatchHighDownActually(axesInfo, dispatchAction, api); + return outputPayload; + } + + function processOnAxis(axisInfo, newValue, updaters, noSnap, outputFinder) { + var axis = axisInfo.axis; + + if (axis.scale.isBlank() || !axis.containData(newValue)) { + return; + } + + if (!axisInfo.involveSeries) { + updaters.showPointer(axisInfo, newValue); + return; + } // Heavy calculation. So put it after axis.containData checking. + + + var payloadInfo = buildPayloadsBySeries(newValue, axisInfo); + var payloadBatch = payloadInfo.payloadBatch; + var snapToValue = payloadInfo.snapToValue; // Fill content of event obj for echarts.connect. + // By default use the first involved series data as a sample to connect. + + if (payloadBatch[0] && outputFinder.seriesIndex == null) { + extend(outputFinder, payloadBatch[0]); + } // If no linkSource input, this process is for collecting link + // target, where snap should not be accepted. + + + if (!noSnap && axisInfo.snap) { + if (axis.containData(snapToValue) && snapToValue != null) { + newValue = snapToValue; + } + } + + updaters.showPointer(axisInfo, newValue, payloadBatch); // Tooltip should always be snapToValue, otherwise there will be + // incorrect "axis value ~ series value" mapping displayed in tooltip. + + updaters.showTooltip(axisInfo, payloadInfo, snapToValue); + } + + function buildPayloadsBySeries(value, axisInfo) { + var axis = axisInfo.axis; + var dim = axis.dim; + var snapToValue = value; + var payloadBatch = []; + var minDist = Number.MAX_VALUE; + var minDiff = -1; + each$4(axisInfo.seriesModels, function (series, idx) { + var dataDim = series.getData().mapDimensionsAll(dim); + var seriesNestestValue; + var dataIndices; + + if (series.getAxisTooltipData) { + var result = series.getAxisTooltipData(dataDim, value, axis); + dataIndices = result.dataIndices; + seriesNestestValue = result.nestestValue; + } else { + dataIndices = series.indicesOfNearest(dim, dataDim[0], value, // Add a threshold to avoid find the wrong dataIndex + // when data length is not same. + // false, + axis.type === 'category' ? 0.5 : null); + + if (!dataIndices.length) { + return; + } + + seriesNestestValue = series.getData().get(dataDim[0], dataIndices[0]); + } + + if (seriesNestestValue == null || !isFinite(seriesNestestValue)) { + return; + } + + var diff = value - seriesNestestValue; + var dist = Math.abs(diff); // Consider category case + + if (dist <= minDist) { + if (dist < minDist || diff >= 0 && minDiff < 0) { + minDist = dist; + minDiff = diff; + snapToValue = seriesNestestValue; + payloadBatch.length = 0; + } + + each$4(dataIndices, function (dataIndex) { + payloadBatch.push({ + seriesIndex: series.seriesIndex, + dataIndexInside: dataIndex, + dataIndex: series.getData().getRawIndex(dataIndex) + }); + }); + } + }); + return { + payloadBatch: payloadBatch, + snapToValue: snapToValue + }; + } + + function showPointer(showValueMap, axisInfo, value, payloadBatch) { + showValueMap[axisInfo.key] = { + value: value, + payloadBatch: payloadBatch + }; + } + + function showTooltip(dataByCoordSys, axisInfo, payloadInfo, value) { + var payloadBatch = payloadInfo.payloadBatch; + var axis = axisInfo.axis; + var axisModel = axis.model; + var axisPointerModel = axisInfo.axisPointerModel; // If no data, do not create anything in dataByCoordSys, + // whose length will be used to judge whether dispatch action. + + if (!axisInfo.triggerTooltip || !payloadBatch.length) { + return; + } + + var coordSysModel = axisInfo.coordSys.model; + var coordSysKey = makeKey(coordSysModel); + var coordSysItem = dataByCoordSys.map[coordSysKey]; + + if (!coordSysItem) { + coordSysItem = dataByCoordSys.map[coordSysKey] = { + coordSysId: coordSysModel.id, + coordSysIndex: coordSysModel.componentIndex, + coordSysType: coordSysModel.type, + coordSysMainType: coordSysModel.mainType, + dataByAxis: [] + }; + dataByCoordSys.list.push(coordSysItem); + } + + coordSysItem.dataByAxis.push({ + axisDim: axis.dim, + axisIndex: axisModel.componentIndex, + axisType: axisModel.type, + axisId: axisModel.id, + value: value, + // Caustion: viewHelper.getValueLabel is actually on "view stage", which + // depends that all models have been updated. So it should not be performed + // here. Considering axisPointerModel used here is volatile, which is hard + // to be retrieve in TooltipView, we prepare parameters here. + valueLabelOpt: { + precision: axisPointerModel.get(['label', 'precision']), + formatter: axisPointerModel.get(['label', 'formatter']) + }, + seriesDataIndices: payloadBatch.slice() + }); + } + + function updateModelActually(showValueMap, axesInfo, outputPayload) { + var outputAxesInfo = outputPayload.axesInfo = []; // Basic logic: If no 'show' required, 'hide' this axisPointer. + + each$4(axesInfo, function (axisInfo, key) { + var option = axisInfo.axisPointerModel.option; + var valItem = showValueMap[key]; + + if (valItem) { + !axisInfo.useHandle && (option.status = 'show'); + option.value = valItem.value; // For label formatter param and highlight. + + option.seriesDataIndices = (valItem.payloadBatch || []).slice(); + } // When always show (e.g., handle used), remain + // original value and status. + else { + // If hide, value still need to be set, consider + // click legend to toggle axis blank. + !axisInfo.useHandle && (option.status = 'hide'); + } // If status is 'hide', should be no info in payload. + + + option.status === 'show' && outputAxesInfo.push({ + axisDim: axisInfo.axis.dim, + axisIndex: axisInfo.axis.model.componentIndex, + value: option.value + }); + }); + } + + function dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction) { + // Basic logic: If no showTip required, hideTip will be dispatched. + if (illegalPoint(point) || !dataByCoordSys.list.length) { + dispatchAction({ + type: 'hideTip' + }); + return; + } // In most case only one axis (or event one series is used). It is + // convenient to fetch payload.seriesIndex and payload.dataIndex + // directly. So put the first seriesIndex and dataIndex of the first + // axis on the payload. + + + var sampleItem = ((dataByCoordSys.list[0].dataByAxis[0] || {}).seriesDataIndices || [])[0] || {}; + dispatchAction({ + type: 'showTip', + escapeConnect: true, + x: point[0], + y: point[1], + tooltipOption: payload.tooltipOption, + position: payload.position, + dataIndexInside: sampleItem.dataIndexInside, + dataIndex: sampleItem.dataIndex, + seriesIndex: sampleItem.seriesIndex, + dataByCoordSys: dataByCoordSys.list + }); + } + + function dispatchHighDownActually(axesInfo, dispatchAction, api) { + // FIXME + // highlight status modification should be a stage of main process? + // (Consider confilct (e.g., legend and axisPointer) and setOption) + var zr = api.getZr(); + var highDownKey = 'axisPointerLastHighlights'; + var lastHighlights = inner$3(zr)[highDownKey] || {}; + var newHighlights = inner$3(zr)[highDownKey] = {}; // Update highlight/downplay status according to axisPointer model. + // Build hash map and remove duplicate incidentally. + + each$4(axesInfo, function (axisInfo, key) { + var option = axisInfo.axisPointerModel.option; + option.status === 'show' && axisInfo.triggerEmphasis && each$4(option.seriesDataIndices, function (batchItem) { + var key = batchItem.seriesIndex + ' | ' + batchItem.dataIndex; + newHighlights[key] = batchItem; + }); + }); // Diff. + + var toHighlight = []; + var toDownplay = []; + each$4(lastHighlights, function (batchItem, key) { + !newHighlights[key] && toDownplay.push(batchItem); + }); + each$4(newHighlights, function (batchItem, key) { + !lastHighlights[key] && toHighlight.push(batchItem); + }); + toDownplay.length && api.dispatchAction({ + type: 'downplay', + escapeConnect: true, + // Not blur others when highlight in axisPointer. + notBlur: true, + batch: toDownplay + }); + toHighlight.length && api.dispatchAction({ + type: 'highlight', + escapeConnect: true, + // Not blur others when highlight in axisPointer. + notBlur: true, + batch: toHighlight + }); + } + + function findInputAxisInfo(inputAxesInfo, axisInfo) { + for (var i = 0; i < (inputAxesInfo || []).length; i++) { + var inputAxisInfo = inputAxesInfo[i]; + + if (axisInfo.axis.dim === inputAxisInfo.axisDim && axisInfo.axis.model.componentIndex === inputAxisInfo.axisIndex) { + return inputAxisInfo; + } + } + } + + function makeMapperParam(axisInfo) { + var axisModel = axisInfo.axis.model; + var item = {}; + var dim = item.axisDim = axisInfo.axis.dim; + item.axisIndex = item[dim + 'AxisIndex'] = axisModel.componentIndex; + item.axisName = item[dim + 'AxisName'] = axisModel.name; + item.axisId = item[dim + 'AxisId'] = axisModel.id; + return item; + } + + function illegalPoint(point) { + return !point || point[0] == null || isNaN(point[0]) || point[1] == null || isNaN(point[1]); + } + + function install$3(registers) { + // CartesianAxisPointer is not supposed to be required here. But consider + // echarts.simple.js and online build tooltip, which only require gridSimple, + // CartesianAxisPointer should be able to required somewhere. + AxisView.registerAxisPointerClass('CartesianAxisPointer', CartesianAxisPointer); + registers.registerComponentModel(AxisPointerModel); + registers.registerComponentView(AxisPointerView); + registers.registerPreprocessor(function (option) { + // Always has a global axisPointerModel for default setting. + if (option) { + (!option.axisPointer || option.axisPointer.length === 0) && (option.axisPointer = {}); + var link = option.axisPointer.link; // Normalize to array to avoid object mergin. But if link + // is not set, remain null/undefined, otherwise it will + // override existent link setting. + + if (link && !isArray(link)) { + option.axisPointer.link = [link]; + } + } + }); // This process should proformed after coordinate systems created + // and series data processed. So put it on statistic processing stage. + + registers.registerProcessor(registers.PRIORITY.PROCESSOR.STATISTIC, function (ecModel, api) { + // Build axisPointerModel, mergin tooltip.axisPointer model for each axis. + // allAxesInfo should be updated when setOption performed. + ecModel.getComponent('axisPointer').coordSysAxesInfo = collect(ecModel, api); + }); // Broadcast to all views. + + registers.registerAction({ + type: 'updateAxisPointer', + event: 'updateAxisPointer', + update: ':updateAxisPointer' + }, axisTrigger); + } + + var TooltipModel = + /** @class */ + function (_super) { + __extends(TooltipModel, _super); + + function TooltipModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = TooltipModel.type; + return _this; + } + + TooltipModel.type = 'tooltip'; + TooltipModel.dependencies = ['axisPointer']; + TooltipModel.defaultOption = { + // zlevel: 0, + z: 60, + show: true, + // tooltip main content + showContent: true, + // 'trigger' only works on coordinate system. + // 'item' | 'axis' | 'none' + trigger: 'item', + // 'click' | 'mousemove' | 'none' + triggerOn: 'mousemove|click', + alwaysShowContent: false, + renderMode: 'auto', + // whether restraint content inside viewRect. + // If renderMode: 'richText', default true. + // If renderMode: 'html', defaults to `false` (for backward compat). + confine: null, + showDelay: 0, + hideDelay: 100, + // Animation transition time, unit is second + transitionDuration: 0.4, + displayTransition: true, + enterable: false, + backgroundColor: tokens.color.neutral00, + // box shadow + shadowBlur: 10, + shadowColor: 'rgba(0, 0, 0, .2)', + shadowOffsetX: 1, + shadowOffsetY: 2, + // tooltip border radius, unit is px, default is 4 + borderRadius: 4, + // tooltip border width, unit is px, default is 0 (no border) + borderWidth: 1, + defaultBorderColor: tokens.color.border, + // Tooltip inside padding, default is 5 for all direction + // Array is allowed to set up, right, bottom, left, same with css + // The default value: See `tooltip/tooltipMarkup.ts#getPaddingFromTooltipModel`. + padding: null, + // Extra css text + extraCssText: '', + // axis indicator, trigger by axis + axisPointer: { + // default is line + // legal values: 'line' | 'shadow' | 'cross' + type: 'line', + // Valid when type is line, appoint tooltip line locate on which line. Optional + // legal values: 'x' | 'y' | 'angle' | 'radius' | 'auto' + // default is 'auto', chose the axis which type is category. + // for multiply y axis, cartesian coord chose x axis, polar chose angle axis + axis: 'auto', + animation: 'auto', + animationDurationUpdate: 200, + animationEasingUpdate: 'exponentialOut', + crossStyle: { + color: tokens.color.borderShade, + width: 1, + type: 'dashed', + // TODO formatter + textStyle: {} + } // lineStyle and shadowStyle should not be specified here, + // otherwise it will always override those styles on option.axisPointer. + + }, + textStyle: { + color: tokens.color.tertiary, + fontSize: 14 + } + }; + return TooltipModel; + }(ComponentModel); + /* global document */ + + + function shouldTooltipConfine(tooltipModel) { + var confineOption = tooltipModel.get('confine'); + return confineOption != null ? !!confineOption // In richText mode, the outside part can not be visible. + : tooltipModel.get('renderMode') === 'richText'; + } + + function testStyle(styleProps) { + if (!env.domSupported) { + return; + } + + var style = document.documentElement.style; + + for (var i = 0, len = styleProps.length; i < len; i++) { + if (styleProps[i] in style) { + return styleProps[i]; + } + } + } + + var TRANSFORM_VENDOR = testStyle(['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']); + var TRANSITION_VENDOR = testStyle(['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']); + + function toCSSVendorPrefix(styleVendor, styleProp) { + if (!styleVendor) { + return styleProp; + } + + styleProp = toCamelCase(styleProp, true); + var idx = styleVendor.indexOf(styleProp); + styleVendor = idx === -1 ? styleProp : "-" + styleVendor.slice(0, idx) + "-" + styleProp; + return styleVendor.toLowerCase(); + } + + function getComputedStyle(el, style) { + var stl = el.currentStyle || document.defaultView && document.defaultView.getComputedStyle(el); + return stl ? style ? stl[style] : stl : null; + } + /* global document, window */ + + + var CSS_TRANSITION_VENDOR = toCSSVendorPrefix(TRANSITION_VENDOR, 'transition'); + var CSS_TRANSFORM_VENDOR = toCSSVendorPrefix(TRANSFORM_VENDOR, 'transform'); // eslint-disable-next-line + + var gCssText = "position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;" + (env.transform3dSupported ? 'will-change:transform;' : ''); + + function mirrorPos(pos) { + pos = pos === 'left' ? 'right' : pos === 'right' ? 'left' : pos === 'top' ? 'bottom' : 'top'; + return pos; + } + + function assembleArrow(tooltipModel, borderColor, arrowPosition) { + if (!isString(arrowPosition) || arrowPosition === 'inside') { + return ''; + } + + var backgroundColor = tooltipModel.get('backgroundColor'); + var borderWidth = tooltipModel.get('borderWidth'); + borderColor = convertToColorString(borderColor); + var arrowPos = mirrorPos(arrowPosition); + var arrowSize = Math.max(Math.round(borderWidth) * 1.5, 6); + var positionStyle = ''; + var transformStyle = CSS_TRANSFORM_VENDOR + ':'; + var rotateDeg; + + if (indexOf(['left', 'right'], arrowPos) > -1) { + positionStyle += 'top:50%'; + transformStyle += "translateY(-50%) rotate(" + (rotateDeg = arrowPos === 'left' ? -225 : -45) + "deg)"; + } else { + positionStyle += 'left:50%'; + transformStyle += "translateX(-50%) rotate(" + (rotateDeg = arrowPos === 'top' ? 225 : 45) + "deg)"; + } + + var rotateRadian = rotateDeg * Math.PI / 180; + var arrowWH = arrowSize + borderWidth; + var rotatedWH = arrowWH * Math.abs(Math.cos(rotateRadian)) + arrowWH * Math.abs(Math.sin(rotateRadian)); + var arrowOffset = Math.round(((rotatedWH - Math.SQRT2 * borderWidth) / 2 + Math.SQRT2 * borderWidth - (rotatedWH - arrowWH) / 2) * 100) / 100; + positionStyle += ";" + arrowPos + ":-" + arrowOffset + "px"; + var borderStyle = borderColor + " solid " + borderWidth + "px;"; + var styleCss = ["position:absolute;width:" + arrowSize + "px;height:" + arrowSize + "px;z-index:-1;", positionStyle + ";" + transformStyle + ";", "border-bottom:" + borderStyle, "border-right:" + borderStyle, "background-color:" + backgroundColor + ";"]; + return "
"; + } + + function assembleTransition(duration, onlyFadeTransition, enableDisplayTransition) { + var transitionCurve = 'cubic-bezier(0.23,1,0.32,1)'; + var transitionOption = ''; + var transitionText = ''; + + if (enableDisplayTransition) { + transitionOption = " " + duration / 2 + "s " + transitionCurve; + transitionText = "opacity" + transitionOption + ",visibility" + transitionOption; + } + + if (!onlyFadeTransition) { + transitionOption = " " + duration + "s " + transitionCurve; + transitionText += (transitionText.length ? ',' : '') + (env.transformSupported ? "" + CSS_TRANSFORM_VENDOR + transitionOption : ",left" + transitionOption + ",top" + transitionOption); + } + + return CSS_TRANSITION_VENDOR + ':' + transitionText; + } + + function assembleTransform(x, y, toString) { + // If using float on style, the final width of the dom might + // keep changing slightly while mouse move. So `toFixed(0)` them. + var x0 = x.toFixed(0) + 'px'; + var y0 = y.toFixed(0) + 'px'; // not support transform, use `left` and `top` instead. + + if (!env.transformSupported) { + return toString ? "top:" + y0 + ";left:" + x0 + ";" : [['top', y0], ['left', x0]]; + } // support transform + + + var is3d = env.transform3dSupported; + var translate = "translate" + (is3d ? '3d' : '') + "(" + x0 + "," + y0 + (is3d ? ',0' : '') + ")"; + return toString ? 'top:0;left:0;' + CSS_TRANSFORM_VENDOR + ':' + translate + ';' : [['top', 0], ['left', 0], [TRANSFORM_VENDOR, translate]]; + } + /** + * @param {Object} textStyle + * @return {string} + * @inner + */ + + + function assembleFont(textStyleModel) { + var cssText = []; + var fontSize = textStyleModel.get('fontSize'); + var color = textStyleModel.getTextColor(); + color && cssText.push('color:' + color); + cssText.push('font:' + textStyleModel.getFont()); // @ts-ignore, leave it to the tooltip refactor. + + var lineHeight = retrieve2(textStyleModel.get('lineHeight'), Math.round(fontSize * 3 / 2)); + fontSize && cssText.push('line-height:' + lineHeight + 'px'); + var shadowColor = textStyleModel.get('textShadowColor'); + var shadowBlur = textStyleModel.get('textShadowBlur') || 0; + var shadowOffsetX = textStyleModel.get('textShadowOffsetX') || 0; + var shadowOffsetY = textStyleModel.get('textShadowOffsetY') || 0; + shadowColor && shadowBlur && cssText.push('text-shadow:' + shadowOffsetX + 'px ' + shadowOffsetY + 'px ' + shadowBlur + 'px ' + shadowColor); + each$4(['decoration', 'align'], function (name) { + var val = textStyleModel.get(name); + val && cssText.push('text-' + name + ':' + val); + }); + return cssText.join(';'); + } + + function assembleCssText(tooltipModel, enableTransition, onlyFadeTransition, enableDisplayTransition) { + var cssText = []; + var transitionDuration = tooltipModel.get('transitionDuration'); + var backgroundColor = tooltipModel.get('backgroundColor'); + var shadowBlur = tooltipModel.get('shadowBlur'); + var shadowColor = tooltipModel.get('shadowColor'); + var shadowOffsetX = tooltipModel.get('shadowOffsetX'); + var shadowOffsetY = tooltipModel.get('shadowOffsetY'); + var textStyleModel = tooltipModel.getModel('textStyle'); + var padding = getPaddingFromTooltipModel(tooltipModel, 'html'); + var boxShadow = shadowOffsetX + "px " + shadowOffsetY + "px " + shadowBlur + "px " + shadowColor; + cssText.push('box-shadow:' + boxShadow); // Animation transition. Do not animate when transitionDuration <= 0. + + enableTransition && transitionDuration > 0 && cssText.push(assembleTransition(transitionDuration, onlyFadeTransition, enableDisplayTransition)); + + if (backgroundColor) { + cssText.push('background-color:' + backgroundColor); + } // Border style + + + each$4(['width', 'color', 'radius'], function (name) { + var borderName = 'border-' + name; + var camelCase = toCamelCase(borderName); + var val = tooltipModel.get(camelCase); + val != null && cssText.push(borderName + ':' + val + (name === 'color' ? '' : 'px')); + }); // Text style + + cssText.push(assembleFont(textStyleModel)); // Padding + + if (padding != null) { + cssText.push('padding:' + normalizeCssArray(padding).join('px ') + 'px'); + } + + return cssText.join(';') + ';'; + } // If not able to make, do not modify the input `out`. + + + function makeStyleCoord$1(out, zr, container, zrX, zrY) { + var zrPainter = zr && zr.painter; + + if (container) { + var zrViewportRoot = zrPainter && zrPainter.getViewportRoot(); + + if (zrViewportRoot) { + // Some APPs might use scale on body, so we support CSS transform here. + transformLocalCoord(out, zrViewportRoot, container, zrX, zrY); + } + } else { + out[0] = zrX; + out[1] = zrY; // xy should be based on canvas root. But tooltipContent is + // the sibling of canvas root. So padding of ec container + // should be considered here. + + var viewportRootOffset = zrPainter && zrPainter.getViewportRootOffset(); + + if (viewportRootOffset) { + out[0] += viewportRootOffset.offsetLeft; + out[1] += viewportRootOffset.offsetTop; + } + } + + out[2] = out[0] / zr.getWidth(); + out[3] = out[1] / zr.getHeight(); + } + + var TooltipHTMLContent = + /** @class */ + function () { + function TooltipHTMLContent(api, opt) { + this._show = false; + this._styleCoord = [0, 0, 0, 0]; + this._enterable = true; + this._alwaysShowContent = false; + this._firstShow = true; + this._longHide = true; + + if (env.wxa) { + return null; + } + + var el = document.createElement('div'); // TODO: TYPE + + el.domBelongToZr = true; + this.el = el; + var zr = this._zr = api.getZr(); + var appendTo = opt.appendTo; + var container = appendTo && (isString(appendTo) ? document.querySelector(appendTo) : isDom(appendTo) ? appendTo : isFunction(appendTo) && appendTo(api.getDom())); + makeStyleCoord$1(this._styleCoord, zr, container, api.getWidth() / 2, api.getHeight() / 2); + (container || api.getDom()).appendChild(el); + this._api = api; + this._container = container; // FIXME + // Is it needed to trigger zr event manually if + // the browser do not support `pointer-events: none`. + + var self = this; + + el.onmouseenter = function () { + // clear the timeout in hideLater and keep showing tooltip + if (self._enterable) { + clearTimeout(self._hideTimeout); + self._show = true; + } + + self._inContent = true; + }; + + el.onmousemove = function (e) { + e = e || window.event; + + if (!self._enterable) { + // `pointer-events: none` is set to tooltip content div + // if `enterable` is set as `false`, and `el.onmousemove` + // can not be triggered. But in browser that do not + // support `pointer-events`, we need to do this: + // Try trigger zrender event to avoid mouse + // in and out shape too frequently + var handler = zr.handler; + var zrViewportRoot = zr.painter.getViewportRoot(); + normalizeEvent(zrViewportRoot, e, true); + handler.dispatch('mousemove', e); + } + }; + + el.onmouseleave = function () { + // set `_inContent` to `false` before `hideLater` + self._inContent = false; + + if (self._enterable) { + if (self._show) { + self.hideLater(self._hideDelay); + } + } + }; + } + /** + * Update when tooltip is rendered + */ + + + TooltipHTMLContent.prototype.update = function (tooltipModel) { + // FIXME + // Move this logic to ec main? + if (!this._container) { + var container = this._api.getDom(); + + var position = getComputedStyle(container, 'position'); + var domStyle = container.style; + + if (domStyle.position !== 'absolute' && position !== 'absolute') { + domStyle.position = 'relative'; + } + } // move tooltip if chart resized + + + var alwaysShowContent = tooltipModel.get('alwaysShowContent'); + alwaysShowContent && this._moveIfResized(); // update alwaysShowContent + + this._alwaysShowContent = alwaysShowContent; + this._enableDisplayTransition = tooltipModel.get('displayTransition') && tooltipModel.get('transitionDuration') > 0; // update className + + this.el.className = tooltipModel.get('className') || ''; // Hide the tooltip + // PENDING + // this.hide(); + }; + + TooltipHTMLContent.prototype.show = function (tooltipModel, nearPointColor) { + clearTimeout(this._hideTimeout); + clearTimeout(this._longHideTimeout); + var el = this.el; + var style = el.style; + var styleCoord = this._styleCoord; + + if (!el.innerHTML) { + style.display = 'none'; + } else { + style.cssText = gCssText + assembleCssText(tooltipModel, !this._firstShow, this._longHide, this._enableDisplayTransition) // initial transform + + assembleTransform(styleCoord[0], styleCoord[1], true) + ("border-color:" + convertToColorString(nearPointColor) + ";") + (tooltipModel.get('extraCssText') || '') // If mouse occasionally move over the tooltip, a mouseout event will be + // triggered by canvas, and cause some unexpectable result like dragging + // stop, "unfocusAdjacency". Here `pointer-events: none` is used to solve + // it. Although it is not supported by IE8~IE10, fortunately it is a rare + // scenario. + + (";pointer-events:" + (this._enterable ? 'auto' : 'none')); + } + + this._show = true; + this._firstShow = false; + this._longHide = false; + }; + + TooltipHTMLContent.prototype.setContent = function (content, markers, tooltipModel, borderColor, arrowPosition) { + var el = this.el; + + if (content == null) { + el.innerHTML = ''; + return; + } + + var arrow = ''; + + if (isString(arrowPosition) && tooltipModel.get('trigger') === 'item' && !shouldTooltipConfine(tooltipModel)) { + arrow = assembleArrow(tooltipModel, borderColor, arrowPosition); + } + + if (isString(content)) { + el.innerHTML = content + arrow; + } else if (content) { + // Clear previous + el.innerHTML = ''; + + if (!isArray(content)) { + content = [content]; + } + + for (var i = 0; i < content.length; i++) { + if (isDom(content[i]) && content[i].parentNode !== el) { + el.appendChild(content[i]); + } + } // no arrow if empty + + + if (arrow && el.childNodes.length) { + // no need to create a new parent element, but it's not supported by IE 10 and older. + // const arrowEl = document.createRange().createContextualFragment(arrow); + var arrowEl = document.createElement('div'); + arrowEl.innerHTML = arrow; + el.appendChild(arrowEl); + } + } + }; + + TooltipHTMLContent.prototype.setEnterable = function (enterable) { + this._enterable = enterable; + }; + + TooltipHTMLContent.prototype.getSize = function () { + var el = this.el; + return el ? [el.offsetWidth, el.offsetHeight] : [0, 0]; + }; + + TooltipHTMLContent.prototype.moveTo = function (zrX, zrY) { + if (!this.el) { + return; + } + + var styleCoord = this._styleCoord; + makeStyleCoord$1(styleCoord, this._zr, this._container, zrX, zrY); + + if (styleCoord[0] != null && styleCoord[1] != null) { + var style_1 = this.el.style; + var transforms = assembleTransform(styleCoord[0], styleCoord[1]); + each$4(transforms, function (transform) { + style_1[transform[0]] = transform[1]; + }); + } + }; + /** + * when `alwaysShowContent` is true, + * move the tooltip after chart resized + */ + + + TooltipHTMLContent.prototype._moveIfResized = function () { + // The ratio of left to width + var ratioX = this._styleCoord[2]; // The ratio of top to height + + var ratioY = this._styleCoord[3]; + this.moveTo(ratioX * this._zr.getWidth(), ratioY * this._zr.getHeight()); + }; + + TooltipHTMLContent.prototype.hide = function () { + var _this = this; + + var style = this.el.style; + + if (this._enableDisplayTransition) { + style.visibility = 'hidden'; + style.opacity = '0'; + } else { + style.display = 'none'; + } + + env.transform3dSupported && (style.willChange = ''); + this._show = false; + this._longHideTimeout = setTimeout(function () { + return _this._longHide = true; + }, 500); + }; + + TooltipHTMLContent.prototype.hideLater = function (time) { + if (this._show && !(this._inContent && this._enterable) && !this._alwaysShowContent) { + if (time) { + this._hideDelay = time; // Set show false to avoid invoke hideLater multiple times + + this._show = false; + this._hideTimeout = setTimeout(bind$1(this.hide, this), time); + } else { + this.hide(); + } + } + }; + + TooltipHTMLContent.prototype.isShow = function () { + return this._show; + }; + + TooltipHTMLContent.prototype.dispose = function () { + clearTimeout(this._hideTimeout); + clearTimeout(this._longHideTimeout); + var zr = this._zr; + transformLocalCoordClear(zr && zr.painter && zr.painter.getViewportRoot(), this._container); + var el = this.el; + + if (el) { + el.onmouseenter = el.onmousemove = el.onmouseleave = null; + var parentNode = el.parentNode; + parentNode && parentNode.removeChild(el); + } + + this.el = this._container = null; + }; + + return TooltipHTMLContent; + }(); + + var TooltipRichContent = + /** @class */ + function () { + function TooltipRichContent(api) { + this._show = false; + this._styleCoord = [0, 0, 0, 0]; + this._alwaysShowContent = false; + this._enterable = true; + this._zr = api.getZr(); + makeStyleCoord(this._styleCoord, this._zr, api.getWidth() / 2, api.getHeight() / 2); + } + /** + * Update when tooltip is rendered + */ + + + TooltipRichContent.prototype.update = function (tooltipModel) { + var alwaysShowContent = tooltipModel.get('alwaysShowContent'); + alwaysShowContent && this._moveIfResized(); // update alwaysShowContent + + this._alwaysShowContent = alwaysShowContent; + }; + + TooltipRichContent.prototype.show = function () { + if (this._hideTimeout) { + clearTimeout(this._hideTimeout); + } + + this.el.show(); + this._show = true; + }; + /** + * Set tooltip content + */ + + + TooltipRichContent.prototype.setContent = function (content, markupStyleCreator, tooltipModel, borderColor, arrowPosition) { + var _this = this; + + if (isObject$2(content)) { + throwError('Passing DOM nodes as content is not supported in richText tooltip!'); + } + + if (this.el) { + this._zr.remove(this.el); + } + + var textStyleModel = tooltipModel.getModel('textStyle'); + this.el = new ZRText({ + style: { + rich: markupStyleCreator.richTextStyles, + text: content, + lineHeight: 22, + borderWidth: 1, + borderColor: borderColor, + textShadowColor: textStyleModel.get('textShadowColor'), + fill: tooltipModel.get(['textStyle', 'color']), + padding: getPaddingFromTooltipModel(tooltipModel, 'richText'), + verticalAlign: 'top', + align: 'left' + }, + z: tooltipModel.get('z') + }); + each$4(['backgroundColor', 'borderRadius', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'], function (propName) { + _this.el.style[propName] = tooltipModel.get(propName); + }); + each$4(['textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY'], function (propName) { + _this.el.style[propName] = textStyleModel.get(propName) || 0; + }); + + this._zr.add(this.el); + + var self = this; + this.el.on('mouseover', function () { + // clear the timeout in hideLater and keep showing tooltip + if (self._enterable) { + clearTimeout(self._hideTimeout); + self._show = true; + } + + self._inContent = true; + }); + this.el.on('mouseout', function () { + if (self._enterable) { + if (self._show) { + self.hideLater(self._hideDelay); + } + } + + self._inContent = false; + }); + }; + + TooltipRichContent.prototype.setEnterable = function (enterable) { + this._enterable = enterable; + }; + + TooltipRichContent.prototype.getSize = function () { + var el = this.el; + var bounding = this.el.getBoundingRect(); // bounding rect does not include shadow. For renderMode richText, + // if overflow, it will be cut. So calculate them accurately. + + var shadowOuterSize = calcShadowOuterSize(el.style); + return [bounding.width + shadowOuterSize.left + shadowOuterSize.right, bounding.height + shadowOuterSize.top + shadowOuterSize.bottom]; + }; + + TooltipRichContent.prototype.moveTo = function (x, y) { + var el = this.el; + + if (el) { + var styleCoord = this._styleCoord; + makeStyleCoord(styleCoord, this._zr, x, y); + x = styleCoord[0]; + y = styleCoord[1]; + var style = el.style; + var borderWidth = mathMaxWith0(style.borderWidth || 0); + var shadowOuterSize = calcShadowOuterSize(style); // rich text x, y do not include border. + + el.x = x + borderWidth + shadowOuterSize.left; + el.y = y + borderWidth + shadowOuterSize.top; + el.markRedraw(); + } + }; + /** + * when `alwaysShowContent` is true, + * move the tooltip after chart resized + */ + + + TooltipRichContent.prototype._moveIfResized = function () { + // The ratio of left to width + var ratioX = this._styleCoord[2]; // The ratio of top to height + + var ratioY = this._styleCoord[3]; + this.moveTo(ratioX * this._zr.getWidth(), ratioY * this._zr.getHeight()); + }; + + TooltipRichContent.prototype.hide = function () { + if (this.el) { + this.el.hide(); + } + + this._show = false; + }; + + TooltipRichContent.prototype.hideLater = function (time) { + if (this._show && !(this._inContent && this._enterable) && !this._alwaysShowContent) { + if (time) { + this._hideDelay = time; // Set show false to avoid invoke hideLater multiple times + + this._show = false; + this._hideTimeout = setTimeout(bind$1(this.hide, this), time); + } else { + this.hide(); + } + } + }; + + TooltipRichContent.prototype.isShow = function () { + return this._show; + }; + + TooltipRichContent.prototype.dispose = function () { + this._zr.remove(this.el); + }; + + return TooltipRichContent; + }(); + + function mathMaxWith0(val) { + return Math.max(0, val); + } + + function calcShadowOuterSize(style) { + var shadowBlur = mathMaxWith0(style.shadowBlur || 0); + var shadowOffsetX = mathMaxWith0(style.shadowOffsetX || 0); + var shadowOffsetY = mathMaxWith0(style.shadowOffsetY || 0); + return { + left: mathMaxWith0(shadowBlur - shadowOffsetX), + right: mathMaxWith0(shadowBlur + shadowOffsetX), + top: mathMaxWith0(shadowBlur - shadowOffsetY), + bottom: mathMaxWith0(shadowBlur + shadowOffsetY) + }; + } + + function makeStyleCoord(out, zr, zrX, zrY) { + out[0] = zrX; + out[1] = zrY; + out[2] = out[0] / zr.getWidth(); + out[3] = out[1] / zr.getHeight(); + } + + var proxyRect = new Rect({ + shape: { + x: -1, + y: -1, + width: 2, + height: 2 + } + }); + + var TooltipView = + /** @class */ + function (_super) { + __extends(TooltipView, _super); + + function TooltipView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = TooltipView.type; + return _this; + } + + TooltipView.prototype.init = function (ecModel, api) { + if (env.node || !api.getDom()) { + return; + } + + var tooltipModel = ecModel.getComponent('tooltip'); + var renderMode = this._renderMode = getTooltipRenderMode(tooltipModel.get('renderMode')); + this._tooltipContent = renderMode === 'richText' ? new TooltipRichContent(api) : new TooltipHTMLContent(api, { + appendTo: tooltipModel.get('appendToBody', true) ? 'body' : tooltipModel.get('appendTo', true) + }); + }; + + TooltipView.prototype.render = function (tooltipModel, ecModel, api) { + if (env.node || !api.getDom()) { + return; + } // Reset + + + this.group.removeAll(); + this._tooltipModel = tooltipModel; + this._ecModel = ecModel; + this._api = api; + var tooltipContent = this._tooltipContent; + tooltipContent.update(tooltipModel); + tooltipContent.setEnterable(tooltipModel.get('enterable')); + + this._initGlobalListener(); + + this._keepShow(); // PENDING + // `mousemove` event will be triggered very frequently when the mouse moves fast, + // which causes that the `updatePosition` function was also called frequently. + // In Chrome with devtools open and Firefox, tooltip looks laggy and shakes. See #14695 #16101 + // To avoid frequent triggering, + // consider throttling it in 50ms when transition is enabled + + + if (this._renderMode !== 'richText' && tooltipModel.get('transitionDuration')) { + createOrUpdate(this, '_updatePosition', 50, 'fixRate'); + } else { + clear(this, '_updatePosition'); + } + }; + + TooltipView.prototype._initGlobalListener = function () { + var tooltipModel = this._tooltipModel; + var triggerOn = tooltipModel.get('triggerOn'); + register('itemTooltip', this._api, bind$1(function (currTrigger, e, dispatchAction) { + // If 'none', it is not controlled by mouse totally. + if (triggerOn !== 'none') { + if (triggerOn.indexOf(currTrigger) >= 0) { + this._tryShow(e, dispatchAction); + } else if (currTrigger === 'leave') { + this._hide(dispatchAction); + } + } + }, this)); + }; + + TooltipView.prototype._keepShow = function () { + var tooltipModel = this._tooltipModel; + var ecModel = this._ecModel; + var api = this._api; + var triggerOn = tooltipModel.get('triggerOn'); // Try to keep the tooltip show when refreshing + + if (this._lastX != null && this._lastY != null // When user is willing to control tooltip totally using API, + // self.manuallyShowTip({x, y}) might cause tooltip hide, + // which is not expected. + && triggerOn !== 'none' && triggerOn !== 'click') { + var self_1 = this; + clearTimeout(this._refreshUpdateTimeout); + this._refreshUpdateTimeout = setTimeout(function () { + // Show tip next tick after other charts are rendered + // In case highlight action has wrong result + // FIXME + !api.isDisposed() && self_1.manuallyShowTip(tooltipModel, ecModel, api, { + x: self_1._lastX, + y: self_1._lastY, + dataByCoordSys: self_1._lastDataByCoordSys + }); + }); + } + }; + /** + * Show tip manually by + * dispatchAction({ + * type: 'showTip', + * x: 10, + * y: 10 + * }); + * Or + * dispatchAction({ + * type: 'showTip', + * seriesIndex: 0, + * dataIndex or dataIndexInside or name + * }); + * + * TODO Batch + */ + + + TooltipView.prototype.manuallyShowTip = function (tooltipModel, ecModel, api, payload) { + if (payload.from === this.uid || env.node || !api.getDom()) { + return; + } + + var dispatchAction = makeDispatchAction(payload, api); // Reset ticket + + this._ticket = ''; // When triggered from axisPointer. + + var dataByCoordSys = payload.dataByCoordSys; + var cmptRef = findComponentReference(payload, ecModel, api); + + if (cmptRef) { + var rect = cmptRef.el.getBoundingRect().clone(); + rect.applyTransform(cmptRef.el.transform); + + this._tryShow({ + offsetX: rect.x + rect.width / 2, + offsetY: rect.y + rect.height / 2, + target: cmptRef.el, + position: payload.position, + // When manully trigger, the mouse is not on the el, so we'd better to + // position tooltip on the bottom of the el and display arrow is possible. + positionDefault: 'bottom' + }, dispatchAction); + } else if (payload.tooltip && payload.x != null && payload.y != null) { + var el = proxyRect; + el.x = payload.x; + el.y = payload.y; + el.update(); + getECData(el).tooltipConfig = { + name: null, + option: payload.tooltip + }; // Manually show tooltip while view is not using zrender elements. + + this._tryShow({ + offsetX: payload.x, + offsetY: payload.y, + target: el + }, dispatchAction); + } else if (dataByCoordSys) { + this._tryShow({ + offsetX: payload.x, + offsetY: payload.y, + position: payload.position, + dataByCoordSys: dataByCoordSys, + tooltipOption: payload.tooltipOption + }, dispatchAction); + } else if (payload.seriesIndex != null) { + if (this._manuallyAxisShowTip(tooltipModel, ecModel, api, payload)) { + return; + } + + var pointInfo = findPointFromSeries(payload, ecModel); + var cx = pointInfo.point[0]; + var cy = pointInfo.point[1]; + + if (cx != null && cy != null) { + this._tryShow({ + offsetX: cx, + offsetY: cy, + target: pointInfo.el, + position: payload.position, + // When manully trigger, the mouse is not on the el, so we'd better to + // position tooltip on the bottom of the el and display arrow is possible. + positionDefault: 'bottom' + }, dispatchAction); + } + } else if (payload.x != null && payload.y != null) { + // FIXME + // should wrap dispatchAction like `axisPointer/globalListener` ? + api.dispatchAction({ + type: 'updateAxisPointer', + x: payload.x, + y: payload.y + }); + + this._tryShow({ + offsetX: payload.x, + offsetY: payload.y, + position: payload.position, + target: api.getZr().findHover(payload.x, payload.y).target + }, dispatchAction); + } + }; + + TooltipView.prototype.manuallyHideTip = function (tooltipModel, ecModel, api, payload) { + var tooltipContent = this._tooltipContent; + + if (this._tooltipModel) { + tooltipContent.hideLater(this._tooltipModel.get('hideDelay')); + } + + this._lastX = this._lastY = this._lastDataByCoordSys = null; + + if (payload.from !== this.uid) { + this._hide(makeDispatchAction(payload, api)); + } + }; // Be compatible with previous design, that is, when tooltip.type is 'axis' and + // dispatchAction 'showTip' with seriesIndex and dataIndex will trigger axis pointer + // and tooltip. + + + TooltipView.prototype._manuallyAxisShowTip = function (tooltipModel, ecModel, api, payload) { + var seriesIndex = payload.seriesIndex; + var dataIndex = payload.dataIndex; // @ts-ignore + + var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo; + + if (seriesIndex == null || dataIndex == null || coordSysAxesInfo == null) { + return; + } + + var seriesModel = ecModel.getSeriesByIndex(seriesIndex); + + if (!seriesModel) { + return; + } + + var data = seriesModel.getData(); + var tooltipCascadedModel = buildTooltipModel([data.getItemModel(dataIndex), seriesModel, (seriesModel.coordinateSystem || {}).model], this._tooltipModel); + + if (tooltipCascadedModel.get('trigger') !== 'axis') { + return; + } + + api.dispatchAction({ + type: 'updateAxisPointer', + seriesIndex: seriesIndex, + dataIndex: dataIndex, + position: payload.position + }); + return true; + }; + + TooltipView.prototype._tryShow = function (e, dispatchAction) { + var el = e.target; + var tooltipModel = this._tooltipModel; + + if (!tooltipModel) { + return; + } // Save mouse x, mouse y. So we can try to keep showing the tip if chart is refreshed + + + this._lastX = e.offsetX; + this._lastY = e.offsetY; + var dataByCoordSys = e.dataByCoordSys; + + if (dataByCoordSys && dataByCoordSys.length) { + this._showAxisTooltip(dataByCoordSys, e); + } else if (el) { + var ecData = getECData(el); + + if (ecData.ssrType === 'legend') { + // Don't trigger tooltip for legend tooltip item + return; + } + + this._lastDataByCoordSys = null; + var seriesDispatcher_1; + var cmptDispatcher_1; + findEventDispatcher(el, function (target) { + if (target.tooltipDisabled) { + seriesDispatcher_1 = cmptDispatcher_1 = null; + return true; + } + + if (seriesDispatcher_1 || cmptDispatcher_1) { + return; + } // Always show item tooltip if mouse is on the element with dataIndex + + + if (getECData(target).dataIndex != null) { + seriesDispatcher_1 = target; + } // Tooltip provided directly. Like legend. + else if (getECData(target).tooltipConfig != null) { + cmptDispatcher_1 = target; + } + }, true); + + if (seriesDispatcher_1) { + this._showSeriesItemTooltip(e, seriesDispatcher_1, dispatchAction); + } else if (cmptDispatcher_1) { + this._showComponentItemTooltip(e, cmptDispatcher_1, dispatchAction); + } else { + this._hide(dispatchAction); + } + } else { + this._lastDataByCoordSys = null; + + this._hide(dispatchAction); + } + }; + + TooltipView.prototype._showOrMove = function (tooltipModel, cb) { + // showDelay is used in this case: tooltip.enterable is set + // as true. User intent to move mouse into tooltip and click + // something. `showDelay` makes it easier to enter the content + // but tooltip do not move immediately. + var delay = tooltipModel.get('showDelay'); + cb = bind$1(cb, this); + clearTimeout(this._showTimout); + delay > 0 ? this._showTimout = setTimeout(cb, delay) : cb(); + }; + + TooltipView.prototype._showAxisTooltip = function (dataByCoordSys, e) { + var ecModel = this._ecModel; + var globalTooltipModel = this._tooltipModel; + var point = [e.offsetX, e.offsetY]; + var singleTooltipModel = buildTooltipModel([e.tooltipOption], globalTooltipModel); + var renderMode = this._renderMode; + var cbParamsList = []; + var articleMarkup = createTooltipMarkup('section', { + blocks: [], + noHeader: true + }); // Only for legacy: `Serise['formatTooltip']` returns a string. + + var markupTextArrLegacy = []; + var markupStyleCreator = new TooltipMarkupStyleCreator(); + each$4(dataByCoordSys, function (itemCoordSys) { + each$4(itemCoordSys.dataByAxis, function (axisItem) { + var axisModel = ecModel.getComponent(axisItem.axisDim + 'Axis', axisItem.axisIndex); + var axisValue = axisItem.value; + + if (!axisModel || axisValue == null) { + return; + } // FIXME: when using `tooltip.trigger: 'axis'`, the precision of the axis value displayed in tooltip + // should match the original series values rather than using the default stretegy in Interval.ts + // (getPrecision(interval) + 2); otherwise it may cuase confusion. + + + var axisValueLabel = getValueLabel(axisValue, axisModel.axis, ecModel, axisItem.seriesDataIndices, axisItem.valueLabelOpt); + var axisSectionMarkup = createTooltipMarkup('section', { + header: axisValueLabel, + noHeader: !trim(axisValueLabel), + sortBlocks: true, + blocks: [] + }); + articleMarkup.blocks.push(axisSectionMarkup); + each$4(axisItem.seriesDataIndices, function (idxItem) { + var series = ecModel.getSeriesByIndex(idxItem.seriesIndex); + var dataIndex = idxItem.dataIndexInside; + var cbParams = series.getDataParams(dataIndex); // Can't find data. + + if (cbParams.dataIndex < 0) { + return; + } + + cbParams.axisDim = axisItem.axisDim; + cbParams.axisIndex = axisItem.axisIndex; + cbParams.axisType = axisItem.axisType; + cbParams.axisId = axisItem.axisId; + cbParams.axisValue = getAxisRawValue(axisModel.axis, { + value: axisValue + }); + cbParams.axisValueLabel = axisValueLabel; // Pre-create marker style for makers. Users can assemble richText + // text in `formatter` callback and use those markers style. + + cbParams.marker = markupStyleCreator.makeTooltipMarker('item', convertToColorString(cbParams.color), renderMode); + var seriesTooltipResult = normalizeTooltipFormatResult(series.formatTooltip(dataIndex, true, null)); + var frag = seriesTooltipResult.frag; + + if (frag) { + var valueFormatter = buildTooltipModel([series], globalTooltipModel).get('valueFormatter'); + axisSectionMarkup.blocks.push(valueFormatter ? extend({ + valueFormatter: valueFormatter + }, frag) : frag); + } + + if (seriesTooltipResult.text) { + markupTextArrLegacy.push(seriesTooltipResult.text); + } + + cbParamsList.push(cbParams); + }); + }); + }); // In most cases, the second axis is displays upper on the first one. + // So we reverse it to look better. + + articleMarkup.blocks.reverse(); + markupTextArrLegacy.reverse(); + var positionExpr = e.position; + var orderMode = singleTooltipModel.get('order'); + var builtMarkupText = buildTooltipMarkup(articleMarkup, markupStyleCreator, renderMode, orderMode, ecModel.get('useUTC'), singleTooltipModel.get('textStyle')); + builtMarkupText && markupTextArrLegacy.unshift(builtMarkupText); + var blockBreak = renderMode === 'richText' ? '\n\n' : '
'; + var allMarkupText = markupTextArrLegacy.join(blockBreak); + + this._showOrMove(singleTooltipModel, function () { + if (this._updateContentNotChangedOnAxis(dataByCoordSys, cbParamsList)) { + this._updatePosition(singleTooltipModel, positionExpr, point[0], point[1], this._tooltipContent, cbParamsList); + } else { + this._showTooltipContent(singleTooltipModel, allMarkupText, cbParamsList, Math.random() + '', point[0], point[1], positionExpr, null, markupStyleCreator); + } + }); // Do not trigger events here, because this branch only be entered + // from dispatchAction. + + }; + + TooltipView.prototype._showSeriesItemTooltip = function (e, dispatcher, dispatchAction) { + var ecModel = this._ecModel; + var ecData = getECData(dispatcher); // Use dataModel in element if possible + // Used when mouseover on a element like markPoint or edge + // In which case, the data is not main data in series. + + var seriesIndex = ecData.seriesIndex; + var seriesModel = ecModel.getSeriesByIndex(seriesIndex); // For example, graph link. + + var dataModel = ecData.dataModel || seriesModel; + var dataIndex = ecData.dataIndex; + var dataType = ecData.dataType; + var data = dataModel.getData(dataType); + var renderMode = this._renderMode; + var positionDefault = e.positionDefault; + var tooltipModel = buildTooltipModel([data.getItemModel(dataIndex), dataModel, seriesModel && (seriesModel.coordinateSystem || {}).model], this._tooltipModel, positionDefault ? { + position: positionDefault + } : null); + var tooltipTrigger = tooltipModel.get('trigger'); + + if (tooltipTrigger != null && tooltipTrigger !== 'item') { + return; + } + + var params = dataModel.getDataParams(dataIndex, dataType); + var markupStyleCreator = new TooltipMarkupStyleCreator(); // Pre-create marker style for makers. Users can assemble richText + // text in `formatter` callback and use those markers style. + + params.marker = markupStyleCreator.makeTooltipMarker('item', convertToColorString(params.color), renderMode); + var seriesTooltipResult = normalizeTooltipFormatResult(dataModel.formatTooltip(dataIndex, false, dataType)); + var orderMode = tooltipModel.get('order'); + var valueFormatter = tooltipModel.get('valueFormatter'); + var frag = seriesTooltipResult.frag; + var markupText = frag ? buildTooltipMarkup(valueFormatter ? extend({ + valueFormatter: valueFormatter + }, frag) : frag, markupStyleCreator, renderMode, orderMode, ecModel.get('useUTC'), tooltipModel.get('textStyle')) : seriesTooltipResult.text; + var asyncTicket = 'item_' + dataModel.name + '_' + dataIndex; + + this._showOrMove(tooltipModel, function () { + this._showTooltipContent(tooltipModel, markupText, params, asyncTicket, e.offsetX, e.offsetY, e.position, e.target, markupStyleCreator); + }); // FIXME + // duplicated showtip if manuallyShowTip is called from dispatchAction. + + + dispatchAction({ + type: 'showTip', + dataIndexInside: dataIndex, + dataIndex: data.getRawIndex(dataIndex), + seriesIndex: seriesIndex, + from: this.uid + }); + }; + + TooltipView.prototype._showComponentItemTooltip = function (e, el, dispatchAction) { + var isHTMLRenderMode = this._renderMode === 'html'; + var ecData = getECData(el); + var tooltipConfig = ecData.tooltipConfig; + var tooltipOpt = tooltipConfig.option || {}; + var encodeHTMLContent = tooltipOpt.encodeHTMLContent; + + if (isString(tooltipOpt)) { + var content = tooltipOpt; + tooltipOpt = { + content: content, + // Fixed formatter + formatter: content + }; // when `tooltipConfig.option` is a string rather than an object, + // we can't know if the content needs to be encoded + // for the sake of security, encode it by default. + + encodeHTMLContent = true; + } + + if (encodeHTMLContent && isHTMLRenderMode && tooltipOpt.content) { + // clone might be unnecessary? + tooltipOpt = clone$3(tooltipOpt); + tooltipOpt.content = encodeHTML(tooltipOpt.content); + } + + var tooltipModelCascade = [tooltipOpt]; + + var cmpt = this._ecModel.getComponent(ecData.componentMainType, ecData.componentIndex); + + if (cmpt) { + tooltipModelCascade.push(cmpt); + } // In most cases, component tooltip formatter has different params with series tooltip formatter, + // so that they cannot share the same formatter. Since the global tooltip formatter is used for series + // by convention, we do not use it as the default formatter for component. + + + tooltipModelCascade.push({ + formatter: tooltipOpt.content + }); + var positionDefault = e.positionDefault; + var subTooltipModel = buildTooltipModel(tooltipModelCascade, this._tooltipModel, positionDefault ? { + position: positionDefault + } : null); + var defaultHtml = subTooltipModel.get('content'); + var asyncTicket = Math.random() + ''; // PENDING: this case do not support richText style yet. + + var markupStyleCreator = new TooltipMarkupStyleCreator(); // Do not check whether `trigger` is 'none' here, because `trigger` + // only works on coordinate system. In fact, we have not found case + // that requires setting `trigger` nothing on component yet. + + this._showOrMove(subTooltipModel, function () { + // Use formatterParams from element defined in component + // Avoid users modify it. + var formatterParams = clone$3(subTooltipModel.get('formatterParams') || {}); + + this._showTooltipContent(subTooltipModel, defaultHtml, formatterParams, asyncTicket, e.offsetX, e.offsetY, e.position, el, markupStyleCreator); + }); // If not dispatch showTip, tip may be hide triggered by axis. + + + dispatchAction({ + type: 'showTip', + from: this.uid + }); + }; + + TooltipView.prototype._showTooltipContent = function ( // Use Model insteadof TooltipModel because this model may be from series or other options. + // Instead of top level tooltip. + tooltipModel, defaultHtml, params, asyncTicket, x, y, positionExpr, el, markupStyleCreator) { + // Reset ticket + this._ticket = ''; + + if (!tooltipModel.get('showContent') || !tooltipModel.get('show')) { + return; + } + + var tooltipContent = this._tooltipContent; + tooltipContent.setEnterable(tooltipModel.get('enterable')); + var formatter = tooltipModel.get('formatter'); + positionExpr = positionExpr || tooltipModel.get('position'); + var html = defaultHtml; + + var nearPoint = this._getNearestPoint([x, y], params, tooltipModel.get('trigger'), tooltipModel.get('borderColor'), tooltipModel.get('defaultBorderColor', true)); + + var nearPointColor = nearPoint.color; + + if (formatter) { + if (isString(formatter)) { + var useUTC = tooltipModel.ecModel.get('useUTC'); + var params0 = isArray(params) ? params[0] : params; + var isTimeAxis = params0 && params0.axisType && params0.axisType.indexOf('time') >= 0; + html = formatter; + + if (isTimeAxis) { + html = format$1(params0.axisValue, html, useUTC); + } + + html = formatTpl(html, params, true); + } else if (isFunction(formatter)) { + var callback = bind$1(function (cbTicket, html) { + if (cbTicket === this._ticket) { + tooltipContent.setContent(html, markupStyleCreator, tooltipModel, nearPointColor, positionExpr); + + this._updatePosition(tooltipModel, positionExpr, x, y, tooltipContent, params, el); + } + }, this); + this._ticket = asyncTicket; + html = formatter(params, asyncTicket, callback); + } else { + html = formatter; + } + } + + tooltipContent.setContent(html, markupStyleCreator, tooltipModel, nearPointColor, positionExpr); + tooltipContent.show(tooltipModel, nearPointColor); + + this._updatePosition(tooltipModel, positionExpr, x, y, tooltipContent, params, el); + }; + + TooltipView.prototype._getNearestPoint = function (point, tooltipDataParams, trigger, borderColor, defaultBorderColor) { + if (trigger === 'axis' || isArray(tooltipDataParams)) { + return { + color: borderColor || defaultBorderColor + }; + } + + if (!isArray(tooltipDataParams)) { + return { + color: borderColor || tooltipDataParams.color || tooltipDataParams.borderColor + }; + } + }; + + TooltipView.prototype._updatePosition = function (tooltipModel, positionExpr, x, // Mouse x + y, // Mouse y + content, params, el) { + var viewWidth = this._api.getWidth(); + + var viewHeight = this._api.getHeight(); + + positionExpr = positionExpr || tooltipModel.get('position'); + var contentSize = content.getSize(); + var align = tooltipModel.get('align'); + var vAlign = tooltipModel.get('verticalAlign'); + var rect = el && el.getBoundingRect().clone(); + el && rect.applyTransform(el.transform); + + if (isFunction(positionExpr)) { + // Callback of position can be an array or a string specify the position + positionExpr = positionExpr([x, y], params, content.el, rect, { + viewSize: [viewWidth, viewHeight], + contentSize: contentSize.slice() + }); + } + + if (isArray(positionExpr)) { + x = parsePercent(positionExpr[0], viewWidth); + y = parsePercent(positionExpr[1], viewHeight); + } else if (isObject$2(positionExpr)) { + var boxLayoutPosition = positionExpr; + boxLayoutPosition.width = contentSize[0]; + boxLayoutPosition.height = contentSize[1]; + var layoutRect = getLayoutRect(boxLayoutPosition, { + width: viewWidth, + height: viewHeight + }); + x = layoutRect.x; + y = layoutRect.y; + align = null; // When positionExpr is left/top/right/bottom, + // align and verticalAlign will not work. + + vAlign = null; + } // Specify tooltip position by string 'top' 'bottom' 'left' 'right' around graphic element + else if (isString(positionExpr) && el) { + var pos = calcTooltipPosition(positionExpr, rect, contentSize, tooltipModel.get('borderWidth')); + x = pos[0]; + y = pos[1]; + } else { + var pos = refixTooltipPosition(x, y, content, viewWidth, viewHeight, align ? null : 20, vAlign ? null : 20); + x = pos[0]; + y = pos[1]; + } + + align && (x -= isCenterAlign(align) ? contentSize[0] / 2 : align === 'right' ? contentSize[0] : 0); + vAlign && (y -= isCenterAlign(vAlign) ? contentSize[1] / 2 : vAlign === 'bottom' ? contentSize[1] : 0); + + if (shouldTooltipConfine(tooltipModel)) { + var pos = confineTooltipPosition(x, y, content, viewWidth, viewHeight); + x = pos[0]; + y = pos[1]; + } + + content.moveTo(x, y); + }; // FIXME + // Should we remove this but leave this to user? + + + TooltipView.prototype._updateContentNotChangedOnAxis = function (dataByCoordSys, cbParamsList) { + var lastCoordSys = this._lastDataByCoordSys; + var lastCbParamsList = this._cbParamsList; + var contentNotChanged = !!lastCoordSys && lastCoordSys.length === dataByCoordSys.length; + contentNotChanged && each$4(lastCoordSys, function (lastItemCoordSys, indexCoordSys) { + var lastDataByAxis = lastItemCoordSys.dataByAxis || []; + var thisItemCoordSys = dataByCoordSys[indexCoordSys] || {}; + var thisDataByAxis = thisItemCoordSys.dataByAxis || []; + contentNotChanged = contentNotChanged && lastDataByAxis.length === thisDataByAxis.length; + contentNotChanged && each$4(lastDataByAxis, function (lastItem, indexAxis) { + var thisItem = thisDataByAxis[indexAxis] || {}; + var lastIndices = lastItem.seriesDataIndices || []; + var newIndices = thisItem.seriesDataIndices || []; + contentNotChanged = contentNotChanged && lastItem.value === thisItem.value && lastItem.axisType === thisItem.axisType && lastItem.axisId === thisItem.axisId && lastIndices.length === newIndices.length; + contentNotChanged && each$4(lastIndices, function (lastIdxItem, j) { + var newIdxItem = newIndices[j]; + contentNotChanged = contentNotChanged && lastIdxItem.seriesIndex === newIdxItem.seriesIndex && lastIdxItem.dataIndex === newIdxItem.dataIndex; + }); // check is cbParams data value changed + + lastCbParamsList && each$4(lastItem.seriesDataIndices, function (idxItem) { + var seriesIdx = idxItem.seriesIndex; + var cbParams = cbParamsList[seriesIdx]; + var lastCbParams = lastCbParamsList[seriesIdx]; + + if (cbParams && lastCbParams && lastCbParams.data !== cbParams.data) { + contentNotChanged = false; + } + }); + }); + }); + this._lastDataByCoordSys = dataByCoordSys; + this._cbParamsList = cbParamsList; + return !!contentNotChanged; + }; + + TooltipView.prototype._hide = function (dispatchAction) { + // Do not directly hideLater here, because this behavior may be prevented + // in dispatchAction when showTip is dispatched. + // FIXME + // duplicated hideTip if manuallyHideTip is called from dispatchAction. + this._lastDataByCoordSys = null; + dispatchAction({ + type: 'hideTip', + from: this.uid + }); + }; + + TooltipView.prototype.dispose = function (ecModel, api) { + if (env.node || !api.getDom()) { + return; + } + + clear(this, '_updatePosition'); + + this._tooltipContent.dispose(); + + unregister('itemTooltip', api); + }; + + TooltipView.type = 'tooltip'; + return TooltipView; + }(ComponentView); + /** + * From top to bottom. (the last one should be globalTooltipModel); + */ + + + function buildTooltipModel(modelCascade, globalTooltipModel, defaultTooltipOption) { + // Last is always tooltip model. + var ecModel = globalTooltipModel.ecModel; + var resultModel; + + if (defaultTooltipOption) { + resultModel = new Model(defaultTooltipOption, ecModel, ecModel); + resultModel = new Model(globalTooltipModel.option, resultModel, ecModel); + } else { + resultModel = globalTooltipModel; + } + + for (var i = modelCascade.length - 1; i >= 0; i--) { + var tooltipOpt = modelCascade[i]; + + if (tooltipOpt) { + if (tooltipOpt instanceof Model) { + tooltipOpt = tooltipOpt.get('tooltip', true); + } // In each data item tooltip can be simply write: + // { + // value: 10, + // tooltip: 'Something you need to know' + // } + + + if (isString(tooltipOpt)) { + tooltipOpt = { + formatter: tooltipOpt + }; + } + + if (tooltipOpt) { + resultModel = new Model(tooltipOpt, resultModel, ecModel); + } + } + } + + return resultModel; + } + + function makeDispatchAction(payload, api) { + return payload.dispatchAction || bind$1(api.dispatchAction, api); + } + + function refixTooltipPosition(x, y, content, viewWidth, viewHeight, gapH, gapV) { + var size = content.getSize(); + var width = size[0]; + var height = size[1]; + + if (gapH != null) { + // Add extra 2 pixels for this case: + // At present the "values" in default tooltip are using CSS `float: right`. + // When the right edge of the tooltip box is on the right side of the + // viewport, the `float` layout might push the "values" to the second line. + if (x + width + gapH + 2 > viewWidth) { + x -= width + gapH; + } else { + x += gapH; + } + } + + if (gapV != null) { + if (y + height + gapV > viewHeight) { + y -= height + gapV; + } else { + y += gapV; + } + } + + return [x, y]; + } + + function confineTooltipPosition(x, y, content, viewWidth, viewHeight) { + var size = content.getSize(); + var width = size[0]; + var height = size[1]; + x = Math.min(x + width, viewWidth) - width; + y = Math.min(y + height, viewHeight) - height; + x = Math.max(x, 0); + y = Math.max(y, 0); + return [x, y]; + } + + function calcTooltipPosition(position, rect, contentSize, borderWidth) { + var domWidth = contentSize[0]; + var domHeight = contentSize[1]; + var offset = Math.ceil(Math.SQRT2 * borderWidth) + 8; + var x = 0; + var y = 0; + var rectWidth = rect.width; + var rectHeight = rect.height; + + switch (position) { + case 'inside': + x = rect.x + rectWidth / 2 - domWidth / 2; + y = rect.y + rectHeight / 2 - domHeight / 2; + break; + + case 'top': + x = rect.x + rectWidth / 2 - domWidth / 2; + y = rect.y - domHeight - offset; + break; + + case 'bottom': + x = rect.x + rectWidth / 2 - domWidth / 2; + y = rect.y + rectHeight + offset; + break; + + case 'left': + x = rect.x - domWidth - offset; + y = rect.y + rectHeight / 2 - domHeight / 2; + break; + + case 'right': + x = rect.x + rectWidth + offset; + y = rect.y + rectHeight / 2 - domHeight / 2; + } + + return [x, y]; + } + + function isCenterAlign(align) { + return align === 'center' || align === 'middle'; + } + /** + * Find target component by payload like: + * ```js + * { legendId: 'some_id', name: 'xxx' } + * { toolboxIndex: 1, name: 'xxx' } + * { geoName: 'some_name', name: 'xxx' } + * ``` + * PENDING: at present only + * + * If not found, return null/undefined. + */ + + + function findComponentReference(payload, ecModel, api) { + var queryOptionMap = preParseFinder(payload).queryOptionMap; + var componentMainType = queryOptionMap.keys()[0]; + + if (!componentMainType || componentMainType === 'series') { + return; + } + + var queryResult = queryReferringComponents(ecModel, componentMainType, queryOptionMap.get(componentMainType), { + useDefault: false, + enableAll: false, + enableNone: false + }); + var model = queryResult.models[0]; + + if (!model) { + return; + } + + var view = api.getViewOfComponentModel(model); + var el; + view.group.traverse(function (subEl) { + var tooltipConfig = getECData(subEl).tooltipConfig; + + if (tooltipConfig && tooltipConfig.name === payload.name) { + el = subEl; + return true; // stop + } + }); + + if (el) { + return { + componentMainType: componentMainType, + componentIndex: model.componentIndex, + el: el + }; + } + } + + function install$2(registers) { + use(install$3); + registers.registerComponentModel(TooltipModel); + registers.registerComponentView(TooltipView); + /** + * @action + * @property {string} type + * @property {number} seriesIndex + * @property {number} dataIndex + * @property {number} [x] + * @property {number} [y] + */ + + registers.registerAction({ + type: 'showTip', + event: 'showTip', + update: 'tooltip:manuallyShowTip' + }, noop); + registers.registerAction({ + type: 'hideTip', + event: 'hideTip', + update: 'tooltip:manuallyHideTip' + }, noop); + } + + use(install$2); + + function checkMarkerInSeries(seriesOpts, markerType) { + if (!seriesOpts) { + return false; + } + + var seriesOptArr = isArray(seriesOpts) ? seriesOpts : [seriesOpts]; + + for (var idx = 0; idx < seriesOptArr.length; idx++) { + if (seriesOptArr[idx] && seriesOptArr[idx][markerType]) { + return true; + } + } + + return false; + } + + function fillLabel(opt) { + defaultEmphasis(opt, 'label', ['show']); + } // { [componentType]: MarkerModel } + + + var inner$2 = makeInner(); + + var MarkerModel = + /** @class */ + function (_super) { + __extends(MarkerModel, _super); + + function MarkerModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MarkerModel.type; + /** + * If marker model is created by self from series + */ + + _this.createdBySelf = false; + _this.preventAutoZ = true; + return _this; + } + /** + * @overrite + */ + + + MarkerModel.prototype.init = function (option, parentModel, ecModel) { + { + if (this.type === 'marker') { + throw new Error('Marker component is abstract component. Use markLine, markPoint, markArea instead.'); + } + } + this.mergeDefaultAndTheme(option, ecModel); + + this._mergeOption(option, ecModel, false, true); + }; + + MarkerModel.prototype.isAnimationEnabled = function () { + if (env.node) { + return false; + } + + var hostSeries = this.__hostSeries; + return this.getShallow('animation') && hostSeries && hostSeries.isAnimationEnabled(); + }; + /** + * @overrite + */ + + + MarkerModel.prototype.mergeOption = function (newOpt, ecModel) { + this._mergeOption(newOpt, ecModel, false, false); + }; + + MarkerModel.prototype._mergeOption = function (newOpt, ecModel, createdBySelf, isInit) { + var componentType = this.mainType; + + if (!createdBySelf) { + ecModel.eachSeries(function (seriesModel) { + // mainType can be markPoint, markLine, markArea + var markerOpt = seriesModel.get(this.mainType, true); + var markerModel = inner$2(seriesModel)[componentType]; + + if (!markerOpt || !markerOpt.data) { + inner$2(seriesModel)[componentType] = null; + return; + } + + if (!markerModel) { + if (isInit) { + // Default label emphasis `position` and `show` + fillLabel(markerOpt); + } + + each$4(markerOpt.data, function (item) { + // FIXME Overwrite fillLabel method ? + if (item instanceof Array) { + fillLabel(item[0]); + fillLabel(item[1]); + } else { + fillLabel(item); + } + }); + markerModel = this.createMarkerModelFromSeries(markerOpt, this, ecModel); // markerModel = new ImplementedMarkerModel( + // markerOpt, this, ecModel + // ); + + extend(markerModel, { + mainType: this.mainType, + // Use the same series index and name + seriesIndex: seriesModel.seriesIndex, + name: seriesModel.name, + createdBySelf: true + }); + markerModel.__hostSeries = seriesModel; + } else { + markerModel._mergeOption(markerOpt, ecModel, true); + } + + inner$2(seriesModel)[componentType] = markerModel; + }, this); + } + }; + + MarkerModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { + var data = this.getData(); + var value = this.getRawValue(dataIndex); + var itemName = data.getName(dataIndex); + return createTooltipMarkup('section', { + header: this.name, + blocks: [createTooltipMarkup('nameValue', { + name: itemName, + value: value, + noName: !itemName, + noValue: value == null + })] + }); + }; + + MarkerModel.prototype.getData = function () { + return this._data; + }; + + MarkerModel.prototype.setData = function (data) { + this._data = data; + }; + + MarkerModel.prototype.getDataParams = function (dataIndex, dataType) { + var params = DataFormatMixin.prototype.getDataParams.call(this, dataIndex, dataType); + var hostSeries = this.__hostSeries; + + if (hostSeries) { + params.seriesId = hostSeries.id; + params.seriesName = hostSeries.name; + params.seriesType = hostSeries.subType; + } + + return params; + }; + + MarkerModel.getMarkerModelFromSeries = function (seriesModel, // Support three types of markers. Strict check. + componentType) { + return inner$2(seriesModel)[componentType]; + }; + + MarkerModel.type = 'marker'; + MarkerModel.dependencies = ['series', 'grid', 'polar', 'geo']; + return MarkerModel; + }(ComponentModel); + + mixin(MarkerModel, DataFormatMixin.prototype); + + var MarkAreaModel = + /** @class */ + function (_super) { + __extends(MarkAreaModel, _super); + + function MarkAreaModel() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MarkAreaModel.type; + return _this; + } + + MarkAreaModel.prototype.createMarkerModelFromSeries = function (markerOpt, masterMarkerModel, ecModel) { + return new MarkAreaModel(markerOpt, masterMarkerModel, ecModel); + }; + + MarkAreaModel.type = 'markArea'; + MarkAreaModel.defaultOption = { + // zlevel: 0, + // PENDING + z: 1, + tooltip: { + trigger: 'item' + }, + // markArea should fixed on the coordinate system + animation: false, + label: { + show: true, + position: 'top' + }, + itemStyle: { + // color and borderColor default to use color from series + // color: 'auto' + // borderColor: 'auto' + borderWidth: 0 + }, + emphasis: { + label: { + show: true, + position: 'top' + } + } + }; + return MarkAreaModel; + }(MarkerModel); + + function hasXOrY(item) { + return !(isNaN(parseFloat(item.x)) && isNaN(parseFloat(item.y))); + } + + function hasXAndY(item) { + return !isNaN(parseFloat(item.x)) && !isNaN(parseFloat(item.y)); + } + + function markerTypeCalculatorWithExtent(markerType, data, axisDim, otherDataDim, targetDataDim, otherCoordIndex, targetCoordIndex) { + var coordArr = []; + var stacked = isDimensionStacked(data, targetDataDim + /* , otherDataDim */ + ); + var calcDataDim = stacked ? data.getCalculationInfo('stackResultDimension') : targetDataDim; + var value = numCalculate(data, calcDataDim, markerType); + var seriesModel = data.hostModel; + var dataIndex = seriesModel.indicesOfNearest(axisDim, calcDataDim, value)[0]; + coordArr[otherCoordIndex] = data.get(otherDataDim, dataIndex); + coordArr[targetCoordIndex] = data.get(calcDataDim, dataIndex); + var coordArrValue = data.get(targetDataDim, dataIndex); // Make it simple, do not visit all stacked value to count precision. + + var precision = getPrecision(data.get(targetDataDim, dataIndex)); + precision = Math.min(precision, 20); + + if (precision >= 0) { + coordArr[targetCoordIndex] = +coordArr[targetCoordIndex].toFixed(precision); + } + + return [coordArr, coordArrValue]; + } // TODO Specified percent + + + var markerTypeCalculator = { + min: curry$1(markerTypeCalculatorWithExtent, 'min'), + max: curry$1(markerTypeCalculatorWithExtent, 'max'), + average: curry$1(markerTypeCalculatorWithExtent, 'average'), + median: curry$1(markerTypeCalculatorWithExtent, 'median') + }; + /** + * Transform markPoint data item to format used in List by do the following + * 1. Calculate statistic like `max`, `min`, `average` + * 2. Convert `item.xAxis`, `item.yAxis` to `item.coord` array + */ + + function dataTransform(seriesModel, item) { + if (!item) { + return; + } + + var data = seriesModel.getData(); + var coordSys = seriesModel.coordinateSystem; + var dims = coordSys && coordSys.dimensions; // 1. If not specify the position with pixel directly + // 2. If `coord` is not a data array. Which uses `xAxis`, + // `yAxis` to specify the coord on each dimension + // parseFloat first because item.x and item.y can be percent string like '20%' + + if (!hasXAndY(item) && !isArray(item.coord) && isArray(dims)) { + var axisInfo = getAxisInfo(item, data, coordSys, seriesModel); // Clone the option + // Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value + + item = clone$3(item); + + if (item.type && markerTypeCalculator[item.type] && axisInfo.baseAxis && axisInfo.valueAxis) { + var otherCoordIndex = indexOf(dims, axisInfo.baseAxis.dim); + var targetCoordIndex = indexOf(dims, axisInfo.valueAxis.dim); + var coordInfo = markerTypeCalculator[item.type](data, axisInfo.valueAxis.dim, axisInfo.baseDataDim, axisInfo.valueDataDim, otherCoordIndex, targetCoordIndex); + item.coord = coordInfo[0]; // Force to use the value of calculated value. + // let item use the value without stack. + + item.value = coordInfo[1]; + } else { + // FIXME Only has one of xAxis and yAxis. + item.coord = [item.xAxis != null ? item.xAxis : item.radiusAxis, item.yAxis != null ? item.yAxis : item.angleAxis]; + } + } // x y is provided + + + if (item.coord == null || !isArray(dims)) { + item.coord = []; + var baseAxis = seriesModel.getBaseAxis(); + + if (baseAxis && item.type && markerTypeCalculator[item.type]) { + var otherAxis = coordSys.getOtherAxis(baseAxis); + + if (otherAxis) { + item.value = numCalculate(data, data.mapDimension(otherAxis.dim), item.type); + } + } + } else { + // Each coord support max, min, average + var coord = item.coord; + + for (var i = 0; i < 2; i++) { + if (markerTypeCalculator[coord[i]]) { + coord[i] = numCalculate(data, data.mapDimension(dims[i]), coord[i]); + } + } + } + + return item; + } + + function getAxisInfo(item, data, coordSys, seriesModel) { + var ret = {}; + + if (item.valueIndex != null || item.valueDim != null) { + ret.valueDataDim = item.valueIndex != null ? data.getDimension(item.valueIndex) : item.valueDim; + ret.valueAxis = coordSys.getAxis(dataDimToCoordDim(seriesModel, ret.valueDataDim)); + ret.baseAxis = coordSys.getOtherAxis(ret.valueAxis); + ret.baseDataDim = data.mapDimension(ret.baseAxis.dim); + } else { + ret.baseAxis = seriesModel.getBaseAxis(); + ret.valueAxis = coordSys.getOtherAxis(ret.baseAxis); + ret.baseDataDim = data.mapDimension(ret.baseAxis.dim); + ret.valueDataDim = data.mapDimension(ret.valueAxis.dim); + } + + return ret; + } + + function dataDimToCoordDim(seriesModel, dataDim) { + var dimItem = seriesModel.getData().getDimensionInfo(dataDim); + return dimItem && dimItem.coordDim; + } + /** + * Filter data which is out of coordinateSystem range + * [dataFilter description] + */ + + + function dataFilter( // Currently only polar and cartesian has containData. + coordSys, item) { + // Always return true if there is no coordSys + return coordSys && coordSys.containData && item.coord && !hasXOrY(item) ? coordSys.containData(item.coord) : true; + } + + function zoneFilter( // Currently only polar and cartesian has containData. + coordSys, item1, item2) { + // Always return true if there is no coordSys + return coordSys && coordSys.containZone && item1.coord && item2.coord && !hasXOrY(item1) && !hasXOrY(item2) ? coordSys.containZone(item1.coord, item2.coord) : true; + } + + function numCalculate(data, valueDataDim, type) { + if (type === 'average') { + var sum_1 = 0; + var count_1 = 0; + data.each(valueDataDim, function (val, idx) { + if (!isNaN(val)) { + sum_1 += val; + count_1++; + } + }); + return sum_1 / count_1; + } else if (type === 'median') { + return data.getMedian(valueDataDim); + } else { + // max & min + return data.getDataExtent(valueDataDim)[type === 'max' ? 1 : 0]; + } + } + + var inner$1 = makeInner(); + + var MarkerView = + /** @class */ + function (_super) { + __extends(MarkerView, _super); + + function MarkerView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MarkerView.type; + return _this; + } + + MarkerView.prototype.init = function () { + this.markerGroupMap = createHashMap(); + }; + + MarkerView.prototype.render = function (markerModel, ecModel, api) { + var _this = this; + + var markerGroupMap = this.markerGroupMap; + markerGroupMap.each(function (item) { + inner$1(item).keep = false; + }); + ecModel.eachSeries(function (seriesModel) { + var markerModel = MarkerModel.getMarkerModelFromSeries(seriesModel, _this.type); + markerModel && _this.renderSeries(seriesModel, markerModel, ecModel, api); + }); + markerGroupMap.each(function (item) { + !inner$1(item).keep && _this.group.remove(item.group); + }); + updateZ(ecModel, markerGroupMap, this.type); + }; + + MarkerView.prototype.markKeep = function (drawGroup) { + inner$1(drawGroup).keep = true; + }; + + MarkerView.prototype.toggleBlurSeries = function (seriesModelList, isBlur) { + var _this = this; + + each$4(seriesModelList, function (seriesModel) { + var markerModel = MarkerModel.getMarkerModelFromSeries(seriesModel, _this.type); + + if (markerModel) { + var data = markerModel.getData(); + data.eachItemGraphicEl(function (el) { + if (el) { + isBlur ? enterBlur(el) : leaveBlur(el); + } + }); + } + }); + }; + + MarkerView.type = 'marker'; + return MarkerView; + }(ComponentView); + + function updateZ(ecModel, markerGroupMap, type) { + ecModel.eachSeries(function (seriesModel) { + var markerModel = MarkerModel.getMarkerModelFromSeries(seriesModel, type); + var markerDraw = markerGroupMap.get(seriesModel.id); + + if (markerModel && markerDraw && markerDraw.group) { + var _a = retrieveZInfo(markerModel), + z = _a.z, + zlevel = _a.zlevel; + + traverseUpdateZ(markerDraw.group, z, zlevel); + } + }); + } + + var inner = makeInner(); + + var markAreaTransform = function (seriesModel, coordSys, maModel, item) { + // item may be null + var item0 = item[0]; + var item1 = item[1]; + + if (!item0 || !item1) { + return; + } + + var lt = dataTransform(seriesModel, item0); + var rb = dataTransform(seriesModel, item1); // FIXME make sure lt is less than rb + + var ltCoord = lt.coord; + var rbCoord = rb.coord; + ltCoord[0] = retrieve(ltCoord[0], -Infinity); + ltCoord[1] = retrieve(ltCoord[1], -Infinity); + rbCoord[0] = retrieve(rbCoord[0], Infinity); + rbCoord[1] = retrieve(rbCoord[1], Infinity); // Merge option into one + + var result = mergeAll([{}, lt, rb]); + result.coord = [lt.coord, rb.coord]; + result.x0 = lt.x; + result.y0 = lt.y; + result.x1 = rb.x; + result.y1 = rb.y; + return result; + }; + + function isInfinity(val) { + return !isNaN(val) && !isFinite(val); + } // If a markArea has one dim + + + function ifMarkAreaHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) { + var otherDimIndex = 1 - dimIndex; + return isInfinity(fromCoord[otherDimIndex]) && isInfinity(toCoord[otherDimIndex]); + } + + function markAreaFilter(coordSys, item) { + var fromCoord = item.coord[0]; + var toCoord = item.coord[1]; + var item0 = { + coord: fromCoord, + x: item.x0, + y: item.y0 + }; + var item1 = { + coord: toCoord, + x: item.x1, + y: item.y1 + }; + + if (isCoordinateSystemType(coordSys, 'cartesian2d')) { + // In case + // { + // markArea: { + // data: [{ yAxis: 2 }] + // } + // } + if (fromCoord && toCoord && (ifMarkAreaHasOnlyDim(1, fromCoord, toCoord) || ifMarkAreaHasOnlyDim(0, fromCoord, toCoord))) { + return true; + } // Directly returning true may also do the work, + // because markArea will not be shown automatically + // when it's not included in coordinate system. + // But filtering ahead can avoid keeping rendering markArea + // when there are too many of them. + + + return zoneFilter(coordSys, item0, item1); + } + + return dataFilter(coordSys, item0) || dataFilter(coordSys, item1); + } // dims can be ['x0', 'y0'], ['x1', 'y1'], ['x0', 'y1'], ['x1', 'y0'] + + + function getSingleMarkerEndPoint(data, idx, dims, seriesModel, api) { + var coordSys = seriesModel.coordinateSystem; + var itemModel = data.getItemModel(idx); + var point; + var xPx = parsePercent(itemModel.get(dims[0]), api.getWidth()); + var yPx = parsePercent(itemModel.get(dims[1]), api.getHeight()); + + if (!isNaN(xPx) && !isNaN(yPx)) { + point = [xPx, yPx]; + } else { + // Chart like bar may have there own marker positioning logic + if (seriesModel.getMarkerPosition) { + // Consider the case that user input the right-bottom point first + // Pick the larger x and y as 'x1' and 'y1' + var pointValue0 = data.getValues(['x0', 'y0'], idx); + var pointValue1 = data.getValues(['x1', 'y1'], idx); + var clampPointValue0 = coordSys.clampData(pointValue0); + var clampPointValue1 = coordSys.clampData(pointValue1); + var pointValue = []; + + if (dims[0] === 'x0') { + pointValue[0] = clampPointValue0[0] > clampPointValue1[0] ? pointValue1[0] : pointValue0[0]; + } else { + pointValue[0] = clampPointValue0[0] > clampPointValue1[0] ? pointValue0[0] : pointValue1[0]; + } + + if (dims[1] === 'y0') { + pointValue[1] = clampPointValue0[1] > clampPointValue1[1] ? pointValue1[1] : pointValue0[1]; + } else { + pointValue[1] = clampPointValue0[1] > clampPointValue1[1] ? pointValue0[1] : pointValue1[1]; + } // Use the getMarkerPosition + + + point = seriesModel.getMarkerPosition(pointValue, dims, true); + } else { + var x = data.get(dims[0], idx); + var y = data.get(dims[1], idx); + var pt = [x, y]; + coordSys.clampData && coordSys.clampData(pt, pt); + point = coordSys.dataToPoint(pt, true); + } + + if (isCoordinateSystemType(coordSys, 'cartesian2d')) { + // TODO: TYPE ts@4.1 may still infer it as Axis instead of Axis2D. Not sure if it's a bug + var xAxis = coordSys.getAxis('x'); + var yAxis = coordSys.getAxis('y'); + var x = data.get(dims[0], idx); + var y = data.get(dims[1], idx); + + if (isInfinity(x)) { + point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[dims[0] === 'x0' ? 0 : 1]); + } else if (isInfinity(y)) { + point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[dims[1] === 'y0' ? 0 : 1]); + } + } // Use x, y if has any + + + if (!isNaN(xPx)) { + point[0] = xPx; + } + + if (!isNaN(yPx)) { + point[1] = yPx; + } + } + + return point; + } + + var dimPermutations = [['x0', 'y0'], ['x1', 'y0'], ['x1', 'y1'], ['x0', 'y1']]; + + var MarkAreaView = + /** @class */ + function (_super) { + __extends(MarkAreaView, _super); + + function MarkAreaView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + + _this.type = MarkAreaView.type; + return _this; + } + + MarkAreaView.prototype.updateTransform = function (markAreaModel, ecModel, api) { + ecModel.eachSeries(function (seriesModel) { + var maModel = MarkerModel.getMarkerModelFromSeries(seriesModel, 'markArea'); + + if (maModel) { + var areaData_1 = maModel.getData(); + areaData_1.each(function (idx) { + var points = map$1(dimPermutations, function (dim) { + return getSingleMarkerEndPoint(areaData_1, idx, dim, seriesModel, api); + }); // Layout + + areaData_1.setItemLayout(idx, points); + var el = areaData_1.getItemGraphicEl(idx); + el.setShape('points', points); + }); + } + }, this); + }; + + MarkAreaView.prototype.renderSeries = function (seriesModel, maModel, ecModel, api) { + var coordSys = seriesModel.coordinateSystem; + var seriesId = seriesModel.id; + var seriesData = seriesModel.getData(); + var areaGroupMap = this.markerGroupMap; + var polygonGroup = areaGroupMap.get(seriesId) || areaGroupMap.set(seriesId, { + group: new Group$2() + }); + this.group.add(polygonGroup.group); + this.markKeep(polygonGroup); + var areaData = createList(coordSys, seriesModel, maModel); // Line data for tooltip and formatter + + maModel.setData(areaData); // Update visual and layout of line + + areaData.each(function (idx) { + // Layout + var points = map$1(dimPermutations, function (dim) { + return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api); + }); + var xAxisScale = coordSys.getAxis('x').scale; + var yAxisScale = coordSys.getAxis('y').scale; + var xAxisExtent = xAxisScale.getExtent(); + var yAxisExtent = yAxisScale.getExtent(); + var xPointExtent = [xAxisScale.parse(areaData.get('x0', idx)), xAxisScale.parse(areaData.get('x1', idx))]; + var yPointExtent = [yAxisScale.parse(areaData.get('y0', idx)), yAxisScale.parse(areaData.get('y1', idx))]; + asc(xPointExtent); + asc(yPointExtent); + var overlapped = !(xAxisExtent[0] > xPointExtent[1] || xAxisExtent[1] < xPointExtent[0] || yAxisExtent[0] > yPointExtent[1] || yAxisExtent[1] < yPointExtent[0]); // If none of the area is inside coordSys, allClipped is set to be true + // in layout so that label will not be displayed. See #12591 + + var allClipped = !overlapped; + areaData.setItemLayout(idx, { + points: points, + allClipped: allClipped + }); + var itemModel = areaData.getItemModel(idx); + var style = itemModel.getModel('itemStyle').getItemStyle(); + var z2 = itemModel.get('z2'); + var color = getVisualFromData(seriesData, 'color'); + + if (!style.fill) { + style.fill = color; + + if (isString(style.fill)) { + style.fill = modifyAlpha(style.fill, 0.4); + } + } + + if (!style.stroke) { + style.stroke = color; + } // Visual + + + areaData.setItemVisual(idx, 'style', style); + areaData.setItemVisual(idx, 'z2', retrieve2(z2, 0)); + }); + areaData.diff(inner(polygonGroup).data).add(function (idx) { + var layout = areaData.getItemLayout(idx); + var z2 = areaData.getItemVisual(idx, 'z2'); + + if (!layout.allClipped) { + var polygon = new Polygon({ + z2: retrieve2(z2, 0), + shape: { + points: layout.points + } + }); + areaData.setItemGraphicEl(idx, polygon); + polygonGroup.group.add(polygon); + } + }).update(function (newIdx, oldIdx) { + var polygon = inner(polygonGroup).data.getItemGraphicEl(oldIdx); + var layout = areaData.getItemLayout(newIdx); + var z2 = areaData.getItemVisual(newIdx, 'z2'); + + if (!layout.allClipped) { + if (polygon) { + updateProps$1(polygon, { + z2: retrieve2(z2, 0), + shape: { + points: layout.points + } + }, maModel, newIdx); + } else { + polygon = new Polygon({ + shape: { + points: layout.points + } + }); + } + + areaData.setItemGraphicEl(newIdx, polygon); + polygonGroup.group.add(polygon); + } else if (polygon) { + polygonGroup.group.remove(polygon); + } + }).remove(function (idx) { + var polygon = inner(polygonGroup).data.getItemGraphicEl(idx); + polygonGroup.group.remove(polygon); + }).execute(); + areaData.eachItemGraphicEl(function (polygon, idx) { + var itemModel = areaData.getItemModel(idx); + var style = areaData.getItemVisual(idx, 'style'); + polygon.useStyle(areaData.getItemVisual(idx, 'style')); + setLabelStyle(polygon, getLabelStatesModels(itemModel), { + labelFetcher: maModel, + labelDataIndex: idx, + defaultText: areaData.getName(idx) || '', + inheritColor: isString(style.fill) ? modifyAlpha(style.fill, 1) : tokens.color.neutral99 + }); + setStatesStylesFromModel(polygon, itemModel); + toggleHoverEmphasis(polygon, null, null, itemModel.get(['emphasis', 'disabled'])); + getECData(polygon).dataModel = maModel; + }); + inner(polygonGroup).data = areaData; + polygonGroup.group.silent = maModel.get('silent') || seriesModel.get('silent'); + }; + + MarkAreaView.type = 'markArea'; + return MarkAreaView; + }(MarkerView); + + function createList(coordSys, seriesModel, maModel) { + var areaData; + var dataDims; + var dims = ['x0', 'y0', 'x1', 'y1']; + + if (coordSys) { + var coordDimsInfos_1 = map$1(coordSys && coordSys.dimensions, function (coordDim) { + var data = seriesModel.getData(); + var info = data.getDimensionInfo(data.mapDimension(coordDim)) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys + + return extend(extend({}, info), { + name: coordDim, + // DON'T use ordinalMeta to parse and collect ordinal. + ordinalMeta: null + }); + }); + dataDims = map$1(dims, function (dim, idx) { + return { + name: dim, + type: coordDimsInfos_1[idx % 2].type + }; + }); + areaData = new SeriesData(dataDims, maModel); + } else { + dataDims = [{ + name: 'value', + type: 'float' + }]; + areaData = new SeriesData(dataDims, maModel); + } + + var optData = map$1(maModel.get('data'), curry$1(markAreaTransform, seriesModel, coordSys, maModel)); + + if (coordSys) { + optData = filter(optData, curry$1(markAreaFilter, coordSys)); + } + + var dimValueGetter = coordSys ? function (item, dimName, dataIndex, dimIndex) { + // TODO should convert to ParsedValue? + var rawVal = item.coord[Math.floor(dimIndex / 2)][dimIndex % 2]; + return parseDataValue(rawVal, dataDims[dimIndex]); + } : function (item, dimName, dataIndex, dimIndex) { + return parseDataValue(item.value, dataDims[dimIndex]); + }; + areaData.initData(optData, null, dimValueGetter); + areaData.hasItemOption = true; + return areaData; + } + + function install$1(registers) { + registers.registerComponentModel(MarkAreaModel); + registers.registerComponentView(MarkAreaView); + registers.registerPreprocessor(function (opt) { + if (checkMarkerInSeries(opt.series, 'markArea')) { + // Make sure markArea component is enabled + opt.markArea = opt.markArea || {}; + } + }); + } + + use(install$1); + use(install$a); + var RELATIONAL_EXPRESSION_OP_ALIAS_MAP = { + value: 'eq', + // PENDING: not good for literal semantic? + '<': 'lt', + '<=': 'lte', + '>': 'gt', + '>=': 'gte', + '=': 'eq', + '!=': 'ne', + '<>': 'ne' // Might be misleading for sake of the difference between '==' and '===', + // so don't support them. + // '==': 'eq', + // '===': 'seq', + // '!==': 'sne' + // PENDING: Whether support some common alias "ge", "le", "neq"? + // ge: 'gte', + // le: 'lte', + // neq: 'ne', + + }; // type RelationalExpressionOpEvaluate = (tarVal: unknown, condVal: unknown) => boolean; + + var RegExpEvaluator = + /** @class */ + function () { + function RegExpEvaluator(rVal) { + // Support condVal: RegExp | string + var condValue = this._condVal = isString(rVal) ? new RegExp(rVal) : isRegExp(rVal) ? rVal : null; + + if (condValue == null) { + var errMsg = ''; + { + errMsg = makePrintable('Illegal regexp', rVal, 'in'); + } + throwError(errMsg); + } + } + + RegExpEvaluator.prototype.evaluate = function (lVal) { + var type = typeof lVal; + return isString(type) ? this._condVal.test(lVal) : isNumber(type) ? this._condVal.test(lVal + '') : false; + }; + + return RegExpEvaluator; + }(); + + var ConstConditionInternal = + /** @class */ + function () { + function ConstConditionInternal() {} + + ConstConditionInternal.prototype.evaluate = function () { + return this.value; + }; + + return ConstConditionInternal; + }(); + + var AndConditionInternal = + /** @class */ + function () { + function AndConditionInternal() {} + + AndConditionInternal.prototype.evaluate = function () { + var children = this.children; + + for (var i = 0; i < children.length; i++) { + if (!children[i].evaluate()) { + return false; + } + } + + return true; + }; + + return AndConditionInternal; + }(); + + var OrConditionInternal = + /** @class */ + function () { + function OrConditionInternal() {} + + OrConditionInternal.prototype.evaluate = function () { + var children = this.children; + + for (var i = 0; i < children.length; i++) { + if (children[i].evaluate()) { + return true; + } + } + + return false; + }; + + return OrConditionInternal; + }(); + + var NotConditionInternal = + /** @class */ + function () { + function NotConditionInternal() {} + + NotConditionInternal.prototype.evaluate = function () { + return !this.child.evaluate(); + }; + + return NotConditionInternal; + }(); + + var RelationalConditionInternal = + /** @class */ + function () { + function RelationalConditionInternal() {} + + RelationalConditionInternal.prototype.evaluate = function () { + var needParse = !!this.valueParser; // Call getValue with no `this`. + + var getValue = this.getValue; + var tarValRaw = getValue(this.valueGetterParam); + var tarValParsed = needParse ? this.valueParser(tarValRaw) : null; // Relational cond follow "and" logic internally. + + for (var i = 0; i < this.subCondList.length; i++) { + if (!this.subCondList[i].evaluate(needParse ? tarValParsed : tarValRaw)) { + return false; + } + } + + return true; + }; + + return RelationalConditionInternal; + }(); + + function parseOption(exprOption, getters) { + if (exprOption === true || exprOption === false) { + var cond = new ConstConditionInternal(); + cond.value = exprOption; + return cond; + } + + var errMsg = ''; + + if (!isObjectNotArray(exprOption)) { + { + errMsg = makePrintable('Illegal config. Expect a plain object but actually', exprOption); + } + throwError(errMsg); + } + + if (exprOption.and) { + return parseAndOrOption('and', exprOption, getters); + } else if (exprOption.or) { + return parseAndOrOption('or', exprOption, getters); + } else if (exprOption.not) { + return parseNotOption(exprOption, getters); + } + + return parseRelationalOption(exprOption, getters); + } + + function parseAndOrOption(op, exprOption, getters) { + var subOptionArr = exprOption[op]; + var errMsg = ''; + { + errMsg = makePrintable('"and"/"or" condition should only be `' + op + ': [...]` and must not be empty array.', 'Illegal condition:', exprOption); + } + + if (!isArray(subOptionArr)) { + throwError(errMsg); + } + + if (!subOptionArr.length) { + throwError(errMsg); + } + + var cond = op === 'and' ? new AndConditionInternal() : new OrConditionInternal(); + cond.children = map$1(subOptionArr, function (subOption) { + return parseOption(subOption, getters); + }); + + if (!cond.children.length) { + throwError(errMsg); + } + + return cond; + } + + function parseNotOption(exprOption, getters) { + var subOption = exprOption.not; + var errMsg = ''; + { + errMsg = makePrintable('"not" condition should only be `not: {}`.', 'Illegal condition:', exprOption); + } + + if (!isObjectNotArray(subOption)) { + throwError(errMsg); + } + + var cond = new NotConditionInternal(); + cond.child = parseOption(subOption, getters); + + if (!cond.child) { + throwError(errMsg); + } + + return cond; + } + + function parseRelationalOption(exprOption, getters) { + var errMsg = ''; + var valueGetterParam = getters.prepareGetValue(exprOption); + var subCondList = []; + var exprKeys = keys(exprOption); + var parserName = exprOption.parser; + var valueParser = parserName ? getRawValueParser(parserName) : null; + + for (var i = 0; i < exprKeys.length; i++) { + var keyRaw = exprKeys[i]; + + if (keyRaw === 'parser' || getters.valueGetterAttrMap.get(keyRaw)) { + continue; + } + + var op = hasOwn(RELATIONAL_EXPRESSION_OP_ALIAS_MAP, keyRaw) ? RELATIONAL_EXPRESSION_OP_ALIAS_MAP[keyRaw] : keyRaw; + var condValueRaw = exprOption[keyRaw]; + var condValueParsed = valueParser ? valueParser(condValueRaw) : condValueRaw; + var evaluator = createFilterComparator(op, condValueParsed) || op === 'reg' && new RegExpEvaluator(condValueParsed); + + if (!evaluator) { + { + errMsg = makePrintable('Illegal relational operation: "' + keyRaw + '" in condition:', exprOption); + } + throwError(errMsg); + } + + subCondList.push(evaluator); + } + + if (!subCondList.length) { + { + errMsg = makePrintable('Relational condition must have at least one operator.', 'Illegal condition:', exprOption); + } // No relational operator always disabled in case of dangers result. + + throwError(errMsg); + } + + var cond = new RelationalConditionInternal(); + cond.valueGetterParam = valueGetterParam; + cond.valueParser = valueParser; + cond.getValue = getters.getValue; + cond.subCondList = subCondList; + return cond; + } + + function isObjectNotArray(val) { + return isObject$2(val) && !isArrayLike(val); + } + + var ConditionalExpressionParsed = + /** @class */ + function () { + function ConditionalExpressionParsed(exprOption, getters) { + this._cond = parseOption(exprOption, getters); + } + + ConditionalExpressionParsed.prototype.evaluate = function () { + return this._cond.evaluate(); + }; + + return ConditionalExpressionParsed; + }(); + + function parseConditionalExpression(exprOption, getters) { + return new ConditionalExpressionParsed(exprOption, getters); + } + + var filterTransform = { + type: 'echarts:filter', + // PENDING: enhance to filter by index rather than create new data + transform: function (params) { + // [Caveat] Fail-Fast: + // Do not return the whole dataset unless user config indicates it explicitly. + // For example, if no condition is specified by mistake, returning an empty result + // is better than returning the entire raw source for the user to find the mistake. + var upstream = params.upstream; + var rawItem; + var condition = parseConditionalExpression(params.config, { + valueGetterAttrMap: createHashMap({ + dimension: true + }), + prepareGetValue: function (exprOption) { + var errMsg = ''; + var dimLoose = exprOption.dimension; + + if (!hasOwn(exprOption, 'dimension')) { + { + errMsg = makePrintable('Relation condition must has prop "dimension" specified.', 'Illegal condition:', exprOption); + } + throwError(errMsg); + } + + var dimInfo = upstream.getDimensionInfo(dimLoose); + + if (!dimInfo) { + { + errMsg = makePrintable('Can not find dimension info via: ' + dimLoose + '.\n', 'Existing dimensions: ', upstream.cloneAllDimensionInfo(), '.\n', 'Illegal condition:', exprOption, '.\n'); + } + throwError(errMsg); + } + + return { + dimIdx: dimInfo.index + }; + }, + getValue: function (param) { + return upstream.retrieveValueFromItem(rawItem, param.dimIdx); + } + }); + var resultData = []; + + for (var i = 0, len = upstream.count(); i < len; i++) { + rawItem = upstream.getRawDataItem(i); + + if (condition.evaluate()) { + resultData.push(rawItem); + } + } + + return { + data: resultData + }; + } + }; + var sampleLog = ''; + { + sampleLog = ['Valid config is like:', '{ dimension: "age", order: "asc" }', 'or [{ dimension: "age", order: "asc"], { dimension: "date", order: "desc" }]'].join(' '); + } + var sortTransform = { + type: 'echarts:sort', + transform: function (params) { + var upstream = params.upstream; + var config = params.config; + var errMsg = ''; // Normalize + // const orderExprList: OrderExpression[] = isArray(config[0]) + // ? config as OrderExpression[] + // : [config as OrderExpression]; + + var orderExprList = normalizeToArray(config); + + if (!orderExprList.length) { + { + errMsg = 'Empty `config` in sort transform.'; + } + throwError(errMsg); + } + + var orderDefList = []; + each$4(orderExprList, function (orderExpr) { + var dimLoose = orderExpr.dimension; + var order = orderExpr.order; + var parserName = orderExpr.parser; + var incomparable = orderExpr.incomparable; + + if (dimLoose == null) { + { + errMsg = 'Sort transform config must has "dimension" specified.' + sampleLog; + } + throwError(errMsg); + } + + if (order !== 'asc' && order !== 'desc') { + { + errMsg = 'Sort transform config must has "order" specified.' + sampleLog; + } + throwError(errMsg); + } + + if (incomparable && incomparable !== 'min' && incomparable !== 'max') { + var errMsg_1 = ''; + { + errMsg_1 = 'incomparable must be "min" or "max" rather than "' + incomparable + '".'; + } + throwError(errMsg_1); + } + + if (order !== 'asc' && order !== 'desc') { + var errMsg_2 = ''; + { + errMsg_2 = 'order must be "asc" or "desc" rather than "' + order + '".'; + } + throwError(errMsg_2); + } + + var dimInfo = upstream.getDimensionInfo(dimLoose); + + if (!dimInfo) { + { + errMsg = makePrintable('Can not find dimension info via: ' + dimLoose + '.\n', 'Existing dimensions: ', upstream.cloneAllDimensionInfo(), '.\n', 'Illegal config:', orderExpr, '.\n'); + } + throwError(errMsg); + } + + var parser = parserName ? getRawValueParser(parserName) : null; + + if (parserName && !parser) { + { + errMsg = makePrintable('Invalid parser name ' + parserName + '.\n', 'Illegal config:', orderExpr, '.\n'); + } + throwError(errMsg); + } + + orderDefList.push({ + dimIdx: dimInfo.index, + parser: parser, + comparator: new SortOrderComparator(order, incomparable) + }); + }); // TODO: support it? + + var sourceFormat = upstream.sourceFormat; + + if (sourceFormat !== SOURCE_FORMAT_ARRAY_ROWS && sourceFormat !== SOURCE_FORMAT_OBJECT_ROWS) { + { + errMsg = 'sourceFormat "' + sourceFormat + '" is not supported yet'; + } + throwError(errMsg); + } // Other upstream format are all array. + + + var resultData = []; + + for (var i = 0, len = upstream.count(); i < len; i++) { + resultData.push(upstream.getRawDataItem(i)); + } + + resultData.sort(function (item0, item1) { + for (var i = 0; i < orderDefList.length; i++) { + var orderDef = orderDefList[i]; + var val0 = upstream.retrieveValueFromItem(item0, orderDef.dimIdx); + var val1 = upstream.retrieveValueFromItem(item1, orderDef.dimIdx); + + if (orderDef.parser) { + val0 = orderDef.parser(val0); + val1 = orderDef.parser(val1); + } + + var result = orderDef.comparator.evaluate(val0, val1); + + if (result !== 0) { + return result; + } + } + + return 0; + }); + return { + data: resultData + }; + } + }; + + function install(registers) { + registers.registerTransform(filterTransform); + registers.registerTransform(sortTransform); + } + + use(install); + exports.Axis = Axis; + exports.ChartView = ChartView; + exports.ComponentModel = ComponentModel; + exports.ComponentView = ComponentView; + exports.List = SeriesData; + exports.Model = Model; + exports.PRIORITY = PRIORITY; + exports.SeriesModel = SeriesModel; + exports.color = color$2; + exports.connect = connect; + exports.dataTool = dataTool; + exports.dependencies = dependencies; + exports.disConnect = disConnect; + exports.disconnect = disconnect; + exports.dispose = dispose; + exports.env = env; + exports.extendChartView = extendChartView; + exports.extendComponentModel = extendComponentModel; + exports.extendComponentView = extendComponentView; + exports.extendSeriesModel = extendSeriesModel; + exports.format = format; + exports.getCoordinateSystemDimensions = getCoordinateSystemDimensions; + exports.getInstanceByDom = getInstanceByDom; + exports.getInstanceById = getInstanceById; + exports.getMap = getMap; + exports.graphic = graphic; + exports.helper = helper; + exports.init = init; + exports.innerDrawElementOnCanvas = brushSingle; + exports.matrix = matrix; + exports.number = number; + exports.parseGeoJSON = parseGeoJSON; + exports.parseGeoJson = parseGeoJSON; + exports.registerAction = registerAction; + exports.registerCoordinateSystem = registerCoordinateSystem; + exports.registerCustomSeries = registerCustomSeries; + exports.registerLayout = registerLayout; + exports.registerLoading = registerLoading; + exports.registerLocale = registerLocale; + exports.registerMap = registerMap; + exports.registerPostInit = registerPostInit; + exports.registerPostUpdate = registerPostUpdate; + exports.registerPreprocessor = registerPreprocessor; + exports.registerProcessor = registerProcessor; + exports.registerTheme = registerTheme; + exports.registerTransform = registerTransform; + exports.registerUpdateLifecycle = registerUpdateLifecycle; + exports.registerVisual = registerVisual; + exports.setCanvasCreator = setCanvasCreator; + exports.setPlatformAPI = setPlatformAPI; + exports.throttle = throttle; + exports.time = time; + exports.use = use; + exports.util = util; + exports.vector = vector; + exports.version = version; + exports.zrUtil = util$1; + exports.zrender = zrender; +}); \ No newline at end of file diff --git a/src/site/generate_appending_a_log_message.js b/src/site/generate_appending_a_log_message.js new file mode 100644 index 000000000..41eb58b4a --- /dev/null +++ b/src/site/generate_appending_a_log_message.js @@ -0,0 +1,119 @@ + +// Get the DOM container for the plot +var containerDOM = document.getElementById('appending_a_log_message_plot'); +if (!containerDOM) { + throw new Error("Could not find 'appending_a_log_message_plot' element"); +} +var myChart = echarts.init(containerDOM, null, { renderer: 'canvas' }); + + +// Find the benchmark html table +var benchmark_data = null; +var element = document.getElementById('benchmark_data_marker'); +while (element && element.tagName) { + if (element.tagName === 'TABLE') { + benchmark_data = element; + break; + } + element = element.nextElementSibling; +} +if (!benchmark_data) { + throw new Error("Could not find benchmark data");; +} + +// Identify the benchmark tests to be included on the plot +var benchmark_pattern = []; +benchmark_pattern.push(new RegExp("Appending (.*) using ([A-Za-z]+), pattern: \\%m\\%n$")); +benchmark_pattern.push(new RegExp("Async, Sending (.*) using ([A-Za-z <]+)$")); +const value_regex_pattern = new RegExp("([0-9]+) ns") + +// Extract the data +var plot_data = new Map(); +var xAxisLabels = []; +for (let i = 0; i < benchmark_data.rows.length; ++i) { + const columns = benchmark_data.rows[i].cells; + if (2 < columns.length) { + const value_match = value_regex_pattern.exec(columns[1].innerText); + if (value_match && 1 < value_match.length) { + for (let rIndex = 0; rIndex < benchmark_pattern.length; ++rIndex) { + const benchmark_match = benchmark_pattern[rIndex].exec(columns[0].innerText); + if (benchmark_match && 2 < benchmark_match.length) { + if (!xAxisLabels.includes(benchmark_match[1])) { + xAxisLabels.push(benchmark_match[1]); + } + var keyValueMap = plot_data.get(benchmark_match[2]); + if (!keyValueMap) { + keyValueMap = new Map(); + plot_data.set(benchmark_match[2], keyValueMap); + } + keyValueMap.set(benchmark_match[1], value_match[1]); + } + } + } + } +} + +// Generate a series for each legend +var legend_data = []; +var series_data = []; +for (const [key, keyValueMap] of plot_data.entries()) { + var series_values = [key]; + for (let i = 0; i < xAxisLabels.length; ++i) { + var value = keyValueMap.get(xAxisLabels[i]); + series_values.push(value ? value : null); + } + + legend_data.push(key); + var series_data_item = new Map(); + series_data_item.set('name', key); + series_data_item.set('type', 'line'); + series_data_item.set('data', series_values); + series_data.push(series_data_item); +} + +// Configure the chart +var chart_data = { + title: { text: 'Appending a log message' }, + yAxis: { + name : 'Average elapsed time (ns)', + nameLocation : 'center' + }, +/* + legend: { + orient: 'vertical', + left: 100, + top: 'center', + data: legend_data + }, + xAxis: { + axisTick : { alignWithLabel: true }, + axisLabel : { rotate: 30 }, + name : 'Log message content', + nameLocation : 'center', + data: xAxisLabels + }, + series: series_data +}; +*/ + legend: { + orient: "vertical", + left: 100, + top: "center", + data: [ "MessageBuffer", "FMT", "FMT and AsyncBuffer", "operator<< and AsyncBuffer" ] + }, + xAxis: { + axisTick: { alignWithLabel: true }, + axisLabel: { rotate: 30 }, + name: 'Log message content', + nameLocation: 'center', + data: [ "5 char string", "49 char string", "int value", "int+float", "int+10float" ] + }, + series: [ + { type: "line", name: "MessageBuffer", data: [ 334, 370, 509, 911, 4579 ] }, + { type: "line", name: "FMT", data: [ null, 346, 376, 508, 1671 ] }, + { type: "line", name: "FMT and AsyncBuffer", data: [ null, null, null, null, 784 ] }, + { type: "line", name: "operator<< and AsyncBuffer", data: [ null, null, null, null, 1211 ] } + ] +}; +// Display the chart +myChart.setOption(chart_data); diff --git a/src/site/markdown/performance.md b/src/site/markdown/performance.md index 2cefd64de..863e5c4f4 100644 --- a/src/site/markdown/performance.md +++ b/src/site/markdown/performance.md @@ -84,7 +84,9 @@ The "Iterations" column derivation is explained in [Google Benchmark documentati L2 Unified 256 KiB (x4) L3 Unified 6144 KiB (x1) Load Average: 0.07, 0.03, 0.01 - +@htmlonly +
+@endhtmlonly | Benchmark | Time | CPU | Iterations | | --------- | -------: | --: | ---------: | | Testing disabled logging request | 0.472 ns | 0.472 ns | 1000000000 | @@ -123,13 +125,17 @@ The "Iterations" column derivation is explained in [Google Benchmark documentati -# The "Async" benchmarks test [AsyncAppender](@ref log4cxx::AsyncAppender) throughput, with logging events discarded in the background thread. -# The "Logging" benchmarks write to a file using buffered output. Overhead is 2-3 times more when not using buffered output. -The above table shows that the overhead of an enabled logging request +@htmlonly +
+ + +@endhtmlonly + +The above graph shows that the overhead of an enabled logging request varies greatly with the message content. A single operations-per-second number is not meaningful. -Most importantly note that [using buffered output](@ref log4cxx::FileAppender::setOption) -reduces overhead more than any other detail. -Note also that logging from multiple threads concurrently +Note that logging from multiple threads concurrently to a common appender generally does not increase throughput due to lock contention in [doAppend method](@ref log4cxx::AppenderSkeleton::doAppend). To simplify the work of an appender implementator, @@ -137,6 +143,9 @@ the [doAppend method](@ref log4cxx::AppenderSkeleton::doAppend) currently preven concurrently entering [the append method](@ref log4cxx::AppenderSkeleton::append), which is the method required to be implemented by a concrete appender class. +Note also that [using buffered output](@ref log4cxx::FileAppender::setOption) +reduces overhead more than any other detail. + The [AsyncAppender](@ref log4cxx::AsyncAppender) provides the least overhead when logging concurrently from multiple threads as it overrides the [doAppend method](@ref log4cxx::AsyncAppender::doAppend) diff --git a/src/site/test_echarts.html b/src/site/test_echarts.html new file mode 100644 index 000000000..18557844c --- /dev/null +++ b/src/site/test_echarts.html @@ -0,0 +1,15 @@ + + + + + + +

Hello World!

+
+ + + +
+ +
+ \ No newline at end of file diff --git a/src/site/test_echarts.js b/src/site/test_echarts.js new file mode 100644 index 000000000..3fa27d6cb --- /dev/null +++ b/src/site/test_echarts.js @@ -0,0 +1,36 @@ +var chart_data = { + "title": { "text": "Appending a log message" }, + "legend": { + "orient": "vertical", + "left": 100, + "top": "center", + "data": [ "MessageBuffer", "FMT", "FMT and AsyncBuffer", "operator<< and AsyncBuffer" ] + }, + "xAxis": { + axisTick: { + alignWithLabel: true + }, + axisLabel: { + rotate: 30 + }, + name : 'Log message content', + nameLocation : 'center', + data : [ "5 char string", "49 char string", "int value", "int+float", "int+10float" ] + }, + "yAxis": { + name : 'Average elapsed time (ns)', + nameLocation : 'center' + }, + "series": [ + { "type": "line", "name": "MessageBuffer", "data": [ 334, 370, 509, 911, 4579 ] }, + { "type": "line", "name": "FMT", "data": [ null, 346, 376, 508, 1671 ] }, + { "type": "line", "name": "FMT and AsyncBuffer", "data": [ null, null, null, null, 784 ] }, + { "type": "line", "name": "operator<< and AsyncBuffer", "data": [ null, null, null, null, 1211 ] } + ] +}; + +var containerDOM = document.getElementById('appending_a_log_message_plot'); +if (containerDOM) { + var myChart = echarts.init(containerDOM, null, { renderer: 'canvas' }); + myChart.setOption(chart_data); +} From 91c7638d8dbc741947540b25429c863c19576e6d Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Thu, 27 Nov 2025 11:57:11 +1100 Subject: [PATCH 2/6] Fix code so it uses data in the html table --- src/site/generate_appending_a_log_message.js | 47 ++++++-------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/src/site/generate_appending_a_log_message.js b/src/site/generate_appending_a_log_message.js index 41eb58b4a..d6a5ce05d 100644 --- a/src/site/generate_appending_a_log_message.js +++ b/src/site/generate_appending_a_log_message.js @@ -57,17 +57,17 @@ for (let i = 0; i < benchmark_data.rows.length; ++i) { var legend_data = []; var series_data = []; for (const [key, keyValueMap] of plot_data.entries()) { - var series_values = [key]; + legend_data.push(key); + var series_values = []; for (let i = 0; i < xAxisLabels.length; ++i) { var value = keyValueMap.get(xAxisLabels[i]); - series_values.push(value ? value : null); + series_values.push(value ? parseInt(value) : null); } - - legend_data.push(key); - var series_data_item = new Map(); - series_data_item.set('name', key); - series_data_item.set('type', 'line'); - series_data_item.set('data', series_values); + var series_data_item = { + name: key, + type: 'line', + data: series_values + }; series_data.push(series_data_item); } @@ -75,45 +75,24 @@ for (const [key, keyValueMap] of plot_data.entries()) { var chart_data = { title: { text: 'Appending a log message' }, yAxis: { - name : 'Average elapsed time (ns)', - nameLocation : 'center' + name: 'Average elapsed time (ns)', + nameLocation: 'center' }, -/* legend: { orient: 'vertical', left: 100, top: 'center', data: legend_data }, - xAxis: { - axisTick : { alignWithLabel: true }, - axisLabel : { rotate: 30 }, - name : 'Log message content', - nameLocation : 'center', - data: xAxisLabels - }, - series: series_data -}; -*/ - legend: { - orient: "vertical", - left: 100, - top: "center", - data: [ "MessageBuffer", "FMT", "FMT and AsyncBuffer", "operator<< and AsyncBuffer" ] - }, xAxis: { axisTick: { alignWithLabel: true }, axisLabel: { rotate: 30 }, name: 'Log message content', nameLocation: 'center', - data: [ "5 char string", "49 char string", "int value", "int+float", "int+10float" ] + data: xAxisLabels }, - series: [ - { type: "line", name: "MessageBuffer", data: [ 334, 370, 509, 911, 4579 ] }, - { type: "line", name: "FMT", data: [ null, 346, 376, 508, 1671 ] }, - { type: "line", name: "FMT and AsyncBuffer", data: [ null, null, null, null, 784 ] }, - { type: "line", name: "operator<< and AsyncBuffer", data: [ null, null, null, null, 1211 ] } - ] + series: series_data }; + // Display the chart myChart.setOption(chart_data); From 7063de75f127cf1861eda895f16f02739e040597 Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Thu, 27 Nov 2025 12:03:48 +1100 Subject: [PATCH 3/6] Add explaination for AsyncBuffer overhead reduction --- src/site/markdown/performance.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/site/markdown/performance.md b/src/site/markdown/performance.md index 863e5c4f4..06b04f55d 100644 --- a/src/site/markdown/performance.md +++ b/src/site/markdown/performance.md @@ -134,6 +134,9 @@ The "Iterations" column derivation is explained in [Google Benchmark documentati The above graph shows that the overhead of an enabled logging request varies greatly with the message content. A single operations-per-second number is not meaningful. +It also shows two data points where binary to text conversion +is moved to a background thread +using [AsyncBuffer](@ref log4cxx::helpers::AsyncBuffer) and [AsyncAppender](@ref log4cxx::AsyncAppender). Note that logging from multiple threads concurrently to a common appender generally does not increase throughput From 31e279e57350d7872778987002a457efae67feff Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Thu, 27 Nov 2025 16:59:59 +1100 Subject: [PATCH 4/6] Improve clarity --- src/site/generate_appending_a_log_message.js | 14 +++++++------- src/site/markdown/performance.md | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/site/generate_appending_a_log_message.js b/src/site/generate_appending_a_log_message.js index d6a5ce05d..b57fba60f 100644 --- a/src/site/generate_appending_a_log_message.js +++ b/src/site/generate_appending_a_log_message.js @@ -30,13 +30,13 @@ const value_regex_pattern = new RegExp("([0-9]+) ns") // Extract the data var plot_data = new Map(); var xAxisLabels = []; -for (let i = 0; i < benchmark_data.rows.length; ++i) { - const columns = benchmark_data.rows[i].cells; +for (const row of benchmark_data.rows) { + const columns = row.cells; if (2 < columns.length) { const value_match = value_regex_pattern.exec(columns[1].innerText); if (value_match && 1 < value_match.length) { - for (let rIndex = 0; rIndex < benchmark_pattern.length; ++rIndex) { - const benchmark_match = benchmark_pattern[rIndex].exec(columns[0].innerText); + for (const pattern of benchmark_pattern) { + const benchmark_match = pattern.exec(columns[0].innerText); if (benchmark_match && 2 < benchmark_match.length) { if (!xAxisLabels.includes(benchmark_match[1])) { xAxisLabels.push(benchmark_match[1]); @@ -59,8 +59,8 @@ var series_data = []; for (const [key, keyValueMap] of plot_data.entries()) { legend_data.push(key); var series_values = []; - for (let i = 0; i < xAxisLabels.length; ++i) { - var value = keyValueMap.get(xAxisLabels[i]); + for (const label of xAxisLabels) { + var value = keyValueMap.get(label); series_values.push(value ? parseInt(value) : null); } var series_data_item = { @@ -80,7 +80,7 @@ var chart_data = { }, legend: { orient: 'vertical', - left: 100, + left: 150, top: 'center', data: legend_data }, diff --git a/src/site/markdown/performance.md b/src/site/markdown/performance.md index 06b04f55d..279aba05b 100644 --- a/src/site/markdown/performance.md +++ b/src/site/markdown/performance.md @@ -126,14 +126,14 @@ The "Iterations" column derivation is explained in [Google Benchmark documentati -# The "Logging" benchmarks write to a file using buffered output. Overhead is 2-3 times more when not using buffered output. @htmlonly -
+
@endhtmlonly The above graph shows that the overhead of an enabled logging request -varies greatly with the message content. -A single operations-per-second number is not meaningful. +varies greatly with the message content and that +the `LOG4CXX_[level]_FMT` macros have lower overhead. It also shows two data points where binary to text conversion is moved to a background thread using [AsyncBuffer](@ref log4cxx::helpers::AsyncBuffer) and [AsyncAppender](@ref log4cxx::AsyncAppender). From 815a74cee0e79192614dc404ea238ecbe79e9c75 Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Mon, 1 Dec 2025 12:50:56 +1100 Subject: [PATCH 5/6] Reduce load time of the web-site performance page --- src/site/CMakeLists.txt | 4 +- src/site/echarts.js | 57475 ----------------------------- src/site/echarts.min.js | 1 + src/site/markdown/performance.md | 2 +- 4 files changed, 4 insertions(+), 57478 deletions(-) delete mode 100644 src/site/echarts.js create mode 100644 src/site/echarts.min.js diff --git a/src/site/CMakeLists.txt b/src/site/CMakeLists.txt index 07888695f..a2773243a 100644 --- a/src/site/CMakeLists.txt +++ b/src/site/CMakeLists.txt @@ -54,8 +54,8 @@ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/markdown/download.md.in configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/markdown/development/build-cmake.md.in ${CMAKE_CURRENT_BINARY_DIR}/markdown/development/build-cmake.md ) -configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/echarts.js - ${CMAKE_CURRENT_BINARY_DIR}/html/echarts.js +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/echarts.min.js + ${CMAKE_CURRENT_BINARY_DIR}/html/echarts.min.js COPYONLY ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/generate_appending_a_log_message.js diff --git a/src/site/echarts.js b/src/site/echarts.js deleted file mode 100644 index 24f0ba3b8..000000000 --- a/src/site/echarts.js +++ /dev/null @@ -1,57475 +0,0 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.echarts = {})); -})(this, function (exports) { - 'use strict'; - /*! ***************************************************************************** - Copyright (c) Microsoft Corporation. - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted. - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */ - - /* global Reflect, Promise */ - - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || { - __proto__: [] - } instanceof Array && function (d, b) { - d.__proto__ = b; - } || function (d, b) { - for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; - }; - - return extendStatics(d, b); - }; - - function __extends(d, b) { - if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); - extendStatics(d, b); - - function __() { - this.constructor = d; - } - - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - } - - var Browser = function () { - function Browser() { - this.firefox = false; - this.ie = false; - this.edge = false; - this.newEdge = false; - this.weChat = false; - } - - return Browser; - }(); - - var Env = function () { - function Env() { - this.browser = new Browser(); - this.node = false; - this.wxa = false; - this.worker = false; - this.svgSupported = false; - this.touchEventsSupported = false; - this.pointerEventsSupported = false; - this.domSupported = false; - this.transformSupported = false; - this.transform3dSupported = false; - this.hasGlobalWindow = typeof window !== 'undefined'; - } - - return Env; - }(); - - var env = new Env(); - - if (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') { - env.wxa = true; - env.touchEventsSupported = true; - } else if (typeof document === 'undefined' && typeof self !== 'undefined') { - env.worker = true; - } else if (!env.hasGlobalWindow || 'Deno' in window || typeof navigator !== 'undefined' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Node.js') > -1) { - env.node = true; - env.svgSupported = true; - } else { - detect(navigator.userAgent, env); - } - - function detect(ua, env) { - var browser = env.browser; - var firefox = ua.match(/Firefox\/([\d.]+)/); - var ie = ua.match(/MSIE\s([\d.]+)/) || ua.match(/Trident\/.+?rv:(([\d.]+))/); - var edge = ua.match(/Edge?\/([\d.]+)/); - var weChat = /micromessenger/i.test(ua); - - if (firefox) { - browser.firefox = true; - browser.version = firefox[1]; - } - - if (ie) { - browser.ie = true; - browser.version = ie[1]; - } - - if (edge) { - browser.edge = true; - browser.version = edge[1]; - browser.newEdge = +edge[1].split('.')[0] > 18; - } - - if (weChat) { - browser.weChat = true; - } - - env.svgSupported = typeof SVGRect !== 'undefined'; - env.touchEventsSupported = 'ontouchstart' in window && !browser.ie && !browser.edge; - env.pointerEventsSupported = 'onpointerdown' in window && (browser.edge || browser.ie && +browser.version >= 11); - var domSupported = env.domSupported = typeof document !== 'undefined'; - - if (domSupported) { - var style = document.documentElement.style; - env.transform3dSupported = (browser.ie && 'transition' in style || browser.edge || 'WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix() || 'MozPerspective' in style) && !('OTransition' in style); - env.transformSupported = env.transform3dSupported || browser.ie && +browser.version >= 9; - } - } - - var DEFAULT_FONT_SIZE = 12; - var DEFAULT_FONT_FAMILY = 'sans-serif'; - var DEFAULT_FONT = DEFAULT_FONT_SIZE + "px " + DEFAULT_FONT_FAMILY; - var OFFSET = 20; - var SCALE = 100; - var defaultWidthMapStr = "007LLmW'55;N0500LLLLLLLLLL00NNNLzWW\\\\WQb\\0FWLg\\bWb\\WQ\\WrWWQ000CL5LLFLL0LL**F*gLLLL5F0LF\\FFF5.5N"; - - function getTextWidthMap(mapStr) { - var map = {}; - - if (typeof JSON === 'undefined') { - return map; - } - - for (var i = 0; i < mapStr.length; i++) { - var char = String.fromCharCode(i + 32); - var size = (mapStr.charCodeAt(i) - OFFSET) / SCALE; - map[char] = size; - } - - return map; - } - - var DEFAULT_TEXT_WIDTH_MAP = getTextWidthMap(defaultWidthMapStr); - var platformApi = { - createCanvas: function () { - return typeof document !== 'undefined' && document.createElement('canvas'); - }, - measureText: function () { - var _ctx; - - var _cachedFont; - - return function (text, font) { - if (!_ctx) { - var canvas = platformApi.createCanvas(); - _ctx = canvas && canvas.getContext('2d'); - } - - if (_ctx) { - if (_cachedFont !== font) { - _cachedFont = _ctx.font = font || DEFAULT_FONT; - } - - return _ctx.measureText(text); - } else { - text = text || ''; - font = font || DEFAULT_FONT; - var res = /((?:\d+)?\.?\d*)px/.exec(font); - var fontSize = res && +res[1] || DEFAULT_FONT_SIZE; - var width = 0; - - if (font.indexOf('mono') >= 0) { - width = fontSize * text.length; - } else { - for (var i = 0; i < text.length; i++) { - var preCalcWidth = DEFAULT_TEXT_WIDTH_MAP[text[i]]; - width += preCalcWidth == null ? fontSize : preCalcWidth * fontSize; - } - } - - return { - width: width - }; - } - }; - }(), - loadImage: function (src, onload, onerror) { - var image = new Image(); - image.onload = onload; - image.onerror = onerror; - image.src = src; - return image; - } - }; - - function setPlatformAPI(newPlatformApis) { - for (var key in platformApi) { - if (newPlatformApis[key]) { - platformApi[key] = newPlatformApis[key]; - } - } - } - - var BUILTIN_OBJECT = reduce(['Function', 'RegExp', 'Date', 'Error', 'CanvasGradient', 'CanvasPattern', 'Image', 'Canvas'], function (obj, val) { - obj['[object ' + val + ']'] = true; - return obj; - }, {}); - var TYPED_ARRAY = reduce(['Int8', 'Uint8', 'Uint8Clamped', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Float32', 'Float64'], function (obj, val) { - obj['[object ' + val + 'Array]'] = true; - return obj; - }, {}); - var objToString = Object.prototype.toString; - var arrayProto = Array.prototype; - var nativeForEach = arrayProto.forEach; - var nativeFilter = arrayProto.filter; - var nativeSlice = arrayProto.slice; - var nativeMap = arrayProto.map; - - var ctorFunction = function () {}.constructor; - - var protoFunction = ctorFunction ? ctorFunction.prototype : null; - var protoKey = '__proto__'; - var idStart = 0x0907; - - function guid() { - return idStart++; - } - - function logError() { - var args = []; - - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - - if (typeof console !== 'undefined') { - console.error.apply(console, args); - } - } - - function clone$3(source) { - if (source == null || typeof source !== 'object') { - return source; - } - - var result = source; - var typeStr = objToString.call(source); - - if (typeStr === '[object Array]') { - if (!isPrimitive(source)) { - result = []; - - for (var i = 0, len = source.length; i < len; i++) { - result[i] = clone$3(source[i]); - } - } - } else if (TYPED_ARRAY[typeStr]) { - if (!isPrimitive(source)) { - var Ctor = source.constructor; - - if (Ctor.from) { - result = Ctor.from(source); - } else { - result = new Ctor(source.length); - - for (var i = 0, len = source.length; i < len; i++) { - result[i] = source[i]; - } - } - } - } else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) { - result = {}; - - for (var key in source) { - if (source.hasOwnProperty(key) && key !== protoKey) { - result[key] = clone$3(source[key]); - } - } - } - - return result; - } - - function merge(target, source, overwrite) { - if (!isObject$2(source) || !isObject$2(target)) { - return overwrite ? clone$3(source) : target; - } - - for (var key in source) { - if (source.hasOwnProperty(key) && key !== protoKey) { - var targetProp = target[key]; - var sourceProp = source[key]; - - if (isObject$2(sourceProp) && isObject$2(targetProp) && !isArray(sourceProp) && !isArray(targetProp) && !isDom(sourceProp) && !isDom(targetProp) && !isBuiltInObject(sourceProp) && !isBuiltInObject(targetProp) && !isPrimitive(sourceProp) && !isPrimitive(targetProp)) { - merge(targetProp, sourceProp, overwrite); - } else if (overwrite || !(key in target)) { - target[key] = clone$3(source[key]); - } - } - } - - return target; - } - - function mergeAll(targetAndSources, overwrite) { - var result = targetAndSources[0]; - - for (var i = 1, len = targetAndSources.length; i < len; i++) { - result = merge(result, targetAndSources[i], overwrite); - } - - return result; - } - - function extend(target, source) { - if (Object.assign) { - Object.assign(target, source); - } else { - for (var key in source) { - if (source.hasOwnProperty(key) && key !== protoKey) { - target[key] = source[key]; - } - } - } - - return target; - } - - function defaults(target, source, overlay) { - var keysArr = keys(source); - - for (var i = 0, len = keysArr.length; i < len; i++) { - var key = keysArr[i]; - - if (overlay ? source[key] != null : target[key] == null) { - target[key] = source[key]; - } - } - - return target; - } - - var createCanvas = platformApi.createCanvas; - - function indexOf(array, value) { - if (array) { - if (array.indexOf) { - return array.indexOf(value); - } - - for (var i = 0, len = array.length; i < len; i++) { - if (array[i] === value) { - return i; - } - } - } - - return -1; - } - - function inherits(clazz, baseClazz) { - var clazzPrototype = clazz.prototype; - - function F() {} - - F.prototype = baseClazz.prototype; - clazz.prototype = new F(); - - for (var prop in clazzPrototype) { - if (clazzPrototype.hasOwnProperty(prop)) { - clazz.prototype[prop] = clazzPrototype[prop]; - } - } - - clazz.prototype.constructor = clazz; - clazz.superClass = baseClazz; - } - - function mixin(target, source, override) { - target = 'prototype' in target ? target.prototype : target; - source = 'prototype' in source ? source.prototype : source; - - if (Object.getOwnPropertyNames) { - var keyList = Object.getOwnPropertyNames(source); - - for (var i = 0; i < keyList.length; i++) { - var key = keyList[i]; - - if (key !== 'constructor') { - if (override ? source[key] != null : target[key] == null) { - target[key] = source[key]; - } - } - } - } else { - defaults(target, source, override); - } - } - - function isArrayLike(data) { - if (!data) { - return false; - } - - if (typeof data === 'string') { - return false; - } - - return typeof data.length === 'number'; - } - - function each$4(arr, cb, context) { - if (!(arr && cb)) { - return; - } - - if (arr.forEach && arr.forEach === nativeForEach) { - arr.forEach(cb, context); - } else if (arr.length === +arr.length) { - for (var i = 0, len = arr.length; i < len; i++) { - cb.call(context, arr[i], i, arr); - } - } else { - for (var key in arr) { - if (arr.hasOwnProperty(key)) { - cb.call(context, arr[key], key, arr); - } - } - } - } - - function map$1(arr, cb, context) { - if (!arr) { - return []; - } - - if (!cb) { - return slice(arr); - } - - if (arr.map && arr.map === nativeMap) { - return arr.map(cb, context); - } else { - var result = []; - - for (var i = 0, len = arr.length; i < len; i++) { - result.push(cb.call(context, arr[i], i, arr)); - } - - return result; - } - } - - function reduce(arr, cb, memo, context) { - if (!(arr && cb)) { - return; - } - - for (var i = 0, len = arr.length; i < len; i++) { - memo = cb.call(context, memo, arr[i], i, arr); - } - - return memo; - } - - function filter(arr, cb, context) { - if (!arr) { - return []; - } - - if (!cb) { - return slice(arr); - } - - if (arr.filter && arr.filter === nativeFilter) { - return arr.filter(cb, context); - } else { - var result = []; - - for (var i = 0, len = arr.length; i < len; i++) { - if (cb.call(context, arr[i], i, arr)) { - result.push(arr[i]); - } - } - - return result; - } - } - - function find(arr, cb, context) { - if (!(arr && cb)) { - return; - } - - for (var i = 0, len = arr.length; i < len; i++) { - if (cb.call(context, arr[i], i, arr)) { - return arr[i]; - } - } - } - - function keys(obj) { - if (!obj) { - return []; - } - - if (Object.keys) { - return Object.keys(obj); - } - - var keyList = []; - - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - keyList.push(key); - } - } - - return keyList; - } - - function bindPolyfill(func, context) { - var args = []; - - for (var _i = 2; _i < arguments.length; _i++) { - args[_i - 2] = arguments[_i]; - } - - return function () { - return func.apply(context, args.concat(nativeSlice.call(arguments))); - }; - } - - var bind$1 = protoFunction && isFunction(protoFunction.bind) ? protoFunction.call.bind(protoFunction.bind) : bindPolyfill; - - function curry$1(func) { - var args = []; - - for (var _i = 1; _i < arguments.length; _i++) { - args[_i - 1] = arguments[_i]; - } - - return function () { - return func.apply(this, args.concat(nativeSlice.call(arguments))); - }; - } - - function isArray(value) { - if (Array.isArray) { - return Array.isArray(value); - } - - return objToString.call(value) === '[object Array]'; - } - - function isFunction(value) { - return typeof value === 'function'; - } - - function isString(value) { - return typeof value === 'string'; - } - - function isStringSafe(value) { - return objToString.call(value) === '[object String]'; - } - - function isNumber(value) { - return typeof value === 'number'; - } - - function isObject$2(value) { - var type = typeof value; - return type === 'function' || !!value && type === 'object'; - } - - function isBuiltInObject(value) { - return !!BUILTIN_OBJECT[objToString.call(value)]; - } - - function isTypedArray(value) { - return !!TYPED_ARRAY[objToString.call(value)]; - } - - function isDom(value) { - return typeof value === 'object' && typeof value.nodeType === 'number' && typeof value.ownerDocument === 'object'; - } - - function isGradientObject(value) { - return value.colorStops != null; - } - - function isImagePatternObject(value) { - return value.image != null; - } - - function isRegExp(value) { - return objToString.call(value) === '[object RegExp]'; - } - - function eqNaN(value) { - return value !== value; - } - - function retrieve() { - var args = []; - - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - - for (var i = 0, len = args.length; i < len; i++) { - if (args[i] != null) { - return args[i]; - } - } - } - - function retrieve2(value0, value1) { - return value0 != null ? value0 : value1; - } - - function retrieve3(value0, value1, value2) { - return value0 != null ? value0 : value1 != null ? value1 : value2; - } - - function slice(arr) { - var args = []; - - for (var _i = 1; _i < arguments.length; _i++) { - args[_i - 1] = arguments[_i]; - } - - return nativeSlice.apply(arr, args); - } - - function normalizeCssArray$1(val) { - if (typeof val === 'number') { - return [val, val, val, val]; - } - - var len = val.length; - - if (len === 2) { - return [val[0], val[1], val[0], val[1]]; - } else if (len === 3) { - return [val[0], val[1], val[2], val[1]]; - } - - return val; - } - - function assert(condition, message) { - if (!condition) { - throw new Error(message); - } - } - - function trim(str) { - if (str == null) { - return null; - } else if (typeof str.trim === 'function') { - return str.trim(); - } else { - return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); - } - } - - var primitiveKey = '__ec_primitive__'; - - function setAsPrimitive(obj) { - obj[primitiveKey] = true; - } - - function isPrimitive(obj) { - return obj[primitiveKey]; - } - - var MapPolyfill = function () { - function MapPolyfill() { - this.data = {}; - } - - MapPolyfill.prototype["delete"] = function (key) { - var existed = this.has(key); - - if (existed) { - delete this.data[key]; - } - - return existed; - }; - - MapPolyfill.prototype.has = function (key) { - return this.data.hasOwnProperty(key); - }; - - MapPolyfill.prototype.get = function (key) { - return this.data[key]; - }; - - MapPolyfill.prototype.set = function (key, value) { - this.data[key] = value; - return this; - }; - - MapPolyfill.prototype.keys = function () { - return keys(this.data); - }; - - MapPolyfill.prototype.forEach = function (callback) { - var data = this.data; - - for (var key in data) { - if (data.hasOwnProperty(key)) { - callback(data[key], key); - } - } - }; - - return MapPolyfill; - }(); - - var isNativeMapSupported = typeof Map === 'function'; - - function maybeNativeMap() { - return isNativeMapSupported ? new Map() : new MapPolyfill(); - } - - var HashMap = function () { - function HashMap(obj) { - var isArr = isArray(obj); - this.data = maybeNativeMap(); - var thisMap = this; - obj instanceof HashMap ? obj.each(visit) : obj && each$4(obj, visit); - - function visit(value, key) { - isArr ? thisMap.set(value, key) : thisMap.set(key, value); - } - } - - HashMap.prototype.hasKey = function (key) { - return this.data.has(key); - }; - - HashMap.prototype.get = function (key) { - return this.data.get(key); - }; - - HashMap.prototype.set = function (key, value) { - this.data.set(key, value); - return value; - }; - - HashMap.prototype.each = function (cb, context) { - this.data.forEach(function (value, key) { - cb.call(context, value, key); - }); - }; - - HashMap.prototype.keys = function () { - var keys = this.data.keys(); - return isNativeMapSupported ? Array.from(keys) : keys; - }; - - HashMap.prototype.removeKey = function (key) { - this.data["delete"](key); - }; - - return HashMap; - }(); - - function createHashMap(obj) { - return new HashMap(obj); - } - - function concatArray(a, b) { - var newArray = new a.constructor(a.length + b.length); - - for (var i = 0; i < a.length; i++) { - newArray[i] = a[i]; - } - - var offset = a.length; - - for (var i = 0; i < b.length; i++) { - newArray[i + offset] = b[i]; - } - - return newArray; - } - - function createObject(proto, properties) { - var obj; - - if (Object.create) { - obj = Object.create(proto); - } else { - var StyleCtor = function () {}; - - StyleCtor.prototype = proto; - obj = new StyleCtor(); - } - - if (properties) { - extend(obj, properties); - } - - return obj; - } - - function disableUserSelect(dom) { - var domStyle = dom.style; - domStyle.webkitUserSelect = 'none'; - domStyle.userSelect = 'none'; - domStyle.webkitTapHighlightColor = 'rgba(0,0,0,0)'; - domStyle['-webkit-touch-callout'] = 'none'; - } - - function hasOwn(own, prop) { - return own.hasOwnProperty(prop); - } - - function noop() {} - - var RADIAN_TO_DEGREE = 180 / Math.PI; - var EPSILON$4 = Number.EPSILON || Math.pow(2, -52); - var util$1 = /*#__PURE__*/Object.freeze({ - __proto__: null, - EPSILON: EPSILON$4, - HashMap: HashMap, - RADIAN_TO_DEGREE: RADIAN_TO_DEGREE, - assert: assert, - bind: bind$1, - clone: clone$3, - concatArray: concatArray, - createCanvas: createCanvas, - createHashMap: createHashMap, - createObject: createObject, - curry: curry$1, - defaults: defaults, - disableUserSelect: disableUserSelect, - each: each$4, - eqNaN: eqNaN, - extend: extend, - filter: filter, - find: find, - guid: guid, - hasOwn: hasOwn, - indexOf: indexOf, - inherits: inherits, - isArray: isArray, - isArrayLike: isArrayLike, - isBuiltInObject: isBuiltInObject, - isDom: isDom, - isFunction: isFunction, - isGradientObject: isGradientObject, - isImagePatternObject: isImagePatternObject, - isNumber: isNumber, - isObject: isObject$2, - isPrimitive: isPrimitive, - isRegExp: isRegExp, - isString: isString, - isStringSafe: isStringSafe, - isTypedArray: isTypedArray, - keys: keys, - logError: logError, - map: map$1, - merge: merge, - mergeAll: mergeAll, - mixin: mixin, - noop: noop, - normalizeCssArray: normalizeCssArray$1, - reduce: reduce, - retrieve: retrieve, - retrieve2: retrieve2, - retrieve3: retrieve3, - setAsPrimitive: setAsPrimitive, - slice: slice, - trim: trim - }); - - function create$1(x, y) { - if (x == null) { - x = 0; - } - - if (y == null) { - y = 0; - } - - return [x, y]; - } - - function copy$1(out, v) { - out[0] = v[0]; - out[1] = v[1]; - return out; - } - - function clone$2(v) { - return [v[0], v[1]]; - } - - function set$1(out, a, b) { - out[0] = a; - out[1] = b; - return out; - } - - function add(out, v1, v2) { - out[0] = v1[0] + v2[0]; - out[1] = v1[1] + v2[1]; - return out; - } - - function scaleAndAdd(out, v1, v2, a) { - out[0] = v1[0] + v2[0] * a; - out[1] = v1[1] + v2[1] * a; - return out; - } - - function sub(out, v1, v2) { - out[0] = v1[0] - v2[0]; - out[1] = v1[1] - v2[1]; - return out; - } - - function len(v) { - return Math.sqrt(lenSquare(v)); - } - - var length = len; - - function lenSquare(v) { - return v[0] * v[0] + v[1] * v[1]; - } - - var lengthSquare = lenSquare; - - function mul$1(out, v1, v2) { - out[0] = v1[0] * v2[0]; - out[1] = v1[1] * v2[1]; - return out; - } - - function div(out, v1, v2) { - out[0] = v1[0] / v2[0]; - out[1] = v1[1] / v2[1]; - return out; - } - - function dot(v1, v2) { - return v1[0] * v2[0] + v1[1] * v2[1]; - } - - function scale$2(out, v, s) { - out[0] = v[0] * s; - out[1] = v[1] * s; - return out; - } - - function normalize$1(out, v) { - var d = len(v); - - if (d === 0) { - out[0] = 0; - out[1] = 0; - } else { - out[0] = v[0] / d; - out[1] = v[1] / d; - } - - return out; - } - - function distance(v1, v2) { - return Math.sqrt((v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1])); - } - - var dist$1 = distance; - - function distanceSquare(v1, v2) { - return (v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1]); - } - - var distSquare = distanceSquare; - - function negate(out, v) { - out[0] = -v[0]; - out[1] = -v[1]; - return out; - } - - function lerp$1(out, v1, v2, t) { - out[0] = v1[0] + t * (v2[0] - v1[0]); - out[1] = v1[1] + t * (v2[1] - v1[1]); - return out; - } - - function applyTransform$1(out, v, m) { - var x = v[0]; - var y = v[1]; - out[0] = m[0] * x + m[2] * y + m[4]; - out[1] = m[1] * x + m[3] * y + m[5]; - return out; - } - - function min$1(out, v1, v2) { - out[0] = Math.min(v1[0], v2[0]); - out[1] = Math.min(v1[1], v2[1]); - return out; - } - - function max$1(out, v1, v2) { - out[0] = Math.max(v1[0], v2[0]); - out[1] = Math.max(v1[1], v2[1]); - return out; - } - - var vector = /*#__PURE__*/Object.freeze({ - __proto__: null, - add: add, - applyTransform: applyTransform$1, - clone: clone$2, - copy: copy$1, - create: create$1, - dist: dist$1, - distSquare: distSquare, - distance: distance, - distanceSquare: distanceSquare, - div: div, - dot: dot, - len: len, - lenSquare: lenSquare, - length: length, - lengthSquare: lengthSquare, - lerp: lerp$1, - max: max$1, - min: min$1, - mul: mul$1, - negate: negate, - normalize: normalize$1, - scale: scale$2, - scaleAndAdd: scaleAndAdd, - set: set$1, - sub: sub - }); - - var Param = function () { - function Param(target, e) { - this.target = target; - this.topTarget = e && e.topTarget; - } - - return Param; - }(); - - var Draggable = function () { - function Draggable(handler) { - this.handler = handler; - handler.on('mousedown', this._dragStart, this); - handler.on('mousemove', this._drag, this); - handler.on('mouseup', this._dragEnd, this); - } - - Draggable.prototype._dragStart = function (e) { - var draggingTarget = e.target; - - while (draggingTarget && !draggingTarget.draggable) { - draggingTarget = draggingTarget.parent || draggingTarget.__hostTarget; - } - - if (draggingTarget) { - this._draggingTarget = draggingTarget; - draggingTarget.dragging = true; - this._x = e.offsetX; - this._y = e.offsetY; - this.handler.dispatchToElement(new Param(draggingTarget, e), 'dragstart', e.event); - } - }; - - Draggable.prototype._drag = function (e) { - var draggingTarget = this._draggingTarget; - - if (draggingTarget) { - var x = e.offsetX; - var y = e.offsetY; - var dx = x - this._x; - var dy = y - this._y; - this._x = x; - this._y = y; - draggingTarget.drift(dx, dy, e); - this.handler.dispatchToElement(new Param(draggingTarget, e), 'drag', e.event); - var dropTarget = this.handler.findHover(x, y, draggingTarget).target; - var lastDropTarget = this._dropTarget; - this._dropTarget = dropTarget; - - if (draggingTarget !== dropTarget) { - if (lastDropTarget && dropTarget !== lastDropTarget) { - this.handler.dispatchToElement(new Param(lastDropTarget, e), 'dragleave', e.event); - } - - if (dropTarget && dropTarget !== lastDropTarget) { - this.handler.dispatchToElement(new Param(dropTarget, e), 'dragenter', e.event); - } - } - } - }; - - Draggable.prototype._dragEnd = function (e) { - var draggingTarget = this._draggingTarget; - - if (draggingTarget) { - draggingTarget.dragging = false; - } - - this.handler.dispatchToElement(new Param(draggingTarget, e), 'dragend', e.event); - - if (this._dropTarget) { - this.handler.dispatchToElement(new Param(this._dropTarget, e), 'drop', e.event); - } - - this._draggingTarget = null; - this._dropTarget = null; - }; - - return Draggable; - }(); - - var Eventful = function () { - function Eventful(eventProcessors) { - if (eventProcessors) { - this._$eventProcessor = eventProcessors; - } - } - - Eventful.prototype.on = function (event, query, handler, context) { - if (!this._$handlers) { - this._$handlers = {}; - } - - var _h = this._$handlers; - - if (typeof query === 'function') { - context = handler; - handler = query; - query = null; - } - - if (!handler || !event) { - return this; - } - - var eventProcessor = this._$eventProcessor; - - if (query != null && eventProcessor && eventProcessor.normalizeQuery) { - query = eventProcessor.normalizeQuery(query); - } - - if (!_h[event]) { - _h[event] = []; - } - - for (var i = 0; i < _h[event].length; i++) { - if (_h[event][i].h === handler) { - return this; - } - } - - var wrap = { - h: handler, - query: query, - ctx: context || this, - callAtLast: handler.zrEventfulCallAtLast - }; - var lastIndex = _h[event].length - 1; - var lastWrap = _h[event][lastIndex]; - lastWrap && lastWrap.callAtLast ? _h[event].splice(lastIndex, 0, wrap) : _h[event].push(wrap); - return this; - }; - - Eventful.prototype.isSilent = function (eventName) { - var _h = this._$handlers; - return !_h || !_h[eventName] || !_h[eventName].length; - }; - - Eventful.prototype.off = function (eventType, handler) { - var _h = this._$handlers; - - if (!_h) { - return this; - } - - if (!eventType) { - this._$handlers = {}; - return this; - } - - if (handler) { - if (_h[eventType]) { - var newList = []; - - for (var i = 0, l = _h[eventType].length; i < l; i++) { - if (_h[eventType][i].h !== handler) { - newList.push(_h[eventType][i]); - } - } - - _h[eventType] = newList; - } - - if (_h[eventType] && _h[eventType].length === 0) { - delete _h[eventType]; - } - } else { - delete _h[eventType]; - } - - return this; - }; - - Eventful.prototype.trigger = function (eventType) { - var args = []; - - for (var _i = 1; _i < arguments.length; _i++) { - args[_i - 1] = arguments[_i]; - } - - if (!this._$handlers) { - return this; - } - - var _h = this._$handlers[eventType]; - var eventProcessor = this._$eventProcessor; - - if (_h) { - var argLen = args.length; - var len = _h.length; - - for (var i = 0; i < len; i++) { - var hItem = _h[i]; - - if (eventProcessor && eventProcessor.filter && hItem.query != null && !eventProcessor.filter(eventType, hItem.query)) { - continue; - } - - switch (argLen) { - case 0: - hItem.h.call(hItem.ctx); - break; - - case 1: - hItem.h.call(hItem.ctx, args[0]); - break; - - case 2: - hItem.h.call(hItem.ctx, args[0], args[1]); - break; - - default: - hItem.h.apply(hItem.ctx, args); - break; - } - } - } - - eventProcessor && eventProcessor.afterTrigger && eventProcessor.afterTrigger(eventType); - return this; - }; - - Eventful.prototype.triggerWithContext = function (type) { - var args = []; - - for (var _i = 1; _i < arguments.length; _i++) { - args[_i - 1] = arguments[_i]; - } - - if (!this._$handlers) { - return this; - } - - var _h = this._$handlers[type]; - var eventProcessor = this._$eventProcessor; - - if (_h) { - var argLen = args.length; - var ctx = args[argLen - 1]; - var len = _h.length; - - for (var i = 0; i < len; i++) { - var hItem = _h[i]; - - if (eventProcessor && eventProcessor.filter && hItem.query != null && !eventProcessor.filter(type, hItem.query)) { - continue; - } - - switch (argLen) { - case 0: - hItem.h.call(ctx); - break; - - case 1: - hItem.h.call(ctx, args[0]); - break; - - case 2: - hItem.h.call(ctx, args[0], args[1]); - break; - - default: - hItem.h.apply(ctx, args.slice(1, argLen - 1)); - break; - } - } - } - - eventProcessor && eventProcessor.afterTrigger && eventProcessor.afterTrigger(type); - return this; - }; - - return Eventful; - }(); - - var LN2 = Math.log(2); - - function determinant(rows, rank, rowStart, rowMask, colMask, detCache) { - var cacheKey = rowMask + '-' + colMask; - var fullRank = rows.length; - - if (detCache.hasOwnProperty(cacheKey)) { - return detCache[cacheKey]; - } - - if (rank === 1) { - var colStart = Math.round(Math.log((1 << fullRank) - 1 & ~colMask) / LN2); - return rows[rowStart][colStart]; - } - - var subRowMask = rowMask | 1 << rowStart; - var subRowStart = rowStart + 1; - - while (rowMask & 1 << subRowStart) { - subRowStart++; - } - - var sum = 0; - - for (var j = 0, colLocalIdx = 0; j < fullRank; j++) { - var colTag = 1 << j; - - if (!(colTag & colMask)) { - sum += (colLocalIdx % 2 ? -1 : 1) * rows[rowStart][j] * determinant(rows, rank - 1, subRowStart, subRowMask, colMask | colTag, detCache); - colLocalIdx++; - } - } - - detCache[cacheKey] = sum; - return sum; - } - - function buildTransformer(src, dest) { - var mA = [[src[0], src[1], 1, 0, 0, 0, -dest[0] * src[0], -dest[0] * src[1]], [0, 0, 0, src[0], src[1], 1, -dest[1] * src[0], -dest[1] * src[1]], [src[2], src[3], 1, 0, 0, 0, -dest[2] * src[2], -dest[2] * src[3]], [0, 0, 0, src[2], src[3], 1, -dest[3] * src[2], -dest[3] * src[3]], [src[4], src[5], 1, 0, 0, 0, -dest[4] * src[4], -dest[4] * src[5]], [0, 0, 0, src[4], src[5], 1, -dest[5] * src[4], -dest[5] * src[5]], [src[6], src[7], 1, 0, 0, 0, -dest[6] * src[6], -dest[6] * src[7]], [0, 0, 0, src[6], src[7], 1, -dest[7] * src[6], -dest[7] * src[7]]]; - var detCache = {}; - var det = determinant(mA, 8, 0, 0, 0, detCache); - - if (det === 0) { - return; - } - - var vh = []; - - for (var i = 0; i < 8; i++) { - for (var j = 0; j < 8; j++) { - vh[j] == null && (vh[j] = 0); - vh[j] += ((i + j) % 2 ? -1 : 1) * determinant(mA, 7, i === 0 ? 1 : 0, 1 << i, 1 << j, detCache) / det * dest[i]; - } - } - - return function (out, srcPointX, srcPointY) { - var pk = srcPointX * vh[6] + srcPointY * vh[7] + 1; - out[0] = (srcPointX * vh[0] + srcPointY * vh[1] + vh[2]) / pk; - out[1] = (srcPointX * vh[3] + srcPointY * vh[4] + vh[5]) / pk; - }; - } - - var EVENT_SAVED_PROP = '___zrEVENTSAVED'; - var _calcOut$1 = []; - - function transformLocalCoord(out, elFrom, elTarget, inX, inY) { - return transformCoordWithViewport(_calcOut$1, elFrom, inX, inY, true) && transformCoordWithViewport(out, elTarget, _calcOut$1[0], _calcOut$1[1]); - } - - function transformLocalCoordClear(elFrom, elTarget) { - elFrom && dealClear(elFrom); - elTarget && dealClear(elTarget); - - function dealClear(el) { - var saved = el[EVENT_SAVED_PROP]; - - if (saved) { - saved.clearMarkers && saved.clearMarkers(); - delete el[EVENT_SAVED_PROP]; - } - } - } - - function transformCoordWithViewport(out, el, inX, inY, inverse) { - if (el.getBoundingClientRect && env.domSupported && !isCanvasEl(el)) { - var saved = el[EVENT_SAVED_PROP] || (el[EVENT_SAVED_PROP] = {}); - var markers = prepareCoordMarkers(el, saved); - var transformer = preparePointerTransformer(markers, saved, inverse); - - if (transformer) { - transformer(out, inX, inY); - return true; - } - } - - return false; - } - - function prepareCoordMarkers(el, saved) { - var markers = saved.markers; - - if (markers) { - return markers; - } - - markers = saved.markers = []; - var propLR = ['left', 'right']; - var propTB = ['top', 'bottom']; - - for (var i = 0; i < 4; i++) { - var marker = document.createElement('div'); - var stl = marker.style; - var idxLR = i % 2; - var idxTB = (i >> 1) % 2; - stl.cssText = ['position: absolute', 'visibility: hidden', 'padding: 0', 'margin: 0', 'border-width: 0', 'user-select: none', 'width:0', 'height:0', propLR[idxLR] + ':0', propTB[idxTB] + ':0', propLR[1 - idxLR] + ':auto', propTB[1 - idxTB] + ':auto', ''].join('!important;'); - el.appendChild(marker); - markers.push(marker); - } - - saved.clearMarkers = function () { - each$4(markers, function (marker) { - marker.parentNode && marker.parentNode.removeChild(marker); - }); - }; - - return markers; - } - - function preparePointerTransformer(markers, saved, inverse) { - var transformerName = inverse ? 'invTrans' : 'trans'; - var transformer = saved[transformerName]; - var oldSrcCoords = saved.srcCoords; - var srcCoords = []; - var destCoords = []; - var oldCoordTheSame = true; - - for (var i = 0; i < 4; i++) { - var rect = markers[i].getBoundingClientRect(); - var ii = 2 * i; - var x = rect.left; - var y = rect.top; - srcCoords.push(x, y); - oldCoordTheSame = oldCoordTheSame && oldSrcCoords && x === oldSrcCoords[ii] && y === oldSrcCoords[ii + 1]; - destCoords.push(markers[i].offsetLeft, markers[i].offsetTop); - } - - return oldCoordTheSame && transformer ? transformer : (saved.srcCoords = srcCoords, saved[transformerName] = inverse ? buildTransformer(destCoords, srcCoords) : buildTransformer(srcCoords, destCoords)); - } - - function isCanvasEl(el) { - return el.nodeName.toUpperCase() === 'CANVAS'; - } - - var replaceReg = /([&<>"'])/g; - var replaceMap = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - '\'': ''' - }; - - function encodeHTML(source) { - return source == null ? '' : (source + '').replace(replaceReg, function (str, c) { - return replaceMap[c]; - }); - } - - var MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/; - var _calcOut = []; - var firefoxNotSupportOffsetXY = env.browser.firefox && +env.browser.version.split('.')[0] < 39; - - function clientToLocal(el, e, out, calculate) { - out = out || {}; - - if (calculate) { - calculateZrXY(el, e, out); - } else if (firefoxNotSupportOffsetXY && e.layerX != null && e.layerX !== e.offsetX) { - out.zrX = e.layerX; - out.zrY = e.layerY; - } else if (e.offsetX != null) { - out.zrX = e.offsetX; - out.zrY = e.offsetY; - } else { - calculateZrXY(el, e, out); - } - - return out; - } - - function calculateZrXY(el, e, out) { - if (env.domSupported && el.getBoundingClientRect) { - var ex = e.clientX; - var ey = e.clientY; - - if (isCanvasEl(el)) { - var box = el.getBoundingClientRect(); - out.zrX = ex - box.left; - out.zrY = ey - box.top; - return; - } else { - if (transformCoordWithViewport(_calcOut, el, ex, ey)) { - out.zrX = _calcOut[0]; - out.zrY = _calcOut[1]; - return; - } - } - } - - out.zrX = out.zrY = 0; - } - - function getNativeEvent(e) { - return e || window.event; - } - - function normalizeEvent(el, e, calculate) { - e = getNativeEvent(e); - - if (e.zrX != null) { - return e; - } - - var eventType = e.type; - var isTouch = eventType && eventType.indexOf('touch') >= 0; - - if (!isTouch) { - clientToLocal(el, e, e, calculate); - var wheelDelta = getWheelDeltaMayPolyfill(e); - e.zrDelta = wheelDelta ? wheelDelta / 120 : -(e.detail || 0) / 3; - } else { - var touch = eventType !== 'touchend' ? e.targetTouches[0] : e.changedTouches[0]; - touch && clientToLocal(el, touch, e, calculate); - } - - var button = e.button; - - if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) { - e.which = button & 1 ? 1 : button & 2 ? 3 : button & 4 ? 2 : 0; - } - - return e; - } - - function getWheelDeltaMayPolyfill(e) { - var rawWheelDelta = e.wheelDelta; - - if (rawWheelDelta) { - return rawWheelDelta; - } - - var deltaX = e.deltaX; - var deltaY = e.deltaY; - - if (deltaX == null || deltaY == null) { - return rawWheelDelta; - } - - var delta = deltaY !== 0 ? Math.abs(deltaY) : Math.abs(deltaX); - var sign = deltaY > 0 ? -1 : deltaY < 0 ? 1 : deltaX > 0 ? -1 : 1; - return 3 * delta * sign; - } - - function addEventListener(el, name, handler, opt) { - el.addEventListener(name, handler, opt); - } - - function removeEventListener(el, name, handler, opt) { - el.removeEventListener(name, handler, opt); - } - - var stop = function (e) { - e.preventDefault(); - e.stopPropagation(); - e.cancelBubble = true; - }; - - var GestureMgr = function () { - function GestureMgr() { - this._track = []; - } - - GestureMgr.prototype.recognize = function (event, target, root) { - this._doTrack(event, target, root); - - return this._recognize(event); - }; - - GestureMgr.prototype.clear = function () { - this._track.length = 0; - return this; - }; - - GestureMgr.prototype._doTrack = function (event, target, root) { - var touches = event.touches; - - if (!touches) { - return; - } - - var trackItem = { - points: [], - touches: [], - target: target, - event: event - }; - - for (var i = 0, len = touches.length; i < len; i++) { - var touch = touches[i]; - var pos = clientToLocal(root, touch, {}); - trackItem.points.push([pos.zrX, pos.zrY]); - trackItem.touches.push(touch); - } - - this._track.push(trackItem); - }; - - GestureMgr.prototype._recognize = function (event) { - for (var eventName in recognizers) { - if (recognizers.hasOwnProperty(eventName)) { - var gestureInfo = recognizers[eventName](this._track, event); - - if (gestureInfo) { - return gestureInfo; - } - } - } - }; - - return GestureMgr; - }(); - - function dist(pointPair) { - var dx = pointPair[1][0] - pointPair[0][0]; - var dy = pointPair[1][1] - pointPair[0][1]; - return Math.sqrt(dx * dx + dy * dy); - } - - function center(pointPair) { - return [(pointPair[0][0] + pointPair[1][0]) / 2, (pointPair[0][1] + pointPair[1][1]) / 2]; - } - - var recognizers = { - pinch: function (tracks, event) { - var trackLen = tracks.length; - - if (!trackLen) { - return; - } - - var pinchEnd = (tracks[trackLen - 1] || {}).points; - var pinchPre = (tracks[trackLen - 2] || {}).points || pinchEnd; - - if (pinchPre && pinchPre.length > 1 && pinchEnd && pinchEnd.length > 1) { - var pinchScale = dist(pinchEnd) / dist(pinchPre); - !isFinite(pinchScale) && (pinchScale = 1); - event.pinchScale = pinchScale; - var pinchCenter = center(pinchEnd); - event.pinchX = pinchCenter[0]; - event.pinchY = pinchCenter[1]; - return { - type: 'pinch', - target: tracks[0].target, - event: event - }; - } - } - }; - - function create() { - return [1, 0, 0, 1, 0, 0]; - } - - function identity(out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 1; - out[4] = 0; - out[5] = 0; - return out; - } - - function copy(out, m) { - out[0] = m[0]; - out[1] = m[1]; - out[2] = m[2]; - out[3] = m[3]; - out[4] = m[4]; - out[5] = m[5]; - return out; - } - - function mul(out, m1, m2) { - var out0 = m1[0] * m2[0] + m1[2] * m2[1]; - var out1 = m1[1] * m2[0] + m1[3] * m2[1]; - var out2 = m1[0] * m2[2] + m1[2] * m2[3]; - var out3 = m1[1] * m2[2] + m1[3] * m2[3]; - var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4]; - var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5]; - out[0] = out0; - out[1] = out1; - out[2] = out2; - out[3] = out3; - out[4] = out4; - out[5] = out5; - return out; - } - - function translate(out, a, v) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4] + v[0]; - out[5] = a[5] + v[1]; - return out; - } - - function rotate(out, a, rad, pivot) { - if (pivot === void 0) { - pivot = [0, 0]; - } - - var aa = a[0]; - var ac = a[2]; - var atx = a[4]; - var ab = a[1]; - var ad = a[3]; - var aty = a[5]; - var st = Math.sin(rad); - var ct = Math.cos(rad); - out[0] = aa * ct + ab * st; - out[1] = -aa * st + ab * ct; - out[2] = ac * ct + ad * st; - out[3] = -ac * st + ct * ad; - out[4] = ct * (atx - pivot[0]) + st * (aty - pivot[1]) + pivot[0]; - out[5] = ct * (aty - pivot[1]) - st * (atx - pivot[0]) + pivot[1]; - return out; - } - - function scale$1(out, a, v) { - var vx = v[0]; - var vy = v[1]; - out[0] = a[0] * vx; - out[1] = a[1] * vy; - out[2] = a[2] * vx; - out[3] = a[3] * vy; - out[4] = a[4] * vx; - out[5] = a[5] * vy; - return out; - } - - function invert(out, a) { - var aa = a[0]; - var ac = a[2]; - var atx = a[4]; - var ab = a[1]; - var ad = a[3]; - var aty = a[5]; - var det = aa * ad - ab * ac; - - if (!det) { - return null; - } - - det = 1.0 / det; - out[0] = ad * det; - out[1] = -ab * det; - out[2] = -ac * det; - out[3] = aa * det; - out[4] = (ac * aty - ad * atx) * det; - out[5] = (ab * atx - aa * aty) * det; - return out; - } - - function clone$1(a) { - var b = create(); - copy(b, a); - return b; - } - - var matrix = /*#__PURE__*/Object.freeze({ - __proto__: null, - clone: clone$1, - copy: copy, - create: create, - identity: identity, - invert: invert, - mul: mul, - rotate: rotate, - scale: scale$1, - translate: translate - }); - - var Point = function () { - function Point(x, y) { - this.x = x || 0; - this.y = y || 0; - } - - Point.prototype.copy = function (other) { - this.x = other.x; - this.y = other.y; - return this; - }; - - Point.prototype.clone = function () { - return new Point(this.x, this.y); - }; - - Point.prototype.set = function (x, y) { - this.x = x; - this.y = y; - return this; - }; - - Point.prototype.equal = function (other) { - return other.x === this.x && other.y === this.y; - }; - - Point.prototype.add = function (other) { - this.x += other.x; - this.y += other.y; - return this; - }; - - Point.prototype.scale = function (scalar) { - this.x *= scalar; - this.y *= scalar; - }; - - Point.prototype.scaleAndAdd = function (other, scalar) { - this.x += other.x * scalar; - this.y += other.y * scalar; - }; - - Point.prototype.sub = function (other) { - this.x -= other.x; - this.y -= other.y; - return this; - }; - - Point.prototype.dot = function (other) { - return this.x * other.x + this.y * other.y; - }; - - Point.prototype.len = function () { - return Math.sqrt(this.x * this.x + this.y * this.y); - }; - - Point.prototype.lenSquare = function () { - return this.x * this.x + this.y * this.y; - }; - - Point.prototype.normalize = function () { - var len = this.len(); - this.x /= len; - this.y /= len; - return this; - }; - - Point.prototype.distance = function (other) { - var dx = this.x - other.x; - var dy = this.y - other.y; - return Math.sqrt(dx * dx + dy * dy); - }; - - Point.prototype.distanceSquare = function (other) { - var dx = this.x - other.x; - var dy = this.y - other.y; - return dx * dx + dy * dy; - }; - - Point.prototype.negate = function () { - this.x = -this.x; - this.y = -this.y; - return this; - }; - - Point.prototype.transform = function (m) { - if (!m) { - return; - } - - var x = this.x; - var y = this.y; - this.x = m[0] * x + m[2] * y + m[4]; - this.y = m[1] * x + m[3] * y + m[5]; - return this; - }; - - Point.prototype.toArray = function (out) { - out[0] = this.x; - out[1] = this.y; - return out; - }; - - Point.prototype.fromArray = function (input) { - this.x = input[0]; - this.y = input[1]; - }; - - Point.set = function (p, x, y) { - p.x = x; - p.y = y; - }; - - Point.copy = function (p, p2) { - p.x = p2.x; - p.y = p2.y; - }; - - Point.len = function (p) { - return Math.sqrt(p.x * p.x + p.y * p.y); - }; - - Point.lenSquare = function (p) { - return p.x * p.x + p.y * p.y; - }; - - Point.dot = function (p0, p1) { - return p0.x * p1.x + p0.y * p1.y; - }; - - Point.add = function (out, p0, p1) { - out.x = p0.x + p1.x; - out.y = p0.y + p1.y; - }; - - Point.sub = function (out, p0, p1) { - out.x = p0.x - p1.x; - out.y = p0.y - p1.y; - }; - - Point.scale = function (out, p0, scalar) { - out.x = p0.x * scalar; - out.y = p0.y * scalar; - }; - - Point.scaleAndAdd = function (out, p0, p1, scalar) { - out.x = p0.x + p1.x * scalar; - out.y = p0.y + p1.y * scalar; - }; - - Point.lerp = function (out, p0, p1, t) { - var onet = 1 - t; - out.x = onet * p0.x + t * p1.x; - out.y = onet * p0.y + t * p1.y; - }; - - return Point; - }(); - - var mathMin$7 = Math.min; - var mathMax$7 = Math.max; - var mathAbs$4 = Math.abs; - var XY$2 = ['x', 'y']; - var WH$2 = ['width', 'height']; - var lt = new Point(); - var rb = new Point(); - var lb = new Point(); - var rt = new Point(); - - var _intersectCtx$1 = createIntersectContext(); - - var _minTv$1 = _intersectCtx$1.minTv; - var _maxTv$1 = _intersectCtx$1.maxTv; - var _lenMinMax = [0, 0]; - - var BoundingRect = function () { - function BoundingRect(x, y, width, height) { - BoundingRect.set(this, x, y, width, height); - } - - BoundingRect.set = function (target, x, y, width, height) { - if (width < 0) { - x = x + width; - width = -width; - } - - if (height < 0) { - y = y + height; - height = -height; - } - - target.x = x; - target.y = y; - target.width = width; - target.height = height; - return target; - }; - - BoundingRect.prototype.union = function (other) { - var x = mathMin$7(other.x, this.x); - var y = mathMin$7(other.y, this.y); - - if (isFinite(this.x) && isFinite(this.width)) { - this.width = mathMax$7(other.x + other.width, this.x + this.width) - x; - } else { - this.width = other.width; - } - - if (isFinite(this.y) && isFinite(this.height)) { - this.height = mathMax$7(other.y + other.height, this.y + this.height) - y; - } else { - this.height = other.height; - } - - this.x = x; - this.y = y; - }; - - BoundingRect.prototype.applyTransform = function (m) { - BoundingRect.applyTransform(this, this, m); - }; - - BoundingRect.prototype.calculateTransform = function (b) { - var a = this; - var sx = b.width / a.width; - var sy = b.height / a.height; - var m = create(); - translate(m, m, [-a.x, -a.y]); - scale$1(m, m, [sx, sy]); - translate(m, m, [b.x, b.y]); - return m; - }; - - BoundingRect.prototype.intersect = function (b, mtv, opt) { - return BoundingRect.intersect(this, b, mtv, opt); - }; - - BoundingRect.intersect = function (a, b, mtv, opt) { - if (mtv) { - Point.set(mtv, 0, 0); - } - - var outIntersectRect = opt && opt.outIntersectRect || null; - var clamp = opt && opt.clamp; - - if (outIntersectRect) { - outIntersectRect.x = outIntersectRect.y = outIntersectRect.width = outIntersectRect.height = NaN; - } - - if (!a || !b) { - return false; - } - - if (!(a instanceof BoundingRect)) { - a = BoundingRect.set(_tmpIntersectA, a.x, a.y, a.width, a.height); - } - - if (!(b instanceof BoundingRect)) { - b = BoundingRect.set(_tmpIntersectB, b.x, b.y, b.width, b.height); - } - - var useMTV = !!mtv; - - _intersectCtx$1.reset(opt, useMTV); - - var touchThreshold = _intersectCtx$1.touchThreshold; - var ax0 = a.x + touchThreshold; - var ax1 = a.x + a.width - touchThreshold; - var ay0 = a.y + touchThreshold; - var ay1 = a.y + a.height - touchThreshold; - var bx0 = b.x + touchThreshold; - var bx1 = b.x + b.width - touchThreshold; - var by0 = b.y + touchThreshold; - var by1 = b.y + b.height - touchThreshold; - - if (ax0 > ax1 || ay0 > ay1 || bx0 > bx1 || by0 > by1) { - return false; - } - - var overlap = !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0); - - if (useMTV || outIntersectRect) { - _lenMinMax[0] = Infinity; - _lenMinMax[1] = 0; - intersectOneDim(ax0, ax1, bx0, bx1, 0, useMTV, outIntersectRect, clamp); - intersectOneDim(ay0, ay1, by0, by1, 1, useMTV, outIntersectRect, clamp); - - if (useMTV) { - Point.copy(mtv, overlap ? _intersectCtx$1.useDir ? _intersectCtx$1.dirMinTv : _minTv$1 : _maxTv$1); - } - } - - return overlap; - }; - - BoundingRect.contain = function (rect, x, y) { - return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height; - }; - - BoundingRect.prototype.contain = function (x, y) { - return BoundingRect.contain(this, x, y); - }; - - BoundingRect.prototype.clone = function () { - return new BoundingRect(this.x, this.y, this.width, this.height); - }; - - BoundingRect.prototype.copy = function (other) { - BoundingRect.copy(this, other); - }; - - BoundingRect.prototype.plain = function () { - return { - x: this.x, - y: this.y, - width: this.width, - height: this.height - }; - }; - - BoundingRect.prototype.isFinite = function () { - return isFinite(this.x) && isFinite(this.y) && isFinite(this.width) && isFinite(this.height); - }; - - BoundingRect.prototype.isZero = function () { - return this.width === 0 || this.height === 0; - }; - - BoundingRect.create = function (rect) { - return new BoundingRect(rect.x, rect.y, rect.width, rect.height); - }; - - BoundingRect.copy = function (target, source) { - target.x = source.x; - target.y = source.y; - target.width = source.width; - target.height = source.height; - return target; - }; - - BoundingRect.applyTransform = function (target, source, m) { - if (!m) { - if (target !== source) { - BoundingRect.copy(target, source); - } - - return; - } - - if (m[1] < 1e-5 && m[1] > -1e-5 && m[2] < 1e-5 && m[2] > -1e-5) { - var sx = m[0]; - var sy = m[3]; - var tx = m[4]; - var ty = m[5]; - target.x = source.x * sx + tx; - target.y = source.y * sy + ty; - target.width = source.width * sx; - target.height = source.height * sy; - - if (target.width < 0) { - target.x += target.width; - target.width = -target.width; - } - - if (target.height < 0) { - target.y += target.height; - target.height = -target.height; - } - - return; - } - - lt.x = lb.x = source.x; - lt.y = rt.y = source.y; - rb.x = rt.x = source.x + source.width; - rb.y = lb.y = source.y + source.height; - lt.transform(m); - rt.transform(m); - rb.transform(m); - lb.transform(m); - target.x = mathMin$7(lt.x, rb.x, lb.x, rt.x); - target.y = mathMin$7(lt.y, rb.y, lb.y, rt.y); - var maxX = mathMax$7(lt.x, rb.x, lb.x, rt.x); - var maxY = mathMax$7(lt.y, rb.y, lb.y, rt.y); - target.width = maxX - target.x; - target.height = maxY - target.y; - }; - - return BoundingRect; - }(); - - var _tmpIntersectA = new BoundingRect(0, 0, 0, 0); - - var _tmpIntersectB = new BoundingRect(0, 0, 0, 0); - - function intersectOneDim(a0, a1, b0, b1, updateDimIdx, useMTV, outIntersectRect, clamp) { - var d0 = mathAbs$4(a1 - b0); - var d1 = mathAbs$4(b1 - a0); - var d01min = mathMin$7(d0, d1); - var updateDim = XY$2[updateDimIdx]; - var zeroDim = XY$2[1 - updateDimIdx]; - var wh = WH$2[updateDimIdx]; - - if (a1 < b0 || b1 < a0) { - if (d0 < d1) { - if (useMTV) { - _maxTv$1[updateDim] = -d0; - } - - if (clamp) { - outIntersectRect[updateDim] = a1; - outIntersectRect[wh] = 0; - } - } else { - if (useMTV) { - _maxTv$1[updateDim] = d1; - } - - if (clamp) { - outIntersectRect[updateDim] = a0; - outIntersectRect[wh] = 0; - } - } - } else { - if (outIntersectRect) { - outIntersectRect[updateDim] = mathMax$7(a0, b0); - outIntersectRect[wh] = mathMin$7(a1, b1) - outIntersectRect[updateDim]; - } - - if (useMTV) { - if (d01min < _lenMinMax[0] || _intersectCtx$1.useDir) { - _lenMinMax[0] = mathMin$7(d01min, _lenMinMax[0]); - - if (d0 < d1 || !_intersectCtx$1.bidirectional) { - _minTv$1[updateDim] = d0; - _minTv$1[zeroDim] = 0; - - if (_intersectCtx$1.useDir) { - _intersectCtx$1.calcDirMTV(); - } - } - - if (d0 >= d1 || !_intersectCtx$1.bidirectional) { - _minTv$1[updateDim] = -d1; - _minTv$1[zeroDim] = 0; - - if (_intersectCtx$1.useDir) { - _intersectCtx$1.calcDirMTV(); - } - } - } - } - } - } - - function createIntersectContext() { - var _direction = 0; - - var _dirCheckVec = new Point(); - - var _dirTmp = new Point(); - - var _ctx = { - minTv: new Point(), - maxTv: new Point(), - useDir: false, - dirMinTv: new Point(), - touchThreshold: 0, - bidirectional: true, - negativeSize: false, - reset: function (opt, useMTV) { - _ctx.touchThreshold = 0; - - if (opt && opt.touchThreshold != null) { - _ctx.touchThreshold = mathMax$7(0, opt.touchThreshold); - } - - _ctx.negativeSize = false; - - if (!useMTV) { - return; - } - - _ctx.minTv.set(Infinity, Infinity); - - _ctx.maxTv.set(0, 0); - - _ctx.useDir = false; - - if (opt && opt.direction != null) { - _ctx.useDir = true; - - _ctx.dirMinTv.copy(_ctx.minTv); - - _dirTmp.copy(_ctx.minTv); - - _direction = opt.direction; - _ctx.bidirectional = opt.bidirectional == null || !!opt.bidirectional; - - if (!_ctx.bidirectional) { - _dirCheckVec.set(Math.cos(_direction), Math.sin(_direction)); - } - } - }, - calcDirMTV: function () { - var minTv = _ctx.minTv; - var dirMinTv = _ctx.dirMinTv; - var squareMag = minTv.y * minTv.y + minTv.x * minTv.x; - var dirSin = Math.sin(_direction); - var dirCos = Math.cos(_direction); - var dotProd = dirSin * minTv.y + dirCos * minTv.x; - - if (nearZero(dotProd)) { - if (nearZero(minTv.x) && nearZero(minTv.y)) { - dirMinTv.set(0, 0); - } - - return; - } - - _dirTmp.x = squareMag * dirCos / dotProd; - _dirTmp.y = squareMag * dirSin / dotProd; - - if (nearZero(_dirTmp.x) && nearZero(_dirTmp.y)) { - dirMinTv.set(0, 0); - return; - } - - if ((_ctx.bidirectional || _dirCheckVec.dot(_dirTmp) > 0) && _dirTmp.len() < dirMinTv.len()) { - dirMinTv.copy(_dirTmp); - } - } - }; - - function nearZero(val) { - return mathAbs$4(val) < 1e-10; - } - - return _ctx; - } - - var SILENT = 'silent'; - - function makeEventPacket(eveType, targetInfo, event) { - return { - type: eveType, - event: event, - target: targetInfo.target, - topTarget: targetInfo.topTarget, - cancelBubble: false, - offsetX: event.zrX, - offsetY: event.zrY, - gestureEvent: event.gestureEvent, - pinchX: event.pinchX, - pinchY: event.pinchY, - pinchScale: event.pinchScale, - wheelDelta: event.zrDelta, - zrByTouch: event.zrByTouch, - which: event.which, - stop: stopEvent - }; - } - - function stopEvent() { - stop(this.event); - } - - var EmptyProxy = function (_super) { - __extends(EmptyProxy, _super); - - function EmptyProxy() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.handler = null; - return _this; - } - - EmptyProxy.prototype.dispose = function () {}; - - EmptyProxy.prototype.setCursor = function () {}; - - return EmptyProxy; - }(Eventful); - - var HoveredResult = function () { - function HoveredResult(x, y) { - this.x = x; - this.y = y; - } - - return HoveredResult; - }(); - - var handlerNames = ['click', 'dblclick', 'mousewheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu']; - var tmpRect$1 = new BoundingRect(0, 0, 0, 0); - - var Handler = function (_super) { - __extends(Handler, _super); - - function Handler(storage, painter, proxy, painterRoot, pointerSize) { - var _this = _super.call(this) || this; - - _this._hovered = new HoveredResult(0, 0); - _this.storage = storage; - _this.painter = painter; - _this.painterRoot = painterRoot; - _this._pointerSize = pointerSize; - proxy = proxy || new EmptyProxy(); - _this.proxy = null; - - _this.setHandlerProxy(proxy); - - _this._draggingMgr = new Draggable(_this); - return _this; - } - - Handler.prototype.setHandlerProxy = function (proxy) { - if (this.proxy) { - this.proxy.dispose(); - } - - if (proxy) { - each$4(handlerNames, function (name) { - proxy.on && proxy.on(name, this[name], this); - }, this); - proxy.handler = this; - } - - this.proxy = proxy; - }; - - Handler.prototype.mousemove = function (event) { - var x = event.zrX; - var y = event.zrY; - var isOutside = isOutsideBoundary(this, x, y); - var lastHovered = this._hovered; - var lastHoveredTarget = lastHovered.target; - - if (lastHoveredTarget && !lastHoveredTarget.__zr) { - lastHovered = this.findHover(lastHovered.x, lastHovered.y); - lastHoveredTarget = lastHovered.target; - } - - var hovered = this._hovered = isOutside ? new HoveredResult(x, y) : this.findHover(x, y); - var hoveredTarget = hovered.target; - var proxy = this.proxy; - proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default'); - - if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) { - this.dispatchToElement(lastHovered, 'mouseout', event); - } - - this.dispatchToElement(hovered, 'mousemove', event); - - if (hoveredTarget && hoveredTarget !== lastHoveredTarget) { - this.dispatchToElement(hovered, 'mouseover', event); - } - }; - - Handler.prototype.mouseout = function (event) { - var eventControl = event.zrEventControl; - - if (eventControl !== 'only_globalout') { - this.dispatchToElement(this._hovered, 'mouseout', event); - } - - if (eventControl !== 'no_globalout') { - this.trigger('globalout', { - type: 'globalout', - event: event - }); - } - }; - - Handler.prototype.resize = function () { - this._hovered = new HoveredResult(0, 0); - }; - - Handler.prototype.dispatch = function (eventName, eventArgs) { - var handler = this[eventName]; - handler && handler.call(this, eventArgs); - }; - - Handler.prototype.dispose = function () { - this.proxy.dispose(); - this.storage = null; - this.proxy = null; - this.painter = null; - }; - - Handler.prototype.setCursorStyle = function (cursorStyle) { - var proxy = this.proxy; - proxy.setCursor && proxy.setCursor(cursorStyle); - }; - - Handler.prototype.dispatchToElement = function (targetInfo, eventName, event) { - targetInfo = targetInfo || {}; - var el = targetInfo.target; - - if (el && el.silent) { - return; - } - - var eventKey = 'on' + eventName; - var eventPacket = makeEventPacket(eventName, targetInfo, event); - - while (el) { - el[eventKey] && (eventPacket.cancelBubble = !!el[eventKey].call(el, eventPacket)); - el.trigger(eventName, eventPacket); - el = el.__hostTarget ? el.__hostTarget : el.parent; - - if (eventPacket.cancelBubble) { - break; - } - } - - if (!eventPacket.cancelBubble) { - this.trigger(eventName, eventPacket); - - if (this.painter && this.painter.eachOtherLayer) { - this.painter.eachOtherLayer(function (layer) { - if (typeof layer[eventKey] === 'function') { - layer[eventKey].call(layer, eventPacket); - } - - if (layer.trigger) { - layer.trigger(eventName, eventPacket); - } - }); - } - } - }; - - Handler.prototype.findHover = function (x, y, exclude) { - var list = this.storage.getDisplayList(); - var out = new HoveredResult(x, y); - setHoverTarget(list, out, x, y, exclude); - - if (this._pointerSize && !out.target) { - var candidates = []; - var pointerSize = this._pointerSize; - var targetSizeHalf = pointerSize / 2; - var pointerRect = new BoundingRect(x - targetSizeHalf, y - targetSizeHalf, pointerSize, pointerSize); - - for (var i = list.length - 1; i >= 0; i--) { - var el = list[i]; - - if (el !== exclude && !el.ignore && !el.ignoreCoarsePointer && (!el.parent || !el.parent.ignoreCoarsePointer)) { - tmpRect$1.copy(el.getBoundingRect()); - - if (el.transform) { - tmpRect$1.applyTransform(el.transform); - } - - if (tmpRect$1.intersect(pointerRect)) { - candidates.push(el); - } - } - } - - if (candidates.length) { - var rStep = 4; - var thetaStep = Math.PI / 12; - var PI2 = Math.PI * 2; - - for (var r = 0; r < targetSizeHalf; r += rStep) { - for (var theta = 0; theta < PI2; theta += thetaStep) { - var x1 = x + r * Math.cos(theta); - var y1 = y + r * Math.sin(theta); - setHoverTarget(candidates, out, x1, y1, exclude); - - if (out.target) { - return out; - } - } - } - } - } - - return out; - }; - - Handler.prototype.processGesture = function (event, stage) { - if (!this._gestureMgr) { - this._gestureMgr = new GestureMgr(); - } - - var gestureMgr = this._gestureMgr; - stage === 'start' && gestureMgr.clear(); - var gestureInfo = gestureMgr.recognize(event, this.findHover(event.zrX, event.zrY, null).target, this.proxy.dom); - stage === 'end' && gestureMgr.clear(); - - if (gestureInfo) { - var type = gestureInfo.type; - event.gestureEvent = type; - var res = new HoveredResult(); - res.target = gestureInfo.target; - this.dispatchToElement(res, type, gestureInfo.event); - } - }; - - return Handler; - }(Eventful); - - each$4(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) { - Handler.prototype[name] = function (event) { - var x = event.zrX; - var y = event.zrY; - var isOutside = isOutsideBoundary(this, x, y); - var hovered; - var hoveredTarget; - - if (name !== 'mouseup' || !isOutside) { - hovered = this.findHover(x, y); - hoveredTarget = hovered.target; - } - - if (name === 'mousedown') { - this._downEl = hoveredTarget; - this._downPoint = [event.zrX, event.zrY]; - this._upEl = hoveredTarget; - } else if (name === 'mouseup') { - this._upEl = hoveredTarget; - } else if (name === 'click') { - if (this._downEl !== this._upEl || !this._downPoint || dist$1(this._downPoint, [event.zrX, event.zrY]) > 4) { - return; - } - - this._downPoint = null; - } - - this.dispatchToElement(hovered, name, event); - }; - }); - - function isHover(displayable, x, y) { - if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) { - var el = displayable; - var isSilent = void 0; - var ignoreClip = false; - - while (el) { - if (el.ignoreClip) { - ignoreClip = true; - } - - if (!ignoreClip) { - var clipPath = el.getClipPath(); - - if (clipPath && !clipPath.contain(x, y)) { - return false; - } - } - - if (el.silent) { - isSilent = true; - } - - var hostEl = el.__hostTarget; - el = hostEl ? el.ignoreHostSilent ? null : hostEl : el.parent; - } - - return isSilent ? SILENT : true; - } - - return false; - } - - function setHoverTarget(list, out, x, y, exclude) { - for (var i = list.length - 1; i >= 0; i--) { - var el = list[i]; - var hoverCheckResult = void 0; - - if (el !== exclude && !el.ignore && (hoverCheckResult = isHover(el, x, y))) { - !out.topTarget && (out.topTarget = el); - - if (hoverCheckResult !== SILENT) { - out.target = el; - break; - } - } - } - } - - function isOutsideBoundary(handlerInstance, x, y) { - var painter = handlerInstance.painter; - return x < 0 || x > painter.getWidth() || y < 0 || y > painter.getHeight(); - } - - var DEFAULT_MIN_MERGE = 32; - var DEFAULT_MIN_GALLOPING = 7; - - function minRunLength(n) { - var r = 0; - - while (n >= DEFAULT_MIN_MERGE) { - r |= n & 1; - n >>= 1; - } - - return n + r; - } - - function makeAscendingRun(array, lo, hi, compare) { - var runHi = lo + 1; - - if (runHi === hi) { - return 1; - } - - if (compare(array[runHi++], array[lo]) < 0) { - while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) { - runHi++; - } - - reverseRun(array, lo, runHi); - } else { - while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) { - runHi++; - } - } - - return runHi - lo; - } - - function reverseRun(array, lo, hi) { - hi--; - - while (lo < hi) { - var t = array[lo]; - array[lo++] = array[hi]; - array[hi--] = t; - } - } - - function binaryInsertionSort(array, lo, hi, start, compare) { - if (start === lo) { - start++; - } - - for (; start < hi; start++) { - var pivot = array[start]; - var left = lo; - var right = start; - var mid; - - while (left < right) { - mid = left + right >>> 1; - - if (compare(pivot, array[mid]) < 0) { - right = mid; - } else { - left = mid + 1; - } - } - - var n = start - left; - - switch (n) { - case 3: - array[left + 3] = array[left + 2]; - - case 2: - array[left + 2] = array[left + 1]; - - case 1: - array[left + 1] = array[left]; - break; - - default: - while (n > 0) { - array[left + n] = array[left + n - 1]; - n--; - } - - } - - array[left] = pivot; - } - } - - function gallopLeft(value, array, start, length, hint, compare) { - var lastOffset = 0; - var maxOffset = 0; - var offset = 1; - - if (compare(value, array[start + hint]) > 0) { - maxOffset = length - hint; - - while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) { - lastOffset = offset; - offset = (offset << 1) + 1; - - if (offset <= 0) { - offset = maxOffset; - } - } - - if (offset > maxOffset) { - offset = maxOffset; - } - - lastOffset += hint; - offset += hint; - } else { - maxOffset = hint + 1; - - while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) { - lastOffset = offset; - offset = (offset << 1) + 1; - - if (offset <= 0) { - offset = maxOffset; - } - } - - if (offset > maxOffset) { - offset = maxOffset; - } - - var tmp = lastOffset; - lastOffset = hint - offset; - offset = hint - tmp; - } - - lastOffset++; - - while (lastOffset < offset) { - var m = lastOffset + (offset - lastOffset >>> 1); - - if (compare(value, array[start + m]) > 0) { - lastOffset = m + 1; - } else { - offset = m; - } - } - - return offset; - } - - function gallopRight(value, array, start, length, hint, compare) { - var lastOffset = 0; - var maxOffset = 0; - var offset = 1; - - if (compare(value, array[start + hint]) < 0) { - maxOffset = hint + 1; - - while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) { - lastOffset = offset; - offset = (offset << 1) + 1; - - if (offset <= 0) { - offset = maxOffset; - } - } - - if (offset > maxOffset) { - offset = maxOffset; - } - - var tmp = lastOffset; - lastOffset = hint - offset; - offset = hint - tmp; - } else { - maxOffset = length - hint; - - while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) { - lastOffset = offset; - offset = (offset << 1) + 1; - - if (offset <= 0) { - offset = maxOffset; - } - } - - if (offset > maxOffset) { - offset = maxOffset; - } - - lastOffset += hint; - offset += hint; - } - - lastOffset++; - - while (lastOffset < offset) { - var m = lastOffset + (offset - lastOffset >>> 1); - - if (compare(value, array[start + m]) < 0) { - offset = m; - } else { - lastOffset = m + 1; - } - } - - return offset; - } - - function TimSort(array, compare) { - var minGallop = DEFAULT_MIN_GALLOPING; - var runStart; - var runLength; - var stackSize = 0; - var tmp = []; - runStart = []; - runLength = []; - - function pushRun(_runStart, _runLength) { - runStart[stackSize] = _runStart; - runLength[stackSize] = _runLength; - stackSize += 1; - } - - function mergeRuns() { - while (stackSize > 1) { - var n = stackSize - 2; - - if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) { - if (runLength[n - 1] < runLength[n + 1]) { - n--; - } - } else if (runLength[n] > runLength[n + 1]) { - break; - } - - mergeAt(n); - } - } - - function forceMergeRuns() { - while (stackSize > 1) { - var n = stackSize - 2; - - if (n > 0 && runLength[n - 1] < runLength[n + 1]) { - n--; - } - - mergeAt(n); - } - } - - function mergeAt(i) { - var start1 = runStart[i]; - var length1 = runLength[i]; - var start2 = runStart[i + 1]; - var length2 = runLength[i + 1]; - runLength[i] = length1 + length2; - - if (i === stackSize - 3) { - runStart[i + 1] = runStart[i + 2]; - runLength[i + 1] = runLength[i + 2]; - } - - stackSize--; - var k = gallopRight(array[start2], array, start1, length1, 0, compare); - start1 += k; - length1 -= k; - - if (length1 === 0) { - return; - } - - length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare); - - if (length2 === 0) { - return; - } - - if (length1 <= length2) { - mergeLow(start1, length1, start2, length2); - } else { - mergeHigh(start1, length1, start2, length2); - } - } - - function mergeLow(start1, length1, start2, length2) { - var i = 0; - - for (i = 0; i < length1; i++) { - tmp[i] = array[start1 + i]; - } - - var cursor1 = 0; - var cursor2 = start2; - var dest = start1; - array[dest++] = array[cursor2++]; - - if (--length2 === 0) { - for (i = 0; i < length1; i++) { - array[dest + i] = tmp[cursor1 + i]; - } - - return; - } - - if (length1 === 1) { - for (i = 0; i < length2; i++) { - array[dest + i] = array[cursor2 + i]; - } - - array[dest + length2] = tmp[cursor1]; - return; - } - - var _minGallop = minGallop; - var count1; - var count2; - var exit; - - while (1) { - count1 = 0; - count2 = 0; - exit = false; - - do { - if (compare(array[cursor2], tmp[cursor1]) < 0) { - array[dest++] = array[cursor2++]; - count2++; - count1 = 0; - - if (--length2 === 0) { - exit = true; - break; - } - } else { - array[dest++] = tmp[cursor1++]; - count1++; - count2 = 0; - - if (--length1 === 1) { - exit = true; - break; - } - } - } while ((count1 | count2) < _minGallop); - - if (exit) { - break; - } - - do { - count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare); - - if (count1 !== 0) { - for (i = 0; i < count1; i++) { - array[dest + i] = tmp[cursor1 + i]; - } - - dest += count1; - cursor1 += count1; - length1 -= count1; - - if (length1 <= 1) { - exit = true; - break; - } - } - - array[dest++] = array[cursor2++]; - - if (--length2 === 0) { - exit = true; - break; - } - - count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare); - - if (count2 !== 0) { - for (i = 0; i < count2; i++) { - array[dest + i] = array[cursor2 + i]; - } - - dest += count2; - cursor2 += count2; - length2 -= count2; - - if (length2 === 0) { - exit = true; - break; - } - } - - array[dest++] = tmp[cursor1++]; - - if (--length1 === 1) { - exit = true; - break; - } - - _minGallop--; - } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING); - - if (exit) { - break; - } - - if (_minGallop < 0) { - _minGallop = 0; - } - - _minGallop += 2; - } - - minGallop = _minGallop; - minGallop < 1 && (minGallop = 1); - - if (length1 === 1) { - for (i = 0; i < length2; i++) { - array[dest + i] = array[cursor2 + i]; - } - - array[dest + length2] = tmp[cursor1]; - } else if (length1 === 0) { - throw new Error(); - } else { - for (i = 0; i < length1; i++) { - array[dest + i] = tmp[cursor1 + i]; - } - } - } - - function mergeHigh(start1, length1, start2, length2) { - var i = 0; - - for (i = 0; i < length2; i++) { - tmp[i] = array[start2 + i]; - } - - var cursor1 = start1 + length1 - 1; - var cursor2 = length2 - 1; - var dest = start2 + length2 - 1; - var customCursor = 0; - var customDest = 0; - array[dest--] = array[cursor1--]; - - if (--length1 === 0) { - customCursor = dest - (length2 - 1); - - for (i = 0; i < length2; i++) { - array[customCursor + i] = tmp[i]; - } - - return; - } - - if (length2 === 1) { - dest -= length1; - cursor1 -= length1; - customDest = dest + 1; - customCursor = cursor1 + 1; - - for (i = length1 - 1; i >= 0; i--) { - array[customDest + i] = array[customCursor + i]; - } - - array[dest] = tmp[cursor2]; - return; - } - - var _minGallop = minGallop; - - while (true) { - var count1 = 0; - var count2 = 0; - var exit = false; - - do { - if (compare(tmp[cursor2], array[cursor1]) < 0) { - array[dest--] = array[cursor1--]; - count1++; - count2 = 0; - - if (--length1 === 0) { - exit = true; - break; - } - } else { - array[dest--] = tmp[cursor2--]; - count2++; - count1 = 0; - - if (--length2 === 1) { - exit = true; - break; - } - } - } while ((count1 | count2) < _minGallop); - - if (exit) { - break; - } - - do { - count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare); - - if (count1 !== 0) { - dest -= count1; - cursor1 -= count1; - length1 -= count1; - customDest = dest + 1; - customCursor = cursor1 + 1; - - for (i = count1 - 1; i >= 0; i--) { - array[customDest + i] = array[customCursor + i]; - } - - if (length1 === 0) { - exit = true; - break; - } - } - - array[dest--] = tmp[cursor2--]; - - if (--length2 === 1) { - exit = true; - break; - } - - count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare); - - if (count2 !== 0) { - dest -= count2; - cursor2 -= count2; - length2 -= count2; - customDest = dest + 1; - customCursor = cursor2 + 1; - - for (i = 0; i < count2; i++) { - array[customDest + i] = tmp[customCursor + i]; - } - - if (length2 <= 1) { - exit = true; - break; - } - } - - array[dest--] = array[cursor1--]; - - if (--length1 === 0) { - exit = true; - break; - } - - _minGallop--; - } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING); - - if (exit) { - break; - } - - if (_minGallop < 0) { - _minGallop = 0; - } - - _minGallop += 2; - } - - minGallop = _minGallop; - - if (minGallop < 1) { - minGallop = 1; - } - - if (length2 === 1) { - dest -= length1; - cursor1 -= length1; - customDest = dest + 1; - customCursor = cursor1 + 1; - - for (i = length1 - 1; i >= 0; i--) { - array[customDest + i] = array[customCursor + i]; - } - - array[dest] = tmp[cursor2]; - } else if (length2 === 0) { - throw new Error(); - } else { - customCursor = dest - (length2 - 1); - - for (i = 0; i < length2; i++) { - array[customCursor + i] = tmp[i]; - } - } - } - - return { - mergeRuns: mergeRuns, - forceMergeRuns: forceMergeRuns, - pushRun: pushRun - }; - } - - function sort(array, compare, lo, hi) { - if (!lo) { - lo = 0; - } - - if (!hi) { - hi = array.length; - } - - var remaining = hi - lo; - - if (remaining < 2) { - return; - } - - var runLength = 0; - - if (remaining < DEFAULT_MIN_MERGE) { - runLength = makeAscendingRun(array, lo, hi, compare); - binaryInsertionSort(array, lo, hi, lo + runLength, compare); - return; - } - - var ts = TimSort(array, compare); - var minRun = minRunLength(remaining); - - do { - runLength = makeAscendingRun(array, lo, hi, compare); - - if (runLength < minRun) { - var force = remaining; - - if (force > minRun) { - force = minRun; - } - - binaryInsertionSort(array, lo, lo + force, lo + runLength, compare); - runLength = force; - } - - ts.pushRun(lo, runLength); - ts.mergeRuns(); - remaining -= runLength; - lo += runLength; - } while (remaining !== 0); - - ts.forceMergeRuns(); - } - - var REDRAW_BIT = 1; - var STYLE_CHANGED_BIT = 2; - var SHAPE_CHANGED_BIT = 4; - var invalidZErrorLogged = false; - - function logInvalidZError() { - if (invalidZErrorLogged) { - return; - } - - invalidZErrorLogged = true; - console.warn('z / z2 / zlevel of displayable is invalid, which may cause unexpected errors'); - } - - function shapeCompareFunc(a, b) { - if (a.zlevel === b.zlevel) { - if (a.z === b.z) { - return a.z2 - b.z2; - } - - return a.z - b.z; - } - - return a.zlevel - b.zlevel; - } - - var Storage = function () { - function Storage() { - this._roots = []; - this._displayList = []; - this._displayListLen = 0; - this.displayableSortFunc = shapeCompareFunc; - } - - Storage.prototype.traverse = function (cb, context) { - for (var i = 0; i < this._roots.length; i++) { - this._roots[i].traverse(cb, context); - } - }; - - Storage.prototype.getDisplayList = function (update, includeIgnore) { - includeIgnore = includeIgnore || false; - var displayList = this._displayList; - - if (update || !displayList.length) { - this.updateDisplayList(includeIgnore); - } - - return displayList; - }; - - Storage.prototype.updateDisplayList = function (includeIgnore) { - this._displayListLen = 0; - var roots = this._roots; - var displayList = this._displayList; - - for (var i = 0, len = roots.length; i < len; i++) { - this._updateAndAddDisplayable(roots[i], null, includeIgnore); - } - - displayList.length = this._displayListLen; - sort(displayList, shapeCompareFunc); - }; - - Storage.prototype._updateAndAddDisplayable = function (el, parentClipPaths, includeIgnore) { - if (el.ignore && !includeIgnore) { - return; - } - - el.beforeUpdate(); - el.update(); - el.afterUpdate(); - var userSetClipPath = el.getClipPath(); - var parentHasClipPaths = parentClipPaths && parentClipPaths.length; - var clipPathIdx = 0; - var thisClipPaths = el.__clipPaths; - - if (!el.ignoreClip && (parentHasClipPaths || userSetClipPath)) { - if (!thisClipPaths) { - thisClipPaths = el.__clipPaths = []; - } - - if (parentHasClipPaths) { - for (var idx = 0; idx < parentClipPaths.length; idx++) { - thisClipPaths[clipPathIdx++] = parentClipPaths[idx]; - } - } - - var currentClipPath = userSetClipPath; - var parentClipPath = el; - - while (currentClipPath) { - currentClipPath.parent = parentClipPath; - currentClipPath.updateTransform(); - thisClipPaths[clipPathIdx++] = currentClipPath; - parentClipPath = currentClipPath; - currentClipPath = currentClipPath.getClipPath(); - } - } - - if (thisClipPaths) { - thisClipPaths.length = clipPathIdx; - } - - if (el.childrenRef) { - var children = el.childrenRef(); - - for (var i = 0; i < children.length; i++) { - var child = children[i]; - - if (el.__dirty) { - child.__dirty |= REDRAW_BIT; - } - - this._updateAndAddDisplayable(child, thisClipPaths, includeIgnore); - } - - el.__dirty = 0; - } else { - var disp = el; - - if (isNaN(disp.z)) { - logInvalidZError(); - disp.z = 0; - } - - if (isNaN(disp.z2)) { - logInvalidZError(); - disp.z2 = 0; - } - - if (isNaN(disp.zlevel)) { - logInvalidZError(); - disp.zlevel = 0; - } - - this._displayList[this._displayListLen++] = disp; - } - - var decalEl = el.getDecalElement && el.getDecalElement(); - - if (decalEl) { - this._updateAndAddDisplayable(decalEl, thisClipPaths, includeIgnore); - } - - var textGuide = el.getTextGuideLine(); - - if (textGuide) { - this._updateAndAddDisplayable(textGuide, thisClipPaths, includeIgnore); - } - - var textEl = el.getTextContent(); - - if (textEl) { - this._updateAndAddDisplayable(textEl, thisClipPaths, includeIgnore); - } - }; - - Storage.prototype.addRoot = function (el) { - if (el.__zr && el.__zr.storage === this) { - return; - } - - this._roots.push(el); - }; - - Storage.prototype.delRoot = function (el) { - if (el instanceof Array) { - for (var i = 0, l = el.length; i < l; i++) { - this.delRoot(el[i]); - } - - return; - } - - var idx = indexOf(this._roots, el); - - if (idx >= 0) { - this._roots.splice(idx, 1); - } - }; - - Storage.prototype.delAllRoots = function () { - this._roots = []; - this._displayList = []; - this._displayListLen = 0; - return; - }; - - Storage.prototype.getRoots = function () { - return this._roots; - }; - - Storage.prototype.dispose = function () { - this._displayList = null; - this._roots = null; - }; - - return Storage; - }(); - - var requestAnimationFrame; - - requestAnimationFrame = env.hasGlobalWindow && (window.requestAnimationFrame && window.requestAnimationFrame.bind(window) || window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window) || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame) || function (func) { - return setTimeout(func, 16); - }; - - var requestAnimationFrame$1 = requestAnimationFrame; - var easingFuncs = { - linear: function (k) { - return k; - }, - quadraticIn: function (k) { - return k * k; - }, - quadraticOut: function (k) { - return k * (2 - k); - }, - quadraticInOut: function (k) { - if ((k *= 2) < 1) { - return 0.5 * k * k; - } - - return -0.5 * (--k * (k - 2) - 1); - }, - cubicIn: function (k) { - return k * k * k; - }, - cubicOut: function (k) { - return --k * k * k + 1; - }, - cubicInOut: function (k) { - if ((k *= 2) < 1) { - return 0.5 * k * k * k; - } - - return 0.5 * ((k -= 2) * k * k + 2); - }, - quarticIn: function (k) { - return k * k * k * k; - }, - quarticOut: function (k) { - return 1 - --k * k * k * k; - }, - quarticInOut: function (k) { - if ((k *= 2) < 1) { - return 0.5 * k * k * k * k; - } - - return -0.5 * ((k -= 2) * k * k * k - 2); - }, - quinticIn: function (k) { - return k * k * k * k * k; - }, - quinticOut: function (k) { - return --k * k * k * k * k + 1; - }, - quinticInOut: function (k) { - if ((k *= 2) < 1) { - return 0.5 * k * k * k * k * k; - } - - return 0.5 * ((k -= 2) * k * k * k * k + 2); - }, - sinusoidalIn: function (k) { - return 1 - Math.cos(k * Math.PI / 2); - }, - sinusoidalOut: function (k) { - return Math.sin(k * Math.PI / 2); - }, - sinusoidalInOut: function (k) { - return 0.5 * (1 - Math.cos(Math.PI * k)); - }, - exponentialIn: function (k) { - return k === 0 ? 0 : Math.pow(1024, k - 1); - }, - exponentialOut: function (k) { - return k === 1 ? 1 : 1 - Math.pow(2, -10 * k); - }, - exponentialInOut: function (k) { - if (k === 0) { - return 0; - } - - if (k === 1) { - return 1; - } - - if ((k *= 2) < 1) { - return 0.5 * Math.pow(1024, k - 1); - } - - return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2); - }, - circularIn: function (k) { - return 1 - Math.sqrt(1 - k * k); - }, - circularOut: function (k) { - return Math.sqrt(1 - --k * k); - }, - circularInOut: function (k) { - if ((k *= 2) < 1) { - return -0.5 * (Math.sqrt(1 - k * k) - 1); - } - - return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1); - }, - elasticIn: function (k) { - var s; - var a = 0.1; - var p = 0.4; - - if (k === 0) { - return 0; - } - - if (k === 1) { - return 1; - } - - if (!a || a < 1) { - a = 1; - s = p / 4; - } else { - s = p * Math.asin(1 / a) / (2 * Math.PI); - } - - return -(a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p)); - }, - elasticOut: function (k) { - var s; - var a = 0.1; - var p = 0.4; - - if (k === 0) { - return 0; - } - - if (k === 1) { - return 1; - } - - if (!a || a < 1) { - a = 1; - s = p / 4; - } else { - s = p * Math.asin(1 / a) / (2 * Math.PI); - } - - return a * Math.pow(2, -10 * k) * Math.sin((k - s) * (2 * Math.PI) / p) + 1; - }, - elasticInOut: function (k) { - var s; - var a = 0.1; - var p = 0.4; - - if (k === 0) { - return 0; - } - - if (k === 1) { - return 1; - } - - if (!a || a < 1) { - a = 1; - s = p / 4; - } else { - s = p * Math.asin(1 / a) / (2 * Math.PI); - } - - if ((k *= 2) < 1) { - return -0.5 * (a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p)); - } - - return a * Math.pow(2, -10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1; - }, - backIn: function (k) { - var s = 1.70158; - return k * k * ((s + 1) * k - s); - }, - backOut: function (k) { - var s = 1.70158; - return --k * k * ((s + 1) * k + s) + 1; - }, - backInOut: function (k) { - var s = 1.70158 * 1.525; - - if ((k *= 2) < 1) { - return 0.5 * (k * k * ((s + 1) * k - s)); - } - - return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2); - }, - bounceIn: function (k) { - return 1 - easingFuncs.bounceOut(1 - k); - }, - bounceOut: function (k) { - if (k < 1 / 2.75) { - return 7.5625 * k * k; - } else if (k < 2 / 2.75) { - return 7.5625 * (k -= 1.5 / 2.75) * k + 0.75; - } else if (k < 2.5 / 2.75) { - return 7.5625 * (k -= 2.25 / 2.75) * k + 0.9375; - } else { - return 7.5625 * (k -= 2.625 / 2.75) * k + 0.984375; - } - }, - bounceInOut: function (k) { - if (k < 0.5) { - return easingFuncs.bounceIn(k * 2) * 0.5; - } - - return easingFuncs.bounceOut(k * 2 - 1) * 0.5 + 0.5; - } - }; - var mathPow$1 = Math.pow; - var mathSqrt$3 = Math.sqrt; - var EPSILON$3 = 1e-8; - var EPSILON_NUMERIC = 1e-4; - var THREE_SQRT = mathSqrt$3(3); - var ONE_THIRD = 1 / 3; - - var _v0 = create$1(); - - var _v1 = create$1(); - - var _v2 = create$1(); - - function isAroundZero(val) { - return val > -EPSILON$3 && val < EPSILON$3; - } - - function isNotAroundZero$1(val) { - return val > EPSILON$3 || val < -EPSILON$3; - } - - function cubicAt(p0, p1, p2, p3, t) { - var onet = 1 - t; - return onet * onet * (onet * p0 + 3 * t * p1) + t * t * (t * p3 + 3 * onet * p2); - } - - function cubicDerivativeAt(p0, p1, p2, p3, t) { - var onet = 1 - t; - return 3 * (((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet + (p3 - p2) * t * t); - } - - function cubicRootAt(p0, p1, p2, p3, val, roots) { - var a = p3 + 3 * (p1 - p2) - p0; - var b = 3 * (p2 - p1 * 2 + p0); - var c = 3 * (p1 - p0); - var d = p0 - val; - var A = b * b - 3 * a * c; - var B = b * c - 9 * a * d; - var C = c * c - 3 * b * d; - var n = 0; - - if (isAroundZero(A) && isAroundZero(B)) { - if (isAroundZero(b)) { - roots[0] = 0; - } else { - var t1 = -c / b; - - if (t1 >= 0 && t1 <= 1) { - roots[n++] = t1; - } - } - } else { - var disc = B * B - 4 * A * C; - - if (isAroundZero(disc)) { - var K = B / A; - var t1 = -b / a + K; - var t2 = -K / 2; - - if (t1 >= 0 && t1 <= 1) { - roots[n++] = t1; - } - - if (t2 >= 0 && t2 <= 1) { - roots[n++] = t2; - } - } else if (disc > 0) { - var discSqrt = mathSqrt$3(disc); - var Y1 = A * b + 1.5 * a * (-B + discSqrt); - var Y2 = A * b + 1.5 * a * (-B - discSqrt); - - if (Y1 < 0) { - Y1 = -mathPow$1(-Y1, ONE_THIRD); - } else { - Y1 = mathPow$1(Y1, ONE_THIRD); - } - - if (Y2 < 0) { - Y2 = -mathPow$1(-Y2, ONE_THIRD); - } else { - Y2 = mathPow$1(Y2, ONE_THIRD); - } - - var t1 = (-b - (Y1 + Y2)) / (3 * a); - - if (t1 >= 0 && t1 <= 1) { - roots[n++] = t1; - } - } else { - var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt$3(A * A * A)); - var theta = Math.acos(T) / 3; - var ASqrt = mathSqrt$3(A); - var tmp = Math.cos(theta); - var t1 = (-b - 2 * ASqrt * tmp) / (3 * a); - var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a); - var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a); - - if (t1 >= 0 && t1 <= 1) { - roots[n++] = t1; - } - - if (t2 >= 0 && t2 <= 1) { - roots[n++] = t2; - } - - if (t3 >= 0 && t3 <= 1) { - roots[n++] = t3; - } - } - } - - return n; - } - - function cubicExtrema(p0, p1, p2, p3, extrema) { - var b = 6 * p2 - 12 * p1 + 6 * p0; - var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2; - var c = 3 * p1 - 3 * p0; - var n = 0; - - if (isAroundZero(a)) { - if (isNotAroundZero$1(b)) { - var t1 = -c / b; - - if (t1 >= 0 && t1 <= 1) { - extrema[n++] = t1; - } - } - } else { - var disc = b * b - 4 * a * c; - - if (isAroundZero(disc)) { - extrema[0] = -b / (2 * a); - } else if (disc > 0) { - var discSqrt = mathSqrt$3(disc); - var t1 = (-b + discSqrt) / (2 * a); - var t2 = (-b - discSqrt) / (2 * a); - - if (t1 >= 0 && t1 <= 1) { - extrema[n++] = t1; - } - - if (t2 >= 0 && t2 <= 1) { - extrema[n++] = t2; - } - } - } - - return n; - } - - function cubicSubdivide(p0, p1, p2, p3, t, out) { - var p01 = (p1 - p0) * t + p0; - var p12 = (p2 - p1) * t + p1; - var p23 = (p3 - p2) * t + p2; - var p012 = (p12 - p01) * t + p01; - var p123 = (p23 - p12) * t + p12; - var p0123 = (p123 - p012) * t + p012; - out[0] = p0; - out[1] = p01; - out[2] = p012; - out[3] = p0123; - out[4] = p0123; - out[5] = p123; - out[6] = p23; - out[7] = p3; - } - - function cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, out) { - var t; - var interval = 0.005; - var d = Infinity; - var prev; - var next; - var d1; - var d2; - _v0[0] = x; - _v0[1] = y; - - for (var _t = 0; _t < 1; _t += 0.05) { - _v1[0] = cubicAt(x0, x1, x2, x3, _t); - _v1[1] = cubicAt(y0, y1, y2, y3, _t); - d1 = distSquare(_v0, _v1); - - if (d1 < d) { - t = _t; - d = d1; - } - } - - d = Infinity; - - for (var i = 0; i < 32; i++) { - if (interval < EPSILON_NUMERIC) { - break; - } - - prev = t - interval; - next = t + interval; - _v1[0] = cubicAt(x0, x1, x2, x3, prev); - _v1[1] = cubicAt(y0, y1, y2, y3, prev); - d1 = distSquare(_v1, _v0); - - if (prev >= 0 && d1 < d) { - t = prev; - d = d1; - } else { - _v2[0] = cubicAt(x0, x1, x2, x3, next); - _v2[1] = cubicAt(y0, y1, y2, y3, next); - d2 = distSquare(_v2, _v0); - - if (next <= 1 && d2 < d) { - t = next; - d = d2; - } else { - interval *= 0.5; - } - } - } - - if (out) { - out[0] = cubicAt(x0, x1, x2, x3, t); - out[1] = cubicAt(y0, y1, y2, y3, t); - } - - return mathSqrt$3(d); - } - - function cubicLength(x0, y0, x1, y1, x2, y2, x3, y3, iteration) { - var px = x0; - var py = y0; - var d = 0; - var step = 1 / iteration; - - for (var i = 1; i <= iteration; i++) { - var t = i * step; - var x = cubicAt(x0, x1, x2, x3, t); - var y = cubicAt(y0, y1, y2, y3, t); - var dx = x - px; - var dy = y - py; - d += Math.sqrt(dx * dx + dy * dy); - px = x; - py = y; - } - - return d; - } - - function quadraticAt(p0, p1, p2, t) { - var onet = 1 - t; - return onet * (onet * p0 + 2 * t * p1) + t * t * p2; - } - - function quadraticDerivativeAt(p0, p1, p2, t) { - return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1)); - } - - function quadraticRootAt(p0, p1, p2, val, roots) { - var a = p0 - 2 * p1 + p2; - var b = 2 * (p1 - p0); - var c = p0 - val; - var n = 0; - - if (isAroundZero(a)) { - if (isNotAroundZero$1(b)) { - var t1 = -c / b; - - if (t1 >= 0 && t1 <= 1) { - roots[n++] = t1; - } - } - } else { - var disc = b * b - 4 * a * c; - - if (isAroundZero(disc)) { - var t1 = -b / (2 * a); - - if (t1 >= 0 && t1 <= 1) { - roots[n++] = t1; - } - } else if (disc > 0) { - var discSqrt = mathSqrt$3(disc); - var t1 = (-b + discSqrt) / (2 * a); - var t2 = (-b - discSqrt) / (2 * a); - - if (t1 >= 0 && t1 <= 1) { - roots[n++] = t1; - } - - if (t2 >= 0 && t2 <= 1) { - roots[n++] = t2; - } - } - } - - return n; - } - - function quadraticExtremum(p0, p1, p2) { - var divider = p0 + p2 - 2 * p1; - - if (divider === 0) { - return 0.5; - } else { - return (p0 - p1) / divider; - } - } - - function quadraticSubdivide(p0, p1, p2, t, out) { - var p01 = (p1 - p0) * t + p0; - var p12 = (p2 - p1) * t + p1; - var p012 = (p12 - p01) * t + p01; - out[0] = p0; - out[1] = p01; - out[2] = p012; - out[3] = p012; - out[4] = p12; - out[5] = p2; - } - - function quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, out) { - var t; - var interval = 0.005; - var d = Infinity; - _v0[0] = x; - _v0[1] = y; - - for (var _t = 0; _t < 1; _t += 0.05) { - _v1[0] = quadraticAt(x0, x1, x2, _t); - _v1[1] = quadraticAt(y0, y1, y2, _t); - var d1 = distSquare(_v0, _v1); - - if (d1 < d) { - t = _t; - d = d1; - } - } - - d = Infinity; - - for (var i = 0; i < 32; i++) { - if (interval < EPSILON_NUMERIC) { - break; - } - - var prev = t - interval; - var next = t + interval; - _v1[0] = quadraticAt(x0, x1, x2, prev); - _v1[1] = quadraticAt(y0, y1, y2, prev); - var d1 = distSquare(_v1, _v0); - - if (prev >= 0 && d1 < d) { - t = prev; - d = d1; - } else { - _v2[0] = quadraticAt(x0, x1, x2, next); - _v2[1] = quadraticAt(y0, y1, y2, next); - var d2 = distSquare(_v2, _v0); - - if (next <= 1 && d2 < d) { - t = next; - d = d2; - } else { - interval *= 0.5; - } - } - } - - if (out) { - out[0] = quadraticAt(x0, x1, x2, t); - out[1] = quadraticAt(y0, y1, y2, t); - } - - return mathSqrt$3(d); - } - - function quadraticLength(x0, y0, x1, y1, x2, y2, iteration) { - var px = x0; - var py = y0; - var d = 0; - var step = 1 / iteration; - - for (var i = 1; i <= iteration; i++) { - var t = i * step; - var x = quadraticAt(x0, x1, x2, t); - var y = quadraticAt(y0, y1, y2, t); - var dx = x - px; - var dy = y - py; - d += Math.sqrt(dx * dx + dy * dy); - px = x; - py = y; - } - - return d; - } - - var regexp = /cubic-bezier\(([0-9,\.e ]+)\)/; - - function createCubicEasingFunc(cubicEasingStr) { - var cubic = cubicEasingStr && regexp.exec(cubicEasingStr); - - if (cubic) { - var points = cubic[1].split(','); - var a_1 = +trim(points[0]); - var b_1 = +trim(points[1]); - var c_1 = +trim(points[2]); - var d_1 = +trim(points[3]); - - if (isNaN(a_1 + b_1 + c_1 + d_1)) { - return; - } - - var roots_1 = []; - return function (p) { - return p <= 0 ? 0 : p >= 1 ? 1 : cubicRootAt(0, a_1, c_1, 1, p, roots_1) && cubicAt(0, b_1, d_1, 1, roots_1[0]); - }; - } - } - - var Clip = function () { - function Clip(opts) { - this._inited = false; - this._startTime = 0; - this._pausedTime = 0; - this._paused = false; - this._life = opts.life || 1000; - this._delay = opts.delay || 0; - this.loop = opts.loop || false; - this.onframe = opts.onframe || noop; - this.ondestroy = opts.ondestroy || noop; - this.onrestart = opts.onrestart || noop; - opts.easing && this.setEasing(opts.easing); - } - - Clip.prototype.step = function (globalTime, deltaTime) { - if (!this._inited) { - this._startTime = globalTime + this._delay; - this._inited = true; - } - - if (this._paused) { - this._pausedTime += deltaTime; - return; - } - - var life = this._life; - var elapsedTime = globalTime - this._startTime - this._pausedTime; - var percent = elapsedTime / life; - - if (percent < 0) { - percent = 0; - } - - percent = Math.min(percent, 1); - var easingFunc = this.easingFunc; - var schedule = easingFunc ? easingFunc(percent) : percent; - this.onframe(schedule); - - if (percent === 1) { - if (this.loop) { - var remainder = elapsedTime % life; - this._startTime = globalTime - remainder; - this._pausedTime = 0; - this.onrestart(); - } else { - return true; - } - } - - return false; - }; - - Clip.prototype.pause = function () { - this._paused = true; - }; - - Clip.prototype.resume = function () { - this._paused = false; - }; - - Clip.prototype.setEasing = function (easing) { - this.easing = easing; - this.easingFunc = isFunction(easing) ? easing : easingFuncs[easing] || createCubicEasingFunc(easing); - }; - - return Clip; - }(); - - var Entry = function () { - function Entry(val) { - this.value = val; - } - - return Entry; - }(); - - var LinkedList = function () { - function LinkedList() { - this._len = 0; - } - - LinkedList.prototype.insert = function (val) { - var entry = new Entry(val); - this.insertEntry(entry); - return entry; - }; - - LinkedList.prototype.insertEntry = function (entry) { - if (!this.head) { - this.head = this.tail = entry; - } else { - this.tail.next = entry; - entry.prev = this.tail; - entry.next = null; - this.tail = entry; - } - - this._len++; - }; - - LinkedList.prototype.remove = function (entry) { - var prev = entry.prev; - var next = entry.next; - - if (prev) { - prev.next = next; - } else { - this.head = next; - } - - if (next) { - next.prev = prev; - } else { - this.tail = prev; - } - - entry.next = entry.prev = null; - this._len--; - }; - - LinkedList.prototype.len = function () { - return this._len; - }; - - LinkedList.prototype.clear = function () { - this.head = this.tail = null; - this._len = 0; - }; - - return LinkedList; - }(); - - var LRU = function () { - function LRU(maxSize) { - this._list = new LinkedList(); - this._maxSize = 10; - this._map = {}; - this._maxSize = maxSize; - } - - LRU.prototype.put = function (key, value) { - var list = this._list; - var map = this._map; - var removed = null; - - if (map[key] == null) { - var len = list.len(); - var entry = this._lastRemovedEntry; - - if (len >= this._maxSize && len > 0) { - var leastUsedEntry = list.head; - list.remove(leastUsedEntry); - delete map[leastUsedEntry.key]; - removed = leastUsedEntry.value; - this._lastRemovedEntry = leastUsedEntry; - } - - if (entry) { - entry.value = value; - } else { - entry = new Entry(value); - } - - entry.key = key; - list.insertEntry(entry); - map[key] = entry; - } - - return removed; - }; - - LRU.prototype.get = function (key) { - var entry = this._map[key]; - var list = this._list; - - if (entry != null) { - if (entry !== list.tail) { - list.remove(entry); - list.insertEntry(entry); - } - - return entry.value; - } - }; - - LRU.prototype.clear = function () { - this._list.clear(); - - this._map = {}; - }; - - LRU.prototype.len = function () { - return this._list.len(); - }; - - return LRU; - }(); - - var kCSSColorTable = { - 'transparent': [0, 0, 0, 0], - 'aliceblue': [240, 248, 255, 1], - 'antiquewhite': [250, 235, 215, 1], - 'aqua': [0, 255, 255, 1], - 'aquamarine': [127, 255, 212, 1], - 'azure': [240, 255, 255, 1], - 'beige': [245, 245, 220, 1], - 'bisque': [255, 228, 196, 1], - 'black': [0, 0, 0, 1], - 'blanchedalmond': [255, 235, 205, 1], - 'blue': [0, 0, 255, 1], - 'blueviolet': [138, 43, 226, 1], - 'brown': [165, 42, 42, 1], - 'burlywood': [222, 184, 135, 1], - 'cadetblue': [95, 158, 160, 1], - 'chartreuse': [127, 255, 0, 1], - 'chocolate': [210, 105, 30, 1], - 'coral': [255, 127, 80, 1], - 'cornflowerblue': [100, 149, 237, 1], - 'cornsilk': [255, 248, 220, 1], - 'crimson': [220, 20, 60, 1], - 'cyan': [0, 255, 255, 1], - 'darkblue': [0, 0, 139, 1], - 'darkcyan': [0, 139, 139, 1], - 'darkgoldenrod': [184, 134, 11, 1], - 'darkgray': [169, 169, 169, 1], - 'darkgreen': [0, 100, 0, 1], - 'darkgrey': [169, 169, 169, 1], - 'darkkhaki': [189, 183, 107, 1], - 'darkmagenta': [139, 0, 139, 1], - 'darkolivegreen': [85, 107, 47, 1], - 'darkorange': [255, 140, 0, 1], - 'darkorchid': [153, 50, 204, 1], - 'darkred': [139, 0, 0, 1], - 'darksalmon': [233, 150, 122, 1], - 'darkseagreen': [143, 188, 143, 1], - 'darkslateblue': [72, 61, 139, 1], - 'darkslategray': [47, 79, 79, 1], - 'darkslategrey': [47, 79, 79, 1], - 'darkturquoise': [0, 206, 209, 1], - 'darkviolet': [148, 0, 211, 1], - 'deeppink': [255, 20, 147, 1], - 'deepskyblue': [0, 191, 255, 1], - 'dimgray': [105, 105, 105, 1], - 'dimgrey': [105, 105, 105, 1], - 'dodgerblue': [30, 144, 255, 1], - 'firebrick': [178, 34, 34, 1], - 'floralwhite': [255, 250, 240, 1], - 'forestgreen': [34, 139, 34, 1], - 'fuchsia': [255, 0, 255, 1], - 'gainsboro': [220, 220, 220, 1], - 'ghostwhite': [248, 248, 255, 1], - 'gold': [255, 215, 0, 1], - 'goldenrod': [218, 165, 32, 1], - 'gray': [128, 128, 128, 1], - 'green': [0, 128, 0, 1], - 'greenyellow': [173, 255, 47, 1], - 'grey': [128, 128, 128, 1], - 'honeydew': [240, 255, 240, 1], - 'hotpink': [255, 105, 180, 1], - 'indianred': [205, 92, 92, 1], - 'indigo': [75, 0, 130, 1], - 'ivory': [255, 255, 240, 1], - 'khaki': [240, 230, 140, 1], - 'lavender': [230, 230, 250, 1], - 'lavenderblush': [255, 240, 245, 1], - 'lawngreen': [124, 252, 0, 1], - 'lemonchiffon': [255, 250, 205, 1], - 'lightblue': [173, 216, 230, 1], - 'lightcoral': [240, 128, 128, 1], - 'lightcyan': [224, 255, 255, 1], - 'lightgoldenrodyellow': [250, 250, 210, 1], - 'lightgray': [211, 211, 211, 1], - 'lightgreen': [144, 238, 144, 1], - 'lightgrey': [211, 211, 211, 1], - 'lightpink': [255, 182, 193, 1], - 'lightsalmon': [255, 160, 122, 1], - 'lightseagreen': [32, 178, 170, 1], - 'lightskyblue': [135, 206, 250, 1], - 'lightslategray': [119, 136, 153, 1], - 'lightslategrey': [119, 136, 153, 1], - 'lightsteelblue': [176, 196, 222, 1], - 'lightyellow': [255, 255, 224, 1], - 'lime': [0, 255, 0, 1], - 'limegreen': [50, 205, 50, 1], - 'linen': [250, 240, 230, 1], - 'magenta': [255, 0, 255, 1], - 'maroon': [128, 0, 0, 1], - 'mediumaquamarine': [102, 205, 170, 1], - 'mediumblue': [0, 0, 205, 1], - 'mediumorchid': [186, 85, 211, 1], - 'mediumpurple': [147, 112, 219, 1], - 'mediumseagreen': [60, 179, 113, 1], - 'mediumslateblue': [123, 104, 238, 1], - 'mediumspringgreen': [0, 250, 154, 1], - 'mediumturquoise': [72, 209, 204, 1], - 'mediumvioletred': [199, 21, 133, 1], - 'midnightblue': [25, 25, 112, 1], - 'mintcream': [245, 255, 250, 1], - 'mistyrose': [255, 228, 225, 1], - 'moccasin': [255, 228, 181, 1], - 'navajowhite': [255, 222, 173, 1], - 'navy': [0, 0, 128, 1], - 'oldlace': [253, 245, 230, 1], - 'olive': [128, 128, 0, 1], - 'olivedrab': [107, 142, 35, 1], - 'orange': [255, 165, 0, 1], - 'orangered': [255, 69, 0, 1], - 'orchid': [218, 112, 214, 1], - 'palegoldenrod': [238, 232, 170, 1], - 'palegreen': [152, 251, 152, 1], - 'paleturquoise': [175, 238, 238, 1], - 'palevioletred': [219, 112, 147, 1], - 'papayawhip': [255, 239, 213, 1], - 'peachpuff': [255, 218, 185, 1], - 'peru': [205, 133, 63, 1], - 'pink': [255, 192, 203, 1], - 'plum': [221, 160, 221, 1], - 'powderblue': [176, 224, 230, 1], - 'purple': [128, 0, 128, 1], - 'red': [255, 0, 0, 1], - 'rosybrown': [188, 143, 143, 1], - 'royalblue': [65, 105, 225, 1], - 'saddlebrown': [139, 69, 19, 1], - 'salmon': [250, 128, 114, 1], - 'sandybrown': [244, 164, 96, 1], - 'seagreen': [46, 139, 87, 1], - 'seashell': [255, 245, 238, 1], - 'sienna': [160, 82, 45, 1], - 'silver': [192, 192, 192, 1], - 'skyblue': [135, 206, 235, 1], - 'slateblue': [106, 90, 205, 1], - 'slategray': [112, 128, 144, 1], - 'slategrey': [112, 128, 144, 1], - 'snow': [255, 250, 250, 1], - 'springgreen': [0, 255, 127, 1], - 'steelblue': [70, 130, 180, 1], - 'tan': [210, 180, 140, 1], - 'teal': [0, 128, 128, 1], - 'thistle': [216, 191, 216, 1], - 'tomato': [255, 99, 71, 1], - 'turquoise': [64, 224, 208, 1], - 'violet': [238, 130, 238, 1], - 'wheat': [245, 222, 179, 1], - 'white': [255, 255, 255, 1], - 'whitesmoke': [245, 245, 245, 1], - 'yellow': [255, 255, 0, 1], - 'yellowgreen': [154, 205, 50, 1] - }; - - function clampCssByte(i) { - i = Math.round(i); - return i < 0 ? 0 : i > 255 ? 255 : i; - } - - function clampCssAngle(i) { - i = Math.round(i); - return i < 0 ? 0 : i > 360 ? 360 : i; - } - - function clampCssFloat(f) { - return f < 0 ? 0 : f > 1 ? 1 : f; - } - - function parseCssInt(val) { - var str = val; - - if (str.length && str.charAt(str.length - 1) === '%') { - return clampCssByte(parseFloat(str) / 100 * 255); - } - - return clampCssByte(parseInt(str, 10)); - } - - function parseCssFloat(val) { - var str = val; - - if (str.length && str.charAt(str.length - 1) === '%') { - return clampCssFloat(parseFloat(str) / 100); - } - - return clampCssFloat(parseFloat(str)); - } - - function cssHueToRgb(m1, m2, h) { - if (h < 0) { - h += 1; - } else if (h > 1) { - h -= 1; - } - - if (h * 6 < 1) { - return m1 + (m2 - m1) * h * 6; - } - - if (h * 2 < 1) { - return m2; - } - - if (h * 3 < 2) { - return m1 + (m2 - m1) * (2 / 3 - h) * 6; - } - - return m1; - } - - function lerpNumber(a, b, p) { - return a + (b - a) * p; - } - - function setRgba(out, r, g, b, a) { - out[0] = r; - out[1] = g; - out[2] = b; - out[3] = a; - return out; - } - - function copyRgba(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; - } - - var colorCache = new LRU(20); - var lastRemovedArr = null; - - function putToCache(colorStr, rgbaArr) { - if (lastRemovedArr) { - copyRgba(lastRemovedArr, rgbaArr); - } - - lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || rgbaArr.slice()); - } - - function parse(colorStr, rgbaArr) { - if (!colorStr) { - return; - } - - rgbaArr = rgbaArr || []; - var cached = colorCache.get(colorStr); - - if (cached) { - return copyRgba(rgbaArr, cached); - } - - colorStr = colorStr + ''; - var str = colorStr.replace(/ /g, '').toLowerCase(); - - if (str in kCSSColorTable) { - copyRgba(rgbaArr, kCSSColorTable[str]); - putToCache(colorStr, rgbaArr); - return rgbaArr; - } - - var strLen = str.length; - - if (str.charAt(0) === '#') { - if (strLen === 4 || strLen === 5) { - var iv = parseInt(str.slice(1, 4), 16); - - if (!(iv >= 0 && iv <= 0xfff)) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - - setRgba(rgbaArr, (iv & 0xf00) >> 4 | (iv & 0xf00) >> 8, iv & 0xf0 | (iv & 0xf0) >> 4, iv & 0xf | (iv & 0xf) << 4, strLen === 5 ? parseInt(str.slice(4), 16) / 0xf : 1); - putToCache(colorStr, rgbaArr); - return rgbaArr; - } else if (strLen === 7 || strLen === 9) { - var iv = parseInt(str.slice(1, 7), 16); - - if (!(iv >= 0 && iv <= 0xffffff)) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - - setRgba(rgbaArr, (iv & 0xff0000) >> 16, (iv & 0xff00) >> 8, iv & 0xff, strLen === 9 ? parseInt(str.slice(7), 16) / 0xff : 1); - putToCache(colorStr, rgbaArr); - return rgbaArr; - } - - return; - } - - var op = str.indexOf('('); - var ep = str.indexOf(')'); - - if (op !== -1 && ep + 1 === strLen) { - var fname = str.substr(0, op); - var params = str.substr(op + 1, ep - (op + 1)).split(','); - var alpha = 1; - - switch (fname) { - case 'rgba': - if (params.length !== 4) { - return params.length === 3 ? setRgba(rgbaArr, +params[0], +params[1], +params[2], 1) : setRgba(rgbaArr, 0, 0, 0, 1); - } - - alpha = parseCssFloat(params.pop()); - - case 'rgb': - if (params.length >= 3) { - setRgba(rgbaArr, parseCssInt(params[0]), parseCssInt(params[1]), parseCssInt(params[2]), params.length === 3 ? alpha : parseCssFloat(params[3])); - putToCache(colorStr, rgbaArr); - return rgbaArr; - } else { - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - - case 'hsla': - if (params.length !== 4) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - - params[3] = parseCssFloat(params[3]); - hsla2rgba(params, rgbaArr); - putToCache(colorStr, rgbaArr); - return rgbaArr; - - case 'hsl': - if (params.length !== 3) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - - hsla2rgba(params, rgbaArr); - putToCache(colorStr, rgbaArr); - return rgbaArr; - - default: - return; - } - } - - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - - function hsla2rgba(hsla, rgba) { - var h = (parseFloat(hsla[0]) % 360 + 360) % 360 / 360; - var s = parseCssFloat(hsla[1]); - var l = parseCssFloat(hsla[2]); - var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; - var m1 = l * 2 - m2; - rgba = rgba || []; - setRgba(rgba, clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255), clampCssByte(cssHueToRgb(m1, m2, h) * 255), clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255), 1); - - if (hsla.length === 4) { - rgba[3] = hsla[3]; - } - - return rgba; - } - - function rgba2hsla(rgba) { - if (!rgba) { - return; - } - - var R = rgba[0] / 255; - var G = rgba[1] / 255; - var B = rgba[2] / 255; - var vMin = Math.min(R, G, B); - var vMax = Math.max(R, G, B); - var delta = vMax - vMin; - var L = (vMax + vMin) / 2; - var H; - var S; - - if (delta === 0) { - H = 0; - S = 0; - } else { - if (L < 0.5) { - S = delta / (vMax + vMin); - } else { - S = delta / (2 - vMax - vMin); - } - - var deltaR = ((vMax - R) / 6 + delta / 2) / delta; - var deltaG = ((vMax - G) / 6 + delta / 2) / delta; - var deltaB = ((vMax - B) / 6 + delta / 2) / delta; - - if (R === vMax) { - H = deltaB - deltaG; - } else if (G === vMax) { - H = 1 / 3 + deltaR - deltaB; - } else if (B === vMax) { - H = 2 / 3 + deltaG - deltaR; - } - - if (H < 0) { - H += 1; - } - - if (H > 1) { - H -= 1; - } - } - - var hsla = [H * 360, S, L]; - - if (rgba[3] != null) { - hsla.push(rgba[3]); - } - - return hsla; - } - - function lift(color, level) { - var colorArr = parse(color); - - if (colorArr) { - for (var i = 0; i < 3; i++) { - if (level < 0) { - colorArr[i] = colorArr[i] * (1 - level) | 0; - } else { - colorArr[i] = (255 - colorArr[i]) * level + colorArr[i] | 0; - } - - if (colorArr[i] > 255) { - colorArr[i] = 255; - } else if (colorArr[i] < 0) { - colorArr[i] = 0; - } - } - - return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb'); - } - } - - function toHex(color) { - var colorArr = parse(color); - - if (colorArr) { - return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + +colorArr[2]).toString(16).slice(1); - } - } - - function fastLerp(normalizedValue, colors, out) { - if (!(colors && colors.length) || !(normalizedValue >= 0 && normalizedValue <= 1)) { - return; - } - - out = out || []; - var value = normalizedValue * (colors.length - 1); - var leftIndex = Math.floor(value); - var rightIndex = Math.ceil(value); - var leftColor = colors[leftIndex]; - var rightColor = colors[rightIndex]; - var dv = value - leftIndex; - out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)); - out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)); - out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)); - out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv)); - return out; - } - - var fastMapToColor = fastLerp; - - function lerp(normalizedValue, colors, fullOutput) { - if (!(colors && colors.length) || !(normalizedValue >= 0 && normalizedValue <= 1)) { - return; - } - - var value = normalizedValue * (colors.length - 1); - var leftIndex = Math.floor(value); - var rightIndex = Math.ceil(value); - var leftColor = parse(colors[leftIndex]); - var rightColor = parse(colors[rightIndex]); - var dv = value - leftIndex; - var color = stringify([clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)), clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)), clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)), clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv))], 'rgba'); - return fullOutput ? { - color: color, - leftIndex: leftIndex, - rightIndex: rightIndex, - value: value - } : color; - } - - var mapToColor = lerp; - - function modifyHSL(color, h, s, l) { - var colorArr = parse(color); - - if (color) { - colorArr = rgba2hsla(colorArr); - h != null && (colorArr[0] = clampCssAngle(isFunction(h) ? h(colorArr[0]) : h)); - s != null && (colorArr[1] = parseCssFloat(isFunction(s) ? s(colorArr[1]) : s)); - l != null && (colorArr[2] = parseCssFloat(isFunction(l) ? l(colorArr[2]) : l)); - return stringify(hsla2rgba(colorArr), 'rgba'); - } - } - - function modifyAlpha(color, alpha) { - var colorArr = parse(color); - - if (colorArr && alpha != null) { - colorArr[3] = clampCssFloat(alpha); - return stringify(colorArr, 'rgba'); - } - } - - function stringify(arrColor, type) { - if (!arrColor || !arrColor.length) { - return; - } - - var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2]; - - if (type === 'rgba' || type === 'hsva' || type === 'hsla') { - colorStr += ',' + arrColor[3]; - } - - return type + '(' + colorStr + ')'; - } - - function lum(color, backgroundLum) { - var arr = parse(color); - return arr ? (0.299 * arr[0] + 0.587 * arr[1] + 0.114 * arr[2]) * arr[3] / 255 + (1 - arr[3]) * backgroundLum : 0; - } - - function random() { - return stringify([Math.round(Math.random() * 255), Math.round(Math.random() * 255), Math.round(Math.random() * 255)], 'rgb'); - } - - var liftedColorCache = new LRU(100); - - function liftColor(color) { - if (isString(color)) { - var liftedColor = liftedColorCache.get(color); - - if (!liftedColor) { - liftedColor = lift(color, -0.1); - liftedColorCache.put(color, liftedColor); - } - - return liftedColor; - } else if (isGradientObject(color)) { - var ret = extend({}, color); - ret.colorStops = map$1(color.colorStops, function (stop) { - return { - offset: stop.offset, - color: lift(stop.color, -0.1) - }; - }); - return ret; - } - - return color; - } - - var color$2 = /*#__PURE__*/Object.freeze({ - __proto__: null, - fastLerp: fastLerp, - fastMapToColor: fastMapToColor, - lerp: lerp, - lift: lift, - liftColor: liftColor, - lum: lum, - mapToColor: mapToColor, - modifyAlpha: modifyAlpha, - modifyHSL: modifyHSL, - parse: parse, - parseCssFloat: parseCssFloat, - parseCssInt: parseCssInt, - random: random, - stringify: stringify, - toHex: toHex - }); - - function isLinearGradient(val) { - return val.type === 'linear'; - } - - function isRadialGradient(val) { - return val.type === 'radial'; - } - - (function () { - if (env.hasGlobalWindow && isFunction(window.btoa)) { - return function (str) { - return window.btoa(unescape(encodeURIComponent(str))); - }; - } - - if (typeof Buffer !== 'undefined') { - return function (str) { - return Buffer.from(str).toString('base64'); - }; - } - - return function (str) { - { - logError('Base64 isn\'t natively supported in the current environment.'); - } - return null; - }; - })(); - - var arraySlice = Array.prototype.slice; - - function interpolateNumber$1(p0, p1, percent) { - return (p1 - p0) * percent + p0; - } - - function interpolate1DArray(out, p0, p1, percent) { - var len = p0.length; - - for (var i = 0; i < len; i++) { - out[i] = interpolateNumber$1(p0[i], p1[i], percent); - } - - return out; - } - - function interpolate2DArray(out, p0, p1, percent) { - var len = p0.length; - var len2 = len && p0[0].length; - - for (var i = 0; i < len; i++) { - if (!out[i]) { - out[i] = []; - } - - for (var j = 0; j < len2; j++) { - out[i][j] = interpolateNumber$1(p0[i][j], p1[i][j], percent); - } - } - - return out; - } - - function add1DArray(out, p0, p1, sign) { - var len = p0.length; - - for (var i = 0; i < len; i++) { - out[i] = p0[i] + p1[i] * sign; - } - - return out; - } - - function add2DArray(out, p0, p1, sign) { - var len = p0.length; - var len2 = len && p0[0].length; - - for (var i = 0; i < len; i++) { - if (!out[i]) { - out[i] = []; - } - - for (var j = 0; j < len2; j++) { - out[i][j] = p0[i][j] + p1[i][j] * sign; - } - } - - return out; - } - - function fillColorStops(val0, val1) { - var len0 = val0.length; - var len1 = val1.length; - var shorterArr = len0 > len1 ? val1 : val0; - var shorterLen = Math.min(len0, len1); - var last = shorterArr[shorterLen - 1] || { - color: [0, 0, 0, 0], - offset: 0 - }; - - for (var i = shorterLen; i < Math.max(len0, len1); i++) { - shorterArr.push({ - offset: last.offset, - color: last.color.slice() - }); - } - } - - function fillArray(val0, val1, arrDim) { - var arr0 = val0; - var arr1 = val1; - - if (!arr0.push || !arr1.push) { - return; - } - - var arr0Len = arr0.length; - var arr1Len = arr1.length; - - if (arr0Len !== arr1Len) { - var isPreviousLarger = arr0Len > arr1Len; - - if (isPreviousLarger) { - arr0.length = arr1Len; - } else { - for (var i = arr0Len; i < arr1Len; i++) { - arr0.push(arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i])); - } - } - } - - var len2 = arr0[0] && arr0[0].length; - - for (var i = 0; i < arr0.length; i++) { - if (arrDim === 1) { - if (isNaN(arr0[i])) { - arr0[i] = arr1[i]; - } - } else { - for (var j = 0; j < len2; j++) { - if (isNaN(arr0[i][j])) { - arr0[i][j] = arr1[i][j]; - } - } - } - } - } - - function cloneValue(value) { - if (isArrayLike(value)) { - var len = value.length; - - if (isArrayLike(value[0])) { - var ret = []; - - for (var i = 0; i < len; i++) { - ret.push(arraySlice.call(value[i])); - } - - return ret; - } - - return arraySlice.call(value); - } - - return value; - } - - function rgba2String(rgba) { - rgba[0] = Math.floor(rgba[0]) || 0; - rgba[1] = Math.floor(rgba[1]) || 0; - rgba[2] = Math.floor(rgba[2]) || 0; - rgba[3] = rgba[3] == null ? 1 : rgba[3]; - return 'rgba(' + rgba.join(',') + ')'; - } - - function guessArrayDim(value) { - return isArrayLike(value && value[0]) ? 2 : 1; - } - - var VALUE_TYPE_NUMBER = 0; - var VALUE_TYPE_1D_ARRAY = 1; - var VALUE_TYPE_2D_ARRAY = 2; - var VALUE_TYPE_COLOR = 3; - var VALUE_TYPE_LINEAR_GRADIENT = 4; - var VALUE_TYPE_RADIAL_GRADIENT = 5; - var VALUE_TYPE_UNKOWN = 6; - - function isGradientValueType(valType) { - return valType === VALUE_TYPE_LINEAR_GRADIENT || valType === VALUE_TYPE_RADIAL_GRADIENT; - } - - function isArrayValueType(valType) { - return valType === VALUE_TYPE_1D_ARRAY || valType === VALUE_TYPE_2D_ARRAY; - } - - var tmpRgba = [0, 0, 0, 0]; - - var Track = function () { - function Track(propName) { - this.keyframes = []; - this.discrete = false; - this._invalid = false; - this._needsSort = false; - this._lastFr = 0; - this._lastFrP = 0; - this.propName = propName; - } - - Track.prototype.isFinished = function () { - return this._finished; - }; - - Track.prototype.setFinished = function () { - this._finished = true; - - if (this._additiveTrack) { - this._additiveTrack.setFinished(); - } - }; - - Track.prototype.needsAnimate = function () { - return this.keyframes.length >= 1; - }; - - Track.prototype.getAdditiveTrack = function () { - return this._additiveTrack; - }; - - Track.prototype.addKeyframe = function (time, rawValue, easing) { - this._needsSort = true; - var keyframes = this.keyframes; - var len = keyframes.length; - var discrete = false; - var valType = VALUE_TYPE_UNKOWN; - var value = rawValue; - - if (isArrayLike(rawValue)) { - var arrayDim = guessArrayDim(rawValue); - valType = arrayDim; - - if (arrayDim === 1 && !isNumber(rawValue[0]) || arrayDim === 2 && !isNumber(rawValue[0][0])) { - discrete = true; - } - } else { - if (isNumber(rawValue) && !eqNaN(rawValue)) { - valType = VALUE_TYPE_NUMBER; - } else if (isString(rawValue)) { - if (!isNaN(+rawValue)) { - valType = VALUE_TYPE_NUMBER; - } else { - var colorArray = parse(rawValue); - - if (colorArray) { - value = colorArray; - valType = VALUE_TYPE_COLOR; - } - } - } else if (isGradientObject(rawValue)) { - var parsedGradient = extend({}, value); - parsedGradient.colorStops = map$1(rawValue.colorStops, function (colorStop) { - return { - offset: colorStop.offset, - color: parse(colorStop.color) - }; - }); - - if (isLinearGradient(rawValue)) { - valType = VALUE_TYPE_LINEAR_GRADIENT; - } else if (isRadialGradient(rawValue)) { - valType = VALUE_TYPE_RADIAL_GRADIENT; - } - - value = parsedGradient; - } - } - - if (len === 0) { - this.valType = valType; - } else if (valType !== this.valType || valType === VALUE_TYPE_UNKOWN) { - discrete = true; - } - - this.discrete = this.discrete || discrete; - var kf = { - time: time, - value: value, - rawValue: rawValue, - percent: 0 - }; - - if (easing) { - kf.easing = easing; - kf.easingFunc = isFunction(easing) ? easing : easingFuncs[easing] || createCubicEasingFunc(easing); - } - - keyframes.push(kf); - return kf; - }; - - Track.prototype.prepare = function (maxTime, additiveTrack) { - var kfs = this.keyframes; - - if (this._needsSort) { - kfs.sort(function (a, b) { - return a.time - b.time; - }); - } - - var valType = this.valType; - var kfsLen = kfs.length; - var lastKf = kfs[kfsLen - 1]; - var isDiscrete = this.discrete; - var isArr = isArrayValueType(valType); - var isGradient = isGradientValueType(valType); - - for (var i = 0; i < kfsLen; i++) { - var kf = kfs[i]; - var value = kf.value; - var lastValue = lastKf.value; - kf.percent = kf.time / maxTime; - - if (!isDiscrete) { - if (isArr && i !== kfsLen - 1) { - fillArray(value, lastValue, valType); - } else if (isGradient) { - fillColorStops(value.colorStops, lastValue.colorStops); - } - } - } - - if (!isDiscrete && valType !== VALUE_TYPE_RADIAL_GRADIENT && additiveTrack && this.needsAnimate() && additiveTrack.needsAnimate() && valType === additiveTrack.valType && !additiveTrack._finished) { - this._additiveTrack = additiveTrack; - var startValue = kfs[0].value; - - for (var i = 0; i < kfsLen; i++) { - if (valType === VALUE_TYPE_NUMBER) { - kfs[i].additiveValue = kfs[i].value - startValue; - } else if (valType === VALUE_TYPE_COLOR) { - kfs[i].additiveValue = add1DArray([], kfs[i].value, startValue, -1); - } else if (isArrayValueType(valType)) { - kfs[i].additiveValue = valType === VALUE_TYPE_1D_ARRAY ? add1DArray([], kfs[i].value, startValue, -1) : add2DArray([], kfs[i].value, startValue, -1); - } - } - } - }; - - Track.prototype.step = function (target, percent) { - if (this._finished) { - return; - } - - if (this._additiveTrack && this._additiveTrack._finished) { - this._additiveTrack = null; - } - - var isAdditive = this._additiveTrack != null; - var valueKey = isAdditive ? 'additiveValue' : 'value'; - var valType = this.valType; - var keyframes = this.keyframes; - var kfsNum = keyframes.length; - var propName = this.propName; - var isValueColor = valType === VALUE_TYPE_COLOR; - var frameIdx; - var lastFrame = this._lastFr; - var mathMin = Math.min; - var frame; - var nextFrame; - - if (kfsNum === 1) { - frame = nextFrame = keyframes[0]; - } else { - if (percent < 0) { - frameIdx = 0; - } else if (percent < this._lastFrP) { - var start = mathMin(lastFrame + 1, kfsNum - 1); - - for (frameIdx = start; frameIdx >= 0; frameIdx--) { - if (keyframes[frameIdx].percent <= percent) { - break; - } - } - - frameIdx = mathMin(frameIdx, kfsNum - 2); - } else { - for (frameIdx = lastFrame; frameIdx < kfsNum; frameIdx++) { - if (keyframes[frameIdx].percent > percent) { - break; - } - } - - frameIdx = mathMin(frameIdx - 1, kfsNum - 2); - } - - nextFrame = keyframes[frameIdx + 1]; - frame = keyframes[frameIdx]; - } - - if (!(frame && nextFrame)) { - return; - } - - this._lastFr = frameIdx; - this._lastFrP = percent; - var interval = nextFrame.percent - frame.percent; - var w = interval === 0 ? 1 : mathMin((percent - frame.percent) / interval, 1); - - if (nextFrame.easingFunc) { - w = nextFrame.easingFunc(w); - } - - var targetArr = isAdditive ? this._additiveValue : isValueColor ? tmpRgba : target[propName]; - - if ((isArrayValueType(valType) || isValueColor) && !targetArr) { - targetArr = this._additiveValue = []; - } - - if (this.discrete) { - target[propName] = w < 1 ? frame.rawValue : nextFrame.rawValue; - } else if (isArrayValueType(valType)) { - valType === VALUE_TYPE_1D_ARRAY ? interpolate1DArray(targetArr, frame[valueKey], nextFrame[valueKey], w) : interpolate2DArray(targetArr, frame[valueKey], nextFrame[valueKey], w); - } else if (isGradientValueType(valType)) { - var val = frame[valueKey]; - var nextVal_1 = nextFrame[valueKey]; - var isLinearGradient_1 = valType === VALUE_TYPE_LINEAR_GRADIENT; - target[propName] = { - type: isLinearGradient_1 ? 'linear' : 'radial', - x: interpolateNumber$1(val.x, nextVal_1.x, w), - y: interpolateNumber$1(val.y, nextVal_1.y, w), - colorStops: map$1(val.colorStops, function (colorStop, idx) { - var nextColorStop = nextVal_1.colorStops[idx]; - return { - offset: interpolateNumber$1(colorStop.offset, nextColorStop.offset, w), - color: rgba2String(interpolate1DArray([], colorStop.color, nextColorStop.color, w)) - }; - }), - global: nextVal_1.global - }; - - if (isLinearGradient_1) { - target[propName].x2 = interpolateNumber$1(val.x2, nextVal_1.x2, w); - target[propName].y2 = interpolateNumber$1(val.y2, nextVal_1.y2, w); - } else { - target[propName].r = interpolateNumber$1(val.r, nextVal_1.r, w); - } - } else if (isValueColor) { - interpolate1DArray(targetArr, frame[valueKey], nextFrame[valueKey], w); - - if (!isAdditive) { - target[propName] = rgba2String(targetArr); - } - } else { - var value = interpolateNumber$1(frame[valueKey], nextFrame[valueKey], w); - - if (isAdditive) { - this._additiveValue = value; - } else { - target[propName] = value; - } - } - - if (isAdditive) { - this._addToTarget(target); - } - }; - - Track.prototype._addToTarget = function (target) { - var valType = this.valType; - var propName = this.propName; - var additiveValue = this._additiveValue; - - if (valType === VALUE_TYPE_NUMBER) { - target[propName] = target[propName] + additiveValue; - } else if (valType === VALUE_TYPE_COLOR) { - parse(target[propName], tmpRgba); - add1DArray(tmpRgba, tmpRgba, additiveValue, 1); - target[propName] = rgba2String(tmpRgba); - } else if (valType === VALUE_TYPE_1D_ARRAY) { - add1DArray(target[propName], target[propName], additiveValue, 1); - } else if (valType === VALUE_TYPE_2D_ARRAY) { - add2DArray(target[propName], target[propName], additiveValue, 1); - } - }; - - return Track; - }(); - - var Animator = function () { - function Animator(target, loop, allowDiscreteAnimation, additiveTo) { - this._tracks = {}; - this._trackKeys = []; - this._maxTime = 0; - this._started = 0; - this._clip = null; - this._target = target; - this._loop = loop; - - if (loop && additiveTo) { - logError('Can\' use additive animation on looped animation.'); - return; - } - - this._additiveAnimators = additiveTo; - this._allowDiscrete = allowDiscreteAnimation; - } - - Animator.prototype.getMaxTime = function () { - return this._maxTime; - }; - - Animator.prototype.getDelay = function () { - return this._delay; - }; - - Animator.prototype.getLoop = function () { - return this._loop; - }; - - Animator.prototype.getTarget = function () { - return this._target; - }; - - Animator.prototype.changeTarget = function (target) { - this._target = target; - }; - - Animator.prototype.when = function (time, props, easing) { - return this.whenWithKeys(time, props, keys(props), easing); - }; - - Animator.prototype.whenWithKeys = function (time, props, propNames, easing) { - var tracks = this._tracks; - - for (var i = 0; i < propNames.length; i++) { - var propName = propNames[i]; - var track = tracks[propName]; - - if (!track) { - track = tracks[propName] = new Track(propName); - var initialValue = void 0; - - var additiveTrack = this._getAdditiveTrack(propName); - - if (additiveTrack) { - var addtiveTrackKfs = additiveTrack.keyframes; - var lastFinalKf = addtiveTrackKfs[addtiveTrackKfs.length - 1]; - initialValue = lastFinalKf && lastFinalKf.value; - - if (additiveTrack.valType === VALUE_TYPE_COLOR && initialValue) { - initialValue = rgba2String(initialValue); - } - } else { - initialValue = this._target[propName]; - } - - if (initialValue == null) { - continue; - } - - if (time > 0) { - track.addKeyframe(0, cloneValue(initialValue), easing); - } - - this._trackKeys.push(propName); - } - - track.addKeyframe(time, cloneValue(props[propName]), easing); - } - - this._maxTime = Math.max(this._maxTime, time); - return this; - }; - - Animator.prototype.pause = function () { - this._clip.pause(); - - this._paused = true; - }; - - Animator.prototype.resume = function () { - this._clip.resume(); - - this._paused = false; - }; - - Animator.prototype.isPaused = function () { - return !!this._paused; - }; - - Animator.prototype.duration = function (duration) { - this._maxTime = duration; - this._force = true; - return this; - }; - - Animator.prototype._doneCallback = function () { - this._setTracksFinished(); - - this._clip = null; - var doneList = this._doneCbs; - - if (doneList) { - var len = doneList.length; - - for (var i = 0; i < len; i++) { - doneList[i].call(this); - } - } - }; - - Animator.prototype._abortedCallback = function () { - this._setTracksFinished(); - - var animation = this.animation; - var abortedList = this._abortedCbs; - - if (animation) { - animation.removeClip(this._clip); - } - - this._clip = null; - - if (abortedList) { - for (var i = 0; i < abortedList.length; i++) { - abortedList[i].call(this); - } - } - }; - - Animator.prototype._setTracksFinished = function () { - var tracks = this._tracks; - var tracksKeys = this._trackKeys; - - for (var i = 0; i < tracksKeys.length; i++) { - tracks[tracksKeys[i]].setFinished(); - } - }; - - Animator.prototype._getAdditiveTrack = function (trackName) { - var additiveTrack; - var additiveAnimators = this._additiveAnimators; - - if (additiveAnimators) { - for (var i = 0; i < additiveAnimators.length; i++) { - var track = additiveAnimators[i].getTrack(trackName); - - if (track) { - additiveTrack = track; - } - } - } - - return additiveTrack; - }; - - Animator.prototype.start = function (easing) { - if (this._started > 0) { - return; - } - - this._started = 1; - var self = this; - var tracks = []; - var maxTime = this._maxTime || 0; - - for (var i = 0; i < this._trackKeys.length; i++) { - var propName = this._trackKeys[i]; - var track = this._tracks[propName]; - - var additiveTrack = this._getAdditiveTrack(propName); - - var kfs = track.keyframes; - var kfsNum = kfs.length; - track.prepare(maxTime, additiveTrack); - - if (track.needsAnimate()) { - if (!this._allowDiscrete && track.discrete) { - var lastKf = kfs[kfsNum - 1]; - - if (lastKf) { - self._target[track.propName] = lastKf.rawValue; - } - - track.setFinished(); - } else { - tracks.push(track); - } - } - } - - if (tracks.length || this._force) { - var clip = new Clip({ - life: maxTime, - loop: this._loop, - delay: this._delay || 0, - onframe: function (percent) { - self._started = 2; - var additiveAnimators = self._additiveAnimators; - - if (additiveAnimators) { - var stillHasAdditiveAnimator = false; - - for (var i = 0; i < additiveAnimators.length; i++) { - if (additiveAnimators[i]._clip) { - stillHasAdditiveAnimator = true; - break; - } - } - - if (!stillHasAdditiveAnimator) { - self._additiveAnimators = null; - } - } - - for (var i = 0; i < tracks.length; i++) { - tracks[i].step(self._target, percent); - } - - var onframeList = self._onframeCbs; - - if (onframeList) { - for (var i = 0; i < onframeList.length; i++) { - onframeList[i](self._target, percent); - } - } - }, - ondestroy: function () { - self._doneCallback(); - } - }); - this._clip = clip; - - if (this.animation) { - this.animation.addClip(clip); - } - - if (easing) { - clip.setEasing(easing); - } - } else { - this._doneCallback(); - } - - return this; - }; - - Animator.prototype.stop = function (forwardToLast) { - if (!this._clip) { - return; - } - - var clip = this._clip; - - if (forwardToLast) { - clip.onframe(1); - } - - this._abortedCallback(); - }; - - Animator.prototype.delay = function (time) { - this._delay = time; - return this; - }; - - Animator.prototype.during = function (cb) { - if (cb) { - if (!this._onframeCbs) { - this._onframeCbs = []; - } - - this._onframeCbs.push(cb); - } - - return this; - }; - - Animator.prototype.done = function (cb) { - if (cb) { - if (!this._doneCbs) { - this._doneCbs = []; - } - - this._doneCbs.push(cb); - } - - return this; - }; - - Animator.prototype.aborted = function (cb) { - if (cb) { - if (!this._abortedCbs) { - this._abortedCbs = []; - } - - this._abortedCbs.push(cb); - } - - return this; - }; - - Animator.prototype.getClip = function () { - return this._clip; - }; - - Animator.prototype.getTrack = function (propName) { - return this._tracks[propName]; - }; - - Animator.prototype.getTracks = function () { - var _this = this; - - return map$1(this._trackKeys, function (key) { - return _this._tracks[key]; - }); - }; - - Animator.prototype.stopTracks = function (propNames, forwardToLast) { - if (!propNames.length || !this._clip) { - return true; - } - - var tracks = this._tracks; - var tracksKeys = this._trackKeys; - - for (var i = 0; i < propNames.length; i++) { - var track = tracks[propNames[i]]; - - if (track && !track.isFinished()) { - if (forwardToLast) { - track.step(this._target, 1); - } else if (this._started === 1) { - track.step(this._target, 0); - } - - track.setFinished(); - } - } - - var allAborted = true; - - for (var i = 0; i < tracksKeys.length; i++) { - if (!tracks[tracksKeys[i]].isFinished()) { - allAborted = false; - break; - } - } - - if (allAborted) { - this._abortedCallback(); - } - - return allAborted; - }; - - Animator.prototype.saveTo = function (target, trackKeys, firstOrLast) { - if (!target) { - return; - } - - trackKeys = trackKeys || this._trackKeys; - - for (var i = 0; i < trackKeys.length; i++) { - var propName = trackKeys[i]; - var track = this._tracks[propName]; - - if (!track || track.isFinished()) { - continue; - } - - var kfs = track.keyframes; - var kf = kfs[firstOrLast ? 0 : kfs.length - 1]; - - if (kf) { - target[propName] = cloneValue(kf.rawValue); - } - } - }; - - Animator.prototype.__changeFinalValue = function (finalProps, trackKeys) { - trackKeys = trackKeys || keys(finalProps); - - for (var i = 0; i < trackKeys.length; i++) { - var propName = trackKeys[i]; - var track = this._tracks[propName]; - - if (!track) { - continue; - } - - var kfs = track.keyframes; - - if (kfs.length > 1) { - var lastKf = kfs.pop(); - track.addKeyframe(lastKf.time, finalProps[propName]); - track.prepare(this._maxTime, track.getAdditiveTrack()); - } - } - }; - - return Animator; - }(); - - function getTime() { - return new Date().getTime(); - } - - var Animation = function (_super) { - __extends(Animation, _super); - - function Animation(opts) { - var _this = _super.call(this) || this; - - _this._running = false; - _this._time = 0; - _this._pausedTime = 0; - _this._pauseStart = 0; - _this._paused = false; - opts = opts || {}; - _this.stage = opts.stage || {}; - return _this; - } - - Animation.prototype.addClip = function (clip) { - if (clip.animation) { - this.removeClip(clip); - } - - if (!this._head) { - this._head = this._tail = clip; - } else { - this._tail.next = clip; - clip.prev = this._tail; - clip.next = null; - this._tail = clip; - } - - clip.animation = this; - }; - - Animation.prototype.addAnimator = function (animator) { - animator.animation = this; - var clip = animator.getClip(); - - if (clip) { - this.addClip(clip); - } - }; - - Animation.prototype.removeClip = function (clip) { - if (!clip.animation) { - return; - } - - var prev = clip.prev; - var next = clip.next; - - if (prev) { - prev.next = next; - } else { - this._head = next; - } - - if (next) { - next.prev = prev; - } else { - this._tail = prev; - } - - clip.next = clip.prev = clip.animation = null; - }; - - Animation.prototype.removeAnimator = function (animator) { - var clip = animator.getClip(); - - if (clip) { - this.removeClip(clip); - } - - animator.animation = null; - }; - - Animation.prototype.update = function (notTriggerFrameAndStageUpdate) { - var time = getTime() - this._pausedTime; - - var delta = time - this._time; - var clip = this._head; - - while (clip) { - var nextClip = clip.next; - var finished = clip.step(time, delta); - - if (finished) { - clip.ondestroy(); - this.removeClip(clip); - clip = nextClip; - } else { - clip = nextClip; - } - } - - this._time = time; - - if (!notTriggerFrameAndStageUpdate) { - this.trigger('frame', delta); - this.stage.update && this.stage.update(); - } - }; - - Animation.prototype._startLoop = function () { - var self = this; - this._running = true; - - function step() { - if (self._running) { - requestAnimationFrame$1(step); - !self._paused && self.update(); - } - } - - requestAnimationFrame$1(step); - }; - - Animation.prototype.start = function () { - if (this._running) { - return; - } - - this._time = getTime(); - this._pausedTime = 0; - - this._startLoop(); - }; - - Animation.prototype.stop = function () { - this._running = false; - }; - - Animation.prototype.pause = function () { - if (!this._paused) { - this._pauseStart = getTime(); - this._paused = true; - } - }; - - Animation.prototype.resume = function () { - if (this._paused) { - this._pausedTime += getTime() - this._pauseStart; - this._paused = false; - } - }; - - Animation.prototype.clear = function () { - var clip = this._head; - - while (clip) { - var nextClip = clip.next; - clip.prev = clip.next = clip.animation = null; - clip = nextClip; - } - - this._head = this._tail = null; - }; - - Animation.prototype.isFinished = function () { - return this._head == null; - }; - - Animation.prototype.animate = function (target, options) { - options = options || {}; - this.start(); - var animator = new Animator(target, options.loop); - this.addAnimator(animator); - return animator; - }; - - return Animation; - }(Eventful); - - var TOUCH_CLICK_DELAY = 300; - var globalEventSupported = env.domSupported; - - var localNativeListenerNames = function () { - var mouseHandlerNames = ['click', 'dblclick', 'mousewheel', 'wheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu']; - var touchHandlerNames = ['touchstart', 'touchend', 'touchmove']; - var pointerEventNameMap = { - pointerdown: 1, - pointerup: 1, - pointermove: 1, - pointerout: 1 - }; - var pointerHandlerNames = map$1(mouseHandlerNames, function (name) { - var nm = name.replace('mouse', 'pointer'); - return pointerEventNameMap.hasOwnProperty(nm) ? nm : name; - }); - return { - mouse: mouseHandlerNames, - touch: touchHandlerNames, - pointer: pointerHandlerNames - }; - }(); - - var globalNativeListenerNames = { - mouse: ['mousemove', 'mouseup'], - pointer: ['pointermove', 'pointerup'] - }; - var wheelEventSupported = false; - - function isPointerFromTouch(event) { - var pointerType = event.pointerType; - return pointerType === 'pen' || pointerType === 'touch'; - } - - function setTouchTimer(scope) { - scope.touching = true; - - if (scope.touchTimer != null) { - clearTimeout(scope.touchTimer); - scope.touchTimer = null; - } - - scope.touchTimer = setTimeout(function () { - scope.touching = false; - scope.touchTimer = null; - }, 700); - } - - function markTouch(event) { - event && (event.zrByTouch = true); - } - - function normalizeGlobalEvent(instance, event) { - return normalizeEvent(instance.dom, new FakeGlobalEvent(instance, event), true); - } - - function isLocalEl(instance, el) { - var elTmp = el; - var isLocal = false; - - while (elTmp && elTmp.nodeType !== 9 && !(isLocal = elTmp.domBelongToZr || elTmp !== el && elTmp === instance.painterRoot)) { - elTmp = elTmp.parentNode; - } - - return isLocal; - } - - var FakeGlobalEvent = function () { - function FakeGlobalEvent(instance, event) { - this.stopPropagation = noop; - this.stopImmediatePropagation = noop; - this.preventDefault = noop; - this.type = event.type; - this.target = this.currentTarget = instance.dom; - this.pointerType = event.pointerType; - this.clientX = event.clientX; - this.clientY = event.clientY; - } - - return FakeGlobalEvent; - }(); - - var localDOMHandlers = { - mousedown: function (event) { - event = normalizeEvent(this.dom, event); - this.__mayPointerCapture = [event.zrX, event.zrY]; - this.trigger('mousedown', event); - }, - mousemove: function (event) { - event = normalizeEvent(this.dom, event); - var downPoint = this.__mayPointerCapture; - - if (downPoint && (event.zrX !== downPoint[0] || event.zrY !== downPoint[1])) { - this.__togglePointerCapture(true); - } - - this.trigger('mousemove', event); - }, - mouseup: function (event) { - event = normalizeEvent(this.dom, event); - - this.__togglePointerCapture(false); - - this.trigger('mouseup', event); - }, - mouseout: function (event) { - event = normalizeEvent(this.dom, event); - var element = event.toElement || event.relatedTarget; - - if (!isLocalEl(this, element)) { - if (this.__pointerCapturing) { - event.zrEventControl = 'no_globalout'; - } - - this.trigger('mouseout', event); - } - }, - wheel: function (event) { - wheelEventSupported = true; - event = normalizeEvent(this.dom, event); - this.trigger('mousewheel', event); - }, - mousewheel: function (event) { - if (wheelEventSupported) { - return; - } - - event = normalizeEvent(this.dom, event); - this.trigger('mousewheel', event); - }, - touchstart: function (event) { - event = normalizeEvent(this.dom, event); - markTouch(event); - this.__lastTouchMoment = new Date(); - this.handler.processGesture(event, 'start'); - localDOMHandlers.mousemove.call(this, event); - localDOMHandlers.mousedown.call(this, event); - }, - touchmove: function (event) { - event = normalizeEvent(this.dom, event); - markTouch(event); - this.handler.processGesture(event, 'change'); - localDOMHandlers.mousemove.call(this, event); - }, - touchend: function (event) { - event = normalizeEvent(this.dom, event); - markTouch(event); - this.handler.processGesture(event, 'end'); - localDOMHandlers.mouseup.call(this, event); - - if (+new Date() - +this.__lastTouchMoment < TOUCH_CLICK_DELAY) { - localDOMHandlers.click.call(this, event); - } - }, - pointerdown: function (event) { - localDOMHandlers.mousedown.call(this, event); - }, - pointermove: function (event) { - if (!isPointerFromTouch(event)) { - localDOMHandlers.mousemove.call(this, event); - } - }, - pointerup: function (event) { - localDOMHandlers.mouseup.call(this, event); - }, - pointerout: function (event) { - if (!isPointerFromTouch(event)) { - localDOMHandlers.mouseout.call(this, event); - } - } - }; - each$4(['click', 'dblclick', 'contextmenu'], function (name) { - localDOMHandlers[name] = function (event) { - event = normalizeEvent(this.dom, event); - this.trigger(name, event); - }; - }); - var globalDOMHandlers = { - pointermove: function (event) { - if (!isPointerFromTouch(event)) { - globalDOMHandlers.mousemove.call(this, event); - } - }, - pointerup: function (event) { - globalDOMHandlers.mouseup.call(this, event); - }, - mousemove: function (event) { - this.trigger('mousemove', event); - }, - mouseup: function (event) { - var pointerCaptureReleasing = this.__pointerCapturing; - - this.__togglePointerCapture(false); - - this.trigger('mouseup', event); - - if (pointerCaptureReleasing) { - event.zrEventControl = 'only_globalout'; - this.trigger('mouseout', event); - } - } - }; - - function mountLocalDOMEventListeners(instance, scope) { - var domHandlers = scope.domHandlers; - - if (env.pointerEventsSupported) { - each$4(localNativeListenerNames.pointer, function (nativeEventName) { - mountSingleDOMEventListener(scope, nativeEventName, function (event) { - domHandlers[nativeEventName].call(instance, event); - }); - }); - } else { - if (env.touchEventsSupported) { - each$4(localNativeListenerNames.touch, function (nativeEventName) { - mountSingleDOMEventListener(scope, nativeEventName, function (event) { - domHandlers[nativeEventName].call(instance, event); - setTouchTimer(scope); - }); - }); - } - - each$4(localNativeListenerNames.mouse, function (nativeEventName) { - mountSingleDOMEventListener(scope, nativeEventName, function (event) { - event = getNativeEvent(event); - - if (!scope.touching) { - domHandlers[nativeEventName].call(instance, event); - } - }); - }); - } - } - - function mountGlobalDOMEventListeners(instance, scope) { - if (env.pointerEventsSupported) { - each$4(globalNativeListenerNames.pointer, mount); - } else if (!env.touchEventsSupported) { - each$4(globalNativeListenerNames.mouse, mount); - } - - function mount(nativeEventName) { - function nativeEventListener(event) { - event = getNativeEvent(event); - - if (!isLocalEl(instance, event.target)) { - event = normalizeGlobalEvent(instance, event); - scope.domHandlers[nativeEventName].call(instance, event); - } - } - - mountSingleDOMEventListener(scope, nativeEventName, nativeEventListener, { - capture: true - }); - } - } - - function mountSingleDOMEventListener(scope, nativeEventName, listener, opt) { - scope.mounted[nativeEventName] = listener; - scope.listenerOpts[nativeEventName] = opt; - addEventListener(scope.domTarget, nativeEventName, listener, opt); - } - - function unmountDOMEventListeners(scope) { - var mounted = scope.mounted; - - for (var nativeEventName in mounted) { - if (mounted.hasOwnProperty(nativeEventName)) { - removeEventListener(scope.domTarget, nativeEventName, mounted[nativeEventName], scope.listenerOpts[nativeEventName]); - } - } - - scope.mounted = {}; - } - - var DOMHandlerScope = function () { - function DOMHandlerScope(domTarget, domHandlers) { - this.mounted = {}; - this.listenerOpts = {}; - this.touching = false; - this.domTarget = domTarget; - this.domHandlers = domHandlers; - } - - return DOMHandlerScope; - }(); - - var HandlerDomProxy = function (_super) { - __extends(HandlerDomProxy, _super); - - function HandlerDomProxy(dom, painterRoot) { - var _this = _super.call(this) || this; - - _this.__pointerCapturing = false; - _this.dom = dom; - _this.painterRoot = painterRoot; - _this._localHandlerScope = new DOMHandlerScope(dom, localDOMHandlers); - - if (globalEventSupported) { - _this._globalHandlerScope = new DOMHandlerScope(document, globalDOMHandlers); - } - - mountLocalDOMEventListeners(_this, _this._localHandlerScope); - return _this; - } - - HandlerDomProxy.prototype.dispose = function () { - unmountDOMEventListeners(this._localHandlerScope); - - if (globalEventSupported) { - unmountDOMEventListeners(this._globalHandlerScope); - } - }; - - HandlerDomProxy.prototype.setCursor = function (cursorStyle) { - this.dom.style && (this.dom.style.cursor = cursorStyle || 'default'); - }; - - HandlerDomProxy.prototype.__togglePointerCapture = function (isPointerCapturing) { - this.__mayPointerCapture = null; - - if (globalEventSupported && +this.__pointerCapturing ^ +isPointerCapturing) { - this.__pointerCapturing = isPointerCapturing; - var globalHandlerScope = this._globalHandlerScope; - isPointerCapturing ? mountGlobalDOMEventListeners(this, globalHandlerScope) : unmountDOMEventListeners(globalHandlerScope); - } - }; - - return HandlerDomProxy; - }(Eventful); - - var dpr = 1; - - if (env.hasGlobalWindow) { - dpr = Math.max(window.devicePixelRatio || window.screen && window.screen.deviceXDPI / window.screen.logicalXDPI || 1, 1); - } - - var devicePixelRatio = dpr; - var DARK_MODE_THRESHOLD = 0.4; - var DARK_LABEL_COLOR = '#333'; - var LIGHT_LABEL_COLOR = '#ccc'; - var LIGHTER_LABEL_COLOR = '#eee'; - var mIdentity = identity; - var EPSILON$2 = 5e-5; - - function isNotAroundZero(val) { - return val > EPSILON$2 || val < -EPSILON$2; - } - - var scaleTmp = []; - var tmpTransform = []; - var originTransform = create(); - var abs = Math.abs; - - var Transformable = function () { - function Transformable() {} - - Transformable.prototype.getLocalTransform = function (m) { - return Transformable.getLocalTransform(this, m); - }; - - Transformable.prototype.setPosition = function (arr) { - this.x = arr[0]; - this.y = arr[1]; - }; - - Transformable.prototype.setScale = function (arr) { - this.scaleX = arr[0]; - this.scaleY = arr[1]; - }; - - Transformable.prototype.setSkew = function (arr) { - this.skewX = arr[0]; - this.skewY = arr[1]; - }; - - Transformable.prototype.setOrigin = function (arr) { - this.originX = arr[0]; - this.originY = arr[1]; - }; - - Transformable.prototype.needLocalTransform = function () { - return isNotAroundZero(this.rotation) || isNotAroundZero(this.x) || isNotAroundZero(this.y) || isNotAroundZero(this.scaleX - 1) || isNotAroundZero(this.scaleY - 1) || isNotAroundZero(this.skewX) || isNotAroundZero(this.skewY); - }; - - Transformable.prototype.updateTransform = function () { - var parentTransform = this.parent && this.parent.transform; - var needLocalTransform = this.needLocalTransform(); - var m = this.transform; - - if (!(needLocalTransform || parentTransform)) { - if (m) { - mIdentity(m); - this.invTransform = null; - } - - return; - } - - m = m || create(); - - if (needLocalTransform) { - this.getLocalTransform(m); - } else { - mIdentity(m); - } - - if (parentTransform) { - if (needLocalTransform) { - mul(m, parentTransform, m); - } else { - copy(m, parentTransform); - } - } - - this.transform = m; - - this._resolveGlobalScaleRatio(m); - }; - - Transformable.prototype._resolveGlobalScaleRatio = function (m) { - var globalScaleRatio = this.globalScaleRatio; - - if (globalScaleRatio != null && globalScaleRatio !== 1) { - this.getGlobalScale(scaleTmp); - var relX = scaleTmp[0] < 0 ? -1 : 1; - var relY = scaleTmp[1] < 0 ? -1 : 1; - var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0; - var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0; - m[0] *= sx; - m[1] *= sx; - m[2] *= sy; - m[3] *= sy; - } - - this.invTransform = this.invTransform || create(); - invert(this.invTransform, m); - }; - - Transformable.prototype.getComputedTransform = function () { - var transformNode = this; - var ancestors = []; - - while (transformNode) { - ancestors.push(transformNode); - transformNode = transformNode.parent; - } - - while (transformNode = ancestors.pop()) { - transformNode.updateTransform(); - } - - return this.transform; - }; - - Transformable.prototype.setLocalTransform = function (m) { - if (!m) { - return; - } - - var sx = m[0] * m[0] + m[1] * m[1]; - var sy = m[2] * m[2] + m[3] * m[3]; - var rotation = Math.atan2(m[1], m[0]); - var shearX = Math.PI / 2 + rotation - Math.atan2(m[3], m[2]); - sy = Math.sqrt(sy) * Math.cos(shearX); - sx = Math.sqrt(sx); - this.skewX = shearX; - this.skewY = 0; - this.rotation = -rotation; - this.x = +m[4]; - this.y = +m[5]; - this.scaleX = sx; - this.scaleY = sy; - this.originX = 0; - this.originY = 0; - }; - - Transformable.prototype.decomposeTransform = function () { - if (!this.transform) { - return; - } - - var parent = this.parent; - var m = this.transform; - - if (parent && parent.transform) { - parent.invTransform = parent.invTransform || create(); - mul(tmpTransform, parent.invTransform, m); - m = tmpTransform; - } - - var ox = this.originX; - var oy = this.originY; - - if (ox || oy) { - originTransform[4] = ox; - originTransform[5] = oy; - mul(tmpTransform, m, originTransform); - tmpTransform[4] -= ox; - tmpTransform[5] -= oy; - m = tmpTransform; - } - - this.setLocalTransform(m); - }; - - Transformable.prototype.getGlobalScale = function (out) { - var m = this.transform; - out = out || []; - - if (!m) { - out[0] = 1; - out[1] = 1; - return out; - } - - out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]); - out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]); - - if (m[0] < 0) { - out[0] = -out[0]; - } - - if (m[3] < 0) { - out[1] = -out[1]; - } - - return out; - }; - - Transformable.prototype.transformCoordToLocal = function (x, y) { - var v2 = [x, y]; - var invTransform = this.invTransform; - - if (invTransform) { - applyTransform$1(v2, v2, invTransform); - } - - return v2; - }; - - Transformable.prototype.transformCoordToGlobal = function (x, y) { - var v2 = [x, y]; - var transform = this.transform; - - if (transform) { - applyTransform$1(v2, v2, transform); - } - - return v2; - }; - - Transformable.prototype.getLineScale = function () { - var m = this.transform; - return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10 ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1])) : 1; - }; - - Transformable.prototype.copyTransform = function (source) { - copyTransform(this, source); - }; - - Transformable.getLocalTransform = function (target, m) { - m = m || []; - var ox = target.originX || 0; - var oy = target.originY || 0; - var sx = target.scaleX; - var sy = target.scaleY; - var ax = target.anchorX; - var ay = target.anchorY; - var rotation = target.rotation || 0; - var x = target.x; - var y = target.y; - var skewX = target.skewX ? Math.tan(target.skewX) : 0; - var skewY = target.skewY ? Math.tan(-target.skewY) : 0; - - if (ox || oy || ax || ay) { - var dx = ox + ax; - var dy = oy + ay; - m[4] = -dx * sx - skewX * dy * sy; - m[5] = -dy * sy - skewY * dx * sx; - } else { - m[4] = m[5] = 0; - } - - m[0] = sx; - m[3] = sy; - m[1] = skewY * sx; - m[2] = skewX * sy; - rotation && rotate(m, m, rotation); - m[4] += ox + x; - m[5] += oy + y; - return m; - }; - - Transformable.initDefaultProps = function () { - var proto = Transformable.prototype; - proto.scaleX = proto.scaleY = proto.globalScaleRatio = 1; - proto.x = proto.y = proto.originX = proto.originY = proto.skewX = proto.skewY = proto.rotation = proto.anchorX = proto.anchorY = 0; - }(); - - return Transformable; - }(); - - var TRANSFORMABLE_PROPS = ['x', 'y', 'originX', 'originY', 'anchorX', 'anchorY', 'rotation', 'scaleX', 'scaleY', 'skewX', 'skewY']; - - function copyTransform(target, source) { - for (var i = 0; i < TRANSFORMABLE_PROPS.length; i++) { - var propName = TRANSFORMABLE_PROPS[i]; - target[propName] = source[propName]; - } - } - - function ensureFontMeasureInfo(font) { - if (!_fontMeasureInfoCache) { - _fontMeasureInfoCache = new LRU(100); - } - - font = font || DEFAULT_FONT; - - var measureInfo = _fontMeasureInfoCache.get(font); - - if (!measureInfo) { - measureInfo = { - font: font, - strWidthCache: new LRU(500), - asciiWidthMap: null, - asciiWidthMapTried: false, - stWideCharWidth: platformApi.measureText('国', font).width, - asciiCharWidth: platformApi.measureText('a', font).width - }; - - _fontMeasureInfoCache.put(font, measureInfo); - } - - return measureInfo; - } - - var _fontMeasureInfoCache; - - function tryCreateASCIIWidthMap(font) { - if (_getASCIIWidthMapLongCount >= GET_ASCII_WIDTH_LONG_COUNT_MAX) { - return; - } - - font = font || DEFAULT_FONT; - var asciiWidthMap = []; - var start = +new Date(); - - for (var code = 0; code <= 127; code++) { - asciiWidthMap[code] = platformApi.measureText(String.fromCharCode(code), font).width; - } - - var cost = +new Date() - start; - - if (cost > 16) { - _getASCIIWidthMapLongCount = GET_ASCII_WIDTH_LONG_COUNT_MAX; - } else if (cost > 2) { - _getASCIIWidthMapLongCount++; - } - - return asciiWidthMap; - } - - var _getASCIIWidthMapLongCount = 0; - var GET_ASCII_WIDTH_LONG_COUNT_MAX = 5; - - function measureCharWidth(fontMeasureInfo, charCode) { - if (!fontMeasureInfo.asciiWidthMapTried) { - fontMeasureInfo.asciiWidthMap = tryCreateASCIIWidthMap(fontMeasureInfo.font); - fontMeasureInfo.asciiWidthMapTried = true; - } - - return 0 <= charCode && charCode <= 127 ? fontMeasureInfo.asciiWidthMap != null ? fontMeasureInfo.asciiWidthMap[charCode] : fontMeasureInfo.asciiCharWidth : fontMeasureInfo.stWideCharWidth; - } - - function measureWidth(fontMeasureInfo, text) { - var strWidthCache = fontMeasureInfo.strWidthCache; - var width = strWidthCache.get(text); - - if (width == null) { - width = platformApi.measureText(text, fontMeasureInfo.font).width; - strWidthCache.put(text, width); - } - - return width; - } - - function innerGetBoundingRect(text, font, textAlign, textBaseline) { - var width = measureWidth(ensureFontMeasureInfo(font), text); - var height = getLineHeight(font); - var x = adjustTextX(0, width, textAlign); - var y = adjustTextY(0, height, textBaseline); - var rect = new BoundingRect(x, y, width, height); - return rect; - } - - function getBoundingRect(text, font, textAlign, textBaseline) { - var textLines = ((text || '') + '').split('\n'); - var len = textLines.length; - - if (len === 1) { - return innerGetBoundingRect(textLines[0], font, textAlign, textBaseline); - } else { - var uniondRect = new BoundingRect(0, 0, 0, 0); - - for (var i = 0; i < textLines.length; i++) { - var rect = innerGetBoundingRect(textLines[i], font, textAlign, textBaseline); - i === 0 ? uniondRect.copy(rect) : uniondRect.union(rect); - } - - return uniondRect; - } - } - - function adjustTextX(x, width, textAlign, inverse) { - if (textAlign === 'right') { - !inverse ? x -= width : x += width; - } else if (textAlign === 'center') { - !inverse ? x -= width / 2 : x += width / 2; - } - - return x; - } - - function adjustTextY(y, height, verticalAlign, inverse) { - if (verticalAlign === 'middle') { - !inverse ? y -= height / 2 : y += height / 2; - } else if (verticalAlign === 'bottom') { - !inverse ? y -= height : y += height; - } - - return y; - } - - function getLineHeight(font) { - return ensureFontMeasureInfo(font).stWideCharWidth; - } - - function parsePercent$1(value, maxValue) { - if (typeof value === 'string') { - if (value.lastIndexOf('%') >= 0) { - return parseFloat(value) / 100 * maxValue; - } - - return parseFloat(value); - } - - return value; - } - - function calculateTextPosition(out, opts, rect) { - var textPosition = opts.position || 'inside'; - var distance = opts.distance != null ? opts.distance : 5; - var height = rect.height; - var width = rect.width; - var halfHeight = height / 2; - var x = rect.x; - var y = rect.y; - var textAlign = 'left'; - var textVerticalAlign = 'top'; - - if (textPosition instanceof Array) { - x += parsePercent$1(textPosition[0], rect.width); - y += parsePercent$1(textPosition[1], rect.height); - textAlign = null; - textVerticalAlign = null; - } else { - switch (textPosition) { - case 'left': - x -= distance; - y += halfHeight; - textAlign = 'right'; - textVerticalAlign = 'middle'; - break; - - case 'right': - x += distance + width; - y += halfHeight; - textVerticalAlign = 'middle'; - break; - - case 'top': - x += width / 2; - y -= distance; - textAlign = 'center'; - textVerticalAlign = 'bottom'; - break; - - case 'bottom': - x += width / 2; - y += height + distance; - textAlign = 'center'; - break; - - case 'inside': - x += width / 2; - y += halfHeight; - textAlign = 'center'; - textVerticalAlign = 'middle'; - break; - - case 'insideLeft': - x += distance; - y += halfHeight; - textVerticalAlign = 'middle'; - break; - - case 'insideRight': - x += width - distance; - y += halfHeight; - textAlign = 'right'; - textVerticalAlign = 'middle'; - break; - - case 'insideTop': - x += width / 2; - y += distance; - textAlign = 'center'; - break; - - case 'insideBottom': - x += width / 2; - y += height - distance; - textAlign = 'center'; - textVerticalAlign = 'bottom'; - break; - - case 'insideTopLeft': - x += distance; - y += distance; - break; - - case 'insideTopRight': - x += width - distance; - y += distance; - textAlign = 'right'; - break; - - case 'insideBottomLeft': - x += distance; - y += height - distance; - textVerticalAlign = 'bottom'; - break; - - case 'insideBottomRight': - x += width - distance; - y += height - distance; - textAlign = 'right'; - textVerticalAlign = 'bottom'; - break; - } - } - - out = out || {}; - out.x = x; - out.y = y; - out.align = textAlign; - out.verticalAlign = textVerticalAlign; - return out; - } - - var PRESERVED_NORMAL_STATE = '__zr_normal__'; - var PRIMARY_STATES_KEYS$1 = TRANSFORMABLE_PROPS.concat(['ignore']); - var DEFAULT_ANIMATABLE_MAP = reduce(TRANSFORMABLE_PROPS, function (obj, key) { - obj[key] = true; - return obj; - }, { - ignore: false - }); - var tmpTextPosCalcRes = {}; - var tmpBoundingRect = new BoundingRect(0, 0, 0, 0); - var tmpInnerTextTrans = []; - - var Element = function () { - function Element(props) { - this.id = guid(); - this.animators = []; - this.currentStates = []; - this.states = {}; - - this._init(props); - } - - Element.prototype._init = function (props) { - this.attr(props); - }; - - Element.prototype.drift = function (dx, dy, e) { - switch (this.draggable) { - case 'horizontal': - dy = 0; - break; - - case 'vertical': - dx = 0; - break; - } - - var m = this.transform; - - if (!m) { - m = this.transform = [1, 0, 0, 1, 0, 0]; - } - - m[4] += dx; - m[5] += dy; - this.decomposeTransform(); - this.markRedraw(); - }; - - Element.prototype.beforeUpdate = function () {}; - - Element.prototype.afterUpdate = function () {}; - - Element.prototype.update = function () { - this.updateTransform(); - - if (this.__dirty) { - this.updateInnerText(); - } - }; - - Element.prototype.updateInnerText = function (forceUpdate) { - var textEl = this._textContent; - - if (textEl && (!textEl.ignore || forceUpdate)) { - if (!this.textConfig) { - this.textConfig = {}; - } - - var textConfig = this.textConfig; - var isLocal = textConfig.local; - var innerTransformable = textEl.innerTransformable; - var textAlign = void 0; - var textVerticalAlign = void 0; - var textStyleChanged = false; - innerTransformable.parent = isLocal ? this : null; - var innerOrigin = false; - innerTransformable.copyTransform(textEl); - var hasPosition = textConfig.position != null; - var autoOverflowArea = textConfig.autoOverflowArea; - var layoutRect = void 0; - - if (autoOverflowArea || hasPosition) { - layoutRect = tmpBoundingRect; - - if (textConfig.layoutRect) { - layoutRect.copy(textConfig.layoutRect); - } else { - layoutRect.copy(this.getBoundingRect()); - } - - if (!isLocal) { - layoutRect.applyTransform(this.transform); - } - } - - if (hasPosition) { - if (this.calculateTextPosition) { - this.calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect); - } else { - calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect); - } - - innerTransformable.x = tmpTextPosCalcRes.x; - innerTransformable.y = tmpTextPosCalcRes.y; - textAlign = tmpTextPosCalcRes.align; - textVerticalAlign = tmpTextPosCalcRes.verticalAlign; - var textOrigin = textConfig.origin; - - if (textOrigin && textConfig.rotation != null) { - var relOriginX = void 0; - var relOriginY = void 0; - - if (textOrigin === 'center') { - relOriginX = layoutRect.width * 0.5; - relOriginY = layoutRect.height * 0.5; - } else { - relOriginX = parsePercent$1(textOrigin[0], layoutRect.width); - relOriginY = parsePercent$1(textOrigin[1], layoutRect.height); - } - - innerOrigin = true; - innerTransformable.originX = -innerTransformable.x + relOriginX + (isLocal ? 0 : layoutRect.x); - innerTransformable.originY = -innerTransformable.y + relOriginY + (isLocal ? 0 : layoutRect.y); - } - } - - if (textConfig.rotation != null) { - innerTransformable.rotation = textConfig.rotation; - } - - var textOffset = textConfig.offset; - - if (textOffset) { - innerTransformable.x += textOffset[0]; - innerTransformable.y += textOffset[1]; - - if (!innerOrigin) { - innerTransformable.originX = -textOffset[0]; - innerTransformable.originY = -textOffset[1]; - } - } - - var innerTextDefaultStyle = this._innerTextDefaultStyle || (this._innerTextDefaultStyle = {}); - - if (autoOverflowArea) { - var overflowRect = innerTextDefaultStyle.overflowRect = innerTextDefaultStyle.overflowRect || new BoundingRect(0, 0, 0, 0); - innerTransformable.getLocalTransform(tmpInnerTextTrans); - invert(tmpInnerTextTrans, tmpInnerTextTrans); - BoundingRect.copy(overflowRect, layoutRect); - overflowRect.applyTransform(tmpInnerTextTrans); - } else { - innerTextDefaultStyle.overflowRect = null; - } - - var isInside = textConfig.inside == null ? typeof textConfig.position === 'string' && textConfig.position.indexOf('inside') >= 0 : textConfig.inside; - var textFill = void 0; - var textStroke = void 0; - var autoStroke = void 0; - - if (isInside && this.canBeInsideText()) { - textFill = textConfig.insideFill; - textStroke = textConfig.insideStroke; - - if (textFill == null || textFill === 'auto') { - textFill = this.getInsideTextFill(); - } - - if (textStroke == null || textStroke === 'auto') { - textStroke = this.getInsideTextStroke(textFill); - autoStroke = true; - } - } else { - textFill = textConfig.outsideFill; - textStroke = textConfig.outsideStroke; - - if (textFill == null || textFill === 'auto') { - textFill = this.getOutsideFill(); - } - - if (textStroke == null || textStroke === 'auto') { - textStroke = this.getOutsideStroke(textFill); - autoStroke = true; - } - } - - textFill = textFill || '#000'; - - if (textFill !== innerTextDefaultStyle.fill || textStroke !== innerTextDefaultStyle.stroke || autoStroke !== innerTextDefaultStyle.autoStroke || textAlign !== innerTextDefaultStyle.align || textVerticalAlign !== innerTextDefaultStyle.verticalAlign) { - textStyleChanged = true; - innerTextDefaultStyle.fill = textFill; - innerTextDefaultStyle.stroke = textStroke; - innerTextDefaultStyle.autoStroke = autoStroke; - innerTextDefaultStyle.align = textAlign; - innerTextDefaultStyle.verticalAlign = textVerticalAlign; - textEl.setDefaultTextStyle(innerTextDefaultStyle); - } - - textEl.__dirty |= REDRAW_BIT; - - if (textStyleChanged) { - textEl.dirtyStyle(true); - } - } - }; - - Element.prototype.canBeInsideText = function () { - return true; - }; - - Element.prototype.getInsideTextFill = function () { - return '#fff'; - }; - - Element.prototype.getInsideTextStroke = function (textFill) { - return '#000'; - }; - - Element.prototype.getOutsideFill = function () { - return this.__zr && this.__zr.isDarkMode() ? LIGHT_LABEL_COLOR : DARK_LABEL_COLOR; - }; - - Element.prototype.getOutsideStroke = function (textFill) { - var backgroundColor = this.__zr && this.__zr.getBackgroundColor(); - - var colorArr = typeof backgroundColor === 'string' && parse(backgroundColor); - - if (!colorArr) { - colorArr = [255, 255, 255, 1]; - } - - var alpha = colorArr[3]; - - var isDark = this.__zr.isDarkMode(); - - for (var i = 0; i < 3; i++) { - colorArr[i] = colorArr[i] * alpha + (isDark ? 0 : 255) * (1 - alpha); - } - - colorArr[3] = 1; - return stringify(colorArr, 'rgba'); - }; - - Element.prototype.traverse = function (cb, context) {}; - - Element.prototype.attrKV = function (key, value) { - if (key === 'textConfig') { - this.setTextConfig(value); - } else if (key === 'textContent') { - this.setTextContent(value); - } else if (key === 'clipPath') { - this.setClipPath(value); - } else if (key === 'extra') { - this.extra = this.extra || {}; - extend(this.extra, value); - } else { - this[key] = value; - } - }; - - Element.prototype.hide = function () { - this.ignore = true; - this.markRedraw(); - }; - - Element.prototype.show = function () { - this.ignore = false; - this.markRedraw(); - }; - - Element.prototype.attr = function (keyOrObj, value) { - if (typeof keyOrObj === 'string') { - this.attrKV(keyOrObj, value); - } else if (isObject$2(keyOrObj)) { - var obj = keyOrObj; - var keysArr = keys(obj); - - for (var i = 0; i < keysArr.length; i++) { - var key = keysArr[i]; - this.attrKV(key, keyOrObj[key]); - } - } - - this.markRedraw(); - return this; - }; - - Element.prototype.saveCurrentToNormalState = function (toState) { - this._innerSaveToNormal(toState); - - var normalState = this._normalState; - - for (var i = 0; i < this.animators.length; i++) { - var animator = this.animators[i]; - var fromStateTransition = animator.__fromStateTransition; - - if (animator.getLoop() || fromStateTransition && fromStateTransition !== PRESERVED_NORMAL_STATE) { - continue; - } - - var targetName = animator.targetName; - var target = targetName ? normalState[targetName] : normalState; - animator.saveTo(target); - } - }; - - Element.prototype._innerSaveToNormal = function (toState) { - var normalState = this._normalState; - - if (!normalState) { - normalState = this._normalState = {}; - } - - if (toState.textConfig && !normalState.textConfig) { - normalState.textConfig = this.textConfig; - } - - this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS$1); - }; - - Element.prototype._savePrimaryToNormal = function (toState, normalState, primaryKeys) { - for (var i = 0; i < primaryKeys.length; i++) { - var key = primaryKeys[i]; - - if (toState[key] != null && !(key in normalState)) { - normalState[key] = this[key]; - } - } - }; - - Element.prototype.hasState = function () { - return this.currentStates.length > 0; - }; - - Element.prototype.getState = function (name) { - return this.states[name]; - }; - - Element.prototype.ensureState = function (name) { - var states = this.states; - - if (!states[name]) { - states[name] = {}; - } - - return states[name]; - }; - - Element.prototype.clearStates = function (noAnimation) { - this.useState(PRESERVED_NORMAL_STATE, false, noAnimation); - }; - - Element.prototype.useState = function (stateName, keepCurrentStates, noAnimation, forceUseHoverLayer) { - var toNormalState = stateName === PRESERVED_NORMAL_STATE; - var hasStates = this.hasState(); - - if (!hasStates && toNormalState) { - return; - } - - var currentStates = this.currentStates; - var animationCfg = this.stateTransition; - - if (indexOf(currentStates, stateName) >= 0 && (keepCurrentStates || currentStates.length === 1)) { - return; - } - - var state; - - if (this.stateProxy && !toNormalState) { - state = this.stateProxy(stateName); - } - - if (!state) { - state = this.states && this.states[stateName]; - } - - if (!state && !toNormalState) { - logError("State " + stateName + " not exists."); - return; - } - - if (!toNormalState) { - this.saveCurrentToNormalState(state); - } - - var useHoverLayer = !!(state && state.hoverLayer || forceUseHoverLayer); - - if (useHoverLayer) { - this._toggleHoverLayerFlag(true); - } - - this._applyStateObj(stateName, state, this._normalState, keepCurrentStates, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg); - - var textContent = this._textContent; - var textGuide = this._textGuide; - - if (textContent) { - textContent.useState(stateName, keepCurrentStates, noAnimation, useHoverLayer); - } - - if (textGuide) { - textGuide.useState(stateName, keepCurrentStates, noAnimation, useHoverLayer); - } - - if (toNormalState) { - this.currentStates = []; - this._normalState = {}; - } else { - if (!keepCurrentStates) { - this.currentStates = [stateName]; - } else { - this.currentStates.push(stateName); - } - } - - this._updateAnimationTargets(); - - this.markRedraw(); - - if (!useHoverLayer && this.__inHover) { - this._toggleHoverLayerFlag(false); - - this.__dirty &= ~REDRAW_BIT; - } - - return state; - }; - - Element.prototype.useStates = function (states, noAnimation, forceUseHoverLayer) { - if (!states.length) { - this.clearStates(); - } else { - var stateObjects = []; - var currentStates = this.currentStates; - var len = states.length; - var notChange = len === currentStates.length; - - if (notChange) { - for (var i = 0; i < len; i++) { - if (states[i] !== currentStates[i]) { - notChange = false; - break; - } - } - } - - if (notChange) { - return; - } - - for (var i = 0; i < len; i++) { - var stateName = states[i]; - var stateObj = void 0; - - if (this.stateProxy) { - stateObj = this.stateProxy(stateName, states); - } - - if (!stateObj) { - stateObj = this.states[stateName]; - } - - if (stateObj) { - stateObjects.push(stateObj); - } - } - - var lastStateObj = stateObjects[len - 1]; - var useHoverLayer = !!(lastStateObj && lastStateObj.hoverLayer || forceUseHoverLayer); - - if (useHoverLayer) { - this._toggleHoverLayerFlag(true); - } - - var mergedState = this._mergeStates(stateObjects); - - var animationCfg = this.stateTransition; - this.saveCurrentToNormalState(mergedState); - - this._applyStateObj(states.join(','), mergedState, this._normalState, false, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg); - - var textContent = this._textContent; - var textGuide = this._textGuide; - - if (textContent) { - textContent.useStates(states, noAnimation, useHoverLayer); - } - - if (textGuide) { - textGuide.useStates(states, noAnimation, useHoverLayer); - } - - this._updateAnimationTargets(); - - this.currentStates = states.slice(); - this.markRedraw(); - - if (!useHoverLayer && this.__inHover) { - this._toggleHoverLayerFlag(false); - - this.__dirty &= ~REDRAW_BIT; - } - } - }; - - Element.prototype.isSilent = function () { - var el = this; - - while (el) { - if (el.silent) { - return true; - } - - var hostEl = el.__hostTarget; - el = hostEl ? el.ignoreHostSilent ? null : hostEl : el.parent; - } - - return false; - }; - - Element.prototype._updateAnimationTargets = function () { - for (var i = 0; i < this.animators.length; i++) { - var animator = this.animators[i]; - - if (animator.targetName) { - animator.changeTarget(this[animator.targetName]); - } - } - }; - - Element.prototype.removeState = function (state) { - var idx = indexOf(this.currentStates, state); - - if (idx >= 0) { - var currentStates = this.currentStates.slice(); - currentStates.splice(idx, 1); - this.useStates(currentStates); - } - }; - - Element.prototype.replaceState = function (oldState, newState, forceAdd) { - var currentStates = this.currentStates.slice(); - var idx = indexOf(currentStates, oldState); - var newStateExists = indexOf(currentStates, newState) >= 0; - - if (idx >= 0) { - if (!newStateExists) { - currentStates[idx] = newState; - } else { - currentStates.splice(idx, 1); - } - } else if (forceAdd && !newStateExists) { - currentStates.push(newState); - } - - this.useStates(currentStates); - }; - - Element.prototype.toggleState = function (state, enable) { - if (enable) { - this.useState(state, true); - } else { - this.removeState(state); - } - }; - - Element.prototype._mergeStates = function (states) { - var mergedState = {}; - var mergedTextConfig; - - for (var i = 0; i < states.length; i++) { - var state = states[i]; - extend(mergedState, state); - - if (state.textConfig) { - mergedTextConfig = mergedTextConfig || {}; - extend(mergedTextConfig, state.textConfig); - } - } - - if (mergedTextConfig) { - mergedState.textConfig = mergedTextConfig; - } - - return mergedState; - }; - - Element.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) { - var needsRestoreToNormal = !(state && keepCurrentStates); - - if (state && state.textConfig) { - this.textConfig = extend({}, keepCurrentStates ? this.textConfig : normalState.textConfig); - extend(this.textConfig, state.textConfig); - } else if (needsRestoreToNormal) { - if (normalState.textConfig) { - this.textConfig = normalState.textConfig; - } - } - - var transitionTarget = {}; - var hasTransition = false; - - for (var i = 0; i < PRIMARY_STATES_KEYS$1.length; i++) { - var key = PRIMARY_STATES_KEYS$1[i]; - var propNeedsTransition = transition && DEFAULT_ANIMATABLE_MAP[key]; - - if (state && state[key] != null) { - if (propNeedsTransition) { - hasTransition = true; - transitionTarget[key] = state[key]; - } else { - this[key] = state[key]; - } - } else if (needsRestoreToNormal) { - if (normalState[key] != null) { - if (propNeedsTransition) { - hasTransition = true; - transitionTarget[key] = normalState[key]; - } else { - this[key] = normalState[key]; - } - } - } - } - - if (!transition) { - for (var i = 0; i < this.animators.length; i++) { - var animator = this.animators[i]; - var targetName = animator.targetName; - - if (!animator.getLoop()) { - animator.__changeFinalValue(targetName ? (state || normalState)[targetName] : state || normalState); - } - } - } - - if (hasTransition) { - this._transitionState(stateName, transitionTarget, animationCfg); - } - }; - - Element.prototype._attachComponent = function (componentEl) { - if (componentEl.__zr && !componentEl.__hostTarget) { - { - throw new Error('Text element has been added to zrender.'); - } - } - - if (componentEl === this) { - { - throw new Error('Recursive component attachment.'); - } - } - - var zr = this.__zr; - - if (zr) { - componentEl.addSelfToZr(zr); - } - - componentEl.__zr = zr; - componentEl.__hostTarget = this; - }; - - Element.prototype._detachComponent = function (componentEl) { - if (componentEl.__zr) { - componentEl.removeSelfFromZr(componentEl.__zr); - } - - componentEl.__zr = null; - componentEl.__hostTarget = null; - }; - - Element.prototype.getClipPath = function () { - return this._clipPath; - }; - - Element.prototype.setClipPath = function (clipPath) { - if (this._clipPath && this._clipPath !== clipPath) { - this.removeClipPath(); - } - - this._attachComponent(clipPath); - - this._clipPath = clipPath; - this.markRedraw(); - }; - - Element.prototype.removeClipPath = function () { - var clipPath = this._clipPath; - - if (clipPath) { - this._detachComponent(clipPath); - - this._clipPath = null; - this.markRedraw(); - } - }; - - Element.prototype.getTextContent = function () { - return this._textContent; - }; - - Element.prototype.setTextContent = function (textEl) { - var previousTextContent = this._textContent; - - if (previousTextContent === textEl) { - return; - } - - if (previousTextContent && previousTextContent !== textEl) { - this.removeTextContent(); - } - - { - if (textEl.__zr && !textEl.__hostTarget) { - throw new Error('Text element has been added to zrender.'); - } - } - textEl.innerTransformable = new Transformable(); - - this._attachComponent(textEl); - - this._textContent = textEl; - this.markRedraw(); - }; - - Element.prototype.setTextConfig = function (cfg) { - if (!this.textConfig) { - this.textConfig = {}; - } - - extend(this.textConfig, cfg); - this.markRedraw(); - }; - - Element.prototype.removeTextConfig = function () { - this.textConfig = null; - this.markRedraw(); - }; - - Element.prototype.removeTextContent = function () { - var textEl = this._textContent; - - if (textEl) { - textEl.innerTransformable = null; - - this._detachComponent(textEl); - - this._textContent = null; - this._innerTextDefaultStyle = null; - this.markRedraw(); - } - }; - - Element.prototype.getTextGuideLine = function () { - return this._textGuide; - }; - - Element.prototype.setTextGuideLine = function (guideLine) { - if (this._textGuide && this._textGuide !== guideLine) { - this.removeTextGuideLine(); - } - - this._attachComponent(guideLine); - - this._textGuide = guideLine; - this.markRedraw(); - }; - - Element.prototype.removeTextGuideLine = function () { - var textGuide = this._textGuide; - - if (textGuide) { - this._detachComponent(textGuide); - - this._textGuide = null; - this.markRedraw(); - } - }; - - Element.prototype.markRedraw = function () { - this.__dirty |= REDRAW_BIT; - var zr = this.__zr; - - if (zr) { - if (this.__inHover) { - zr.refreshHover(); - } else { - zr.refresh(); - } - } - - if (this.__hostTarget) { - this.__hostTarget.markRedraw(); - } - }; - - Element.prototype.dirty = function () { - this.markRedraw(); - }; - - Element.prototype._toggleHoverLayerFlag = function (inHover) { - this.__inHover = inHover; - var textContent = this._textContent; - var textGuide = this._textGuide; - - if (textContent) { - textContent.__inHover = inHover; - } - - if (textGuide) { - textGuide.__inHover = inHover; - } - }; - - Element.prototype.addSelfToZr = function (zr) { - if (this.__zr === zr) { - return; - } - - this.__zr = zr; - var animators = this.animators; - - if (animators) { - for (var i = 0; i < animators.length; i++) { - zr.animation.addAnimator(animators[i]); - } - } - - if (this._clipPath) { - this._clipPath.addSelfToZr(zr); - } - - if (this._textContent) { - this._textContent.addSelfToZr(zr); - } - - if (this._textGuide) { - this._textGuide.addSelfToZr(zr); - } - }; - - Element.prototype.removeSelfFromZr = function (zr) { - if (!this.__zr) { - return; - } - - this.__zr = null; - var animators = this.animators; - - if (animators) { - for (var i = 0; i < animators.length; i++) { - zr.animation.removeAnimator(animators[i]); - } - } - - if (this._clipPath) { - this._clipPath.removeSelfFromZr(zr); - } - - if (this._textContent) { - this._textContent.removeSelfFromZr(zr); - } - - if (this._textGuide) { - this._textGuide.removeSelfFromZr(zr); - } - }; - - Element.prototype.animate = function (key, loop, allowDiscreteAnimation) { - var target = key ? this[key] : this; - { - if (!target) { - logError('Property "' + key + '" is not existed in element ' + this.id); - return; - } - } - var animator = new Animator(target, loop, allowDiscreteAnimation); - key && (animator.targetName = key); - this.addAnimator(animator, key); - return animator; - }; - - Element.prototype.addAnimator = function (animator, key) { - var zr = this.__zr; - var el = this; - animator.during(function () { - el.updateDuringAnimation(key); - }).done(function () { - var animators = el.animators; - var idx = indexOf(animators, animator); - - if (idx >= 0) { - animators.splice(idx, 1); - } - }); - this.animators.push(animator); - - if (zr) { - zr.animation.addAnimator(animator); - } - - zr && zr.wakeUp(); - }; - - Element.prototype.updateDuringAnimation = function (key) { - this.markRedraw(); - }; - - Element.prototype.stopAnimation = function (scope, forwardToLast) { - var animators = this.animators; - var len = animators.length; - var leftAnimators = []; - - for (var i = 0; i < len; i++) { - var animator = animators[i]; - - if (!scope || scope === animator.scope) { - animator.stop(forwardToLast); - } else { - leftAnimators.push(animator); - } - } - - this.animators = leftAnimators; - return this; - }; - - Element.prototype.animateTo = function (target, cfg, animationProps) { - animateTo(this, target, cfg, animationProps); - }; - - Element.prototype.animateFrom = function (target, cfg, animationProps) { - animateTo(this, target, cfg, animationProps, true); - }; - - Element.prototype._transitionState = function (stateName, target, cfg, animationProps) { - var animators = animateTo(this, target, cfg, animationProps); - - for (var i = 0; i < animators.length; i++) { - animators[i].__fromStateTransition = stateName; - } - }; - - Element.prototype.getBoundingRect = function () { - return null; - }; - - Element.prototype.getPaintRect = function () { - return null; - }; - - Element.initDefaultProps = function () { - var elProto = Element.prototype; - elProto.type = 'element'; - elProto.name = ''; - elProto.ignore = elProto.silent = elProto.ignoreHostSilent = elProto.isGroup = elProto.draggable = elProto.dragging = elProto.ignoreClip = elProto.__inHover = false; - elProto.__dirty = REDRAW_BIT; - var logs = {}; - - function logDeprecatedError(key, xKey, yKey) { - if (!logs[key + xKey + yKey]) { - console.warn("DEPRECATED: '" + key + "' has been deprecated. use '" + xKey + "', '" + yKey + "' instead"); - logs[key + xKey + yKey] = true; - } - } - - function createLegacyProperty(key, privateKey, xKey, yKey) { - Object.defineProperty(elProto, key, { - get: function () { - { - logDeprecatedError(key, xKey, yKey); - } - - if (!this[privateKey]) { - var pos = this[privateKey] = []; - enhanceArray(this, pos); - } - - return this[privateKey]; - }, - set: function (pos) { - { - logDeprecatedError(key, xKey, yKey); - } - this[xKey] = pos[0]; - this[yKey] = pos[1]; - this[privateKey] = pos; - enhanceArray(this, pos); - } - }); - - function enhanceArray(self, pos) { - Object.defineProperty(pos, 0, { - get: function () { - return self[xKey]; - }, - set: function (val) { - self[xKey] = val; - } - }); - Object.defineProperty(pos, 1, { - get: function () { - return self[yKey]; - }, - set: function (val) { - self[yKey] = val; - } - }); - } - } - - if (Object.defineProperty) { - createLegacyProperty('position', '_legacyPos', 'x', 'y'); - createLegacyProperty('scale', '_legacyScale', 'scaleX', 'scaleY'); - createLegacyProperty('origin', '_legacyOrigin', 'originX', 'originY'); - } - }(); - - return Element; - }(); - - mixin(Element, Eventful); - mixin(Element, Transformable); - - function animateTo(animatable, target, cfg, animationProps, reverse) { - cfg = cfg || {}; - var animators = []; - animateToShallow(animatable, '', animatable, target, cfg, animationProps, animators, reverse); - var finishCount = animators.length; - var doneHappened = false; - var cfgDone = cfg.done; - var cfgAborted = cfg.aborted; - - var doneCb = function () { - doneHappened = true; - finishCount--; - - if (finishCount <= 0) { - doneHappened ? cfgDone && cfgDone() : cfgAborted && cfgAborted(); - } - }; - - var abortedCb = function () { - finishCount--; - - if (finishCount <= 0) { - doneHappened ? cfgDone && cfgDone() : cfgAborted && cfgAborted(); - } - }; - - if (!finishCount) { - cfgDone && cfgDone(); - } - - if (animators.length > 0 && cfg.during) { - animators[0].during(function (target, percent) { - cfg.during(percent); - }); - } - - for (var i = 0; i < animators.length; i++) { - var animator = animators[i]; - - if (doneCb) { - animator.done(doneCb); - } - - if (abortedCb) { - animator.aborted(abortedCb); - } - - if (cfg.force) { - animator.duration(cfg.duration); - } - - animator.start(cfg.easing); - } - - return animators; - } - - function copyArrShallow(source, target, len) { - for (var i = 0; i < len; i++) { - source[i] = target[i]; - } - } - - function is2DArray(value) { - return isArrayLike(value[0]); - } - - function copyValue(target, source, key) { - if (isArrayLike(source[key])) { - if (!isArrayLike(target[key])) { - target[key] = []; - } - - if (isTypedArray(source[key])) { - var len = source[key].length; - - if (target[key].length !== len) { - target[key] = new source[key].constructor(len); - copyArrShallow(target[key], source[key], len); - } - } else { - var sourceArr = source[key]; - var targetArr = target[key]; - var len0 = sourceArr.length; - - if (is2DArray(sourceArr)) { - var len1 = sourceArr[0].length; - - for (var i = 0; i < len0; i++) { - if (!targetArr[i]) { - targetArr[i] = Array.prototype.slice.call(sourceArr[i]); - } else { - copyArrShallow(targetArr[i], sourceArr[i], len1); - } - } - } else { - copyArrShallow(targetArr, sourceArr, len0); - } - - targetArr.length = sourceArr.length; - } - } else { - target[key] = source[key]; - } - } - - function isValueSame(val1, val2) { - return val1 === val2 || isArrayLike(val1) && isArrayLike(val2) && is1DArraySame(val1, val2); - } - - function is1DArraySame(arr0, arr1) { - var len = arr0.length; - - if (len !== arr1.length) { - return false; - } - - for (var i = 0; i < len; i++) { - if (arr0[i] !== arr1[i]) { - return false; - } - } - - return true; - } - - function animateToShallow(animatable, topKey, animateObj, target, cfg, animationProps, animators, reverse) { - var targetKeys = keys(target); - var duration = cfg.duration; - var delay = cfg.delay; - var additive = cfg.additive; - var setToFinal = cfg.setToFinal; - var animateAll = !isObject$2(animationProps); - var existsAnimators = animatable.animators; - var animationKeys = []; - - for (var k = 0; k < targetKeys.length; k++) { - var innerKey = targetKeys[k]; - var targetVal = target[innerKey]; - - if (targetVal != null && animateObj[innerKey] != null && (animateAll || animationProps[innerKey])) { - if (isObject$2(targetVal) && !isArrayLike(targetVal) && !isGradientObject(targetVal)) { - if (topKey) { - if (!reverse) { - animateObj[innerKey] = targetVal; - animatable.updateDuringAnimation(topKey); - } - - continue; - } - - animateToShallow(animatable, innerKey, animateObj[innerKey], targetVal, cfg, animationProps && animationProps[innerKey], animators, reverse); - } else { - animationKeys.push(innerKey); - } - } else if (!reverse) { - animateObj[innerKey] = targetVal; - animatable.updateDuringAnimation(topKey); - animationKeys.push(innerKey); - } - } - - var keyLen = animationKeys.length; - - if (!additive && keyLen) { - for (var i = 0; i < existsAnimators.length; i++) { - var animator = existsAnimators[i]; - - if (animator.targetName === topKey) { - var allAborted = animator.stopTracks(animationKeys); - - if (allAborted) { - var idx = indexOf(existsAnimators, animator); - existsAnimators.splice(idx, 1); - } - } - } - } - - if (!cfg.force) { - animationKeys = filter(animationKeys, function (key) { - return !isValueSame(target[key], animateObj[key]); - }); - keyLen = animationKeys.length; - } - - if (keyLen > 0 || cfg.force && !animators.length) { - var revertedSource = void 0; - var reversedTarget = void 0; - var sourceClone = void 0; - - if (reverse) { - reversedTarget = {}; - - if (setToFinal) { - revertedSource = {}; - } - - for (var i = 0; i < keyLen; i++) { - var innerKey = animationKeys[i]; - reversedTarget[innerKey] = animateObj[innerKey]; - - if (setToFinal) { - revertedSource[innerKey] = target[innerKey]; - } else { - animateObj[innerKey] = target[innerKey]; - } - } - } else if (setToFinal) { - sourceClone = {}; - - for (var i = 0; i < keyLen; i++) { - var innerKey = animationKeys[i]; - sourceClone[innerKey] = cloneValue(animateObj[innerKey]); - copyValue(animateObj, target, innerKey); - } - } - - var animator = new Animator(animateObj, false, false, additive ? filter(existsAnimators, function (animator) { - return animator.targetName === topKey; - }) : null); - animator.targetName = topKey; - - if (cfg.scope) { - animator.scope = cfg.scope; - } - - if (setToFinal && revertedSource) { - animator.whenWithKeys(0, revertedSource, animationKeys); - } - - if (sourceClone) { - animator.whenWithKeys(0, sourceClone, animationKeys); - } - - animator.whenWithKeys(duration == null ? 500 : duration, reverse ? reversedTarget : target, animationKeys).delay(delay || 0); - animatable.addAnimator(animator, topKey); - animators.push(animator); - } - } - - var Group$2 = function (_super) { - __extends(Group, _super); - - function Group(opts) { - var _this = _super.call(this) || this; - - _this.isGroup = true; - _this._children = []; - - _this.attr(opts); - - return _this; - } - - Group.prototype.childrenRef = function () { - return this._children; - }; - - Group.prototype.children = function () { - return this._children.slice(); - }; - - Group.prototype.childAt = function (idx) { - return this._children[idx]; - }; - - Group.prototype.childOfName = function (name) { - var children = this._children; - - for (var i = 0; i < children.length; i++) { - if (children[i].name === name) { - return children[i]; - } - } - }; - - Group.prototype.childCount = function () { - return this._children.length; - }; - - Group.prototype.add = function (child) { - if (child) { - if (child !== this && child.parent !== this) { - this._children.push(child); - - this._doAdd(child); - } - - { - if (child.__hostTarget) { - throw 'This elemenet has been used as an attachment'; - } - } - } - - return this; - }; - - Group.prototype.addBefore = function (child, nextSibling) { - if (child && child !== this && child.parent !== this && nextSibling && nextSibling.parent === this) { - var children = this._children; - var idx = children.indexOf(nextSibling); - - if (idx >= 0) { - children.splice(idx, 0, child); - - this._doAdd(child); - } - } - - return this; - }; - - Group.prototype.replace = function (oldChild, newChild) { - var idx = indexOf(this._children, oldChild); - - if (idx >= 0) { - this.replaceAt(newChild, idx); - } - - return this; - }; - - Group.prototype.replaceAt = function (child, index) { - var children = this._children; - var old = children[index]; - - if (child && child !== this && child.parent !== this && child !== old) { - children[index] = child; - old.parent = null; - var zr = this.__zr; - - if (zr) { - old.removeSelfFromZr(zr); - } - - this._doAdd(child); - } - - return this; - }; - - Group.prototype._doAdd = function (child) { - if (child.parent) { - child.parent.remove(child); - } - - child.parent = this; - var zr = this.__zr; - - if (zr && zr !== child.__zr) { - child.addSelfToZr(zr); - } - - zr && zr.refresh(); - }; - - Group.prototype.remove = function (child) { - var zr = this.__zr; - var children = this._children; - var idx = indexOf(children, child); - - if (idx < 0) { - return this; - } - - children.splice(idx, 1); - child.parent = null; - - if (zr) { - child.removeSelfFromZr(zr); - } - - zr && zr.refresh(); - return this; - }; - - Group.prototype.removeAll = function () { - var children = this._children; - var zr = this.__zr; - - for (var i = 0; i < children.length; i++) { - var child = children[i]; - - if (zr) { - child.removeSelfFromZr(zr); - } - - child.parent = null; - } - - children.length = 0; - return this; - }; - - Group.prototype.eachChild = function (cb, context) { - var children = this._children; - - for (var i = 0; i < children.length; i++) { - var child = children[i]; - cb.call(context, child, i); - } - - return this; - }; - - Group.prototype.traverse = function (cb, context) { - for (var i = 0; i < this._children.length; i++) { - var child = this._children[i]; - var stopped = cb.call(context, child); - - if (child.isGroup && !stopped) { - child.traverse(cb, context); - } - } - - return this; - }; - - Group.prototype.addSelfToZr = function (zr) { - _super.prototype.addSelfToZr.call(this, zr); - - for (var i = 0; i < this._children.length; i++) { - var child = this._children[i]; - child.addSelfToZr(zr); - } - }; - - Group.prototype.removeSelfFromZr = function (zr) { - _super.prototype.removeSelfFromZr.call(this, zr); - - for (var i = 0; i < this._children.length; i++) { - var child = this._children[i]; - child.removeSelfFromZr(zr); - } - }; - - Group.prototype.getBoundingRect = function (includeChildren) { - var tmpRect = new BoundingRect(0, 0, 0, 0); - var children = includeChildren || this._children; - var tmpMat = []; - var rect = null; - - for (var i = 0; i < children.length; i++) { - var child = children[i]; - - if (child.ignore || child.invisible) { - continue; - } - - var childRect = child.getBoundingRect(); - var transform = child.getLocalTransform(tmpMat); - - if (transform) { - BoundingRect.applyTransform(tmpRect, childRect, transform); - rect = rect || tmpRect.clone(); - rect.union(tmpRect); - } else { - rect = rect || childRect.clone(); - rect.union(childRect); - } - } - - return rect || tmpRect; - }; - - return Group; - }(Element); - - Group$2.prototype.type = 'group'; - /*! - * ZRender, a high performance 2d drawing library. - * - * Copyright (c) 2013, Baidu Inc. - * All rights reserved. - * - * LICENSE - * https://github.com/ecomfe/zrender/blob/master/LICENSE.txt - */ - - var painterCtors = {}; - var instances$1 = {}; - - function delInstance(id) { - delete instances$1[id]; - } - - function isDarkMode(backgroundColor) { - if (!backgroundColor) { - return false; - } - - if (typeof backgroundColor === 'string') { - return lum(backgroundColor, 1) < DARK_MODE_THRESHOLD; - } else if (backgroundColor.colorStops) { - var colorStops = backgroundColor.colorStops; - var totalLum = 0; - var len = colorStops.length; - - for (var i = 0; i < len; i++) { - totalLum += lum(colorStops[i].color, 1); - } - - totalLum /= len; - return totalLum < DARK_MODE_THRESHOLD; - } - - return false; - } - - var ZRender = function () { - function ZRender(id, dom, opts) { - var _this = this; - - this._sleepAfterStill = 10; - this._stillFrameAccum = 0; - this._needsRefresh = true; - this._needsRefreshHover = true; - this._darkMode = false; - opts = opts || {}; - this.dom = dom; - this.id = id; - var storage = new Storage(); - var rendererType = opts.renderer || 'canvas'; - - if (!painterCtors[rendererType]) { - rendererType = keys(painterCtors)[0]; - } - - { - if (!painterCtors[rendererType]) { - throw new Error("Renderer '" + rendererType + "' is not imported. Please import it first."); - } - } - opts.useDirtyRect = opts.useDirtyRect == null ? false : opts.useDirtyRect; - var painter = new painterCtors[rendererType](dom, storage, opts, id); - var ssrMode = opts.ssr || painter.ssrOnly; - this.storage = storage; - this.painter = painter; - var handlerProxy = !env.node && !env.worker && !ssrMode ? new HandlerDomProxy(painter.getViewportRoot(), painter.root) : null; - var useCoarsePointer = opts.useCoarsePointer; - var usePointerSize = useCoarsePointer == null || useCoarsePointer === 'auto' ? env.touchEventsSupported : !!useCoarsePointer; - var defaultPointerSize = 44; - var pointerSize; - - if (usePointerSize) { - pointerSize = retrieve2(opts.pointerSize, defaultPointerSize); - } - - this.handler = new Handler(storage, painter, handlerProxy, painter.root, pointerSize); - this.animation = new Animation({ - stage: { - update: ssrMode ? null : function () { - return _this._flush(true); - } - } - }); - - if (!ssrMode) { - this.animation.start(); - } - } - - ZRender.prototype.add = function (el) { - if (this._disposed || !el) { - return; - } - - this.storage.addRoot(el); - el.addSelfToZr(this); - this.refresh(); - }; - - ZRender.prototype.remove = function (el) { - if (this._disposed || !el) { - return; - } - - this.storage.delRoot(el); - el.removeSelfFromZr(this); - this.refresh(); - }; - - ZRender.prototype.configLayer = function (zLevel, config) { - if (this._disposed) { - return; - } - - if (this.painter.configLayer) { - this.painter.configLayer(zLevel, config); - } - - this.refresh(); - }; - - ZRender.prototype.setBackgroundColor = function (backgroundColor) { - if (this._disposed) { - return; - } - - if (this.painter.setBackgroundColor) { - this.painter.setBackgroundColor(backgroundColor); - } - - this.refresh(); - this._backgroundColor = backgroundColor; - this._darkMode = isDarkMode(backgroundColor); - }; - - ZRender.prototype.getBackgroundColor = function () { - return this._backgroundColor; - }; - - ZRender.prototype.setDarkMode = function (darkMode) { - this._darkMode = darkMode; - }; - - ZRender.prototype.isDarkMode = function () { - return this._darkMode; - }; - - ZRender.prototype.refreshImmediately = function (fromInside) { - if (this._disposed) { - return; - } - - if (!fromInside) { - this.animation.update(true); - } - - this._needsRefresh = false; - this.painter.refresh(); - this._needsRefresh = false; - }; - - ZRender.prototype.refresh = function () { - if (this._disposed) { - return; - } - - this._needsRefresh = true; - this.animation.start(); - }; - - ZRender.prototype.flush = function () { - if (this._disposed) { - return; - } - - this._flush(false); - }; - - ZRender.prototype._flush = function (fromInside) { - var triggerRendered; - var start = getTime(); - - if (this._needsRefresh) { - triggerRendered = true; - this.refreshImmediately(fromInside); - } - - if (this._needsRefreshHover) { - triggerRendered = true; - this.refreshHoverImmediately(); - } - - var end = getTime(); - - if (triggerRendered) { - this._stillFrameAccum = 0; - this.trigger('rendered', { - elapsedTime: end - start - }); - } else if (this._sleepAfterStill > 0) { - this._stillFrameAccum++; - - if (this._stillFrameAccum > this._sleepAfterStill) { - this.animation.stop(); - } - } - }; - - ZRender.prototype.setSleepAfterStill = function (stillFramesCount) { - this._sleepAfterStill = stillFramesCount; - }; - - ZRender.prototype.wakeUp = function () { - if (this._disposed) { - return; - } - - this.animation.start(); - this._stillFrameAccum = 0; - }; - - ZRender.prototype.refreshHover = function () { - this._needsRefreshHover = true; - }; - - ZRender.prototype.refreshHoverImmediately = function () { - if (this._disposed) { - return; - } - - this._needsRefreshHover = false; - - if (this.painter.refreshHover && this.painter.getType() === 'canvas') { - this.painter.refreshHover(); - } - }; - - ZRender.prototype.resize = function (opts) { - if (this._disposed) { - return; - } - - opts = opts || {}; - this.painter.resize(opts.width, opts.height); - this.handler.resize(); - }; - - ZRender.prototype.clearAnimation = function () { - if (this._disposed) { - return; - } - - this.animation.clear(); - }; - - ZRender.prototype.getWidth = function () { - if (this._disposed) { - return; - } - - return this.painter.getWidth(); - }; - - ZRender.prototype.getHeight = function () { - if (this._disposed) { - return; - } - - return this.painter.getHeight(); - }; - - ZRender.prototype.setCursorStyle = function (cursorStyle) { - if (this._disposed) { - return; - } - - this.handler.setCursorStyle(cursorStyle); - }; - - ZRender.prototype.findHover = function (x, y) { - if (this._disposed) { - return; - } - - return this.handler.findHover(x, y); - }; - - ZRender.prototype.on = function (eventName, eventHandler, context) { - if (!this._disposed) { - this.handler.on(eventName, eventHandler, context); - } - - return this; - }; - - ZRender.prototype.off = function (eventName, eventHandler) { - if (this._disposed) { - return; - } - - this.handler.off(eventName, eventHandler); - }; - - ZRender.prototype.trigger = function (eventName, event) { - if (this._disposed) { - return; - } - - this.handler.trigger(eventName, event); - }; - - ZRender.prototype.clear = function () { - if (this._disposed) { - return; - } - - var roots = this.storage.getRoots(); - - for (var i = 0; i < roots.length; i++) { - if (roots[i] instanceof Group$2) { - roots[i].removeSelfFromZr(this); - } - } - - this.storage.delAllRoots(); - this.painter.clear(); - }; - - ZRender.prototype.dispose = function () { - if (this._disposed) { - return; - } - - this.animation.stop(); - this.clear(); - this.storage.dispose(); - this.painter.dispose(); - this.handler.dispose(); - this.animation = this.storage = this.painter = this.handler = null; - this._disposed = true; - delInstance(this.id); - }; - - return ZRender; - }(); - - function init$1(dom, opts) { - var zr = new ZRender(guid(), dom, opts); - instances$1[zr.id] = zr; - return zr; - } - - function dispose$1(zr) { - zr.dispose(); - } - - function disposeAll() { - for (var key in instances$1) { - if (instances$1.hasOwnProperty(key)) { - instances$1[key].dispose(); - } - } - - instances$1 = {}; - } - - function getInstance(id) { - return instances$1[id]; - } - - function registerPainter(name, Ctor) { - painterCtors[name] = Ctor; - } - - var ssrDataGetter; - - function getElementSSRData(el) { - if (typeof ssrDataGetter === 'function') { - return ssrDataGetter(el); - } - } - - function registerSSRDataGetter(getter) { - ssrDataGetter = getter; - } - - var version$1 = '6.0.0'; - var zrender = /*#__PURE__*/Object.freeze({ - __proto__: null, - dispose: dispose$1, - disposeAll: disposeAll, - getElementSSRData: getElementSSRData, - getInstance: getInstance, - init: init$1, - registerPainter: registerPainter, - registerSSRDataGetter: registerSSRDataGetter, - version: version$1 - }); - var RADIAN_EPSILON = 1e-4; // Although chrome already enlarge this number to 100 for `toFixed`, but - // we sill follow the spec for compatibility. - - var ROUND_SUPPORTED_PRECISION_MAX = 20; - - function _trim(str) { - return str.replace(/^\s+|\s+$/g, ''); - } - - var mathMin$6 = Math.min; - var mathMax$6 = Math.max; - var mathAbs$3 = Math.abs; - /** - * Linear mapping a value from domain to range - * @param val - * @param domain Domain extent domain[0] can be bigger than domain[1] - * @param range Range extent range[0] can be bigger than range[1] - * @param clamp Default to be false - */ - - function linearMap(val, domain, range, clamp) { - var d0 = domain[0]; - var d1 = domain[1]; - var r0 = range[0]; - var r1 = range[1]; - var subDomain = d1 - d0; - var subRange = r1 - r0; - - if (subDomain === 0) { - return subRange === 0 ? r0 : (r0 + r1) / 2; - } // Avoid accuracy problem in edge, such as - // 146.39 - 62.83 === 83.55999999999999. - // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError - // It is a little verbose for efficiency considering this method - // is a hotspot. - - - if (clamp) { - if (subDomain > 0) { - if (val <= d0) { - return r0; - } else if (val >= d1) { - return r1; - } - } else { - if (val >= d0) { - return r0; - } else if (val <= d1) { - return r1; - } - } - } else { - if (val === d0) { - return r0; - } - - if (val === d1) { - return r1; - } - } - - return (val - d0) / subDomain * subRange + r0; - } - /** - * Preserve the name `parsePercent` for backward compatibility, - * and it's effectively published as `echarts.number.parsePercent`. - */ - - - var parsePercent = parsePositionOption; - /** - * @see {parsePositionSizeOption} and also accept a string preset. - * @see {PositionSizeOption} - */ - - function parsePositionOption(option, percentBase, percentOffset) { - switch (option) { - case 'center': - case 'middle': - option = '50%'; - break; - - case 'left': - case 'top': - option = '0%'; - break; - - case 'right': - case 'bottom': - option = '100%'; - break; - } - - return parsePositionSizeOption(option, percentBase, percentOffset); - } - /** - * Accept number, or numeric stirng (`'123'`), or percentage ('100%'), as x/y/width/height pixel number. - * If null/undefined or invalid, return NaN. - * (But allow JS type coercion (`+option`) due to backward compatibility) - * @see {PositionSizeOption} - */ - - - function parsePositionSizeOption(option, percentBase, percentOffset) { - if (isString(option)) { - if (_trim(option).match(/%$/)) { - return parseFloat(option) / 100 * percentBase + (percentOffset || 0); - } - - return parseFloat(option); - } // Allow flexible input due to backward compatibility. - - - return option == null ? NaN : +option; - } - - function round$1(x, precision, returnStr) { - if (precision == null) { - // FIXME: the default precision should not be provided, since there is no universally adaptable - // precision. The caller need to input a precision according to the scenarios. - precision = 10; - } // Avoid range error - - - precision = Math.min(Math.max(0, precision), ROUND_SUPPORTED_PRECISION_MAX); // PENDING: 1.005.toFixed(2) is '1.00' rather than '1.01' - - x = (+x).toFixed(precision); - return returnStr ? x : +x; - } - /** - * Inplacd asc sort arr. - * The input arr will be modified. - */ - - - function asc(arr) { - arr.sort(function (a, b) { - return a - b; - }); - return arr; - } - /** - * Get precision. - */ - - - function getPrecision(val) { - val = +val; - - if (isNaN(val)) { - return 0; - } // It is much faster than methods converting number to string as follows - // let tmp = val.toString(); - // return tmp.length - 1 - tmp.indexOf('.'); - // especially when precision is low - // Notice: - // (1) If the loop count is over about 20, it is slower than `getPrecisionSafe`. - // (see https://jsbench.me/2vkpcekkvw/1) - // (2) If the val is less than for example 1e-15, the result may be incorrect. - // (see test/ut/spec/util/number.test.ts `getPrecision_equal_random`) - - - if (val > 1e-14) { - var e = 1; - - for (var i = 0; i < 15; i++, e *= 10) { - if (Math.round(val * e) / e === val) { - return i; - } - } - } - - return getPrecisionSafe(val); - } - /** - * Get precision with slow but safe method - */ - - - function getPrecisionSafe(val) { - // toLowerCase for: '3.4E-12' - var str = val.toString().toLowerCase(); // Consider scientific notation: '3.4e-12' '3.4e+12' - - var eIndex = str.indexOf('e'); - var exp = eIndex > 0 ? +str.slice(eIndex + 1) : 0; - var significandPartLen = eIndex > 0 ? eIndex : str.length; - var dotIndex = str.indexOf('.'); - var decimalPartLen = dotIndex < 0 ? 0 : significandPartLen - 1 - dotIndex; - return Math.max(0, decimalPartLen - exp); - } - /** - * Minimal dicernible data precisioin according to a single pixel. - */ - - - function getPixelPrecision(dataExtent, pixelExtent) { - var log = Math.log; - var LN10 = Math.LN10; - var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10); - var sizeQuantity = Math.round(log(mathAbs$3(pixelExtent[1] - pixelExtent[0])) / LN10); // toFixed() digits argument must be between 0 and 20. - - var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20); - return !isFinite(precision) ? 20 : precision; - } - /** - * Get a data of given precision, assuring the sum of percentages - * in valueList is 1. - * The largest remainder method is used. - * https://en.wikipedia.org/wiki/Largest_remainder_method - * - * @param valueList a list of all data - * @param idx index of the data to be processed in valueList - * @param precision integer number showing digits of precision - * @return percent ranging from 0 to 100 - */ - - - function getPercentWithPrecision(valueList, idx, precision) { - if (!valueList[idx]) { - return 0; - } - - var seats = getPercentSeats(valueList, precision); - return seats[idx] || 0; - } - /** - * Get a data of given precision, assuring the sum of percentages - * in valueList is 1. - * The largest remainder method is used. - * https://en.wikipedia.org/wiki/Largest_remainder_method - * - * @param valueList a list of all data - * @param precision integer number showing digits of precision - * @return {Array} - */ - - - function getPercentSeats(valueList, precision) { - var sum = reduce(valueList, function (acc, val) { - return acc + (isNaN(val) ? 0 : val); - }, 0); - - if (sum === 0) { - return []; - } - - var digits = Math.pow(10, precision); - var votesPerQuota = map$1(valueList, function (val) { - return (isNaN(val) ? 0 : val) / sum * digits * 100; - }); - var targetSeats = digits * 100; - var seats = map$1(votesPerQuota, function (votes) { - // Assign automatic seats. - return Math.floor(votes); - }); - var currentSum = reduce(seats, function (acc, val) { - return acc + val; - }, 0); - var remainder = map$1(votesPerQuota, function (votes, idx) { - return votes - seats[idx]; - }); // Has remainding votes. - - while (currentSum < targetSeats) { - // Find next largest remainder. - var max = Number.NEGATIVE_INFINITY; - var maxId = null; - - for (var i = 0, len = remainder.length; i < len; ++i) { - if (remainder[i] > max) { - max = remainder[i]; - maxId = i; - } - } // Add a vote to max remainder. - - - ++seats[maxId]; - remainder[maxId] = 0; - ++currentSum; - } - - return map$1(seats, function (seat) { - return seat / digits; - }); - } - /** - * Solve the floating point adding problem like 0.1 + 0.2 === 0.30000000000000004 - * See - */ - - - function addSafe(val0, val1) { - var maxPrecision = Math.max(getPrecision(val0), getPrecision(val1)); // const multiplier = Math.pow(10, maxPrecision); - // return (Math.round(val0 * multiplier) + Math.round(val1 * multiplier)) / multiplier; - - var sum = val0 + val1; // // PENDING: support more? - - return maxPrecision > ROUND_SUPPORTED_PRECISION_MAX ? sum : round$1(sum, maxPrecision); - } // Number.MAX_SAFE_INTEGER, ie do not support. - - - var MAX_SAFE_INTEGER = 9007199254740991; - /** - * To 0 - 2 * PI, considering negative radian. - */ - - function remRadian(radian) { - var pi2 = Math.PI * 2; - return (radian % pi2 + pi2) % pi2; - } - /** - * @param {type} radian - * @return {boolean} - */ - - - function isRadianAroundZero(val) { - return val > -RADIAN_EPSILON && val < RADIAN_EPSILON; - } // eslint-disable-next-line - - - var TIME_REG = /^(?:(\d{4})(?:[-\/](\d{1,2})(?:[-\/](\d{1,2})(?:[T ](\d{1,2})(?::(\d{1,2})(?::(\d{1,2})(?:[.,](\d+))?)?)?(Z|[\+\-]\d\d:?\d\d)?)?)?)?)?$/; // jshint ignore:line - - /** - * @param value valid type: number | string | Date, otherwise return `new Date(NaN)` - * These values can be accepted: - * + An instance of Date, represent a time in its own time zone. - * + Or string in a subset of ISO 8601, only including: - * + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06', - * + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123', - * + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00', - * all of which will be treated as local time if time zone is not specified - * (see ). - * + Or other string format, including (all of which will be treated as local time): - * '2012', '2012-3-1', '2012/3/1', '2012/03/01', - * '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123' - * + a timestamp, which represent a time in UTC. - * @return date Never be null/undefined. If invalid, return `new Date(NaN)`. - */ - - function parseDate(value) { - if (value instanceof Date) { - return value; - } else if (isString(value)) { - // Different browsers parse date in different way, so we parse it manually. - // Some other issues: - // new Date('1970-01-01') is UTC, - // new Date('1970/01/01') and new Date('1970-1-01') is local. - // See issue #3623 - var match = TIME_REG.exec(value); - - if (!match) { - // return Invalid Date. - return new Date(NaN); - } // Use local time when no timezone offset is specified. - - - if (!match[8]) { - // match[n] can only be string or undefined. - // But take care of '12' + 1 => '121'. - return new Date(+match[1], +(match[2] || 1) - 1, +match[3] || 1, +match[4] || 0, +(match[5] || 0), +match[6] || 0, match[7] ? +match[7].substring(0, 3) : 0); - } // Timezoneoffset of Javascript Date has considered DST (Daylight Saving Time, - // https://tc39.github.io/ecma262/#sec-daylight-saving-time-adjustment). - // For example, system timezone is set as "Time Zone: America/Toronto", - // then these code will get different result: - // `new Date(1478411999999).getTimezoneOffset(); // get 240` - // `new Date(1478412000000).getTimezoneOffset(); // get 300` - // So we should not use `new Date`, but use `Date.UTC`. - else { - var hour = +match[4] || 0; - - if (match[8].toUpperCase() !== 'Z') { - hour -= +match[8].slice(0, 3); - } - - return new Date(Date.UTC(+match[1], +(match[2] || 1) - 1, +match[3] || 1, hour, +(match[5] || 0), +match[6] || 0, match[7] ? +match[7].substring(0, 3) : 0)); - } - } else if (value == null) { - return new Date(NaN); - } - - return new Date(Math.round(value)); - } - /** - * Quantity of a number. e.g. 0.1, 1, 10, 100 - * - * @param val - * @return - */ - - - function quantity(val) { - return Math.pow(10, quantityExponent(val)); - } - /** - * Exponent of the quantity of a number - * e.g., 1234 equals to 1.234*10^3, so quantityExponent(1234) is 3 - * - * @param val non-negative value - * @return - */ - - - function quantityExponent(val) { - if (val === 0) { - return 0; - } - - var exp = Math.floor(Math.log(val) / Math.LN10); - /** - * exp is expected to be the rounded-down result of the base-10 log of val. - * But due to the precision loss with Math.log(val), we need to restore it - * using 10^exp to make sure we can get val back from exp. #11249 - */ - - if (val / Math.pow(10, exp) >= 10) { - exp++; - } - - return exp; - } - /** - * find a “nice” number approximately equal to x. Round the number if round = true, - * take ceiling if round = false. The primary observation is that the “nicest” - * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers. - * - * See "Nice Numbers for Graph Labels" of Graphic Gems. - * - * @param val Non-negative value. - * @param round - * @return Niced number - */ - - - function nice(val, round) { - var exponent = quantityExponent(val); - var exp10 = Math.pow(10, exponent); - var f = val / exp10; // 1 <= f < 10 - - var nf; - - if (round) { - if (f < 1.5) { - nf = 1; - } else if (f < 2.5) { - nf = 2; - } else if (f < 4) { - nf = 3; - } else if (f < 7) { - nf = 5; - } else { - nf = 10; - } - } else { - if (f < 1) { - nf = 1; - } else if (f < 2) { - nf = 2; - } else if (f < 3) { - nf = 3; - } else if (f < 5) { - nf = 5; - } else { - nf = 10; - } - } - - val = nf * exp10; // Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754). - // 20 is the uppper bound of toFixed. - - return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val; - } - /** - * This code was copied from "d3.js" - * . - * See the license statement at the head of this file. - * @param ascArr - */ - - - function quantile(ascArr, p) { - var H = (ascArr.length - 1) * p + 1; - var h = Math.floor(H); - var v = +ascArr[h - 1]; - var e = H - h; - return e ? v + e * (ascArr[h] - v) : v; - } - /** - * Order intervals asc, and split them when overlap. - * expect(numberUtil.reformIntervals([ - * {interval: [18, 62], close: [1, 1]}, - * {interval: [-Infinity, -70], close: [0, 0]}, - * {interval: [-70, -26], close: [1, 1]}, - * {interval: [-26, 18], close: [1, 1]}, - * {interval: [62, 150], close: [1, 1]}, - * {interval: [106, 150], close: [1, 1]}, - * {interval: [150, Infinity], close: [0, 0]} - * ])).toEqual([ - * {interval: [-Infinity, -70], close: [0, 0]}, - * {interval: [-70, -26], close: [1, 1]}, - * {interval: [-26, 18], close: [0, 1]}, - * {interval: [18, 62], close: [0, 1]}, - * {interval: [62, 150], close: [0, 1]}, - * {interval: [150, Infinity], close: [0, 0]} - * ]); - * @param list, where `close` mean open or close - * of the interval, and Infinity can be used. - * @return The origin list, which has been reformed. - */ - - - function reformIntervals(list) { - list.sort(function (a, b) { - return littleThan(a, b, 0) ? -1 : 1; - }); - var curr = -Infinity; - var currClose = 1; - - for (var i = 0; i < list.length;) { - var interval = list[i].interval; - var close_1 = list[i].close; - - for (var lg = 0; lg < 2; lg++) { - if (interval[lg] <= curr) { - interval[lg] = curr; - close_1[lg] = !lg ? 1 - currClose : 1; - } - - curr = interval[lg]; - currClose = close_1[lg]; - } - - if (interval[0] === interval[1] && close_1[0] * close_1[1] !== 1) { - list.splice(i, 1); - } else { - i++; - } - } - - return list; - - function littleThan(a, b, lg) { - return a.interval[lg] < b.interval[lg] || a.interval[lg] === b.interval[lg] && (a.close[lg] - b.close[lg] === (!lg ? 1 : -1) || !lg && littleThan(a, b, 1)); - } - } - /** - * [Numeric is defined as]: - * `parseFloat(val) == val` - * For example: - * numeric: - * typeof number except NaN, '-123', '123', '2e3', '-2e3', '011', 'Infinity', Infinity, - * and they rounded by white-spaces or line-terminal like ' -123 \n ' (see es spec) - * not-numeric: - * null, undefined, [], {}, true, false, 'NaN', NaN, '123ab', - * empty string, string with only white-spaces or line-terminal (see es spec), - * 0x12, '0x12', '-0x12', 012, '012', '-012', - * non-string, ... - * - * @test See full test cases in `test/ut/spec/util/number.js`. - * @return Must be a typeof number. If not numeric, return NaN. - */ - - - function numericToNumber(val) { - var valFloat = parseFloat(val); - return valFloat == val // eslint-disable-line eqeqeq - && (valFloat !== 0 || !isString(val) || val.indexOf('x') <= 0) // For case ' 0x0 '. - ? valFloat : NaN; - } - /** - * Definition of "numeric": see `numericToNumber`. - */ - - - function isNumeric(val) { - return !isNaN(numericToNumber(val)); - } - /** - * Use random base to prevent users hard code depending on - * this auto generated marker id. - * @return An positive integer. - */ - - - function getRandomIdBase() { - return Math.round(Math.random() * 9); - } - /** - * Get the greatest common divisor. - * - * @param {number} a one number - * @param {number} b the other number - */ - - - function getGreatestCommonDividor(a, b) { - if (b === 0) { - return a; - } - - return getGreatestCommonDividor(b, a % b); - } - /** - * Get the least common multiple. - * - * @param {number} a one number - * @param {number} b the other number - */ - - - function getLeastCommonMultiple(a, b) { - if (a == null) { - return b; - } - - if (b == null) { - return a; - } - - return a * b / getGreatestCommonDividor(a, b); - } - - var ECHARTS_PREFIX = '[ECharts] '; - var storedLogs = {}; - var hasConsole = typeof console !== 'undefined' // eslint-disable-next-line - && console.warn && console.log; - - function outputLog(type, str, onlyOnce) { - if (hasConsole) { - if (onlyOnce) { - if (storedLogs[str]) { - return; - } - - storedLogs[str] = true; - } // eslint-disable-next-line - - - console[type](ECHARTS_PREFIX + str); - } - } - - function log(str, onlyOnce) { - outputLog('log', str, onlyOnce); - } - - function warn(str, onlyOnce) { - outputLog('warn', str, onlyOnce); - } - - function error(str, onlyOnce) { - outputLog('error', str, onlyOnce); - } - - function deprecateLog(str) { - { - // Not display duplicate message. - outputLog('warn', 'DEPRECATED: ' + str, true); - } - } - - function deprecateReplaceLog(oldOpt, newOpt, scope) { - { - deprecateLog((scope ? "[" + scope + "]" : '') + (oldOpt + " is deprecated; use " + newOpt + " instead.")); - } - } - /** - * If in __DEV__ environment, get console printable message for users hint. - * Parameters are separated by ' '. - * @usage - * makePrintable('This is an error on', someVar, someObj); - * - * @param hintInfo anything about the current execution context to hint users. - * @throws Error - */ - - - function makePrintable() { - var hintInfo = []; - - for (var _i = 0; _i < arguments.length; _i++) { - hintInfo[_i] = arguments[_i]; - } - - var msg = ''; - { - // Fuzzy stringify for print. - // This code only exist in dev environment. - var makePrintableStringIfPossible_1 = function (val) { - return val === void 0 ? 'undefined' : val === Infinity ? 'Infinity' : val === -Infinity ? '-Infinity' : eqNaN(val) ? 'NaN' : val instanceof Date ? 'Date(' + val.toISOString() + ')' : isFunction(val) ? 'function () { ... }' : isRegExp(val) ? val + '' : null; - }; - - msg = map$1(hintInfo, function (arg) { - if (isString(arg)) { - // Print without quotation mark for some statement. - return arg; - } else { - var printableStr = makePrintableStringIfPossible_1(arg); - - if (printableStr != null) { - return printableStr; - } else if (typeof JSON !== 'undefined' && JSON.stringify) { - try { - return JSON.stringify(arg, function (n, val) { - var printableStr = makePrintableStringIfPossible_1(val); - return printableStr == null ? val : printableStr; - }); // In most cases the info object is small, so do not line break. - } catch (err) { - return '?'; - } - } else { - return '?'; - } - } - }).join(' '); - } - return msg; - } - /** - * @throws Error - */ - - - function throwError(msg) { - throw new Error(msg); - } - - function interpolateNumber(p0, p1, percent) { - return (p1 - p0) * percent + p0; - } - /** - * Make the name displayable. But we should - * make sure it is not duplicated with user - * specified name, so use '\0'; - */ - - - var DUMMY_COMPONENT_NAME_PREFIX = 'series\0'; - var INTERNAL_COMPONENT_ID_PREFIX = '\0_ec_\0'; - /** - * If value is not array, then translate it to array. - * @param {*} value - * @return {Array} [value] or value - */ - - function normalizeToArray(value) { - return value instanceof Array ? value : value == null ? [] : [value]; - } - /** - * Sync default option between normal and emphasis like `position` and `show` - * In case some one will write code like - * label: { - * show: false, - * position: 'outside', - * fontSize: 18 - * }, - * emphasis: { - * label: { show: true } - * } - */ - - - function defaultEmphasis(opt, key, subOpts) { - // Caution: performance sensitive. - if (opt) { - opt[key] = opt[key] || {}; - opt.emphasis = opt.emphasis || {}; - opt.emphasis[key] = opt.emphasis[key] || {}; // Default emphasis option from normal - - for (var i = 0, len = subOpts.length; i < len; i++) { - var subOptName = subOpts[i]; - - if (!opt.emphasis[key].hasOwnProperty(subOptName) && opt[key].hasOwnProperty(subOptName)) { - opt.emphasis[key][subOptName] = opt[key][subOptName]; - } - } - } - } - - var TEXT_STYLE_OPTIONS = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'rich', 'tag', 'color', 'textBorderColor', 'textBorderWidth', 'width', 'height', 'lineHeight', 'align', 'verticalAlign', 'baseline', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY', 'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY', 'backgroundColor', 'borderColor', 'borderWidth', 'borderRadius', 'padding']; // modelUtil.LABEL_OPTIONS = modelUtil.TEXT_STYLE_OPTIONS.concat([ - // 'position', 'offset', 'rotate', 'origin', 'show', 'distance', 'formatter', - // 'fontStyle', 'fontWeight', 'fontSize', 'fontFamily', - // // FIXME: deprecated, check and remove it. - // 'textStyle' - // ]); - - /** - * The method does not ensure performance. - * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}] - * This helper method retrieves value from data. - */ - - function getDataItemValue(dataItem) { - return isObject$2(dataItem) && !isArray(dataItem) && !(dataItem instanceof Date) ? dataItem.value : dataItem; - } - /** - * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}] - * This helper method determine if dataItem has extra option besides value - */ - - - function isDataItemOption(dataItem) { - return isObject$2(dataItem) && !(dataItem instanceof Array); // // markLine data can be array - // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array)); - } - /** - * Mapping to existings for merge. - * - * Mode "normalMege": - * The mapping result (merge result) will keep the order of the existing - * component, rather than the order of new option. Because we should ensure - * some specified index reference (like xAxisIndex) keep work. - * And in most cases, "merge option" is used to update partial option but not - * be expected to change the order. - * - * Mode "replaceMege": - * (1) Only the id mapped components will be merged. - * (2) Other existing components (except internal components) will be removed. - * (3) Other new options will be used to create new component. - * (4) The index of the existing components will not be modified. - * That means their might be "hole" after the removal. - * The new components are created first at those available index. - * - * Mode "replaceAll": - * This mode try to support that reproduce an echarts instance from another - * echarts instance (via `getOption`) in some simple cases. - * In this scenario, the `result` index are exactly the consistent with the `newCmptOptions`, - * which ensures the component index referring (like `xAxisIndex: ?`) corrent. That is, - * the "hole" in `newCmptOptions` will also be kept. - * On the contrary, other modes try best to eliminate holes. - * PENDING: This is an experimental mode yet. - * - * @return See the comment of . - */ - - - function mappingToExists(existings, newCmptOptions, mode) { - var isNormalMergeMode = mode === 'normalMerge'; - var isReplaceMergeMode = mode === 'replaceMerge'; - var isReplaceAllMode = mode === 'replaceAll'; - existings = existings || []; - newCmptOptions = (newCmptOptions || []).slice(); - var existingIdIdxMap = createHashMap(); // Validate id and name on user input option. - - each$4(newCmptOptions, function (cmptOption, index) { - if (!isObject$2(cmptOption)) { - newCmptOptions[index] = null; - return; - } - - { - // There is some legacy case that name is set as `false`. - // But should work normally rather than throw error. - if (cmptOption.id != null && !isValidIdOrName(cmptOption.id)) { - warnInvalidateIdOrName(cmptOption.id); - } - - if (cmptOption.name != null && !isValidIdOrName(cmptOption.name)) { - warnInvalidateIdOrName(cmptOption.name); - } - } - }); - var result = prepareResult(existings, existingIdIdxMap, mode); - - if (isNormalMergeMode || isReplaceMergeMode) { - mappingById(result, existings, existingIdIdxMap, newCmptOptions); - } - - if (isNormalMergeMode) { - mappingByName(result, newCmptOptions); - } - - if (isNormalMergeMode || isReplaceMergeMode) { - mappingByIndex(result, newCmptOptions, isReplaceMergeMode); - } else if (isReplaceAllMode) { - mappingInReplaceAllMode(result, newCmptOptions); - } - - makeIdAndName(result); // The array `result` MUST NOT contain elided items, otherwise the - // forEach will omit those items and result in incorrect result. - - return result; - } - - function prepareResult(existings, existingIdIdxMap, mode) { - var result = []; - - if (mode === 'replaceAll') { - return result; - } // Do not use native `map` to in case that the array `existings` - // contains elided items, which will be omitted. - - - for (var index = 0; index < existings.length; index++) { - var existing = existings[index]; // Because of replaceMerge, `existing` may be null/undefined. - - if (existing && existing.id != null) { - existingIdIdxMap.set(existing.id, index); - } // For non-internal-componnets: - // Mode "normalMerge": all existings kept. - // Mode "replaceMerge": all existing removed unless mapped by id. - // For internal-components: - // go with "replaceMerge" approach in both mode. - - - result.push({ - existing: mode === 'replaceMerge' || isComponentIdInternal(existing) ? null : existing, - newOption: null, - keyInfo: null, - brandNew: null - }); - } - - return result; - } - - function mappingById(result, existings, existingIdIdxMap, newCmptOptions) { - // Mapping by id if specified. - each$4(newCmptOptions, function (cmptOption, index) { - if (!cmptOption || cmptOption.id == null) { - return; - } - - var optionId = makeComparableKey(cmptOption.id); - var existingIdx = existingIdIdxMap.get(optionId); - - if (existingIdx != null) { - var resultItem = result[existingIdx]; - assert(!resultItem.newOption, 'Duplicated option on id "' + optionId + '".'); - resultItem.newOption = cmptOption; // In both mode, if id matched, new option will be merged to - // the existings rather than creating new component model. - - resultItem.existing = existings[existingIdx]; - newCmptOptions[index] = null; - } - }); - } - - function mappingByName(result, newCmptOptions) { - // Mapping by name if specified. - each$4(newCmptOptions, function (cmptOption, index) { - if (!cmptOption || cmptOption.name == null) { - return; - } - - for (var i = 0; i < result.length; i++) { - var existing = result[i].existing; - - if (!result[i].newOption // Consider name: two map to one. - // Can not match when both ids existing but different. - && existing && (existing.id == null || cmptOption.id == null) && !isComponentIdInternal(cmptOption) && !isComponentIdInternal(existing) && keyExistAndEqual('name', existing, cmptOption)) { - result[i].newOption = cmptOption; - newCmptOptions[index] = null; - return; - } - } - }); - } - - function mappingByIndex(result, newCmptOptions, brandNew) { - each$4(newCmptOptions, function (cmptOption) { - if (!cmptOption) { - return; - } // Find the first place that not mapped by id and not internal component (consider the "hole"). - - - var resultItem; - var nextIdx = 0; - - while ( // Be `!resultItem` only when `nextIdx >= result.length`. - (resultItem = result[nextIdx] // (1) Existing models that already have id should be able to mapped to. Because - // after mapping performed, model will always be assigned with an id if user not given. - // After that all models have id. - // (2) If new option has id, it can only set to a hole or append to the last. It should - // not be merged to the existings with different id. Because id should not be overwritten. - // (3) Name can be overwritten, because axis use name as 'show label text'. - ) && (resultItem.newOption || isComponentIdInternal(resultItem.existing) || // In mode "replaceMerge", here no not-mapped-non-internal-existing. - resultItem.existing && cmptOption.id != null && !keyExistAndEqual('id', cmptOption, resultItem.existing))) { - nextIdx++; - } - - if (resultItem) { - resultItem.newOption = cmptOption; - resultItem.brandNew = brandNew; - } else { - result.push({ - newOption: cmptOption, - brandNew: brandNew, - existing: null, - keyInfo: null - }); - } - - nextIdx++; - }); - } - - function mappingInReplaceAllMode(result, newCmptOptions) { - each$4(newCmptOptions, function (cmptOption) { - // The feature "reproduce" requires "hole" will also reproduced - // in case that component index referring are broken. - result.push({ - newOption: cmptOption, - brandNew: true, - existing: null, - keyInfo: null - }); - }); - } - /** - * Make id and name for mapping result (result of mappingToExists) - * into `keyInfo` field. - */ - - - function makeIdAndName(mapResult) { - // We use this id to hash component models and view instances - // in echarts. id can be specified by user, or auto generated. - // The id generation rule ensures new view instance are able - // to mapped to old instance when setOption are called in - // no-merge mode. So we generate model id by name and plus - // type in view id. - // name can be duplicated among components, which is convenient - // to specify multi components (like series) by one name. - // Ensure that each id is distinct. - var idMap = createHashMap(); - each$4(mapResult, function (item) { - var existing = item.existing; - existing && idMap.set(existing.id, item); - }); - each$4(mapResult, function (item) { - var opt = item.newOption; // Force ensure id not duplicated. - - assert(!opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item, 'id duplicates: ' + (opt && opt.id)); - opt && opt.id != null && idMap.set(opt.id, item); - !item.keyInfo && (item.keyInfo = {}); - }); // Make name and id. - - each$4(mapResult, function (item, index) { - var existing = item.existing; - var opt = item.newOption; - var keyInfo = item.keyInfo; - - if (!isObject$2(opt)) { - return; - } // Name can be overwritten. Consider case: axis.name = '20km'. - // But id generated by name will not be changed, which affect - // only in that case: setOption with 'not merge mode' and view - // instance will be recreated, which can be accepted. - - - keyInfo.name = opt.name != null ? makeComparableKey(opt.name) : existing ? existing.name // Avoid that different series has the same name, - // because name may be used like in color pallet. - : DUMMY_COMPONENT_NAME_PREFIX + index; - - if (existing) { - keyInfo.id = makeComparableKey(existing.id); - } else if (opt.id != null) { - keyInfo.id = makeComparableKey(opt.id); - } else { - // Consider this situatoin: - // optionA: [{name: 'a'}, {name: 'a'}, {..}] - // optionB [{..}, {name: 'a'}, {name: 'a'}] - // Series with the same name between optionA and optionB - // should be mapped. - var idNum = 0; - - do { - keyInfo.id = '\0' + keyInfo.name + '\0' + idNum++; - } while (idMap.get(keyInfo.id)); - } - - idMap.set(keyInfo.id, item); - }); - } - - function keyExistAndEqual(attr, obj1, obj2) { - var key1 = convertOptionIdName(obj1[attr], null); - var key2 = convertOptionIdName(obj2[attr], null); // See `MappingExistingItem`. `id` and `name` trade string equals to number. - - return key1 != null && key2 != null && key1 === key2; - } - /** - * @return return null if not exist. - */ - - - function makeComparableKey(val) { - { - if (val == null) { - throw new Error(); - } - } - return convertOptionIdName(val, ''); - } - - function convertOptionIdName(idOrName, defaultValue) { - if (idOrName == null) { - return defaultValue; - } - - return isString(idOrName) ? idOrName : isNumber(idOrName) || isStringSafe(idOrName) ? idOrName + '' : defaultValue; - } - - function warnInvalidateIdOrName(idOrName) { - { - warn('`' + idOrName + '` is invalid id or name. Must be a string or number.'); - } - } - - function isValidIdOrName(idOrName) { - return isStringSafe(idOrName) || isNumeric(idOrName); - } - - function isNameSpecified(componentModel) { - var name = componentModel.name; // Is specified when `indexOf` get -1 or > 0. - - return !!(name && name.indexOf(DUMMY_COMPONENT_NAME_PREFIX)); - } - /** - * @public - * @param {Object} cmptOption - * @return {boolean} - */ - - - function isComponentIdInternal(cmptOption) { - return cmptOption && cmptOption.id != null && makeComparableKey(cmptOption.id).indexOf(INTERNAL_COMPONENT_ID_PREFIX) === 0; - } - - function setComponentTypeToKeyInfo(mappingResult, mainType, componentModelCtor) { - // Set mainType and complete subType. - each$4(mappingResult, function (item) { - var newOption = item.newOption; - - if (isObject$2(newOption)) { - item.keyInfo.mainType = mainType; - item.keyInfo.subType = determineSubType(mainType, newOption, item.existing, componentModelCtor); - } - }); - } - - function determineSubType(mainType, newCmptOption, existComponent, componentModelCtor) { - var subType = newCmptOption.type ? newCmptOption.type : existComponent ? existComponent.subType // Use determineSubType only when there is no existComponent. - : componentModelCtor.determineSubType(mainType, newCmptOption); // tooltip, markline, markpoint may always has no subType - - return subType; - } - /** - * @param payload Contains dataIndex (means rawIndex) / dataIndexInside / name - * each of which can be Array or primary type. - * @return dataIndex If not found, return undefined/null. - */ - - - function queryDataIndex(data, payload) { - if (payload.dataIndexInside != null) { - return payload.dataIndexInside; - } else if (payload.dataIndex != null) { - return isArray(payload.dataIndex) ? map$1(payload.dataIndex, function (value) { - return data.indexOfRawIndex(value); - }) : data.indexOfRawIndex(payload.dataIndex); - } else if (payload.name != null) { - return isArray(payload.name) ? map$1(payload.name, function (value) { - return data.indexOfName(value); - }) : data.indexOfName(payload.name); - } - } - /** - * Enable property storage to any host object. - * Notice: Serialization is not supported. - * - * For example: - * let inner = zrUitl.makeInner(); - * - * function some1(hostObj) { - * inner(hostObj).someProperty = 1212; - * ... - * } - * function some2() { - * let fields = inner(this); - * fields.someProperty1 = 1212; - * fields.someProperty2 = 'xx'; - * ... - * } - * - * @return {Function} - */ - - - function makeInner() { - var key = '__ec_inner_' + innerUniqueIndex++; - return function (hostObj) { - return hostObj[key] || (hostObj[key] = {}); - }; - } - - var innerUniqueIndex = getRandomIdBase(); - /** - * The same behavior as `component.getReferringComponents`. - */ - - function parseFinder(ecModel, finderInput, opt) { - var _a = preParseFinder(finderInput, opt), - mainTypeSpecified = _a.mainTypeSpecified, - queryOptionMap = _a.queryOptionMap, - others = _a.others; - - var result = others; - var defaultMainType = opt ? opt.defaultMainType : null; - - if (!mainTypeSpecified && defaultMainType) { - queryOptionMap.set(defaultMainType, {}); - } - - queryOptionMap.each(function (queryOption, mainType) { - var queryResult = queryReferringComponents(ecModel, mainType, queryOption, { - useDefault: defaultMainType === mainType, - enableAll: opt && opt.enableAll != null ? opt.enableAll : true, - enableNone: opt && opt.enableNone != null ? opt.enableNone : true - }); - result[mainType + 'Models'] = queryResult.models; - result[mainType + 'Model'] = queryResult.models[0]; - }); - return result; - } - - function preParseFinder(finderInput, opt) { - var finder; - - if (isString(finderInput)) { - var obj = {}; - obj[finderInput + 'Index'] = 0; - finder = obj; - } else { - finder = finderInput; - } - - var queryOptionMap = createHashMap(); - var others = {}; - var mainTypeSpecified = false; - each$4(finder, function (value, key) { - // Exclude 'dataIndex' and other illegal keys. - if (key === 'dataIndex' || key === 'dataIndexInside') { - others[key] = value; - return; - } - - var parsedKey = key.match(/^(\w+)(Index|Id|Name)$/) || []; - var mainType = parsedKey[1]; - var queryType = (parsedKey[2] || '').toLowerCase(); - - if (!mainType || !queryType || opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0) { - return; - } - - mainTypeSpecified = mainTypeSpecified || !!mainType; - var queryOption = queryOptionMap.get(mainType) || queryOptionMap.set(mainType, {}); - queryOption[queryType] = value; - }); - return { - mainTypeSpecified: mainTypeSpecified, - queryOptionMap: queryOptionMap, - others: others - }; - } - - var SINGLE_REFERRING = { - useDefault: true, - enableAll: false, - enableNone: false - }; - - function queryReferringComponents(ecModel, mainType, userOption, opt) { - opt = opt || SINGLE_REFERRING; - var indexOption = userOption.index; - var idOption = userOption.id; - var nameOption = userOption.name; - var result = { - models: null, - specified: indexOption != null || idOption != null || nameOption != null - }; - - if (!result.specified) { - // Use the first as default if `useDefault`. - var firstCmpt = void 0; - result.models = opt.useDefault && (firstCmpt = ecModel.getComponent(mainType)) ? [firstCmpt] : []; - return result; - } - - if (indexOption === 'none' || indexOption === false) { - if (opt.enableNone) { - result.models = []; - return result; - } else { - // Do not throw; consider if some component previously does not use this method, - // and start to use it, need to be fault-tolerant for backward compatibility. - { - error('`"none"` or `false` is not a valid value on index option.'); - } - indexOption = -1; // Can not query by index but may still query by id/name if specified. - } - } // `queryComponents` will return all components if - // both all of index/id/name are null/undefined. - - - if (indexOption === 'all') { - if (opt.enableAll) { - indexOption = idOption = nameOption = null; - } else { - { - error('`"all"` is not a valid value on index option.'); - } - indexOption = -1; - } - } - - result.models = ecModel.queryComponents({ - mainType: mainType, - index: indexOption, - id: idOption, - name: nameOption - }); - return result; - } - - function setAttribute(dom, key, value) { - dom.setAttribute ? dom.setAttribute(key, value) : dom[key] = value; - } - - function getAttribute(dom, key) { - return dom.getAttribute ? dom.getAttribute(key) : dom[key]; - } - - function getTooltipRenderMode(renderModeOption) { - if (renderModeOption === 'auto') { - // Using html when `document` exists, use richText otherwise - return env.domSupported ? 'html' : 'richText'; - } else { - return renderModeOption || 'html'; - } - } - /** - * Interpolate raw values of a series with percent - * - * @param data data - * @param labelModel label model of the text element - * @param sourceValue start value. May be null/undefined when init. - * @param targetValue end value - * @param percent 0~1 percentage; 0 uses start value while 1 uses end value - * @return interpolated values - * If `sourceValue` and `targetValue` are `number`, return `number`. - * If `sourceValue` and `targetValue` are `string`, return `string`. - * If `sourceValue` and `targetValue` are `(string | number)[]`, return `(string | number)[]`. - * Other cases do not supported. - */ - - - function interpolateRawValues(data, precision, sourceValue, targetValue, percent) { - var isAutoPrecision = precision == null || precision === 'auto'; - - if (targetValue == null) { - return targetValue; - } - - if (isNumber(targetValue)) { - var value = interpolateNumber(sourceValue || 0, targetValue, percent); - return round$1(value, isAutoPrecision ? Math.max(getPrecision(sourceValue || 0), getPrecision(targetValue)) : precision); - } else if (isString(targetValue)) { - return percent < 1 ? sourceValue : targetValue; - } else { - var interpolated = []; - var leftArr = sourceValue; - var rightArr = targetValue; - var length_1 = Math.max(leftArr ? leftArr.length : 0, rightArr.length); - - for (var i = 0; i < length_1; ++i) { - var info = data.getDimensionInfo(i); // Don't interpolate ordinal dims - - if (info && info.type === 'ordinal') { - // In init, there is no `sourceValue`, but should better not to get undefined result. - interpolated[i] = (percent < 1 && leftArr ? leftArr : rightArr)[i]; - } else { - var leftVal = leftArr && leftArr[i] ? leftArr[i] : 0; - var rightVal = rightArr[i]; - var value = interpolateNumber(leftVal, rightVal, percent); - interpolated[i] = round$1(value, isAutoPrecision ? Math.max(getPrecision(leftVal), getPrecision(rightVal)) : precision); - } - } - - return interpolated; - } - } - - var TYPE_DELIMITER = '.'; - var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___'; - var IS_EXTENDED_CLASS = '___EC__EXTENDED_CLASS___'; - /** - * Notice, parseClassType('') should returns {main: '', sub: ''} - * @public - */ - - function parseClassType(componentType) { - var ret = { - main: '', - sub: '' - }; - - if (componentType) { - var typeArr = componentType.split(TYPE_DELIMITER); - ret.main = typeArr[0] || ''; - ret.sub = typeArr[1] || ''; - } - - return ret; - } - /** - * @public - */ - - - function checkClassType(componentType) { - assert(/^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType), 'componentType "' + componentType + '" illegal'); - } - - function isExtendedClass(clz) { - return !!(clz && clz[IS_EXTENDED_CLASS]); - } - /** - * Implements `ExtendableConstructor` for `rootClz`. - * - * @usage - * ```ts - * class Xxx {} - * type XxxConstructor = typeof Xxx & ExtendableConstructor - * enableClassExtend(Xxx as XxxConstructor); - * ``` - */ - - - function enableClassExtend(rootClz, mandatoryMethods) { - rootClz.$constructor = rootClz; // FIXME: not necessary? - - rootClz.extend = function (proto) { - { - each$4(mandatoryMethods, function (method) { - if (!proto[method]) { - console.warn('Method `' + method + '` should be implemented' + (proto.type ? ' in ' + proto.type : '') + '.'); - } - }); - } - var superClass = this; - var ExtendedClass; - - if (isESClass(superClass)) { - ExtendedClass = - /** @class */ - function (_super) { - __extends(class_1, _super); - - function class_1() { - return _super.apply(this, arguments) || this; - } - - return class_1; - }(superClass); - } else { - // For backward compat, we both support ts class inheritance and this - // "extend" approach. - // The constructor should keep the same behavior as ts class inheritance: - // If this constructor/$constructor is not declared, auto invoke the super - // constructor. - // If this constructor/$constructor is declared, it is responsible for - // calling the super constructor. - ExtendedClass = function () { - (proto.$constructor || superClass).apply(this, arguments); - }; - - inherits(ExtendedClass, this); - } - - extend(ExtendedClass.prototype, proto); - ExtendedClass[IS_EXTENDED_CLASS] = true; - ExtendedClass.extend = this.extend; - ExtendedClass.superCall = superCall; - ExtendedClass.superApply = superApply; - ExtendedClass.superClass = superClass; - return ExtendedClass; - }; - } - - function isESClass(fn) { - return isFunction(fn) && /^class\s/.test(Function.prototype.toString.call(fn)); - } - /** - * A work around to both support ts extend and this extend mechanism. - * on sub-class. - * @usage - * ```ts - * class Component { ... } - * classUtil.enableClassExtend(Component); - * classUtil.enableClassManagement(Component, {registerWhenExtend: true}); - * - * class Series extends Component { ... } - * // Without calling `markExtend`, `registerWhenExtend` will not work. - * Component.markExtend(Series); - * ``` - */ - - - function mountExtend(SubClz, SupperClz) { - SubClz.extend = SupperClz.extend; - } // A random offset. - - - var classBase = Math.round(Math.random() * 10); - /** - * Implements `CheckableConstructor` for `target`. - * Can not use instanceof, consider different scope by - * cross domain or es module import in ec extensions. - * Mount a method "isInstance()" to Clz. - * - * @usage - * ```ts - * class Xxx {} - * type XxxConstructor = typeof Xxx & CheckableConstructor; - * enableClassCheck(Xxx as XxxConstructor) - * ``` - */ - - function enableClassCheck(target) { - var classAttr = ['__\0is_clz', classBase++].join('_'); - target.prototype[classAttr] = true; - { - assert(!target.isInstance, 'The method "is" can not be defined.'); - } - - target.isInstance = function (obj) { - return !!(obj && obj[classAttr]); - }; - } // superCall should have class info, which can not be fetched from 'this'. - // Consider this case: - // class A has method f, - // class B inherits class A, overrides method f, f call superApply('f'), - // class C inherits class B, does not override method f, - // then when method of class C is called, dead loop occurred. - - - function superCall(context, methodName) { - var args = []; - - for (var _i = 2; _i < arguments.length; _i++) { - args[_i - 2] = arguments[_i]; - } - - return this.superClass.prototype[methodName].apply(context, args); - } - - function superApply(context, methodName, args) { - return this.superClass.prototype[methodName].apply(context, args); - } - /** - * Implements `ClassManager` for `target` - * - * @usage - * ```ts - * class Xxx {} - * type XxxConstructor = typeof Xxx & ClassManager - * enableClassManagement(Xxx as XxxConstructor); - * ``` - */ - - - function enableClassManagement(target) { - /** - * Component model classes - * key: componentType, - * value: - * componentClass, when componentType is 'a' - * or Object., when componentType is 'a.b' - */ - var storage = {}; - - target.registerClass = function (clz) { - // `type` should not be a "instance member". - // If using TS class, should better declared as `static type = 'series.pie'`. - // otherwise users have to mount `type` on prototype manually. - // For backward compat and enable instance visit type via `this.type`, - // we still support fetch `type` from prototype. - var componentFullType = clz.type || clz.prototype.type; - - if (componentFullType) { - checkClassType(componentFullType); // If only static type declared, we assign it to prototype mandatorily. - - clz.prototype.type = componentFullType; - var componentTypeInfo = parseClassType(componentFullType); - - if (!componentTypeInfo.sub) { - { - if (storage[componentTypeInfo.main]) { - console.warn(componentTypeInfo.main + ' exists.'); - } - } - storage[componentTypeInfo.main] = clz; - } else if (componentTypeInfo.sub !== IS_CONTAINER) { - var container = makeContainer(componentTypeInfo); - container[componentTypeInfo.sub] = clz; - } - } - - return clz; - }; - - target.getClass = function (mainType, subType, throwWhenNotFound) { - var clz = storage[mainType]; - - if (clz && clz[IS_CONTAINER]) { - clz = subType ? clz[subType] : null; - } - - if (throwWhenNotFound && !clz) { - throw new Error(!subType ? mainType + '.' + 'type should be specified.' : 'Component ' + mainType + '.' + (subType || '') + ' is used but not imported.'); - } - - return clz; - }; - - target.getClassesByMainType = function (componentType) { - var componentTypeInfo = parseClassType(componentType); - var result = []; - var obj = storage[componentTypeInfo.main]; - - if (obj && obj[IS_CONTAINER]) { - each$4(obj, function (o, type) { - type !== IS_CONTAINER && result.push(o); - }); - } else { - result.push(obj); - } - - return result; - }; - - target.hasClass = function (componentType) { - // Just consider componentType.main. - var componentTypeInfo = parseClassType(componentType); - return !!storage[componentTypeInfo.main]; - }; - /** - * @return Like ['aa', 'bb'], but can not be ['aa.xx'] - */ - - - target.getAllClassMainTypes = function () { - var types = []; - each$4(storage, function (obj, type) { - types.push(type); - }); - return types; - }; - /** - * If a main type is container and has sub types - */ - - - target.hasSubTypes = function (componentType) { - var componentTypeInfo = parseClassType(componentType); - var obj = storage[componentTypeInfo.main]; - return obj && obj[IS_CONTAINER]; - }; - - function makeContainer(componentTypeInfo) { - var container = storage[componentTypeInfo.main]; - - if (!container || !container[IS_CONTAINER]) { - container = storage[componentTypeInfo.main] = {}; - container[IS_CONTAINER] = true; - } - - return container; - } - } // /** - // * @param {string|Array.} properties - // */ - // export function setReadOnly(obj, properties) { - // FIXME It seems broken in IE8 simulation of IE11 - // if (!zrUtil.isArray(properties)) { - // properties = properties != null ? [properties] : []; - // } - // zrUtil.each(properties, function (prop) { - // let value = obj[prop]; - // Object.defineProperty - // && Object.defineProperty(obj, prop, { - // value: value, writable: false - // }); - // zrUtil.isArray(obj[prop]) - // && Object.freeze - // && Object.freeze(obj[prop]); - // }); - // } - - - function makeStyleMapper(properties, ignoreParent) { - // Normalize - for (var i = 0; i < properties.length; i++) { - if (!properties[i][1]) { - properties[i][1] = properties[i][0]; - } - } - - ignoreParent = ignoreParent || false; - return function (model, excludes, includes) { - var style = {}; - - for (var i = 0; i < properties.length; i++) { - var propName = properties[i][1]; - - if (excludes && indexOf(excludes, propName) >= 0 || includes && indexOf(includes, propName) < 0) { - continue; - } - - var val = model.getShallow(propName, ignoreParent); - - if (val != null) { - style[properties[i][0]] = val; - } - } // TODO Text or image? - - - return style; - }; - } - - var AREA_STYLE_KEY_MAP = [['fill', 'color'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['opacity'], ['shadowColor'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`. - // So do not transfer decal directly. - ]; - var getAreaStyle = makeStyleMapper(AREA_STYLE_KEY_MAP); - - var AreaStyleMixin = - /** @class */ - function () { - function AreaStyleMixin() {} - - AreaStyleMixin.prototype.getAreaStyle = function (excludes, includes) { - return getAreaStyle(this, excludes, includes); - }; - - return AreaStyleMixin; - }(); - - var globalImageCache = new LRU(50); - - function findExistImage(newImageOrSrc) { - if (typeof newImageOrSrc === 'string') { - var cachedImgObj = globalImageCache.get(newImageOrSrc); - return cachedImgObj && cachedImgObj.image; - } else { - return newImageOrSrc; - } - } - - function createOrUpdateImage(newImageOrSrc, image, hostEl, onload, cbPayload) { - if (!newImageOrSrc) { - return image; - } else if (typeof newImageOrSrc === 'string') { - if (image && image.__zrImageSrc === newImageOrSrc || !hostEl) { - return image; - } - - var cachedImgObj = globalImageCache.get(newImageOrSrc); - var pendingWrap = { - hostEl: hostEl, - cb: onload, - cbPayload: cbPayload - }; - - if (cachedImgObj) { - image = cachedImgObj.image; - !isImageReady(image) && cachedImgObj.pending.push(pendingWrap); - } else { - image = platformApi.loadImage(newImageOrSrc, imageOnLoad, imageOnLoad); - image.__zrImageSrc = newImageOrSrc; - globalImageCache.put(newImageOrSrc, image.__cachedImgObj = { - image: image, - pending: [pendingWrap] - }); - } - - return image; - } else { - return newImageOrSrc; - } - } - - function imageOnLoad() { - var cachedImgObj = this.__cachedImgObj; - this.onload = this.onerror = this.__cachedImgObj = null; - - for (var i = 0; i < cachedImgObj.pending.length; i++) { - var pendingWrap = cachedImgObj.pending[i]; - var cb = pendingWrap.cb; - cb && cb(this, pendingWrap.cbPayload); - pendingWrap.hostEl.dirty(); - } - - cachedImgObj.pending.length = 0; - } - - function isImageReady(image) { - return image && image.width && image.height; - } - - var STYLE_REG = /\{([a-zA-Z0-9_]+)\|([^}]*)\}/g; - - function truncateText(text, containerWidth, font, ellipsis, options) { - var out = {}; - truncateText2(out, text, containerWidth, font, ellipsis, options); - return out.text; - } - - function truncateText2(out, text, containerWidth, font, ellipsis, options) { - if (!containerWidth) { - out.text = ''; - out.isTruncated = false; - return; - } - - var textLines = (text + '').split('\n'); - options = prepareTruncateOptions(containerWidth, font, ellipsis, options); - var isTruncated = false; - var truncateOut = {}; - - for (var i = 0, len = textLines.length; i < len; i++) { - truncateSingleLine(truncateOut, textLines[i], options); - textLines[i] = truncateOut.textLine; - isTruncated = isTruncated || truncateOut.isTruncated; - } - - out.text = textLines.join('\n'); - out.isTruncated = isTruncated; - } - - function prepareTruncateOptions(containerWidth, font, ellipsis, options) { - options = options || {}; - var preparedOpts = extend({}, options); - ellipsis = retrieve2(ellipsis, '...'); - preparedOpts.maxIterations = retrieve2(options.maxIterations, 2); - var minChar = preparedOpts.minChar = retrieve2(options.minChar, 0); - var fontMeasureInfo = preparedOpts.fontMeasureInfo = ensureFontMeasureInfo(font); - var ascCharWidth = fontMeasureInfo.asciiCharWidth; - preparedOpts.placeholder = retrieve2(options.placeholder, ''); - var contentWidth = containerWidth = Math.max(0, containerWidth - 1); - - for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) { - contentWidth -= ascCharWidth; - } - - var ellipsisWidth = measureWidth(fontMeasureInfo, ellipsis); - - if (ellipsisWidth > contentWidth) { - ellipsis = ''; - ellipsisWidth = 0; - } - - contentWidth = containerWidth - ellipsisWidth; - preparedOpts.ellipsis = ellipsis; - preparedOpts.ellipsisWidth = ellipsisWidth; - preparedOpts.contentWidth = contentWidth; - preparedOpts.containerWidth = containerWidth; - return preparedOpts; - } - - function truncateSingleLine(out, textLine, options) { - var containerWidth = options.containerWidth; - var contentWidth = options.contentWidth; - var fontMeasureInfo = options.fontMeasureInfo; - - if (!containerWidth) { - out.textLine = ''; - out.isTruncated = false; - return; - } - - var lineWidth = measureWidth(fontMeasureInfo, textLine); - - if (lineWidth <= containerWidth) { - out.textLine = textLine; - out.isTruncated = false; - return; - } - - for (var j = 0;; j++) { - if (lineWidth <= contentWidth || j >= options.maxIterations) { - textLine += options.ellipsis; - break; - } - - var subLength = j === 0 ? estimateLength(textLine, contentWidth, fontMeasureInfo) : lineWidth > 0 ? Math.floor(textLine.length * contentWidth / lineWidth) : 0; - textLine = textLine.substr(0, subLength); - lineWidth = measureWidth(fontMeasureInfo, textLine); - } - - if (textLine === '') { - textLine = options.placeholder; - } - - out.textLine = textLine; - out.isTruncated = true; - } - - function estimateLength(text, contentWidth, fontMeasureInfo) { - var width = 0; - var i = 0; - - for (var len = text.length; i < len && width < contentWidth; i++) { - width += measureCharWidth(fontMeasureInfo, text.charCodeAt(i)); - } - - return i; - } - - function parsePlainText(rawText, style, defaultOuterWidth, defaultOuterHeight) { - var text = formatText(rawText); - var overflow = style.overflow; - var padding = style.padding; - var paddingH = padding ? padding[1] + padding[3] : 0; - var paddingV = padding ? padding[0] + padding[2] : 0; - var font = style.font; - var truncate = overflow === 'truncate'; - var calculatedLineHeight = getLineHeight(font); - var lineHeight = retrieve2(style.lineHeight, calculatedLineHeight); - var truncateLineOverflow = style.lineOverflow === 'truncate'; - var isTruncated = false; - var width = style.width; - - if (width == null && defaultOuterWidth != null) { - width = defaultOuterWidth - paddingH; - } - - var height = style.height; - - if (height == null && defaultOuterHeight != null) { - height = defaultOuterHeight - paddingV; - } - - var lines; - - if (width != null && (overflow === 'break' || overflow === 'breakAll')) { - lines = text ? wrapText(text, style.font, width, overflow === 'breakAll', 0).lines : []; - } else { - lines = text ? text.split('\n') : []; - } - - var contentHeight = lines.length * lineHeight; - - if (height == null) { - height = contentHeight; - } - - if (contentHeight > height && truncateLineOverflow) { - var lineCount = Math.floor(height / lineHeight); - isTruncated = isTruncated || lines.length > lineCount; - lines = lines.slice(0, lineCount); - contentHeight = lines.length * lineHeight; - } - - if (text && truncate && width != null) { - var options = prepareTruncateOptions(width, font, style.ellipsis, { - minChar: style.truncateMinChar, - placeholder: style.placeholder - }); - var singleOut = {}; - - for (var i = 0; i < lines.length; i++) { - truncateSingleLine(singleOut, lines[i], options); - lines[i] = singleOut.textLine; - isTruncated = isTruncated || singleOut.isTruncated; - } - } - - var outerHeight = height; - var contentWidth = 0; - var fontMeasureInfo = ensureFontMeasureInfo(font); - - for (var i = 0; i < lines.length; i++) { - contentWidth = Math.max(measureWidth(fontMeasureInfo, lines[i]), contentWidth); - } - - if (width == null) { - width = contentWidth; - } - - var outerWidth = width; - outerHeight += paddingV; - outerWidth += paddingH; - return { - lines: lines, - height: height, - outerWidth: outerWidth, - outerHeight: outerHeight, - lineHeight: lineHeight, - calculatedLineHeight: calculatedLineHeight, - contentWidth: contentWidth, - contentHeight: contentHeight, - width: width, - isTruncated: isTruncated - }; - } - - var RichTextToken = function () { - function RichTextToken() {} - - return RichTextToken; - }(); - - var RichTextLine = function () { - function RichTextLine(tokens) { - this.tokens = []; - - if (tokens) { - this.tokens = tokens; - } - } - - return RichTextLine; - }(); - - var RichTextContentBlock = function () { - function RichTextContentBlock() { - this.width = 0; - this.height = 0; - this.contentWidth = 0; - this.contentHeight = 0; - this.outerWidth = 0; - this.outerHeight = 0; - this.lines = []; - this.isTruncated = false; - } - - return RichTextContentBlock; - }(); - - function parseRichText(rawText, style, defaultOuterWidth, defaultOuterHeight, topTextAlign) { - var contentBlock = new RichTextContentBlock(); - var text = formatText(rawText); - - if (!text) { - return contentBlock; - } - - var stlPadding = style.padding; - var stlPaddingH = stlPadding ? stlPadding[1] + stlPadding[3] : 0; - var stlPaddingV = stlPadding ? stlPadding[0] + stlPadding[2] : 0; - var topWidth = style.width; - - if (topWidth == null && defaultOuterWidth != null) { - topWidth = defaultOuterWidth - stlPaddingH; - } - - var topHeight = style.height; - - if (topHeight == null && defaultOuterHeight != null) { - topHeight = defaultOuterHeight - stlPaddingV; - } - - var overflow = style.overflow; - var wrapInfo = (overflow === 'break' || overflow === 'breakAll') && topWidth != null ? { - width: topWidth, - accumWidth: 0, - breakAll: overflow === 'breakAll' - } : null; - var lastIndex = STYLE_REG.lastIndex = 0; - var result; - - while ((result = STYLE_REG.exec(text)) != null) { - var matchedIndex = result.index; - - if (matchedIndex > lastIndex) { - pushTokens(contentBlock, text.substring(lastIndex, matchedIndex), style, wrapInfo); - } - - pushTokens(contentBlock, result[2], style, wrapInfo, result[1]); - lastIndex = STYLE_REG.lastIndex; - } - - if (lastIndex < text.length) { - pushTokens(contentBlock, text.substring(lastIndex, text.length), style, wrapInfo); - } - - var pendingList = []; - var calculatedHeight = 0; - var calculatedWidth = 0; - var truncate = overflow === 'truncate'; - var truncateLine = style.lineOverflow === 'truncate'; - var tmpTruncateOut = {}; - - function finishLine(line, lineWidth, lineHeight) { - line.width = lineWidth; - line.lineHeight = lineHeight; - calculatedHeight += lineHeight; - calculatedWidth = Math.max(calculatedWidth, lineWidth); - } - - outer: for (var i = 0; i < contentBlock.lines.length; i++) { - var line = contentBlock.lines[i]; - var lineHeight = 0; - var lineWidth = 0; - - for (var j = 0; j < line.tokens.length; j++) { - var token = line.tokens[j]; - var tokenStyle = token.styleName && style.rich[token.styleName] || {}; - var textPadding = token.textPadding = tokenStyle.padding; - var paddingH = textPadding ? textPadding[1] + textPadding[3] : 0; - var font = token.font = tokenStyle.font || style.font; - token.contentHeight = getLineHeight(font); - var tokenHeight = retrieve2(tokenStyle.height, token.contentHeight); - token.innerHeight = tokenHeight; - textPadding && (tokenHeight += textPadding[0] + textPadding[2]); - token.height = tokenHeight; - token.lineHeight = retrieve3(tokenStyle.lineHeight, style.lineHeight, tokenHeight); - token.align = tokenStyle && tokenStyle.align || topTextAlign; - token.verticalAlign = tokenStyle && tokenStyle.verticalAlign || 'middle'; - - if (truncateLine && topHeight != null && calculatedHeight + token.lineHeight > topHeight) { - var originalLength = contentBlock.lines.length; - - if (j > 0) { - line.tokens = line.tokens.slice(0, j); - finishLine(line, lineWidth, lineHeight); - contentBlock.lines = contentBlock.lines.slice(0, i + 1); - } else { - contentBlock.lines = contentBlock.lines.slice(0, i); - } - - contentBlock.isTruncated = contentBlock.isTruncated || contentBlock.lines.length < originalLength; - break outer; - } - - var styleTokenWidth = tokenStyle.width; - var tokenWidthNotSpecified = styleTokenWidth == null || styleTokenWidth === 'auto'; - - if (typeof styleTokenWidth === 'string' && styleTokenWidth.charAt(styleTokenWidth.length - 1) === '%') { - token.percentWidth = styleTokenWidth; - pendingList.push(token); - token.contentWidth = measureWidth(ensureFontMeasureInfo(font), token.text); - } else { - if (tokenWidthNotSpecified) { - var textBackgroundColor = tokenStyle.backgroundColor; - var bgImg = textBackgroundColor && textBackgroundColor.image; - - if (bgImg) { - bgImg = findExistImage(bgImg); - - if (isImageReady(bgImg)) { - token.width = Math.max(token.width, bgImg.width * tokenHeight / bgImg.height); - } - } - } - - var remainTruncWidth = truncate && topWidth != null ? topWidth - lineWidth : null; - - if (remainTruncWidth != null && remainTruncWidth < token.width) { - if (!tokenWidthNotSpecified || remainTruncWidth < paddingH) { - token.text = ''; - token.width = token.contentWidth = 0; - } else { - truncateText2(tmpTruncateOut, token.text, remainTruncWidth - paddingH, font, style.ellipsis, { - minChar: style.truncateMinChar - }); - token.text = tmpTruncateOut.text; - contentBlock.isTruncated = contentBlock.isTruncated || tmpTruncateOut.isTruncated; - token.width = token.contentWidth = measureWidth(ensureFontMeasureInfo(font), token.text); - } - } else { - token.contentWidth = measureWidth(ensureFontMeasureInfo(font), token.text); - } - } - - token.width += paddingH; - lineWidth += token.width; - tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight)); - } - - finishLine(line, lineWidth, lineHeight); - } - - contentBlock.outerWidth = contentBlock.width = retrieve2(topWidth, calculatedWidth); - contentBlock.outerHeight = contentBlock.height = retrieve2(topHeight, calculatedHeight); - contentBlock.contentHeight = calculatedHeight; - contentBlock.contentWidth = calculatedWidth; - contentBlock.outerWidth += stlPaddingH; - contentBlock.outerHeight += stlPaddingV; - - for (var i = 0; i < pendingList.length; i++) { - var token = pendingList[i]; - var percentWidth = token.percentWidth; - token.width = parseInt(percentWidth, 10) / 100 * contentBlock.width; - } - - return contentBlock; - } - - function pushTokens(block, str, style, wrapInfo, styleName) { - var isEmptyStr = str === ''; - var tokenStyle = styleName && style.rich[styleName] || {}; - var lines = block.lines; - var font = tokenStyle.font || style.font; - var newLine = false; - var strLines; - var linesWidths; - - if (wrapInfo) { - var tokenPadding = tokenStyle.padding; - var tokenPaddingH = tokenPadding ? tokenPadding[1] + tokenPadding[3] : 0; - - if (tokenStyle.width != null && tokenStyle.width !== 'auto') { - var outerWidth_1 = parsePercent$1(tokenStyle.width, wrapInfo.width) + tokenPaddingH; - - if (lines.length > 0) { - if (outerWidth_1 + wrapInfo.accumWidth > wrapInfo.width) { - strLines = str.split('\n'); - newLine = true; - } - } - - wrapInfo.accumWidth = outerWidth_1; - } else { - var res = wrapText(str, font, wrapInfo.width, wrapInfo.breakAll, wrapInfo.accumWidth); - wrapInfo.accumWidth = res.accumWidth + tokenPaddingH; - linesWidths = res.linesWidths; - strLines = res.lines; - } - } - - if (!strLines) { - strLines = str.split('\n'); - } - - var fontMeasureInfo = ensureFontMeasureInfo(font); - - for (var i = 0; i < strLines.length; i++) { - var text = strLines[i]; - var token = new RichTextToken(); - token.styleName = styleName; - token.text = text; - token.isLineHolder = !text && !isEmptyStr; - - if (typeof tokenStyle.width === 'number') { - token.width = tokenStyle.width; - } else { - token.width = linesWidths ? linesWidths[i] : measureWidth(fontMeasureInfo, text); - } - - if (!i && !newLine) { - var tokens = (lines[lines.length - 1] || (lines[0] = new RichTextLine())).tokens; - var tokensLen = tokens.length; - tokensLen === 1 && tokens[0].isLineHolder ? tokens[0] = token : (text || !tokensLen || isEmptyStr) && tokens.push(token); - } else { - lines.push(new RichTextLine([token])); - } - } - } - - function isAlphabeticLetter(ch) { - var code = ch.charCodeAt(0); - return code >= 0x20 && code <= 0x24F || code >= 0x370 && code <= 0x10FF || code >= 0x1200 && code <= 0x13FF || code >= 0x1E00 && code <= 0x206F; - } - - var breakCharMap = reduce(',&?/;] '.split(''), function (obj, ch) { - obj[ch] = true; - return obj; - }, {}); - - function isWordBreakChar(ch) { - if (isAlphabeticLetter(ch)) { - if (breakCharMap[ch]) { - return true; - } - - return false; - } - - return true; - } - - function wrapText(text, font, lineWidth, isBreakAll, lastAccumWidth) { - var lines = []; - var linesWidths = []; - var line = ''; - var currentWord = ''; - var currentWordWidth = 0; - var accumWidth = 0; - var fontMeasureInfo = ensureFontMeasureInfo(font); - - for (var i = 0; i < text.length; i++) { - var ch = text.charAt(i); - - if (ch === '\n') { - if (currentWord) { - line += currentWord; - accumWidth += currentWordWidth; - } - - lines.push(line); - linesWidths.push(accumWidth); - line = ''; - currentWord = ''; - currentWordWidth = 0; - accumWidth = 0; - continue; - } - - var chWidth = measureCharWidth(fontMeasureInfo, ch.charCodeAt(0)); - var inWord = isBreakAll ? false : !isWordBreakChar(ch); - - if (!lines.length ? lastAccumWidth + accumWidth + chWidth > lineWidth : accumWidth + chWidth > lineWidth) { - if (!accumWidth) { - if (inWord) { - lines.push(currentWord); - linesWidths.push(currentWordWidth); - currentWord = ch; - currentWordWidth = chWidth; - } else { - lines.push(ch); - linesWidths.push(chWidth); - } - } else if (line || currentWord) { - if (inWord) { - if (!line) { - line = currentWord; - currentWord = ''; - currentWordWidth = 0; - accumWidth = currentWordWidth; - } - - lines.push(line); - linesWidths.push(accumWidth - currentWordWidth); - currentWord += ch; - currentWordWidth += chWidth; - line = ''; - accumWidth = currentWordWidth; - } else { - if (currentWord) { - line += currentWord; - currentWord = ''; - currentWordWidth = 0; - } - - lines.push(line); - linesWidths.push(accumWidth); - line = ch; - accumWidth = chWidth; - } - } - - continue; - } - - accumWidth += chWidth; - - if (inWord) { - currentWord += ch; - currentWordWidth += chWidth; - } else { - if (currentWord) { - line += currentWord; - currentWord = ''; - currentWordWidth = 0; - } - - line += ch; - } - } - - if (currentWord) { - line += currentWord; - } - - if (line) { - lines.push(line); - linesWidths.push(accumWidth); - } - - if (lines.length === 1) { - accumWidth += lastAccumWidth; - } - - return { - accumWidth: accumWidth, - lines: lines, - linesWidths: linesWidths - }; - } - - function calcInnerTextOverflowArea(out, overflowRect, baseX, baseY, textAlign, textVerticalAlign) { - out.baseX = baseX; - out.baseY = baseY; - out.outerWidth = out.outerHeight = null; - - if (!overflowRect) { - return; - } - - var textWidth = overflowRect.width * 2; - var textHeight = overflowRect.height * 2; - BoundingRect.set(tmpCITCTextRect, adjustTextX(baseX, textWidth, textAlign), adjustTextY(baseY, textHeight, textVerticalAlign), textWidth, textHeight); - BoundingRect.intersect(overflowRect, tmpCITCTextRect, null, tmpCITCIntersectRectOpt); - var outIntersectRect = tmpCITCIntersectRectOpt.outIntersectRect; - out.outerWidth = outIntersectRect.width; - out.outerHeight = outIntersectRect.height; - out.baseX = adjustTextX(outIntersectRect.x, outIntersectRect.width, textAlign, true); - out.baseY = adjustTextY(outIntersectRect.y, outIntersectRect.height, textVerticalAlign, true); - } - - var tmpCITCTextRect = new BoundingRect(0, 0, 0, 0); - var tmpCITCIntersectRectOpt = { - outIntersectRect: {}, - clamp: true - }; - - function formatText(text) { - return text != null ? text += '' : text = ''; - } - - function tSpanCreateBoundingRect(style) { - var text = formatText(style.text); - var font = style.font; - var contentWidth = measureWidth(ensureFontMeasureInfo(font), text); - var contentHeight = getLineHeight(font); - return tSpanCreateBoundingRect2(style, contentWidth, contentHeight, null); - } - - function tSpanCreateBoundingRect2(style, contentWidth, contentHeight, forceLineWidth) { - var rect = new BoundingRect(adjustTextX(style.x || 0, contentWidth, style.textAlign), adjustTextY(style.y || 0, contentHeight, style.textBaseline), contentWidth, contentHeight); - var lineWidth = forceLineWidth != null ? forceLineWidth : tSpanHasStroke(style) ? style.lineWidth : 0; - - if (lineWidth > 0) { - rect.x -= lineWidth / 2; - rect.y -= lineWidth / 2; - rect.width += lineWidth; - rect.height += lineWidth; - } - - return rect; - } - - function tSpanHasStroke(style) { - var stroke = style.stroke; - return stroke != null && stroke !== 'none' && style.lineWidth > 0; - } - - var STYLE_MAGIC_KEY = '__zr_style_' + Math.round(Math.random() * 10); - var DEFAULT_COMMON_STYLE = { - shadowBlur: 0, - shadowOffsetX: 0, - shadowOffsetY: 0, - shadowColor: '#000', - opacity: 1, - blend: 'source-over' - }; - var DEFAULT_COMMON_ANIMATION_PROPS = { - style: { - shadowBlur: true, - shadowOffsetX: true, - shadowOffsetY: true, - shadowColor: true, - opacity: true - } - }; - DEFAULT_COMMON_STYLE[STYLE_MAGIC_KEY] = true; - var PRIMARY_STATES_KEYS = ['z', 'z2', 'invisible']; - var PRIMARY_STATES_KEYS_IN_HOVER_LAYER = ['invisible']; - - var Displayable = function (_super) { - __extends(Displayable, _super); - - function Displayable(props) { - return _super.call(this, props) || this; - } - - Displayable.prototype._init = function (props) { - var keysArr = keys(props); - - for (var i = 0; i < keysArr.length; i++) { - var key = keysArr[i]; - - if (key === 'style') { - this.useStyle(props[key]); - } else { - _super.prototype.attrKV.call(this, key, props[key]); - } - } - - if (!this.style) { - this.useStyle({}); - } - }; - - Displayable.prototype.beforeBrush = function () {}; - - Displayable.prototype.afterBrush = function () {}; - - Displayable.prototype.innerBeforeBrush = function () {}; - - Displayable.prototype.innerAfterBrush = function () {}; - - Displayable.prototype.shouldBePainted = function (viewWidth, viewHeight, considerClipPath, considerAncestors) { - var m = this.transform; - - if (this.ignore || this.invisible || this.style.opacity === 0 || this.culling && isDisplayableCulled(this, viewWidth, viewHeight) || m && !m[0] && !m[3]) { - return false; - } - - if (considerClipPath && this.__clipPaths && this.__clipPaths.length) { - for (var i = 0; i < this.__clipPaths.length; ++i) { - if (this.__clipPaths[i].isZeroArea()) { - return false; - } - } - } - - if (considerAncestors && this.parent) { - var parent_1 = this.parent; - - while (parent_1) { - if (parent_1.ignore) { - return false; - } - - parent_1 = parent_1.parent; - } - } - - return true; - }; - - Displayable.prototype.contain = function (x, y) { - return this.rectContain(x, y); - }; - - Displayable.prototype.traverse = function (cb, context) { - cb.call(context, this); - }; - - Displayable.prototype.rectContain = function (x, y) { - var coord = this.transformCoordToLocal(x, y); - var rect = this.getBoundingRect(); - return rect.contain(coord[0], coord[1]); - }; - - Displayable.prototype.getPaintRect = function () { - var rect = this._paintRect; - - if (!this._paintRect || this.__dirty) { - var transform = this.transform; - var elRect = this.getBoundingRect(); - var style = this.style; - var shadowSize = style.shadowBlur || 0; - var shadowOffsetX = style.shadowOffsetX || 0; - var shadowOffsetY = style.shadowOffsetY || 0; - rect = this._paintRect || (this._paintRect = new BoundingRect(0, 0, 0, 0)); - - if (transform) { - BoundingRect.applyTransform(rect, elRect, transform); - } else { - rect.copy(elRect); - } - - if (shadowSize || shadowOffsetX || shadowOffsetY) { - rect.width += shadowSize * 2 + Math.abs(shadowOffsetX); - rect.height += shadowSize * 2 + Math.abs(shadowOffsetY); - rect.x = Math.min(rect.x, rect.x + shadowOffsetX - shadowSize); - rect.y = Math.min(rect.y, rect.y + shadowOffsetY - shadowSize); - } - - var tolerance = this.dirtyRectTolerance; - - if (!rect.isZero()) { - rect.x = Math.floor(rect.x - tolerance); - rect.y = Math.floor(rect.y - tolerance); - rect.width = Math.ceil(rect.width + 1 + tolerance * 2); - rect.height = Math.ceil(rect.height + 1 + tolerance * 2); - } - } - - return rect; - }; - - Displayable.prototype.setPrevPaintRect = function (paintRect) { - if (paintRect) { - this._prevPaintRect = this._prevPaintRect || new BoundingRect(0, 0, 0, 0); - - this._prevPaintRect.copy(paintRect); - } else { - this._prevPaintRect = null; - } - }; - - Displayable.prototype.getPrevPaintRect = function () { - return this._prevPaintRect; - }; - - Displayable.prototype.animateStyle = function (loop) { - return this.animate('style', loop); - }; - - Displayable.prototype.updateDuringAnimation = function (targetKey) { - if (targetKey === 'style') { - this.dirtyStyle(); - } else { - this.markRedraw(); - } - }; - - Displayable.prototype.attrKV = function (key, value) { - if (key !== 'style') { - _super.prototype.attrKV.call(this, key, value); - } else { - if (!this.style) { - this.useStyle(value); - } else { - this.setStyle(value); - } - } - }; - - Displayable.prototype.setStyle = function (keyOrObj, value) { - if (typeof keyOrObj === 'string') { - this.style[keyOrObj] = value; - } else { - extend(this.style, keyOrObj); - } - - this.dirtyStyle(); - return this; - }; - - Displayable.prototype.dirtyStyle = function (notRedraw) { - if (!notRedraw) { - this.markRedraw(); - } - - this.__dirty |= STYLE_CHANGED_BIT; - - if (this._rect) { - this._rect = null; - } - }; - - Displayable.prototype.dirty = function () { - this.dirtyStyle(); - }; - - Displayable.prototype.styleChanged = function () { - return !!(this.__dirty & STYLE_CHANGED_BIT); - }; - - Displayable.prototype.styleUpdated = function () { - this.__dirty &= ~STYLE_CHANGED_BIT; - }; - - Displayable.prototype.createStyle = function (obj) { - return createObject(DEFAULT_COMMON_STYLE, obj); - }; - - Displayable.prototype.useStyle = function (obj) { - if (!obj[STYLE_MAGIC_KEY]) { - obj = this.createStyle(obj); - } - - if (this.__inHover) { - this.__hoverStyle = obj; - } else { - this.style = obj; - } - - this.dirtyStyle(); - }; - - Displayable.prototype.isStyleObject = function (obj) { - return obj[STYLE_MAGIC_KEY]; - }; - - Displayable.prototype._innerSaveToNormal = function (toState) { - _super.prototype._innerSaveToNormal.call(this, toState); - - var normalState = this._normalState; - - if (toState.style && !normalState.style) { - normalState.style = this._mergeStyle(this.createStyle(), this.style); - } - - this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS); - }; - - Displayable.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) { - _super.prototype._applyStateObj.call(this, stateName, state, normalState, keepCurrentStates, transition, animationCfg); - - var needsRestoreToNormal = !(state && keepCurrentStates); - var targetStyle; - - if (state && state.style) { - if (transition) { - if (keepCurrentStates) { - targetStyle = state.style; - } else { - targetStyle = this._mergeStyle(this.createStyle(), normalState.style); - - this._mergeStyle(targetStyle, state.style); - } - } else { - targetStyle = this._mergeStyle(this.createStyle(), keepCurrentStates ? this.style : normalState.style); - - this._mergeStyle(targetStyle, state.style); - } - } else if (needsRestoreToNormal) { - targetStyle = normalState.style; - } - - if (targetStyle) { - if (transition) { - var sourceStyle = this.style; - this.style = this.createStyle(needsRestoreToNormal ? {} : sourceStyle); - - if (needsRestoreToNormal) { - var changedKeys = keys(sourceStyle); - - for (var i = 0; i < changedKeys.length; i++) { - var key = changedKeys[i]; - - if (key in targetStyle) { - targetStyle[key] = targetStyle[key]; - this.style[key] = sourceStyle[key]; - } - } - } - - var targetKeys = keys(targetStyle); - - for (var i = 0; i < targetKeys.length; i++) { - var key = targetKeys[i]; - this.style[key] = this.style[key]; - } - - this._transitionState(stateName, { - style: targetStyle - }, animationCfg, this.getAnimationStyleProps()); - } else { - this.useStyle(targetStyle); - } - } - - var statesKeys = this.__inHover ? PRIMARY_STATES_KEYS_IN_HOVER_LAYER : PRIMARY_STATES_KEYS; - - for (var i = 0; i < statesKeys.length; i++) { - var key = statesKeys[i]; - - if (state && state[key] != null) { - this[key] = state[key]; - } else if (needsRestoreToNormal) { - if (normalState[key] != null) { - this[key] = normalState[key]; - } - } - } - }; - - Displayable.prototype._mergeStates = function (states) { - var mergedState = _super.prototype._mergeStates.call(this, states); - - var mergedStyle; - - for (var i = 0; i < states.length; i++) { - var state = states[i]; - - if (state.style) { - mergedStyle = mergedStyle || {}; - - this._mergeStyle(mergedStyle, state.style); - } - } - - if (mergedStyle) { - mergedState.style = mergedStyle; - } - - return mergedState; - }; - - Displayable.prototype._mergeStyle = function (targetStyle, sourceStyle) { - extend(targetStyle, sourceStyle); - return targetStyle; - }; - - Displayable.prototype.getAnimationStyleProps = function () { - return DEFAULT_COMMON_ANIMATION_PROPS; - }; - - Displayable.initDefaultProps = function () { - var dispProto = Displayable.prototype; - dispProto.type = 'displayable'; - dispProto.invisible = false; - dispProto.z = 0; - dispProto.z2 = 0; - dispProto.zlevel = 0; - dispProto.culling = false; - dispProto.cursor = 'pointer'; - dispProto.rectHover = false; - dispProto.incremental = false; - dispProto._rect = null; - dispProto.dirtyRectTolerance = 0; - dispProto.__dirty = REDRAW_BIT | STYLE_CHANGED_BIT; - }(); - - return Displayable; - }(Element); - - var tmpRect = new BoundingRect(0, 0, 0, 0); - var viewRect = new BoundingRect(0, 0, 0, 0); - - function isDisplayableCulled(el, width, height) { - tmpRect.copy(el.getBoundingRect()); - - if (el.transform) { - tmpRect.applyTransform(el.transform); - } - - viewRect.width = width; - viewRect.height = height; - return !tmpRect.intersect(viewRect); - } - - var mathMin$5 = Math.min; - var mathMax$5 = Math.max; - var mathSin$3 = Math.sin; - var mathCos$3 = Math.cos; - var PI2$6 = Math.PI * 2; - var start = create$1(); - var end = create$1(); - var extremity = create$1(); - - function fromLine(x0, y0, x1, y1, min, max) { - min[0] = mathMin$5(x0, x1); - min[1] = mathMin$5(y0, y1); - max[0] = mathMax$5(x0, x1); - max[1] = mathMax$5(y0, y1); - } - - var xDim = []; - var yDim = []; - - function fromCubic(x0, y0, x1, y1, x2, y2, x3, y3, min, max) { - var cubicExtrema$1 = cubicExtrema; - var cubicAt$1 = cubicAt; - var n = cubicExtrema$1(x0, x1, x2, x3, xDim); - min[0] = Infinity; - min[1] = Infinity; - max[0] = -Infinity; - max[1] = -Infinity; - - for (var i = 0; i < n; i++) { - var x = cubicAt$1(x0, x1, x2, x3, xDim[i]); - min[0] = mathMin$5(x, min[0]); - max[0] = mathMax$5(x, max[0]); - } - - n = cubicExtrema$1(y0, y1, y2, y3, yDim); - - for (var i = 0; i < n; i++) { - var y = cubicAt$1(y0, y1, y2, y3, yDim[i]); - min[1] = mathMin$5(y, min[1]); - max[1] = mathMax$5(y, max[1]); - } - - min[0] = mathMin$5(x0, min[0]); - max[0] = mathMax$5(x0, max[0]); - min[0] = mathMin$5(x3, min[0]); - max[0] = mathMax$5(x3, max[0]); - min[1] = mathMin$5(y0, min[1]); - max[1] = mathMax$5(y0, max[1]); - min[1] = mathMin$5(y3, min[1]); - max[1] = mathMax$5(y3, max[1]); - } - - function fromQuadratic(x0, y0, x1, y1, x2, y2, min, max) { - var quadraticExtremum$1 = quadraticExtremum; - var quadraticAt$1 = quadraticAt; - var tx = mathMax$5(mathMin$5(quadraticExtremum$1(x0, x1, x2), 1), 0); - var ty = mathMax$5(mathMin$5(quadraticExtremum$1(y0, y1, y2), 1), 0); - var x = quadraticAt$1(x0, x1, x2, tx); - var y = quadraticAt$1(y0, y1, y2, ty); - min[0] = mathMin$5(x0, x2, x); - min[1] = mathMin$5(y0, y2, y); - max[0] = mathMax$5(x0, x2, x); - max[1] = mathMax$5(y0, y2, y); - } - - function fromArc(x, y, rx, ry, startAngle, endAngle, anticlockwise, min, max) { - var vec2Min = min$1; - var vec2Max = max$1; - var diff = Math.abs(startAngle - endAngle); - - if (diff % PI2$6 < 1e-4 && diff > 1e-4) { - min[0] = x - rx; - min[1] = y - ry; - max[0] = x + rx; - max[1] = y + ry; - return; - } - - start[0] = mathCos$3(startAngle) * rx + x; - start[1] = mathSin$3(startAngle) * ry + y; - end[0] = mathCos$3(endAngle) * rx + x; - end[1] = mathSin$3(endAngle) * ry + y; - vec2Min(min, start, end); - vec2Max(max, start, end); - startAngle = startAngle % PI2$6; - - if (startAngle < 0) { - startAngle = startAngle + PI2$6; - } - - endAngle = endAngle % PI2$6; - - if (endAngle < 0) { - endAngle = endAngle + PI2$6; - } - - if (startAngle > endAngle && !anticlockwise) { - endAngle += PI2$6; - } else if (startAngle < endAngle && anticlockwise) { - startAngle += PI2$6; - } - - if (anticlockwise) { - var tmp = endAngle; - endAngle = startAngle; - startAngle = tmp; - } - - for (var angle = 0; angle < endAngle; angle += Math.PI / 2) { - if (angle > startAngle) { - extremity[0] = mathCos$3(angle) * rx + x; - extremity[1] = mathSin$3(angle) * ry + y; - vec2Min(min, extremity, min); - vec2Max(max, extremity, max); - } - } - } - - var CMD$3 = { - M: 1, - L: 2, - C: 3, - Q: 4, - A: 5, - Z: 6, - R: 7 - }; - var tmpOutX = []; - var tmpOutY = []; - var min = []; - var max = []; - var min2 = []; - var max2 = []; - var mathMin$4 = Math.min; - var mathMax$4 = Math.max; - var mathCos$2 = Math.cos; - var mathSin$2 = Math.sin; - var mathAbs$2 = Math.abs; - var PI$4 = Math.PI; - var PI2$5 = PI$4 * 2; - var hasTypedArray = typeof Float32Array !== 'undefined'; - var tmpAngles = []; - - function modPI2(radian) { - var n = Math.round(radian / PI$4 * 1e8) / 1e8; - return n % 2 * PI$4; - } - - function normalizeArcAngles(angles, anticlockwise) { - var newStartAngle = modPI2(angles[0]); - - if (newStartAngle < 0) { - newStartAngle += PI2$5; - } - - var delta = newStartAngle - angles[0]; - var newEndAngle = angles[1]; - newEndAngle += delta; - - if (!anticlockwise && newEndAngle - newStartAngle >= PI2$5) { - newEndAngle = newStartAngle + PI2$5; - } else if (anticlockwise && newStartAngle - newEndAngle >= PI2$5) { - newEndAngle = newStartAngle - PI2$5; - } else if (!anticlockwise && newStartAngle > newEndAngle) { - newEndAngle = newStartAngle + (PI2$5 - modPI2(newStartAngle - newEndAngle)); - } else if (anticlockwise && newStartAngle < newEndAngle) { - newEndAngle = newStartAngle - (PI2$5 - modPI2(newEndAngle - newStartAngle)); - } - - angles[0] = newStartAngle; - angles[1] = newEndAngle; - } - - var PathProxy = function () { - function PathProxy(notSaveData) { - this.dpr = 1; - this._xi = 0; - this._yi = 0; - this._x0 = 0; - this._y0 = 0; - this._len = 0; - - if (notSaveData) { - this._saveData = false; - } - - if (this._saveData) { - this.data = []; - } - } - - PathProxy.prototype.increaseVersion = function () { - this._version++; - }; - - PathProxy.prototype.getVersion = function () { - return this._version; - }; - - PathProxy.prototype.setScale = function (sx, sy, segmentIgnoreThreshold) { - segmentIgnoreThreshold = segmentIgnoreThreshold || 0; - - if (segmentIgnoreThreshold > 0) { - this._ux = mathAbs$2(segmentIgnoreThreshold / devicePixelRatio / sx) || 0; - this._uy = mathAbs$2(segmentIgnoreThreshold / devicePixelRatio / sy) || 0; - } - }; - - PathProxy.prototype.setDPR = function (dpr) { - this.dpr = dpr; - }; - - PathProxy.prototype.setContext = function (ctx) { - this._ctx = ctx; - }; - - PathProxy.prototype.getContext = function () { - return this._ctx; - }; - - PathProxy.prototype.beginPath = function () { - this._ctx && this._ctx.beginPath(); - this.reset(); - return this; - }; - - PathProxy.prototype.reset = function () { - if (this._saveData) { - this._len = 0; - } - - if (this._pathSegLen) { - this._pathSegLen = null; - this._pathLen = 0; - } - - this._version++; - }; - - PathProxy.prototype.moveTo = function (x, y) { - this._drawPendingPt(); - - this.addData(CMD$3.M, x, y); - this._ctx && this._ctx.moveTo(x, y); - this._x0 = x; - this._y0 = y; - this._xi = x; - this._yi = y; - return this; - }; - - PathProxy.prototype.lineTo = function (x, y) { - var dx = mathAbs$2(x - this._xi); - var dy = mathAbs$2(y - this._yi); - var exceedUnit = dx > this._ux || dy > this._uy; - this.addData(CMD$3.L, x, y); - - if (this._ctx && exceedUnit) { - this._ctx.lineTo(x, y); - } - - if (exceedUnit) { - this._xi = x; - this._yi = y; - this._pendingPtDist = 0; - } else { - var d2 = dx * dx + dy * dy; - - if (d2 > this._pendingPtDist) { - this._pendingPtX = x; - this._pendingPtY = y; - this._pendingPtDist = d2; - } - } - - return this; - }; - - PathProxy.prototype.bezierCurveTo = function (x1, y1, x2, y2, x3, y3) { - this._drawPendingPt(); - - this.addData(CMD$3.C, x1, y1, x2, y2, x3, y3); - - if (this._ctx) { - this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3); - } - - this._xi = x3; - this._yi = y3; - return this; - }; - - PathProxy.prototype.quadraticCurveTo = function (x1, y1, x2, y2) { - this._drawPendingPt(); - - this.addData(CMD$3.Q, x1, y1, x2, y2); - - if (this._ctx) { - this._ctx.quadraticCurveTo(x1, y1, x2, y2); - } - - this._xi = x2; - this._yi = y2; - return this; - }; - - PathProxy.prototype.arc = function (cx, cy, r, startAngle, endAngle, anticlockwise) { - this._drawPendingPt(); - - tmpAngles[0] = startAngle; - tmpAngles[1] = endAngle; - normalizeArcAngles(tmpAngles, anticlockwise); - startAngle = tmpAngles[0]; - endAngle = tmpAngles[1]; - var delta = endAngle - startAngle; - this.addData(CMD$3.A, cx, cy, r, r, startAngle, delta, 0, anticlockwise ? 0 : 1); - this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise); - this._xi = mathCos$2(endAngle) * r + cx; - this._yi = mathSin$2(endAngle) * r + cy; - return this; - }; - - PathProxy.prototype.arcTo = function (x1, y1, x2, y2, radius) { - this._drawPendingPt(); - - if (this._ctx) { - this._ctx.arcTo(x1, y1, x2, y2, radius); - } - - return this; - }; - - PathProxy.prototype.rect = function (x, y, w, h) { - this._drawPendingPt(); - - this._ctx && this._ctx.rect(x, y, w, h); - this.addData(CMD$3.R, x, y, w, h); - return this; - }; - - PathProxy.prototype.closePath = function () { - this._drawPendingPt(); - - this.addData(CMD$3.Z); - var ctx = this._ctx; - var x0 = this._x0; - var y0 = this._y0; - - if (ctx) { - ctx.closePath(); - } - - this._xi = x0; - this._yi = y0; - return this; - }; - - PathProxy.prototype.fill = function (ctx) { - ctx && ctx.fill(); - this.toStatic(); - }; - - PathProxy.prototype.stroke = function (ctx) { - ctx && ctx.stroke(); - this.toStatic(); - }; - - PathProxy.prototype.len = function () { - return this._len; - }; - - PathProxy.prototype.setData = function (data) { - if (!this._saveData) { - return; - } - - var len = data.length; - - if (!(this.data && this.data.length === len) && hasTypedArray) { - this.data = new Float32Array(len); - } - - for (var i = 0; i < len; i++) { - this.data[i] = data[i]; - } - - this._len = len; - }; - - PathProxy.prototype.appendPath = function (path) { - if (!this._saveData) { - return; - } - - if (!(path instanceof Array)) { - path = [path]; - } - - var len = path.length; - var appendSize = 0; - var offset = this._len; - - for (var i = 0; i < len; i++) { - appendSize += path[i].len(); - } - - var oldData = this.data; - - if (hasTypedArray && (oldData instanceof Float32Array || !oldData)) { - this.data = new Float32Array(offset + appendSize); - - if (offset > 0 && oldData) { - for (var k = 0; k < offset; k++) { - this.data[k] = oldData[k]; - } - } - } - - for (var i = 0; i < len; i++) { - var appendPathData = path[i].data; - - for (var k = 0; k < appendPathData.length; k++) { - this.data[offset++] = appendPathData[k]; - } - } - - this._len = offset; - }; - - PathProxy.prototype.addData = function (cmd, a, b, c, d, e, f, g, h) { - if (!this._saveData) { - return; - } - - var data = this.data; - - if (this._len + arguments.length > data.length) { - this._expandData(); - - data = this.data; - } - - for (var i = 0; i < arguments.length; i++) { - data[this._len++] = arguments[i]; - } - }; - - PathProxy.prototype._drawPendingPt = function () { - if (this._pendingPtDist > 0) { - this._ctx && this._ctx.lineTo(this._pendingPtX, this._pendingPtY); - this._pendingPtDist = 0; - } - }; - - PathProxy.prototype._expandData = function () { - if (!(this.data instanceof Array)) { - var newData = []; - - for (var i = 0; i < this._len; i++) { - newData[i] = this.data[i]; - } - - this.data = newData; - } - }; - - PathProxy.prototype.toStatic = function () { - if (!this._saveData) { - return; - } - - this._drawPendingPt(); - - var data = this.data; - - if (data instanceof Array) { - data.length = this._len; - - if (hasTypedArray && this._len > 11) { - this.data = new Float32Array(data); - } - } - }; - - PathProxy.prototype.getBoundingRect = function () { - min[0] = min[1] = min2[0] = min2[1] = Number.MAX_VALUE; - max[0] = max[1] = max2[0] = max2[1] = -Number.MAX_VALUE; - var data = this.data; - var xi = 0; - var yi = 0; - var x0 = 0; - var y0 = 0; - var i; - - for (i = 0; i < this._len;) { - var cmd = data[i++]; - var isFirst = i === 1; - - if (isFirst) { - xi = data[i]; - yi = data[i + 1]; - x0 = xi; - y0 = yi; - } - - switch (cmd) { - case CMD$3.M: - xi = x0 = data[i++]; - yi = y0 = data[i++]; - min2[0] = x0; - min2[1] = y0; - max2[0] = x0; - max2[1] = y0; - break; - - case CMD$3.L: - fromLine(xi, yi, data[i], data[i + 1], min2, max2); - xi = data[i++]; - yi = data[i++]; - break; - - case CMD$3.C: - fromCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], min2, max2); - xi = data[i++]; - yi = data[i++]; - break; - - case CMD$3.Q: - fromQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], min2, max2); - xi = data[i++]; - yi = data[i++]; - break; - - case CMD$3.A: - var cx = data[i++]; - var cy = data[i++]; - var rx = data[i++]; - var ry = data[i++]; - var startAngle = data[i++]; - var endAngle = data[i++] + startAngle; - i += 1; - var anticlockwise = !data[i++]; - - if (isFirst) { - x0 = mathCos$2(startAngle) * rx + cx; - y0 = mathSin$2(startAngle) * ry + cy; - } - - fromArc(cx, cy, rx, ry, startAngle, endAngle, anticlockwise, min2, max2); - xi = mathCos$2(endAngle) * rx + cx; - yi = mathSin$2(endAngle) * ry + cy; - break; - - case CMD$3.R: - x0 = xi = data[i++]; - y0 = yi = data[i++]; - var width = data[i++]; - var height = data[i++]; - fromLine(x0, y0, x0 + width, y0 + height, min2, max2); - break; - - case CMD$3.Z: - xi = x0; - yi = y0; - break; - } - - min$1(min, min, min2); - max$1(max, max, max2); - } - - if (i === 0) { - min[0] = min[1] = max[0] = max[1] = 0; - } - - return new BoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]); - }; - - PathProxy.prototype._calculateLength = function () { - var data = this.data; - var len = this._len; - var ux = this._ux; - var uy = this._uy; - var xi = 0; - var yi = 0; - var x0 = 0; - var y0 = 0; - - if (!this._pathSegLen) { - this._pathSegLen = []; - } - - var pathSegLen = this._pathSegLen; - var pathTotalLen = 0; - var segCount = 0; - - for (var i = 0; i < len;) { - var cmd = data[i++]; - var isFirst = i === 1; - - if (isFirst) { - xi = data[i]; - yi = data[i + 1]; - x0 = xi; - y0 = yi; - } - - var l = -1; - - switch (cmd) { - case CMD$3.M: - xi = x0 = data[i++]; - yi = y0 = data[i++]; - break; - - case CMD$3.L: - { - var x2 = data[i++]; - var y2 = data[i++]; - var dx = x2 - xi; - var dy = y2 - yi; - - if (mathAbs$2(dx) > ux || mathAbs$2(dy) > uy || i === len - 1) { - l = Math.sqrt(dx * dx + dy * dy); - xi = x2; - yi = y2; - } - - break; - } - - case CMD$3.C: - { - var x1 = data[i++]; - var y1 = data[i++]; - var x2 = data[i++]; - var y2 = data[i++]; - var x3 = data[i++]; - var y3 = data[i++]; - l = cubicLength(xi, yi, x1, y1, x2, y2, x3, y3, 10); - xi = x3; - yi = y3; - break; - } - - case CMD$3.Q: - { - var x1 = data[i++]; - var y1 = data[i++]; - var x2 = data[i++]; - var y2 = data[i++]; - l = quadraticLength(xi, yi, x1, y1, x2, y2, 10); - xi = x2; - yi = y2; - break; - } - - case CMD$3.A: - var cx = data[i++]; - var cy = data[i++]; - var rx = data[i++]; - var ry = data[i++]; - var startAngle = data[i++]; - var delta = data[i++]; - var endAngle = delta + startAngle; - i += 1; - - if (isFirst) { - x0 = mathCos$2(startAngle) * rx + cx; - y0 = mathSin$2(startAngle) * ry + cy; - } - - l = mathMax$4(rx, ry) * mathMin$4(PI2$5, Math.abs(delta)); - xi = mathCos$2(endAngle) * rx + cx; - yi = mathSin$2(endAngle) * ry + cy; - break; - - case CMD$3.R: - { - x0 = xi = data[i++]; - y0 = yi = data[i++]; - var width = data[i++]; - var height = data[i++]; - l = width * 2 + height * 2; - break; - } - - case CMD$3.Z: - { - var dx = x0 - xi; - var dy = y0 - yi; - l = Math.sqrt(dx * dx + dy * dy); - xi = x0; - yi = y0; - break; - } - } - - if (l >= 0) { - pathSegLen[segCount++] = l; - pathTotalLen += l; - } - } - - this._pathLen = pathTotalLen; - return pathTotalLen; - }; - - PathProxy.prototype.rebuildPath = function (ctx, percent) { - var d = this.data; - var ux = this._ux; - var uy = this._uy; - var len = this._len; - var x0; - var y0; - var xi; - var yi; - var x; - var y; - var drawPart = percent < 1; - var pathSegLen; - var pathTotalLen; - var accumLength = 0; - var segCount = 0; - var displayedLength; - var pendingPtDist = 0; - var pendingPtX; - var pendingPtY; - - if (drawPart) { - if (!this._pathSegLen) { - this._calculateLength(); - } - - pathSegLen = this._pathSegLen; - pathTotalLen = this._pathLen; - displayedLength = percent * pathTotalLen; - - if (!displayedLength) { - return; - } - } - - lo: for (var i = 0; i < len;) { - var cmd = d[i++]; - var isFirst = i === 1; - - if (isFirst) { - xi = d[i]; - yi = d[i + 1]; - x0 = xi; - y0 = yi; - } - - if (cmd !== CMD$3.L && pendingPtDist > 0) { - ctx.lineTo(pendingPtX, pendingPtY); - pendingPtDist = 0; - } - - switch (cmd) { - case CMD$3.M: - x0 = xi = d[i++]; - y0 = yi = d[i++]; - ctx.moveTo(xi, yi); - break; - - case CMD$3.L: - { - x = d[i++]; - y = d[i++]; - var dx = mathAbs$2(x - xi); - var dy = mathAbs$2(y - yi); - - if (dx > ux || dy > uy) { - if (drawPart) { - var l = pathSegLen[segCount++]; - - if (accumLength + l > displayedLength) { - var t = (displayedLength - accumLength) / l; - ctx.lineTo(xi * (1 - t) + x * t, yi * (1 - t) + y * t); - break lo; - } - - accumLength += l; - } - - ctx.lineTo(x, y); - xi = x; - yi = y; - pendingPtDist = 0; - } else { - var d2 = dx * dx + dy * dy; - - if (d2 > pendingPtDist) { - pendingPtX = x; - pendingPtY = y; - pendingPtDist = d2; - } - } - - break; - } - - case CMD$3.C: - { - var x1 = d[i++]; - var y1 = d[i++]; - var x2 = d[i++]; - var y2 = d[i++]; - var x3 = d[i++]; - var y3 = d[i++]; - - if (drawPart) { - var l = pathSegLen[segCount++]; - - if (accumLength + l > displayedLength) { - var t = (displayedLength - accumLength) / l; - cubicSubdivide(xi, x1, x2, x3, t, tmpOutX); - cubicSubdivide(yi, y1, y2, y3, t, tmpOutY); - ctx.bezierCurveTo(tmpOutX[1], tmpOutY[1], tmpOutX[2], tmpOutY[2], tmpOutX[3], tmpOutY[3]); - break lo; - } - - accumLength += l; - } - - ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3); - xi = x3; - yi = y3; - break; - } - - case CMD$3.Q: - { - var x1 = d[i++]; - var y1 = d[i++]; - var x2 = d[i++]; - var y2 = d[i++]; - - if (drawPart) { - var l = pathSegLen[segCount++]; - - if (accumLength + l > displayedLength) { - var t = (displayedLength - accumLength) / l; - quadraticSubdivide(xi, x1, x2, t, tmpOutX); - quadraticSubdivide(yi, y1, y2, t, tmpOutY); - ctx.quadraticCurveTo(tmpOutX[1], tmpOutY[1], tmpOutX[2], tmpOutY[2]); - break lo; - } - - accumLength += l; - } - - ctx.quadraticCurveTo(x1, y1, x2, y2); - xi = x2; - yi = y2; - break; - } - - case CMD$3.A: - var cx = d[i++]; - var cy = d[i++]; - var rx = d[i++]; - var ry = d[i++]; - var startAngle = d[i++]; - var delta = d[i++]; - var psi = d[i++]; - var anticlockwise = !d[i++]; - var r = rx > ry ? rx : ry; - var isEllipse = mathAbs$2(rx - ry) > 1e-3; - var endAngle = startAngle + delta; - var breakBuild = false; - - if (drawPart) { - var l = pathSegLen[segCount++]; - - if (accumLength + l > displayedLength) { - endAngle = startAngle + delta * (displayedLength - accumLength) / l; - breakBuild = true; - } - - accumLength += l; - } - - if (isEllipse && ctx.ellipse) { - ctx.ellipse(cx, cy, rx, ry, psi, startAngle, endAngle, anticlockwise); - } else { - ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise); - } - - if (breakBuild) { - break lo; - } - - if (isFirst) { - x0 = mathCos$2(startAngle) * rx + cx; - y0 = mathSin$2(startAngle) * ry + cy; - } - - xi = mathCos$2(endAngle) * rx + cx; - yi = mathSin$2(endAngle) * ry + cy; - break; - - case CMD$3.R: - x0 = xi = d[i]; - y0 = yi = d[i + 1]; - x = d[i++]; - y = d[i++]; - var width = d[i++]; - var height = d[i++]; - - if (drawPart) { - var l = pathSegLen[segCount++]; - - if (accumLength + l > displayedLength) { - var d_1 = displayedLength - accumLength; - ctx.moveTo(x, y); - ctx.lineTo(x + mathMin$4(d_1, width), y); - d_1 -= width; - - if (d_1 > 0) { - ctx.lineTo(x + width, y + mathMin$4(d_1, height)); - } - - d_1 -= height; - - if (d_1 > 0) { - ctx.lineTo(x + mathMax$4(width - d_1, 0), y + height); - } - - d_1 -= width; - - if (d_1 > 0) { - ctx.lineTo(x, y + mathMax$4(height - d_1, 0)); - } - - break lo; - } - - accumLength += l; - } - - ctx.rect(x, y, width, height); - break; - - case CMD$3.Z: - if (drawPart) { - var l = pathSegLen[segCount++]; - - if (accumLength + l > displayedLength) { - var t = (displayedLength - accumLength) / l; - ctx.lineTo(xi * (1 - t) + x0 * t, yi * (1 - t) + y0 * t); - break lo; - } - - accumLength += l; - } - - ctx.closePath(); - xi = x0; - yi = y0; - } - } - }; - - PathProxy.prototype.clone = function () { - var newProxy = new PathProxy(); - var data = this.data; - newProxy.data = data.slice ? data.slice() : Array.prototype.slice.call(data); - newProxy._len = this._len; - return newProxy; - }; - - PathProxy.prototype.canSave = function () { - return !!this._saveData; - }; - - PathProxy.CMD = CMD$3; - - PathProxy.initDefaultProps = function () { - var proto = PathProxy.prototype; - proto._saveData = true; - proto._ux = 0; - proto._uy = 0; - proto._pendingPtDist = 0; - proto._version = 0; - }(); - - return PathProxy; - }(); - - function containStroke$4(x0, y0, x1, y1, lineWidth, x, y) { - if (lineWidth === 0) { - return false; - } - - var _l = lineWidth; - var _a = 0; - var _b = x0; - - if (y > y0 + _l && y > y1 + _l || y < y0 - _l && y < y1 - _l || x > x0 + _l && x > x1 + _l || x < x0 - _l && x < x1 - _l) { - return false; - } - - if (x0 !== x1) { - _a = (y0 - y1) / (x0 - x1); - _b = (x0 * y1 - x1 * y0) / (x0 - x1); - } else { - return Math.abs(x - x0) <= _l / 2; - } - - var tmp = _a * x - y + _b; - - var _s = tmp * tmp / (_a * _a + 1); - - return _s <= _l / 2 * _l / 2; - } - - function containStroke$3(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) { - if (lineWidth === 0) { - return false; - } - - var _l = lineWidth; - - if (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l || y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l || x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l || x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l) { - return false; - } - - var d = cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, null); - return d <= _l / 2; - } - - function containStroke$2(x0, y0, x1, y1, x2, y2, lineWidth, x, y) { - if (lineWidth === 0) { - return false; - } - - var _l = lineWidth; - - if (y > y0 + _l && y > y1 + _l && y > y2 + _l || y < y0 - _l && y < y1 - _l && y < y2 - _l || x > x0 + _l && x > x1 + _l && x > x2 + _l || x < x0 - _l && x < x1 - _l && x < x2 - _l) { - return false; - } - - var d = quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, null); - return d <= _l / 2; - } - - var PI2$4 = Math.PI * 2; - - function normalizeRadian(angle) { - angle %= PI2$4; - - if (angle < 0) { - angle += PI2$4; - } - - return angle; - } - - var PI2$3 = Math.PI * 2; - - function containStroke$1(cx, cy, r, startAngle, endAngle, anticlockwise, lineWidth, x, y) { - if (lineWidth === 0) { - return false; - } - - var _l = lineWidth; - x -= cx; - y -= cy; - var d = Math.sqrt(x * x + y * y); - - if (d - _l > r || d + _l < r) { - return false; - } - - if (Math.abs(startAngle - endAngle) % PI2$3 < 1e-4) { - return true; - } - - if (anticlockwise) { - var tmp = startAngle; - startAngle = normalizeRadian(endAngle); - endAngle = normalizeRadian(tmp); - } else { - startAngle = normalizeRadian(startAngle); - endAngle = normalizeRadian(endAngle); - } - - if (startAngle > endAngle) { - endAngle += PI2$3; - } - - var angle = Math.atan2(y, x); - - if (angle < 0) { - angle += PI2$3; - } - - return angle >= startAngle && angle <= endAngle || angle + PI2$3 >= startAngle && angle + PI2$3 <= endAngle; - } - - function windingLine(x0, y0, x1, y1, x, y) { - if (y > y0 && y > y1 || y < y0 && y < y1) { - return 0; - } - - if (y1 === y0) { - return 0; - } - - var t = (y - y0) / (y1 - y0); - var dir = y1 < y0 ? 1 : -1; - - if (t === 1 || t === 0) { - dir = y1 < y0 ? 0.5 : -0.5; - } - - var x_ = t * (x1 - x0) + x0; - return x_ === x ? Infinity : x_ > x ? dir : 0; - } - - var CMD$2 = PathProxy.CMD; - var PI2$2 = Math.PI * 2; - var EPSILON$1 = 1e-4; - - function isAroundEqual$1(a, b) { - return Math.abs(a - b) < EPSILON$1; - } - - var roots = [-1, -1, -1]; - var extrema = [-1, -1]; - - function swapExtrema() { - var tmp = extrema[0]; - extrema[0] = extrema[1]; - extrema[1] = tmp; - } - - function windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) { - if (y > y0 && y > y1 && y > y2 && y > y3 || y < y0 && y < y1 && y < y2 && y < y3) { - return 0; - } - - var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots); - - if (nRoots === 0) { - return 0; - } else { - var w = 0; - var nExtrema = -1; - var y0_ = void 0; - var y1_ = void 0; - - for (var i = 0; i < nRoots; i++) { - var t = roots[i]; - var unit = t === 0 || t === 1 ? 0.5 : 1; - var x_ = cubicAt(x0, x1, x2, x3, t); - - if (x_ < x) { - continue; - } - - if (nExtrema < 0) { - nExtrema = cubicExtrema(y0, y1, y2, y3, extrema); - - if (extrema[1] < extrema[0] && nExtrema > 1) { - swapExtrema(); - } - - y0_ = cubicAt(y0, y1, y2, y3, extrema[0]); - - if (nExtrema > 1) { - y1_ = cubicAt(y0, y1, y2, y3, extrema[1]); - } - } - - if (nExtrema === 2) { - if (t < extrema[0]) { - w += y0_ < y0 ? unit : -unit; - } else if (t < extrema[1]) { - w += y1_ < y0_ ? unit : -unit; - } else { - w += y3 < y1_ ? unit : -unit; - } - } else { - if (t < extrema[0]) { - w += y0_ < y0 ? unit : -unit; - } else { - w += y3 < y0_ ? unit : -unit; - } - } - } - - return w; - } - } - - function windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) { - if (y > y0 && y > y1 && y > y2 || y < y0 && y < y1 && y < y2) { - return 0; - } - - var nRoots = quadraticRootAt(y0, y1, y2, y, roots); - - if (nRoots === 0) { - return 0; - } else { - var t = quadraticExtremum(y0, y1, y2); - - if (t >= 0 && t <= 1) { - var w = 0; - var y_ = quadraticAt(y0, y1, y2, t); - - for (var i = 0; i < nRoots; i++) { - var unit = roots[i] === 0 || roots[i] === 1 ? 0.5 : 1; - var x_ = quadraticAt(x0, x1, x2, roots[i]); - - if (x_ < x) { - continue; - } - - if (roots[i] < t) { - w += y_ < y0 ? unit : -unit; - } else { - w += y2 < y_ ? unit : -unit; - } - } - - return w; - } else { - var unit = roots[0] === 0 || roots[0] === 1 ? 0.5 : 1; - var x_ = quadraticAt(x0, x1, x2, roots[0]); - - if (x_ < x) { - return 0; - } - - return y2 < y0 ? unit : -unit; - } - } - } - - function windingArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y) { - y -= cy; - - if (y > r || y < -r) { - return 0; - } - - var tmp = Math.sqrt(r * r - y * y); - roots[0] = -tmp; - roots[1] = tmp; - var dTheta = Math.abs(startAngle - endAngle); - - if (dTheta < 1e-4) { - return 0; - } - - if (dTheta >= PI2$2 - 1e-4) { - startAngle = 0; - endAngle = PI2$2; - var dir = anticlockwise ? 1 : -1; - - if (x >= roots[0] + cx && x <= roots[1] + cx) { - return dir; - } else { - return 0; - } - } - - if (startAngle > endAngle) { - var tmp_1 = startAngle; - startAngle = endAngle; - endAngle = tmp_1; - } - - if (startAngle < 0) { - startAngle += PI2$2; - endAngle += PI2$2; - } - - var w = 0; - - for (var i = 0; i < 2; i++) { - var x_ = roots[i]; - - if (x_ + cx > x) { - var angle = Math.atan2(y, x_); - var dir = anticlockwise ? 1 : -1; - - if (angle < 0) { - angle = PI2$2 + angle; - } - - if (angle >= startAngle && angle <= endAngle || angle + PI2$2 >= startAngle && angle + PI2$2 <= endAngle) { - if (angle > Math.PI / 2 && angle < Math.PI * 1.5) { - dir = -dir; - } - - w += dir; - } - } - } - - return w; - } - - function containPath(path, lineWidth, isStroke, x, y) { - var data = path.data; - var len = path.len(); - var w = 0; - var xi = 0; - var yi = 0; - var x0 = 0; - var y0 = 0; - var x1; - var y1; - - for (var i = 0; i < len;) { - var cmd = data[i++]; - var isFirst = i === 1; - - if (cmd === CMD$2.M && i > 1) { - if (!isStroke) { - w += windingLine(xi, yi, x0, y0, x, y); - } - } - - if (isFirst) { - xi = data[i]; - yi = data[i + 1]; - x0 = xi; - y0 = yi; - } - - switch (cmd) { - case CMD$2.M: - x0 = data[i++]; - y0 = data[i++]; - xi = x0; - yi = y0; - break; - - case CMD$2.L: - if (isStroke) { - if (containStroke$4(xi, yi, data[i], data[i + 1], lineWidth, x, y)) { - return true; - } - } else { - w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0; - } - - xi = data[i++]; - yi = data[i++]; - break; - - case CMD$2.C: - if (isStroke) { - if (containStroke$3(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) { - return true; - } - } else { - w += windingCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y) || 0; - } - - xi = data[i++]; - yi = data[i++]; - break; - - case CMD$2.Q: - if (isStroke) { - if (containStroke$2(xi, yi, data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) { - return true; - } - } else { - w += windingQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y) || 0; - } - - xi = data[i++]; - yi = data[i++]; - break; - - case CMD$2.A: - var cx = data[i++]; - var cy = data[i++]; - var rx = data[i++]; - var ry = data[i++]; - var theta = data[i++]; - var dTheta = data[i++]; - i += 1; - var anticlockwise = !!(1 - data[i++]); - x1 = Math.cos(theta) * rx + cx; - y1 = Math.sin(theta) * ry + cy; - - if (!isFirst) { - w += windingLine(xi, yi, x1, y1, x, y); - } else { - x0 = x1; - y0 = y1; - } - - var _x = (x - cx) * ry / rx + cx; - - if (isStroke) { - if (containStroke$1(cx, cy, ry, theta, theta + dTheta, anticlockwise, lineWidth, _x, y)) { - return true; - } - } else { - w += windingArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y); - } - - xi = Math.cos(theta + dTheta) * rx + cx; - yi = Math.sin(theta + dTheta) * ry + cy; - break; - - case CMD$2.R: - x0 = xi = data[i++]; - y0 = yi = data[i++]; - var width = data[i++]; - var height = data[i++]; - x1 = x0 + width; - y1 = y0 + height; - - if (isStroke) { - if (containStroke$4(x0, y0, x1, y0, lineWidth, x, y) || containStroke$4(x1, y0, x1, y1, lineWidth, x, y) || containStroke$4(x1, y1, x0, y1, lineWidth, x, y) || containStroke$4(x0, y1, x0, y0, lineWidth, x, y)) { - return true; - } - } else { - w += windingLine(x1, y0, x1, y1, x, y); - w += windingLine(x0, y1, x0, y0, x, y); - } - - break; - - case CMD$2.Z: - if (isStroke) { - if (containStroke$4(xi, yi, x0, y0, lineWidth, x, y)) { - return true; - } - } else { - w += windingLine(xi, yi, x0, y0, x, y); - } - - xi = x0; - yi = y0; - break; - } - } - - if (!isStroke && !isAroundEqual$1(yi, y0)) { - w += windingLine(xi, yi, x0, y0, x, y) || 0; - } - - return w !== 0; - } - - function contain$2(pathProxy, x, y) { - return containPath(pathProxy, 0, false, x, y); - } - - function containStroke(pathProxy, lineWidth, x, y) { - return containPath(pathProxy, lineWidth, true, x, y); - } - - var DEFAULT_PATH_STYLE = defaults({ - fill: '#000', - stroke: null, - strokePercent: 1, - fillOpacity: 1, - strokeOpacity: 1, - lineDashOffset: 0, - lineWidth: 1, - lineCap: 'butt', - miterLimit: 10, - strokeNoScale: false, - strokeFirst: false - }, DEFAULT_COMMON_STYLE); - var DEFAULT_PATH_ANIMATION_PROPS = { - style: defaults({ - fill: true, - stroke: true, - strokePercent: true, - fillOpacity: true, - strokeOpacity: true, - lineDashOffset: true, - lineWidth: true, - miterLimit: true - }, DEFAULT_COMMON_ANIMATION_PROPS.style) - }; - var pathCopyParams = TRANSFORMABLE_PROPS.concat(['invisible', 'culling', 'z', 'z2', 'zlevel', 'parent']); - - var Path = function (_super) { - __extends(Path, _super); - - function Path(opts) { - return _super.call(this, opts) || this; - } - - Path.prototype.update = function () { - var _this = this; - - _super.prototype.update.call(this); - - var style = this.style; - - if (style.decal) { - var decalEl = this._decalEl = this._decalEl || new Path(); - - if (decalEl.buildPath === Path.prototype.buildPath) { - decalEl.buildPath = function (ctx) { - _this.buildPath(ctx, _this.shape); - }; - } - - decalEl.silent = true; - var decalElStyle = decalEl.style; - - for (var key in style) { - if (decalElStyle[key] !== style[key]) { - decalElStyle[key] = style[key]; - } - } - - decalElStyle.fill = style.fill ? style.decal : null; - decalElStyle.decal = null; - decalElStyle.shadowColor = null; - style.strokeFirst && (decalElStyle.stroke = null); - - for (var i = 0; i < pathCopyParams.length; ++i) { - decalEl[pathCopyParams[i]] = this[pathCopyParams[i]]; - } - - decalEl.__dirty |= REDRAW_BIT; - } else if (this._decalEl) { - this._decalEl = null; - } - }; - - Path.prototype.getDecalElement = function () { - return this._decalEl; - }; - - Path.prototype._init = function (props) { - var keysArr = keys(props); - this.shape = this.getDefaultShape(); - var defaultStyle = this.getDefaultStyle(); - - if (defaultStyle) { - this.useStyle(defaultStyle); - } - - for (var i = 0; i < keysArr.length; i++) { - var key = keysArr[i]; - var value = props[key]; - - if (key === 'style') { - if (!this.style) { - this.useStyle(value); - } else { - extend(this.style, value); - } - } else if (key === 'shape') { - extend(this.shape, value); - } else { - _super.prototype.attrKV.call(this, key, value); - } - } - - if (!this.style) { - this.useStyle({}); - } - }; - - Path.prototype.getDefaultStyle = function () { - return null; - }; - - Path.prototype.getDefaultShape = function () { - return {}; - }; - - Path.prototype.canBeInsideText = function () { - return this.hasFill(); - }; - - Path.prototype.getInsideTextFill = function () { - var pathFill = this.style.fill; - - if (pathFill !== 'none') { - if (isString(pathFill)) { - var fillLum = lum(pathFill, 0); - - if (fillLum > 0.5) { - return DARK_LABEL_COLOR; - } else if (fillLum > 0.2) { - return LIGHTER_LABEL_COLOR; - } - - return LIGHT_LABEL_COLOR; - } else if (pathFill) { - return LIGHT_LABEL_COLOR; - } - } - - return DARK_LABEL_COLOR; - }; - - Path.prototype.getInsideTextStroke = function (textFill) { - var pathFill = this.style.fill; - - if (isString(pathFill)) { - var zr = this.__zr; - var isDarkMode = !!(zr && zr.isDarkMode()); - var isDarkLabel = lum(textFill, 0) < DARK_MODE_THRESHOLD; - - if (isDarkMode === isDarkLabel) { - return pathFill; - } - } - }; - - Path.prototype.buildPath = function (ctx, shapeCfg, inBatch) {}; - - Path.prototype.pathUpdated = function () { - this.__dirty &= ~SHAPE_CHANGED_BIT; - }; - - Path.prototype.getUpdatedPathProxy = function (inBatch) { - !this.path && this.createPathProxy(); - this.path.beginPath(); - this.buildPath(this.path, this.shape, inBatch); - return this.path; - }; - - Path.prototype.createPathProxy = function () { - this.path = new PathProxy(false); - }; - - Path.prototype.hasStroke = function () { - var style = this.style; - var stroke = style.stroke; - return !(stroke == null || stroke === 'none' || !(style.lineWidth > 0)); - }; - - Path.prototype.hasFill = function () { - var style = this.style; - var fill = style.fill; - return fill != null && fill !== 'none'; - }; - - Path.prototype.getBoundingRect = function () { - var rect = this._rect; - var style = this.style; - var needsUpdateRect = !rect; - - if (needsUpdateRect) { - var firstInvoke = false; - - if (!this.path) { - firstInvoke = true; - this.createPathProxy(); - } - - var path = this.path; - - if (firstInvoke || this.__dirty & SHAPE_CHANGED_BIT) { - path.beginPath(); - this.buildPath(path, this.shape, false); - this.pathUpdated(); - } - - rect = path.getBoundingRect(); - } - - this._rect = rect; - - if (this.hasStroke() && this.path && this.path.len() > 0) { - var rectStroke = this._rectStroke || (this._rectStroke = rect.clone()); - - if (this.__dirty || needsUpdateRect) { - rectStroke.copy(rect); - var lineScale = style.strokeNoScale ? this.getLineScale() : 1; - var w = style.lineWidth; - - if (!this.hasFill()) { - var strokeContainThreshold = this.strokeContainThreshold; - w = Math.max(w, strokeContainThreshold == null ? 4 : strokeContainThreshold); - } - - if (lineScale > 1e-10) { - rectStroke.width += w / lineScale; - rectStroke.height += w / lineScale; - rectStroke.x -= w / lineScale / 2; - rectStroke.y -= w / lineScale / 2; - } - } - - return rectStroke; - } - - return rect; - }; - - Path.prototype.contain = function (x, y) { - var localPos = this.transformCoordToLocal(x, y); - var rect = this.getBoundingRect(); - var style = this.style; - x = localPos[0]; - y = localPos[1]; - - if (rect.contain(x, y)) { - var pathProxy = this.path; - - if (this.hasStroke()) { - var lineWidth = style.lineWidth; - var lineScale = style.strokeNoScale ? this.getLineScale() : 1; - - if (lineScale > 1e-10) { - if (!this.hasFill()) { - lineWidth = Math.max(lineWidth, this.strokeContainThreshold); - } - - if (containStroke(pathProxy, lineWidth / lineScale, x, y)) { - return true; - } - } - } - - if (this.hasFill()) { - return contain$2(pathProxy, x, y); - } - } - - return false; - }; - - Path.prototype.dirtyShape = function () { - this.__dirty |= SHAPE_CHANGED_BIT; - - if (this._rect) { - this._rect = null; - } - - if (this._decalEl) { - this._decalEl.dirtyShape(); - } - - this.markRedraw(); - }; - - Path.prototype.dirty = function () { - this.dirtyStyle(); - this.dirtyShape(); - }; - - Path.prototype.animateShape = function (loop) { - return this.animate('shape', loop); - }; - - Path.prototype.updateDuringAnimation = function (targetKey) { - if (targetKey === 'style') { - this.dirtyStyle(); - } else if (targetKey === 'shape') { - this.dirtyShape(); - } else { - this.markRedraw(); - } - }; - - Path.prototype.attrKV = function (key, value) { - if (key === 'shape') { - this.setShape(value); - } else { - _super.prototype.attrKV.call(this, key, value); - } - }; - - Path.prototype.setShape = function (keyOrObj, value) { - var shape = this.shape; - - if (!shape) { - shape = this.shape = {}; - } - - if (typeof keyOrObj === 'string') { - shape[keyOrObj] = value; - } else { - extend(shape, keyOrObj); - } - - this.dirtyShape(); - return this; - }; - - Path.prototype.shapeChanged = function () { - return !!(this.__dirty & SHAPE_CHANGED_BIT); - }; - - Path.prototype.createStyle = function (obj) { - return createObject(DEFAULT_PATH_STYLE, obj); - }; - - Path.prototype._innerSaveToNormal = function (toState) { - _super.prototype._innerSaveToNormal.call(this, toState); - - var normalState = this._normalState; - - if (toState.shape && !normalState.shape) { - normalState.shape = extend({}, this.shape); - } - }; - - Path.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) { - _super.prototype._applyStateObj.call(this, stateName, state, normalState, keepCurrentStates, transition, animationCfg); - - var needsRestoreToNormal = !(state && keepCurrentStates); - var targetShape; - - if (state && state.shape) { - if (transition) { - if (keepCurrentStates) { - targetShape = state.shape; - } else { - targetShape = extend({}, normalState.shape); - extend(targetShape, state.shape); - } - } else { - targetShape = extend({}, keepCurrentStates ? this.shape : normalState.shape); - extend(targetShape, state.shape); - } - } else if (needsRestoreToNormal) { - targetShape = normalState.shape; - } - - if (targetShape) { - if (transition) { - this.shape = extend({}, this.shape); - var targetShapePrimaryProps = {}; - var shapeKeys = keys(targetShape); - - for (var i = 0; i < shapeKeys.length; i++) { - var key = shapeKeys[i]; - - if (typeof targetShape[key] === 'object') { - this.shape[key] = targetShape[key]; - } else { - targetShapePrimaryProps[key] = targetShape[key]; - } - } - - this._transitionState(stateName, { - shape: targetShapePrimaryProps - }, animationCfg); - } else { - this.shape = targetShape; - this.dirtyShape(); - } - } - }; - - Path.prototype._mergeStates = function (states) { - var mergedState = _super.prototype._mergeStates.call(this, states); - - var mergedShape; - - for (var i = 0; i < states.length; i++) { - var state = states[i]; - - if (state.shape) { - mergedShape = mergedShape || {}; - - this._mergeStyle(mergedShape, state.shape); - } - } - - if (mergedShape) { - mergedState.shape = mergedShape; - } - - return mergedState; - }; - - Path.prototype.getAnimationStyleProps = function () { - return DEFAULT_PATH_ANIMATION_PROPS; - }; - - Path.prototype.isZeroArea = function () { - return false; - }; - - Path.extend = function (defaultProps) { - var Sub = function (_super) { - __extends(Sub, _super); - - function Sub(opts) { - var _this = _super.call(this, opts) || this; - - defaultProps.init && defaultProps.init.call(_this, opts); - return _this; - } - - Sub.prototype.getDefaultStyle = function () { - return clone$3(defaultProps.style); - }; - - Sub.prototype.getDefaultShape = function () { - return clone$3(defaultProps.shape); - }; - - return Sub; - }(Path); - - for (var key in defaultProps) { - if (typeof defaultProps[key] === 'function') { - Sub.prototype[key] = defaultProps[key]; - } - } - - return Sub; - }; - - Path.initDefaultProps = function () { - var pathProto = Path.prototype; - pathProto.type = 'path'; - pathProto.strokeContainThreshold = 5; - pathProto.segmentIgnoreThreshold = 0; - pathProto.subPixelOptimize = false; - pathProto.autoBatch = false; - pathProto.__dirty = REDRAW_BIT | STYLE_CHANGED_BIT | SHAPE_CHANGED_BIT; - }(); - - return Path; - }(Displayable); - - var DEFAULT_TSPAN_STYLE = defaults({ - strokeFirst: true, - font: DEFAULT_FONT, - x: 0, - y: 0, - textAlign: 'left', - textBaseline: 'top', - miterLimit: 2 - }, DEFAULT_PATH_STYLE); - - var TSpan = function (_super) { - __extends(TSpan, _super); - - function TSpan() { - return _super !== null && _super.apply(this, arguments) || this; - } - - TSpan.prototype.hasStroke = function () { - return tSpanHasStroke(this.style); - }; - - TSpan.prototype.hasFill = function () { - var style = this.style; - var fill = style.fill; - return fill != null && fill !== 'none'; - }; - - TSpan.prototype.createStyle = function (obj) { - return createObject(DEFAULT_TSPAN_STYLE, obj); - }; - - TSpan.prototype.setBoundingRect = function (rect) { - this._rect = rect; - }; - - TSpan.prototype.getBoundingRect = function () { - if (!this._rect) { - this._rect = tSpanCreateBoundingRect(this.style); - } - - return this._rect; - }; - - TSpan.initDefaultProps = function () { - var tspanProto = TSpan.prototype; - tspanProto.dirtyRectTolerance = 10; - }(); - - return TSpan; - }(Displayable); - - TSpan.prototype.type = 'tspan'; - var DEFAULT_IMAGE_STYLE = defaults({ - x: 0, - y: 0 - }, DEFAULT_COMMON_STYLE); - var DEFAULT_IMAGE_ANIMATION_PROPS = { - style: defaults({ - x: true, - y: true, - width: true, - height: true, - sx: true, - sy: true, - sWidth: true, - sHeight: true - }, DEFAULT_COMMON_ANIMATION_PROPS.style) - }; - - function isImageLike(source) { - return !!(source && typeof source !== 'string' && source.width && source.height); - } - - var ZRImage = function (_super) { - __extends(ZRImage, _super); - - function ZRImage() { - return _super !== null && _super.apply(this, arguments) || this; - } - - ZRImage.prototype.createStyle = function (obj) { - return createObject(DEFAULT_IMAGE_STYLE, obj); - }; - - ZRImage.prototype._getSize = function (dim) { - var style = this.style; - var size = style[dim]; - - if (size != null) { - return size; - } - - var imageSource = isImageLike(style.image) ? style.image : this.__image; - - if (!imageSource) { - return 0; - } - - var otherDim = dim === 'width' ? 'height' : 'width'; - var otherDimSize = style[otherDim]; - - if (otherDimSize == null) { - return imageSource[dim]; - } else { - return imageSource[dim] / imageSource[otherDim] * otherDimSize; - } - }; - - ZRImage.prototype.getWidth = function () { - return this._getSize('width'); - }; - - ZRImage.prototype.getHeight = function () { - return this._getSize('height'); - }; - - ZRImage.prototype.getAnimationStyleProps = function () { - return DEFAULT_IMAGE_ANIMATION_PROPS; - }; - - ZRImage.prototype.getBoundingRect = function () { - var style = this.style; - - if (!this._rect) { - this._rect = new BoundingRect(style.x || 0, style.y || 0, this.getWidth(), this.getHeight()); - } - - return this._rect; - }; - - return ZRImage; - }(Displayable); - - ZRImage.prototype.type = 'image'; - - function buildPath$2(ctx, shape) { - var x = shape.x; - var y = shape.y; - var width = shape.width; - var height = shape.height; - var r = shape.r; - var r1; - var r2; - var r3; - var r4; - - if (width < 0) { - x = x + width; - width = -width; - } - - if (height < 0) { - y = y + height; - height = -height; - } - - if (typeof r === 'number') { - r1 = r2 = r3 = r4 = r; - } else if (r instanceof Array) { - if (r.length === 1) { - r1 = r2 = r3 = r4 = r[0]; - } else if (r.length === 2) { - r1 = r3 = r[0]; - r2 = r4 = r[1]; - } else if (r.length === 3) { - r1 = r[0]; - r2 = r4 = r[1]; - r3 = r[2]; - } else { - r1 = r[0]; - r2 = r[1]; - r3 = r[2]; - r4 = r[3]; - } - } else { - r1 = r2 = r3 = r4 = 0; - } - - var total; - - if (r1 + r2 > width) { - total = r1 + r2; - r1 *= width / total; - r2 *= width / total; - } - - if (r3 + r4 > width) { - total = r3 + r4; - r3 *= width / total; - r4 *= width / total; - } - - if (r2 + r3 > height) { - total = r2 + r3; - r2 *= height / total; - r3 *= height / total; - } - - if (r1 + r4 > height) { - total = r1 + r4; - r1 *= height / total; - r4 *= height / total; - } - - ctx.moveTo(x + r1, y); - ctx.lineTo(x + width - r2, y); - r2 !== 0 && ctx.arc(x + width - r2, y + r2, r2, -Math.PI / 2, 0); - ctx.lineTo(x + width, y + height - r3); - r3 !== 0 && ctx.arc(x + width - r3, y + height - r3, r3, 0, Math.PI / 2); - ctx.lineTo(x + r4, y + height); - r4 !== 0 && ctx.arc(x + r4, y + height - r4, r4, Math.PI / 2, Math.PI); - ctx.lineTo(x, y + r1); - r1 !== 0 && ctx.arc(x + r1, y + r1, r1, Math.PI, Math.PI * 1.5); - } - - var round = Math.round; - - function subPixelOptimizeLine$1(outputShape, inputShape, style) { - if (!inputShape) { - return; - } - - var x1 = inputShape.x1; - var x2 = inputShape.x2; - var y1 = inputShape.y1; - var y2 = inputShape.y2; - outputShape.x1 = x1; - outputShape.x2 = x2; - outputShape.y1 = y1; - outputShape.y2 = y2; - var lineWidth = style && style.lineWidth; - - if (!lineWidth) { - return outputShape; - } - - if (round(x1 * 2) === round(x2 * 2)) { - outputShape.x1 = outputShape.x2 = subPixelOptimize$1(x1, lineWidth, true); - } - - if (round(y1 * 2) === round(y2 * 2)) { - outputShape.y1 = outputShape.y2 = subPixelOptimize$1(y1, lineWidth, true); - } - - return outputShape; - } - - function subPixelOptimizeRect$1(outputShape, inputShape, style) { - if (!inputShape) { - return; - } - - var originX = inputShape.x; - var originY = inputShape.y; - var originWidth = inputShape.width; - var originHeight = inputShape.height; - outputShape.x = originX; - outputShape.y = originY; - outputShape.width = originWidth; - outputShape.height = originHeight; - var lineWidth = style && style.lineWidth; - - if (!lineWidth) { - return outputShape; - } - - outputShape.x = subPixelOptimize$1(originX, lineWidth, true); - outputShape.y = subPixelOptimize$1(originY, lineWidth, true); - outputShape.width = Math.max(subPixelOptimize$1(originX + originWidth, lineWidth, false) - outputShape.x, originWidth === 0 ? 0 : 1); - outputShape.height = Math.max(subPixelOptimize$1(originY + originHeight, lineWidth, false) - outputShape.y, originHeight === 0 ? 0 : 1); - return outputShape; - } - - function subPixelOptimize$1(position, lineWidth, positiveOrNegative) { - if (!lineWidth) { - return position; - } - - var doubledPosition = round(position * 2); - return (doubledPosition + round(lineWidth)) % 2 === 0 ? doubledPosition / 2 : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2; - } - - var RectShape = function () { - function RectShape() { - this.x = 0; - this.y = 0; - this.width = 0; - this.height = 0; - } - - return RectShape; - }(); - - var subPixelOptimizeOutputShape$1 = {}; - - var Rect = function (_super) { - __extends(Rect, _super); - - function Rect(opts) { - return _super.call(this, opts) || this; - } - - Rect.prototype.getDefaultShape = function () { - return new RectShape(); - }; - - Rect.prototype.buildPath = function (ctx, shape) { - var x; - var y; - var width; - var height; - - if (this.subPixelOptimize) { - var optimizedShape = subPixelOptimizeRect$1(subPixelOptimizeOutputShape$1, shape, this.style); - x = optimizedShape.x; - y = optimizedShape.y; - width = optimizedShape.width; - height = optimizedShape.height; - optimizedShape.r = shape.r; - shape = optimizedShape; - } else { - x = shape.x; - y = shape.y; - width = shape.width; - height = shape.height; - } - - if (!shape.r) { - ctx.rect(x, y, width, height); - } else { - buildPath$2(ctx, shape); - } - }; - - Rect.prototype.isZeroArea = function () { - return !this.shape.width || !this.shape.height; - }; - - return Rect; - }(Path); - - Rect.prototype.type = 'rect'; - var DEFAULT_RICH_TEXT_COLOR = { - fill: '#000' - }; - var DEFAULT_STROKE_LINE_WIDTH = 2; - var tmpCITOverflowAreaOut = {}; - var DEFAULT_TEXT_ANIMATION_PROPS = { - style: defaults({ - fill: true, - stroke: true, - fillOpacity: true, - strokeOpacity: true, - lineWidth: true, - fontSize: true, - lineHeight: true, - width: true, - height: true, - textShadowColor: true, - textShadowBlur: true, - textShadowOffsetX: true, - textShadowOffsetY: true, - backgroundColor: true, - padding: true, - borderColor: true, - borderWidth: true, - borderRadius: true - }, DEFAULT_COMMON_ANIMATION_PROPS.style) - }; - - var ZRText = function (_super) { - __extends(ZRText, _super); - - function ZRText(opts) { - var _this = _super.call(this) || this; - - _this.type = 'text'; - _this._children = []; - _this._defaultStyle = DEFAULT_RICH_TEXT_COLOR; - - _this.attr(opts); - - return _this; - } - - ZRText.prototype.childrenRef = function () { - return this._children; - }; - - ZRText.prototype.update = function () { - _super.prototype.update.call(this); - - if (this.styleChanged()) { - this._updateSubTexts(); - } - - for (var i = 0; i < this._children.length; i++) { - var child = this._children[i]; - child.zlevel = this.zlevel; - child.z = this.z; - child.z2 = this.z2; - child.culling = this.culling; - child.cursor = this.cursor; - child.invisible = this.invisible; - } - }; - - ZRText.prototype.updateTransform = function () { - var innerTransformable = this.innerTransformable; - - if (innerTransformable) { - innerTransformable.updateTransform(); - - if (innerTransformable.transform) { - this.transform = innerTransformable.transform; - } - } else { - _super.prototype.updateTransform.call(this); - } - }; - - ZRText.prototype.getLocalTransform = function (m) { - var innerTransformable = this.innerTransformable; - return innerTransformable ? innerTransformable.getLocalTransform(m) : _super.prototype.getLocalTransform.call(this, m); - }; - - ZRText.prototype.getComputedTransform = function () { - if (this.__hostTarget) { - this.__hostTarget.getComputedTransform(); - - this.__hostTarget.updateInnerText(true); - } - - return _super.prototype.getComputedTransform.call(this); - }; - - ZRText.prototype._updateSubTexts = function () { - this._childCursor = 0; - normalizeTextStyle(this.style); - this.style.rich ? this._updateRichTexts() : this._updatePlainTexts(); - this._children.length = this._childCursor; - this.styleUpdated(); - }; - - ZRText.prototype.addSelfToZr = function (zr) { - _super.prototype.addSelfToZr.call(this, zr); - - for (var i = 0; i < this._children.length; i++) { - this._children[i].__zr = zr; - } - }; - - ZRText.prototype.removeSelfFromZr = function (zr) { - _super.prototype.removeSelfFromZr.call(this, zr); - - for (var i = 0; i < this._children.length; i++) { - this._children[i].__zr = null; - } - }; - - ZRText.prototype.getBoundingRect = function () { - if (this.styleChanged()) { - this._updateSubTexts(); - } - - if (!this._rect) { - var tmpRect = new BoundingRect(0, 0, 0, 0); - var children = this._children; - var tmpMat = []; - var rect = null; - - for (var i = 0; i < children.length; i++) { - var child = children[i]; - var childRect = child.getBoundingRect(); - var transform = child.getLocalTransform(tmpMat); - - if (transform) { - tmpRect.copy(childRect); - tmpRect.applyTransform(transform); - rect = rect || tmpRect.clone(); - rect.union(tmpRect); - } else { - rect = rect || childRect.clone(); - rect.union(childRect); - } - } - - this._rect = rect || tmpRect; - } - - return this._rect; - }; - - ZRText.prototype.setDefaultTextStyle = function (defaultTextStyle) { - this._defaultStyle = defaultTextStyle || DEFAULT_RICH_TEXT_COLOR; - }; - - ZRText.prototype.setTextContent = function (textContent) { - { - throw new Error('Can\'t attach text on another text'); - } - }; - - ZRText.prototype._mergeStyle = function (targetStyle, sourceStyle) { - if (!sourceStyle) { - return targetStyle; - } - - var sourceRich = sourceStyle.rich; - var targetRich = targetStyle.rich || sourceRich && {}; - extend(targetStyle, sourceStyle); - - if (sourceRich && targetRich) { - this._mergeRich(targetRich, sourceRich); - - targetStyle.rich = targetRich; - } else if (targetRich) { - targetStyle.rich = targetRich; - } - - return targetStyle; - }; - - ZRText.prototype._mergeRich = function (targetRich, sourceRich) { - var richNames = keys(sourceRich); - - for (var i = 0; i < richNames.length; i++) { - var richName = richNames[i]; - targetRich[richName] = targetRich[richName] || {}; - extend(targetRich[richName], sourceRich[richName]); - } - }; - - ZRText.prototype.getAnimationStyleProps = function () { - return DEFAULT_TEXT_ANIMATION_PROPS; - }; - - ZRText.prototype._getOrCreateChild = function (Ctor) { - var child = this._children[this._childCursor]; - - if (!child || !(child instanceof Ctor)) { - child = new Ctor(); - } - - this._children[this._childCursor++] = child; - child.__zr = this.__zr; - child.parent = this; - return child; - }; - - ZRText.prototype._updatePlainTexts = function () { - var style = this.style; - var textFont = style.font || DEFAULT_FONT; - var textPadding = style.padding; - var defaultStyle = this._defaultStyle; - var baseX = style.x || 0; - var baseY = style.y || 0; - var textAlign = style.align || defaultStyle.align || 'left'; - var verticalAlign = style.verticalAlign || defaultStyle.verticalAlign || 'top'; - calcInnerTextOverflowArea(tmpCITOverflowAreaOut, defaultStyle.overflowRect, baseX, baseY, textAlign, verticalAlign); - baseX = tmpCITOverflowAreaOut.baseX; - baseY = tmpCITOverflowAreaOut.baseY; - var text = getStyleText(style); - var contentBlock = parsePlainText(text, style, tmpCITOverflowAreaOut.outerWidth, tmpCITOverflowAreaOut.outerHeight); - var needDrawBg = needDrawBackground(style); - var bgColorDrawn = !!style.backgroundColor; - var outerHeight = contentBlock.outerHeight; - var outerWidth = contentBlock.outerWidth; - var textLines = contentBlock.lines; - var lineHeight = contentBlock.lineHeight; - this.isTruncated = !!contentBlock.isTruncated; - var textX = baseX; - var textY = adjustTextY(baseY, contentBlock.contentHeight, verticalAlign); - - if (needDrawBg || textPadding) { - var boxX = adjustTextX(baseX, outerWidth, textAlign); - var boxY = adjustTextY(baseY, outerHeight, verticalAlign); - needDrawBg && this._renderBackground(style, style, boxX, boxY, outerWidth, outerHeight); - } - - textY += lineHeight / 2; - - if (textPadding) { - textX = getTextXForPadding(baseX, textAlign, textPadding); - - if (verticalAlign === 'top') { - textY += textPadding[0]; - } else if (verticalAlign === 'bottom') { - textY -= textPadding[2]; - } - } - - var defaultLineWidth = 0; - var usingDefaultStroke = false; - var useDefaultFill = false; - var textFill = getFill('fill' in style ? style.fill : (useDefaultFill = true, defaultStyle.fill)); - var textStroke = getStroke('stroke' in style ? style.stroke : !bgColorDrawn && (!defaultStyle.autoStroke || useDefaultFill) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, usingDefaultStroke = true, defaultStyle.stroke) : null); - var hasShadow = style.textShadowBlur > 0; - - for (var i = 0; i < textLines.length; i++) { - var el = this._getOrCreateChild(TSpan); - - var subElStyle = el.createStyle(); - el.useStyle(subElStyle); - subElStyle.text = textLines[i]; - subElStyle.x = textX; - subElStyle.y = textY; - - if (textAlign) { - subElStyle.textAlign = textAlign; - } - - subElStyle.textBaseline = 'middle'; - subElStyle.opacity = style.opacity; - subElStyle.strokeFirst = true; - - if (hasShadow) { - subElStyle.shadowBlur = style.textShadowBlur || 0; - subElStyle.shadowColor = style.textShadowColor || 'transparent'; - subElStyle.shadowOffsetX = style.textShadowOffsetX || 0; - subElStyle.shadowOffsetY = style.textShadowOffsetY || 0; - } - - subElStyle.stroke = textStroke; - subElStyle.fill = textFill; - - if (textStroke) { - subElStyle.lineWidth = style.lineWidth || defaultLineWidth; - subElStyle.lineDash = style.lineDash; - subElStyle.lineDashOffset = style.lineDashOffset || 0; - } - - subElStyle.font = textFont; - setSeparateFont(subElStyle, style); - textY += lineHeight; - el.setBoundingRect(tSpanCreateBoundingRect2(subElStyle, contentBlock.contentWidth, contentBlock.calculatedLineHeight, usingDefaultStroke ? 0 : null)); - } - }; - - ZRText.prototype._updateRichTexts = function () { - var style = this.style; - var defaultStyle = this._defaultStyle; - var textAlign = style.align || defaultStyle.align; - var verticalAlign = style.verticalAlign || defaultStyle.verticalAlign; - var baseX = style.x || 0; - var baseY = style.y || 0; - calcInnerTextOverflowArea(tmpCITOverflowAreaOut, defaultStyle.overflowRect, baseX, baseY, textAlign, verticalAlign); - baseX = tmpCITOverflowAreaOut.baseX; - baseY = tmpCITOverflowAreaOut.baseY; - var text = getStyleText(style); - var contentBlock = parseRichText(text, style, tmpCITOverflowAreaOut.outerWidth, tmpCITOverflowAreaOut.outerHeight, textAlign); - var contentWidth = contentBlock.width; - var outerWidth = contentBlock.outerWidth; - var outerHeight = contentBlock.outerHeight; - var textPadding = style.padding; - this.isTruncated = !!contentBlock.isTruncated; - var boxX = adjustTextX(baseX, outerWidth, textAlign); - var boxY = adjustTextY(baseY, outerHeight, verticalAlign); - var xLeft = boxX; - var lineTop = boxY; - - if (textPadding) { - xLeft += textPadding[3]; - lineTop += textPadding[0]; - } - - var xRight = xLeft + contentWidth; - - if (needDrawBackground(style)) { - this._renderBackground(style, style, boxX, boxY, outerWidth, outerHeight); - } - - var bgColorDrawn = !!style.backgroundColor; - - for (var i = 0; i < contentBlock.lines.length; i++) { - var line = contentBlock.lines[i]; - var tokens = line.tokens; - var tokenCount = tokens.length; - var lineHeight = line.lineHeight; - var remainedWidth = line.width; - var leftIndex = 0; - var lineXLeft = xLeft; - var lineXRight = xRight; - var rightIndex = tokenCount - 1; - var token = void 0; - - while (leftIndex < tokenCount && (token = tokens[leftIndex], !token.align || token.align === 'left')) { - this._placeToken(token, style, lineHeight, lineTop, lineXLeft, 'left', bgColorDrawn); - - remainedWidth -= token.width; - lineXLeft += token.width; - leftIndex++; - } - - while (rightIndex >= 0 && (token = tokens[rightIndex], token.align === 'right')) { - this._placeToken(token, style, lineHeight, lineTop, lineXRight, 'right', bgColorDrawn); - - remainedWidth -= token.width; - lineXRight -= token.width; - rightIndex--; - } - - lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - remainedWidth) / 2; - - while (leftIndex <= rightIndex) { - token = tokens[leftIndex]; - - this._placeToken(token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center', bgColorDrawn); - - lineXLeft += token.width; - leftIndex++; - } - - lineTop += lineHeight; - } - }; - - ZRText.prototype._placeToken = function (token, style, lineHeight, lineTop, x, textAlign, parentBgColorDrawn) { - var tokenStyle = style.rich[token.styleName] || {}; - tokenStyle.text = token.text; - var verticalAlign = token.verticalAlign; - var y = lineTop + lineHeight / 2; - - if (verticalAlign === 'top') { - y = lineTop + token.height / 2; - } else if (verticalAlign === 'bottom') { - y = lineTop + lineHeight - token.height / 2; - } - - var needDrawBg = !token.isLineHolder && needDrawBackground(tokenStyle); - needDrawBg && this._renderBackground(tokenStyle, style, textAlign === 'right' ? x - token.width : textAlign === 'center' ? x - token.width / 2 : x, y - token.height / 2, token.width, token.height); - var bgColorDrawn = !!tokenStyle.backgroundColor; - var textPadding = token.textPadding; - - if (textPadding) { - x = getTextXForPadding(x, textAlign, textPadding); - y -= token.height / 2 - textPadding[0] - token.innerHeight / 2; - } - - var el = this._getOrCreateChild(TSpan); - - var subElStyle = el.createStyle(); - el.useStyle(subElStyle); - var defaultStyle = this._defaultStyle; - var useDefaultFill = false; - var defaultLineWidth = 0; - var usingDefaultStroke = false; - var textFill = getFill('fill' in tokenStyle ? tokenStyle.fill : 'fill' in style ? style.fill : (useDefaultFill = true, defaultStyle.fill)); - var textStroke = getStroke('stroke' in tokenStyle ? tokenStyle.stroke : 'stroke' in style ? style.stroke : !bgColorDrawn && !parentBgColorDrawn && (!defaultStyle.autoStroke || useDefaultFill) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, usingDefaultStroke = true, defaultStyle.stroke) : null); - var hasShadow = tokenStyle.textShadowBlur > 0 || style.textShadowBlur > 0; - subElStyle.text = token.text; - subElStyle.x = x; - subElStyle.y = y; - - if (hasShadow) { - subElStyle.shadowBlur = tokenStyle.textShadowBlur || style.textShadowBlur || 0; - subElStyle.shadowColor = tokenStyle.textShadowColor || style.textShadowColor || 'transparent'; - subElStyle.shadowOffsetX = tokenStyle.textShadowOffsetX || style.textShadowOffsetX || 0; - subElStyle.shadowOffsetY = tokenStyle.textShadowOffsetY || style.textShadowOffsetY || 0; - } - - subElStyle.textAlign = textAlign; - subElStyle.textBaseline = 'middle'; - subElStyle.font = token.font || DEFAULT_FONT; - subElStyle.opacity = retrieve3(tokenStyle.opacity, style.opacity, 1); - setSeparateFont(subElStyle, tokenStyle); - - if (textStroke) { - subElStyle.lineWidth = retrieve3(tokenStyle.lineWidth, style.lineWidth, defaultLineWidth); - subElStyle.lineDash = retrieve2(tokenStyle.lineDash, style.lineDash); - subElStyle.lineDashOffset = style.lineDashOffset || 0; - subElStyle.stroke = textStroke; - } - - if (textFill) { - subElStyle.fill = textFill; - } - - el.setBoundingRect(tSpanCreateBoundingRect2(subElStyle, token.contentWidth, token.contentHeight, usingDefaultStroke ? 0 : null)); - }; - - ZRText.prototype._renderBackground = function (style, topStyle, x, y, width, height) { - var textBackgroundColor = style.backgroundColor; - var textBorderWidth = style.borderWidth; - var textBorderColor = style.borderColor; - var isImageBg = textBackgroundColor && textBackgroundColor.image; - var isPlainOrGradientBg = textBackgroundColor && !isImageBg; - var textBorderRadius = style.borderRadius; - var self = this; - var rectEl; - var imgEl; - - if (isPlainOrGradientBg || style.lineHeight || textBorderWidth && textBorderColor) { - rectEl = this._getOrCreateChild(Rect); - rectEl.useStyle(rectEl.createStyle()); - rectEl.style.fill = null; - var rectShape = rectEl.shape; - rectShape.x = x; - rectShape.y = y; - rectShape.width = width; - rectShape.height = height; - rectShape.r = textBorderRadius; - rectEl.dirtyShape(); - } - - if (isPlainOrGradientBg) { - var rectStyle = rectEl.style; - rectStyle.fill = textBackgroundColor || null; - rectStyle.fillOpacity = retrieve2(style.fillOpacity, 1); - } else if (isImageBg) { - imgEl = this._getOrCreateChild(ZRImage); - - imgEl.onload = function () { - self.dirtyStyle(); - }; - - var imgStyle = imgEl.style; - imgStyle.image = textBackgroundColor.image; - imgStyle.x = x; - imgStyle.y = y; - imgStyle.width = width; - imgStyle.height = height; - } - - if (textBorderWidth && textBorderColor) { - var rectStyle = rectEl.style; - rectStyle.lineWidth = textBorderWidth; - rectStyle.stroke = textBorderColor; - rectStyle.strokeOpacity = retrieve2(style.strokeOpacity, 1); - rectStyle.lineDash = style.borderDash; - rectStyle.lineDashOffset = style.borderDashOffset || 0; - rectEl.strokeContainThreshold = 0; - - if (rectEl.hasFill() && rectEl.hasStroke()) { - rectStyle.strokeFirst = true; - rectStyle.lineWidth *= 2; - } - } - - var commonStyle = (rectEl || imgEl).style; - commonStyle.shadowBlur = style.shadowBlur || 0; - commonStyle.shadowColor = style.shadowColor || 'transparent'; - commonStyle.shadowOffsetX = style.shadowOffsetX || 0; - commonStyle.shadowOffsetY = style.shadowOffsetY || 0; - commonStyle.opacity = retrieve3(style.opacity, topStyle.opacity, 1); - }; - - ZRText.makeFont = function (style) { - var font = ''; - - if (hasSeparateFont(style)) { - font = [style.fontStyle, style.fontWeight, parseFontSize(style.fontSize), style.fontFamily || 'sans-serif'].join(' '); - } - - return font && trim(font) || style.textFont || style.font; - }; - - return ZRText; - }(Displayable); - - var VALID_TEXT_ALIGN = { - left: true, - right: 1, - center: 1 - }; - var VALID_TEXT_VERTICAL_ALIGN = { - top: 1, - bottom: 1, - middle: 1 - }; - var FONT_PARTS = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily']; - - function parseFontSize(fontSize) { - if (typeof fontSize === 'string' && (fontSize.indexOf('px') !== -1 || fontSize.indexOf('rem') !== -1 || fontSize.indexOf('em') !== -1)) { - return fontSize; - } else if (!isNaN(+fontSize)) { - return fontSize + 'px'; - } else { - return DEFAULT_FONT_SIZE + 'px'; - } - } - - function setSeparateFont(targetStyle, sourceStyle) { - for (var i = 0; i < FONT_PARTS.length; i++) { - var fontProp = FONT_PARTS[i]; - var val = sourceStyle[fontProp]; - - if (val != null) { - targetStyle[fontProp] = val; - } - } - } - - function hasSeparateFont(style) { - return style.fontSize != null || style.fontFamily || style.fontWeight; - } - - function normalizeTextStyle(style) { - normalizeStyle(style); - each$4(style.rich, normalizeStyle); - return style; - } - - function normalizeStyle(style) { - if (style) { - style.font = ZRText.makeFont(style); - var textAlign = style.align; - textAlign === 'middle' && (textAlign = 'center'); - style.align = textAlign == null || VALID_TEXT_ALIGN[textAlign] ? textAlign : 'left'; - var verticalAlign = style.verticalAlign; - verticalAlign === 'center' && (verticalAlign = 'middle'); - style.verticalAlign = verticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[verticalAlign] ? verticalAlign : 'top'; - var textPadding = style.padding; - - if (textPadding) { - style.padding = normalizeCssArray$1(style.padding); - } - } - } - - function getStroke(stroke, lineWidth) { - return stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none' ? null : stroke.image || stroke.colorStops ? '#000' : stroke; - } - - function getFill(fill) { - return fill == null || fill === 'none' ? null : fill.image || fill.colorStops ? '#000' : fill; - } - - function getTextXForPadding(x, textAlign, textPadding) { - return textAlign === 'right' ? x - textPadding[1] : textAlign === 'center' ? x + textPadding[3] / 2 - textPadding[1] / 2 : x + textPadding[3]; - } - - function getStyleText(style) { - var text = style.text; - text != null && (text += ''); - return text; - } - - function needDrawBackground(style) { - return !!(style.backgroundColor || style.lineHeight || style.borderWidth && style.borderColor); - } - - var getECData = makeInner(); - - var setCommonECData = function (seriesIndex, dataType, dataIdx, el) { - if (el) { - var ecData = getECData(el); // Add data index and series index for indexing the data by element - // Useful in tooltip - - ecData.dataIndex = dataIdx; - ecData.dataType = dataType; - ecData.seriesIndex = seriesIndex; - ecData.ssrType = 'chart'; // TODO: not store dataIndex on children. - - if (el.type === 'group') { - el.traverse(function (child) { - var childECData = getECData(child); - childECData.seriesIndex = seriesIndex; - childECData.dataIndex = dataIdx; - childECData.dataType = dataType; - childECData.ssrType = 'chart'; - }); - } - } - }; // Reserve 0 as default. - - - var _highlightNextDigit = 1; - var _highlightKeyMap = {}; - var getSavedStates = makeInner(); - var getComponentStates = makeInner(); - var HOVER_STATE_NORMAL = 0; - var HOVER_STATE_BLUR = 1; - var HOVER_STATE_EMPHASIS = 2; - var SPECIAL_STATES = ['emphasis', 'blur', 'select']; - var DISPLAY_STATES = ['normal', 'emphasis', 'blur', 'select']; - var Z2_EMPHASIS_LIFT = 10; - var Z2_SELECT_LIFT = 9; - var HIGHLIGHT_ACTION_TYPE = 'highlight'; - var DOWNPLAY_ACTION_TYPE = 'downplay'; - var SELECT_ACTION_TYPE = 'select'; - var UNSELECT_ACTION_TYPE = 'unselect'; - var TOGGLE_SELECT_ACTION_TYPE = 'toggleSelect'; - var SELECT_CHANGED_EVENT_TYPE = 'selectchanged'; - - function hasFillOrStroke(fillOrStroke) { - return fillOrStroke != null && fillOrStroke !== 'none'; - } - - function doChangeHoverState(el, stateName, hoverStateEnum) { - if (el.onHoverStateChange && (el.hoverState || 0) !== hoverStateEnum) { - el.onHoverStateChange(stateName); - } - - el.hoverState = hoverStateEnum; - } - - function singleEnterEmphasis(el) { - // Only mark the flag. - // States will be applied in the echarts.ts in next frame. - doChangeHoverState(el, 'emphasis', HOVER_STATE_EMPHASIS); - } - - function singleLeaveEmphasis(el) { - // Only mark the flag. - // States will be applied in the echarts.ts in next frame. - if (el.hoverState === HOVER_STATE_EMPHASIS) { - doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL); - } - } - - function singleEnterBlur(el) { - doChangeHoverState(el, 'blur', HOVER_STATE_BLUR); - } - - function singleLeaveBlur(el) { - if (el.hoverState === HOVER_STATE_BLUR) { - doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL); - } - } - - function singleEnterSelect(el) { - el.selected = true; - } - - function singleLeaveSelect(el) { - el.selected = false; - } - - function updateElementState(el, updater, commonParam) { - updater(el, commonParam); - } - - function traverseUpdateState(el, updater, commonParam) { - updateElementState(el, updater, commonParam); - el.isGroup && el.traverse(function (child) { - updateElementState(child, updater, commonParam); - }); - } - - function setStatesFlag(el, stateName) { - switch (stateName) { - case 'emphasis': - el.hoverState = HOVER_STATE_EMPHASIS; - break; - - case 'normal': - el.hoverState = HOVER_STATE_NORMAL; - break; - - case 'blur': - el.hoverState = HOVER_STATE_BLUR; - break; - - case 'select': - el.selected = true; - } - } - - function getFromStateStyle(el, props, toStateName, defaultValue) { - var style = el.style; - var fromState = {}; - - for (var i = 0; i < props.length; i++) { - var propName = props[i]; - var val = style[propName]; - fromState[propName] = val == null ? defaultValue && defaultValue[propName] : val; - } - - for (var i = 0; i < el.animators.length; i++) { - var animator = el.animators[i]; - - if (animator.__fromStateTransition // Don't consider the animation to emphasis state. - && animator.__fromStateTransition.indexOf(toStateName) < 0 && animator.targetName === 'style') { - animator.saveTo(fromState, props); - } - } - - return fromState; - } - - function createEmphasisDefaultState(el, stateName, targetStates, state) { - var hasSelect = targetStates && indexOf(targetStates, 'select') >= 0; - var cloned = false; - - if (el instanceof Path) { - var store = getSavedStates(el); - var fromFill = hasSelect ? store.selectFill || store.normalFill : store.normalFill; - var fromStroke = hasSelect ? store.selectStroke || store.normalStroke : store.normalStroke; - - if (hasFillOrStroke(fromFill) || hasFillOrStroke(fromStroke)) { - state = state || {}; - var emphasisStyle = state.style || {}; // inherit case - - if (emphasisStyle.fill === 'inherit') { - cloned = true; - state = extend({}, state); - emphasisStyle = extend({}, emphasisStyle); - emphasisStyle.fill = fromFill; - } // Apply default color lift - else if (!hasFillOrStroke(emphasisStyle.fill) && hasFillOrStroke(fromFill)) { - cloned = true; // Not modify the original value. - - state = extend({}, state); - emphasisStyle = extend({}, emphasisStyle); // Already being applied 'emphasis'. DON'T lift color multiple times. - - emphasisStyle.fill = liftColor(fromFill); - } // Not highlight stroke if fill has been highlighted. - else if (!hasFillOrStroke(emphasisStyle.stroke) && hasFillOrStroke(fromStroke)) { - if (!cloned) { - state = extend({}, state); - emphasisStyle = extend({}, emphasisStyle); - } - - emphasisStyle.stroke = liftColor(fromStroke); - } - - state.style = emphasisStyle; - } - } - - if (state) { - // TODO Share with textContent? - if (state.z2 == null) { - if (!cloned) { - state = extend({}, state); - } - - var z2EmphasisLift = el.z2EmphasisLift; - state.z2 = el.z2 + (z2EmphasisLift != null ? z2EmphasisLift : Z2_EMPHASIS_LIFT); - } - } - - return state; - } - - function createSelectDefaultState(el, stateName, state) { - // const hasSelect = indexOf(el.currentStates, stateName) >= 0; - if (state) { - // TODO Share with textContent? - if (state.z2 == null) { - state = extend({}, state); - var z2SelectLift = el.z2SelectLift; - state.z2 = el.z2 + (z2SelectLift != null ? z2SelectLift : Z2_SELECT_LIFT); - } - } - - return state; - } - - function createBlurDefaultState(el, stateName, state) { - var hasBlur = indexOf(el.currentStates, stateName) >= 0; - var currentOpacity = el.style.opacity; - var fromState = !hasBlur ? getFromStateStyle(el, ['opacity'], stateName, { - opacity: 1 - }) : null; - state = state || {}; - var blurStyle = state.style || {}; - - if (blurStyle.opacity == null) { - // clone state - state = extend({}, state); - blurStyle = extend({ - // Already being applied 'emphasis'. DON'T mul opacity multiple times. - opacity: hasBlur ? currentOpacity : fromState.opacity * 0.1 - }, blurStyle); - state.style = blurStyle; - } - - return state; - } - - function elementStateProxy(stateName, targetStates) { - var state = this.states[stateName]; - - if (this.style) { - if (stateName === 'emphasis') { - return createEmphasisDefaultState(this, stateName, targetStates, state); - } else if (stateName === 'blur') { - return createBlurDefaultState(this, stateName, state); - } else if (stateName === 'select') { - return createSelectDefaultState(this, stateName, state); - } - } - - return state; - } - /** - * Set hover style (namely "emphasis style") of element. - * @param el Should not be `zrender/graphic/Group`. - * @param focus 'self' | 'selfInSeries' | 'series' - */ - - - function setDefaultStateProxy(el) { - el.stateProxy = elementStateProxy; - var textContent = el.getTextContent(); - var textGuide = el.getTextGuideLine(); - - if (textContent) { - textContent.stateProxy = elementStateProxy; - } - - if (textGuide) { - textGuide.stateProxy = elementStateProxy; - } - } - - function enterEmphasisWhenMouseOver(el, e) { - !shouldSilent(el, e) // "emphasis" event highlight has higher priority than mouse highlight. - && !el.__highByOuter && traverseUpdateState(el, singleEnterEmphasis); - } - - function leaveEmphasisWhenMouseOut(el, e) { - !shouldSilent(el, e) // "emphasis" event highlight has higher priority than mouse highlight. - && !el.__highByOuter && traverseUpdateState(el, singleLeaveEmphasis); - } - - function enterEmphasis(el, highlightDigit) { - el.__highByOuter |= 1 << (highlightDigit || 0); - traverseUpdateState(el, singleEnterEmphasis); - } - - function leaveEmphasis(el, highlightDigit) { - !(el.__highByOuter &= ~(1 << (highlightDigit || 0))) && traverseUpdateState(el, singleLeaveEmphasis); - } - - function enterBlur(el) { - traverseUpdateState(el, singleEnterBlur); - } - - function leaveBlur(el) { - traverseUpdateState(el, singleLeaveBlur); - } - - function enterSelect(el) { - traverseUpdateState(el, singleEnterSelect); - } - - function leaveSelect(el) { - traverseUpdateState(el, singleLeaveSelect); - } - - function shouldSilent(el, e) { - return el.__highDownSilentOnTouch && e.zrByTouch; - } - - function allLeaveBlur(api) { - var model = api.getModel(); - var leaveBlurredSeries = []; - var allComponentViews = []; - model.eachComponent(function (componentType, componentModel) { - var componentStates = getComponentStates(componentModel); - var isSeries = componentType === 'series'; - var view = isSeries ? api.getViewOfSeriesModel(componentModel) : api.getViewOfComponentModel(componentModel); - !isSeries && allComponentViews.push(view); - - if (componentStates.isBlured) { - // Leave blur anyway - view.group.traverse(function (child) { - singleLeaveBlur(child); - }); - isSeries && leaveBlurredSeries.push(componentModel); - } - - componentStates.isBlured = false; - }); - each$4(allComponentViews, function (view) { - if (view && view.toggleBlurSeries) { - view.toggleBlurSeries(leaveBlurredSeries, false, model); - } - }); - } - - function blurSeries(targetSeriesIndex, focus, blurScope, api) { - var ecModel = api.getModel(); - blurScope = blurScope || 'coordinateSystem'; - - function leaveBlurOfIndices(data, dataIndices) { - for (var i = 0; i < dataIndices.length; i++) { - var itemEl = data.getItemGraphicEl(dataIndices[i]); - itemEl && leaveBlur(itemEl); - } - } - - if (targetSeriesIndex == null) { - return; - } - - if (!focus || focus === 'none') { - return; - } - - var targetSeriesModel = ecModel.getSeriesByIndex(targetSeriesIndex); - var targetCoordSys = targetSeriesModel.coordinateSystem; - - if (targetCoordSys && targetCoordSys.master) { - targetCoordSys = targetCoordSys.master; - } - - var blurredSeries = []; - ecModel.eachSeries(function (seriesModel) { - var sameSeries = targetSeriesModel === seriesModel; - var coordSys = seriesModel.coordinateSystem; - - if (coordSys && coordSys.master) { - coordSys = coordSys.master; - } - - var sameCoordSys = coordSys && targetCoordSys ? coordSys === targetCoordSys : sameSeries; // If there is no coordinate system. use sameSeries instead. - - if (!( // Not blur other series if blurScope series - blurScope === 'series' && !sameSeries // Not blur other coordinate system if blurScope is coordinateSystem - || blurScope === 'coordinateSystem' && !sameCoordSys // Not blur self series if focus is series. - || focus === 'series' && sameSeries // TODO blurScope: coordinate system - )) { - var view = api.getViewOfSeriesModel(seriesModel); - view.group.traverse(function (child) { - // For the elements that have been triggered by other components, - // and are still required to be highlighted, - // because the current is directly forced to blur the element, - // it will cause the focus self to be unable to highlight, so skip the blur of this element. - if (child.__highByOuter && sameSeries && focus === 'self') { - return; - } - - singleEnterBlur(child); - }); - - if (isArrayLike(focus)) { - leaveBlurOfIndices(seriesModel.getData(), focus); - } else if (isObject$2(focus)) { - var dataTypes = keys(focus); - - for (var d = 0; d < dataTypes.length; d++) { - leaveBlurOfIndices(seriesModel.getData(dataTypes[d]), focus[dataTypes[d]]); - } - } - - blurredSeries.push(seriesModel); - getComponentStates(seriesModel).isBlured = true; - } - }); - ecModel.eachComponent(function (componentType, componentModel) { - if (componentType === 'series') { - return; - } - - var view = api.getViewOfComponentModel(componentModel); - - if (view && view.toggleBlurSeries) { - view.toggleBlurSeries(blurredSeries, true, ecModel); - } - }); - } - - function blurComponent(componentMainType, componentIndex, api) { - if (componentMainType == null || componentIndex == null) { - return; - } - - var componentModel = api.getModel().getComponent(componentMainType, componentIndex); - - if (!componentModel) { - return; - } - - getComponentStates(componentModel).isBlured = true; - var view = api.getViewOfComponentModel(componentModel); - - if (!view || !view.focusBlurEnabled) { - return; - } - - view.group.traverse(function (child) { - singleEnterBlur(child); - }); - } - - function blurSeriesFromHighlightPayload(seriesModel, payload, api) { - var seriesIndex = seriesModel.seriesIndex; - var data = seriesModel.getData(payload.dataType); - - if (!data) { - { - error("Unknown dataType " + payload.dataType); - } - return; - } - - var dataIndex = queryDataIndex(data, payload); // Pick the first one if there is multiple/none exists. - - dataIndex = (isArray(dataIndex) ? dataIndex[0] : dataIndex) || 0; - var el = data.getItemGraphicEl(dataIndex); - - if (!el) { - var count = data.count(); - var current = 0; // If data on dataIndex is NaN. - - while (!el && current < count) { - el = data.getItemGraphicEl(current++); - } - } - - if (el) { - var ecData = getECData(el); - blurSeries(seriesIndex, ecData.focus, ecData.blurScope, api); - } else { - // If there is no element put on the data. Try getting it from raw option - // TODO Should put it on seriesModel? - var focus_1 = seriesModel.get(['emphasis', 'focus']); - var blurScope = seriesModel.get(['emphasis', 'blurScope']); - - if (focus_1 != null) { - blurSeries(seriesIndex, focus_1, blurScope, api); - } - } - } - - function findComponentHighDownDispatchers(componentMainType, componentIndex, name, api) { - var ret = { - focusSelf: false, - dispatchers: null - }; - - if (componentMainType == null || componentMainType === 'series' || componentIndex == null || name == null) { - return ret; - } - - var componentModel = api.getModel().getComponent(componentMainType, componentIndex); - - if (!componentModel) { - return ret; - } - - var view = api.getViewOfComponentModel(componentModel); - - if (!view || !view.findHighDownDispatchers) { - return ret; - } - - var dispatchers = view.findHighDownDispatchers(name); // At presnet, the component (like Geo) only blur inside itself. - // So we do not use `blurScope` in component. - - var focusSelf; - - for (var i = 0; i < dispatchers.length; i++) { - if (!isHighDownDispatcher(dispatchers[i])) { - error('param should be highDownDispatcher'); - } - - if (getECData(dispatchers[i]).focus === 'self') { - focusSelf = true; - break; - } - } - - return { - focusSelf: focusSelf, - dispatchers: dispatchers - }; - } - - function handleGlobalMouseOverForHighDown(dispatcher, e, api) { - if (!isHighDownDispatcher(dispatcher)) { - error('param should be highDownDispatcher'); - } - - var ecData = getECData(dispatcher); - - var _a = findComponentHighDownDispatchers(ecData.componentMainType, ecData.componentIndex, ecData.componentHighDownName, api), - dispatchers = _a.dispatchers, - focusSelf = _a.focusSelf; // If `findHighDownDispatchers` is supported on the component, - // highlight/downplay elements with the same name. - - - if (dispatchers) { - if (focusSelf) { - blurComponent(ecData.componentMainType, ecData.componentIndex, api); - } - - each$4(dispatchers, function (dispatcher) { - return enterEmphasisWhenMouseOver(dispatcher, e); - }); - } else { - // Try blur all in the related series. Then emphasis the hoverred. - // TODO. progressive mode. - blurSeries(ecData.seriesIndex, ecData.focus, ecData.blurScope, api); - - if (ecData.focus === 'self') { - blurComponent(ecData.componentMainType, ecData.componentIndex, api); - } // Other than series, component that not support `findHighDownDispatcher` will - // also use it. But in this case, highlight/downplay are only supported in - // mouse hover but not in dispatchAction. - - - enterEmphasisWhenMouseOver(dispatcher, e); - } - } - - function handleGlobalMouseOutForHighDown(dispatcher, e, api) { - if (!isHighDownDispatcher(dispatcher)) { - error('param should be highDownDispatcher'); - } - - allLeaveBlur(api); - var ecData = getECData(dispatcher); - var dispatchers = findComponentHighDownDispatchers(ecData.componentMainType, ecData.componentIndex, ecData.componentHighDownName, api).dispatchers; - - if (dispatchers) { - each$4(dispatchers, function (dispatcher) { - return leaveEmphasisWhenMouseOut(dispatcher, e); - }); - } else { - leaveEmphasisWhenMouseOut(dispatcher, e); - } - } - - function toggleSelectionFromPayload(seriesModel, payload, api) { - if (!isSelectChangePayload(payload)) { - return; - } - - var dataType = payload.dataType; - var data = seriesModel.getData(dataType); - var dataIndex = queryDataIndex(data, payload); - - if (!isArray(dataIndex)) { - dataIndex = [dataIndex]; - } - - seriesModel[payload.type === TOGGLE_SELECT_ACTION_TYPE ? 'toggleSelect' : payload.type === SELECT_ACTION_TYPE ? 'select' : 'unselect'](dataIndex, dataType); - } - - function updateSeriesElementSelection(seriesModel) { - var allData = seriesModel.getAllData(); - each$4(allData, function (_a) { - var data = _a.data, - type = _a.type; - data.eachItemGraphicEl(function (el, idx) { - seriesModel.isSelected(idx, type) ? enterSelect(el) : leaveSelect(el); - }); - }); - } - - function getAllSelectedIndices(ecModel) { - var ret = []; - ecModel.eachSeries(function (seriesModel) { - var allData = seriesModel.getAllData(); - each$4(allData, function (_a) { - _a.data; - var type = _a.type; - var dataIndices = seriesModel.getSelectedDataIndices(); - - if (dataIndices.length > 0) { - var item = { - dataIndex: dataIndices, - seriesIndex: seriesModel.seriesIndex - }; - - if (type != null) { - item.dataType = type; - } - - ret.push(item); - } - }); - }); - return ret; - } - /** - * Enable the function that mouseover will trigger the emphasis state. - * - * NOTE: - * This function should be used on the element with dataIndex, seriesIndex. - * - */ - - - function enableHoverEmphasis(el, focus, blurScope) { - setAsHighDownDispatcher(el, true); - traverseUpdateState(el, setDefaultStateProxy); - enableHoverFocus(el, focus, blurScope); - } - - function disableHoverEmphasis(el) { - setAsHighDownDispatcher(el, false); - } - - function toggleHoverEmphasis(el, focus, blurScope, isDisabled) { - isDisabled ? disableHoverEmphasis(el) : enableHoverEmphasis(el, focus, blurScope); - } - - function enableHoverFocus(el, focus, blurScope) { - var ecData = getECData(el); - - if (focus != null) { - // TODO dataIndex may be set after this function. This check is not useful. - // if (ecData.dataIndex == null) { - // if (__DEV__) { - // console.warn('focus can only been set on element with dataIndex'); - // } - // } - // else { - ecData.focus = focus; - ecData.blurScope = blurScope; // } - } else if (ecData.focus) { - ecData.focus = null; - } - } - - var OTHER_STATES = ['emphasis', 'blur', 'select']; - var defaultStyleGetterMap = { - itemStyle: 'getItemStyle', - lineStyle: 'getLineStyle', - areaStyle: 'getAreaStyle' - }; - /** - * Set emphasis/blur/selected states of element. - */ - - function setStatesStylesFromModel(el, itemModel, styleType, // default itemStyle - getter) { - styleType = styleType || 'itemStyle'; - - for (var i = 0; i < OTHER_STATES.length; i++) { - var stateName = OTHER_STATES[i]; - var model = itemModel.getModel([stateName, styleType]); - var state = el.ensureState(stateName); // Let it throw error if getterType is not found. - - state.style = getter ? getter(model) : model[defaultStyleGetterMap[styleType]](); - } - } - /** - * - * Set element as highlight / downplay dispatcher. - * It will be checked when element received mouseover event or from highlight action. - * It's in change of all highlight/downplay behavior of it's children. - * - * @param el - * @param el.highDownSilentOnTouch - * In touch device, mouseover event will be trigger on touchstart event - * (see module:zrender/dom/HandlerProxy). By this mechanism, we can - * conveniently use hoverStyle when tap on touch screen without additional - * code for compatibility. - * But if the chart/component has select feature, which usually also use - * hoverStyle, there might be conflict between 'select-highlight' and - * 'hover-highlight' especially when roam is enabled (see geo for example). - * In this case, `highDownSilentOnTouch` should be used to disable - * hover-highlight on touch device. - * @param asDispatcher If `false`, do not set as "highDownDispatcher". - */ - - - function setAsHighDownDispatcher(el, asDispatcher) { - var disable = asDispatcher === false; - var extendedEl = el; // Make `highDownSilentOnTouch` and `onStateChange` only work after - // `setAsHighDownDispatcher` called. Avoid it is modified by user unexpectedly. - - if (el.highDownSilentOnTouch) { - extendedEl.__highDownSilentOnTouch = el.highDownSilentOnTouch; - } // Simple optimize, since this method might be - // called for each elements of a group in some cases. - - - if (!disable || extendedEl.__highDownDispatcher) { - // Emphasis, normal can be triggered manually by API or other components like hover link. - // el[method]('emphasis', onElementEmphasisEvent)[method]('normal', onElementNormalEvent); - // Also keep previous record. - extendedEl.__highByOuter = extendedEl.__highByOuter || 0; - extendedEl.__highDownDispatcher = !disable; - } - } - - function isHighDownDispatcher(el) { - return !!(el && el.__highDownDispatcher); - } - /** - * Support highlight/downplay record on each elements. - * For the case: hover highlight/downplay (legend, visualMap, ...) and - * user triggered highlight/downplay should not conflict. - * Only all of the highlightDigit cleared, return to normal. - * @param {string} highlightKey - * @return {number} highlightDigit - */ - - - function getHighlightDigit(highlightKey) { - var highlightDigit = _highlightKeyMap[highlightKey]; - - if (highlightDigit == null && _highlightNextDigit <= 32) { - highlightDigit = _highlightKeyMap[highlightKey] = _highlightNextDigit++; - } - - return highlightDigit; - } - - function isSelectChangePayload(payload) { - var payloadType = payload.type; - return payloadType === SELECT_ACTION_TYPE || payloadType === UNSELECT_ACTION_TYPE || payloadType === TOGGLE_SELECT_ACTION_TYPE; - } - - function isHighDownPayload(payload) { - var payloadType = payload.type; - return payloadType === HIGHLIGHT_ACTION_TYPE || payloadType === DOWNPLAY_ACTION_TYPE; - } - - function savePathStates(el) { - var store = getSavedStates(el); - store.normalFill = el.style.fill; - store.normalStroke = el.style.stroke; - var selectState = el.states.select || {}; - store.selectFill = selectState.style && selectState.style.fill || null; - store.selectStroke = selectState.style && selectState.style.stroke || null; - } - - var CMD$1 = PathProxy.CMD; - var points = [[], [], []]; - var mathSqrt$2 = Math.sqrt; - var mathAtan2 = Math.atan2; - - function transformPath(path, m) { - if (!m) { - return; - } - - var data = path.data; - var len = path.len(); - var cmd; - var nPoint; - var i; - var j; - var k; - var p; - var M = CMD$1.M; - var C = CMD$1.C; - var L = CMD$1.L; - var R = CMD$1.R; - var A = CMD$1.A; - var Q = CMD$1.Q; - - for (i = 0, j = 0; i < len;) { - cmd = data[i++]; - j = i; - nPoint = 0; - - switch (cmd) { - case M: - nPoint = 1; - break; - - case L: - nPoint = 1; - break; - - case C: - nPoint = 3; - break; - - case Q: - nPoint = 2; - break; - - case A: - var x = m[4]; - var y = m[5]; - var sx = mathSqrt$2(m[0] * m[0] + m[1] * m[1]); - var sy = mathSqrt$2(m[2] * m[2] + m[3] * m[3]); - var angle = mathAtan2(-m[1] / sy, m[0] / sx); - data[i] *= sx; - data[i++] += x; - data[i] *= sy; - data[i++] += y; - data[i++] *= sx; - data[i++] *= sy; - data[i++] += angle; - data[i++] += angle; - i += 2; - j = i; - break; - - case R: - p[0] = data[i++]; - p[1] = data[i++]; - applyTransform$1(p, p, m); - data[j++] = p[0]; - data[j++] = p[1]; - p[0] += data[i++]; - p[1] += data[i++]; - applyTransform$1(p, p, m); - data[j++] = p[0]; - data[j++] = p[1]; - } - - for (k = 0; k < nPoint; k++) { - var p_1 = points[k]; - p_1[0] = data[i++]; - p_1[1] = data[i++]; - applyTransform$1(p_1, p_1, m); - data[j++] = p_1[0]; - data[j++] = p_1[1]; - } - } - - path.increaseVersion(); - } - - var mathSqrt$1 = Math.sqrt; - var mathSin$1 = Math.sin; - var mathCos$1 = Math.cos; - var PI$3 = Math.PI; - - function vMag(v) { - return Math.sqrt(v[0] * v[0] + v[1] * v[1]); - } - - function vRatio(u, v) { - return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v)); - } - - function vAngle(u, v) { - return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(vRatio(u, v)); - } - - function processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) { - var psi = psiDeg * (PI$3 / 180.0); - var xp = mathCos$1(psi) * (x1 - x2) / 2.0 + mathSin$1(psi) * (y1 - y2) / 2.0; - var yp = -1 * mathSin$1(psi) * (x1 - x2) / 2.0 + mathCos$1(psi) * (y1 - y2) / 2.0; - var lambda = xp * xp / (rx * rx) + yp * yp / (ry * ry); - - if (lambda > 1) { - rx *= mathSqrt$1(lambda); - ry *= mathSqrt$1(lambda); - } - - var f = (fa === fs ? -1 : 1) * mathSqrt$1((rx * rx * (ry * ry) - rx * rx * (yp * yp) - ry * ry * (xp * xp)) / (rx * rx * (yp * yp) + ry * ry * (xp * xp))) || 0; - var cxp = f * rx * yp / ry; - var cyp = f * -ry * xp / rx; - var cx = (x1 + x2) / 2.0 + mathCos$1(psi) * cxp - mathSin$1(psi) * cyp; - var cy = (y1 + y2) / 2.0 + mathSin$1(psi) * cxp + mathCos$1(psi) * cyp; - var theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]); - var u = [(xp - cxp) / rx, (yp - cyp) / ry]; - var v = [(-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry]; - var dTheta = vAngle(u, v); - - if (vRatio(u, v) <= -1) { - dTheta = PI$3; - } - - if (vRatio(u, v) >= 1) { - dTheta = 0; - } - - if (dTheta < 0) { - var n = Math.round(dTheta / PI$3 * 1e6) / 1e6; - dTheta = PI$3 * 2 + n % 2 * PI$3; - } - - path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs); - } - - var commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig; - var numberReg = /-?([0-9]*\.)?[0-9]+([eE]-?[0-9]+)?/g; - - function createPathProxyFromString(data) { - var path = new PathProxy(); - - if (!data) { - return path; - } - - var cpx = 0; - var cpy = 0; - var subpathX = cpx; - var subpathY = cpy; - var prevCmd; - var CMD = PathProxy.CMD; - var cmdList = data.match(commandReg); - - if (!cmdList) { - return path; - } - - for (var l = 0; l < cmdList.length; l++) { - var cmdText = cmdList[l]; - var cmdStr = cmdText.charAt(0); - var cmd = void 0; - var p = cmdText.match(numberReg) || []; - var pLen = p.length; - - for (var i = 0; i < pLen; i++) { - p[i] = parseFloat(p[i]); - } - - var off = 0; - - while (off < pLen) { - var ctlPtx = void 0; - var ctlPty = void 0; - var rx = void 0; - var ry = void 0; - var psi = void 0; - var fa = void 0; - var fs = void 0; - var x1 = cpx; - var y1 = cpy; - var len = void 0; - var pathData = void 0; - - switch (cmdStr) { - case 'l': - cpx += p[off++]; - cpy += p[off++]; - cmd = CMD.L; - path.addData(cmd, cpx, cpy); - break; - - case 'L': - cpx = p[off++]; - cpy = p[off++]; - cmd = CMD.L; - path.addData(cmd, cpx, cpy); - break; - - case 'm': - cpx += p[off++]; - cpy += p[off++]; - cmd = CMD.M; - path.addData(cmd, cpx, cpy); - subpathX = cpx; - subpathY = cpy; - cmdStr = 'l'; - break; - - case 'M': - cpx = p[off++]; - cpy = p[off++]; - cmd = CMD.M; - path.addData(cmd, cpx, cpy); - subpathX = cpx; - subpathY = cpy; - cmdStr = 'L'; - break; - - case 'h': - cpx += p[off++]; - cmd = CMD.L; - path.addData(cmd, cpx, cpy); - break; - - case 'H': - cpx = p[off++]; - cmd = CMD.L; - path.addData(cmd, cpx, cpy); - break; - - case 'v': - cpy += p[off++]; - cmd = CMD.L; - path.addData(cmd, cpx, cpy); - break; - - case 'V': - cpy = p[off++]; - cmd = CMD.L; - path.addData(cmd, cpx, cpy); - break; - - case 'C': - cmd = CMD.C; - path.addData(cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]); - cpx = p[off - 2]; - cpy = p[off - 1]; - break; - - case 'c': - cmd = CMD.C; - path.addData(cmd, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy); - cpx += p[off - 2]; - cpy += p[off - 1]; - break; - - case 'S': - ctlPtx = cpx; - ctlPty = cpy; - len = path.len(); - pathData = path.data; - - if (prevCmd === CMD.C) { - ctlPtx += cpx - pathData[len - 4]; - ctlPty += cpy - pathData[len - 3]; - } - - cmd = CMD.C; - x1 = p[off++]; - y1 = p[off++]; - cpx = p[off++]; - cpy = p[off++]; - path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy); - break; - - case 's': - ctlPtx = cpx; - ctlPty = cpy; - len = path.len(); - pathData = path.data; - - if (prevCmd === CMD.C) { - ctlPtx += cpx - pathData[len - 4]; - ctlPty += cpy - pathData[len - 3]; - } - - cmd = CMD.C; - x1 = cpx + p[off++]; - y1 = cpy + p[off++]; - cpx += p[off++]; - cpy += p[off++]; - path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy); - break; - - case 'Q': - x1 = p[off++]; - y1 = p[off++]; - cpx = p[off++]; - cpy = p[off++]; - cmd = CMD.Q; - path.addData(cmd, x1, y1, cpx, cpy); - break; - - case 'q': - x1 = p[off++] + cpx; - y1 = p[off++] + cpy; - cpx += p[off++]; - cpy += p[off++]; - cmd = CMD.Q; - path.addData(cmd, x1, y1, cpx, cpy); - break; - - case 'T': - ctlPtx = cpx; - ctlPty = cpy; - len = path.len(); - pathData = path.data; - - if (prevCmd === CMD.Q) { - ctlPtx += cpx - pathData[len - 4]; - ctlPty += cpy - pathData[len - 3]; - } - - cpx = p[off++]; - cpy = p[off++]; - cmd = CMD.Q; - path.addData(cmd, ctlPtx, ctlPty, cpx, cpy); - break; - - case 't': - ctlPtx = cpx; - ctlPty = cpy; - len = path.len(); - pathData = path.data; - - if (prevCmd === CMD.Q) { - ctlPtx += cpx - pathData[len - 4]; - ctlPty += cpy - pathData[len - 3]; - } - - cpx += p[off++]; - cpy += p[off++]; - cmd = CMD.Q; - path.addData(cmd, ctlPtx, ctlPty, cpx, cpy); - break; - - case 'A': - rx = p[off++]; - ry = p[off++]; - psi = p[off++]; - fa = p[off++]; - fs = p[off++]; - x1 = cpx, y1 = cpy; - cpx = p[off++]; - cpy = p[off++]; - cmd = CMD.A; - processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path); - break; - - case 'a': - rx = p[off++]; - ry = p[off++]; - psi = p[off++]; - fa = p[off++]; - fs = p[off++]; - x1 = cpx, y1 = cpy; - cpx += p[off++]; - cpy += p[off++]; - cmd = CMD.A; - processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path); - break; - } - } - - if (cmdStr === 'z' || cmdStr === 'Z') { - cmd = CMD.Z; - path.addData(cmd); - cpx = subpathX; - cpy = subpathY; - } - - prevCmd = cmd; - } - - path.toStatic(); - return path; - } - - var SVGPath = function (_super) { - __extends(SVGPath, _super); - - function SVGPath() { - return _super !== null && _super.apply(this, arguments) || this; - } - - SVGPath.prototype.applyTransform = function (m) {}; - - return SVGPath; - }(Path); - - function isPathProxy(path) { - return path.setData != null; - } - - function createPathOptions(str, opts) { - var pathProxy = createPathProxyFromString(str); - var innerOpts = extend({}, opts); - - innerOpts.buildPath = function (path) { - var beProxy = isPathProxy(path); - - if (beProxy && path.canSave()) { - path.appendPath(pathProxy); - var ctx = path.getContext(); - - if (ctx) { - path.rebuildPath(ctx, 1); - } - } else { - var ctx = beProxy ? path.getContext() : path; - - if (ctx) { - pathProxy.rebuildPath(ctx, 1); - } - } - }; - - innerOpts.applyTransform = function (m) { - transformPath(pathProxy, m); - this.dirtyShape(); - }; - - return innerOpts; - } - - function createFromString(str, opts) { - return new SVGPath(createPathOptions(str, opts)); - } - - function extendFromString(str, defaultOpts) { - var innerOpts = createPathOptions(str, defaultOpts); - - var Sub = function (_super) { - __extends(Sub, _super); - - function Sub(opts) { - var _this = _super.call(this, opts) || this; - - _this.applyTransform = innerOpts.applyTransform; - _this.buildPath = innerOpts.buildPath; - return _this; - } - - return Sub; - }(SVGPath); - - return Sub; - } - - function mergePath$1(pathEls, opts) { - var pathList = []; - var len = pathEls.length; - - for (var i = 0; i < len; i++) { - var pathEl = pathEls[i]; - pathList.push(pathEl.getUpdatedPathProxy(true)); - } - - var pathBundle = new Path(opts); - pathBundle.createPathProxy(); - - pathBundle.buildPath = function (path) { - if (isPathProxy(path)) { - path.appendPath(pathList); - var ctx = path.getContext(); - - if (ctx) { - path.rebuildPath(ctx, 1); - } - } - }; - - return pathBundle; - } - - var CircleShape = function () { - function CircleShape() { - this.cx = 0; - this.cy = 0; - this.r = 0; - } - - return CircleShape; - }(); - - var Circle = function (_super) { - __extends(Circle, _super); - - function Circle(opts) { - return _super.call(this, opts) || this; - } - - Circle.prototype.getDefaultShape = function () { - return new CircleShape(); - }; - - Circle.prototype.buildPath = function (ctx, shape) { - ctx.moveTo(shape.cx + shape.r, shape.cy); - ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2); - }; - - return Circle; - }(Path); - - Circle.prototype.type = 'circle'; - - var EllipseShape = function () { - function EllipseShape() { - this.cx = 0; - this.cy = 0; - this.rx = 0; - this.ry = 0; - } - - return EllipseShape; - }(); - - var Ellipse = function (_super) { - __extends(Ellipse, _super); - - function Ellipse(opts) { - return _super.call(this, opts) || this; - } - - Ellipse.prototype.getDefaultShape = function () { - return new EllipseShape(); - }; - - Ellipse.prototype.buildPath = function (ctx, shape) { - var k = 0.5522848; - var x = shape.cx; - var y = shape.cy; - var a = shape.rx; - var b = shape.ry; - var ox = a * k; - var oy = b * k; - ctx.moveTo(x - a, y); - ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b); - ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y); - ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b); - ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y); - ctx.closePath(); - }; - - return Ellipse; - }(Path); - - Ellipse.prototype.type = 'ellipse'; - var PI$2 = Math.PI; - var PI2$1 = PI$2 * 2; - var mathSin = Math.sin; - var mathCos = Math.cos; - var mathACos = Math.acos; - var mathATan2 = Math.atan2; - var mathAbs$1 = Math.abs; - var mathSqrt = Math.sqrt; - var mathMax$3 = Math.max; - var mathMin$3 = Math.min; - var e = 1e-4; - - function intersect(x0, y0, x1, y1, x2, y2, x3, y3) { - var dx10 = x1 - x0; - var dy10 = y1 - y0; - var dx32 = x3 - x2; - var dy32 = y3 - y2; - var t = dy32 * dx10 - dx32 * dy10; - - if (t * t < e) { - return; - } - - t = (dx32 * (y0 - y2) - dy32 * (x0 - x2)) / t; - return [x0 + t * dx10, y0 + t * dy10]; - } - - function computeCornerTangents(x0, y0, x1, y1, radius, cr, clockwise) { - var x01 = x0 - x1; - var y01 = y0 - y1; - var lo = (clockwise ? cr : -cr) / mathSqrt(x01 * x01 + y01 * y01); - var ox = lo * y01; - var oy = -lo * x01; - var x11 = x0 + ox; - var y11 = y0 + oy; - var x10 = x1 + ox; - var y10 = y1 + oy; - var x00 = (x11 + x10) / 2; - var y00 = (y11 + y10) / 2; - var dx = x10 - x11; - var dy = y10 - y11; - var d2 = dx * dx + dy * dy; - var r = radius - cr; - var s = x11 * y10 - x10 * y11; - var d = (dy < 0 ? -1 : 1) * mathSqrt(mathMax$3(0, r * r * d2 - s * s)); - var cx0 = (s * dy - dx * d) / d2; - var cy0 = (-s * dx - dy * d) / d2; - var cx1 = (s * dy + dx * d) / d2; - var cy1 = (-s * dx + dy * d) / d2; - var dx0 = cx0 - x00; - var dy0 = cy0 - y00; - var dx1 = cx1 - x00; - var dy1 = cy1 - y00; - - if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) { - cx0 = cx1; - cy0 = cy1; - } - - return { - cx: cx0, - cy: cy0, - x0: -ox, - y0: -oy, - x1: cx0 * (radius / r - 1), - y1: cy0 * (radius / r - 1) - }; - } - - function normalizeCornerRadius(cr) { - var arr; - - if (isArray(cr)) { - var len = cr.length; - - if (!len) { - return cr; - } - - if (len === 1) { - arr = [cr[0], cr[0], 0, 0]; - } else if (len === 2) { - arr = [cr[0], cr[0], cr[1], cr[1]]; - } else if (len === 3) { - arr = cr.concat(cr[2]); - } else { - arr = cr; - } - } else { - arr = [cr, cr, cr, cr]; - } - - return arr; - } - - function buildPath$1(ctx, shape) { - var _a; - - var radius = mathMax$3(shape.r, 0); - var innerRadius = mathMax$3(shape.r0 || 0, 0); - var hasRadius = radius > 0; - var hasInnerRadius = innerRadius > 0; - - if (!hasRadius && !hasInnerRadius) { - return; - } - - if (!hasRadius) { - radius = innerRadius; - innerRadius = 0; - } - - if (innerRadius > radius) { - var tmp = radius; - radius = innerRadius; - innerRadius = tmp; - } - - var startAngle = shape.startAngle, - endAngle = shape.endAngle; - - if (isNaN(startAngle) || isNaN(endAngle)) { - return; - } - - var cx = shape.cx, - cy = shape.cy; - var clockwise = !!shape.clockwise; - var arc = mathAbs$1(endAngle - startAngle); - var mod = arc > PI2$1 && arc % PI2$1; - mod > e && (arc = mod); - - if (!(radius > e)) { - ctx.moveTo(cx, cy); - } else if (arc > PI2$1 - e) { - ctx.moveTo(cx + radius * mathCos(startAngle), cy + radius * mathSin(startAngle)); - ctx.arc(cx, cy, radius, startAngle, endAngle, !clockwise); - - if (innerRadius > e) { - ctx.moveTo(cx + innerRadius * mathCos(endAngle), cy + innerRadius * mathSin(endAngle)); - ctx.arc(cx, cy, innerRadius, endAngle, startAngle, clockwise); - } - } else { - var icrStart = void 0; - var icrEnd = void 0; - var ocrStart = void 0; - var ocrEnd = void 0; - var ocrs = void 0; - var ocre = void 0; - var icrs = void 0; - var icre = void 0; - var ocrMax = void 0; - var icrMax = void 0; - var limitedOcrMax = void 0; - var limitedIcrMax = void 0; - var xre = void 0; - var yre = void 0; - var xirs = void 0; - var yirs = void 0; - var xrs = radius * mathCos(startAngle); - var yrs = radius * mathSin(startAngle); - var xire = innerRadius * mathCos(endAngle); - var yire = innerRadius * mathSin(endAngle); - var hasArc = arc > e; - - if (hasArc) { - var cornerRadius = shape.cornerRadius; - - if (cornerRadius) { - _a = normalizeCornerRadius(cornerRadius), icrStart = _a[0], icrEnd = _a[1], ocrStart = _a[2], ocrEnd = _a[3]; - } - - var halfRd = mathAbs$1(radius - innerRadius) / 2; - ocrs = mathMin$3(halfRd, ocrStart); - ocre = mathMin$3(halfRd, ocrEnd); - icrs = mathMin$3(halfRd, icrStart); - icre = mathMin$3(halfRd, icrEnd); - limitedOcrMax = ocrMax = mathMax$3(ocrs, ocre); - limitedIcrMax = icrMax = mathMax$3(icrs, icre); - - if (ocrMax > e || icrMax > e) { - xre = radius * mathCos(endAngle); - yre = radius * mathSin(endAngle); - xirs = innerRadius * mathCos(startAngle); - yirs = innerRadius * mathSin(startAngle); - - if (arc < PI$2) { - var it_1 = intersect(xrs, yrs, xirs, yirs, xre, yre, xire, yire); - - if (it_1) { - var x0 = xrs - it_1[0]; - var y0 = yrs - it_1[1]; - var x1 = xre - it_1[0]; - var y1 = yre - it_1[1]; - var a = 1 / mathSin(mathACos((x0 * x1 + y0 * y1) / (mathSqrt(x0 * x0 + y0 * y0) * mathSqrt(x1 * x1 + y1 * y1))) / 2); - var b = mathSqrt(it_1[0] * it_1[0] + it_1[1] * it_1[1]); - limitedOcrMax = mathMin$3(ocrMax, (radius - b) / (a + 1)); - limitedIcrMax = mathMin$3(icrMax, (innerRadius - b) / (a - 1)); - } - } - } - } - - if (!hasArc) { - ctx.moveTo(cx + xrs, cy + yrs); - } else if (limitedOcrMax > e) { - var crStart = mathMin$3(ocrStart, limitedOcrMax); - var crEnd = mathMin$3(ocrEnd, limitedOcrMax); - var ct0 = computeCornerTangents(xirs, yirs, xrs, yrs, radius, crStart, clockwise); - var ct1 = computeCornerTangents(xre, yre, xire, yire, radius, crEnd, clockwise); - ctx.moveTo(cx + ct0.cx + ct0.x0, cy + ct0.cy + ct0.y0); - - if (limitedOcrMax < ocrMax && crStart === crEnd) { - ctx.arc(cx + ct0.cx, cy + ct0.cy, limitedOcrMax, mathATan2(ct0.y0, ct0.x0), mathATan2(ct1.y0, ct1.x0), !clockwise); - } else { - crStart > 0 && ctx.arc(cx + ct0.cx, cy + ct0.cy, crStart, mathATan2(ct0.y0, ct0.x0), mathATan2(ct0.y1, ct0.x1), !clockwise); - ctx.arc(cx, cy, radius, mathATan2(ct0.cy + ct0.y1, ct0.cx + ct0.x1), mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1), !clockwise); - crEnd > 0 && ctx.arc(cx + ct1.cx, cy + ct1.cy, crEnd, mathATan2(ct1.y1, ct1.x1), mathATan2(ct1.y0, ct1.x0), !clockwise); - } - } else { - ctx.moveTo(cx + xrs, cy + yrs); - ctx.arc(cx, cy, radius, startAngle, endAngle, !clockwise); - } - - if (!(innerRadius > e) || !hasArc) { - ctx.lineTo(cx + xire, cy + yire); - } else if (limitedIcrMax > e) { - var crStart = mathMin$3(icrStart, limitedIcrMax); - var crEnd = mathMin$3(icrEnd, limitedIcrMax); - var ct0 = computeCornerTangents(xire, yire, xre, yre, innerRadius, -crEnd, clockwise); - var ct1 = computeCornerTangents(xrs, yrs, xirs, yirs, innerRadius, -crStart, clockwise); - ctx.lineTo(cx + ct0.cx + ct0.x0, cy + ct0.cy + ct0.y0); - - if (limitedIcrMax < icrMax && crStart === crEnd) { - ctx.arc(cx + ct0.cx, cy + ct0.cy, limitedIcrMax, mathATan2(ct0.y0, ct0.x0), mathATan2(ct1.y0, ct1.x0), !clockwise); - } else { - crEnd > 0 && ctx.arc(cx + ct0.cx, cy + ct0.cy, crEnd, mathATan2(ct0.y0, ct0.x0), mathATan2(ct0.y1, ct0.x1), !clockwise); - ctx.arc(cx, cy, innerRadius, mathATan2(ct0.cy + ct0.y1, ct0.cx + ct0.x1), mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1), clockwise); - crStart > 0 && ctx.arc(cx + ct1.cx, cy + ct1.cy, crStart, mathATan2(ct1.y1, ct1.x1), mathATan2(ct1.y0, ct1.x0), !clockwise); - } - } else { - ctx.lineTo(cx + xire, cy + yire); - ctx.arc(cx, cy, innerRadius, endAngle, startAngle, clockwise); - } - } - - ctx.closePath(); - } - - var SectorShape = function () { - function SectorShape() { - this.cx = 0; - this.cy = 0; - this.r0 = 0; - this.r = 0; - this.startAngle = 0; - this.endAngle = Math.PI * 2; - this.clockwise = true; - this.cornerRadius = 0; - } - - return SectorShape; - }(); - - var Sector = function (_super) { - __extends(Sector, _super); - - function Sector(opts) { - return _super.call(this, opts) || this; - } - - Sector.prototype.getDefaultShape = function () { - return new SectorShape(); - }; - - Sector.prototype.buildPath = function (ctx, shape) { - buildPath$1(ctx, shape); - }; - - Sector.prototype.isZeroArea = function () { - return this.shape.startAngle === this.shape.endAngle || this.shape.r === this.shape.r0; - }; - - return Sector; - }(Path); - - Sector.prototype.type = 'sector'; - - var RingShape = function () { - function RingShape() { - this.cx = 0; - this.cy = 0; - this.r = 0; - this.r0 = 0; - } - - return RingShape; - }(); - - var Ring = function (_super) { - __extends(Ring, _super); - - function Ring(opts) { - return _super.call(this, opts) || this; - } - - Ring.prototype.getDefaultShape = function () { - return new RingShape(); - }; - - Ring.prototype.buildPath = function (ctx, shape) { - var x = shape.cx; - var y = shape.cy; - var PI2 = Math.PI * 2; - ctx.moveTo(x + shape.r, y); - ctx.arc(x, y, shape.r, 0, PI2, false); - ctx.moveTo(x + shape.r0, y); - ctx.arc(x, y, shape.r0, 0, PI2, true); - }; - - return Ring; - }(Path); - - Ring.prototype.type = 'ring'; - - function smoothBezier(points, smooth, isLoop, constraint) { - var cps = []; - var v = []; - var v1 = []; - var v2 = []; - var prevPoint; - var nextPoint; - var min; - var max; - - if (constraint) { - min = [Infinity, Infinity]; - max = [-Infinity, -Infinity]; - - for (var i = 0, len = points.length; i < len; i++) { - min$1(min, min, points[i]); - max$1(max, max, points[i]); - } - - min$1(min, min, constraint[0]); - max$1(max, max, constraint[1]); - } - - for (var i = 0, len = points.length; i < len; i++) { - var point = points[i]; - - if (isLoop) { - prevPoint = points[i ? i - 1 : len - 1]; - nextPoint = points[(i + 1) % len]; - } else { - if (i === 0 || i === len - 1) { - cps.push(clone$2(points[i])); - continue; - } else { - prevPoint = points[i - 1]; - nextPoint = points[i + 1]; - } - } - - sub(v, nextPoint, prevPoint); - scale$2(v, v, smooth); - var d0 = distance(point, prevPoint); - var d1 = distance(point, nextPoint); - var sum = d0 + d1; - - if (sum !== 0) { - d0 /= sum; - d1 /= sum; - } - - scale$2(v1, v, -d0); - scale$2(v2, v, d1); - var cp0 = add([], point, v1); - var cp1 = add([], point, v2); - - if (constraint) { - max$1(cp0, cp0, min); - min$1(cp0, cp0, max); - max$1(cp1, cp1, min); - min$1(cp1, cp1, max); - } - - cps.push(cp0); - cps.push(cp1); - } - - if (isLoop) { - cps.push(cps.shift()); - } - - return cps; - } - - function buildPath(ctx, shape, closePath) { - var smooth = shape.smooth; - var points = shape.points; - - if (points && points.length >= 2) { - if (smooth) { - var controlPoints = smoothBezier(points, smooth, closePath, shape.smoothConstraint); - ctx.moveTo(points[0][0], points[0][1]); - var len = points.length; - - for (var i = 0; i < (closePath ? len : len - 1); i++) { - var cp1 = controlPoints[i * 2]; - var cp2 = controlPoints[i * 2 + 1]; - var p = points[(i + 1) % len]; - ctx.bezierCurveTo(cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]); - } - } else { - ctx.moveTo(points[0][0], points[0][1]); - - for (var i = 1, l = points.length; i < l; i++) { - ctx.lineTo(points[i][0], points[i][1]); - } - } - - closePath && ctx.closePath(); - } - } - - var PolygonShape = function () { - function PolygonShape() { - this.points = null; - this.smooth = 0; - this.smoothConstraint = null; - } - - return PolygonShape; - }(); - - var Polygon = function (_super) { - __extends(Polygon, _super); - - function Polygon(opts) { - return _super.call(this, opts) || this; - } - - Polygon.prototype.getDefaultShape = function () { - return new PolygonShape(); - }; - - Polygon.prototype.buildPath = function (ctx, shape) { - buildPath(ctx, shape, true); - }; - - return Polygon; - }(Path); - - Polygon.prototype.type = 'polygon'; - - var PolylineShape = function () { - function PolylineShape() { - this.points = null; - this.percent = 1; - this.smooth = 0; - this.smoothConstraint = null; - } - - return PolylineShape; - }(); - - var Polyline = function (_super) { - __extends(Polyline, _super); - - function Polyline(opts) { - return _super.call(this, opts) || this; - } - - Polyline.prototype.getDefaultStyle = function () { - return { - stroke: '#000', - fill: null - }; - }; - - Polyline.prototype.getDefaultShape = function () { - return new PolylineShape(); - }; - - Polyline.prototype.buildPath = function (ctx, shape) { - buildPath(ctx, shape, false); - }; - - return Polyline; - }(Path); - - Polyline.prototype.type = 'polyline'; - var subPixelOptimizeOutputShape = {}; - - var LineShape = function () { - function LineShape() { - this.x1 = 0; - this.y1 = 0; - this.x2 = 0; - this.y2 = 0; - this.percent = 1; - } - - return LineShape; - }(); - - var Line = function (_super) { - __extends(Line, _super); - - function Line(opts) { - return _super.call(this, opts) || this; - } - - Line.prototype.getDefaultStyle = function () { - return { - stroke: '#000', - fill: null - }; - }; - - Line.prototype.getDefaultShape = function () { - return new LineShape(); - }; - - Line.prototype.buildPath = function (ctx, shape) { - var x1; - var y1; - var x2; - var y2; - - if (this.subPixelOptimize) { - var optimizedShape = subPixelOptimizeLine$1(subPixelOptimizeOutputShape, shape, this.style); - x1 = optimizedShape.x1; - y1 = optimizedShape.y1; - x2 = optimizedShape.x2; - y2 = optimizedShape.y2; - } else { - x1 = shape.x1; - y1 = shape.y1; - x2 = shape.x2; - y2 = shape.y2; - } - - var percent = shape.percent; - - if (percent === 0) { - return; - } - - ctx.moveTo(x1, y1); - - if (percent < 1) { - x2 = x1 * (1 - percent) + x2 * percent; - y2 = y1 * (1 - percent) + y2 * percent; - } - - ctx.lineTo(x2, y2); - }; - - Line.prototype.pointAt = function (p) { - var shape = this.shape; - return [shape.x1 * (1 - p) + shape.x2 * p, shape.y1 * (1 - p) + shape.y2 * p]; - }; - - return Line; - }(Path); - - Line.prototype.type = 'line'; - var out = []; - - var BezierCurveShape = function () { - function BezierCurveShape() { - this.x1 = 0; - this.y1 = 0; - this.x2 = 0; - this.y2 = 0; - this.cpx1 = 0; - this.cpy1 = 0; - this.percent = 1; - } - - return BezierCurveShape; - }(); - - function someVectorAt(shape, t, isTangent) { - var cpx2 = shape.cpx2; - var cpy2 = shape.cpy2; - - if (cpx2 != null || cpy2 != null) { - return [(isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t), (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)]; - } else { - return [(isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t), (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)]; - } - } - - var BezierCurve = function (_super) { - __extends(BezierCurve, _super); - - function BezierCurve(opts) { - return _super.call(this, opts) || this; - } - - BezierCurve.prototype.getDefaultStyle = function () { - return { - stroke: '#000', - fill: null - }; - }; - - BezierCurve.prototype.getDefaultShape = function () { - return new BezierCurveShape(); - }; - - BezierCurve.prototype.buildPath = function (ctx, shape) { - var x1 = shape.x1; - var y1 = shape.y1; - var x2 = shape.x2; - var y2 = shape.y2; - var cpx1 = shape.cpx1; - var cpy1 = shape.cpy1; - var cpx2 = shape.cpx2; - var cpy2 = shape.cpy2; - var percent = shape.percent; - - if (percent === 0) { - return; - } - - ctx.moveTo(x1, y1); - - if (cpx2 == null || cpy2 == null) { - if (percent < 1) { - quadraticSubdivide(x1, cpx1, x2, percent, out); - cpx1 = out[1]; - x2 = out[2]; - quadraticSubdivide(y1, cpy1, y2, percent, out); - cpy1 = out[1]; - y2 = out[2]; - } - - ctx.quadraticCurveTo(cpx1, cpy1, x2, y2); - } else { - if (percent < 1) { - cubicSubdivide(x1, cpx1, cpx2, x2, percent, out); - cpx1 = out[1]; - cpx2 = out[2]; - x2 = out[3]; - cubicSubdivide(y1, cpy1, cpy2, y2, percent, out); - cpy1 = out[1]; - cpy2 = out[2]; - y2 = out[3]; - } - - ctx.bezierCurveTo(cpx1, cpy1, cpx2, cpy2, x2, y2); - } - }; - - BezierCurve.prototype.pointAt = function (t) { - return someVectorAt(this.shape, t, false); - }; - - BezierCurve.prototype.tangentAt = function (t) { - var p = someVectorAt(this.shape, t, true); - return normalize$1(p, p); - }; - - return BezierCurve; - }(Path); - - BezierCurve.prototype.type = 'bezier-curve'; - - var ArcShape = function () { - function ArcShape() { - this.cx = 0; - this.cy = 0; - this.r = 0; - this.startAngle = 0; - this.endAngle = Math.PI * 2; - this.clockwise = true; - } - - return ArcShape; - }(); - - var Arc = function (_super) { - __extends(Arc, _super); - - function Arc(opts) { - return _super.call(this, opts) || this; - } - - Arc.prototype.getDefaultStyle = function () { - return { - stroke: '#000', - fill: null - }; - }; - - Arc.prototype.getDefaultShape = function () { - return new ArcShape(); - }; - - Arc.prototype.buildPath = function (ctx, shape) { - var x = shape.cx; - var y = shape.cy; - var r = Math.max(shape.r, 0); - var startAngle = shape.startAngle; - var endAngle = shape.endAngle; - var clockwise = shape.clockwise; - var unitX = Math.cos(startAngle); - var unitY = Math.sin(startAngle); - ctx.moveTo(unitX * r + x, unitY * r + y); - ctx.arc(x, y, r, startAngle, endAngle, !clockwise); - }; - - return Arc; - }(Path); - - Arc.prototype.type = 'arc'; - - var CompoundPath = function (_super) { - __extends(CompoundPath, _super); - - function CompoundPath() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = 'compound'; - return _this; - } - - CompoundPath.prototype._updatePathDirty = function () { - var paths = this.shape.paths; - var dirtyPath = this.shapeChanged(); - - for (var i = 0; i < paths.length; i++) { - dirtyPath = dirtyPath || paths[i].shapeChanged(); - } - - if (dirtyPath) { - this.dirtyShape(); - } - }; - - CompoundPath.prototype.beforeBrush = function () { - this._updatePathDirty(); - - var paths = this.shape.paths || []; - var scale = this.getGlobalScale(); - - for (var i = 0; i < paths.length; i++) { - if (!paths[i].path) { - paths[i].createPathProxy(); - } - - paths[i].path.setScale(scale[0], scale[1], paths[i].segmentIgnoreThreshold); - } - }; - - CompoundPath.prototype.buildPath = function (ctx, shape) { - var paths = shape.paths || []; - - for (var i = 0; i < paths.length; i++) { - paths[i].buildPath(ctx, paths[i].shape, true); - } - }; - - CompoundPath.prototype.afterBrush = function () { - var paths = this.shape.paths || []; - - for (var i = 0; i < paths.length; i++) { - paths[i].pathUpdated(); - } - }; - - CompoundPath.prototype.getBoundingRect = function () { - this._updatePathDirty.call(this); - - return Path.prototype.getBoundingRect.call(this); - }; - - return CompoundPath; - }(Path); - - var Gradient = function () { - function Gradient(colorStops) { - this.colorStops = colorStops || []; - } - - Gradient.prototype.addColorStop = function (offset, color) { - this.colorStops.push({ - offset: offset, - color: color - }); - }; - - return Gradient; - }(); - - var LinearGradient = function (_super) { - __extends(LinearGradient, _super); - - function LinearGradient(x, y, x2, y2, colorStops, globalCoord) { - var _this = _super.call(this, colorStops) || this; - - _this.x = x == null ? 0 : x; - _this.y = y == null ? 0 : y; - _this.x2 = x2 == null ? 1 : x2; - _this.y2 = y2 == null ? 0 : y2; - _this.type = 'linear'; - _this.global = globalCoord || false; - return _this; - } - - return LinearGradient; - }(Gradient); - - var RadialGradient = function (_super) { - __extends(RadialGradient, _super); - - function RadialGradient(x, y, r, colorStops, globalCoord) { - var _this = _super.call(this, colorStops) || this; - - _this.x = x == null ? 0.5 : x; - _this.y = y == null ? 0.5 : y; - _this.r = r == null ? 0.5 : r; - _this.type = 'radial'; - _this.global = globalCoord || false; - return _this; - } - - return RadialGradient; - }(Gradient); - - var mathMin$2 = Math.min; - var mathMax$2 = Math.max; - var mathAbs = Math.abs; - var _extent = [0, 0]; - var _extent2 = [0, 0]; - - var _intersectCtx = createIntersectContext(); - - var _minTv = _intersectCtx.minTv; - var _maxTv = _intersectCtx.maxTv; - - var OrientedBoundingRect = function () { - function OrientedBoundingRect(rect, transform) { - this._corners = []; - this._axes = []; - this._origin = [0, 0]; - - for (var i = 0; i < 4; i++) { - this._corners[i] = new Point(); - } - - for (var i = 0; i < 2; i++) { - this._axes[i] = new Point(); - } - - if (rect) { - this.fromBoundingRect(rect, transform); - } - } - - OrientedBoundingRect.prototype.fromBoundingRect = function (rect, transform) { - var corners = this._corners; - var axes = this._axes; - var x = rect.x; - var y = rect.y; - var x2 = x + rect.width; - var y2 = y + rect.height; - corners[0].set(x, y); - corners[1].set(x2, y); - corners[2].set(x2, y2); - corners[3].set(x, y2); - - if (transform) { - for (var i = 0; i < 4; i++) { - corners[i].transform(transform); - } - } - - Point.sub(axes[0], corners[1], corners[0]); - Point.sub(axes[1], corners[3], corners[0]); - axes[0].normalize(); - axes[1].normalize(); - - for (var i = 0; i < 2; i++) { - this._origin[i] = axes[i].dot(corners[0]); - } - }; - - OrientedBoundingRect.prototype.intersect = function (other, mtv, opt) { - var overlapped = true; - var noMtv = !mtv; - - if (mtv) { - Point.set(mtv, 0, 0); - } - - _intersectCtx.reset(opt, !noMtv); - - if (!this._intersectCheckOneSide(this, other, noMtv, 1)) { - overlapped = false; - - if (noMtv) { - return overlapped; - } - } - - if (!this._intersectCheckOneSide(other, this, noMtv, -1)) { - overlapped = false; - - if (noMtv) { - return overlapped; - } - } - - if (!noMtv && !_intersectCtx.negativeSize) { - Point.copy(mtv, overlapped ? _intersectCtx.useDir ? _intersectCtx.dirMinTv : _minTv : _maxTv); - } - - return overlapped; - }; - - OrientedBoundingRect.prototype._intersectCheckOneSide = function (self, other, noMtv, inverse) { - var overlapped = true; - - for (var i = 0; i < 2; i++) { - var axis = self._axes[i]; - - self._getProjMinMaxOnAxis(i, self._corners, _extent); - - self._getProjMinMaxOnAxis(i, other._corners, _extent2); - - if (_intersectCtx.negativeSize || _extent[1] < _extent2[0] || _extent[0] > _extent2[1]) { - overlapped = false; - - if (_intersectCtx.negativeSize || noMtv) { - return overlapped; - } - - var dist0 = mathAbs(_extent2[0] - _extent[1]); - var dist1 = mathAbs(_extent[0] - _extent2[1]); - - if (mathMin$2(dist0, dist1) > _maxTv.len()) { - if (dist0 < dist1) { - Point.scale(_maxTv, axis, -dist0 * inverse); - } else { - Point.scale(_maxTv, axis, dist1 * inverse); - } - } - } else if (!noMtv) { - var dist0 = mathAbs(_extent2[0] - _extent[1]); - var dist1 = mathAbs(_extent[0] - _extent2[1]); - - if (_intersectCtx.useDir || mathMin$2(dist0, dist1) < _minTv.len()) { - if (dist0 < dist1 || !_intersectCtx.bidirectional) { - Point.scale(_minTv, axis, dist0 * inverse); - - if (_intersectCtx.useDir) { - _intersectCtx.calcDirMTV(); - } - } - - if (dist0 >= dist1 || !_intersectCtx.bidirectional) { - Point.scale(_minTv, axis, -dist1 * inverse); - - if (_intersectCtx.useDir) { - _intersectCtx.calcDirMTV(); - } - } - } - } - } - - return overlapped; - }; - - OrientedBoundingRect.prototype._getProjMinMaxOnAxis = function (dim, corners, out) { - var axis = this._axes[dim]; - var origin = this._origin; - var proj = corners[0].dot(axis) + origin[dim]; - var min = proj; - var max = proj; - - for (var i = 1; i < corners.length; i++) { - var proj_1 = corners[i].dot(axis) + origin[dim]; - min = mathMin$2(proj_1, min); - max = mathMax$2(proj_1, max); - } - - out[0] = min + _intersectCtx.touchThreshold; - out[1] = max - _intersectCtx.touchThreshold; - _intersectCtx.negativeSize = out[1] < out[0]; - }; - - return OrientedBoundingRect; - }(); - - var m = []; - - var IncrementalDisplayable = function (_super) { - __extends(IncrementalDisplayable, _super); - - function IncrementalDisplayable() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.notClear = true; - _this.incremental = true; - _this._displayables = []; - _this._temporaryDisplayables = []; - _this._cursor = 0; - return _this; - } - - IncrementalDisplayable.prototype.traverse = function (cb, context) { - cb.call(context, this); - }; - - IncrementalDisplayable.prototype.useStyle = function () { - this.style = {}; - }; - - IncrementalDisplayable.prototype.getCursor = function () { - return this._cursor; - }; - - IncrementalDisplayable.prototype.innerAfterBrush = function () { - this._cursor = this._displayables.length; - }; - - IncrementalDisplayable.prototype.clearDisplaybles = function () { - this._displayables = []; - this._temporaryDisplayables = []; - this._cursor = 0; - this.markRedraw(); - this.notClear = false; - }; - - IncrementalDisplayable.prototype.clearTemporalDisplayables = function () { - this._temporaryDisplayables = []; - }; - - IncrementalDisplayable.prototype.addDisplayable = function (displayable, notPersistent) { - if (notPersistent) { - this._temporaryDisplayables.push(displayable); - } else { - this._displayables.push(displayable); - } - - this.markRedraw(); - }; - - IncrementalDisplayable.prototype.addDisplayables = function (displayables, notPersistent) { - notPersistent = notPersistent || false; - - for (var i = 0; i < displayables.length; i++) { - this.addDisplayable(displayables[i], notPersistent); - } - }; - - IncrementalDisplayable.prototype.getDisplayables = function () { - return this._displayables; - }; - - IncrementalDisplayable.prototype.getTemporalDisplayables = function () { - return this._temporaryDisplayables; - }; - - IncrementalDisplayable.prototype.eachPendingDisplayable = function (cb) { - for (var i = this._cursor; i < this._displayables.length; i++) { - cb && cb(this._displayables[i]); - } - - for (var i = 0; i < this._temporaryDisplayables.length; i++) { - cb && cb(this._temporaryDisplayables[i]); - } - }; - - IncrementalDisplayable.prototype.update = function () { - this.updateTransform(); - - for (var i = this._cursor; i < this._displayables.length; i++) { - var displayable = this._displayables[i]; - displayable.parent = this; - displayable.update(); - displayable.parent = null; - } - - for (var i = 0; i < this._temporaryDisplayables.length; i++) { - var displayable = this._temporaryDisplayables[i]; - displayable.parent = this; - displayable.update(); - displayable.parent = null; - } - }; - - IncrementalDisplayable.prototype.getBoundingRect = function () { - if (!this._rect) { - var rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity); - - for (var i = 0; i < this._displayables.length; i++) { - var displayable = this._displayables[i]; - var childRect = displayable.getBoundingRect().clone(); - - if (displayable.needLocalTransform()) { - childRect.applyTransform(displayable.getLocalTransform(m)); - } - - rect.union(childRect); - } - - this._rect = rect; - } - - return this._rect; - }; - - IncrementalDisplayable.prototype.contain = function (x, y) { - var localPos = this.transformCoordToLocal(x, y); - var rect = this.getBoundingRect(); - - if (rect.contain(localPos[0], localPos[1])) { - for (var i = 0; i < this._displayables.length; i++) { - var displayable = this._displayables[i]; - - if (displayable.contain(x, y)) { - return true; - } - } - } - - return false; - }; - - return IncrementalDisplayable; - }(Displayable); // Stored properties for further transition. - - - var transitionStore = makeInner(); - /** - * Return null if animation is disabled. - */ - - function getAnimationConfig(animationType, animatableModel, dataIndex, // Extra opts can override the option in animatable model. - extraOpts, // TODO It's only for pictorial bar now. - extraDelayParams) { - var animationPayload; // Check if there is global animation configuration from dataZoom/resize can override the config in option. - // If animation is enabled. Will use this animation config in payload. - // If animation is disabled. Just ignore it. - - if (animatableModel && animatableModel.ecModel) { - var updatePayload = animatableModel.ecModel.getUpdatePayload(); - animationPayload = updatePayload && updatePayload.animation; - } - - var animationEnabled = animatableModel && animatableModel.isAnimationEnabled(); - var isUpdate = animationType === 'update'; - - if (animationEnabled) { - var duration = void 0; - var easing = void 0; - var delay = void 0; - - if (extraOpts) { - duration = retrieve2(extraOpts.duration, 200); - easing = retrieve2(extraOpts.easing, 'cubicOut'); - delay = 0; - } else { - duration = animatableModel.getShallow(isUpdate ? 'animationDurationUpdate' : 'animationDuration'); - easing = animatableModel.getShallow(isUpdate ? 'animationEasingUpdate' : 'animationEasing'); - delay = animatableModel.getShallow(isUpdate ? 'animationDelayUpdate' : 'animationDelay'); - } // animation from payload has highest priority. - - - if (animationPayload) { - animationPayload.duration != null && (duration = animationPayload.duration); - animationPayload.easing != null && (easing = animationPayload.easing); - animationPayload.delay != null && (delay = animationPayload.delay); - } - - if (isFunction(delay)) { - delay = delay(dataIndex, extraDelayParams); - } - - if (isFunction(duration)) { - duration = duration(dataIndex); - } - - var config = { - duration: duration || 0, - delay: delay, - easing: easing - }; - return config; - } else { - return null; - } - } - - function animateOrSetProps(animationType, el, props, animatableModel, dataIndex, cb, during) { - var isFrom = false; - var removeOpt; - - if (isFunction(dataIndex)) { - during = cb; - cb = dataIndex; - dataIndex = null; - } else if (isObject$2(dataIndex)) { - cb = dataIndex.cb; - during = dataIndex.during; - isFrom = dataIndex.isFrom; - removeOpt = dataIndex.removeOpt; - dataIndex = dataIndex.dataIndex; - } - - var isRemove = animationType === 'leave'; - - if (!isRemove) { - // Must stop the remove animation. - el.stopAnimation('leave'); - } - - var animationConfig = getAnimationConfig(animationType, animatableModel, dataIndex, isRemove ? removeOpt || {} : null, animatableModel && animatableModel.getAnimationDelayParams ? animatableModel.getAnimationDelayParams(el, dataIndex) : null); - - if (animationConfig && animationConfig.duration > 0) { - var duration = animationConfig.duration; - var animationDelay = animationConfig.delay; - var animationEasing = animationConfig.easing; - var animateConfig = { - duration: duration, - delay: animationDelay || 0, - easing: animationEasing, - done: cb, - force: !!cb || !!during, - // Set to final state in update/init animation. - // So the post processing based on the path shape can be done correctly. - setToFinal: !isRemove, - scope: animationType, - during: during - }; - isFrom ? el.animateFrom(props, animateConfig) : el.animateTo(props, animateConfig); - } else { - el.stopAnimation(); // If `isFrom`, the props is the "from" props. - - !isFrom && el.attr(props); // Call during at least once. - - during && during(1); - cb && cb(); - } - } - /** - * Update graphic element properties with or without animation according to the - * configuration in series. - * - * Caution: this method will stop previous animation. - * So do not use this method to one element twice before - * animation starts, unless you know what you are doing. - * @example - * graphic.updateProps(el, { - * position: [100, 100] - * }, seriesModel, dataIndex, function () { console.log('Animation done!'); }); - * // Or - * graphic.updateProps(el, { - * position: [100, 100] - * }, seriesModel, function () { console.log('Animation done!'); }); - */ - - - function updateProps$1(el, props, // TODO: TYPE AnimatableModel - animatableModel, dataIndex, cb, during) { - animateOrSetProps('update', el, props, animatableModel, dataIndex, cb, during); - } - /** - * Init graphic element properties with or without animation according to the - * configuration in series. - * - * Caution: this method will stop previous animation. - * So do not use this method to one element twice before - * animation starts, unless you know what you are doing. - */ - - - function initProps(el, props, animatableModel, dataIndex, cb, during) { - animateOrSetProps('enter', el, props, animatableModel, dataIndex, cb, during); - } - /** - * If element is removed. - * It can determine if element is having remove animation. - */ - - - function isElementRemoved(el) { - if (!el.__zr) { - return true; - } - - for (var i = 0; i < el.animators.length; i++) { - var animator = el.animators[i]; - - if (animator.scope === 'leave') { - return true; - } - } - - return false; - } - /** - * Remove graphic element - */ - - - function removeElement(el, props, animatableModel, dataIndex, cb, during) { - // Don't do remove animation twice. - if (isElementRemoved(el)) { - return; - } - - animateOrSetProps('leave', el, props, animatableModel, dataIndex, cb, during); - } - - function fadeOutDisplayable(el, animatableModel, dataIndex, done) { - el.removeTextContent(); - el.removeTextGuideLine(); - removeElement(el, { - style: { - opacity: 0 - } - }, animatableModel, dataIndex, done); - } - - function removeElementWithFadeOut(el, animatableModel, dataIndex) { - function doRemove() { - el.parent && el.parent.remove(el); - } // Hide label and labelLine first - // TODO Also use fade out animation? - - - if (!el.isGroup) { - fadeOutDisplayable(el, animatableModel, dataIndex, doRemove); - } else { - el.traverse(function (disp) { - if (!disp.isGroup) { - // Can invoke doRemove multiple times. - fadeOutDisplayable(disp, animatableModel, dataIndex, doRemove); - } - }); - } - } - /** - * Save old style for style transition in universalTransition module. - * It's used when element will be reused in each render. - * For chart like map, heatmap, which will always create new element. - * We don't need to save this because universalTransition can get old style from the old element - */ - - - function saveOldStyle(el) { - transitionStore(el).oldStyle = el.style; - } - - var _customShapeMap = {}; - var XY$1 = ['x', 'y']; - var WH$1 = ['width', 'height']; - /** - * Extend shape with parameters - */ - - function extendShape(opts) { - return Path.extend(opts); - } - - var extendPathFromString = extendFromString; - /** - * Extend path - */ - - function extendPath(pathData, opts) { - return extendPathFromString(pathData, opts); - } - /** - * Register a user defined shape. - * The shape class can be fetched by `getShapeClass` - * This method will overwrite the registered shapes, including - * the registered built-in shapes, if using the same `name`. - * The shape can be used in `custom series` and - * `graphic component` by declaring `{type: name}`. - * - * @param name - * @param ShapeClass Can be generated by `extendShape`. - */ - - - function registerShape(name, ShapeClass) { - _customShapeMap[name] = ShapeClass; - } - /** - * Find shape class registered by `registerShape`. Usually used in - * fetching user defined shape. - * - * [Caution]: - * (1) This method **MUST NOT be used inside echarts !!!**, unless it is prepared - * to use user registered shapes. - * Because the built-in shape (see `getBuiltInShape`) will be registered by - * `registerShape` by default. That enables users to get both built-in - * shapes as well as the shapes belonging to themsleves. But users can overwrite - * the built-in shapes by using names like 'circle', 'rect' via calling - * `registerShape`. So the echarts inner featrues should not fetch shapes from here - * in case that it is overwritten by users, except that some features, like - * `custom series`, `graphic component`, do it deliberately. - * - * (2) In the features like `custom series`, `graphic component`, the user input - * `{tpye: 'xxx'}` does not only specify shapes but also specify other graphic - * elements like `'group'`, `'text'`, `'image'` or event `'path'`. Those names - * are reserved names, that is, if some user registers a shape named `'image'`, - * the shape will not be used. If we intending to add some more reserved names - * in feature, that might bring break changes (disable some existing user shape - * names). But that case probably rarely happens. So we don't make more mechanism - * to resolve this issue here. - * - * @param name - * @return The shape class. If not found, return nothing. - */ - - - function getShapeClass(name) { - if (_customShapeMap.hasOwnProperty(name)) { - return _customShapeMap[name]; - } - } - /** - * Create a path element from path data string - * @param pathData - * @param opts - * @param rect - * @param layout 'center' or 'cover' default to be cover - */ - - - function makePath(pathData, opts, rect, layout) { - var path = createFromString(pathData, opts); - - if (rect) { - if (layout === 'center') { - rect = centerGraphic(rect, path.getBoundingRect()); - } - - resizePath(path, rect); - } - - return path; - } - /** - * Create a image element from image url - * @param imageUrl image url - * @param opts options - * @param rect constrain rect - * @param layout 'center' or 'cover'. Default to be 'cover' - */ - - - function makeImage(imageUrl, rect, layout) { - var zrImg = new ZRImage({ - style: { - image: imageUrl, - x: rect.x, - y: rect.y, - width: rect.width, - height: rect.height - }, - onload: function (img) { - if (layout === 'center') { - var boundingRect = { - width: img.width, - height: img.height - }; - zrImg.setStyle(centerGraphic(rect, boundingRect)); - } - } - }); - return zrImg; - } - /** - * Get position of centered element in bounding box. - * - * @param rect element local bounding box - * @param boundingRect constraint bounding box - * @return element position containing x, y, width, and height - */ - - - function centerGraphic(rect, boundingRect) { - // Set rect to center, keep width / height ratio. - var aspect = boundingRect.width / boundingRect.height; - var width = rect.height * aspect; - var height; - - if (width <= rect.width) { - height = rect.height; - } else { - width = rect.width; - height = width / aspect; - } - - var cx = rect.x + rect.width / 2; - var cy = rect.y + rect.height / 2; - return { - x: cx - width / 2, - y: cy - height / 2, - width: width, - height: height - }; - } - - var mergePath = mergePath$1; - /** - * Resize a path to fit the rect - * @param path - * @param rect - */ - - function resizePath(path, rect) { - if (!path.applyTransform) { - return; - } - - var pathRect = path.getBoundingRect(); - var m = pathRect.calculateTransform(rect); - path.applyTransform(m); - } - /** - * Sub pixel optimize line for canvas - */ - - - function subPixelOptimizeLine(shape, lineWidth) { - subPixelOptimizeLine$1(shape, shape, { - lineWidth: lineWidth - }); - return shape; - } - /** - * Sub pixel optimize rect for canvas - */ - - - function subPixelOptimizeRect(shape, style) { - subPixelOptimizeRect$1(shape, shape, style); - return shape; - } - /** - * Sub pixel optimize for canvas - * - * @param position Coordinate, such as x, y - * @param lineWidth Should be nonnegative integer. - * @param positiveOrNegative Default false (negative). - * @return Optimized position. - */ - - - var subPixelOptimize = subPixelOptimize$1; - /** - * Get transform matrix of target (param target), - * in coordinate of its ancestor (param ancestor) - * - * @param target - * @param [ancestor] - */ - - function getTransform(target, ancestor) { - var mat = identity([]); - - while (target && target !== ancestor) { - mul(mat, target.getLocalTransform(), mat); - target = target.parent; - } - - return mat; - } - /** - * Apply transform to an vertex. - * @param target [x, y] - * @param transform Can be: - * + Transform matrix: like [1, 0, 0, 1, 0, 0] - * + {position, rotation, scale}, the same as `zrender/Transformable`. - * @param invert Whether use invert matrix. - * @return [x, y] - */ - - - function applyTransform(target, transform, invert$1) { - if (transform && !isArrayLike(transform)) { - transform = Transformable.getLocalTransform(transform); - } - - if (invert$1) { - transform = invert([], transform); - } - - return applyTransform$1([], target, transform); - } - /** - * @param direction 'left' 'right' 'top' 'bottom' - * @param transform Transform matrix: like [1, 0, 0, 1, 0, 0] - * @param invert Whether use invert matrix. - * @return Transformed direction. 'left' 'right' 'top' 'bottom' - */ - - - function transformDirection(direction, transform, invert) { - // Pick a base, ensure that transform result will not be (0, 0). - var hBase = transform[4] === 0 || transform[5] === 0 || transform[0] === 0 ? 1 : mathAbs$3(2 * transform[4] / transform[0]); - var vBase = transform[4] === 0 || transform[5] === 0 || transform[2] === 0 ? 1 : mathAbs$3(2 * transform[4] / transform[2]); - var vertex = [direction === 'left' ? -hBase : direction === 'right' ? hBase : 0, direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0]; - vertex = applyTransform(vertex, transform, invert); - return mathAbs$3(vertex[0]) > mathAbs$3(vertex[1]) ? vertex[0] > 0 ? 'right' : 'left' : vertex[1] > 0 ? 'bottom' : 'top'; - } - - function isNotGroup(el) { - return !el.isGroup; - } - - function isPath(el) { - return el.shape != null; - } - /** - * Apply group transition animation from g1 to g2. - * If no animatableModel, no animation. - */ - - - function groupTransition(g1, g2, animatableModel) { - if (!g1 || !g2) { - return; - } - - function getElMap(g) { - var elMap = {}; - g.traverse(function (el) { - if (isNotGroup(el) && el.anid) { - elMap[el.anid] = el; - } - }); - return elMap; - } - - function getAnimatableProps(el) { - var obj = { - x: el.x, - y: el.y, - rotation: el.rotation - }; - - if (isPath(el)) { - obj.shape = clone$3(el.shape); - } - - return obj; - } - - var elMap1 = getElMap(g1); - g2.traverse(function (el) { - if (isNotGroup(el) && el.anid) { - var oldEl = elMap1[el.anid]; - - if (oldEl) { - var newProp = getAnimatableProps(el); - el.attr(getAnimatableProps(oldEl)); - updateProps$1(el, newProp, animatableModel, getECData(el).dataIndex); - } - } - }); - } - - function clipPointsByRect(points, rect) { - // FIXME: This way might be incorrect when graphic clipped by a corner - // and when element has a border. - return map$1(points, function (point) { - var x = point[0]; - x = mathMax$6(x, rect.x); - x = mathMin$6(x, rect.x + rect.width); - var y = point[1]; - y = mathMax$6(y, rect.y); - y = mathMin$6(y, rect.y + rect.height); - return [x, y]; - }); - } - /** - * Return a new clipped rect. If rect size are negative, return undefined. - */ - - - function clipRectByRect(targetRect, rect) { - var x = mathMax$6(targetRect.x, rect.x); - var x2 = mathMin$6(targetRect.x + targetRect.width, rect.x + rect.width); - var y = mathMax$6(targetRect.y, rect.y); - var y2 = mathMin$6(targetRect.y + targetRect.height, rect.y + rect.height); // If the total rect is cliped, nothing, including the border, - // should be painted. So return undefined. - - if (x2 >= x && y2 >= y) { - return { - x: x, - y: y, - width: x2 - x, - height: y2 - y - }; - } - } - - function createIcon(iconStr, // Support 'image://' or 'path://' or direct svg path. - opt, rect) { - var innerOpts = extend({ - rectHover: true - }, opt); - var style = innerOpts.style = { - strokeNoScale: true - }; - rect = rect || { - x: -1, - y: -1, - width: 2, - height: 2 - }; - - if (iconStr) { - return iconStr.indexOf('image://') === 0 ? (style.image = iconStr.slice(8), defaults(style, rect), new ZRImage(innerOpts)) : makePath(iconStr.replace('path://', ''), innerOpts, rect, 'center'); - } - } - /** - * Return `true` if the given line (line `a`) and the given polygon - * are intersect. - * Note that we do not count colinear as intersect here because no - * requirement for that. We could do that if required in future. - */ - - - function linePolygonIntersect(a1x, a1y, a2x, a2y, points) { - for (var i = 0, p2 = points[points.length - 1]; i < points.length; i++) { - var p = points[i]; - - if (lineLineIntersect(a1x, a1y, a2x, a2y, p[0], p[1], p2[0], p2[1])) { - return true; - } - - p2 = p; - } - } - /** - * Return `true` if the given two lines (line `a` and line `b`) - * are intersect. - * Note that we do not count colinear as intersect here because no - * requirement for that. We could do that if required in future. - */ - - - function lineLineIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) { - // let `vec_m` to be `vec_a2 - vec_a1` and `vec_n` to be `vec_b2 - vec_b1`. - var mx = a2x - a1x; - var my = a2y - a1y; - var nx = b2x - b1x; - var ny = b2y - b1y; // `vec_m` and `vec_n` are parallel iff - // existing `k` such that `vec_m = k · vec_n`, equivalent to `vec_m X vec_n = 0`. - - var nmCrossProduct = crossProduct2d(nx, ny, mx, my); - - if (nearZero(nmCrossProduct)) { - return false; - } // `vec_m` and `vec_n` are intersect iff - // existing `p` and `q` in [0, 1] such that `vec_a1 + p * vec_m = vec_b1 + q * vec_n`, - // such that `q = ((vec_a1 - vec_b1) X vec_m) / (vec_n X vec_m)` - // and `p = ((vec_a1 - vec_b1) X vec_n) / (vec_n X vec_m)`. - - - var b1a1x = a1x - b1x; - var b1a1y = a1y - b1y; - var q = crossProduct2d(b1a1x, b1a1y, mx, my) / nmCrossProduct; - - if (q < 0 || q > 1) { - return false; - } - - var p = crossProduct2d(b1a1x, b1a1y, nx, ny) / nmCrossProduct; - - if (p < 0 || p > 1) { - return false; - } - - return true; - } - /** - * Cross product of 2-dimension vector. - */ - - - function crossProduct2d(x1, y1, x2, y2) { - return x1 * y2 - x2 * y1; - } - - function nearZero(val) { - return val <= 1e-6 && val >= -1e-6; - } - /** - * NOTE: - * A negative-width/height rect (due to negative margins) is not supported; - * it will be clampped to zero width/height. - * Although negative-width/height rects can be defined reasonably following the - * similar sense in CSS, but they are rarely used, hard to understand and complicated. - * - * @param rect Assume its width/height >= 0 if existing. - * x/y/width/height is allowed to be NaN, - * for the case that only x/width or y/height is intended to be computed. - * @param delta - * If be `number[]`, should be `[top, right, bottom, left]`, - * which can be used in padding or margin case. - * @see `normalizeCssArray` in `util/format.ts` - * If be `number`, it means [delta, delta, delta, delta], - * which can be used in lineWidth (borderWith) case, - * [NOTICE]: commonly pass lineWidth / 2, following the convention that border is - * half inside half outside of the rect. - * @param shrinkOrExpand - * `true` - shrink if `delta[i]` is positive, commmonly used in `padding` case. - * `false` - expand if `delta[i]` is positive, commmonly used in `margin` case. (default) - * @param noNegative - * `true` - negative `delta[i]` will be clampped to 0. - * `false` - No clamp to `delta`. (default). - * @return The input `rect`. - */ - - - function expandOrShrinkRect(rect, delta, shrinkOrExpand, noNegative, minSize // by default [0, 0]. - ) { - if (delta == null) { - return rect; - } else if (isNumber(delta)) { - _tmpExpandRectDelta[0] = _tmpExpandRectDelta[1] = _tmpExpandRectDelta[2] = _tmpExpandRectDelta[3] = delta; - } else { - { - assert(delta.length === 4); - } - _tmpExpandRectDelta[0] = delta[0]; - _tmpExpandRectDelta[1] = delta[1]; - _tmpExpandRectDelta[2] = delta[2]; - _tmpExpandRectDelta[3] = delta[3]; - } - - if (noNegative) { - _tmpExpandRectDelta[0] = mathMax$6(0, _tmpExpandRectDelta[0]); - _tmpExpandRectDelta[1] = mathMax$6(0, _tmpExpandRectDelta[1]); - _tmpExpandRectDelta[2] = mathMax$6(0, _tmpExpandRectDelta[2]); - _tmpExpandRectDelta[3] = mathMax$6(0, _tmpExpandRectDelta[3]); - } - - if (shrinkOrExpand) { - _tmpExpandRectDelta[0] = -_tmpExpandRectDelta[0]; - _tmpExpandRectDelta[1] = -_tmpExpandRectDelta[1]; - _tmpExpandRectDelta[2] = -_tmpExpandRectDelta[2]; - _tmpExpandRectDelta[3] = -_tmpExpandRectDelta[3]; - } - - expandRectOnOneDimension(rect, _tmpExpandRectDelta, 'x', 'width', 3, 1, minSize && minSize[0] || 0); - expandRectOnOneDimension(rect, _tmpExpandRectDelta, 'y', 'height', 0, 2, minSize && minSize[1] || 0); - return rect; - } - - var _tmpExpandRectDelta = [0, 0, 0, 0]; - - function expandRectOnOneDimension(rect, delta, xy, wh, ltIdx, rbIdx, minSize) { - var deltaSum = delta[rbIdx] + delta[ltIdx]; - var oldSize = rect[wh]; - rect[wh] += deltaSum; - minSize = mathMax$6(0, mathMin$6(minSize, oldSize)); - - if (rect[wh] < minSize) { - rect[wh] = minSize; // Try to make the position of the zero rect reasonable in most visual cases. - - rect[xy] += delta[ltIdx] >= 0 ? -delta[ltIdx] : delta[rbIdx] >= 0 ? oldSize + delta[rbIdx] : mathAbs$3(deltaSum) > 1e-8 ? (oldSize - minSize) * delta[ltIdx] / deltaSum : 0; - } else { - rect[xy] -= delta[ltIdx]; - } - } - - function setTooltipConfig(opt) { - var itemTooltipOption = opt.itemTooltipOption; - var componentModel = opt.componentModel; - var itemName = opt.itemName; - var itemTooltipOptionObj = isString(itemTooltipOption) ? { - formatter: itemTooltipOption - } : itemTooltipOption; - var mainType = componentModel.mainType; - var componentIndex = componentModel.componentIndex; - var formatterParams = { - componentType: mainType, - name: itemName, - $vars: ['name'] - }; - formatterParams[mainType + 'Index'] = componentIndex; - var formatterParamsExtra = opt.formatterParamsExtra; - - if (formatterParamsExtra) { - each$4(keys(formatterParamsExtra), function (key) { - if (!hasOwn(formatterParams, key)) { - formatterParams[key] = formatterParamsExtra[key]; - formatterParams.$vars.push(key); - } - }); - } - - var ecData = getECData(opt.el); - ecData.componentMainType = mainType; - ecData.componentIndex = componentIndex; - ecData.tooltipConfig = { - name: itemName, - option: defaults({ - content: itemName, - encodeHTMLContent: true, - formatterParams: formatterParams - }, itemTooltipOptionObj) - }; - } - - function traverseElement(el, cb) { - var stopped; // TODO - // Polyfill for fixing zrender group traverse don't visit it's root issue. - - if (el.isGroup) { - stopped = cb(el); - } - - if (!stopped) { - el.traverse(cb); - } - } - - function traverseElements(els, cb) { - if (els) { - if (isArray(els)) { - for (var i = 0; i < els.length; i++) { - traverseElement(els[i], cb); - } - } else { - traverseElement(els, cb); - } - } - } - /** - * After a boundingRect applying a `transform`, whether to be still parallel screen X and Y. - */ - - - function isBoundingRectAxisAligned(transform) { - return !transform || mathAbs$3(transform[1]) < AXIS_ALIGN_EPSILON && mathAbs$3(transform[2]) < AXIS_ALIGN_EPSILON || mathAbs$3(transform[0]) < AXIS_ALIGN_EPSILON && mathAbs$3(transform[3]) < AXIS_ALIGN_EPSILON; - } - - var AXIS_ALIGN_EPSILON = 1e-5; - /** - * Create or copy to the existing bounding rect to avoid modifying `source`. - * - * @usage - * out.rect = ensureCopyRect(out.rect, sourceRect); - */ - - function ensureCopyRect(target, source) { - return target ? BoundingRect.copy(target, source) : source.clone(); - } - /** - * Create or copy to the existing transform to avoid modifying `source`. - * - * [CAUTION]: transform is `NullUndefined` if no transform, following convention of zrender, - * and enable to bypass some unnecessary calculation, since in most cases there is no transform. - * - * @usage - * out.transform = ensureCopyTransform(out.transform, sourceTransform); - */ - - - function ensureCopyTransform(target, source) { - return source ? copy(target || create(), source) : undefined; - } - - function retrieveZInfo(model) { - return { - z: model.get('z') || 0, - zlevel: model.get('zlevel') || 0 - }; - } - /** - * Assume all of the elements has the same `z` and `zlevel`. - */ - - - function calcZ2Range(el) { - var max = -Infinity; - var min = Infinity; - traverseElement(el, function (el) { - visitEl(el); - visitEl(el.getTextContent()); - visitEl(el.getTextGuideLine()); - }); - - function visitEl(el) { - if (!el || el.isGroup) { - return; - } - - var currentStates = el.currentStates; - - if (currentStates.length) { - for (var idx = 0; idx < currentStates.length; idx++) { - calcZ2(el.states[currentStates[idx]]); - } - } - - calcZ2(el); - } - - function calcZ2(entity) { - if (entity) { - var z2 = entity.z2; // Consider z2 may be NullUndefined - - if (z2 > max) { - max = z2; - } - - if (z2 < min) { - min = z2; - } - } - } - - if (min > max) { - min = max = 0; - } - - return { - min: min, - max: max - }; - } - - function traverseUpdateZ(el, z, zlevel) { - doUpdateZ(el, z, zlevel, -Infinity); - } - - function doUpdateZ(el, z, zlevel, // FIXME: Ideally all the labels should be above all the glyphs by default, - // e.g. in graph, edge labels should be above node elements. - // Currently impl does not guarantee that. - maxZ2) { - // `ignoreModelZ` is used to intentionally lift elements to cover other elements, - // where maxZ2 (for label.z2) should also not be counted for its parents. - if (el.ignoreModelZ) { - return maxZ2; - } // Group may also have textContent - - - var label = el.getTextContent(); - var labelLine = el.getTextGuideLine(); - var isGroup = el.isGroup; - - if (isGroup) { - // set z & zlevel of children elements of Group - var children = el.childrenRef(); - - for (var i = 0; i < children.length; i++) { - maxZ2 = mathMax$6(doUpdateZ(children[i], z, zlevel, maxZ2), maxZ2); - } - } else { - // not Group - el.z = z; - el.zlevel = zlevel; - maxZ2 = mathMax$6(el.z2 || 0, maxZ2); - } // always set z and zlevel if label/labelLine exists - - - if (label) { - label.z = z; - label.zlevel = zlevel; // lift z2 of text content - // TODO if el.emphasis.z2 is spcefied, what about textContent. - - isFinite(maxZ2) && (label.z2 = maxZ2 + 2); - } - - if (labelLine) { - var textGuideLineConfig = el.textGuideLineConfig; - labelLine.z = z; - labelLine.zlevel = zlevel; - isFinite(maxZ2) && (labelLine.z2 = maxZ2 + (textGuideLineConfig && textGuideLineConfig.showAbove ? 1 : -1)); - } - - return maxZ2; - } // Register built-in shapes. These shapes might be overwritten - // by users, although we do not recommend that. - - - registerShape('circle', Circle); - registerShape('ellipse', Ellipse); - registerShape('sector', Sector); - registerShape('ring', Ring); - registerShape('polygon', Polygon); - registerShape('polyline', Polyline); - registerShape('rect', Rect); - registerShape('line', Line); - registerShape('bezierCurve', BezierCurve); - registerShape('arc', Arc); - var graphic$1 = /*#__PURE__*/Object.freeze({ - __proto__: null, - Arc: Arc, - BezierCurve: BezierCurve, - BoundingRect: BoundingRect, - Circle: Circle, - CompoundPath: CompoundPath, - Ellipse: Ellipse, - Group: Group$2, - Image: ZRImage, - IncrementalDisplayable: IncrementalDisplayable, - Line: Line, - LinearGradient: LinearGradient, - OrientedBoundingRect: OrientedBoundingRect, - Path: Path, - Point: Point, - Polygon: Polygon, - Polyline: Polyline, - RadialGradient: RadialGradient, - Rect: Rect, - Ring: Ring, - Sector: Sector, - Text: ZRText, - WH: WH$1, - XY: XY$1, - applyTransform: applyTransform, - calcZ2Range: calcZ2Range, - clipPointsByRect: clipPointsByRect, - clipRectByRect: clipRectByRect, - createIcon: createIcon, - ensureCopyRect: ensureCopyRect, - ensureCopyTransform: ensureCopyTransform, - expandOrShrinkRect: expandOrShrinkRect, - extendPath: extendPath, - extendShape: extendShape, - getShapeClass: getShapeClass, - getTransform: getTransform, - groupTransition: groupTransition, - initProps: initProps, - isBoundingRectAxisAligned: isBoundingRectAxisAligned, - isElementRemoved: isElementRemoved, - lineLineIntersect: lineLineIntersect, - linePolygonIntersect: linePolygonIntersect, - makeImage: makeImage, - makePath: makePath, - mergePath: mergePath, - registerShape: registerShape, - removeElement: removeElement, - removeElementWithFadeOut: removeElementWithFadeOut, - resizePath: resizePath, - retrieveZInfo: retrieveZInfo, - setTooltipConfig: setTooltipConfig, - subPixelOptimize: subPixelOptimize, - subPixelOptimizeLine: subPixelOptimizeLine, - subPixelOptimizeRect: subPixelOptimizeRect, - transformDirection: transformDirection, - traverseElements: traverseElements, - traverseUpdateZ: traverseUpdateZ, - updateProps: updateProps$1 - }); - var EMPTY_OBJ = {}; - - function setLabelText(label, labelTexts) { - for (var i = 0; i < SPECIAL_STATES.length; i++) { - var stateName = SPECIAL_STATES[i]; - var text = labelTexts[stateName]; - var state = label.ensureState(stateName); - state.style = state.style || {}; - state.style.text = text; - } - - var oldStates = label.currentStates.slice(); - label.clearStates(true); - label.setStyle({ - text: labelTexts.normal - }); - label.useStates(oldStates, true); - } - - function getLabelText(opt, stateModels, interpolatedValue) { - var labelFetcher = opt.labelFetcher; - var labelDataIndex = opt.labelDataIndex; - var labelDimIndex = opt.labelDimIndex; - var normalModel = stateModels.normal; - var baseText; - - if (labelFetcher) { - baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex, normalModel && normalModel.get('formatter'), interpolatedValue != null ? { - interpolatedValue: interpolatedValue - } : null); - } - - if (baseText == null) { - baseText = isFunction(opt.defaultText) ? opt.defaultText(labelDataIndex, opt, interpolatedValue) : opt.defaultText; - } - - var statesText = { - normal: baseText - }; - - for (var i = 0; i < SPECIAL_STATES.length; i++) { - var stateName = SPECIAL_STATES[i]; - var stateModel = stateModels[stateName]; - statesText[stateName] = retrieve2(labelFetcher ? labelFetcher.getFormattedLabel(labelDataIndex, stateName, null, labelDimIndex, stateModel && stateModel.get('formatter')) : null, baseText); - } - - return statesText; - } - - function setLabelStyle(targetEl, labelStatesModels, opt, stateSpecified // TODO specified position? - ) { - opt = opt || EMPTY_OBJ; - var isSetOnText = targetEl instanceof ZRText; - var needsCreateText = false; - - for (var i = 0; i < DISPLAY_STATES.length; i++) { - var stateModel = labelStatesModels[DISPLAY_STATES[i]]; - - if (stateModel && stateModel.getShallow('show')) { - needsCreateText = true; - break; - } - } - - var textContent = isSetOnText ? targetEl : targetEl.getTextContent(); - - if (needsCreateText) { - if (!isSetOnText) { - // Reuse the previous - if (!textContent) { - textContent = new ZRText(); - targetEl.setTextContent(textContent); - } // Use same state proxy - - - if (targetEl.stateProxy) { - textContent.stateProxy = targetEl.stateProxy; - } - } - - var labelStatesTexts = getLabelText(opt, labelStatesModels); - var normalModel = labelStatesModels.normal; - var showNormal = !!normalModel.getShallow('show'); - var normalStyle = createTextStyle$1(normalModel, stateSpecified && stateSpecified.normal, opt, false, !isSetOnText); - normalStyle.text = labelStatesTexts.normal; - - if (!isSetOnText) { - // Always create new - targetEl.setTextConfig(createTextConfig(normalModel, opt, false)); - } - - for (var i = 0; i < SPECIAL_STATES.length; i++) { - var stateName = SPECIAL_STATES[i]; - var stateModel = labelStatesModels[stateName]; - - if (stateModel) { - var stateObj = textContent.ensureState(stateName); - var stateShow = !!retrieve2(stateModel.getShallow('show'), showNormal); - - if (stateShow !== showNormal) { - stateObj.ignore = !stateShow; - } - - stateObj.style = createTextStyle$1(stateModel, stateSpecified && stateSpecified[stateName], opt, true, !isSetOnText); - stateObj.style.text = labelStatesTexts[stateName]; - - if (!isSetOnText) { - var targetElEmphasisState = targetEl.ensureState(stateName); - targetElEmphasisState.textConfig = createTextConfig(stateModel, opt, true); - } - } - } // PENDING: if there is many requirements that emphasis position - // need to be different from normal position, we might consider - // auto silent is those cases. - - - textContent.silent = !!normalModel.getShallow('silent'); // Keep x and y - - if (textContent.style.x != null) { - normalStyle.x = textContent.style.x; - } - - if (textContent.style.y != null) { - normalStyle.y = textContent.style.y; - } - - textContent.ignore = !showNormal; // Always create new style. - - textContent.useStyle(normalStyle); - textContent.dirty(); - - if (opt.enableTextSetter) { - labelInner(textContent).setLabelText = function (interpolatedValue) { - var labelStatesTexts = getLabelText(opt, labelStatesModels, interpolatedValue); - setLabelText(textContent, labelStatesTexts); - }; - } - } else if (textContent) { - // Not display rich text. - textContent.ignore = true; - } - - targetEl.dirty(); - } - - function getLabelStatesModels(itemModel, labelName) { - labelName = labelName || 'label'; - var statesModels = { - normal: itemModel.getModel(labelName) - }; - - for (var i = 0; i < SPECIAL_STATES.length; i++) { - var stateName = SPECIAL_STATES[i]; - statesModels[stateName] = itemModel.getModel([stateName, labelName]); - } - - return statesModels; - } - /** - * Set basic textStyle properties. - */ - - - function createTextStyle$1(textStyleModel, specifiedTextStyle, // Fixed style in the code. Can't be set by model. - opt, isNotNormal, isAttached // If text is attached on an element. If so, auto color will handling in zrender. - ) { - var textStyle = {}; - setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached); - specifiedTextStyle && extend(textStyle, specifiedTextStyle); // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false); - - return textStyle; - } - - function createTextConfig(textStyleModel, opt, isNotNormal) { - opt = opt || {}; - var textConfig = {}; - var labelPosition; - var labelRotate = textStyleModel.getShallow('rotate'); - var labelDistance = retrieve2(textStyleModel.getShallow('distance'), isNotNormal ? null : 5); - var labelOffset = textStyleModel.getShallow('offset'); - labelPosition = textStyleModel.getShallow('position') || (isNotNormal ? null : 'inside'); // 'outside' is not a valid zr textPostion value, but used - // in bar series, and magic type should be considered. - - labelPosition === 'outside' && (labelPosition = opt.defaultOutsidePosition || 'top'); - - if (labelPosition != null) { - textConfig.position = labelPosition; - } - - if (labelOffset != null) { - textConfig.offset = labelOffset; - } - - if (labelRotate != null) { - labelRotate *= Math.PI / 180; - textConfig.rotation = labelRotate; - } - - if (labelDistance != null) { - textConfig.distance = labelDistance; - } // fill and auto is determined by the color of path fill if it's not specified by developers. - - - textConfig.outsideFill = textStyleModel.get('color') === 'inherit' ? opt.inheritColor || null : 'auto'; - - if (opt.autoOverflowArea != null) { - textConfig.autoOverflowArea = opt.autoOverflowArea; - } - - if (opt.layoutRect != null) { - textConfig.layoutRect = opt.layoutRect; - } - - return textConfig; - } - /** - * The uniform entry of set text style, that is, retrieve style definitions - * from `model` and set to `textStyle` object. - * - * Never in merge mode, but in overwrite mode, that is, all of the text style - * properties will be set. (Consider the states of normal and emphasis and - * default value can be adopted, merge would make the logic too complicated - * to manage.) - */ - - - function setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached) { - // Consider there will be abnormal when merge hover style to normal style if given default value. - opt = opt || EMPTY_OBJ; - var ecModel = textStyleModel.ecModel; - var globalTextStyle = ecModel && ecModel.option.textStyle; // Consider case: - // { - // data: [{ - // value: 12, - // label: { - // rich: { - // // no 'a' here but using parent 'a'. - // } - // } - // }], - // rich: { - // a: { ... } - // } - // } - - var richItemNames = getRichItemNames(textStyleModel); - var richResult; - - if (richItemNames) { - richResult = {}; - var richInheritPlainLabelOptionName = 'richInheritPlainLabel'; - var richInheritPlainLabel = retrieve2(textStyleModel.get(richInheritPlainLabelOptionName), ecModel ? ecModel.get(richInheritPlainLabelOptionName) : undefined); - - for (var name_1 in richItemNames) { - if (richItemNames.hasOwnProperty(name_1)) { - // Cascade is supported in rich. - var richTextStyle = textStyleModel.getModel(['rich', name_1]); // In rich, never `disableBox`. - // consider `label: {formatter: '{a|xx}', color: 'blue', rich: {a: {}}}`, - // the default color `'blue'` will not be adopted if no color declared in `rich`. - // That might confuses users. So probably we should put `textStyleModel` as the - // root ancestor of the `richTextStyle`. But that would be a break change. - // Since v6, the rich style inherits plain label by default - // but this behavior can be disabled by setting `richInheritPlainLabel` to `false`. - - setTokenTextStyle(richResult[name_1] = {}, richTextStyle, globalTextStyle, textStyleModel, richInheritPlainLabel, opt, isNotNormal, isAttached, false, true); - } - } - } - - if (richResult) { - textStyle.rich = richResult; - } - - var overflow = textStyleModel.get('overflow'); - - if (overflow) { - textStyle.overflow = overflow; - } - - var lineOverflow = textStyleModel.get('lineOverflow'); - - if (lineOverflow) { - textStyle.lineOverflow = lineOverflow; - } - - var labelTextStyle = textStyle; // `minMargin` has a higher precedence than `textMargin`, because `textMargin` is allowed - // to be set in `defaultOption`. - - var minMargin = textStyleModel.get('minMargin'); - - if (minMargin != null) { - // `minMargin` only support number value. - minMargin = !isNumber(minMargin) ? 0 : minMargin / 2; - labelTextStyle.margin = [minMargin, minMargin, minMargin, minMargin]; - labelTextStyle.__marginType = LabelMarginType.minMargin; - } else { - var textMargin = textStyleModel.get('textMargin'); - - if (textMargin != null) { - labelTextStyle.margin = normalizeCssArray$1(textMargin); - labelTextStyle.__marginType = LabelMarginType.textMargin; - } - } - - setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, null, null, opt, isNotNormal, isAttached, true, false); - } // Consider case: - // { - // data: [{ - // value: 12, - // label: { - // rich: { - // // no 'a' here but using parent 'a'. - // } - // } - // }], - // rich: { - // a: { ... } - // } - // } - // TODO TextStyleModel - - - function getRichItemNames(textStyleModel) { - // Use object to remove duplicated names. - var richItemNameMap; - - while (textStyleModel && textStyleModel !== textStyleModel.ecModel) { - var rich = (textStyleModel.option || EMPTY_OBJ).rich; - - if (rich) { - richItemNameMap = richItemNameMap || {}; - var richKeys = keys(rich); - - for (var i = 0; i < richKeys.length; i++) { - var richKey = richKeys[i]; - richItemNameMap[richKey] = 1; - } - } - - textStyleModel = textStyleModel.parentModel; - } - - return richItemNameMap; - } - - var TEXT_PROPS_WITH_GLOBAL = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY']; - var TEXT_PROPS_SELF = ['align', 'lineHeight', 'width', 'height', 'tag', 'verticalAlign', 'ellipsis']; - var TEXT_PROPS_BOX = ['padding', 'borderWidth', 'borderRadius', 'borderDashOffset', 'backgroundColor', 'borderColor', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY']; - - function setTokenTextStyle(textStyle, // FIXME: check/refactor for ellipsis handling of rich text. - textStyleModel, globalTextStyle, plainTextModel, richInheritPlainLabel, opt, isNotNormal, isAttached, isBlock, inRich) { - // In merge mode, default value should not be given. - globalTextStyle = !isNotNormal && globalTextStyle || EMPTY_OBJ; - var inheritColor = opt && opt.inheritColor; - var fillColor = textStyleModel.getShallow('color'); - var strokeColor = textStyleModel.getShallow('textBorderColor'); - var opacity = retrieve2(textStyleModel.getShallow('opacity'), globalTextStyle.opacity); - - if (fillColor === 'inherit' || fillColor === 'auto') { - { - if (fillColor === 'auto') { - deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\''); - } - } - - if (inheritColor) { - fillColor = inheritColor; - } else { - fillColor = null; - } - } - - if (strokeColor === 'inherit' || strokeColor === 'auto') { - { - if (strokeColor === 'auto') { - deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\''); - } - } - - if (inheritColor) { - strokeColor = inheritColor; - } else { - strokeColor = null; - } - } - - if (!isAttached) { - // Only use default global textStyle.color if text is individual. - // Otherwise it will use the strategy of attached text color because text may be on a path. - fillColor = fillColor || globalTextStyle.color; - strokeColor = strokeColor || globalTextStyle.textBorderColor; - } - - if (fillColor != null) { - // Might not be a string, e.g, it's a function in axisLabel case; but assume that it will - // be erased by a correct value outside. - textStyle.fill = fillColor; - } - - if (strokeColor != null) { - textStyle.stroke = strokeColor; - } - - var textBorderWidth = retrieve2(textStyleModel.getShallow('textBorderWidth'), globalTextStyle.textBorderWidth); - - if (textBorderWidth != null) { - textStyle.lineWidth = textBorderWidth; - } - - var textBorderType = retrieve2(textStyleModel.getShallow('textBorderType'), globalTextStyle.textBorderType); - - if (textBorderType != null) { - textStyle.lineDash = textBorderType; - } - - var textBorderDashOffset = retrieve2(textStyleModel.getShallow('textBorderDashOffset'), globalTextStyle.textBorderDashOffset); - - if (textBorderDashOffset != null) { - textStyle.lineDashOffset = textBorderDashOffset; - } - - if (!isNotNormal && opacity == null && !inRich) { - opacity = opt && opt.defaultOpacity; - } - - if (opacity != null) { - textStyle.opacity = opacity; - } // TODO - - - if (!isNotNormal && !isAttached) { - // Set default finally. - if (textStyle.fill == null && opt.inheritColor) { - textStyle.fill = opt.inheritColor; - } - } // Do not use `getFont` here, because merge should be supported, where - // part of these properties may be changed in emphasis style, and the - // others should remain their original value got from normal style. - - - for (var i = 0; i < TEXT_PROPS_WITH_GLOBAL.length; i++) { - var key = TEXT_PROPS_WITH_GLOBAL[i]; // props width, height, padding, margin, tag, backgroundColor, borderColor, - // borderWidth, borderRadius, shadowColor, shadowBlur, shadowOffsetX, shadowOffsetY - // may inappropriate to inherit from plainTextStyle. - // And if some props is specified in default options, users may have to reset them one by one. - // Therefore, we only allow these props to inherit from plainTextStyle. - // `richInheritPlainLabel` is switch for backward compatibility - - var val = richInheritPlainLabel !== false && plainTextModel ? retrieve3(textStyleModel.getShallow(key), plainTextModel.getShallow(key), globalTextStyle[key]) : retrieve2(textStyleModel.getShallow(key), globalTextStyle[key]); - - if (val != null) { - textStyle[key] = val; - } - } - - for (var i = 0; i < TEXT_PROPS_SELF.length; i++) { - var key = TEXT_PROPS_SELF[i]; - var val = textStyleModel.getShallow(key); - - if (val != null) { - textStyle[key] = val; - } - } - - if (textStyle.verticalAlign == null) { - var baseline = textStyleModel.getShallow('baseline'); - - if (baseline != null) { - textStyle.verticalAlign = baseline; - } - } - - if (!isBlock || !opt.disableBox) { - for (var i = 0; i < TEXT_PROPS_BOX.length; i++) { - var key = TEXT_PROPS_BOX[i]; - var val = textStyleModel.getShallow(key); - - if (val != null) { - textStyle[key] = val; - } - } - - var borderType = textStyleModel.getShallow('borderType'); - - if (borderType != null) { - textStyle.borderDash = borderType; - } - - if ((textStyle.backgroundColor === 'auto' || textStyle.backgroundColor === 'inherit') && inheritColor) { - { - if (textStyle.backgroundColor === 'auto') { - deprecateReplaceLog('backgroundColor: \'auto\'', 'backgroundColor: \'inherit\''); - } - } - textStyle.backgroundColor = inheritColor; - } - - if ((textStyle.borderColor === 'auto' || textStyle.borderColor === 'inherit') && inheritColor) { - { - if (textStyle.borderColor === 'auto') { - deprecateReplaceLog('borderColor: \'auto\'', 'borderColor: \'inherit\''); - } - } - textStyle.borderColor = inheritColor; - } - } - } - - function getFont(opt, ecModel) { - var gTextStyleModel = ecModel && ecModel.getModel('textStyle'); - return trim([// FIXME in node-canvas fontWeight is before fontStyle - opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '', opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '', (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px', opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'].join(' ')); - } - - var labelInner = makeInner(); - - function setLabelValueAnimation(label, labelStatesModels, value, getDefaultText) { - if (!label) { - return; - } - - var obj = labelInner(label); - obj.prevValue = obj.value; - obj.value = value; - var normalLabelModel = labelStatesModels.normal; - obj.valueAnimation = normalLabelModel.get('valueAnimation'); - - if (obj.valueAnimation) { - obj.precision = normalLabelModel.get('precision'); - obj.defaultInterpolatedText = getDefaultText; - obj.statesModels = labelStatesModels; - } - } - - function animateLabelValue(textEl, dataIndex, data, animatableModel, labelFetcher) { - var labelInnerStore = labelInner(textEl); - - if (!labelInnerStore.valueAnimation || labelInnerStore.prevValue === labelInnerStore.value) { - // Value not changed, no new label animation - return; - } - - var defaultInterpolatedText = labelInnerStore.defaultInterpolatedText; // Consider the case that being animating, do not use the `obj.value`, - // Otherwise it will jump to the `obj.value` when this new animation started. - - var currValue = retrieve2(labelInnerStore.interpolatedValue, labelInnerStore.prevValue); - var targetValue = labelInnerStore.value; - - function during(percent) { - var interpolated = interpolateRawValues(data, labelInnerStore.precision, currValue, targetValue, percent); - labelInnerStore.interpolatedValue = percent === 1 ? null : interpolated; - var labelText = getLabelText({ - labelDataIndex: dataIndex, - labelFetcher: labelFetcher, - defaultText: defaultInterpolatedText ? defaultInterpolatedText(interpolated) : interpolated + '' - }, labelInnerStore.statesModels, interpolated); - setLabelText(textEl, labelText); - } - - textEl.percent = 0; - (labelInnerStore.prevValue == null ? initProps : updateProps$1)(textEl, { - // percent is used to prevent animation from being aborted #15916 - percent: 1 - }, animatableModel, dataIndex, null, during); - } - /** - * PENDING: Temporary impl. unify them? - * @see {LabelCommonOption['textMargin']} - * @see {LabelCommonOption['minMargin']} - */ - - - var LabelMarginType = { - minMargin: 1, - textMargin: 2 - }; - var PATH_COLOR = ['textStyle', 'color']; - var textStyleParams = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'padding', 'lineHeight', 'rich', 'width', 'height', 'overflow']; // TODO Performance improvement? - - var tmpText = new ZRText(); - - var TextStyleMixin = - /** @class */ - function () { - function TextStyleMixin() {} - /** - * Get color property or get color from option.textStyle.color - */ - // TODO Callback - - - TextStyleMixin.prototype.getTextColor = function (isEmphasis) { - var ecModel = this.ecModel; - return this.getShallow('color') || (!isEmphasis && ecModel ? ecModel.get(PATH_COLOR) : null); - }; - /** - * Create font string from fontStyle, fontWeight, fontSize, fontFamily - * @return {string} - */ - - - TextStyleMixin.prototype.getFont = function () { - return getFont({ - fontStyle: this.getShallow('fontStyle'), - fontWeight: this.getShallow('fontWeight'), - fontSize: this.getShallow('fontSize'), - fontFamily: this.getShallow('fontFamily') - }, this.ecModel); - }; - - TextStyleMixin.prototype.getTextRect = function (text) { - var style = { - text: text, - verticalAlign: this.getShallow('verticalAlign') || this.getShallow('baseline') - }; - - for (var i = 0; i < textStyleParams.length; i++) { - style[textStyleParams[i]] = this.getShallow(textStyleParams[i]); - } - - tmpText.useStyle(style); - tmpText.update(); - return tmpText.getBoundingRect(); - }; - - return TextStyleMixin; - }(); - - var LINE_STYLE_KEY_MAP = [['lineWidth', 'width'], ['stroke', 'color'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'], ['lineDash', 'type'], ['lineDashOffset', 'dashOffset'], ['lineCap', 'cap'], ['lineJoin', 'join'], ['miterLimit'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`. - // So do not transfer decal directly. - ]; - var getLineStyle = makeStyleMapper(LINE_STYLE_KEY_MAP); - - var LineStyleMixin = - /** @class */ - function () { - function LineStyleMixin() {} - - LineStyleMixin.prototype.getLineStyle = function (excludes) { - return getLineStyle(this, excludes); - }; - - return LineStyleMixin; - }(); - - var ITEM_STYLE_KEY_MAP = [['fill', 'color'], ['stroke', 'borderColor'], ['lineWidth', 'borderWidth'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'], ['lineDash', 'borderType'], ['lineDashOffset', 'borderDashOffset'], ['lineCap', 'borderCap'], ['lineJoin', 'borderJoin'], ['miterLimit', 'borderMiterLimit'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`. - // So do not transfer decal directly. - ]; - var getItemStyle = makeStyleMapper(ITEM_STYLE_KEY_MAP); - - var ItemStyleMixin = - /** @class */ - function () { - function ItemStyleMixin() {} - - ItemStyleMixin.prototype.getItemStyle = function (excludes, includes) { - return getItemStyle(this, excludes, includes); - }; - - return ItemStyleMixin; - }(); - - var Model = - /** @class */ - function () { - function Model(option, parentModel, ecModel) { - this.parentModel = parentModel; - this.ecModel = ecModel; - this.option = option; // Simple optimization - // if (this.init) { - // if (arguments.length <= 4) { - // this.init(option, parentModel, ecModel, extraOpt); - // } - // else { - // this.init.apply(this, arguments); - // } - // } - } - - Model.prototype.init = function (option, parentModel, ecModel) {}; - /** - * Merge the input option to me. - */ - - - Model.prototype.mergeOption = function (option, ecModel) { - merge(this.option, option, true); - }; // `path` can be 'a.b.c', so the return value type have to be `ModelOption` - // TODO: TYPE strict key check? - // get(path: string | string[], ignoreParent?: boolean): ModelOption; - - - Model.prototype.get = function (path, ignoreParent) { - if (path == null) { - return this.option; - } - - return this._doGet(this.parsePath(path), !ignoreParent && this.parentModel); - }; - - Model.prototype.getShallow = function (key, ignoreParent) { - var option = this.option; - var val = option == null ? option : option[key]; - - if (val == null && !ignoreParent) { - var parentModel = this.parentModel; - - if (parentModel) { - // FIXME:TS do not know how to make it works - val = parentModel.getShallow(key); - } - } - - return val; - }; // `path` can be 'a.b.c', so the return value type have to be `Model` - // getModel(path: string | string[], parentModel?: Model): Model; - // TODO 'a.b.c' is deprecated - - - Model.prototype.getModel = function (path, parentModel) { - var hasPath = path != null; - var pathFinal = hasPath ? this.parsePath(path) : null; - var obj = hasPath ? this._doGet(pathFinal) : this.option; - parentModel = parentModel || this.parentModel && this.parentModel.getModel(this.resolveParentPath(pathFinal)); - return new Model(obj, parentModel, this.ecModel); - }; - /** - * If model has option - */ - - - Model.prototype.isEmpty = function () { - return this.option == null; - }; - - Model.prototype.restoreData = function () {}; // Pending - - - Model.prototype.clone = function () { - var Ctor = this.constructor; - return new Ctor(clone$3(this.option)); - }; // setReadOnly(properties): void { - // clazzUtil.setReadOnly(this, properties); - // } - // If path is null/undefined, return null/undefined. - - - Model.prototype.parsePath = function (path) { - if (typeof path === 'string') { - return path.split('.'); - } - - return path; - }; // Resolve path for parent. Perhaps useful when parent use a different property. - // Default to be a identity resolver. - // Can be modified to a different resolver. - - - Model.prototype.resolveParentPath = function (path) { - return path; - }; // FIXME:TS check whether put this method here - - - Model.prototype.isAnimationEnabled = function () { - if (!env.node && this.option) { - if (this.option.animation != null) { - return !!this.option.animation; - } else if (this.parentModel) { - return this.parentModel.isAnimationEnabled(); - } - } - }; - - Model.prototype._doGet = function (pathArr, parentModel) { - var obj = this.option; - - if (!pathArr) { - return obj; - } - - for (var i = 0; i < pathArr.length; i++) { - // Ignore empty - if (!pathArr[i]) { - continue; - } // obj could be number/string/... (like 0) - - - obj = obj && typeof obj === 'object' ? obj[pathArr[i]] : null; - - if (obj == null) { - break; - } - } - - if (obj == null && parentModel) { - obj = parentModel._doGet(this.resolveParentPath(pathArr), parentModel.parentModel); - } - - return obj; - }; - - return Model; - }(); // Enable Model.extend. - - - enableClassExtend(Model); - enableClassCheck(Model); - mixin(Model, LineStyleMixin); - mixin(Model, ItemStyleMixin); - mixin(Model, AreaStyleMixin); - mixin(Model, TextStyleMixin); // A random offset - - var base = Math.round(Math.random() * 10); - /** - * @public - * @param {string} type - * @return {string} - */ - - function getUID(type) { - // Considering the case of crossing js context, - // use Math.random to make id as unique as possible. - return [type || '', base++].join('_'); - } - /** - * Implements `SubTypeDefaulterManager` for `target`. - */ - - - function enableSubTypeDefaulter(target) { - var subTypeDefaulters = {}; - - target.registerSubTypeDefaulter = function (componentType, defaulter) { - var componentTypeInfo = parseClassType(componentType); - subTypeDefaulters[componentTypeInfo.main] = defaulter; - }; - - target.determineSubType = function (componentType, option) { - var type = option.type; - - if (!type) { - var componentTypeMain = parseClassType(componentType).main; - - if (target.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) { - type = subTypeDefaulters[componentTypeMain](option); - } - } - - return type; - }; - } - /** - * Implements `TopologicalTravelable` for `entity`. - * - * Topological travel on Activity Network (Activity On Vertices). - * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis']. - * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology. - * If there is circular dependencey, Error will be thrown. - */ - - - function enableTopologicalTravel(entity, dependencyGetter) { - /** - * @param targetNameList Target Component type list. - * Can be ['aa', 'bb', 'aa.xx'] - * @param fullNameList By which we can build dependency graph. - * @param callback Params: componentType, dependencies. - * @param context Scope of callback. - */ - entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) { - if (!targetNameList.length) { - return; - } - - var result = makeDepndencyGraph(fullNameList); - var graph = result.graph; - var noEntryList = result.noEntryList; - var targetNameSet = {}; - each$4(targetNameList, function (name) { - targetNameSet[name] = true; - }); - - while (noEntryList.length) { - var currComponentType = noEntryList.pop(); - var currVertex = graph[currComponentType]; - var isInTargetNameSet = !!targetNameSet[currComponentType]; - - if (isInTargetNameSet) { - callback.call(context, currComponentType, currVertex.originalDeps.slice()); - delete targetNameSet[currComponentType]; - } - - each$4(currVertex.successor, isInTargetNameSet ? removeEdgeAndAdd : removeEdge); - } - - each$4(targetNameSet, function () { - var errMsg = ''; - { - errMsg = makePrintable('Circular dependency may exists: ', targetNameSet, targetNameList, fullNameList); - } - throw new Error(errMsg); - }); - - function removeEdge(succComponentType) { - graph[succComponentType].entryCount--; - - if (graph[succComponentType].entryCount === 0) { - noEntryList.push(succComponentType); - } - } // Consider this case: legend depends on series, and we call - // chart.setOption({series: [...]}), where only series is in option. - // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will - // not be called, but only sereis.mergeOption is called. Thus legend - // have no chance to update its local record about series (like which - // name of series is available in legend). - - - function removeEdgeAndAdd(succComponentType) { - targetNameSet[succComponentType] = true; - removeEdge(succComponentType); - } - }; - - function makeDepndencyGraph(fullNameList) { - var graph = {}; - var noEntryList = []; - each$4(fullNameList, function (name) { - var thisItem = createDependencyGraphItem(graph, name); - var originalDeps = thisItem.originalDeps = dependencyGetter(name); - var availableDeps = getAvailableDependencies(originalDeps, fullNameList); - thisItem.entryCount = availableDeps.length; - - if (thisItem.entryCount === 0) { - noEntryList.push(name); - } - - each$4(availableDeps, function (dependentName) { - if (indexOf(thisItem.predecessor, dependentName) < 0) { - thisItem.predecessor.push(dependentName); - } - - var thatItem = createDependencyGraphItem(graph, dependentName); - - if (indexOf(thatItem.successor, dependentName) < 0) { - thatItem.successor.push(name); - } - }); - }); - return { - graph: graph, - noEntryList: noEntryList - }; - } - - function createDependencyGraphItem(graph, name) { - if (!graph[name]) { - graph[name] = { - predecessor: [], - successor: [] - }; - } - - return graph[name]; - } - - function getAvailableDependencies(originalDeps, fullNameList) { - var availableDeps = []; - each$4(originalDeps, function (dep) { - indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep); - }); - return availableDeps; - } - } - - function inheritDefaultOption(superOption, subOption) { - // See also `model/Component.ts#getDefaultOption` - return merge(merge({}, superOption, true), subOption, true); - } - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * AUTO-GENERATED FILE. DO NOT MODIFY. - */ - - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * Language: English. - */ - - - var langEN = { - time: { - month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], - monthAbbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - dayOfWeek: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - dayOfWeekAbbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] - }, - legend: { - selector: { - all: 'All', - inverse: 'Inv' - } - }, - toolbox: { - brush: { - title: { - rect: 'Box Select', - polygon: 'Lasso Select', - lineX: 'Horizontally Select', - lineY: 'Vertically Select', - keep: 'Keep Selections', - clear: 'Clear Selections' - } - }, - dataView: { - title: 'Data View', - lang: ['Data View', 'Close', 'Refresh'] - }, - dataZoom: { - title: { - zoom: 'Zoom', - back: 'Zoom Reset' - } - }, - magicType: { - title: { - line: 'Switch to Line Chart', - bar: 'Switch to Bar Chart', - stack: 'Stack', - tiled: 'Tile' - } - }, - restore: { - title: 'Restore' - }, - saveAsImage: { - title: 'Save as Image', - lang: ['Right Click to Save Image'] - } - }, - series: { - typeNames: { - pie: 'Pie chart', - bar: 'Bar chart', - line: 'Line chart', - scatter: 'Scatter plot', - effectScatter: 'Ripple scatter plot', - radar: 'Radar chart', - tree: 'Tree', - treemap: 'Treemap', - boxplot: 'Boxplot', - candlestick: 'Candlestick', - k: 'K line chart', - heatmap: 'Heat map', - map: 'Map', - parallel: 'Parallel coordinate map', - lines: 'Line graph', - graph: 'Relationship graph', - sankey: 'Sankey diagram', - funnel: 'Funnel chart', - gauge: 'Gauge', - pictorialBar: 'Pictorial bar', - themeRiver: 'Theme River Map', - sunburst: 'Sunburst', - custom: 'Custom chart', - chart: 'Chart' - } - }, - aria: { - general: { - withTitle: 'This is a chart about "{title}"', - withoutTitle: 'This is a chart' - }, - series: { - single: { - prefix: '', - withName: ' with type {seriesType} named {seriesName}.', - withoutName: ' with type {seriesType}.' - }, - multiple: { - prefix: '. It consists of {seriesCount} series count.', - withName: ' The {seriesId} series is a {seriesType} representing {seriesName}.', - withoutName: ' The {seriesId} series is a {seriesType}.', - separator: { - middle: '', - end: '' - } - } - }, - data: { - allData: 'The data is as follows: ', - partialData: 'The first {displayCnt} items are: ', - withName: 'the data for {name} is {value}', - withoutName: '{value}', - separator: { - middle: ', ', - end: '. ' - } - } - } - }; - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * AUTO-GENERATED FILE. DO NOT MODIFY. - */ - - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - var langZH = { - time: { - month: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], - monthAbbr: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], - dayOfWeek: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'], - dayOfWeekAbbr: ['日', '一', '二', '三', '四', '五', '六'] - }, - legend: { - selector: { - all: '全选', - inverse: '反选' - } - }, - toolbox: { - brush: { - title: { - rect: '矩形选择', - polygon: '圈选', - lineX: '横向选择', - lineY: '纵向选择', - keep: '保持选择', - clear: '清除选择' - } - }, - dataView: { - title: '数据视图', - lang: ['数据视图', '关闭', '刷新'] - }, - dataZoom: { - title: { - zoom: '区域缩放', - back: '区域缩放还原' - } - }, - magicType: { - title: { - line: '切换为折线图', - bar: '切换为柱状图', - stack: '切换为堆叠', - tiled: '切换为平铺' - } - }, - restore: { - title: '还原' - }, - saveAsImage: { - title: '保存为图片', - lang: ['右键另存为图片'] - } - }, - series: { - typeNames: { - pie: '饼图', - bar: '柱状图', - line: '折线图', - scatter: '散点图', - effectScatter: '涟漪散点图', - radar: '雷达图', - tree: '树图', - treemap: '矩形树图', - boxplot: '箱型图', - candlestick: 'K线图', - k: 'K线图', - heatmap: '热力图', - map: '地图', - parallel: '平行坐标图', - lines: '线图', - graph: '关系图', - sankey: '桑基图', - funnel: '漏斗图', - gauge: '仪表盘图', - pictorialBar: '象形柱图', - themeRiver: '主题河流图', - sunburst: '旭日图', - custom: '自定义图表', - chart: '图表' - } - }, - aria: { - general: { - withTitle: '这是一个关于“{title}”的图表。', - withoutTitle: '这是一个图表,' - }, - series: { - single: { - prefix: '', - withName: '图表类型是{seriesType},表示{seriesName}。', - withoutName: '图表类型是{seriesType}。' - }, - multiple: { - prefix: '它由{seriesCount}个图表系列组成。', - withName: '第{seriesId}个系列是一个表示{seriesName}的{seriesType},', - withoutName: '第{seriesId}个系列是一个{seriesType},', - separator: { - middle: ';', - end: '。' - } - } - }, - data: { - allData: '其数据是——', - partialData: '其中,前{displayCnt}项是——', - withName: '{name}的数据是{value}', - withoutName: '{value}', - separator: { - middle: ',', - end: '' - } - } - } - }; - var LOCALE_ZH = 'ZH'; - var LOCALE_EN = 'EN'; - var DEFAULT_LOCALE = LOCALE_EN; - var localeStorage = {}; - var localeModels = {}; - var SYSTEM_LANG = !env.domSupported ? DEFAULT_LOCALE : function () { - var langStr = ( - /* eslint-disable-next-line */ - document.documentElement.lang || navigator.language || navigator.browserLanguage || DEFAULT_LOCALE).toUpperCase(); - return langStr.indexOf(LOCALE_ZH) > -1 ? LOCALE_ZH : DEFAULT_LOCALE; - }(); - - function registerLocale(locale, localeObj) { - locale = locale.toUpperCase(); - localeModels[locale] = new Model(localeObj); - localeStorage[locale] = localeObj; - } // export function getLocale(locale: string) { - // return localeStorage[locale]; - // } - - - function createLocaleObject(locale) { - if (isString(locale)) { - var localeObj = localeStorage[locale.toUpperCase()] || {}; - - if (locale === LOCALE_ZH || locale === LOCALE_EN) { - return clone$3(localeObj); - } else { - return merge(clone$3(localeObj), clone$3(localeStorage[DEFAULT_LOCALE]), false); - } - } else { - return merge(clone$3(locale), clone$3(localeStorage[DEFAULT_LOCALE]), false); - } - } - - function getLocaleModel(lang) { - return localeModels[lang]; - } - - function getDefaultLocaleModel() { - return localeModels[DEFAULT_LOCALE]; - } // Default locale - - - registerLocale(LOCALE_EN, langEN); - registerLocale(LOCALE_ZH, langZH); - var _impl$1 = null; - - function getScaleBreakHelper() { - return _impl$1; - } - - var ONE_SECOND = 1000; - var ONE_MINUTE = ONE_SECOND * 60; - var ONE_HOUR = ONE_MINUTE * 60; - var ONE_DAY = ONE_HOUR * 24; - var ONE_YEAR = ONE_DAY * 365; - var primaryTimeUnitFormatterMatchers = { - year: /({yyyy}|{yy})/, - month: /({MMMM}|{MMM}|{MM}|{M})/, - day: /({dd}|{d})/, - hour: /({HH}|{H}|{hh}|{h})/, - minute: /({mm}|{m})/, - second: /({ss}|{s})/, - millisecond: /({SSS}|{S})/ - }; - var defaultFormatterSeed = { - year: '{yyyy}', - month: '{MMM}', - day: '{d}', - hour: '{HH}:{mm}', - minute: '{HH}:{mm}', - second: '{HH}:{mm}:{ss}', - millisecond: '{HH}:{mm}:{ss} {SSS}' - }; - var defaultFullFormatter = '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss} {SSS}'; - var fullDayFormatter = '{yyyy}-{MM}-{dd}'; - var fullLeveledFormatter = { - year: '{yyyy}', - month: '{yyyy}-{MM}', - day: fullDayFormatter, - hour: fullDayFormatter + ' ' + defaultFormatterSeed.hour, - minute: fullDayFormatter + ' ' + defaultFormatterSeed.minute, - second: fullDayFormatter + ' ' + defaultFormatterSeed.second, - millisecond: defaultFullFormatter - }; // Order must be ensured from big to small. - - var primaryTimeUnits = ['year', 'month', 'day', 'hour', 'minute', 'second', 'millisecond']; - var timeUnits = ['year', 'half-year', 'quarter', 'month', 'week', 'half-week', 'day', 'half-day', 'quarter-day', 'hour', 'minute', 'second', 'millisecond']; - - function parseTimeAxisLabelFormatter(formatter) { - // Keep the logic the same with function `leveledFormat`. - return !isString(formatter) && !isFunction(formatter) ? parseTimeAxisLabelFormatterDictionary(formatter) : formatter; - } - /** - * The final generated dictionary is like: - * generated_dict = { - * year: { - * year: ['{yyyy}', ...] - * }, - * month: { - * year: ['{yyyy} {MMM}', ...], - * month: ['{MMM}', ...] - * }, - * day: { - * year: ['{yyyy} {MMM} {d}', ...], - * month: ['{MMM} {d}', ...], - * day: ['{d}', ...] - * }, - * ... - * } - * - * In echarts option, users can specify the entire dictionary or typically just: - * {formatter: { - * year: '{yyyy}', // Or an array of leveled templates: `['{yyyy}', '{bold1|{yyyy}}', ...]`, - * // corresponding to `[level0, level1, level2, ...]`. - * month: '{MMM}', - * day: '{d}', - * hour: '{HH}:{mm}', - * second: '{HH}:{mm}', - * ... - * }} - * If any time unit is not specified in echarts option, the default template is used, - * such as `['{yyyy}', {primary|{yyyy}']`. - * - * The `tick.level` is only used to read string from each array, meaning the style type. - * - * Let `lowerUnit = getUnitFromValue(tick.value)`. - * The non-break axis ticks only use `generated_dict[lowerUnit][lowerUnit][level]`. - * The break axis ticks may use `generated_dict[lowerUnit][upperUnit][level]`, because: - * Consider the case: the non-break ticks are `16th, 23th, Feb, 7th, ...`, where `Feb` is in the break - * range and pruned by breaks, and the break ends might be in lower time unit than day. e.g., break start - * is `Jan 25th 18:00`(in unit `hour`) and break end is `Feb 6th 18:30` (in unit `minute`). Thus the break - * label prefers `Jan 25th 18:00` and `Feb 6th 18:30` rather than only `18:00` and `18:30`, otherwise it - * causes misleading. - * In this case, the tick of the break start and end will both be: - * `{level: 1, lowerTimeUnit: 'minute', upperTimeUnit: 'month'}` - * And get the final template by `generated_dict[lowerTimeUnit][upperTimeUnit][level]`. - * Note that the time unit can not be calculated directly by a single tick value, since the two breaks have - * to be at the same time unit to avoid awkward appearance. i.e., `Jan 25th 18:00` is in the time unit "hour" - * but we need it to be "minute", following `Feb 6th 18:30`. - */ - - - function parseTimeAxisLabelFormatterDictionary(dictOption) { - dictOption = dictOption || {}; - var dict = {}; // Currently if any template is specified by user, it may contain rich text tag, - // such as `'{my_bold|{YYYY}}'`, thus we do add highlight style to it. - // (Note that nested tag (`'{some|{some2|xxx}}'`) in rich text is not supported yet.) - - var canAddHighlight = true; - each$4(primaryTimeUnits, function (lowestUnit) { - canAddHighlight && (canAddHighlight = dictOption[lowestUnit] == null); - }); - each$4(primaryTimeUnits, function (lowestUnit, lowestUnitIdx) { - var upperDictOption = dictOption[lowestUnit]; - dict[lowestUnit] = {}; - var lowerTpl = null; - - for (var upperUnitIdx = lowestUnitIdx; upperUnitIdx >= 0; upperUnitIdx--) { - var upperUnit = primaryTimeUnits[upperUnitIdx]; - var upperDictItemOption = isObject$2(upperDictOption) && !isArray(upperDictOption) ? upperDictOption[upperUnit] : upperDictOption; - var tplArr = void 0; - - if (isArray(upperDictItemOption)) { - tplArr = upperDictItemOption.slice(); - lowerTpl = tplArr[0] || ''; - } else if (isString(upperDictItemOption)) { - lowerTpl = upperDictItemOption; - tplArr = [lowerTpl]; - } else { - if (lowerTpl == null) { - lowerTpl = defaultFormatterSeed[lowestUnit]; - } // Generate the dict by the rule as follows: - // If the user specify (or by default): - // {formatter: { - // year: '{yyyy}', - // month: '{MMM}', - // day: '{d}', - // ... - // }} - // Concat them to make the final dictionary: - // {formatter: { - // year: {year: ['{yyyy}']}, - // month: {year: ['{yyyy} {MMM}'], month: ['{MMM}']}, - // day: {year: ['{yyyy} {MMM} {d}'], month: ['{MMM} {d}'], day: ['{d}']} - // ... - // }} - // And then add `{primary|...}` to each array if from default template. - // This strategy is convinient for user configurating and works for most cases. - // If bad cases encountered, users can specify the entire dictionary themselves - // instead of going through this logic. - else if (!primaryTimeUnitFormatterMatchers[upperUnit].test(lowerTpl)) { - lowerTpl = dict[upperUnit][upperUnit][0] + " " + lowerTpl; - } - - tplArr = [lowerTpl]; - - if (canAddHighlight) { - tplArr[1] = "{primary|" + lowerTpl + "}"; - } - } - - dict[lowestUnit][upperUnit] = tplArr; - } - }); - return dict; - } - - function pad(str, len) { - str += ''; - return '0000'.substr(0, len - str.length) + str; - } - - function getPrimaryTimeUnit(timeUnit) { - switch (timeUnit) { - case 'half-year': - case 'quarter': - return 'month'; - - case 'week': - case 'half-week': - return 'day'; - - case 'half-day': - case 'quarter-day': - return 'hour'; - - default: - // year, minutes, second, milliseconds - return timeUnit; - } - } - - function isPrimaryTimeUnit(timeUnit) { - return timeUnit === getPrimaryTimeUnit(timeUnit); - } - - function getDefaultFormatPrecisionOfInterval(timeUnit) { - switch (timeUnit) { - case 'year': - case 'month': - return 'day'; - - case 'millisecond': - return 'millisecond'; - - default: - // Also for day, hour, minute, second - return 'second'; - } - } - - function format$1( // Note: The result based on `isUTC` are totally different, which can not be just simply - // substituted by the result without `isUTC`. So we make the param `isUTC` mandatory. - time, template, isUTC, lang) { - var date = parseDate(time); - var y = date[fullYearGetterName(isUTC)](); - var M = date[monthGetterName(isUTC)]() + 1; - var q = Math.floor((M - 1) / 3) + 1; - var d = date[dateGetterName(isUTC)](); - var e = date['get' + (isUTC ? 'UTC' : '') + 'Day'](); - var H = date[hoursGetterName(isUTC)](); - var h = (H - 1) % 12 + 1; - var m = date[minutesGetterName(isUTC)](); - var s = date[secondsGetterName(isUTC)](); - var S = date[millisecondsGetterName(isUTC)](); - var a = H >= 12 ? 'pm' : 'am'; - var A = a.toUpperCase(); - var localeModel = lang instanceof Model ? lang : getLocaleModel(lang || SYSTEM_LANG) || getDefaultLocaleModel(); - var timeModel = localeModel.getModel('time'); - var month = timeModel.get('month'); - var monthAbbr = timeModel.get('monthAbbr'); - var dayOfWeek = timeModel.get('dayOfWeek'); - var dayOfWeekAbbr = timeModel.get('dayOfWeekAbbr'); - return (template || '').replace(/{a}/g, a + '').replace(/{A}/g, A + '').replace(/{yyyy}/g, y + '').replace(/{yy}/g, pad(y % 100 + '', 2)).replace(/{Q}/g, q + '').replace(/{MMMM}/g, month[M - 1]).replace(/{MMM}/g, monthAbbr[M - 1]).replace(/{MM}/g, pad(M, 2)).replace(/{M}/g, M + '').replace(/{dd}/g, pad(d, 2)).replace(/{d}/g, d + '').replace(/{eeee}/g, dayOfWeek[e]).replace(/{ee}/g, dayOfWeekAbbr[e]).replace(/{e}/g, e + '').replace(/{HH}/g, pad(H, 2)).replace(/{H}/g, H + '').replace(/{hh}/g, pad(h + '', 2)).replace(/{h}/g, h + '').replace(/{mm}/g, pad(m, 2)).replace(/{m}/g, m + '').replace(/{ss}/g, pad(s, 2)).replace(/{s}/g, s + '').replace(/{SSS}/g, pad(S, 3)).replace(/{S}/g, S + ''); - } - - function leveledFormat(tick, idx, formatter, lang, isUTC) { - var template = null; - - if (isString(formatter)) { - // Single formatter for all units at all levels - template = formatter; - } else if (isFunction(formatter)) { - var extra = { - time: tick.time, - level: tick.time.level - }; - var scaleBreakHelper = getScaleBreakHelper(); - - if (scaleBreakHelper) { - scaleBreakHelper.makeAxisLabelFormatterParamBreak(extra, tick["break"]); - } - - template = formatter(tick.value, idx, extra); - } else { - var tickTime = tick.time; - - if (tickTime) { - var leveledTplArr = formatter[tickTime.lowerTimeUnit][tickTime.upperTimeUnit]; - template = leveledTplArr[Math.min(tickTime.level, leveledTplArr.length - 1)] || ''; - } else { - // tick may be from customTicks or timeline therefore no tick.time. - var unit = getUnitFromValue(tick.value, isUTC); - template = formatter[unit][unit][0]; - } - } - - return format$1(new Date(tick.value), template, isUTC, lang); - } - - function getUnitFromValue(value, isUTC) { - var date = parseDate(value); - var M = date[monthGetterName(isUTC)]() + 1; - var d = date[dateGetterName(isUTC)](); - var h = date[hoursGetterName(isUTC)](); - var m = date[minutesGetterName(isUTC)](); - var s = date[secondsGetterName(isUTC)](); - var S = date[millisecondsGetterName(isUTC)](); - var isSecond = S === 0; - var isMinute = isSecond && s === 0; - var isHour = isMinute && m === 0; - var isDay = isHour && h === 0; - var isMonth = isDay && d === 1; - var isYear = isMonth && M === 1; - - if (isYear) { - return 'year'; - } else if (isMonth) { - return 'month'; - } else if (isDay) { - return 'day'; - } else if (isHour) { - return 'hour'; - } else if (isMinute) { - return 'minute'; - } else if (isSecond) { - return 'second'; - } else { - return 'millisecond'; - } - } // export function getUnitValue( - // value: number | Date, - // unit: TimeUnit, - // isUTC: boolean - // ) : number { - // const date = zrUtil.isNumber(value) - // ? numberUtil.parseDate(value) - // : value; - // unit = unit || getUnitFromValue(value, isUTC); - // switch (unit) { - // case 'year': - // return date[fullYearGetterName(isUTC)](); - // case 'half-year': - // return date[monthGetterName(isUTC)]() >= 6 ? 1 : 0; - // case 'quarter': - // return Math.floor((date[monthGetterName(isUTC)]() + 1) / 4); - // case 'month': - // return date[monthGetterName(isUTC)](); - // case 'day': - // return date[dateGetterName(isUTC)](); - // case 'half-day': - // return date[hoursGetterName(isUTC)]() / 24; - // case 'hour': - // return date[hoursGetterName(isUTC)](); - // case 'minute': - // return date[minutesGetterName(isUTC)](); - // case 'second': - // return date[secondsGetterName(isUTC)](); - // case 'millisecond': - // return date[millisecondsGetterName(isUTC)](); - // } - // } - - /** - * e.g., - * If timeUnit is 'year', return the Jan 1st 00:00:00 000 of that year. - * If timeUnit is 'day', return the 00:00:00 000 of that day. - * - * @return The input date. - */ - - - function roundTime(date, timeUnit, isUTC) { - switch (timeUnit) { - case 'year': - date[monthSetterName(isUTC)](0); - - case 'month': - date[dateSetterName(isUTC)](1); - - case 'day': - date[hoursSetterName(isUTC)](0); - - case 'hour': - date[minutesSetterName(isUTC)](0); - - case 'minute': - date[secondsSetterName(isUTC)](0); - - case 'second': - date[millisecondsSetterName(isUTC)](0); - } - - return date; - } - - function fullYearGetterName(isUTC) { - return isUTC ? 'getUTCFullYear' : 'getFullYear'; - } - - function monthGetterName(isUTC) { - return isUTC ? 'getUTCMonth' : 'getMonth'; - } - - function dateGetterName(isUTC) { - return isUTC ? 'getUTCDate' : 'getDate'; - } - - function hoursGetterName(isUTC) { - return isUTC ? 'getUTCHours' : 'getHours'; - } - - function minutesGetterName(isUTC) { - return isUTC ? 'getUTCMinutes' : 'getMinutes'; - } - - function secondsGetterName(isUTC) { - return isUTC ? 'getUTCSeconds' : 'getSeconds'; - } - - function millisecondsGetterName(isUTC) { - return isUTC ? 'getUTCMilliseconds' : 'getMilliseconds'; - } - - function fullYearSetterName(isUTC) { - return isUTC ? 'setUTCFullYear' : 'setFullYear'; - } - - function monthSetterName(isUTC) { - return isUTC ? 'setUTCMonth' : 'setMonth'; - } - - function dateSetterName(isUTC) { - return isUTC ? 'setUTCDate' : 'setDate'; - } - - function hoursSetterName(isUTC) { - return isUTC ? 'setUTCHours' : 'setHours'; - } - - function minutesSetterName(isUTC) { - return isUTC ? 'setUTCMinutes' : 'setMinutes'; - } - - function secondsSetterName(isUTC) { - return isUTC ? 'setUTCSeconds' : 'setSeconds'; - } - - function millisecondsSetterName(isUTC) { - return isUTC ? 'setUTCMilliseconds' : 'setMilliseconds'; - } - - function getTextRect(text, font, align, verticalAlign, padding, rich, truncate, lineHeight) { - var textEl = new ZRText({ - style: { - text: text, - font: font, - align: align, - verticalAlign: verticalAlign, - padding: padding, - rich: rich, - overflow: truncate ? 'truncate' : null, - lineHeight: lineHeight - } - }); - return textEl.getBoundingRect(); - } - /** - * Add a comma each three digit. - */ - - - function addCommas(x) { - if (!isNumeric(x)) { - return isString(x) ? x : '-'; - } - - var parts = (x + '').split('.'); - return parts[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g, '$1,') + (parts.length > 1 ? '.' + parts[1] : ''); - } - - function toCamelCase(str, upperCaseFirst) { - str = (str || '').toLowerCase().replace(/-(.)/g, function (match, group1) { - return group1.toUpperCase(); - }); - - if (upperCaseFirst && str) { - str = str.charAt(0).toUpperCase() + str.slice(1); - } - - return str; - } - - var normalizeCssArray = normalizeCssArray$1; - /** - * Make value user readable for tooltip and label. - * "User readable": - * Try to not print programmer-specific text like NaN, Infinity, null, undefined. - * Avoid to display an empty string, which users can not recognize there is - * a value and it might look like a bug. - */ - - function makeValueReadable(value, valueType, useUTC) { - var USER_READABLE_DEFUALT_TIME_PATTERN = '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}'; - - function stringToUserReadable(str) { - return str && trim(str) ? str : '-'; - } - - function isNumberUserReadable(num) { - return !!(num != null && !isNaN(num) && isFinite(num)); - } - - var isTypeTime = valueType === 'time'; - var isValueDate = value instanceof Date; - - if (isTypeTime || isValueDate) { - var date = isTypeTime ? parseDate(value) : value; - - if (!isNaN(+date)) { - return format$1(date, USER_READABLE_DEFUALT_TIME_PATTERN, useUTC); - } else if (isValueDate) { - return '-'; - } // In other cases, continue to try to display the value in the following code. - - } - - if (valueType === 'ordinal') { - return isStringSafe(value) ? stringToUserReadable(value) : isNumber(value) ? isNumberUserReadable(value) ? value + '' : '-' : '-'; - } // By default. - - - var numericResult = numericToNumber(value); - return isNumberUserReadable(numericResult) ? addCommas(numericResult) : isStringSafe(value) ? stringToUserReadable(value) : typeof value === 'boolean' ? value + '' : '-'; - } - - var TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; - - var wrapVar = function (varName, seriesIdx) { - return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}'; - }; - /** - * Template formatter - * @param {Array.|Object} paramsList - */ - - - function formatTpl(tpl, paramsList, encode) { - if (!isArray(paramsList)) { - paramsList = [paramsList]; - } - - var seriesLen = paramsList.length; - - if (!seriesLen) { - return ''; - } - - var $vars = paramsList[0].$vars || []; - - for (var i = 0; i < $vars.length; i++) { - var alias = TPL_VAR_ALIAS[i]; - tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0)); - } - - for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) { - for (var k = 0; k < $vars.length; k++) { - var val = paramsList[seriesIdx][$vars[k]]; - tpl = tpl.replace(wrapVar(TPL_VAR_ALIAS[k], seriesIdx), encode ? encodeHTML(val) : val); - } - } - - return tpl; - } - - function getTooltipMarker(inOpt, extraCssText) { - var opt = isString(inOpt) ? { - color: inOpt, - extraCssText: extraCssText - } : inOpt || {}; - var color = opt.color; - var type = opt.type; - extraCssText = opt.extraCssText; - var renderMode = opt.renderMode || 'html'; - - if (!color) { - return ''; - } - - if (renderMode === 'html') { - return type === 'subItem' ? '' : ''; - } else { - // Should better not to auto generate style name by auto-increment number here. - // Because this util is usually called in tooltip formatter, which is probably - // called repeatedly when mouse move and the auto-increment number increases fast. - // Users can make their own style name by theirselves, make it unique and readable. - var markerId = opt.markerId || 'markerX'; - return { - renderMode: renderMode, - content: '{' + markerId + '|} ', - style: type === 'subItem' ? { - width: 4, - height: 4, - borderRadius: 2, - backgroundColor: color - } : { - width: 10, - height: 10, - borderRadius: 5, - backgroundColor: color - } - }; - } - } - /** - * @deprecated Use `time/format` instead. - * ISO Date format - * @param {string} tpl - * @param {number} value - * @param {boolean} [isUTC=false] Default in local time. - * see `module:echarts/scale/Time` - * and `module:echarts/util/number#parseDate`. - * @inner - */ - - - function formatTime(tpl, value, isUTC) { - { - deprecateReplaceLog('echarts.format.formatTime', 'echarts.time.format'); - } - - if (tpl === 'week' || tpl === 'month' || tpl === 'quarter' || tpl === 'half-year' || tpl === 'year') { - tpl = 'MM-dd\nyyyy'; - } - - var date = parseDate(value); - var getUTC = isUTC ? 'getUTC' : 'get'; - var y = date[getUTC + 'FullYear'](); - var M = date[getUTC + 'Month']() + 1; - var d = date[getUTC + 'Date'](); - var h = date[getUTC + 'Hours'](); - var m = date[getUTC + 'Minutes'](); - var s = date[getUTC + 'Seconds'](); - var S = date[getUTC + 'Milliseconds'](); - tpl = tpl.replace('MM', pad(M, 2)).replace('M', M).replace('yyyy', y).replace('yy', pad(y % 100 + '', 2)).replace('dd', pad(d, 2)).replace('d', d).replace('hh', pad(h, 2)).replace('h', h).replace('mm', pad(m, 2)).replace('m', m).replace('ss', pad(s, 2)).replace('s', s).replace('SSS', pad(S, 3)); - return tpl; - } - /** - * Capital first - * @param {string} str - * @return {string} - */ - - - function capitalFirst(str) { - return str ? str.charAt(0).toUpperCase() + str.substr(1) : str; - } - /** - * @return Never be null/undefined. - */ - - - function convertToColorString(color, defaultColor) { - defaultColor = defaultColor || 'transparent'; - return isString(color) ? color : isObject$2(color) ? color.colorStops && (color.colorStops[0] || {}).color || defaultColor : defaultColor; - } - /** - * open new tab - * @param link url - * @param target blank or self - */ - - - function windowOpen(link, target) { - /* global window */ - if (target === '_blank' || target === 'blank') { - var blank = window.open(); - blank.opener = null; - blank.location.href = link; - } else { - window.open(link, target); - } - } - /** - * FIXME: - * `nonSeriesBoxCoordSysCreators` and `_nonSeriesBoxMasterList` are hardcoded implementations. - * Regarding "coord sys layout based on another coord sys", currently we only exprimentally support one level - * dpendency, such as, "grid(cartesian)s can be laid out based on matrix/calendar coord sys." - * But a comprehensive implementation may need to support: - * - Recursive dependencies. e.g., a matrix coord sys lays out based on another matrix coord sys. - * That requires in the implementation `create` and `update` of coord sys are called by a dependency graph. - * (@see enableTopologicalTravel in `util/component.ts`) - */ - - - var nonSeriesBoxCoordSysCreators = {}; - var normalCoordSysCreators = {}; - - var CoordinateSystemManager = - /** @class */ - function () { - function CoordinateSystemManager() { - this._normalMasterList = []; - this._nonSeriesBoxMasterList = []; - } - /** - * Typically, - * - in `create`, a coord sys lays out based on a given rect; - * - in `update`, update the pixel and data extent of there axes (if any) based on processed `series.data`. - * After that, a coord sys can serve (typically by `dataToPoint`/`dataToLayout`/`pointToData`). - * If the coordinate system do not lay out based on `series.data`, `update` is not needed. - */ - - - CoordinateSystemManager.prototype.create = function (ecModel, api) { - this._nonSeriesBoxMasterList = dealCreate(nonSeriesBoxCoordSysCreators, true); - this._normalMasterList = dealCreate(normalCoordSysCreators, false); - - function dealCreate(creatorMap, canBeNonSeriesBox) { - var coordinateSystems = []; - each$4(creatorMap, function (creator, type) { - var list = creator.create(ecModel, api); - coordinateSystems = coordinateSystems.concat(list || []); - { - if (canBeNonSeriesBox) { - // Disallow `update` is a brutal way to ensure `_nonSeriesBoxMasterList`s are ready to - // serve after `create`. But if `update` has to be involved in `_nonSeriesBoxMasterList` - // for some future case, more complicated mechanisms need to be introduced. - each$4(list, function (master) { - return assert(!master.update); - }); - } - } - }); - return coordinateSystems; - } - }; - /** - * @see CoordinateSystem['create'] - */ - - - CoordinateSystemManager.prototype.update = function (ecModel, api) { - each$4(this._normalMasterList, function (coordSys) { - coordSys.update && coordSys.update(ecModel, api); - }); - }; - - CoordinateSystemManager.prototype.getCoordinateSystems = function () { - return this._normalMasterList.concat(this._nonSeriesBoxMasterList); - }; - - CoordinateSystemManager.register = function (type, creator) { - if (type === 'matrix' || type === 'calendar') { - // FIXME: hardcode, @see nonSeriesBoxCoordSysCreators - nonSeriesBoxCoordSysCreators[type] = creator; - return; - } - - normalCoordSysCreators[type] = creator; - }; - - CoordinateSystemManager.get = function (type) { - return normalCoordSysCreators[type] || nonSeriesBoxCoordSysCreators[type]; - }; - - return CoordinateSystemManager; - }(); - - function canBeNonSeriesBoxCoordSys(coordSysType) { - return !!nonSeriesBoxCoordSysCreators[coordSysType]; - } - - var BoxCoordinateSystemCoordFrom = { - // By default fetch coord from `model.get('coord')`. - coord: 1, - // Some model/series, such as pie, is allowed to also get coord from `model.get('center')`, - // if cannot get from `model.get('coord')`. But historically pie use `center` option, but - // geo use `layoutCenter` option to specify layout center; they are not able to be unified. - // Therefor it is not recommended. - coord2: 2 - }; - var coordSysUseMap = createHashMap(); - /** - * @return Be an object, but never be NullUndefined. - */ - - function getCoordForBoxCoordSys(model) { - var coord = model.getShallow('coord', true); - var from = BoxCoordinateSystemCoordFrom.coord; - - if (coord == null) { - var store = coordSysUseMap.get(model.type); - - if (store && store.getCoord2) { - from = BoxCoordinateSystemCoordFrom.coord2; - coord = store.getCoord2(model); - } - } - - return { - coord: coord, - from: from - }; - } - /** - * - "dataCoordSys": each data item is laid out based on a coord sys. - * - "boxCoordSys": the overall bounding rect or anchor point is calculated based on a coord sys. - * e.g., - * grid rect (cartesian rect) is calculate based on matrix/calendar coord sys; - * pie center is calculated based on calendar/cartesian; - * - * The default value (if not declared in option `coordinateSystemUsage`): - * For series, use `dataCoordSys`, since this is the most case and backward compatible. - * For non-series components, use `boxCoordSys`, since `dataCoordSys` is not applicable. - */ - - - var CoordinateSystemUsageKind = { - none: 0, - dataCoordSys: 1, - boxCoordSys: 2 - }; - - function decideCoordSysUsageKind( // Component or series - model, printError) { - // For backward compat, still not use `true` in model.get. - var coordSysType = model.getShallow('coordinateSystem'); - var coordSysUsageOption = model.getShallow('coordinateSystemUsage', true); - var isDeclaredExplicitly = coordSysUsageOption != null; - var kind = CoordinateSystemUsageKind.none; - - if (coordSysType) { - var isSeries = model.mainType === 'series'; - - if (coordSysUsageOption == null) { - coordSysUsageOption = isSeries ? 'data' : 'box'; - } - - if (coordSysUsageOption === 'data') { - kind = CoordinateSystemUsageKind.dataCoordSys; - - if (!isSeries) { - { - if (isDeclaredExplicitly && printError) { - error('coordinateSystemUsage "data" is not supported in non-series components.'); - } - } - kind = CoordinateSystemUsageKind.none; - } - } else if (coordSysUsageOption === 'box') { - kind = CoordinateSystemUsageKind.boxCoordSys; - - if (!isSeries && !canBeNonSeriesBoxCoordSys(coordSysType)) { - { - if (isDeclaredExplicitly && printError) { - error("coordinateSystem \"" + coordSysType + "\" cannot be used" + (" as coordinateSystemUsage \"box\" for \"" + model.type + "\" yet.")); - } - } - kind = CoordinateSystemUsageKind.none; - } - } - } - - return { - coordSysType: coordSysType, - kind: kind - }; - } - /** - * These cases are considered: - * (A) Most series can use only "dataCoordSys", but "boxCoordSys" is not applicable: - * - e.g., series.heatmap, series.line, series.bar, series.scatter, ... - * (B) Some series and most components can use only "boxCoordSys", but "dataCoordSys" is not applicable: - * - e.g., series.pie, series.funnel, ... - * - e.g., grid, polar, geo, title, ... - * (C) Several series can use both "boxCoordSys" and "dataCoordSys", even at the same time: - * - e.g., series.graph, series.map - * - If graph or map series use a "boxCoordSys", it creates a internal "dataCoordSys" to lay out its data. - * - Graph series can use matrix coord sys as either the "dataCoordSys" (each item layout on one cell) - * or "boxCoordSys" (the entire series are layout within one cell). - * - To achieve this effect, - * `series.coordinateSystemUsage: 'box'` needs to be specified explicitly. - * - * Check these echarts option settings: - * - If `series: {type: 'bar'}`: - * dataCoordSys: "cartesian2d", boxCoordSys: "none". - * (since `coordinateSystem: 'cartesian2d'` is the default option in bar.) - * - If `grid: {coordinateSystem: 'matrix'}` - * dataCoordSys: "none", boxCoordSys: "matrix". - * - If `series: {type: 'pie', coordinateSystem: 'matrix'}`: - * dataCoordSys: "none", boxCoordSys: "matrix". - * (since `coordinateSystemUsage: 'box'` is the default option in pie.) - * - If `series: {type: 'graph', coordinateSystem: 'matrix'}`: - * dataCoordSys: "matrix", boxCoordSys: "none" - * - If `series: {type: 'graph', coordinateSystem: 'matrix', coordinateSystemUsage: 'box'}`: - * dataCoordSys: "an internal view", boxCoordSys: "the internal view is laid out on a matrix" - * - If `series: {type: 'map'}`: - * dataCoordSys: "a internal geo", boxCoordSys: "none" - * - If `series: {type: 'map', coordinateSystem: 'geo', geoIndex: 0}`: - * dataCoordSys: "a geo", boxCoordSys: "none" - * - If `series: {type: 'map', coordinateSystem: 'matrix'}`: - * not_applicable - * - If `series: {type: 'map', coordinateSystem: 'matrix', coordinateSystemUsage: 'box'}`: - * dataCoordSys: "an internal geo", boxCoordSys: "the internal geo is laid out on a matrix" - * - * @usage - * For case (A) & (B), - * call `injectCoordSysByOption({coordSysType: 'aaa', ...})` once for each series/components. - * For case (C), - * call `injectCoordSysByOption({coordSysType: 'aaa', ...})` once for each series/components, - * and then call `injectCoordSysByOption({coordSysType: 'bbb', ..., isDefaultDataCoordSys: true})` - * once for each series/components. - * - * @return Whether injected. - */ - - - function injectCoordSysByOption(opt) { - var targetModel = opt.targetModel, - coordSysType = opt.coordSysType, - coordSysProvider = opt.coordSysProvider, - isDefaultDataCoordSys = opt.isDefaultDataCoordSys, - allowNotFound = opt.allowNotFound; - { - assert(!!coordSysType); - } - - var _a = decideCoordSysUsageKind(targetModel, true), - kind = _a.kind, - declaredType = _a.coordSysType; - - if (isDefaultDataCoordSys && kind !== CoordinateSystemUsageKind.dataCoordSys) { - // If both dataCoordSys and boxCoordSys declared in one model. - // There is the only case in series-graph, and no other cases yet. - kind = CoordinateSystemUsageKind.dataCoordSys; - declaredType = coordSysType; - } - - if (kind === CoordinateSystemUsageKind.none || declaredType !== coordSysType) { - return false; - } - - var coordSys = coordSysProvider(coordSysType, targetModel); - - if (!coordSys) { - { - if (!allowNotFound) { - error(coordSysType + " cannot be found for" + (" " + targetModel.type + " (index: " + targetModel.componentIndex + ").")); - } - } - return false; - } - - if (kind === CoordinateSystemUsageKind.dataCoordSys) { - { - assert(targetModel.mainType === 'series'); - } - targetModel.coordinateSystem = coordSys; - } else { - // kind === 'boxCoordSys' - targetModel.boxCoordinateSystem = coordSys; - } - - return true; - } - - var each$3 = each$4; - /** - * @public - */ - - var LOCATION_PARAMS = ['left', 'right', 'top', 'bottom', 'width', 'height']; - /** - * @public - */ - - var HV_NAMES = [['width', 'left', 'right'], ['height', 'top', 'bottom']]; - - function boxLayout(orient, group, gap, maxWidth, maxHeight) { - var x = 0; - var y = 0; - - if (maxWidth == null) { - maxWidth = Infinity; - } - - if (maxHeight == null) { - maxHeight = Infinity; - } - - var currentLineMaxSize = 0; - group.eachChild(function (child, idx) { - var rect = child.getBoundingRect(); - var nextChild = group.childAt(idx + 1); - var nextChildRect = nextChild && nextChild.getBoundingRect(); - var nextX; - var nextY; - - if (orient === 'horizontal') { - var moveX = rect.width + (nextChildRect ? -nextChildRect.x + rect.x : 0); - nextX = x + moveX; // Wrap when width exceeds maxWidth or meet a `newline` group - // FIXME compare before adding gap? - - if (nextX > maxWidth || child.newline) { - x = 0; - nextX = moveX; - y += currentLineMaxSize + gap; - currentLineMaxSize = rect.height; - } else { - // FIXME: consider rect.y is not `0`? - currentLineMaxSize = Math.max(currentLineMaxSize, rect.height); - } - } else { - var moveY = rect.height + (nextChildRect ? -nextChildRect.y + rect.y : 0); - nextY = y + moveY; // Wrap when width exceeds maxHeight or meet a `newline` group - - if (nextY > maxHeight || child.newline) { - x += currentLineMaxSize + gap; - y = 0; - nextY = moveY; - currentLineMaxSize = rect.width; - } else { - currentLineMaxSize = Math.max(currentLineMaxSize, rect.width); - } - } - - if (child.newline) { - return; - } - - child.x = x; - child.y = y; - child.markRedraw(); - orient === 'horizontal' ? x = nextX + gap : y = nextY + gap; - }); - } - /** - * VBox or HBox layouting - * @param {string} orient - * @param {module:zrender/graphic/Group} group - * @param {number} gap - * @param {number} [width=Infinity] - * @param {number} [height=Infinity] - */ - - - var box = boxLayout; - /** - * VBox layouting - * @param {module:zrender/graphic/Group} group - * @param {number} gap - * @param {number} [width=Infinity] - * @param {number} [height=Infinity] - */ - - curry$1(boxLayout, 'vertical'); - /** - * HBox layouting - * @param {module:zrender/graphic/Group} group - * @param {number} gap - * @param {number} [width=Infinity] - * @param {number} [height=Infinity] - */ - - curry$1(boxLayout, 'horizontal'); - - function getBoxLayoutParams(boxLayoutModel, ignoreParent) { - return { - left: boxLayoutModel.getShallow('left', ignoreParent), - top: boxLayoutModel.getShallow('top', ignoreParent), - right: boxLayoutModel.getShallow('right', ignoreParent), - bottom: boxLayoutModel.getShallow('bottom', ignoreParent), - width: boxLayoutModel.getShallow('width', ignoreParent), - height: boxLayoutModel.getShallow('height', ignoreParent) - }; - } - /** - * Parse position info. - */ - - - function getLayoutRect(positionInfo, containerRect, // This is the space from the `containerRect` to the returned bounding rect. - // Commonly used in option `legend.padding`, `timeline.padding`, `title.padding`, - // `visualMap.padding`, ... - // [NOTICE]: - // It's named `margin`, because it's the space that outside the bounding rect. But from - // the perspective of the the caller, it's commonly used as the `padding` of a component, - // because conventionally background color covers this space. - // [BEHAVIOR]: - // - If width/height is specified, `margin` does not effect them. - // - Otherwise, they are calculated based on the rect that `containerRect` shrinked by `margin`. - // - left/right/top/bottom are based on the rect that `containerRect` shrinked by `margin`. - margin) { - margin = normalizeCssArray(margin || 0); - var containerWidth = containerRect.width; - var containerHeight = containerRect.height; - var left = parsePercent(positionInfo.left, containerWidth); - var top = parsePercent(positionInfo.top, containerHeight); - var right = parsePercent(positionInfo.right, containerWidth); - var bottom = parsePercent(positionInfo.bottom, containerHeight); - var width = parsePercent(positionInfo.width, containerWidth); - var height = parsePercent(positionInfo.height, containerHeight); - var verticalMargin = margin[2] + margin[0]; - var horizontalMargin = margin[1] + margin[3]; - var aspect = positionInfo.aspect; // If width is not specified, calculate width from left and right - - if (isNaN(width)) { - width = containerWidth - right - horizontalMargin - left; - } - - if (isNaN(height)) { - height = containerHeight - bottom - verticalMargin - top; - } - - if (aspect != null) { - // If width and height are not given - // 1. Graph should not exceeds the container - // 2. Aspect must be keeped - // 3. Graph should take the space as more as possible - // FIXME - // Margin is not considered, because there is no case that both - // using margin and aspect so far. - if (isNaN(width) && isNaN(height)) { - // PENDING: if only `left` or `right` is defined, perhaps it's more preferable to - // calculate size based on `containerWidth - left` or `containerWidth - left` here, - // but for backward compatibility we do not change it. - if (aspect > containerWidth / containerHeight) { - width = containerWidth * 0.8; - } else { - height = containerHeight * 0.8; - } - } // Calculate width or height with given aspect - - - if (isNaN(width)) { - width = aspect * height; - } - - if (isNaN(height)) { - height = width / aspect; - } - } // If left is not specified, calculate left from right and width - - - if (isNaN(left)) { - left = containerWidth - right - width - horizontalMargin; - } - - if (isNaN(top)) { - top = containerHeight - bottom - height - verticalMargin; - } // Align left and top - - - switch (positionInfo.left || positionInfo.right) { - case 'center': - left = containerWidth / 2 - width / 2 - margin[3]; - break; - - case 'right': - left = containerWidth - width - horizontalMargin; - break; - } - - switch (positionInfo.top || positionInfo.bottom) { - case 'middle': - case 'center': - top = containerHeight / 2 - height / 2 - margin[0]; - break; - - case 'bottom': - top = containerHeight - height - verticalMargin; - break; - } // If something is wrong and left, top, width, height are calculated as NaN - - - left = left || 0; - top = top || 0; - - if (isNaN(width)) { - // Width may be NaN if only one value is given except width - width = containerWidth - horizontalMargin - left - (right || 0); - } - - if (isNaN(height)) { - // Height may be NaN if only one value is given except height - height = containerHeight - verticalMargin - top - (bottom || 0); - } - - var rect = new BoundingRect((containerRect.x || 0) + left + margin[3], (containerRect.y || 0) + top + margin[0], width, height); - rect.margin = margin; - return rect; - } - - var BoxLayoutReferenceType = { - rect: 1, - point: 2 - }; - /** - * Uniformly calculate layout reference (rect or center) based on either: - * - viewport: - * - Get `refContainer` as `{x: 0, y: 0, width: api.getWidth(), height: api.getHeight()}` - * - coordinate system, which can serve in several ways: - * - Use `dataToPoint` to get the `refPoint`, such as, in cartesian2d coord sys. - * - Use `dataToLayout` to get the `refContainer`, such as, in matrix coord sys. - */ - - function createBoxLayoutReference(model, api, opt) { - var refContainer; - var refPoint; - var layoutRefType; - var boxCoordSys = model.boxCoordinateSystem; - var boxCoordFrom; - - if (boxCoordSys) { - var _a = getCoordForBoxCoordSys(model), - coord = _a.coord, - from = _a.from; // Do not use `clamp` in `dataToLayout` and `dataToPoint`, because: - // 1. Should support overflow (such as, by dataZoom), where NaN should be in the result. - // 2. Be consistent with the way used in `series.data` - - - if (boxCoordSys.dataToLayout) { - layoutRefType = BoxLayoutReferenceType.rect; - boxCoordFrom = from; - var result = boxCoordSys.dataToLayout(coord); - refContainer = result.contentRect || result.rect; - } else if (opt && opt.enableLayoutOnlyByCenter && boxCoordSys.dataToPoint) { - layoutRefType = BoxLayoutReferenceType.point; - boxCoordFrom = from; - refPoint = boxCoordSys.dataToPoint(coord); - } else { - { - error(model.type + "[" + model.componentIndex + "]" + (" layout based on " + boxCoordSys.type + " is not supported.")); - } - } - } - - if (layoutRefType == null) { - layoutRefType = BoxLayoutReferenceType.rect; - } - - if (layoutRefType === BoxLayoutReferenceType.rect) { - if (!refContainer) { - refContainer = { - x: 0, - y: 0, - width: api.getWidth(), - height: api.getHeight() - }; - } - - refPoint = [refContainer.x + refContainer.width / 2, refContainer.y + refContainer.height / 2]; - } - - return { - type: layoutRefType, - refContainer: refContainer, - refPoint: refPoint, - boxCoordFrom: boxCoordFrom - }; - } - - function fetchLayoutMode(ins) { - var layoutMode = ins.layoutMode || ins.constructor.layoutMode; - return isObject$2(layoutMode) ? layoutMode : layoutMode ? { - type: layoutMode - } : null; - } - /** - * Consider Case: - * When default option has {left: 0, width: 100}, and we set {right: 0} - * through setOption or media query, using normal zrUtil.merge will cause - * {right: 0} does not take effect. - * - * @example - * ComponentModel.extend({ - * init: function () { - * ... - * let inputPositionParams = layout.getLayoutParams(option); - * this.mergeOption(inputPositionParams); - * }, - * mergeOption: function (newOption) { - * newOption && zrUtil.merge(thisOption, newOption, true); - * layout.mergeLayoutParam(thisOption, newOption); - * } - * }); - * - * @param targetOption - * @param newOption - * @param opt - */ - - - function mergeLayoutParam(targetOption, newOption, opt) { - var ignoreSize = opt && opt.ignoreSize; - !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]); - var hResult = merge(HV_NAMES[0], 0); - var vResult = merge(HV_NAMES[1], 1); - copy(HV_NAMES[0], targetOption, hResult); - copy(HV_NAMES[1], targetOption, vResult); - - function merge(names, hvIdx) { - var newParams = {}; - var newValueCount = 0; - var merged = {}; - var mergedValueCount = 0; - var enoughParamNumber = 2; - each$3(names, function (name) { - merged[name] = targetOption[name]; - }); - each$3(names, function (name) { - // Consider case: newOption.width is null, which is - // set by user for removing width setting. - hasOwn(newOption, name) && (newParams[name] = merged[name] = newOption[name]); - hasValue(newParams, name) && newValueCount++; - hasValue(merged, name) && mergedValueCount++; - }); - - if (ignoreSize[hvIdx]) { - // Only one of left/right is premitted to exist. - if (hasValue(newOption, names[1])) { - merged[names[2]] = null; - } else if (hasValue(newOption, names[2])) { - merged[names[1]] = null; - } - - return merged; - } // Case: newOption: {width: ..., right: ...}, - // or targetOption: {right: ...} and newOption: {width: ...}, - // There is no conflict when merged only has params count - // little than enoughParamNumber. - - - if (mergedValueCount === enoughParamNumber || !newValueCount) { - return merged; - } // Case: newOption: {width: ..., right: ...}, - // Than we can make sure user only want those two, and ignore - // all origin params in targetOption. - else if (newValueCount >= enoughParamNumber) { - return newParams; - } else { - // Chose another param from targetOption by priority. - for (var i = 0; i < names.length; i++) { - var name_1 = names[i]; - - if (!hasOwn(newParams, name_1) && hasOwn(targetOption, name_1)) { - newParams[name_1] = targetOption[name_1]; - break; - } - } - - return newParams; - } - } - - function hasValue(obj, name) { - return obj[name] != null && obj[name] !== 'auto'; - } - - function copy(names, target, source) { - each$3(names, function (name) { - target[name] = source[name]; - }); - } - } - /** - * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object. - */ - - - function getLayoutParams(source) { - return copyLayoutParams({}, source); - } - /** - * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object. - * @param {Object} source - * @return {Object} Result contains those props. - */ - - - function copyLayoutParams(target, source) { - source && target && each$3(LOCATION_PARAMS, function (name) { - hasOwn(source, name) && (target[name] = source[name]); - }); - return target; - } - - var inner$b = makeInner(); - - var ComponentModel = - /** @class */ - function (_super) { - __extends(ComponentModel, _super); - - function ComponentModel(option, parentModel, ecModel) { - var _this = _super.call(this, option, parentModel, ecModel) || this; - - _this.uid = getUID('ec_cpt_model'); - return _this; - } - - ComponentModel.prototype.init = function (option, parentModel, ecModel) { - this.mergeDefaultAndTheme(option, ecModel); - }; - - ComponentModel.prototype.mergeDefaultAndTheme = function (option, ecModel) { - var layoutMode = fetchLayoutMode(this); - var inputPositionParams = layoutMode ? getLayoutParams(option) : {}; - var themeModel = ecModel.getTheme(); - merge(option, themeModel.get(this.mainType)); - merge(option, this.getDefaultOption()); - - if (layoutMode) { - mergeLayoutParam(option, inputPositionParams, layoutMode); - } - }; - - ComponentModel.prototype.mergeOption = function (option, ecModel) { - merge(this.option, option, true); - var layoutMode = fetchLayoutMode(this); - - if (layoutMode) { - mergeLayoutParam(this.option, option, layoutMode); - } - }; - /** - * Called immediately after `init` or `mergeOption` of this instance called. - */ - - - ComponentModel.prototype.optionUpdated = function (newCptOption, isInit) {}; - /** - * [How to declare defaultOption]: - * - * (A) If using class declaration in typescript (since echarts 5): - * ```ts - * import {ComponentOption} from '../model/option.js'; - * export interface XxxOption extends ComponentOption { - * aaa: number - * } - * export class XxxModel extends Component { - * static type = 'xxx'; - * static defaultOption: XxxOption = { - * aaa: 123 - * } - * } - * Component.registerClass(XxxModel); - * ``` - * ```ts - * import {inheritDefaultOption} from '../util/component.js'; - * import {XxxModel, XxxOption} from './XxxModel.js'; - * export interface XxxSubOption extends XxxOption { - * bbb: number - * } - * class XxxSubModel extends XxxModel { - * static defaultOption: XxxSubOption = inheritDefaultOption(XxxModel.defaultOption, { - * bbb: 456 - * }) - * fn() { - * let opt = this.getDefaultOption(); - * // opt is {aaa: 123, bbb: 456} - * } - * } - * ``` - * - * (B) If using class extend (previous approach in echarts 3 & 4): - * ```js - * let XxxComponent = Component.extend({ - * defaultOption: { - * xx: 123 - * } - * }) - * ``` - * ```js - * let XxxSubComponent = XxxComponent.extend({ - * defaultOption: { - * yy: 456 - * }, - * fn: function () { - * let opt = this.getDefaultOption(); - * // opt is {xx: 123, yy: 456} - * } - * }) - * ``` - */ - - - ComponentModel.prototype.getDefaultOption = function () { - var ctor = this.constructor; - - if (!isExtendedClass(ctor)) { - // When using ES class declaration, defaultOption must be declared as static. - // And manually inherit the defaultOption from its parent class if needed, such as, - // ```ts - // static defaultOption = inheritDefaultOption(ParentModel.defaultOption, {...}); - // ``` - return ctor.defaultOption; - } // FIXME: remove this approach? - // Legacy: auto merge defaultOption from ancestor classes if using ParentClass.extend(subProto) - - - var fields = inner$b(this); - - if (!fields.defaultOption) { - var optList = []; - var clz = ctor; - - while (clz) { - var opt = clz.prototype.defaultOption; - opt && optList.push(opt); - clz = clz.superClass; - } - - var defaultOption = {}; - - for (var i = optList.length - 1; i >= 0; i--) { - defaultOption = merge(defaultOption, optList[i], true); - } - - fields.defaultOption = defaultOption; - } - - return fields.defaultOption; - }; - /** - * Notice: always force to input param `useDefault` in case that forget to consider it. - * The same behavior as `modelUtil.parseFinder`. - * - * @param useDefault In many cases like series refer axis and axis refer grid, - * If axis index / axis id not specified, use the first target as default. - * In other cases like dataZoom refer axis, if not specified, measn no refer. - */ - - - ComponentModel.prototype.getReferringComponents = function (mainType, opt) { - var indexKey = mainType + 'Index'; - var idKey = mainType + 'Id'; - return queryReferringComponents(this.ecModel, mainType, { - index: this.get(indexKey, true), - id: this.get(idKey, true) - }, opt); - }; - - ComponentModel.prototype.getBoxLayoutParams = function () { - // Consider itself having box layout configs. - // For backward compatibility, by default do not `ignoreParent`. - return getBoxLayoutParams(this, false); - }; - /** - * Get key for zlevel. - * If developers don't configure zlevel. We will assign zlevel to series based on the key. - * For example, lines with trail effect and progressive series will in an individual zlevel. - */ - - - ComponentModel.prototype.getZLevelKey = function () { - return ''; - }; - - ComponentModel.prototype.setZLevel = function (zlevel) { - this.option.zlevel = zlevel; - }; - - ComponentModel.protoInitialize = function () { - var proto = ComponentModel.prototype; - proto.type = 'component'; - proto.id = ''; - proto.name = ''; - proto.mainType = ''; - proto.subType = ''; - proto.componentIndex = 0; - }(); - - return ComponentModel; - }(Model); - - mountExtend(ComponentModel, Model); - enableClassManagement(ComponentModel); - enableSubTypeDefaulter(ComponentModel); - enableTopologicalTravel(ComponentModel, getDependencies); - - function getDependencies(componentType) { - var deps = []; - each$4(ComponentModel.getClassesByMainType(componentType), function (clz) { - deps = deps.concat(clz.dependencies || clz.prototype.dependencies || []); - }); // Ensure main type. - - deps = map$1(deps, function (type) { - return parseClassType(type).main; - }); // Hack dataset for convenience. - - if (componentType !== 'dataset' && indexOf(deps, 'dataset') <= 0) { - deps.unshift('dataset'); - } - - return deps; - } - - var tokens = { - color: {}, - darkColor: {}, - size: {} - }; - var color$1 = tokens.color = { - theme: ['#5070dd', '#b6d634', '#505372', '#ff994d', '#0ca8df', '#ffd10a', '#fb628b', '#785db0', '#3fbe95'], - neutral00: '#fff', - neutral05: '#f4f7fd', - neutral10: '#e8ebf0', - neutral15: '#dbdee4', - neutral20: '#cfd2d7', - neutral25: '#c3c5cb', - neutral30: '#b7b9be', - neutral35: '#aaacb2', - neutral40: '#9ea0a5', - neutral45: '#929399', - neutral50: '#86878c', - neutral55: '#797b7f', - neutral60: '#6d6e73', - neutral65: '#616266', - neutral70: '#54555a', - neutral75: '#48494d', - neutral80: '#3c3c41', - neutral85: '#303034', - neutral90: '#232328', - neutral95: '#17171b', - neutral99: '#000', - accent05: '#eff1f9', - accent10: '#e0e4f2', - accent15: '#d0d6ec', - accent20: '#c0c9e6', - accent25: '#b1bbdf', - accent30: '#a1aed9', - accent35: '#91a0d3', - accent40: '#8292cc', - accent45: '#7285c6', - accent50: '#6578ba', - accent55: '#5c6da9', - accent60: '#536298', - accent65: '#4a5787', - accent70: '#404c76', - accent75: '#374165', - accent80: '#2e3654', - accent85: '#252b43', - accent90: '#1b2032', - accent95: '#121521', - transparent: 'rgba(0,0,0,0)', - highlight: 'rgba(255,231,130,0.8)' - }; - extend(color$1, { - primary: color$1.neutral80, - secondary: color$1.neutral70, - tertiary: color$1.neutral60, - quaternary: color$1.neutral50, - disabled: color$1.neutral20, - border: color$1.neutral30, - borderTint: color$1.neutral20, - borderShade: color$1.neutral40, - background: color$1.neutral05, - backgroundTint: 'rgba(234,237,245,0.5)', - backgroundTransparent: 'rgba(255,255,255,0)', - backgroundShade: color$1.neutral10, - shadow: 'rgba(0,0,0,0.2)', - shadowTint: 'rgba(129,130,136,0.2)', - axisLine: color$1.neutral70, - axisLineTint: color$1.neutral40, - axisTick: color$1.neutral70, - axisTickMinor: color$1.neutral60, - axisLabel: color$1.neutral70, - axisSplitLine: color$1.neutral15, - axisMinorSplitLine: color$1.neutral05 - }); - - for (var key in color$1) { - if (color$1.hasOwnProperty(key)) { - var hex = color$1[key]; - - if (key === 'theme') { - // Don't modify theme colors. - tokens.darkColor.theme = color$1.theme.slice(); - } else if (key === 'highlight') { - tokens.darkColor.highlight = 'rgba(255,231,130,0.4)'; - } else if (key.indexOf('accent') === 0) { - // Desaturate and lighten accent colors. - tokens.darkColor[key] = modifyHSL(hex, null, function (s) { - return s * 0.5; - }, function (l) { - return Math.min(1, 1.3 - l); - }); - } else { - tokens.darkColor[key] = modifyHSL(hex, null, function (s) { - return s * 0.9; - }, function (l) { - return 1 - Math.pow(l, 1.5); - }); - } - } - } - - tokens.size = { - xxs: 2, - xs: 5, - s: 10, - m: 15, - l: 20, - xl: 30, - xxl: 40, - xxxl: 50 - }; - var platform = ''; // Navigator not exists in node - - if (typeof navigator !== 'undefined') { - /* global navigator */ - platform = navigator.platform || ''; - } - - var decalColor = 'rgba(0, 0, 0, 0.2)'; - var themeColor = tokens.color.theme[0]; - var lightThemeColor = modifyHSL(themeColor, null, null, 0.9); - var globalDefault = { - darkMode: 'auto', - // backgroundColor: 'rgba(0,0,0,0)', - colorBy: 'series', - color: tokens.color.theme, - gradientColor: [lightThemeColor, themeColor], - aria: { - decal: { - decals: [{ - color: decalColor, - dashArrayX: [1, 0], - dashArrayY: [2, 5], - symbolSize: 1, - rotation: Math.PI / 6 - }, { - color: decalColor, - symbol: 'circle', - dashArrayX: [[8, 8], [0, 8, 8, 0]], - dashArrayY: [6, 0], - symbolSize: 0.8 - }, { - color: decalColor, - dashArrayX: [1, 0], - dashArrayY: [4, 3], - rotation: -Math.PI / 4 - }, { - color: decalColor, - dashArrayX: [[6, 6], [0, 6, 6, 0]], - dashArrayY: [6, 0] - }, { - color: decalColor, - dashArrayX: [[1, 0], [1, 6]], - dashArrayY: [1, 0, 6, 0], - rotation: Math.PI / 4 - }, { - color: decalColor, - symbol: 'triangle', - dashArrayX: [[9, 9], [0, 9, 9, 0]], - dashArrayY: [7, 2], - symbolSize: 0.75 - }] - } - }, - // If xAxis and yAxis declared, grid is created by default. - // grid: {}, - textStyle: { - // color: '#000', - // decoration: 'none', - // PENDING - fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif', - // fontFamily: 'Arial, Verdana, sans-serif', - fontSize: 12, - fontStyle: 'normal', - fontWeight: 'normal' - }, - // http://blogs.adobe.com/webplatform/2014/02/24/using-blend-modes-in-html-canvas/ - // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation - // Default is source-over - blendMode: null, - stateAnimation: { - duration: 300, - easing: 'cubicOut' - }, - animation: 'auto', - animationDuration: 1000, - animationDurationUpdate: 500, - animationEasing: 'cubicInOut', - animationEasingUpdate: 'cubicInOut', - animationThreshold: 2000, - // Configuration for progressive/incremental rendering - progressiveThreshold: 3000, - progressive: 400, - // Threshold of if use single hover layer to optimize. - // It is recommended that `hoverLayerThreshold` is equivalent to or less than - // `progressiveThreshold`, otherwise hover will cause restart of progressive, - // which is unexpected. - // see example . - hoverLayerThreshold: 3000, - // See: module:echarts/scale/Time - useUTC: false - }; - var VISUAL_DIMENSIONS = createHashMap(['tooltip', 'label', 'itemName', 'itemId', 'itemGroupId', 'itemChildGroupId', 'seriesName']); - var SOURCE_FORMAT_ORIGINAL = 'original'; - var SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows'; - var SOURCE_FORMAT_OBJECT_ROWS = 'objectRows'; - var SOURCE_FORMAT_KEYED_COLUMNS = 'keyedColumns'; - var SOURCE_FORMAT_TYPED_ARRAY = 'typedArray'; - var SOURCE_FORMAT_UNKNOWN = 'unknown'; - var SERIES_LAYOUT_BY_COLUMN = 'column'; - var SERIES_LAYOUT_BY_ROW = 'row'; // The result of `guessOrdinal`. - - var BE_ORDINAL = { - Must: 1, - Might: 2, - Not: 3 // Other cases - - }; - var innerGlobalModel = makeInner(); - /** - * MUST be called before mergeOption of all series. - */ - - function resetSourceDefaulter(ecModel) { - // `datasetMap` is used to make default encode. - innerGlobalModel(ecModel).datasetMap = createHashMap(); - } - /** - * [The strategy of the arrengment of data dimensions for dataset]: - * "value way": all axes are non-category axes. So series one by one take - * several (the number is coordSysDims.length) dimensions from dataset. - * The result of data arrengment of data dimensions like: - * | ser0_x | ser0_y | ser1_x | ser1_y | ser2_x | ser2_y | - * "category way": at least one axis is category axis. So the the first data - * dimension is always mapped to the first category axis and shared by - * all of the series. The other data dimensions are taken by series like - * "value way" does. - * The result of data arrengment of data dimensions like: - * | ser_shared_x | ser0_y | ser1_y | ser2_y | - * - * @return encode Never be `null/undefined`. - */ - - - function makeSeriesEncodeForAxisCoordSys(coordDimensions, seriesModel, source) { - var encode = {}; - var datasetModel = querySeriesUpstreamDatasetModel(seriesModel); // Currently only make default when using dataset, util more reqirements occur. - - if (!datasetModel || !coordDimensions) { - return encode; - } - - var encodeItemName = []; - var encodeSeriesName = []; - var ecModel = seriesModel.ecModel; - var datasetMap = innerGlobalModel(ecModel).datasetMap; - var key = datasetModel.uid + '_' + source.seriesLayoutBy; - var baseCategoryDimIndex; - var categoryWayValueDimStart; - coordDimensions = coordDimensions.slice(); - each$4(coordDimensions, function (coordDimInfoLoose, coordDimIdx) { - var coordDimInfo = isObject$2(coordDimInfoLoose) ? coordDimInfoLoose : coordDimensions[coordDimIdx] = { - name: coordDimInfoLoose - }; - - if (coordDimInfo.type === 'ordinal' && baseCategoryDimIndex == null) { - baseCategoryDimIndex = coordDimIdx; - categoryWayValueDimStart = getDataDimCountOnCoordDim(coordDimInfo); - } - - encode[coordDimInfo.name] = []; - }); - var datasetRecord = datasetMap.get(key) || datasetMap.set(key, { - categoryWayDim: categoryWayValueDimStart, - valueWayDim: 0 - }); // TODO - // Auto detect first time axis and do arrangement. - - each$4(coordDimensions, function (coordDimInfo, coordDimIdx) { - var coordDimName = coordDimInfo.name; - var count = getDataDimCountOnCoordDim(coordDimInfo); // In value way. - - if (baseCategoryDimIndex == null) { - var start = datasetRecord.valueWayDim; - pushDim(encode[coordDimName], start, count); - pushDim(encodeSeriesName, start, count); - datasetRecord.valueWayDim += count; // ??? TODO give a better default series name rule? - // especially when encode x y specified. - // consider: when multiple series share one dimension - // category axis, series name should better use - // the other dimension name. On the other hand, use - // both dimensions name. - } // In category way, the first category axis. - else if (baseCategoryDimIndex === coordDimIdx) { - pushDim(encode[coordDimName], 0, count); - pushDim(encodeItemName, 0, count); - } // In category way, the other axis. - else { - var start = datasetRecord.categoryWayDim; - pushDim(encode[coordDimName], start, count); - pushDim(encodeSeriesName, start, count); - datasetRecord.categoryWayDim += count; - } - }); - - function pushDim(dimIdxArr, idxFrom, idxCount) { - for (var i = 0; i < idxCount; i++) { - dimIdxArr.push(idxFrom + i); - } - } - - function getDataDimCountOnCoordDim(coordDimInfo) { - var dimsDef = coordDimInfo.dimsDef; - return dimsDef ? dimsDef.length : 1; - } - - encodeItemName.length && (encode.itemName = encodeItemName); - encodeSeriesName.length && (encode.seriesName = encodeSeriesName); - return encode; - } - /** - * @return If return null/undefined, indicate that should not use datasetModel. - */ - - - function querySeriesUpstreamDatasetModel(seriesModel) { - // Caution: consider the scenario: - // A dataset is declared and a series is not expected to use the dataset, - // and at the beginning `setOption({series: { noData })` (just prepare other - // option but no data), then `setOption({series: {data: [...]}); In this case, - // the user should set an empty array to avoid that dataset is used by default. - var thisData = seriesModel.get('data', true); - - if (!thisData) { - return queryReferringComponents(seriesModel.ecModel, 'dataset', { - index: seriesModel.get('datasetIndex', true), - id: seriesModel.get('datasetId', true) - }, SINGLE_REFERRING).models[0]; - } - } - /** - * @return Always return an array event empty. - */ - - - function queryDatasetUpstreamDatasetModels(datasetModel) { - // Only these attributes declared, we by default reference to `datasetIndex: 0`. - // Otherwise, no reference. - if (!datasetModel.get('transform', true) && !datasetModel.get('fromTransformResult', true)) { - return []; - } - - return queryReferringComponents(datasetModel.ecModel, 'dataset', { - index: datasetModel.get('fromDatasetIndex', true), - id: datasetModel.get('fromDatasetId', true) - }, SINGLE_REFERRING).models; - } - /** - * The rule should not be complex, otherwise user might not - * be able to known where the data is wrong. - * The code is ugly, but how to make it neat? - */ - - - function guessOrdinal(source, dimIndex) { - return doGuessOrdinal(source.data, source.sourceFormat, source.seriesLayoutBy, source.dimensionsDefine, source.startIndex, dimIndex); - } // dimIndex may be overflow source data. - // return {BE_ORDINAL} - - - function doGuessOrdinal(data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex) { - var result; // Experience value. - - var maxLoop = 5; - - if (isTypedArray(data)) { - return BE_ORDINAL.Not; - } // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine - // always exists in source. - - - var dimName; - var dimType; - - if (dimensionsDefine) { - var dimDefItem = dimensionsDefine[dimIndex]; - - if (isObject$2(dimDefItem)) { - dimName = dimDefItem.name; - dimType = dimDefItem.type; - } else if (isString(dimDefItem)) { - dimName = dimDefItem; - } - } - - if (dimType != null) { - return dimType === 'ordinal' ? BE_ORDINAL.Must : BE_ORDINAL.Not; - } - - if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) { - var dataArrayRows = data; - - if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) { - var sample = dataArrayRows[dimIndex]; - - for (var i = 0; i < (sample || []).length && i < maxLoop; i++) { - if ((result = detectValue(sample[startIndex + i])) != null) { - return result; - } - } - } else { - for (var i = 0; i < dataArrayRows.length && i < maxLoop; i++) { - var row = dataArrayRows[startIndex + i]; - - if (row && (result = detectValue(row[dimIndex])) != null) { - return result; - } - } - } - } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) { - var dataObjectRows = data; - - if (!dimName) { - return BE_ORDINAL.Not; - } - - for (var i = 0; i < dataObjectRows.length && i < maxLoop; i++) { - var item = dataObjectRows[i]; - - if (item && (result = detectValue(item[dimName])) != null) { - return result; - } - } - } else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) { - var dataKeyedColumns = data; - - if (!dimName) { - return BE_ORDINAL.Not; - } - - var sample = dataKeyedColumns[dimName]; - - if (!sample || isTypedArray(sample)) { - return BE_ORDINAL.Not; - } - - for (var i = 0; i < sample.length && i < maxLoop; i++) { - if ((result = detectValue(sample[i])) != null) { - return result; - } - } - } else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) { - var dataOriginal = data; - - for (var i = 0; i < dataOriginal.length && i < maxLoop; i++) { - var item = dataOriginal[i]; - var val = getDataItemValue(item); - - if (!isArray(val)) { - return BE_ORDINAL.Not; - } - - if ((result = detectValue(val[dimIndex])) != null) { - return result; - } - } - } - - function detectValue(val) { - var beStr = isString(val); // Consider usage convenience, '1', '2' will be treated as "number". - // `Number('')` (or any whitespace) is `0`. - - if (val != null && Number.isFinite(Number(val)) && val !== '') { - return beStr ? BE_ORDINAL.Might : BE_ORDINAL.Not; - } else if (beStr && val !== '-') { - return BE_ORDINAL.Must; - } - } - - return BE_ORDINAL.Not; - } - - var internalOptionCreatorMap = createHashMap(); - - function concatInternalOptions(ecModel, mainType, newCmptOptionList) { - var internalOptionCreator = internalOptionCreatorMap.get(mainType); - - if (!internalOptionCreator) { - return newCmptOptionList; - } - - var internalOptions = internalOptionCreator(ecModel); - - if (!internalOptions) { - return newCmptOptionList; - } - - { - for (var i = 0; i < internalOptions.length; i++) { - assert(isComponentIdInternal(internalOptions[i])); - } - } - return newCmptOptionList.concat(internalOptions); - } - - var innerColor = makeInner(); - makeInner(); - - var PaletteMixin = - /** @class */ - function () { - function PaletteMixin() {} - - PaletteMixin.prototype.getColorFromPalette = function (name, scope, requestNum) { - var defaultPalette = normalizeToArray(this.get('color', true)); - var layeredPalette = this.get('colorLayer', true); - return getFromPalette(this, innerColor, defaultPalette, layeredPalette, name, scope, requestNum); - }; - - PaletteMixin.prototype.clearColorPalette = function () { - clearPalette(this, innerColor); - }; - - return PaletteMixin; - }(); - - function getNearestPalette(palettes, requestColorNum) { - var paletteNum = palettes.length; // TODO palettes must be in order - - for (var i = 0; i < paletteNum; i++) { - if (palettes[i].length > requestColorNum) { - return palettes[i]; - } - } - - return palettes[paletteNum - 1]; - } - /** - * @param name MUST NOT be null/undefined. Otherwise call this function - * twise with the same parameters will get different result. - * @param scope default this. - * @return Can be null/undefined - */ - - - function getFromPalette(that, inner, defaultPalette, layeredPalette, name, scope, requestNum) { - scope = scope || that; - var scopeFields = inner(scope); - var paletteIdx = scopeFields.paletteIdx || 0; - var paletteNameMap = scopeFields.paletteNameMap = scopeFields.paletteNameMap || {}; // Use `hasOwnProperty` to avoid conflict with Object.prototype. - - if (paletteNameMap.hasOwnProperty(name)) { - return paletteNameMap[name]; - } - - var palette = requestNum == null || !layeredPalette ? defaultPalette : getNearestPalette(layeredPalette, requestNum); // In case can't find in layered color palette. - - palette = palette || defaultPalette; - - if (!palette || !palette.length) { - return; - } - - var pickedPaletteItem = palette[paletteIdx]; - - if (name) { - paletteNameMap[name] = pickedPaletteItem; - } - - scopeFields.paletteIdx = (paletteIdx + 1) % palette.length; - return pickedPaletteItem; - } - - function clearPalette(that, inner) { - inner(that).paletteIdx = 0; - inner(that).paletteNameMap = {}; - } // ----------------------- - // Internal method names: - // ----------------------- - - - var reCreateSeriesIndices; - var assertSeriesInitialized; - var initBase; - var OPTION_INNER_KEY = '\0_ec_inner'; - var OPTION_INNER_VALUE = 1; - var BUITIN_COMPONENTS_MAP = { - grid: 'GridComponent', - polar: 'PolarComponent', - geo: 'GeoComponent', - singleAxis: 'SingleAxisComponent', - parallel: 'ParallelComponent', - calendar: 'CalendarComponent', - matrix: 'MatrixComponent', - graphic: 'GraphicComponent', - toolbox: 'ToolboxComponent', - tooltip: 'TooltipComponent', - axisPointer: 'AxisPointerComponent', - brush: 'BrushComponent', - title: 'TitleComponent', - timeline: 'TimelineComponent', - markPoint: 'MarkPointComponent', - markLine: 'MarkLineComponent', - markArea: 'MarkAreaComponent', - legend: 'LegendComponent', - dataZoom: 'DataZoomComponent', - visualMap: 'VisualMapComponent', - // aria: 'AriaComponent', - // dataset: 'DatasetComponent', - // Dependencies - xAxis: 'GridComponent', - yAxis: 'GridComponent', - angleAxis: 'PolarComponent', - radiusAxis: 'PolarComponent' - }; - var BUILTIN_CHARTS_MAP = { - line: 'LineChart', - bar: 'BarChart', - pie: 'PieChart', - scatter: 'ScatterChart', - radar: 'RadarChart', - map: 'MapChart', - tree: 'TreeChart', - treemap: 'TreemapChart', - graph: 'GraphChart', - chord: 'ChordChart', - gauge: 'GaugeChart', - funnel: 'FunnelChart', - parallel: 'ParallelChart', - sankey: 'SankeyChart', - boxplot: 'BoxplotChart', - candlestick: 'CandlestickChart', - effectScatter: 'EffectScatterChart', - lines: 'LinesChart', - heatmap: 'HeatmapChart', - pictorialBar: 'PictorialBarChart', - themeRiver: 'ThemeRiverChart', - sunburst: 'SunburstChart', - custom: 'CustomChart' - }; - var componetsMissingLogPrinted = {}; - - function checkMissingComponents(option) { - each$4(option, function (componentOption, mainType) { - if (!ComponentModel.hasClass(mainType)) { - var componentImportName = BUITIN_COMPONENTS_MAP[mainType]; - - if (componentImportName && !componetsMissingLogPrinted[componentImportName]) { - error("Component " + mainType + " is used but not imported.\nimport { " + componentImportName + " } from 'echarts/components';\necharts.use([" + componentImportName + "]);"); - componetsMissingLogPrinted[componentImportName] = true; - } - } - }); - } - - var GlobalModel = - /** @class */ - function (_super) { - __extends(GlobalModel, _super); - - function GlobalModel() { - return _super !== null && _super.apply(this, arguments) || this; - } - - GlobalModel.prototype.init = function (option, parentModel, ecModel, theme, locale, optionManager) { - theme = theme || {}; - this.option = null; // Mark as not initialized. - - this._theme = new Model(theme); - this._locale = new Model(locale); - this._optionManager = optionManager; - }; - - GlobalModel.prototype.setOption = function (option, opts, optionPreprocessorFuncs) { - { - assert(option != null, 'option is null/undefined'); - assert(option[OPTION_INNER_KEY] !== OPTION_INNER_VALUE, 'please use chart.getOption()'); - } - var innerOpt = normalizeSetOptionInput(opts); - - this._optionManager.setOption(option, optionPreprocessorFuncs, innerOpt); - - this._resetOption(null, innerOpt); - }; - /** - * @param type null/undefined: reset all. - * 'recreate': force recreate all. - * 'timeline': only reset timeline option - * 'media': only reset media query option - * @return Whether option changed. - */ - - - GlobalModel.prototype.resetOption = function (type, opt) { - return this._resetOption(type, normalizeSetOptionInput(opt)); - }; - - GlobalModel.prototype._resetOption = function (type, opt) { - var optionChanged = false; - var optionManager = this._optionManager; - - if (!type || type === 'recreate') { - var baseOption = optionManager.mountOption(type === 'recreate'); - { - checkMissingComponents(baseOption); - } - - if (!this.option || type === 'recreate') { - initBase(this, baseOption); - } else { - this.restoreData(); - - this._mergeOption(baseOption, opt); - } - - optionChanged = true; - } - - if (type === 'timeline' || type === 'media') { - this.restoreData(); - } // By design, if `setOption(option2)` at the second time, and `option2` is a `ECUnitOption`, - // it should better not have the same props with `MediaUnit['option']`. - // Because either `option2` or `MediaUnit['option']` will be always merged to "current option" - // rather than original "baseOption". If they both override a prop, the result might be - // unexpected when media state changed after `setOption` called. - // If we really need to modify a props in each `MediaUnit['option']`, use the full version - // (`{baseOption, media}`) in `setOption`. - // For `timeline`, the case is the same. - - - if (!type || type === 'recreate' || type === 'timeline') { - var timelineOption = optionManager.getTimelineOption(this); - - if (timelineOption) { - optionChanged = true; - - this._mergeOption(timelineOption, opt); - } - } - - if (!type || type === 'recreate' || type === 'media') { - var mediaOptions = optionManager.getMediaOption(this); - - if (mediaOptions.length) { - each$4(mediaOptions, function (mediaOption) { - optionChanged = true; - - this._mergeOption(mediaOption, opt); - }, this); - } - } - - return optionChanged; - }; - - GlobalModel.prototype.mergeOption = function (option) { - this._mergeOption(option, null); - }; - - GlobalModel.prototype._mergeOption = function (newOption, opt) { - var option = this.option; - var componentsMap = this._componentsMap; - var componentsCount = this._componentsCount; - var newCmptTypes = []; - var newCmptTypeMap = createHashMap(); - var replaceMergeMainTypeMap = opt && opt.replaceMergeMainTypeMap; - resetSourceDefaulter(this); // If no component class, merge directly. - // For example: color, animaiton options, etc. - - each$4(newOption, function (componentOption, mainType) { - if (componentOption == null) { - return; - } - - if (!ComponentModel.hasClass(mainType)) { - // globalSettingTask.dirty(); - option[mainType] = option[mainType] == null ? clone$3(componentOption) : merge(option[mainType], componentOption, true); - } else if (mainType) { - newCmptTypes.push(mainType); - newCmptTypeMap.set(mainType, true); - } - }); - - if (replaceMergeMainTypeMap) { - // If there is a mainType `xxx` in `replaceMerge` but not declared in option, - // we trade it as it is declared in option as `{xxx: []}`. Because: - // (1) for normal merge, `{xxx: null/undefined}` are the same meaning as `{xxx: []}`. - // (2) some preprocessor may convert some of `{xxx: null/undefined}` to `{xxx: []}`. - replaceMergeMainTypeMap.each(function (val, mainTypeInReplaceMerge) { - if (ComponentModel.hasClass(mainTypeInReplaceMerge) && !newCmptTypeMap.get(mainTypeInReplaceMerge)) { - newCmptTypes.push(mainTypeInReplaceMerge); - newCmptTypeMap.set(mainTypeInReplaceMerge, true); - } - }); - } - - ComponentModel.topologicalTravel(newCmptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this); - - function visitComponent(mainType) { - var newCmptOptionList = concatInternalOptions(this, mainType, normalizeToArray(newOption[mainType])); - var oldCmptList = componentsMap.get(mainType); - var mergeMode = // `!oldCmptList` means init. See the comment in `mappingToExists` - !oldCmptList ? 'replaceAll' : replaceMergeMainTypeMap && replaceMergeMainTypeMap.get(mainType) ? 'replaceMerge' : 'normalMerge'; - var mappingResult = mappingToExists(oldCmptList, newCmptOptionList, mergeMode); // Set mainType and complete subType. - - setComponentTypeToKeyInfo(mappingResult, mainType, ComponentModel); // Empty it before the travel, in order to prevent `this._componentsMap` - // from being used in the `init`/`mergeOption`/`optionUpdated` of some - // components, which is probably incorrect logic. - - option[mainType] = null; - componentsMap.set(mainType, null); - componentsCount.set(mainType, 0); - var optionsByMainType = []; - var cmptsByMainType = []; - var cmptsCountByMainType = 0; - var tooltipExists; - var tooltipWarningLogged; - each$4(mappingResult, function (resultItem, index) { - var componentModel = resultItem.existing; - var newCmptOption = resultItem.newOption; - - if (!newCmptOption) { - if (componentModel) { - // Consider where is no new option and should be merged using {}, - // see removeEdgeAndAdd in topologicalTravel and - // ComponentModel.getAllClassMainTypes. - componentModel.mergeOption({}, this); - componentModel.optionUpdated({}, false); - } // If no both `resultItem.exist` and `resultItem.option`, - // either it is in `replaceMerge` and not matched by any id, - // or it has been removed in previous `replaceMerge` and left a "hole" in this component index. - - } else { - var isSeriesType = mainType === 'series'; - var ComponentModelClass = ComponentModel.getClass(mainType, resultItem.keyInfo.subType, !isSeriesType // Give a more detailed warn later if series don't exists - ); - - if (!ComponentModelClass) { - { - var subType = resultItem.keyInfo.subType; - var seriesImportName = BUILTIN_CHARTS_MAP[subType]; - - if (!componetsMissingLogPrinted[subType]) { - componetsMissingLogPrinted[subType] = true; - - if (seriesImportName) { - error("Series " + subType + " is used but not imported.\nimport { " + seriesImportName + " } from 'echarts/charts';\necharts.use([" + seriesImportName + "]);"); - } else { - error("Unknown series " + subType); - } - } - } - return; - } // TODO Before multiple tooltips get supported, we do this check to avoid unexpected exception. - - - if (mainType === 'tooltip') { - if (tooltipExists) { - { - if (!tooltipWarningLogged) { - warn('Currently only one tooltip component is allowed.'); - tooltipWarningLogged = true; - } - } - return; - } - - tooltipExists = true; - } - - if (componentModel && componentModel.constructor === ComponentModelClass) { - componentModel.name = resultItem.keyInfo.name; // componentModel.settingTask && componentModel.settingTask.dirty(); - - componentModel.mergeOption(newCmptOption, this); - componentModel.optionUpdated(newCmptOption, false); - } else { - // PENDING Global as parent ? - var extraOpt = extend({ - componentIndex: index - }, resultItem.keyInfo); - componentModel = new ComponentModelClass(newCmptOption, this, this, extraOpt); // Assign `keyInfo` - - extend(componentModel, extraOpt); - - if (resultItem.brandNew) { - componentModel.__requireNewView = true; - } - - componentModel.init(newCmptOption, this, this); // Call optionUpdated after init. - // newCmptOption has been used as componentModel.option - // and may be merged with theme and default, so pass null - // to avoid confusion. - - componentModel.optionUpdated(null, true); - } - } - - if (componentModel) { - optionsByMainType.push(componentModel.option); - cmptsByMainType.push(componentModel); - cmptsCountByMainType++; - } else { - // Always do assign to avoid elided item in array. - optionsByMainType.push(void 0); - cmptsByMainType.push(void 0); - } - }, this); - option[mainType] = optionsByMainType; - componentsMap.set(mainType, cmptsByMainType); - componentsCount.set(mainType, cmptsCountByMainType); // Backup series for filtering. - - if (mainType === 'series') { - reCreateSeriesIndices(this); - } - } // If no series declared, ensure `_seriesIndices` initialized. - - - if (!this._seriesIndices) { - reCreateSeriesIndices(this); - } - }; - /** - * Get option for output (cloned option and inner info removed) - */ - - - GlobalModel.prototype.getOption = function () { - var option = clone$3(this.option); - each$4(option, function (optInMainType, mainType) { - if (ComponentModel.hasClass(mainType)) { - var opts = normalizeToArray(optInMainType); // Inner cmpts need to be removed. - // Inner cmpts might not be at last since ec5.0, but still - // compatible for users: if inner cmpt at last, splice the returned array. - - var realLen = opts.length; - var metNonInner = false; - - for (var i = realLen - 1; i >= 0; i--) { - // Remove options with inner id. - if (opts[i] && !isComponentIdInternal(opts[i])) { - metNonInner = true; - } else { - opts[i] = null; - !metNonInner && realLen--; - } - } - - opts.length = realLen; - option[mainType] = opts; - } - }); - delete option[OPTION_INNER_KEY]; - return option; - }; - - GlobalModel.prototype.setTheme = function (theme) { - this._theme = new Model(theme); - - this._resetOption('recreate', null); - }; - - GlobalModel.prototype.getTheme = function () { - return this._theme; - }; - - GlobalModel.prototype.getLocaleModel = function () { - return this._locale; - }; - - GlobalModel.prototype.setUpdatePayload = function (payload) { - this._payload = payload; - }; - - GlobalModel.prototype.getUpdatePayload = function () { - return this._payload; - }; - /** - * @param idx If not specified, return the first one. - */ - - - GlobalModel.prototype.getComponent = function (mainType, idx) { - var list = this._componentsMap.get(mainType); - - if (list) { - var cmpt = list[idx || 0]; - - if (cmpt) { - return cmpt; - } else if (idx == null) { - for (var i = 0; i < list.length; i++) { - if (list[i]) { - return list[i]; - } - } - } - } - }; - /** - * @return Never be null/undefined. - */ - - - GlobalModel.prototype.queryComponents = function (condition) { - var mainType = condition.mainType; - - if (!mainType) { - return []; - } - - var index = condition.index; - var id = condition.id; - var name = condition.name; - - var cmpts = this._componentsMap.get(mainType); - - if (!cmpts || !cmpts.length) { - return []; - } - - var result; - - if (index != null) { - result = []; - each$4(normalizeToArray(index), function (idx) { - cmpts[idx] && result.push(cmpts[idx]); - }); - } else if (id != null) { - result = queryByIdOrName('id', id, cmpts); - } else if (name != null) { - result = queryByIdOrName('name', name, cmpts); - } else { - // Return all non-empty components in that mainType - result = filter(cmpts, function (cmpt) { - return !!cmpt; - }); - } - - return filterBySubType(result, condition); - }; - /** - * The interface is different from queryComponents, - * which is convenient for inner usage. - * - * @usage - * let result = findComponents( - * {mainType: 'dataZoom', query: {dataZoomId: 'abc'}} - * ); - * let result = findComponents( - * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}} - * ); - * let result = findComponents( - * {mainType: 'series', - * filter: function (model, index) {...}} - * ); - * // result like [component0, componnet1, ...] - */ - - - GlobalModel.prototype.findComponents = function (condition) { - var query = condition.query; - var mainType = condition.mainType; - var queryCond = getQueryCond(query); - var result = queryCond ? this.queryComponents(queryCond) // Retrieve all non-empty components. - : filter(this._componentsMap.get(mainType), function (cmpt) { - return !!cmpt; - }); - return doFilter(filterBySubType(result, condition)); - - function getQueryCond(q) { - var indexAttr = mainType + 'Index'; - var idAttr = mainType + 'Id'; - var nameAttr = mainType + 'Name'; - return q && (q[indexAttr] != null || q[idAttr] != null || q[nameAttr] != null) ? { - mainType: mainType, - // subType will be filtered finally. - index: q[indexAttr], - id: q[idAttr], - name: q[nameAttr] - } : null; - } - - function doFilter(res) { - return condition.filter ? filter(res, condition.filter) : res; - } - }; - - GlobalModel.prototype.eachComponent = function (mainType, cb, context) { - var componentsMap = this._componentsMap; - - if (isFunction(mainType)) { - var ctxForAll_1 = cb; - var cbForAll_1 = mainType; - componentsMap.each(function (cmpts, componentType) { - for (var i = 0; cmpts && i < cmpts.length; i++) { - var cmpt = cmpts[i]; - cmpt && cbForAll_1.call(ctxForAll_1, componentType, cmpt, cmpt.componentIndex); - } - }); - } else { - var cmpts = isString(mainType) ? componentsMap.get(mainType) : isObject$2(mainType) ? this.findComponents(mainType) : null; - - for (var i = 0; cmpts && i < cmpts.length; i++) { - var cmpt = cmpts[i]; - cmpt && cb.call(context, cmpt, cmpt.componentIndex); - } - } - }; - /** - * Get series list before filtered by name. - */ - - - GlobalModel.prototype.getSeriesByName = function (name) { - var nameStr = convertOptionIdName(name, null); - return filter(this._componentsMap.get('series'), function (oneSeries) { - return !!oneSeries && nameStr != null && oneSeries.name === nameStr; - }); - }; - /** - * Get series list before filtered by index. - */ - - - GlobalModel.prototype.getSeriesByIndex = function (seriesIndex) { - return this._componentsMap.get('series')[seriesIndex]; - }; - /** - * Get series list before filtered by type. - * FIXME: rename to getRawSeriesByType? - */ - - - GlobalModel.prototype.getSeriesByType = function (subType) { - return filter(this._componentsMap.get('series'), function (oneSeries) { - return !!oneSeries && oneSeries.subType === subType; - }); - }; - /** - * Get all series before filtered. - */ - - - GlobalModel.prototype.getSeries = function () { - return filter(this._componentsMap.get('series'), function (oneSeries) { - return !!oneSeries; - }); - }; - /** - * Count series before filtered. - */ - - - GlobalModel.prototype.getSeriesCount = function () { - return this._componentsCount.get('series'); - }; - /** - * After filtering, series may be different - * from raw series. - */ - - - GlobalModel.prototype.eachSeries = function (cb, context) { - assertSeriesInitialized(this); - each$4(this._seriesIndices, function (rawSeriesIndex) { - var series = this._componentsMap.get('series')[rawSeriesIndex]; - - cb.call(context, series, rawSeriesIndex); - }, this); - }; - /** - * Iterate raw series before filtered. - * - * @param {Function} cb - * @param {*} context - */ - - - GlobalModel.prototype.eachRawSeries = function (cb, context) { - each$4(this._componentsMap.get('series'), function (series) { - series && cb.call(context, series, series.componentIndex); - }); - }; - /** - * After filtering, series may be different. - * from raw series. - */ - - - GlobalModel.prototype.eachSeriesByType = function (subType, cb, context) { - assertSeriesInitialized(this); - each$4(this._seriesIndices, function (rawSeriesIndex) { - var series = this._componentsMap.get('series')[rawSeriesIndex]; - - if (series.subType === subType) { - cb.call(context, series, rawSeriesIndex); - } - }, this); - }; - /** - * Iterate raw series before filtered of given type. - */ - - - GlobalModel.prototype.eachRawSeriesByType = function (subType, cb, context) { - return each$4(this.getSeriesByType(subType), cb, context); - }; - - GlobalModel.prototype.isSeriesFiltered = function (seriesModel) { - assertSeriesInitialized(this); - return this._seriesIndicesMap.get(seriesModel.componentIndex) == null; - }; - - GlobalModel.prototype.getCurrentSeriesIndices = function () { - return (this._seriesIndices || []).slice(); - }; - - GlobalModel.prototype.filterSeries = function (cb, context) { - assertSeriesInitialized(this); - var newSeriesIndices = []; - each$4(this._seriesIndices, function (seriesRawIdx) { - var series = this._componentsMap.get('series')[seriesRawIdx]; - - cb.call(context, series, seriesRawIdx) && newSeriesIndices.push(seriesRawIdx); - }, this); - this._seriesIndices = newSeriesIndices; - this._seriesIndicesMap = createHashMap(newSeriesIndices); - }; - - GlobalModel.prototype.restoreData = function (payload) { - reCreateSeriesIndices(this); - var componentsMap = this._componentsMap; - var componentTypes = []; - componentsMap.each(function (components, componentType) { - if (ComponentModel.hasClass(componentType)) { - componentTypes.push(componentType); - } - }); - ComponentModel.topologicalTravel(componentTypes, ComponentModel.getAllClassMainTypes(), function (componentType) { - each$4(componentsMap.get(componentType), function (component) { - if (component && (componentType !== 'series' || !isNotTargetSeries(component, payload))) { - component.restoreData(); - } - }); - }); - }; - - GlobalModel.internalField = function () { - reCreateSeriesIndices = function (ecModel) { - var seriesIndices = ecModel._seriesIndices = []; - each$4(ecModel._componentsMap.get('series'), function (series) { - // series may have been removed by `replaceMerge`. - series && seriesIndices.push(series.componentIndex); - }); - ecModel._seriesIndicesMap = createHashMap(seriesIndices); - }; - - assertSeriesInitialized = function (ecModel) { - // Components that use _seriesIndices should depends on series component, - // which make sure that their initialization is after series. - { - if (!ecModel._seriesIndices) { - throw new Error('Option should contains series.'); - } - } - }; - - initBase = function (ecModel, baseOption) { - // Using OPTION_INNER_KEY to mark that this option cannot be used outside, - // i.e. `chart.setOption(chart.getModel().option);` is forbidden. - ecModel.option = {}; - ecModel.option[OPTION_INNER_KEY] = OPTION_INNER_VALUE; // Init with series: [], in case of calling findSeries method - // before series initialized. - - ecModel._componentsMap = createHashMap({ - series: [] - }); - ecModel._componentsCount = createHashMap(); // If user spefied `option.aria`, aria will be enable. This detection should be - // performed before theme and globalDefault merge. - - var airaOption = baseOption.aria; - - if (isObject$2(airaOption) && airaOption.enabled == null) { - airaOption.enabled = true; - } - - mergeTheme(baseOption, ecModel._theme.option); // TODO Needs clone when merging to the unexisted property - - merge(baseOption, globalDefault, false); - - ecModel._mergeOption(baseOption, null); - }; - }(); - - return GlobalModel; - }(Model); - - function isNotTargetSeries(seriesModel, payload) { - if (payload) { - var index = payload.seriesIndex; - var id = payload.seriesId; - var name_1 = payload.seriesName; - return index != null && seriesModel.componentIndex !== index || id != null && seriesModel.id !== id || name_1 != null && seriesModel.name !== name_1; - } - } - - function mergeTheme(option, theme) { - // PENDING - // NOT use `colorLayer` in theme if option has `color` - var notMergeColorLayer = option.color && !option.colorLayer; - each$4(theme, function (themeItem, name) { - if (name === 'colorLayer' && notMergeColorLayer || name === 'color' && option.color) { - return; - } // If it is component model mainType, the model handles that merge later. - // otherwise, merge them here. - - - if (!ComponentModel.hasClass(name)) { - if (typeof themeItem === 'object') { - option[name] = !option[name] ? clone$3(themeItem) : merge(option[name], themeItem, false); - } else { - if (option[name] == null) { - option[name] = themeItem; - } - } - } - }); - } - - function queryByIdOrName(attr, idOrName, cmpts) { - // Here is a break from echarts4: string and number are - // treated as equal. - if (isArray(idOrName)) { - var keyMap_1 = createHashMap(); - each$4(idOrName, function (idOrNameItem) { - if (idOrNameItem != null) { - var idName = convertOptionIdName(idOrNameItem, null); - idName != null && keyMap_1.set(idOrNameItem, true); - } - }); - return filter(cmpts, function (cmpt) { - return cmpt && keyMap_1.get(cmpt[attr]); - }); - } else { - var idName_1 = convertOptionIdName(idOrName, null); - return filter(cmpts, function (cmpt) { - return cmpt && idName_1 != null && cmpt[attr] === idName_1; - }); - } - } - - function filterBySubType(components, condition) { - // Using hasOwnProperty for restrict. Consider - // subType is undefined in user payload. - return condition.hasOwnProperty('subType') ? filter(components, function (cmpt) { - return cmpt && cmpt.subType === condition.subType; - }) : components; - } - - function normalizeSetOptionInput(opts) { - var replaceMergeMainTypeMap = createHashMap(); - opts && each$4(normalizeToArray(opts.replaceMerge), function (mainType) { - { - assert(ComponentModel.hasClass(mainType), '"' + mainType + '" is not valid component main type in "replaceMerge"'); - } - replaceMergeMainTypeMap.set(mainType, true); - }); - return { - replaceMergeMainTypeMap: replaceMergeMainTypeMap - }; - } - - mixin(GlobalModel, PaletteMixin); - var availableMethods = ['getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isSSR', 'isDisposed', 'on', 'off', 'getDataURL', 'getConnectedDataURL', // 'getModel', - 'getOption', // 'getViewOfComponentModel', - // 'getViewOfSeriesModel', - 'getId', 'updateLabelLayout']; - - var ExtensionAPI = - /** @class */ - function () { - function ExtensionAPI(ecInstance) { - each$4(availableMethods, function (methodName) { - this[methodName] = bind$1(ecInstance[methodName], ecInstance); - }, this); - } - - return ExtensionAPI; - }(); - - var QUERY_REG = /^(min|max)?(.+)$/; // Key: mainType - // type FakeComponentsMap = HashMap<(MappingExistingItem & { subType: string })[]>; - - /** - * TERM EXPLANATIONS: - * See `ECOption` and `ECUnitOption` in `src/util/types.ts`. - */ - - var OptionManager = - /** @class */ - function () { - // timeline.notMerge is not supported in ec3. Firstly there is rearly - // case that notMerge is needed. Secondly supporting 'notMerge' requires - // rawOption cloned and backuped when timeline changed, which does no - // good to performance. What's more, that both timeline and setOption - // method supply 'notMerge' brings complex and some problems. - // Consider this case: - // (step1) chart.setOption({timeline: {notMerge: false}, ...}, false); - // (step2) chart.setOption({timeline: {notMerge: true}, ...}, false); - function OptionManager(api) { - this._timelineOptions = []; - this._mediaList = []; - /** - * -1, means default. - * empty means no media. - */ - - this._currentMediaIndices = []; - this._api = api; - } - - OptionManager.prototype.setOption = function (rawOption, optionPreprocessorFuncs, opt) { - if (rawOption) { - // That set dat primitive is dangerous if user reuse the data when setOption again. - each$4(normalizeToArray(rawOption.series), function (series) { - series && series.data && isTypedArray(series.data) && setAsPrimitive(series.data); - }); - each$4(normalizeToArray(rawOption.dataset), function (dataset) { - dataset && dataset.source && isTypedArray(dataset.source) && setAsPrimitive(dataset.source); - }); - } // Caution: some series modify option data, if do not clone, - // it should ensure that the repeat modify correctly - // (create a new object when modify itself). - - - rawOption = clone$3(rawOption); // FIXME - // If some property is set in timeline options or media option but - // not set in baseOption, a warning should be given. - - var optionBackup = this._optionBackup; - var newParsedOption = parseRawOption(rawOption, optionPreprocessorFuncs, !optionBackup); - this._newBaseOption = newParsedOption.baseOption; // For setOption at second time (using merge mode); - - if (optionBackup) { - // FIXME - // the restore merge solution is essentially incorrect. - // the mapping can not be 100% consistent with ecModel, which probably brings - // potential bug! - // The first merge is delayed, because in most cases, users do not call `setOption` twice. - // let fakeCmptsMap = this._fakeCmptsMap; - // if (!fakeCmptsMap) { - // fakeCmptsMap = this._fakeCmptsMap = createHashMap(); - // mergeToBackupOption(fakeCmptsMap, null, optionBackup.baseOption, null); - // } - // mergeToBackupOption( - // fakeCmptsMap, optionBackup.baseOption, newParsedOption.baseOption, opt - // ); - // For simplicity, timeline options and media options do not support merge, - // that is, if you `setOption` twice and both has timeline options, the latter - // timeline options will not be merged to the former, but just substitute them. - if (newParsedOption.timelineOptions.length) { - optionBackup.timelineOptions = newParsedOption.timelineOptions; - } - - if (newParsedOption.mediaList.length) { - optionBackup.mediaList = newParsedOption.mediaList; - } - - if (newParsedOption.mediaDefault) { - optionBackup.mediaDefault = newParsedOption.mediaDefault; - } - } else { - this._optionBackup = newParsedOption; - } - }; - - OptionManager.prototype.mountOption = function (isRecreate) { - var optionBackup = this._optionBackup; - this._timelineOptions = optionBackup.timelineOptions; - this._mediaList = optionBackup.mediaList; - this._mediaDefault = optionBackup.mediaDefault; - this._currentMediaIndices = []; - return clone$3(isRecreate // this._optionBackup.baseOption, which is created at the first `setOption` - // called, and is merged into every new option by inner method `mergeToBackupOption` - // each time `setOption` called, can be only used in `isRecreate`, because - // its reliability is under suspicion. In other cases option merge is - // performed by `model.mergeOption`. - ? optionBackup.baseOption : this._newBaseOption); - }; - - OptionManager.prototype.getTimelineOption = function (ecModel) { - var option; - var timelineOptions = this._timelineOptions; - - if (timelineOptions.length) { - // getTimelineOption can only be called after ecModel inited, - // so we can get currentIndex from timelineModel. - var timelineModel = ecModel.getComponent('timeline'); - - if (timelineModel) { - option = clone$3( // FIXME:TS as TimelineModel or quivlant interface - timelineOptions[timelineModel.getCurrentIndex()]); - } - } - - return option; - }; - - OptionManager.prototype.getMediaOption = function (ecModel) { - var ecWidth = this._api.getWidth(); - - var ecHeight = this._api.getHeight(); - - var mediaList = this._mediaList; - var mediaDefault = this._mediaDefault; - var indices = []; - var result = []; // No media defined. - - if (!mediaList.length && !mediaDefault) { - return result; - } // Multi media may be applied, the latter defined media has higher priority. - - - for (var i = 0, len = mediaList.length; i < len; i++) { - if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) { - indices.push(i); - } - } // FIXME - // Whether mediaDefault should force users to provide? Otherwise - // the change by media query can not be recorvered. - - - if (!indices.length && mediaDefault) { - indices = [-1]; - } - - if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) { - result = map$1(indices, function (index) { - return clone$3(index === -1 ? mediaDefault.option : mediaList[index].option); - }); - } // Otherwise return nothing. - - - this._currentMediaIndices = indices; - return result; - }; - - return OptionManager; - }(); - /** - * [RAW_OPTION_PATTERNS] - * (Note: "series: []" represents all other props in `ECUnitOption`) - * - * (1) No prop "baseOption" declared: - * Root option is used as "baseOption" (except prop "options" and "media"). - * ```js - * option = { - * series: [], - * timeline: {}, - * options: [], - * }; - * option = { - * series: [], - * media: {}, - * }; - * option = { - * series: [], - * timeline: {}, - * options: [], - * media: {}, - * } - * ``` - * - * (2) Prop "baseOption" declared: - * If "baseOption" declared, `ECUnitOption` props can only be declared - * inside "baseOption" except prop "timeline" (compat ec2). - * ```js - * option = { - * baseOption: { - * timeline: {}, - * series: [], - * }, - * options: [] - * }; - * option = { - * baseOption: { - * series: [], - * }, - * media: [] - * }; - * option = { - * baseOption: { - * timeline: {}, - * series: [], - * }, - * options: [] - * media: [] - * }; - * option = { - * // ec3 compat ec2: allow (only) `timeline` declared - * // outside baseOption. Keep this setting for compat. - * timeline: {}, - * baseOption: { - * series: [], - * }, - * options: [], - * media: [] - * }; - * ``` - */ - - - function parseRawOption( // `rawOption` May be modified - rawOption, optionPreprocessorFuncs, isNew) { - var mediaList = []; - var mediaDefault; - var baseOption; - var declaredBaseOption = rawOption.baseOption; // Compatible with ec2, [RAW_OPTION_PATTERNS] above. - - var timelineOnRoot = rawOption.timeline; - var timelineOptionsOnRoot = rawOption.options; - var mediaOnRoot = rawOption.media; - var hasMedia = !!rawOption.media; - var hasTimeline = !!(timelineOptionsOnRoot || timelineOnRoot || declaredBaseOption && declaredBaseOption.timeline); - - if (declaredBaseOption) { - baseOption = declaredBaseOption; // For merge option. - - if (!baseOption.timeline) { - baseOption.timeline = timelineOnRoot; - } - } // For convenience, enable to use the root option as the `baseOption`: - // `{ ...normalOptionProps, media: [{ ... }, { ... }] }` - else { - if (hasTimeline || hasMedia) { - rawOption.options = rawOption.media = null; - } - - baseOption = rawOption; - } - - if (hasMedia) { - if (isArray(mediaOnRoot)) { - each$4(mediaOnRoot, function (singleMedia) { - { - // Real case of wrong config. - if (singleMedia && !singleMedia.option && isObject$2(singleMedia.query) && isObject$2(singleMedia.query.option)) { - error('Illegal media option. Must be like { media: [ { query: {}, option: {} } ] }'); - } - } - - if (singleMedia && singleMedia.option) { - if (singleMedia.query) { - mediaList.push(singleMedia); - } else if (!mediaDefault) { - // Use the first media default. - mediaDefault = singleMedia; - } - } - }); - } else { - { - // Real case of wrong config. - error('Illegal media option. Must be an array. Like { media: [ {...}, {...} ] }'); - } - } - } - - doPreprocess(baseOption); - each$4(timelineOptionsOnRoot, function (option) { - return doPreprocess(option); - }); - each$4(mediaList, function (media) { - return doPreprocess(media.option); - }); - - function doPreprocess(option) { - each$4(optionPreprocessorFuncs, function (preProcess) { - preProcess(option, isNew); - }); - } - - return { - baseOption: baseOption, - timelineOptions: timelineOptionsOnRoot || [], - mediaDefault: mediaDefault, - mediaList: mediaList - }; - } - /** - * @see - * Support: width, height, aspectRatio - * Can use max or min as prefix. - */ - - - function applyMediaQuery(query, ecWidth, ecHeight) { - var realMap = { - width: ecWidth, - height: ecHeight, - aspectratio: ecWidth / ecHeight // lower case for convenience. - - }; - var applicable = true; - each$4(query, function (value, attr) { - var matched = attr.match(QUERY_REG); - - if (!matched || !matched[1] || !matched[2]) { - return; - } - - var operator = matched[1]; - var realAttr = matched[2].toLowerCase(); - - if (!compare(realMap[realAttr], value, operator)) { - applicable = false; - } - }); - return applicable; - } - - function compare(real, expect, operator) { - if (operator === 'min') { - return real >= expect; - } else if (operator === 'max') { - return real <= expect; - } else { - // Equals - return real === expect; - } - } - - function indicesEquals(indices1, indices2) { - // indices is always order by asc and has only finite number. - return indices1.join(',') === indices2.join(','); - } - - var each$2 = each$4; - var isObject$1 = isObject$2; - var POSSIBLE_STYLES = ['areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle', 'chordStyle', 'label', 'labelLine']; - - function compatEC2ItemStyle(opt) { - var itemStyleOpt = opt && opt.itemStyle; - - if (!itemStyleOpt) { - return; - } - - for (var i = 0, len = POSSIBLE_STYLES.length; i < len; i++) { - var styleName = POSSIBLE_STYLES[i]; - var normalItemStyleOpt = itemStyleOpt.normal; - var emphasisItemStyleOpt = itemStyleOpt.emphasis; - - if (normalItemStyleOpt && normalItemStyleOpt[styleName]) { - { - deprecateReplaceLog("itemStyle.normal." + styleName, styleName); - } - opt[styleName] = opt[styleName] || {}; - - if (!opt[styleName].normal) { - opt[styleName].normal = normalItemStyleOpt[styleName]; - } else { - merge(opt[styleName].normal, normalItemStyleOpt[styleName]); - } - - normalItemStyleOpt[styleName] = null; - } - - if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) { - { - deprecateReplaceLog("itemStyle.emphasis." + styleName, "emphasis." + styleName); - } - opt[styleName] = opt[styleName] || {}; - - if (!opt[styleName].emphasis) { - opt[styleName].emphasis = emphasisItemStyleOpt[styleName]; - } else { - merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]); - } - - emphasisItemStyleOpt[styleName] = null; - } - } - } - - function convertNormalEmphasis(opt, optType, useExtend) { - if (opt && opt[optType] && (opt[optType].normal || opt[optType].emphasis)) { - var normalOpt = opt[optType].normal; - var emphasisOpt = opt[optType].emphasis; - - if (normalOpt) { - { - // eslint-disable-next-line max-len - deprecateLog("'normal' hierarchy in " + optType + " has been removed since 4.0. All style properties are configured in " + optType + " directly now."); - } // Timeline controlStyle has other properties besides normal and emphasis - - if (useExtend) { - opt[optType].normal = opt[optType].emphasis = null; - defaults(opt[optType], normalOpt); - } else { - opt[optType] = normalOpt; - } - } - - if (emphasisOpt) { - { - deprecateLog(optType + ".emphasis has been changed to emphasis." + optType + " since 4.0"); - } - opt.emphasis = opt.emphasis || {}; - opt.emphasis[optType] = emphasisOpt; // Also compat the case user mix the style and focus together in ec3 style - // for example: { itemStyle: { normal: {}, emphasis: {focus, shadowBlur} } } - - if (emphasisOpt.focus) { - opt.emphasis.focus = emphasisOpt.focus; - } - - if (emphasisOpt.blurScope) { - opt.emphasis.blurScope = emphasisOpt.blurScope; - } - } - } - } - - function removeEC3NormalStatus(opt) { - convertNormalEmphasis(opt, 'itemStyle'); - convertNormalEmphasis(opt, 'lineStyle'); - convertNormalEmphasis(opt, 'areaStyle'); - convertNormalEmphasis(opt, 'label'); - convertNormalEmphasis(opt, 'labelLine'); // treemap - - convertNormalEmphasis(opt, 'upperLabel'); // graph - - convertNormalEmphasis(opt, 'edgeLabel'); - } - - function compatTextStyle(opt, propName) { - // Check whether is not object (string\null\undefined ...) - var labelOptSingle = isObject$1(opt) && opt[propName]; - var textStyle = isObject$1(labelOptSingle) && labelOptSingle.textStyle; - - if (textStyle) { - { - // eslint-disable-next-line max-len - deprecateLog("textStyle hierarchy in " + propName + " has been removed since 4.0. All textStyle properties are configured in " + propName + " directly now."); - } - - for (var i = 0, len = TEXT_STYLE_OPTIONS.length; i < len; i++) { - var textPropName = TEXT_STYLE_OPTIONS[i]; - - if (textStyle.hasOwnProperty(textPropName)) { - labelOptSingle[textPropName] = textStyle[textPropName]; - } - } - } - } - - function compatEC3CommonStyles(opt) { - if (opt) { - removeEC3NormalStatus(opt); - compatTextStyle(opt, 'label'); - opt.emphasis && compatTextStyle(opt.emphasis, 'label'); - } - } - - function processSeries(seriesOpt) { - if (!isObject$1(seriesOpt)) { - return; - } - - compatEC2ItemStyle(seriesOpt); - removeEC3NormalStatus(seriesOpt); - compatTextStyle(seriesOpt, 'label'); // treemap - - compatTextStyle(seriesOpt, 'upperLabel'); // graph - - compatTextStyle(seriesOpt, 'edgeLabel'); - - if (seriesOpt.emphasis) { - compatTextStyle(seriesOpt.emphasis, 'label'); // treemap - - compatTextStyle(seriesOpt.emphasis, 'upperLabel'); // graph - - compatTextStyle(seriesOpt.emphasis, 'edgeLabel'); - } - - var markPoint = seriesOpt.markPoint; - - if (markPoint) { - compatEC2ItemStyle(markPoint); - compatEC3CommonStyles(markPoint); - } - - var markLine = seriesOpt.markLine; - - if (markLine) { - compatEC2ItemStyle(markLine); - compatEC3CommonStyles(markLine); - } - - var markArea = seriesOpt.markArea; - - if (markArea) { - compatEC3CommonStyles(markArea); - } - - var data = seriesOpt.data; // Break with ec3: if `setOption` again, there may be no `type` in option, - // then the backward compat based on option type will not be performed. - - if (seriesOpt.type === 'graph') { - data = data || seriesOpt.nodes; - var edgeData = seriesOpt.links || seriesOpt.edges; - - if (edgeData && !isTypedArray(edgeData)) { - for (var i = 0; i < edgeData.length; i++) { - compatEC3CommonStyles(edgeData[i]); - } - } - - each$4(seriesOpt.categories, function (opt) { - removeEC3NormalStatus(opt); - }); - } - - if (data && !isTypedArray(data)) { - for (var i = 0; i < data.length; i++) { - compatEC3CommonStyles(data[i]); - } - } // mark point data - - - markPoint = seriesOpt.markPoint; - - if (markPoint && markPoint.data) { - var mpData = markPoint.data; - - for (var i = 0; i < mpData.length; i++) { - compatEC3CommonStyles(mpData[i]); - } - } // mark line data - - - markLine = seriesOpt.markLine; - - if (markLine && markLine.data) { - var mlData = markLine.data; - - for (var i = 0; i < mlData.length; i++) { - if (isArray(mlData[i])) { - compatEC3CommonStyles(mlData[i][0]); - compatEC3CommonStyles(mlData[i][1]); - } else { - compatEC3CommonStyles(mlData[i]); - } - } - } // Series - - - if (seriesOpt.type === 'gauge') { - compatTextStyle(seriesOpt, 'axisLabel'); - compatTextStyle(seriesOpt, 'title'); - compatTextStyle(seriesOpt, 'detail'); - } else if (seriesOpt.type === 'treemap') { - convertNormalEmphasis(seriesOpt.breadcrumb, 'itemStyle'); - each$4(seriesOpt.levels, function (opt) { - removeEC3NormalStatus(opt); - }); - } else if (seriesOpt.type === 'tree') { - removeEC3NormalStatus(seriesOpt.leaves); - } // sunburst starts from ec4, so it does not need to compat levels. - - } - - function toArr(o) { - return isArray(o) ? o : o ? [o] : []; - } - - function toObj(o) { - return (isArray(o) ? o[0] : o) || {}; - } - - function globalCompatStyle(option, isTheme) { - each$2(toArr(option.series), function (seriesOpt) { - isObject$1(seriesOpt) && processSeries(seriesOpt); - }); - var axes = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'parallelAxis', 'radar']; - isTheme && axes.push('valueAxis', 'categoryAxis', 'logAxis', 'timeAxis'); - each$2(axes, function (axisName) { - each$2(toArr(option[axisName]), function (axisOpt) { - if (axisOpt) { - compatTextStyle(axisOpt, 'axisLabel'); - compatTextStyle(axisOpt.axisPointer, 'label'); - } - }); - }); - each$2(toArr(option.parallel), function (parallelOpt) { - var parallelAxisDefault = parallelOpt && parallelOpt.parallelAxisDefault; - compatTextStyle(parallelAxisDefault, 'axisLabel'); - compatTextStyle(parallelAxisDefault && parallelAxisDefault.axisPointer, 'label'); - }); - each$2(toArr(option.calendar), function (calendarOpt) { - convertNormalEmphasis(calendarOpt, 'itemStyle'); - compatTextStyle(calendarOpt, 'dayLabel'); - compatTextStyle(calendarOpt, 'monthLabel'); - compatTextStyle(calendarOpt, 'yearLabel'); - }); // radar.name.textStyle - - each$2(toArr(option.radar), function (radarOpt) { - compatTextStyle(radarOpt, 'name'); // Use axisName instead of name because component has name property - - if (radarOpt.name && radarOpt.axisName == null) { - radarOpt.axisName = radarOpt.name; - delete radarOpt.name; - { - deprecateLog('name property in radar component has been changed to axisName'); - } - } - - if (radarOpt.nameGap != null && radarOpt.axisNameGap == null) { - radarOpt.axisNameGap = radarOpt.nameGap; - delete radarOpt.nameGap; - { - deprecateLog('nameGap property in radar component has been changed to axisNameGap'); - } - } - - { - each$2(radarOpt.indicator, function (indicatorOpt) { - if (indicatorOpt.text) { - deprecateReplaceLog('text', 'name', 'radar.indicator'); - } - }); - } - }); - each$2(toArr(option.geo), function (geoOpt) { - if (isObject$1(geoOpt)) { - compatEC3CommonStyles(geoOpt); - each$2(toArr(geoOpt.regions), function (regionObj) { - compatEC3CommonStyles(regionObj); - }); - } - }); - each$2(toArr(option.timeline), function (timelineOpt) { - compatEC3CommonStyles(timelineOpt); - convertNormalEmphasis(timelineOpt, 'label'); - convertNormalEmphasis(timelineOpt, 'itemStyle'); - convertNormalEmphasis(timelineOpt, 'controlStyle', true); - var data = timelineOpt.data; - isArray(data) && each$4(data, function (item) { - if (isObject$2(item)) { - convertNormalEmphasis(item, 'label'); - convertNormalEmphasis(item, 'itemStyle'); - } - }); - }); - each$2(toArr(option.toolbox), function (toolboxOpt) { - convertNormalEmphasis(toolboxOpt, 'iconStyle'); - each$2(toolboxOpt.feature, function (featureOpt) { - convertNormalEmphasis(featureOpt, 'iconStyle'); - }); - }); - compatTextStyle(toObj(option.axisPointer), 'label'); - compatTextStyle(toObj(option.tooltip).axisPointer, 'label'); // Clean logs - // storedLogs = {}; - } - - function get(opt, path) { - var pathArr = path.split(','); - var obj = opt; - - for (var i = 0; i < pathArr.length; i++) { - obj = obj && obj[pathArr[i]]; - - if (obj == null) { - break; - } - } - - return obj; - } - - function set(opt, path, val, overwrite) { - var pathArr = path.split(','); - var obj = opt; - var key; - var i = 0; - - for (; i < pathArr.length - 1; i++) { - key = pathArr[i]; - - if (obj[key] == null) { - obj[key] = {}; - } - - obj = obj[key]; - } - - if (overwrite || obj[pathArr[i]] == null) { - obj[pathArr[i]] = val; - } - } - - function compatLayoutProperties(option) { - option && each$4(LAYOUT_PROPERTIES, function (prop) { - if (prop[0] in option && !(prop[1] in option)) { - option[prop[1]] = option[prop[0]]; - } - }); - } - - var LAYOUT_PROPERTIES = [['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']]; - var COMPATITABLE_COMPONENTS = ['grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline']; - var BAR_ITEM_STYLE_MAP = [['borderRadius', 'barBorderRadius'], ['borderColor', 'barBorderColor'], ['borderWidth', 'barBorderWidth']]; - - function compatBarItemStyle(option) { - var itemStyle = option && option.itemStyle; - - if (itemStyle) { - for (var i = 0; i < BAR_ITEM_STYLE_MAP.length; i++) { - var oldName = BAR_ITEM_STYLE_MAP[i][1]; - var newName = BAR_ITEM_STYLE_MAP[i][0]; - - if (itemStyle[oldName] != null) { - itemStyle[newName] = itemStyle[oldName]; - { - deprecateReplaceLog(oldName, newName); - } - } - } - } - } - - function compatPieLabel(option) { - if (!option) { - return; - } - - if (option.alignTo === 'edge' && option.margin != null && option.edgeDistance == null) { - { - deprecateReplaceLog('label.margin', 'label.edgeDistance', 'pie'); - } - option.edgeDistance = option.margin; - } - } - - function compatSunburstState(option) { - if (!option) { - return; - } - - if (option.downplay && !option.blur) { - option.blur = option.downplay; - { - deprecateReplaceLog('downplay', 'blur', 'sunburst'); - } - } - } - - function compatGraphFocus(option) { - if (!option) { - return; - } - - if (option.focusNodeAdjacency != null) { - option.emphasis = option.emphasis || {}; - - if (option.emphasis.focus == null) { - { - deprecateReplaceLog('focusNodeAdjacency', 'emphasis: { focus: \'adjacency\'}', 'graph/sankey'); - } - option.emphasis.focus = 'adjacency'; - } - } - } - - function traverseTree(data, cb) { - if (data) { - for (var i = 0; i < data.length; i++) { - cb(data[i]); - data[i] && traverseTree(data[i].children, cb); - } - } - } - - function globalBackwardCompat(option, isTheme) { - globalCompatStyle(option, isTheme); // Make sure series array for model initialization. - - option.series = normalizeToArray(option.series); - each$4(option.series, function (seriesOpt) { - if (!isObject$2(seriesOpt)) { - return; - } - - var seriesType = seriesOpt.type; - - if (seriesType === 'line') { - if (seriesOpt.clipOverflow != null) { - seriesOpt.clip = seriesOpt.clipOverflow; - { - deprecateReplaceLog('clipOverflow', 'clip', 'line'); - } - } - } else if (seriesType === 'pie' || seriesType === 'gauge') { - if (seriesOpt.clockWise != null) { - seriesOpt.clockwise = seriesOpt.clockWise; - { - deprecateReplaceLog('clockWise', 'clockwise'); - } - } - - compatPieLabel(seriesOpt.label); - var data = seriesOpt.data; - - if (data && !isTypedArray(data)) { - for (var i = 0; i < data.length; i++) { - compatPieLabel(data[i]); - } - } - - if (seriesOpt.hoverOffset != null) { - seriesOpt.emphasis = seriesOpt.emphasis || {}; - - if (seriesOpt.emphasis.scaleSize = null) { - { - deprecateReplaceLog('hoverOffset', 'emphasis.scaleSize'); - } - seriesOpt.emphasis.scaleSize = seriesOpt.hoverOffset; - } - } - } else if (seriesType === 'gauge') { - var pointerColor = get(seriesOpt, 'pointer.color'); - pointerColor != null && set(seriesOpt, 'itemStyle.color', pointerColor); - } else if (seriesType === 'bar') { - compatBarItemStyle(seriesOpt); - compatBarItemStyle(seriesOpt.backgroundStyle); - compatBarItemStyle(seriesOpt.emphasis); - var data = seriesOpt.data; - - if (data && !isTypedArray(data)) { - for (var i = 0; i < data.length; i++) { - if (typeof data[i] === 'object') { - compatBarItemStyle(data[i]); - compatBarItemStyle(data[i] && data[i].emphasis); - } - } - } - } else if (seriesType === 'sunburst') { - var highlightPolicy = seriesOpt.highlightPolicy; - - if (highlightPolicy) { - seriesOpt.emphasis = seriesOpt.emphasis || {}; - - if (!seriesOpt.emphasis.focus) { - seriesOpt.emphasis.focus = highlightPolicy; - { - deprecateReplaceLog('highlightPolicy', 'emphasis.focus', 'sunburst'); - } - } - } - - compatSunburstState(seriesOpt); - traverseTree(seriesOpt.data, compatSunburstState); - } else if (seriesType === 'graph' || seriesType === 'sankey') { - compatGraphFocus(seriesOpt); // TODO nodes, edges? - } else if (seriesType === 'map') { - if (seriesOpt.mapType && !seriesOpt.map) { - { - deprecateReplaceLog('mapType', 'map', 'map'); - } - seriesOpt.map = seriesOpt.mapType; - } - - if (seriesOpt.mapLocation) { - { - deprecateLog('`mapLocation` is not used anymore.'); - } - defaults(seriesOpt, seriesOpt.mapLocation); - } - } - - if (seriesOpt.hoverAnimation != null) { - seriesOpt.emphasis = seriesOpt.emphasis || {}; - - if (seriesOpt.emphasis && seriesOpt.emphasis.scale == null) { - { - deprecateReplaceLog('hoverAnimation', 'emphasis.scale'); - } - seriesOpt.emphasis.scale = seriesOpt.hoverAnimation; - } - } - - compatLayoutProperties(seriesOpt); - }); // dataRange has changed to visualMap - - if (option.dataRange) { - option.visualMap = option.dataRange; - } - - each$4(COMPATITABLE_COMPONENTS, function (componentName) { - var options = option[componentName]; - - if (options) { - if (!isArray(options)) { - options = [options]; - } - - each$4(options, function (option) { - compatLayoutProperties(option); - }); - } - }); - } // (1) [Caution]: the logic is correct based on the premises: - // data processing stage is blocked in stream. - // See - // (2) Only register once when import repeatedly. - // Should be executed after series is filtered and before stack calculation. - - - function dataStack$1(ecModel) { - var stackInfoMap = createHashMap(); - ecModel.eachSeries(function (seriesModel) { - var stack = seriesModel.get('stack'); // Compatible: when `stack` is set as '', do not stack. - - if (stack) { - var stackInfoList = stackInfoMap.get(stack) || stackInfoMap.set(stack, []); - var data = seriesModel.getData(); - var stackInfo = { - // Used for calculate axis extent automatically. - // TODO: Type getCalculationInfo return more specific type? - stackResultDimension: data.getCalculationInfo('stackResultDimension'), - stackedOverDimension: data.getCalculationInfo('stackedOverDimension'), - stackedDimension: data.getCalculationInfo('stackedDimension'), - stackedByDimension: data.getCalculationInfo('stackedByDimension'), - isStackedByIndex: data.getCalculationInfo('isStackedByIndex'), - data: data, - seriesModel: seriesModel - }; // If stacked on axis that do not support data stack. - - if (!stackInfo.stackedDimension || !(stackInfo.isStackedByIndex || stackInfo.stackedByDimension)) { - return; - } - - stackInfoList.push(stackInfo); - } - }); // Process each stack group - - stackInfoMap.each(function (stackInfoList) { - if (stackInfoList.length === 0) { - return; - } // Check if stack order needs to be reversed - - - var firstSeries = stackInfoList[0].seriesModel; - var stackOrder = firstSeries.get('stackOrder') || 'seriesAsc'; - - if (stackOrder === 'seriesDesc') { - stackInfoList.reverse(); - } // Set stackedOnSeries for each series in the final order - - - each$4(stackInfoList, function (stackInfo, index) { - stackInfo.data.setCalculationInfo('stackedOnSeries', index > 0 ? stackInfoList[index - 1].seriesModel : null); - }); // Calculate stack values - - calculateStack(stackInfoList); - }); - } - - function calculateStack(stackInfoList) { - each$4(stackInfoList, function (targetStackInfo, idxInStack) { - var resultVal = []; - var resultNaN = [NaN, NaN]; - var dims = [targetStackInfo.stackResultDimension, targetStackInfo.stackedOverDimension]; - var targetData = targetStackInfo.data; - var isStackedByIndex = targetStackInfo.isStackedByIndex; - var stackStrategy = targetStackInfo.seriesModel.get('stackStrategy') || 'samesign'; // Should not write on raw data, because stack series model list changes - // depending on legend selection. - - targetData.modify(dims, function (v0, v1, dataIndex) { - var sum = targetData.get(targetStackInfo.stackedDimension, dataIndex); // Consider `connectNulls` of line area, if value is NaN, stackedOver - // should also be NaN, to draw a appropriate belt area. - - if (isNaN(sum)) { - return resultNaN; - } - - var byValue; - var stackedDataRawIndex; - - if (isStackedByIndex) { - stackedDataRawIndex = targetData.getRawIndex(dataIndex); - } else { - byValue = targetData.get(targetStackInfo.stackedByDimension, dataIndex); - } // If stackOver is NaN, chart view will render point on value start. - - - var stackedOver = NaN; - - for (var j = idxInStack - 1; j >= 0; j--) { - var stackInfo = stackInfoList[j]; // Has been optimized by inverted indices on `stackedByDimension`. - - if (!isStackedByIndex) { - stackedDataRawIndex = stackInfo.data.rawIndexOf(stackInfo.stackedByDimension, byValue); - } - - if (stackedDataRawIndex >= 0) { - var val = stackInfo.data.getByRawIndex(stackInfo.stackResultDimension, stackedDataRawIndex); // Considering positive stack, negative stack and empty data - - if (stackStrategy === 'all' // single stack group - || stackStrategy === 'positive' && val > 0 || stackStrategy === 'negative' && val < 0 || stackStrategy === 'samesign' && sum >= 0 && val > 0 // All positive stack - || stackStrategy === 'samesign' && sum <= 0 && val < 0 // All negative stack - ) { - // The sum has to be very small to be affected by the - // floating arithmetic problem. An incorrect result will probably - // cause axis min/max to be filtered incorrectly. - sum = addSafe(sum, val); - stackedOver = val; - break; - } - } - } - - resultVal[0] = sum; - resultVal[1] = stackedOver; - return resultVal; - }); - }); - } // @inner - - - var SourceImpl = - /** @class */ - function () { - function SourceImpl(fields) { - this.data = fields.data || (fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []); - this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN; // Visit config - - this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN; - this.startIndex = fields.startIndex || 0; - this.dimensionsDetectedCount = fields.dimensionsDetectedCount; - this.metaRawOption = fields.metaRawOption; - var dimensionsDefine = this.dimensionsDefine = fields.dimensionsDefine; - - if (dimensionsDefine) { - for (var i = 0; i < dimensionsDefine.length; i++) { - var dim = dimensionsDefine[i]; - - if (dim.type == null) { - if (guessOrdinal(this, i) === BE_ORDINAL.Must) { - dim.type = 'ordinal'; - } - } - } - } - } - - return SourceImpl; - }(); - - function isSourceInstance(val) { - return val instanceof SourceImpl; - } - /** - * Create a source from option. - * NOTE: Created source is immutable. Don't change any properties in it. - */ - - - function createSource(sourceData, thisMetaRawOption, // can be null. If not provided, auto detect it from `sourceData`. - sourceFormat) { - sourceFormat = sourceFormat || detectSourceFormat(sourceData); - var seriesLayoutBy = thisMetaRawOption.seriesLayoutBy; - var determined = determineSourceDimensions(sourceData, sourceFormat, seriesLayoutBy, thisMetaRawOption.sourceHeader, thisMetaRawOption.dimensions); - var source = new SourceImpl({ - data: sourceData, - sourceFormat: sourceFormat, - seriesLayoutBy: seriesLayoutBy, - dimensionsDefine: determined.dimensionsDefine, - startIndex: determined.startIndex, - dimensionsDetectedCount: determined.dimensionsDetectedCount, - metaRawOption: clone$3(thisMetaRawOption) - }); - return source; - } - /** - * Wrap original series data for some compatibility cases. - */ - - - function createSourceFromSeriesDataOption(data) { - return new SourceImpl({ - data: data, - sourceFormat: isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL - }); - } - /** - * Clone source but excludes source data. - */ - - - function cloneSourceShallow(source) { - return new SourceImpl({ - data: source.data, - sourceFormat: source.sourceFormat, - seriesLayoutBy: source.seriesLayoutBy, - dimensionsDefine: clone$3(source.dimensionsDefine), - startIndex: source.startIndex, - dimensionsDetectedCount: source.dimensionsDetectedCount - }); - } - /** - * Note: An empty array will be detected as `SOURCE_FORMAT_ARRAY_ROWS`. - */ - - - function detectSourceFormat(data) { - var sourceFormat = SOURCE_FORMAT_UNKNOWN; - - if (isTypedArray(data)) { - sourceFormat = SOURCE_FORMAT_TYPED_ARRAY; - } else if (isArray(data)) { - // FIXME Whether tolerate null in top level array? - if (data.length === 0) { - sourceFormat = SOURCE_FORMAT_ARRAY_ROWS; - } - - for (var i = 0, len = data.length; i < len; i++) { - var item = data[i]; - - if (item == null) { - continue; - } else if (isArray(item) || isTypedArray(item)) { - sourceFormat = SOURCE_FORMAT_ARRAY_ROWS; - break; - } else if (isObject$2(item)) { - sourceFormat = SOURCE_FORMAT_OBJECT_ROWS; - break; - } - } - } else if (isObject$2(data)) { - for (var key in data) { - if (hasOwn(data, key) && isArrayLike(data[key])) { - sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS; - break; - } - } - } - - return sourceFormat; - } - /** - * Determine the source definitions from data standalone dimensions definitions - * are not specified. - */ - - - function determineSourceDimensions(data, sourceFormat, seriesLayoutBy, sourceHeader, // standalone raw dimensions definition, like: - // { - // dimensions: ['aa', 'bb', { name: 'cc', type: 'time' }] - // } - // in `dataset` or `series` - dimensionsDefine) { - var dimensionsDetectedCount; - var startIndex; // PENDING: Could data be null/undefined here? - // currently, if `dataset.source` not specified, error thrown. - // if `series.data` not specified, nothing rendered without error thrown. - // Should test these cases. - - if (!data) { - return { - dimensionsDefine: normalizeDimensionsOption(dimensionsDefine), - startIndex: startIndex, - dimensionsDetectedCount: dimensionsDetectedCount - }; - } - - if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) { - var dataArrayRows = data; // Rule: Most of the first line are string: it is header. - // Caution: consider a line with 5 string and 1 number, - // it still can not be sure it is a head, because the - // 5 string may be 5 values of category columns. - - if (sourceHeader === 'auto' || sourceHeader == null) { - arrayRowsTravelFirst(function (val) { - // '-' is regarded as null/undefined. - if (val != null && val !== '-') { - if (isString(val)) { - startIndex == null && (startIndex = 1); - } else { - startIndex = 0; - } - } // 10 is an experience number, avoid long loop. - - }, seriesLayoutBy, dataArrayRows, 10); - } else { - startIndex = isNumber(sourceHeader) ? sourceHeader : sourceHeader ? 1 : 0; - } - - if (!dimensionsDefine && startIndex === 1) { - dimensionsDefine = []; - arrayRowsTravelFirst(function (val, index) { - dimensionsDefine[index] = val != null ? val + '' : ''; - }, seriesLayoutBy, dataArrayRows, Infinity); - } - - dimensionsDetectedCount = dimensionsDefine ? dimensionsDefine.length : seriesLayoutBy === SERIES_LAYOUT_BY_ROW ? dataArrayRows.length : dataArrayRows[0] ? dataArrayRows[0].length : null; - } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) { - if (!dimensionsDefine) { - dimensionsDefine = objectRowsCollectDimensions(data); - } - } else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) { - if (!dimensionsDefine) { - dimensionsDefine = []; - each$4(data, function (colArr, key) { - dimensionsDefine.push(key); - }); - } - } else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) { - var value0 = getDataItemValue(data[0]); - dimensionsDetectedCount = isArray(value0) && value0.length || 1; - } else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) { - { - assert(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.'); - } - } - - return { - startIndex: startIndex, - dimensionsDefine: normalizeDimensionsOption(dimensionsDefine), - dimensionsDetectedCount: dimensionsDetectedCount - }; - } - - function objectRowsCollectDimensions(data) { - var firstIndex = 0; - var obj; - - while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line - - - if (obj) { - return keys(obj); - } - } // Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'], - // which is reasonable. But dimension name is duplicated. - // Returns undefined or an array contains only object without null/undefined or string. - - - function normalizeDimensionsOption(dimensionsDefine) { - if (!dimensionsDefine) { - // The meaning of null/undefined is different from empty array. - return; - } - - var nameMap = createHashMap(); - return map$1(dimensionsDefine, function (rawItem, index) { - rawItem = isObject$2(rawItem) ? rawItem : { - name: rawItem - }; // Other fields will be discarded. - - var item = { - name: rawItem.name, - displayName: rawItem.displayName, - type: rawItem.type - }; // User can set null in dimensions. - // We don't auto specify name, otherwise a given name may - // cause it to be referred unexpectedly. - - if (item.name == null) { - return item; - } // Also consider number form like 2012. - - - item.name += ''; // User may also specify displayName. - // displayName will always exists except user not - // specified or dim name is not specified or detected. - // (A auto generated dim name will not be used as - // displayName). - - if (item.displayName == null) { - item.displayName = item.name; - } - - var exist = nameMap.get(item.name); - - if (!exist) { - nameMap.set(item.name, { - count: 1 - }); - } else { - item.name += '-' + exist.count++; - } - - return item; - }); - } - - function arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) { - if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) { - for (var i = 0; i < data.length && i < maxLoop; i++) { - cb(data[i] ? data[i][0] : null, i); - } - } else { - var value0 = data[0] || []; - - for (var i = 0; i < value0.length && i < maxLoop; i++) { - cb(value0[i], i); - } - } - } - - function shouldRetrieveDataByName(source) { - var sourceFormat = source.sourceFormat; - return sourceFormat === SOURCE_FORMAT_OBJECT_ROWS || sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS; - } - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * AUTO-GENERATED FILE. DO NOT MODIFY. - */ - - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - - var _a, _b, _c, _d; - - var providerMethods; - var mountMethods; - /** - * If normal array used, mutable chunk size is supported. - * If typed array used, chunk size must be fixed. - */ - - var DefaultDataProvider = - /** @class */ - function () { - function DefaultDataProvider(sourceParam, dimSize) { - // let source: Source; - var source = !isSourceInstance(sourceParam) ? createSourceFromSeriesDataOption(sourceParam) : sourceParam; // declare source is Source; - - this._source = source; - var data = this._data = source.data; - var sourceFormat = source.sourceFormat; - var seriesLayoutBy = source.seriesLayoutBy; // Typed array. TODO IE10+? - - if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) { - { - if (dimSize == null) { - throw new Error('Typed array data must specify dimension size'); - } - } - this._offset = 0; - this._dimSize = dimSize; - this._data = data; - } - - { - var validator = rawSourceDataValidatorMap[getMethodMapKey(sourceFormat, seriesLayoutBy)]; - validator && validator(data, source.dimensionsDefine); - } - mountMethods(this, data, source); - } - - DefaultDataProvider.prototype.getSource = function () { - return this._source; - }; - - DefaultDataProvider.prototype.count = function () { - return 0; - }; - - DefaultDataProvider.prototype.getItem = function (idx, out) { - return; - }; - - DefaultDataProvider.prototype.appendData = function (newData) {}; - - DefaultDataProvider.prototype.clean = function () {}; - - DefaultDataProvider.protoInitialize = function () { - // PENDING: To avoid potential incompat (e.g., prototype - // is visited somewhere), still init them on prototype. - var proto = DefaultDataProvider.prototype; - proto.pure = false; - proto.persistent = true; - }(); - - DefaultDataProvider.internalField = function () { - var _a; - - mountMethods = function (provider, data, source) { - var sourceFormat = source.sourceFormat; - var seriesLayoutBy = source.seriesLayoutBy; - var startIndex = source.startIndex; - var dimsDef = source.dimensionsDefine; - var methods = providerMethods[getMethodMapKey(sourceFormat, seriesLayoutBy)]; - { - assert(methods, 'Invalide sourceFormat: ' + sourceFormat); - } - extend(provider, methods); - - if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) { - provider.getItem = getItemForTypedArray; - provider.count = countForTypedArray; - provider.fillStorage = fillStorageForTypedArray; - } else { - var rawItemGetter = getRawSourceItemGetter(sourceFormat, seriesLayoutBy); - provider.getItem = bind$1(rawItemGetter, null, data, startIndex, dimsDef); - var rawCounter = getRawSourceDataCounter(sourceFormat, seriesLayoutBy); - provider.count = bind$1(rawCounter, null, data, startIndex, dimsDef); - } - }; - - var getItemForTypedArray = function (idx, out) { - idx = idx - this._offset; - out = out || []; - var data = this._data; - var dimSize = this._dimSize; - var offset = dimSize * idx; - - for (var i = 0; i < dimSize; i++) { - out[i] = data[offset + i]; - } - - return out; - }; - - var fillStorageForTypedArray = function (start, end, storage, extent) { - var data = this._data; - var dimSize = this._dimSize; - - for (var dim = 0; dim < dimSize; dim++) { - var dimExtent = extent[dim]; - var min = dimExtent[0] == null ? Infinity : dimExtent[0]; - var max = dimExtent[1] == null ? -Infinity : dimExtent[1]; - var count = end - start; - var arr = storage[dim]; - - for (var i = 0; i < count; i++) { - // appendData with TypedArray will always do replace in provider. - var val = data[i * dimSize + dim]; - arr[start + i] = val; - val < min && (min = val); - val > max && (max = val); - } - - dimExtent[0] = min; - dimExtent[1] = max; - } - }; - - var countForTypedArray = function () { - return this._data ? this._data.length / this._dimSize : 0; - }; - - providerMethods = (_a = {}, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = { - pure: true, - appendData: appendDataSimply - }, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = { - pure: true, - appendData: function () { - throw new Error('Do not support appendData when set seriesLayoutBy: "row".'); - } - }, _a[SOURCE_FORMAT_OBJECT_ROWS] = { - pure: true, - appendData: appendDataSimply - }, _a[SOURCE_FORMAT_KEYED_COLUMNS] = { - pure: true, - appendData: function (newData) { - var data = this._data; - each$4(newData, function (newCol, key) { - var oldCol = data[key] || (data[key] = []); - - for (var i = 0; i < (newCol || []).length; i++) { - oldCol.push(newCol[i]); - } - }); - } - }, _a[SOURCE_FORMAT_ORIGINAL] = { - appendData: appendDataSimply - }, _a[SOURCE_FORMAT_TYPED_ARRAY] = { - persistent: false, - pure: true, - appendData: function (newData) { - { - assert(isTypedArray(newData), 'Added data must be TypedArray if data in initialization is TypedArray'); - } - this._data = newData; - }, - // Clean self if data is already used. - clean: function () { - // PENDING - this._offset += this.count(); - this._data = null; - } - }, _a); - - function appendDataSimply(newData) { - for (var i = 0; i < newData.length; i++) { - this._data.push(newData[i]); - } - } - }(); - - return DefaultDataProvider; - }(); - - var validateSimply = function (rawData) { - if (!isArray(rawData)) { - error('series.data or dataset.source must be an array.'); - } - }; - /** - * Only run in dev mode - hint users for debug. - */ - - - var rawSourceDataValidatorMap = (_a = {}, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = validateSimply, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = validateSimply, _a[SOURCE_FORMAT_OBJECT_ROWS] = validateSimply, _a[SOURCE_FORMAT_KEYED_COLUMNS] = function (rawData, dimsDef) { - for (var i = 0; i < dimsDef.length; i++) { - var dimName = dimsDef[i].name; - - if (dimName == null) { - error('dimension name must not be null/undefined.'); - } - } - }, _a[SOURCE_FORMAT_ORIGINAL] = validateSimply, _a); - - var getItemSimply = function (rawData, startIndex, dimsDef, idx) { - return rawData[idx]; - }; - - var rawSourceItemGetterMap = (_b = {}, _b[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = function (rawData, startIndex, dimsDef, idx) { - return rawData[idx + startIndex]; - }, _b[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = function (rawData, startIndex, dimsDef, idx, out) { - idx += startIndex; - var item = out || []; - var data = rawData; - - for (var i = 0; i < data.length; i++) { - var row = data[i]; - item[i] = row ? row[idx] : null; - } - - return item; - }, _b[SOURCE_FORMAT_OBJECT_ROWS] = getItemSimply, _b[SOURCE_FORMAT_KEYED_COLUMNS] = function (rawData, startIndex, dimsDef, idx, out) { - var item = out || []; - - for (var i = 0; i < dimsDef.length; i++) { - var dimName = dimsDef[i].name; - var col = dimName != null ? rawData[dimName] : null; - item[i] = col ? col[idx] : null; - } - - return item; - }, _b[SOURCE_FORMAT_ORIGINAL] = getItemSimply, _b); - - function getRawSourceItemGetter(sourceFormat, seriesLayoutBy) { - var method = rawSourceItemGetterMap[getMethodMapKey(sourceFormat, seriesLayoutBy)]; - { - assert(method, 'Do not support get item on "' + sourceFormat + '", "' + seriesLayoutBy + '".'); - } - return method; - } - - var countSimply = function (rawData, startIndex, dimsDef) { - return rawData.length; - }; - - var rawSourceDataCounterMap = (_c = {}, _c[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = function (rawData, startIndex, dimsDef) { - return Math.max(0, rawData.length - startIndex); - }, _c[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = function (rawData, startIndex, dimsDef) { - var row = rawData[0]; - return row ? Math.max(0, row.length - startIndex) : 0; - }, _c[SOURCE_FORMAT_OBJECT_ROWS] = countSimply, _c[SOURCE_FORMAT_KEYED_COLUMNS] = function (rawData, startIndex, dimsDef) { - var dimName = dimsDef[0].name; - var col = dimName != null ? rawData[dimName] : null; - return col ? col.length : 0; - }, _c[SOURCE_FORMAT_ORIGINAL] = countSimply, _c); - - function getRawSourceDataCounter(sourceFormat, seriesLayoutBy) { - var method = rawSourceDataCounterMap[getMethodMapKey(sourceFormat, seriesLayoutBy)]; - { - assert(method, 'Do not support count on "' + sourceFormat + '", "' + seriesLayoutBy + '".'); - } - return method; - } - - var getRawValueSimply = function (dataItem, dimIndex, property) { - return dataItem[dimIndex]; - }; - - var rawSourceValueGetterMap = (_d = {}, _d[SOURCE_FORMAT_ARRAY_ROWS] = getRawValueSimply, _d[SOURCE_FORMAT_OBJECT_ROWS] = function (dataItem, dimIndex, property) { - return dataItem[property]; - }, _d[SOURCE_FORMAT_KEYED_COLUMNS] = getRawValueSimply, _d[SOURCE_FORMAT_ORIGINAL] = function (dataItem, dimIndex, property) { - // FIXME: In some case (markpoint in geo (geo-map.html)), - // dataItem is {coord: [...]} - var value = getDataItemValue(dataItem); - return !(value instanceof Array) ? value : value[dimIndex]; - }, _d[SOURCE_FORMAT_TYPED_ARRAY] = getRawValueSimply, _d); - - function getRawSourceValueGetter(sourceFormat) { - var method = rawSourceValueGetterMap[sourceFormat]; - { - assert(method, 'Do not support get value on "' + sourceFormat + '".'); - } - return method; - } - - function getMethodMapKey(sourceFormat, seriesLayoutBy) { - return sourceFormat === SOURCE_FORMAT_ARRAY_ROWS ? sourceFormat + '_' + seriesLayoutBy : sourceFormat; - } // ??? FIXME can these logic be more neat: getRawValue, getRawDataItem, - // Consider persistent. - // Caution: why use raw value to display on label or tooltip? - // A reason is to avoid format. For example time value we do not know - // how to format is expected. More over, if stack is used, calculated - // value may be 0.91000000001, which have brings trouble to display. - // TODO: consider how to treat null/undefined/NaN when display? - - - function retrieveRawValue(data, dataIndex, // If dimIndex is null/undefined, return OptionDataItem. - // Otherwise, return OptionDataValue. - dim) { - if (!data) { - return; - } // Consider data may be not persistent. - - - var dataItem = data.getRawDataItem(dataIndex); - - if (dataItem == null) { - return; - } - - var store = data.getStore(); - var sourceFormat = store.getSource().sourceFormat; - - if (dim != null) { - var dimIndex = data.getDimensionIndex(dim); - var property = store.getDimensionProperty(dimIndex); - return getRawSourceValueGetter(sourceFormat)(dataItem, dimIndex, property); - } else { - var result = dataItem; - - if (sourceFormat === SOURCE_FORMAT_ORIGINAL) { - result = getDataItemValue(dataItem); - } - - return result; - } - } - - var DIMENSION_LABEL_REG = /\{@(.+?)\}/g; - - var DataFormatMixin = - /** @class */ - function () { - function DataFormatMixin() {} - /** - * Get params for formatter - */ - - - DataFormatMixin.prototype.getDataParams = function (dataIndex, dataType) { - var data = this.getData(dataType); - var rawValue = this.getRawValue(dataIndex, dataType); - var rawDataIndex = data.getRawIndex(dataIndex); - var name = data.getName(dataIndex); - var itemOpt = data.getRawDataItem(dataIndex); - var style = data.getItemVisual(dataIndex, 'style'); - var color = style && style[data.getItemVisual(dataIndex, 'drawType') || 'fill']; - var borderColor = style && style.stroke; - var mainType = this.mainType; - var isSeries = mainType === 'series'; - var userOutput = data.userOutput && data.userOutput.get(); - return { - componentType: mainType, - componentSubType: this.subType, - componentIndex: this.componentIndex, - seriesType: isSeries ? this.subType : null, - seriesIndex: this.seriesIndex, - seriesId: isSeries ? this.id : null, - seriesName: isSeries ? this.name : null, - name: name, - dataIndex: rawDataIndex, - data: itemOpt, - dataType: dataType, - value: rawValue, - color: color, - borderColor: borderColor, - dimensionNames: userOutput ? userOutput.fullDimensions : null, - encode: userOutput ? userOutput.encode : null, - // Param name list for mapping `a`, `b`, `c`, `d`, `e` - $vars: ['seriesName', 'name', 'value'] - }; - }; - /** - * Format label - * @param dataIndex - * @param status 'normal' by default - * @param dataType - * @param labelDimIndex Only used in some chart that - * use formatter in different dimensions, like radar. - * @param formatter Formatter given outside. - * @return return null/undefined if no formatter - */ - - - DataFormatMixin.prototype.getFormattedLabel = function (dataIndex, status, dataType, labelDimIndex, formatter, extendParams) { - status = status || 'normal'; - var data = this.getData(dataType); - var params = this.getDataParams(dataIndex, dataType); - - if (extendParams) { - params.value = extendParams.interpolatedValue; - } - - if (labelDimIndex != null && isArray(params.value)) { - params.value = params.value[labelDimIndex]; - } - - if (!formatter) { - var itemModel = data.getItemModel(dataIndex); // @ts-ignore - - formatter = itemModel.get(status === 'normal' ? ['label', 'formatter'] : [status, 'label', 'formatter']); - } - - if (isFunction(formatter)) { - params.status = status; - params.dimensionIndex = labelDimIndex; - return formatter(params); - } else if (isString(formatter)) { - var str = formatTpl(formatter, params); // Support 'aaa{@[3]}bbb{@product}ccc'. - // Do not support '}' in dim name util have to. - - return str.replace(DIMENSION_LABEL_REG, function (origin, dimStr) { - var len = dimStr.length; - var dimLoose = dimStr; - - if (dimLoose.charAt(0) === '[' && dimLoose.charAt(len - 1) === ']') { - dimLoose = +dimLoose.slice(1, len - 1); // Also support: '[]' => 0 - - { - if (isNaN(dimLoose)) { - error("Invalide label formatter: @" + dimStr + ", only support @[0], @[1], @[2], ..."); - } - } - } - - var val = retrieveRawValue(data, dataIndex, dimLoose); - - if (extendParams && isArray(extendParams.interpolatedValue)) { - var dimIndex = data.getDimensionIndex(dimLoose); - - if (dimIndex >= 0) { - val = extendParams.interpolatedValue[dimIndex]; - } - } - - return val != null ? val + '' : ''; - }); - } - }; - /** - * Get raw value in option - */ - - - DataFormatMixin.prototype.getRawValue = function (idx, dataType) { - return retrieveRawValue(this.getData(dataType), idx); - }; - /** - * Should be implemented. - * @param {number} dataIndex - * @param {boolean} [multipleSeries=false] - * @param {string} [dataType] - */ - - - DataFormatMixin.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { - // Empty function - return; - }; - - return DataFormatMixin; - }(); // PENDING: previously we accept this type when calling `formatTooltip`, - // but guess little chance has been used outside. Do we need to backward - // compat it? - // type TooltipFormatResultLegacyObject = { - // // `html` means the markup language text, either in 'html' or 'richText'. - // // The name `html` is not appropriate because in 'richText' it is not a HTML - // // string. But still support it for backward compatibility. - // html: string; - // markers: Dictionary; - // }; - - /** - * For backward compat, normalize the return from `formatTooltip`. - */ - - - function normalizeTooltipFormatResult(result) { - var markupText; // let markers: Dictionary; - - var markupFragment; - - if (isObject$2(result)) { - if (result.type) { - markupFragment = result; - } else { - { - console.warn('The return type of `formatTooltip` is not supported: ' + makePrintable(result)); - } - } // else { - // markupText = (result as TooltipFormatResultLegacyObject).html; - // markers = (result as TooltipFormatResultLegacyObject).markers; - // if (markersExisting) { - // markers = zrUtil.merge(markersExisting, markers); - // } - // } - - } else { - markupText = result; - } - - return { - text: markupText, - // markers: markers || markersExisting, - frag: markupFragment - }; - } - /** - * @param {Object} define - * @return See the return of `createTask`. - */ - - - function createTask(define) { - return new Task(define); - } - - var Task = - /** @class */ - function () { - function Task(define) { - define = define || {}; - this._reset = define.reset; - this._plan = define.plan; - this._count = define.count; - this._onDirty = define.onDirty; - this._dirty = true; - } - /** - * @param step Specified step. - * @param skip Skip customer perform call. - * @param modBy Sampling window size. - * @param modDataCount Sampling count. - * @return whether unfinished. - */ - - - Task.prototype.perform = function (performArgs) { - var upTask = this._upstream; - var skip = performArgs && performArgs.skip; // TODO some refactor. - // Pull data. Must pull data each time, because context.data - // may be updated by Series.setData. - - if (this._dirty && upTask) { - var context = this.context; - context.data = context.outputData = upTask.context.outputData; - } - - if (this.__pipeline) { - this.__pipeline.currentTask = this; - } - - var planResult; - - if (this._plan && !skip) { - planResult = this._plan(this.context); - } // Support sharding by mod, which changes the render sequence and makes the rendered graphic - // elements uniformed distributed when progress, especially when moving or zooming. - - - var lastModBy = normalizeModBy(this._modBy); - var lastModDataCount = this._modDataCount || 0; - var modBy = normalizeModBy(performArgs && performArgs.modBy); - var modDataCount = performArgs && performArgs.modDataCount || 0; - - if (lastModBy !== modBy || lastModDataCount !== modDataCount) { - planResult = 'reset'; - } - - function normalizeModBy(val) { - !(val >= 1) && (val = 1); // jshint ignore:line - - return val; - } - - var forceFirstProgress; - - if (this._dirty || planResult === 'reset') { - this._dirty = false; - forceFirstProgress = this._doReset(skip); - } - - this._modBy = modBy; - this._modDataCount = modDataCount; - var step = performArgs && performArgs.step; - - if (upTask) { - { - assert(upTask._outputDueEnd != null); - } - this._dueEnd = upTask._outputDueEnd; - } // DataTask or overallTask - else { - { - assert(!this._progress || this._count); - } - this._dueEnd = this._count ? this._count(this.context) : Infinity; - } // Note: Stubs, that its host overall task let it has progress, has progress. - // If no progress, pass index from upstream to downstream each time plan called. - - - if (this._progress) { - var start = this._dueIndex; - var end = Math.min(step != null ? this._dueIndex + step : Infinity, this._dueEnd); - - if (!skip && (forceFirstProgress || start < end)) { - var progress = this._progress; - - if (isArray(progress)) { - for (var i = 0; i < progress.length; i++) { - this._doProgress(progress[i], start, end, modBy, modDataCount); - } - } else { - this._doProgress(progress, start, end, modBy, modDataCount); - } - } - - this._dueIndex = end; // If no `outputDueEnd`, assume that output data and - // input data is the same, so use `dueIndex` as `outputDueEnd`. - - var outputDueEnd = this._settedOutputEnd != null ? this._settedOutputEnd : end; - { - // ??? Can not rollback. - assert(outputDueEnd >= this._outputDueEnd); - } - this._outputDueEnd = outputDueEnd; - } else { - // (1) Some overall task has no progress. - // (2) Stubs, that its host overall task do not let it has progress, has no progress. - // This should always be performed so it can be passed to downstream. - this._dueIndex = this._outputDueEnd = this._settedOutputEnd != null ? this._settedOutputEnd : this._dueEnd; - } - - return this.unfinished(); - }; - - Task.prototype.dirty = function () { - this._dirty = true; - this._onDirty && this._onDirty(this.context); - }; - - Task.prototype._doProgress = function (progress, start, end, modBy, modDataCount) { - iterator.reset(start, end, modBy, modDataCount); - this._callingProgress = progress; - - this._callingProgress({ - start: start, - end: end, - count: end - start, - next: iterator.next - }, this.context); - }; - - Task.prototype._doReset = function (skip) { - this._dueIndex = this._outputDueEnd = this._dueEnd = 0; - this._settedOutputEnd = null; - var progress; - var forceFirstProgress; - - if (!skip && this._reset) { - progress = this._reset(this.context); - - if (progress && progress.progress) { - forceFirstProgress = progress.forceFirstProgress; - progress = progress.progress; - } // To simplify no progress checking, array must has item. - - - if (isArray(progress) && !progress.length) { - progress = null; - } - } - - this._progress = progress; - this._modBy = this._modDataCount = null; - var downstream = this._downstream; - downstream && downstream.dirty(); - return forceFirstProgress; - }; - - Task.prototype.unfinished = function () { - return this._progress && this._dueIndex < this._dueEnd; - }; - /** - * @param downTask The downstream task. - * @return The downstream task. - */ - - - Task.prototype.pipe = function (downTask) { - { - assert(downTask && !downTask._disposed && downTask !== this); - } // If already downstream, do not dirty downTask. - - if (this._downstream !== downTask || this._dirty) { - this._downstream = downTask; - downTask._upstream = this; - downTask.dirty(); - } - }; - - Task.prototype.dispose = function () { - if (this._disposed) { - return; - } - - this._upstream && (this._upstream._downstream = null); - this._downstream && (this._downstream._upstream = null); - this._dirty = false; - this._disposed = true; - }; - - Task.prototype.getUpstream = function () { - return this._upstream; - }; - - Task.prototype.getDownstream = function () { - return this._downstream; - }; - - Task.prototype.setOutputEnd = function (end) { - // This only happens in dataTask, dataZoom, map, currently. - // where dataZoom do not set end each time, but only set - // when reset. So we should record the set end, in case - // that the stub of dataZoom perform again and earse the - // set end by upstream. - this._outputDueEnd = this._settedOutputEnd = end; - }; - - return Task; - }(); - - var iterator = function () { - var end; - var current; - var modBy; - var modDataCount; - var winCount; - var it = { - reset: function (s, e, sStep, sCount) { - current = s; - end = e; - modBy = sStep; - modDataCount = sCount; - winCount = Math.ceil(modDataCount / modBy); - it.next = modBy > 1 && modDataCount > 0 ? modNext : sequentialNext; - } - }; - return it; - - function sequentialNext() { - return current < end ? current++ : null; - } - - function modNext() { - var dataIndex = current % winCount * modBy + Math.ceil(current / winCount); - var result = current >= end ? null : dataIndex < modDataCount ? dataIndex // If modDataCount is smaller than data.count() (consider `appendData` case), - // Use normal linear rendering mode. - : current; - current++; - return result; - } - }(); // ----------------------------------------------------------------------------- - // For stream debug (Should be commented out after used!) - // @usage: printTask(this, 'begin'); - // @usage: printTask(this, null, {someExtraProp}); - // @usage: Use `__idxInPipeline` as conditional breakpiont. - // - // window.printTask = function (task: any, prefix: string, extra: { [key: string]: unknown }): void { - // window.ecTaskUID == null && (window.ecTaskUID = 0); - // task.uidDebug == null && (task.uidDebug = `task_${window.ecTaskUID++}`); - // task.agent && task.agent.uidDebug == null && (task.agent.uidDebug = `task_${window.ecTaskUID++}`); - // let props = []; - // if (task.__pipeline) { - // let val = `${task.__idxInPipeline}/${task.__pipeline.tail.__idxInPipeline} ${task.agent ? '(stub)' : ''}`; - // props.push({text: '__idxInPipeline/total', value: val}); - // } else { - // let stubCount = 0; - // task.agentStubMap.each(() => stubCount++); - // props.push({text: 'idx', value: `overall (stubs: ${stubCount})`}); - // } - // props.push({text: 'uid', value: task.uidDebug}); - // if (task.__pipeline) { - // props.push({text: 'pipelineId', value: task.__pipeline.id}); - // task.agent && props.push( - // {text: 'stubFor', value: task.agent.uidDebug} - // ); - // } - // props.push( - // {text: 'dirty', value: task._dirty}, - // {text: 'dueIndex', value: task._dueIndex}, - // {text: 'dueEnd', value: task._dueEnd}, - // {text: 'outputDueEnd', value: task._outputDueEnd} - // ); - // if (extra) { - // Object.keys(extra).forEach(key => { - // props.push({text: key, value: extra[key]}); - // }); - // } - // let args = ['color: blue']; - // let msg = `%c[${prefix || 'T'}] %c` + props.map(item => ( - // args.push('color: green', 'color: red'), - // `${item.text}: %c${item.value}` - // )).join('%c, '); - // console.log.apply(console, [msg].concat(args)); - // // console.log(this); - // }; - // window.printPipeline = function (task: any, prefix: string) { - // const pipeline = task.__pipeline; - // let currTask = pipeline.head; - // while (currTask) { - // window.printTask(currTask, prefix); - // currTask = currTask._downstream; - // } - // }; - // window.showChain = function (chainHeadTask) { - // var chain = []; - // var task = chainHeadTask; - // while (task) { - // chain.push({ - // task: task, - // up: task._upstream, - // down: task._downstream, - // idxInPipeline: task.__idxInPipeline - // }); - // task = task._downstream; - // } - // return chain; - // }; - // window.findTaskInChain = function (task, chainHeadTask) { - // let chain = window.showChain(chainHeadTask); - // let result = []; - // for (let i = 0; i < chain.length; i++) { - // let chainItem = chain[i]; - // if (chainItem.task === task) { - // result.push(i); - // } - // } - // return result; - // }; - // window.printChainAEachInChainB = function (chainHeadTaskA, chainHeadTaskB) { - // let chainA = window.showChain(chainHeadTaskA); - // for (let i = 0; i < chainA.length; i++) { - // console.log('chainAIdx:', i, 'inChainB:', window.findTaskInChain(chainA[i].task, chainHeadTaskB)); - // } - // }; - - /** - * Convert raw the value in to inner value in List. - * - * [Performance sensitive] - * - * [Caution]: this is the key logic of user value parser. - * For backward compatibility, do not modify it until you have to! - */ - - - function parseDataValue(value, // For high performance, do not omit the second param. - opt) { - // Performance sensitive. - var dimType = opt && opt.type; - - if (dimType === 'ordinal') { - // If given value is a category string - return value; - } - - if (dimType === 'time' // spead up when using timestamp - && !isNumber(value) && value != null && value !== '-') { - value = +parseDate(value); - } // dimType defaults 'number'. - // If dimType is not ordinal and value is null or undefined or NaN or '-', - // parse to NaN. - // number-like string (like ' 123 ') can be converted to a number. - // where null/undefined or other string will be converted to NaN. - - - return value == null || value === '' ? NaN // If string (like '-'), using '+' parse to NaN - // If object, also parse to NaN - : Number(value); - } - - var valueParserMap = createHashMap({ - 'number': function (val) { - // Do not use `numericToNumber` here. We have `numericToNumber` by default. - // Here the number parser can have loose rule: - // enable to cut suffix: "120px" => 120, "14%" => 14. - return parseFloat(val); - }, - 'time': function (val) { - // return timestamp. - return +parseDate(val); - }, - 'trim': function (val) { - return isString(val) ? trim(val) : val; - } - }); - - function getRawValueParser(type) { - return valueParserMap.get(type); - } - - var ORDER_COMPARISON_OP_MAP = { - lt: function (lval, rval) { - return lval < rval; - }, - lte: function (lval, rval) { - return lval <= rval; - }, - gt: function (lval, rval) { - return lval > rval; - }, - gte: function (lval, rval) { - return lval >= rval; - } - }; - - var FilterOrderComparator = - /** @class */ - function () { - function FilterOrderComparator(op, rval) { - if (!isNumber(rval)) { - var errMsg = ''; - { - errMsg = 'rvalue of "<", ">", "<=", ">=" can only be number in filter.'; - } - throwError(errMsg); - } - - this._opFn = ORDER_COMPARISON_OP_MAP[op]; - this._rvalFloat = numericToNumber(rval); - } // Performance sensitive. - - - FilterOrderComparator.prototype.evaluate = function (lval) { - // Most cases is 'number', and typeof maybe 10 times faseter than parseFloat. - return isNumber(lval) ? this._opFn(lval, this._rvalFloat) : this._opFn(numericToNumber(lval), this._rvalFloat); - }; - - return FilterOrderComparator; - }(); - - var SortOrderComparator = - /** @class */ - function () { - /** - * @param order by default: 'asc' - * @param incomparable by default: Always on the tail. - * That is, if 'asc' => 'max', if 'desc' => 'min' - * See the definition of "incomparable" in [SORT_COMPARISON_RULE]. - */ - function SortOrderComparator(order, incomparable) { - var isDesc = order === 'desc'; - this._resultLT = isDesc ? 1 : -1; - - if (incomparable == null) { - incomparable = isDesc ? 'min' : 'max'; - } - - this._incomparable = incomparable === 'min' ? -Infinity : Infinity; - } // See [SORT_COMPARISON_RULE]. - // Performance sensitive. - - - SortOrderComparator.prototype.evaluate = function (lval, rval) { - // Most cases is 'number', and typeof maybe 10 times faseter than parseFloat. - var lvalFloat = isNumber(lval) ? lval : numericToNumber(lval); - var rvalFloat = isNumber(rval) ? rval : numericToNumber(rval); - var lvalNotNumeric = isNaN(lvalFloat); - var rvalNotNumeric = isNaN(rvalFloat); - - if (lvalNotNumeric) { - lvalFloat = this._incomparable; - } - - if (rvalNotNumeric) { - rvalFloat = this._incomparable; - } - - if (lvalNotNumeric && rvalNotNumeric) { - var lvalIsStr = isString(lval); - var rvalIsStr = isString(rval); - - if (lvalIsStr) { - lvalFloat = rvalIsStr ? lval : 0; - } - - if (rvalIsStr) { - rvalFloat = lvalIsStr ? rval : 0; - } - } - - return lvalFloat < rvalFloat ? this._resultLT : lvalFloat > rvalFloat ? -this._resultLT : 0; - }; - - return SortOrderComparator; - }(); - - var FilterEqualityComparator = - /** @class */ - function () { - function FilterEqualityComparator(isEq, rval) { - this._rval = rval; - this._isEQ = isEq; - this._rvalTypeof = typeof rval; - this._rvalFloat = numericToNumber(rval); - } // Performance sensitive. - - - FilterEqualityComparator.prototype.evaluate = function (lval) { - var eqResult = lval === this._rval; - - if (!eqResult) { - var lvalTypeof = typeof lval; - - if (lvalTypeof !== this._rvalTypeof && (lvalTypeof === 'number' || this._rvalTypeof === 'number')) { - eqResult = numericToNumber(lval) === this._rvalFloat; - } - } - - return this._isEQ ? eqResult : !eqResult; - }; - - return FilterEqualityComparator; - }(); - /** - * [FILTER_COMPARISON_RULE] - * `lt`|`lte`|`gt`|`gte`: - * + rval must be a number. And lval will be converted to number (`numericToNumber`) to compare. - * `eq`: - * + If same type, compare with `===`. - * + If there is one number, convert to number (`numericToNumber`) to compare. - * + Else return `false`. - * `ne`: - * + Not `eq`. - * - * - * [SORT_COMPARISON_RULE] - * All the values are grouped into three categories: - * + "numeric" (number and numeric string) - * + "non-numeric-string" (string that excluding numeric string) - * + "others" - * "numeric" vs "numeric": values are ordered by number order. - * "non-numeric-string" vs "non-numeric-string": values are ordered by ES spec (#sec-abstract-relational-comparison). - * "others" vs "others": do not change order (always return 0). - * "numeric" vs "non-numeric-string": "non-numeric-string" is treated as "incomparable". - * "number" vs "others": "others" is treated as "incomparable". - * "non-numeric-string" vs "others": "others" is treated as "incomparable". - * "incomparable" will be seen as -Infinity or Infinity (depends on the settings). - * MEMO: - * Non-numeric string sort makes sense when we need to put the items with the same tag together. - * But if we support string sort, we still need to avoid the misleading like `'2' > '12'`, - * So we treat "numeric-string" sorted by number order rather than string comparison. - * - * - * [CHECK_LIST_OF_THE_RULE_DESIGN] - * + Do not support string comparison until required. And also need to - * avoid the misleading of "2" > "12". - * + Should avoid the misleading case: - * `" 22 " gte "22"` is `true` but `" 22 " eq "22"` is `false`. - * + JS bad case should be avoided: null <= 0, [] <= 0, ' ' <= 0, ... - * + Only "numeric" can be converted to comparable number, otherwise converted to NaN. - * See `util/number.ts#numericToNumber`. - * - * @return If `op` is not `RelationalOperator`, return null; - */ - - - function createFilterComparator(op, rval) { - return op === 'eq' || op === 'ne' ? new FilterEqualityComparator(op === 'eq', rval) : hasOwn(ORDER_COMPARISON_OP_MAP, op) ? new FilterOrderComparator(op, rval) : null; - } - /** - * TODO: disable writable. - * This structure will be exposed to users. - */ - - - var ExternalSource = - /** @class */ - function () { - function ExternalSource() {} - - ExternalSource.prototype.getRawData = function () { - // Only built-in transform available. - throw new Error('not supported'); - }; - - ExternalSource.prototype.getRawDataItem = function (dataIndex) { - // Only built-in transform available. - throw new Error('not supported'); - }; - - ExternalSource.prototype.cloneRawData = function () { - return; - }; - /** - * @return If dimension not found, return null/undefined. - */ - - - ExternalSource.prototype.getDimensionInfo = function (dim) { - return; - }; - /** - * dimensions defined if and only if either: - * (a) dataset.dimensions are declared. - * (b) dataset data include dimensions definitions in data (detected or via specified `sourceHeader`). - * If dimensions are defined, `dimensionInfoAll` is corresponding to - * the defined dimensions. - * Otherwise, `dimensionInfoAll` is determined by data columns. - * @return Always return an array (even empty array). - */ - - - ExternalSource.prototype.cloneAllDimensionInfo = function () { - return; - }; - - ExternalSource.prototype.count = function () { - return; - }; - /** - * Only support by dimension index. - * No need to support by dimension name in transform function, - * because transform function is not case-specific, no need to use name literally. - */ - - - ExternalSource.prototype.retrieveValue = function (dataIndex, dimIndex) { - return; - }; - - ExternalSource.prototype.retrieveValueFromItem = function (dataItem, dimIndex) { - return; - }; - - ExternalSource.prototype.convertValue = function (rawVal, dimInfo) { - return parseDataValue(rawVal, dimInfo); - }; - - return ExternalSource; - }(); - - function createExternalSource(internalSource, externalTransform) { - var extSource = new ExternalSource(); - var data = internalSource.data; - var sourceFormat = extSource.sourceFormat = internalSource.sourceFormat; - var sourceHeaderCount = internalSource.startIndex; - var errMsg = ''; - - if (internalSource.seriesLayoutBy !== SERIES_LAYOUT_BY_COLUMN) { - // For the logic simplicity in transformer, only 'culumn' is - // supported in data transform. Otherwise, the `dimensionsDefine` - // might be detected by 'row', which probably confuses users. - { - errMsg = '`seriesLayoutBy` of upstream dataset can only be "column" in data transform.'; - } - throwError(errMsg); - } // [MEMO] - // Create a new dimensions structure for exposing. - // Do not expose all dimension info to users directly. - // Because the dimension is probably auto detected from data and not might reliable. - // Should not lead the transformers to think that is reliable and return it. - // See [DIMENSION_INHERIT_RULE] in `sourceManager.ts`. - - - var dimensions = []; - var dimsByName = {}; - var dimsDef = internalSource.dimensionsDefine; - - if (dimsDef) { - each$4(dimsDef, function (dimDef, idx) { - var name = dimDef.name; - var dimDefExt = { - index: idx, - name: name, - displayName: dimDef.displayName - }; - dimensions.push(dimDefExt); // Users probably do not specify dimension name. For simplicity, data transform - // does not generate dimension name. - - if (name != null) { - // Dimension name should not be duplicated. - // For simplicity, data transform forbids name duplication, do not generate - // new name like module `completeDimensions.ts` did, but just tell users. - var errMsg_1 = ''; - - if (hasOwn(dimsByName, name)) { - { - errMsg_1 = 'dimension name "' + name + '" duplicated.'; - } - throwError(errMsg_1); - } - - dimsByName[name] = dimDefExt; - } - }); - } // If dimension definitions are not defined and can not be detected. - // e.g., pure data `[[11, 22], ...]`. - else { - for (var i = 0; i < internalSource.dimensionsDetectedCount || 0; i++) { - // Do not generete name or anything others. The consequence process in - // `transform` or `series` probably have there own name generation strategry. - dimensions.push({ - index: i - }); - } - } // Implement public methods: - - - var rawItemGetter = getRawSourceItemGetter(sourceFormat, SERIES_LAYOUT_BY_COLUMN); - - if (externalTransform.__isBuiltIn) { - extSource.getRawDataItem = function (dataIndex) { - return rawItemGetter(data, sourceHeaderCount, dimensions, dataIndex); - }; - - extSource.getRawData = bind$1(getRawData, null, internalSource); - } - - extSource.cloneRawData = bind$1(cloneRawData, null, internalSource); - var rawCounter = getRawSourceDataCounter(sourceFormat, SERIES_LAYOUT_BY_COLUMN); - extSource.count = bind$1(rawCounter, null, data, sourceHeaderCount, dimensions); - var rawValueGetter = getRawSourceValueGetter(sourceFormat); - - extSource.retrieveValue = function (dataIndex, dimIndex) { - var rawItem = rawItemGetter(data, sourceHeaderCount, dimensions, dataIndex); - return retrieveValueFromItem(rawItem, dimIndex); - }; - - var retrieveValueFromItem = extSource.retrieveValueFromItem = function (dataItem, dimIndex) { - if (dataItem == null) { - return; - } - - var dimDef = dimensions[dimIndex]; // When `dimIndex` is `null`, `rawValueGetter` return the whole item. - - if (dimDef) { - return rawValueGetter(dataItem, dimIndex, dimDef.name); - } - }; - - extSource.getDimensionInfo = bind$1(getDimensionInfo, null, dimensions, dimsByName); - extSource.cloneAllDimensionInfo = bind$1(cloneAllDimensionInfo, null, dimensions); - return extSource; - } - - function getRawData(upstream) { - var sourceFormat = upstream.sourceFormat; - - if (!isSupportedSourceFormat(sourceFormat)) { - var errMsg = ''; - { - errMsg = '`getRawData` is not supported in source format ' + sourceFormat; - } - throwError(errMsg); - } - - return upstream.data; - } - - function cloneRawData(upstream) { - var sourceFormat = upstream.sourceFormat; - var data = upstream.data; - - if (!isSupportedSourceFormat(sourceFormat)) { - var errMsg = ''; - { - errMsg = '`cloneRawData` is not supported in source format ' + sourceFormat; - } - throwError(errMsg); - } - - if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) { - var result = []; - - for (var i = 0, len = data.length; i < len; i++) { - // Not strictly clone for performance - result.push(data[i].slice()); - } - - return result; - } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) { - var result = []; - - for (var i = 0, len = data.length; i < len; i++) { - // Not strictly clone for performance - result.push(extend({}, data[i])); - } - - return result; - } - } - - function getDimensionInfo(dimensions, dimsByName, dim) { - if (dim == null) { - return; - } // Keep the same logic as `List::getDimension` did. - - - if (isNumber(dim) // If being a number-like string but not being defined a dimension name. - || !isNaN(dim) && !hasOwn(dimsByName, dim)) { - return dimensions[dim]; - } else if (hasOwn(dimsByName, dim)) { - return dimsByName[dim]; - } - } - - function cloneAllDimensionInfo(dimensions) { - return clone$3(dimensions); - } - - var externalTransformMap = createHashMap(); - - function registerExternalTransform(externalTransform) { - externalTransform = clone$3(externalTransform); - var type = externalTransform.type; - var errMsg = ''; - - if (!type) { - { - errMsg = 'Must have a `type` when `registerTransform`.'; - } - throwError(errMsg); - } - - var typeParsed = type.split(':'); - - if (typeParsed.length !== 2) { - { - errMsg = 'Name must include namespace like "ns:regression".'; - } - throwError(errMsg); - } // Namespace 'echarts:xxx' is official namespace, where the transforms should - // be called directly via 'xxx' rather than 'echarts:xxx'. - - - var isBuiltIn = false; - - if (typeParsed[0] === 'echarts') { - type = typeParsed[1]; - isBuiltIn = true; - } - - externalTransform.__isBuiltIn = isBuiltIn; - externalTransformMap.set(type, externalTransform); - } - - function applyDataTransform(rawTransOption, sourceList, infoForPrint) { - var pipedTransOption = normalizeToArray(rawTransOption); - var pipeLen = pipedTransOption.length; - var errMsg = ''; - - if (!pipeLen) { - { - errMsg = 'If `transform` declared, it should at least contain one transform.'; - } - throwError(errMsg); - } - - for (var i = 0, len = pipeLen; i < len; i++) { - var transOption = pipedTransOption[i]; - sourceList = applySingleDataTransform(transOption, sourceList, infoForPrint, pipeLen === 1 ? null : i); // piped transform only support single input, except the fist one. - // piped transform only support single output, except the last one. - - if (i !== len - 1) { - sourceList.length = Math.max(sourceList.length, 1); - } - } - - return sourceList; - } - - function applySingleDataTransform(transOption, upSourceList, infoForPrint, // If `pipeIndex` is null/undefined, no piped transform. - pipeIndex) { - var errMsg = ''; - - if (!upSourceList.length) { - { - errMsg = 'Must have at least one upstream dataset.'; - } - throwError(errMsg); - } - - if (!isObject$2(transOption)) { - { - errMsg = 'transform declaration must be an object rather than ' + typeof transOption + '.'; - } - throwError(errMsg); - } - - var transType = transOption.type; - var externalTransform = externalTransformMap.get(transType); - - if (!externalTransform) { - { - errMsg = 'Can not find transform on type "' + transType + '".'; - } - throwError(errMsg); - } // Prepare source - - - var extUpSourceList = map$1(upSourceList, function (upSource) { - return createExternalSource(upSource, externalTransform); - }); - var resultList = normalizeToArray(externalTransform.transform({ - upstream: extUpSourceList[0], - upstreamList: extUpSourceList, - config: clone$3(transOption.config) - })); - { - if (transOption.print) { - var printStrArr = map$1(resultList, function (extSource) { - var pipeIndexStr = pipeIndex != null ? ' === pipe index: ' + pipeIndex : ''; - return ['=== dataset index: ' + infoForPrint.datasetIndex + pipeIndexStr + ' ===', '- transform result data:', makePrintable(extSource.data), '- transform result dimensions:', makePrintable(extSource.dimensions)].join('\n'); - }).join('\n'); - log(printStrArr); - } - } - return map$1(resultList, function (result, resultIndex) { - var errMsg = ''; - - if (!isObject$2(result)) { - { - errMsg = 'A transform should not return some empty results.'; - } - throwError(errMsg); - } - - if (!result.data) { - { - errMsg = 'Transform result data should be not be null or undefined'; - } - throwError(errMsg); - } - - var sourceFormat = detectSourceFormat(result.data); - - if (!isSupportedSourceFormat(sourceFormat)) { - { - errMsg = 'Transform result data should be array rows or object rows.'; - } - throwError(errMsg); - } - - var resultMetaRawOption; - var firstUpSource = upSourceList[0]; - /** - * Intuitively, the end users known the content of the original `dataset.source`, - * calucating the transform result in mind. - * Suppose the original `dataset.source` is: - * ```js - * [ - * ['product', '2012', '2013', '2014', '2015'], - * ['AAA', 41.1, 30.4, 65.1, 53.3], - * ['BBB', 86.5, 92.1, 85.7, 83.1], - * ['CCC', 24.1, 67.2, 79.5, 86.4] - * ] - * ``` - * The dimension info have to be detected from the source data. - * Some of the transformers (like filter, sort) will follow the dimension info - * of upstream, while others use new dimensions (like aggregate). - * Transformer can output a field `dimensions` to define the its own output dimensions. - * We also allow transformers to ignore the output `dimensions` field, and - * inherit the upstream dimensions definition. It can reduce the burden of handling - * dimensions in transformers. - * - * See also [DIMENSION_INHERIT_RULE] in `sourceManager.ts`. - */ - - if (firstUpSource && resultIndex === 0 // If transformer returns `dimensions`, it means that the transformer has different - // dimensions definitions. We do not inherit anything from upstream. - && !result.dimensions) { - var startIndex = firstUpSource.startIndex; // We copy the header of upstream to the result, because: - // (1) The returned data always does not contain header line and can not be used - // as dimension-detection. In this case we can not use "detected dimensions" of - // upstream directly, because it might be detected based on different `seriesLayoutBy`. - // (2) We should support that the series read the upstream source in `seriesLayoutBy: 'row'`. - // So the original detected header should be add to the result, otherwise they can not be read. - - if (startIndex) { - result.data = firstUpSource.data.slice(0, startIndex).concat(result.data); - } - - resultMetaRawOption = { - seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN, - sourceHeader: startIndex, - dimensions: firstUpSource.metaRawOption.dimensions - }; - } else { - resultMetaRawOption = { - seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN, - sourceHeader: 0, - dimensions: result.dimensions - }; - } - - return createSource(result.data, resultMetaRawOption, null); - }); - } - - function isSupportedSourceFormat(sourceFormat) { - return sourceFormat === SOURCE_FORMAT_ARRAY_ROWS || sourceFormat === SOURCE_FORMAT_OBJECT_ROWS; - } - - var UNDEFINED = 'undefined'; - /* global Float64Array, Int32Array, Uint32Array, Uint16Array */ - // Caution: MUST not use `new CtorUint32Array(arr, 0, len)`, because the Ctor of array is - // different from the Ctor of typed array. - - var CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array; - var CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array; - var CtorInt32Array$1 = typeof Int32Array === UNDEFINED ? Array : Int32Array; - var CtorFloat64Array = typeof Float64Array === UNDEFINED ? Array : Float64Array; - /** - * Multi dimensional data store - */ - - var dataCtors = { - 'float': CtorFloat64Array, - 'int': CtorInt32Array$1, - // Ordinal data type can be string or int - 'ordinal': Array, - 'number': Array, - 'time': CtorFloat64Array - }; - var defaultDimValueGetters; - - function getIndicesCtor(rawCount) { - // The possible max value in this._indicies is always this._rawCount despite of filtering. - return rawCount > 65535 ? CtorUint32Array : CtorUint16Array; - } - - function getInitialExtent() { - return [Infinity, -Infinity]; - } - - function cloneChunk(originalChunk) { - var Ctor = originalChunk.constructor; // Only shallow clone is enough when Array. - - return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk); - } - - function prepareStore(store, dimIdx, dimType, end, append) { - var DataCtor = dataCtors[dimType || 'float']; - - if (append) { - var oldStore = store[dimIdx]; - var oldLen = oldStore && oldStore.length; - - if (!(oldLen === end)) { - var newStore = new DataCtor(end); // The cost of the copy is probably inconsiderable - // within the initial chunkSize. - - for (var j = 0; j < oldLen; j++) { - newStore[j] = oldStore[j]; - } - - store[dimIdx] = newStore; - } - } else { - store[dimIdx] = new DataCtor(end); - } - } - /** - * Basically, DataStore API keep immutable. - */ - - - var DataStore = - /** @class */ - function () { - function DataStore() { - this._chunks = []; // It will not be calculated until needed. - - this._rawExtent = []; - this._extent = []; - this._count = 0; - this._rawCount = 0; - this._calcDimNameToIdx = createHashMap(); - } - /** - * Initialize from data - */ - - - DataStore.prototype.initData = function (provider, inputDimensions, dimValueGetter) { - { - assert(isFunction(provider.getItem) && isFunction(provider.count), 'Invalid data provider.'); - } - this._provider = provider; // Clear - - this._chunks = []; - this._indices = null; - this.getRawIndex = this._getRawIdxIdentity; - var source = provider.getSource(); - var defaultGetter = this.defaultDimValueGetter = defaultDimValueGetters[source.sourceFormat]; // Default dim value getter - - this._dimValueGetter = dimValueGetter || defaultGetter; // Reset raw extent. - - this._rawExtent = []; - var willRetrieveDataByName = shouldRetrieveDataByName(source); - this._dimensions = map$1(inputDimensions, function (dim) { - { - if (willRetrieveDataByName) { - assert(dim.property != null); - } - } - return { - // Only pick these two props. Not leak other properties like orderMeta. - type: dim.type, - property: dim.property - }; - }); - - this._initDataFromProvider(0, provider.count()); - }; - - DataStore.prototype.getProvider = function () { - return this._provider; - }; - /** - * Caution: even when a `source` instance owned by a series, the created data store - * may still be shared by different sereis (the source hash does not use all `source` - * props, see `sourceManager`). In this case, the `source` props that are not used in - * hash (like `source.dimensionDefine`) probably only belongs to a certain series and - * thus should not be fetch here. - */ - - - DataStore.prototype.getSource = function () { - return this._provider.getSource(); - }; - /** - * @caution Only used in dataStack. - */ - - - DataStore.prototype.ensureCalculationDimension = function (dimName, type) { - var calcDimNameToIdx = this._calcDimNameToIdx; - var dimensions = this._dimensions; - var calcDimIdx = calcDimNameToIdx.get(dimName); - - if (calcDimIdx != null) { - if (dimensions[calcDimIdx].type === type) { - return calcDimIdx; - } - } else { - calcDimIdx = dimensions.length; - } - - dimensions[calcDimIdx] = { - type: type - }; - calcDimNameToIdx.set(dimName, calcDimIdx); - this._chunks[calcDimIdx] = new dataCtors[type || 'float'](this._rawCount); - this._rawExtent[calcDimIdx] = getInitialExtent(); - return calcDimIdx; - }; - - DataStore.prototype.collectOrdinalMeta = function (dimIdx, ordinalMeta) { - var chunk = this._chunks[dimIdx]; - var dim = this._dimensions[dimIdx]; - var rawExtents = this._rawExtent; - var offset = dim.ordinalOffset || 0; - var len = chunk.length; - - if (offset === 0) { - // We need to reset the rawExtent if collect is from start. - // Because this dimension may be guessed as number and calcuating a wrong extent. - rawExtents[dimIdx] = getInitialExtent(); - } - - var dimRawExtent = rawExtents[dimIdx]; // Parse from previous data offset. len may be changed after appendData - - for (var i = offset; i < len; i++) { - var val = chunk[i] = ordinalMeta.parseAndCollect(chunk[i]); - - if (!isNaN(val)) { - dimRawExtent[0] = Math.min(val, dimRawExtent[0]); - dimRawExtent[1] = Math.max(val, dimRawExtent[1]); - } - } - - dim.ordinalMeta = ordinalMeta; - dim.ordinalOffset = len; - dim.type = 'ordinal'; // Force to be ordinal - }; - - DataStore.prototype.getOrdinalMeta = function (dimIdx) { - var dimInfo = this._dimensions[dimIdx]; - var ordinalMeta = dimInfo.ordinalMeta; - return ordinalMeta; - }; - - DataStore.prototype.getDimensionProperty = function (dimIndex) { - var item = this._dimensions[dimIndex]; - return item && item.property; - }; - /** - * Caution: Can be only called on raw data (before `this._indices` created). - */ - - - DataStore.prototype.appendData = function (data) { - { - assert(!this._indices, 'appendData can only be called on raw data.'); - } - var provider = this._provider; - var start = this.count(); - provider.appendData(data); - var end = provider.count(); - - if (!provider.persistent) { - end += start; - } - - if (start < end) { - this._initDataFromProvider(start, end, true); - } - - return [start, end]; - }; - - DataStore.prototype.appendValues = function (values, minFillLen) { - var chunks = this._chunks; - var dimensions = this._dimensions; - var dimLen = dimensions.length; - var rawExtent = this._rawExtent; - var start = this.count(); - var end = start + Math.max(values.length, minFillLen || 0); - - for (var i = 0; i < dimLen; i++) { - var dim = dimensions[i]; - prepareStore(chunks, i, dim.type, end, true); - } - - var emptyDataItem = []; - - for (var idx = start; idx < end; idx++) { - var sourceIdx = idx - start; // Store the data by dimensions - - for (var dimIdx = 0; dimIdx < dimLen; dimIdx++) { - var dim = dimensions[dimIdx]; - var val = defaultDimValueGetters.arrayRows.call(this, values[sourceIdx] || emptyDataItem, dim.property, sourceIdx, dimIdx); - chunks[dimIdx][idx] = val; - var dimRawExtent = rawExtent[dimIdx]; - val < dimRawExtent[0] && (dimRawExtent[0] = val); - val > dimRawExtent[1] && (dimRawExtent[1] = val); - } - } - - this._rawCount = this._count = end; - return { - start: start, - end: end - }; - }; - - DataStore.prototype._initDataFromProvider = function (start, end, append) { - var provider = this._provider; - var chunks = this._chunks; - var dimensions = this._dimensions; - var dimLen = dimensions.length; - var rawExtent = this._rawExtent; - var dimNames = map$1(dimensions, function (dim) { - return dim.property; - }); - - for (var i = 0; i < dimLen; i++) { - var dim = dimensions[i]; - - if (!rawExtent[i]) { - rawExtent[i] = getInitialExtent(); - } - - prepareStore(chunks, i, dim.type, end, append); - } - - if (provider.fillStorage) { - provider.fillStorage(start, end, chunks, rawExtent); - } else { - var dataItem = []; - - for (var idx = start; idx < end; idx++) { - // NOTICE: Try not to write things into dataItem - dataItem = provider.getItem(idx, dataItem); // Each data item is value - // [1, 2] - // 2 - // Bar chart, line chart which uses category axis - // only gives the 'y' value. 'x' value is the indices of category - // Use a tempValue to normalize the value to be a (x, y) value - // Store the data by dimensions - - for (var dimIdx = 0; dimIdx < dimLen; dimIdx++) { - var dimStorage = chunks[dimIdx]; // PENDING NULL is empty or zero - - var val = this._dimValueGetter(dataItem, dimNames[dimIdx], idx, dimIdx); - - dimStorage[idx] = val; - var dimRawExtent = rawExtent[dimIdx]; - val < dimRawExtent[0] && (dimRawExtent[0] = val); - val > dimRawExtent[1] && (dimRawExtent[1] = val); - } - } - } - - if (!provider.persistent && provider.clean) { - // Clean unused data if data source is typed array. - provider.clean(); - } - - this._rawCount = this._count = end; // Reset data extent - - this._extent = []; - }; - - DataStore.prototype.count = function () { - return this._count; - }; - /** - * Get value. Return NaN if idx is out of range. - */ - - - DataStore.prototype.get = function (dim, idx) { - if (!(idx >= 0 && idx < this._count)) { - return NaN; - } - - var dimStore = this._chunks[dim]; - return dimStore ? dimStore[this.getRawIndex(idx)] : NaN; - }; - - DataStore.prototype.getValues = function (dimensions, idx) { - var values = []; - var dimArr = []; - - if (idx == null) { - idx = dimensions; // TODO get all from store? - - dimensions = []; // All dimensions - - for (var i = 0; i < this._dimensions.length; i++) { - dimArr.push(i); - } - } else { - dimArr = dimensions; - } - - for (var i = 0, len = dimArr.length; i < len; i++) { - values.push(this.get(dimArr[i], idx)); - } - - return values; - }; - /** - * @param dim concrete dim - */ - - - DataStore.prototype.getByRawIndex = function (dim, rawIdx) { - if (!(rawIdx >= 0 && rawIdx < this._rawCount)) { - return NaN; - } - - var dimStore = this._chunks[dim]; - return dimStore ? dimStore[rawIdx] : NaN; - }; - /** - * Get sum of data in one dimension - */ - - - DataStore.prototype.getSum = function (dim) { - var dimData = this._chunks[dim]; - var sum = 0; - - if (dimData) { - for (var i = 0, len = this.count(); i < len; i++) { - var value = this.get(dim, i); - - if (!isNaN(value)) { - sum += value; - } - } - } - - return sum; - }; - /** - * Get median of data in one dimension - */ - - - DataStore.prototype.getMedian = function (dim) { - var dimDataArray = []; // map all data of one dimension - - this.each([dim], function (val) { - if (!isNaN(val)) { - dimDataArray.push(val); - } - }); // TODO - // Use quick select? - - var sortedDimDataArray = dimDataArray.sort(function (a, b) { - return a - b; - }); - var len = this.count(); // calculate median - - return len === 0 ? 0 : len % 2 === 1 ? sortedDimDataArray[(len - 1) / 2] : (sortedDimDataArray[len / 2] + sortedDimDataArray[len / 2 - 1]) / 2; - }; - /** - * Retrieve the index with given raw data index. - */ - - - DataStore.prototype.indexOfRawIndex = function (rawIndex) { - if (rawIndex >= this._rawCount || rawIndex < 0) { - return -1; - } - - if (!this._indices) { - return rawIndex; - } // Indices are ascending - - - var indices = this._indices; // If rawIndex === dataIndex - - var rawDataIndex = indices[rawIndex]; - - if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) { - return rawIndex; - } - - var left = 0; - var right = this._count - 1; - - while (left <= right) { - var mid = (left + right) / 2 | 0; - - if (indices[mid] < rawIndex) { - left = mid + 1; - } else if (indices[mid] > rawIndex) { - right = mid - 1; - } else { - return mid; - } - } - - return -1; - }; - - DataStore.prototype.getIndices = function () { - var newIndices; - var indices = this._indices; - - if (indices) { - var Ctor = indices.constructor; - var thisCount = this._count; // `new Array(a, b, c)` is different from `new Uint32Array(a, b, c)`. - - if (Ctor === Array) { - newIndices = new Ctor(thisCount); - - for (var i = 0; i < thisCount; i++) { - newIndices[i] = indices[i]; - } - } else { - newIndices = new Ctor(indices.buffer, 0, thisCount); - } - } else { - var Ctor = getIndicesCtor(this._rawCount); - newIndices = new Ctor(this.count()); - - for (var i = 0; i < newIndices.length; i++) { - newIndices[i] = i; - } - } - - return newIndices; - }; - /** - * Data filter. - */ - - - DataStore.prototype.filter = function (dims, cb) { - if (!this._count) { - return this; - } - - var newStore = this.clone(); - var count = newStore.count(); - var Ctor = getIndicesCtor(newStore._rawCount); - var newIndices = new Ctor(count); - var value = []; - var dimSize = dims.length; - var offset = 0; - var dim0 = dims[0]; - var chunks = newStore._chunks; - - for (var i = 0; i < count; i++) { - var keep = void 0; - var rawIdx = newStore.getRawIndex(i); // Simple optimization - - if (dimSize === 0) { - keep = cb(i); - } else if (dimSize === 1) { - var val = chunks[dim0][rawIdx]; - keep = cb(val, i); - } else { - var k = 0; - - for (; k < dimSize; k++) { - value[k] = chunks[dims[k]][rawIdx]; - } - - value[k] = i; - keep = cb.apply(null, value); - } - - if (keep) { - newIndices[offset++] = rawIdx; - } - } // Set indices after filtered. - - - if (offset < count) { - newStore._indices = newIndices; - } - - newStore._count = offset; // Reset data extent - - newStore._extent = []; - - newStore._updateGetRawIdx(); - - return newStore; - }; - /** - * Select data in range. (For optimization of filter) - * (Manually inline code, support 5 million data filtering in data zoom.) - */ - - - DataStore.prototype.selectRange = function (range) { - var newStore = this.clone(); - var len = newStore._count; - - if (!len) { - return this; - } - - var dims = keys(range); - var dimSize = dims.length; - - if (!dimSize) { - return this; - } - - var originalCount = newStore.count(); - var Ctor = getIndicesCtor(newStore._rawCount); - var newIndices = new Ctor(originalCount); - var offset = 0; - var dim0 = dims[0]; - var min = range[dim0][0]; - var max = range[dim0][1]; - var storeArr = newStore._chunks; - var quickFinished = false; - - if (!newStore._indices) { - // Extreme optimization for common case. About 2x faster in chrome. - var idx = 0; - - if (dimSize === 1) { - var dimStorage = storeArr[dims[0]]; - - for (var i = 0; i < len; i++) { - var val = dimStorage[i]; // NaN will not be filtered. Consider the case, in line chart, empty - // value indicates the line should be broken. But for the case like - // scatter plot, a data item with empty value will not be rendered, - // but the axis extent may be effected if some other dim of the data - // item has value. Fortunately it is not a significant negative effect. - - if (val >= min && val <= max || isNaN(val)) { - newIndices[offset++] = idx; - } - - idx++; - } - - quickFinished = true; - } else if (dimSize === 2) { - var dimStorage = storeArr[dims[0]]; - var dimStorage2 = storeArr[dims[1]]; - var min2 = range[dims[1]][0]; - var max2 = range[dims[1]][1]; - - for (var i = 0; i < len; i++) { - var val = dimStorage[i]; - var val2 = dimStorage2[i]; // Do not filter NaN, see comment above. - - if ((val >= min && val <= max || isNaN(val)) && (val2 >= min2 && val2 <= max2 || isNaN(val2))) { - newIndices[offset++] = idx; - } - - idx++; - } - - quickFinished = true; - } - } - - if (!quickFinished) { - if (dimSize === 1) { - for (var i = 0; i < originalCount; i++) { - var rawIndex = newStore.getRawIndex(i); - var val = storeArr[dims[0]][rawIndex]; // Do not filter NaN, see comment above. - - if (val >= min && val <= max || isNaN(val)) { - newIndices[offset++] = rawIndex; - } - } - } else { - for (var i = 0; i < originalCount; i++) { - var keep = true; - var rawIndex = newStore.getRawIndex(i); - - for (var k = 0; k < dimSize; k++) { - var dimk = dims[k]; - var val = storeArr[dimk][rawIndex]; // Do not filter NaN, see comment above. - - if (val < range[dimk][0] || val > range[dimk][1]) { - keep = false; - } - } - - if (keep) { - newIndices[offset++] = newStore.getRawIndex(i); - } - } - } - } // Set indices after filtered. - - - if (offset < originalCount) { - newStore._indices = newIndices; - } - - newStore._count = offset; // Reset data extent - - newStore._extent = []; - - newStore._updateGetRawIdx(); - - return newStore; - }; // /** - // * Data mapping to a plain array - // */ - // mapArray(dims: DimensionIndex[], cb: MapArrayCb): any[] { - // const result: any[] = []; - // this.each(dims, function () { - // result.push(cb && (cb as MapArrayCb).apply(null, arguments)); - // }); - // return result; - // } - - /** - * Data mapping to a new List with given dimensions - */ - - - DataStore.prototype.map = function (dims, cb) { - // TODO only clone picked chunks. - var target = this.clone(dims); - - this._updateDims(target, dims, cb); - - return target; - }; - /** - * @caution Danger!! Only used in dataStack. - */ - - - DataStore.prototype.modify = function (dims, cb) { - this._updateDims(this, dims, cb); - }; - - DataStore.prototype._updateDims = function (target, dims, cb) { - var targetChunks = target._chunks; - var tmpRetValue = []; - var dimSize = dims.length; - var dataCount = target.count(); - var values = []; - var rawExtent = target._rawExtent; - - for (var i = 0; i < dims.length; i++) { - rawExtent[dims[i]] = getInitialExtent(); - } - - for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) { - var rawIndex = target.getRawIndex(dataIndex); - - for (var k = 0; k < dimSize; k++) { - values[k] = targetChunks[dims[k]][rawIndex]; - } - - values[dimSize] = dataIndex; - var retValue = cb && cb.apply(null, values); - - if (retValue != null) { - // a number or string (in oridinal dimension)? - if (typeof retValue !== 'object') { - tmpRetValue[0] = retValue; - retValue = tmpRetValue; - } - - for (var i = 0; i < retValue.length; i++) { - var dim = dims[i]; - var val = retValue[i]; - var rawExtentOnDim = rawExtent[dim]; - var dimStore = targetChunks[dim]; - - if (dimStore) { - dimStore[rawIndex] = val; - } - - if (val < rawExtentOnDim[0]) { - rawExtentOnDim[0] = val; - } - - if (val > rawExtentOnDim[1]) { - rawExtentOnDim[1] = val; - } - } - } - } - }; - /** - * Large data down sampling using largest-triangle-three-buckets - * @param {string} valueDimension - * @param {number} targetCount - */ - - - DataStore.prototype.lttbDownSample = function (valueDimension, rate) { - var target = this.clone([valueDimension], true); - var targetStorage = target._chunks; - var dimStore = targetStorage[valueDimension]; - var len = this.count(); - var sampledIndex = 0; - var frameSize = Math.floor(1 / rate); - var currentRawIndex = this.getRawIndex(0); - var maxArea; - var area; - var nextRawIndex; - var newIndices = new (getIndicesCtor(this._rawCount))(Math.min((Math.ceil(len / frameSize) + 2) * 2, len)); // First frame use the first data. - - newIndices[sampledIndex++] = currentRawIndex; - - for (var i = 1; i < len - 1; i += frameSize) { - var nextFrameStart = Math.min(i + frameSize, len - 1); - var nextFrameEnd = Math.min(i + frameSize * 2, len); - var avgX = (nextFrameEnd + nextFrameStart) / 2; - var avgY = 0; - - for (var idx = nextFrameStart; idx < nextFrameEnd; idx++) { - var rawIndex = this.getRawIndex(idx); - var y = dimStore[rawIndex]; - - if (isNaN(y)) { - continue; - } - - avgY += y; - } - - avgY /= nextFrameEnd - nextFrameStart; - var frameStart = i; - var frameEnd = Math.min(i + frameSize, len); - var pointAX = i - 1; - var pointAY = dimStore[currentRawIndex]; - maxArea = -1; - nextRawIndex = frameStart; - var firstNaNIndex = -1; - var countNaN = 0; // Find a point from current frame that construct a triangle with largest area with previous selected point - // And the average of next frame. - - for (var idx = frameStart; idx < frameEnd; idx++) { - var rawIndex = this.getRawIndex(idx); - var y = dimStore[rawIndex]; - - if (isNaN(y)) { - countNaN++; - - if (firstNaNIndex < 0) { - firstNaNIndex = rawIndex; - } - - continue; - } // Calculate triangle area over three buckets - - - area = Math.abs((pointAX - avgX) * (y - pointAY) - (pointAX - idx) * (avgY - pointAY)); - - if (area > maxArea) { - maxArea = area; - nextRawIndex = rawIndex; // Next a is this b - } - } - - if (countNaN > 0 && countNaN < frameEnd - frameStart) { - // Append first NaN point in every bucket. - // It is necessary to ensure the correct order of indices. - newIndices[sampledIndex++] = Math.min(firstNaNIndex, nextRawIndex); - nextRawIndex = Math.max(firstNaNIndex, nextRawIndex); - } - - newIndices[sampledIndex++] = nextRawIndex; - currentRawIndex = nextRawIndex; // This a is the next a (chosen b) - } // First frame use the last data. - - - newIndices[sampledIndex++] = this.getRawIndex(len - 1); - target._count = sampledIndex; - target._indices = newIndices; - target.getRawIndex = this._getRawIdx; - return target; - }; - /** - * Large data down sampling using min-max - * @param {string} valueDimension - * @param {number} rate - */ - - - DataStore.prototype.minmaxDownSample = function (valueDimension, rate) { - var target = this.clone([valueDimension], true); - var targetStorage = target._chunks; - var frameSize = Math.floor(1 / rate); - var dimStore = targetStorage[valueDimension]; - var len = this.count(); // Each frame results in 2 data points, one for min and one for max - - var newIndices = new (getIndicesCtor(this._rawCount))(Math.ceil(len / frameSize) * 2); - var offset = 0; - - for (var i = 0; i < len; i += frameSize) { - var minIndex = i; - var minValue = dimStore[this.getRawIndex(minIndex)]; - var maxIndex = i; - var maxValue = dimStore[this.getRawIndex(maxIndex)]; - var thisFrameSize = frameSize; // Handle final smaller frame - - if (i + frameSize > len) { - thisFrameSize = len - i; - } // Determine min and max within the current frame - - - for (var k = 0; k < thisFrameSize; k++) { - var rawIndex = this.getRawIndex(i + k); - var value = dimStore[rawIndex]; - - if (value < minValue) { - minValue = value; - minIndex = i + k; - } - - if (value > maxValue) { - maxValue = value; - maxIndex = i + k; - } - } - - var rawMinIndex = this.getRawIndex(minIndex); - var rawMaxIndex = this.getRawIndex(maxIndex); // Set the order of the min and max values, based on their ordering in the frame - - if (minIndex < maxIndex) { - newIndices[offset++] = rawMinIndex; - newIndices[offset++] = rawMaxIndex; - } else { - newIndices[offset++] = rawMaxIndex; - newIndices[offset++] = rawMinIndex; - } - } - - target._count = offset; - target._indices = newIndices; - - target._updateGetRawIdx(); - - return target; - }; - /** - * Large data down sampling on given dimension - * @param sampleIndex Sample index for name and id - */ - - - DataStore.prototype.downSample = function (dimension, rate, sampleValue, sampleIndex) { - var target = this.clone([dimension], true); - var targetStorage = target._chunks; - var frameValues = []; - var frameSize = Math.floor(1 / rate); - var dimStore = targetStorage[dimension]; - var len = this.count(); - var rawExtentOnDim = target._rawExtent[dimension] = getInitialExtent(); - var newIndices = new (getIndicesCtor(this._rawCount))(Math.ceil(len / frameSize)); - var offset = 0; - - for (var i = 0; i < len; i += frameSize) { - // Last frame - if (frameSize > len - i) { - frameSize = len - i; - frameValues.length = frameSize; - } - - for (var k = 0; k < frameSize; k++) { - var dataIdx = this.getRawIndex(i + k); - frameValues[k] = dimStore[dataIdx]; - } - - var value = sampleValue(frameValues); - var sampleFrameIdx = this.getRawIndex(Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)); // Only write value on the filtered data - - dimStore[sampleFrameIdx] = value; - - if (value < rawExtentOnDim[0]) { - rawExtentOnDim[0] = value; - } - - if (value > rawExtentOnDim[1]) { - rawExtentOnDim[1] = value; - } - - newIndices[offset++] = sampleFrameIdx; - } - - target._count = offset; - target._indices = newIndices; - - target._updateGetRawIdx(); - - return target; - }; - /** - * Data iteration - * @param ctx default this - * @example - * list.each('x', function (x, idx) {}); - * list.each(['x', 'y'], function (x, y, idx) {}); - * list.each(function (idx) {}) - */ - - - DataStore.prototype.each = function (dims, cb) { - if (!this._count) { - return; - } - - var dimSize = dims.length; - var chunks = this._chunks; - - for (var i = 0, len = this.count(); i < len; i++) { - var rawIdx = this.getRawIndex(i); // Simple optimization - - switch (dimSize) { - case 0: - cb(i); - break; - - case 1: - cb(chunks[dims[0]][rawIdx], i); - break; - - case 2: - cb(chunks[dims[0]][rawIdx], chunks[dims[1]][rawIdx], i); - break; - - default: - var k = 0; - var value = []; - - for (; k < dimSize; k++) { - value[k] = chunks[dims[k]][rawIdx]; - } // Index - - - value[k] = i; - cb.apply(null, value); - } - } - }; - /** - * Get extent of data in one dimension - */ - - - DataStore.prototype.getDataExtent = function (dim) { - // Make sure use concrete dim as cache name. - var dimData = this._chunks[dim]; - var initialExtent = getInitialExtent(); - - if (!dimData) { - return initialExtent; - } // Make more strict checkings to ensure hitting cache. - - - var currEnd = this.count(); // Consider the most cases when using data zoom, `getDataExtent` - // happened before filtering. We cache raw extent, which is not - // necessary to be cleared and recalculated when restore data. - - var useRaw = !this._indices; - var dimExtent; - - if (useRaw) { - return this._rawExtent[dim].slice(); - } - - dimExtent = this._extent[dim]; - - if (dimExtent) { - return dimExtent.slice(); - } - - dimExtent = initialExtent; - var min = dimExtent[0]; - var max = dimExtent[1]; - - for (var i = 0; i < currEnd; i++) { - var rawIdx = this.getRawIndex(i); - var value = dimData[rawIdx]; - value < min && (min = value); - value > max && (max = value); - } - - dimExtent = [min, max]; - this._extent[dim] = dimExtent; - return dimExtent; - }; - /** - * Get raw data item - */ - - - DataStore.prototype.getRawDataItem = function (idx) { - var rawIdx = this.getRawIndex(idx); - - if (!this._provider.persistent) { - var val = []; - var chunks = this._chunks; - - for (var i = 0; i < chunks.length; i++) { - val.push(chunks[i][rawIdx]); - } - - return val; - } else { - return this._provider.getItem(rawIdx); - } - }; - /** - * Clone shallow. - * - * @param clonedDims Determine which dims to clone. Will share the data if not specified. - */ - - - DataStore.prototype.clone = function (clonedDims, ignoreIndices) { - var target = new DataStore(); - var chunks = this._chunks; - var clonedDimsMap = clonedDims && reduce(clonedDims, function (obj, dimIdx) { - obj[dimIdx] = true; - return obj; - }, {}); - - if (clonedDimsMap) { - for (var i = 0; i < chunks.length; i++) { - // Not clone if dim is not picked. - target._chunks[i] = !clonedDimsMap[i] ? chunks[i] : cloneChunk(chunks[i]); - } - } else { - target._chunks = chunks; - } - - this._copyCommonProps(target); - - if (!ignoreIndices) { - target._indices = this._cloneIndices(); - } - - target._updateGetRawIdx(); - - return target; - }; - - DataStore.prototype._copyCommonProps = function (target) { - target._count = this._count; - target._rawCount = this._rawCount; - target._provider = this._provider; - target._dimensions = this._dimensions; - target._extent = clone$3(this._extent); - target._rawExtent = clone$3(this._rawExtent); - }; - - DataStore.prototype._cloneIndices = function () { - if (this._indices) { - var Ctor = this._indices.constructor; - var indices = void 0; - - if (Ctor === Array) { - var thisCount = this._indices.length; - indices = new Ctor(thisCount); - - for (var i = 0; i < thisCount; i++) { - indices[i] = this._indices[i]; - } - } else { - indices = new Ctor(this._indices); - } - - return indices; - } - - return null; - }; - - DataStore.prototype._getRawIdxIdentity = function (idx) { - return idx; - }; - - DataStore.prototype._getRawIdx = function (idx) { - if (idx < this._count && idx >= 0) { - return this._indices[idx]; - } - - return -1; - }; - - DataStore.prototype._updateGetRawIdx = function () { - this.getRawIndex = this._indices ? this._getRawIdx : this._getRawIdxIdentity; - }; - - DataStore.internalField = function () { - function getDimValueSimply(dataItem, property, dataIndex, dimIndex) { - return parseDataValue(dataItem[dimIndex], this._dimensions[dimIndex]); - } - - defaultDimValueGetters = { - arrayRows: getDimValueSimply, - objectRows: function (dataItem, property, dataIndex, dimIndex) { - return parseDataValue(dataItem[property], this._dimensions[dimIndex]); - }, - keyedColumns: getDimValueSimply, - original: function (dataItem, property, dataIndex, dimIndex) { - // Performance sensitive, do not use modelUtil.getDataItemValue. - // If dataItem is an plain object with no value field, the let `value` - // will be assigned with the object, but it will be tread correctly - // in the `convertValue`. - var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value); - return parseDataValue(value instanceof Array ? value[dimIndex] // If value is a single number or something else not array. - : value, this._dimensions[dimIndex]); - }, - typedArray: function (dataItem, property, dataIndex, dimIndex) { - return dataItem[dimIndex]; - } - }; - }(); - - return DataStore; - }(); - /** - * [REQUIREMENT_MEMO]: - * (0) `metaRawOption` means `dimensions`/`sourceHeader`/`seriesLayoutBy` in raw option. - * (1) Keep support the feature: `metaRawOption` can be specified both on `series` and - * `root-dataset`. Them on `series` has higher priority. - * (2) Do not support to set `metaRawOption` on a `non-root-dataset`, because it might - * confuse users: whether those props indicate how to visit the upstream source or visit - * the transform result source, and some transforms has nothing to do with these props, - * and some transforms might have multiple upstream. - * (3) Transforms should specify `metaRawOption` in each output, just like they can be - * declared in `root-dataset`. - * (4) At present only support visit source in `SERIES_LAYOUT_BY_COLUMN` in transforms. - * That is for reducing complexity in transforms. - * PENDING: Whether to provide transposition transform? - * - * [IMPLEMENTAION_MEMO]: - * "sourceVisitConfig" are calculated from `metaRawOption` and `data`. - * They will not be calculated until `source` is about to be visited (to prevent from - * duplicate calcuation). `source` is visited only in series and input to transforms. - * - * [DIMENSION_INHERIT_RULE]: - * By default the dimensions are inherited from ancestors, unless a transform return - * a new dimensions definition. - * Consider the case: - * ```js - * dataset: [{ - * source: [ ['Product', 'Sales', 'Prise'], ['Cookies', 321, 44.21], ...] - * }, { - * transform: { type: 'filter', ... } - * }] - * dataset: [{ - * dimension: ['Product', 'Sales', 'Prise'], - * source: [ ['Cookies', 321, 44.21], ...] - * }, { - * transform: { type: 'filter', ... } - * }] - * ``` - * The two types of option should have the same behavior after transform. - * - * - * [SCENARIO]: - * (1) Provide source data directly: - * ```js - * series: { - * encode: {...}, - * dimensions: [...] - * seriesLayoutBy: 'row', - * data: [[...]] - * } - * ``` - * (2) Series refer to dataset. - * ```js - * series: [{ - * encode: {...} - * // Ignore datasetIndex means `datasetIndex: 0` - * // and the dimensions defination in dataset is used - * }, { - * encode: {...}, - * seriesLayoutBy: 'column', - * datasetIndex: 1 - * }] - * ``` - * (3) dataset transform - * ```js - * dataset: [{ - * source: [...] - * }, { - * source: [...] - * }, { - * // By default from 0. - * transform: { type: 'filter', config: {...} } - * }, { - * // Piped. - * transform: [ - * { type: 'filter', config: {...} }, - * { type: 'sort', config: {...} } - * ] - * }, { - * id: 'regressionData', - * fromDatasetIndex: 1, - * // Third-party transform - * transform: { type: 'ecStat:regression', config: {...} } - * }, { - * // retrieve the extra result. - * id: 'regressionFormula', - * fromDatasetId: 'regressionData', - * fromTransformResult: 1 - * }] - * ``` - */ - - - var SourceManager = - /** @class */ - function () { - function SourceManager(sourceHost) { - // Cached source. Do not repeat calculating if not dirty. - this._sourceList = []; - this._storeList = []; // version sign of each upstream source manager. - - this._upstreamSignList = []; - this._versionSignBase = 0; - this._dirty = true; - this._sourceHost = sourceHost; - } - /** - * Mark dirty. - */ - - - SourceManager.prototype.dirty = function () { - this._setLocalSource([], []); - - this._storeList = []; - this._dirty = true; - }; - - SourceManager.prototype._setLocalSource = function (sourceList, upstreamSignList) { - this._sourceList = sourceList; - this._upstreamSignList = upstreamSignList; - this._versionSignBase++; - - if (this._versionSignBase > 9e10) { - this._versionSignBase = 0; - } - }; - /** - * For detecting whether the upstream source is dirty, so that - * the local cached source (in `_sourceList`) should be discarded. - */ - - - SourceManager.prototype._getVersionSign = function () { - return this._sourceHost.uid + '_' + this._versionSignBase; - }; - /** - * Always return a source instance. Otherwise throw error. - */ - - - SourceManager.prototype.prepareSource = function () { - // For the case that call `setOption` multiple time but no data changed, - // cache the result source to prevent from repeating transform. - if (this._isDirty()) { - this._createSource(); - - this._dirty = false; - } - }; - - SourceManager.prototype._createSource = function () { - this._setLocalSource([], []); - - var sourceHost = this._sourceHost; - - var upSourceMgrList = this._getUpstreamSourceManagers(); - - var hasUpstream = !!upSourceMgrList.length; - var resultSourceList; - var upstreamSignList; - - if (isSeries(sourceHost)) { - var seriesModel = sourceHost; - var data = void 0; - var sourceFormat = void 0; - var upSource = void 0; // Has upstream dataset - - if (hasUpstream) { - var upSourceMgr = upSourceMgrList[0]; - upSourceMgr.prepareSource(); - upSource = upSourceMgr.getSource(); - data = upSource.data; - sourceFormat = upSource.sourceFormat; - upstreamSignList = [upSourceMgr._getVersionSign()]; - } // Series data is from own. - else { - data = seriesModel.get('data', true); - sourceFormat = isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL; - upstreamSignList = []; - } // See [REQUIREMENT_MEMO], merge settings on series and parent dataset if it is root. - - - var newMetaRawOption = this._getSourceMetaRawOption() || {}; - var upMetaRawOption = upSource && upSource.metaRawOption || {}; - var seriesLayoutBy = retrieve2(newMetaRawOption.seriesLayoutBy, upMetaRawOption.seriesLayoutBy) || null; - var sourceHeader = retrieve2(newMetaRawOption.sourceHeader, upMetaRawOption.sourceHeader); // Note here we should not use `upSource.dimensionsDefine`. Consider the case: - // `upSource.dimensionsDefine` is detected by `seriesLayoutBy: 'column'`, - // but series need `seriesLayoutBy: 'row'`. - - var dimensions = retrieve2(newMetaRawOption.dimensions, upMetaRawOption.dimensions); // We share source with dataset as much as possible - // to avoid extra memory cost of high dimensional data. - - var needsCreateSource = seriesLayoutBy !== upMetaRawOption.seriesLayoutBy || !!sourceHeader !== !!upMetaRawOption.sourceHeader || dimensions; - resultSourceList = needsCreateSource ? [createSource(data, { - seriesLayoutBy: seriesLayoutBy, - sourceHeader: sourceHeader, - dimensions: dimensions - }, sourceFormat)] : []; - } else { - var datasetModel = sourceHost; // Has upstream dataset. - - if (hasUpstream) { - var result = this._applyTransform(upSourceMgrList); - - resultSourceList = result.sourceList; - upstreamSignList = result.upstreamSignList; - } // Is root dataset. - else { - var sourceData = datasetModel.get('source', true); - resultSourceList = [createSource(sourceData, this._getSourceMetaRawOption(), null)]; - upstreamSignList = []; - } - } - - { - assert(resultSourceList && upstreamSignList); - } - - this._setLocalSource(resultSourceList, upstreamSignList); - }; - - SourceManager.prototype._applyTransform = function (upMgrList) { - var datasetModel = this._sourceHost; - var transformOption = datasetModel.get('transform', true); - var fromTransformResult = datasetModel.get('fromTransformResult', true); - { - assert(fromTransformResult != null || transformOption != null); - } - - if (fromTransformResult != null) { - var errMsg = ''; - - if (upMgrList.length !== 1) { - { - errMsg = 'When using `fromTransformResult`, there should be only one upstream dataset'; - } - doThrow(errMsg); - } - } - - var sourceList; - var upSourceList = []; - var upstreamSignList = []; - each$4(upMgrList, function (upMgr) { - upMgr.prepareSource(); - var upSource = upMgr.getSource(fromTransformResult || 0); - var errMsg = ''; - - if (fromTransformResult != null && !upSource) { - { - errMsg = 'Can not retrieve result by `fromTransformResult`: ' + fromTransformResult; - } - doThrow(errMsg); - } - - upSourceList.push(upSource); - upstreamSignList.push(upMgr._getVersionSign()); - }); - - if (transformOption) { - sourceList = applyDataTransform(transformOption, upSourceList, { - datasetIndex: datasetModel.componentIndex - }); - } else if (fromTransformResult != null) { - sourceList = [cloneSourceShallow(upSourceList[0])]; - } - - return { - sourceList: sourceList, - upstreamSignList: upstreamSignList - }; - }; - - SourceManager.prototype._isDirty = function () { - if (this._dirty) { - return true; - } // All sourceList is from the some upstream. - - - var upSourceMgrList = this._getUpstreamSourceManagers(); - - for (var i = 0; i < upSourceMgrList.length; i++) { - var upSrcMgr = upSourceMgrList[i]; - - if ( // Consider the case that there is ancestor diry, call it recursively. - // The performance is probably not an issue because usually the chain is not long. - upSrcMgr._isDirty() || this._upstreamSignList[i] !== upSrcMgr._getVersionSign()) { - return true; - } - } - }; - /** - * @param sourceIndex By default 0, means "main source". - * In most cases there is only one source. - */ - - - SourceManager.prototype.getSource = function (sourceIndex) { - sourceIndex = sourceIndex || 0; - var source = this._sourceList[sourceIndex]; - - if (!source) { - // Series may share source instance with dataset. - var upSourceMgrList = this._getUpstreamSourceManagers(); - - return upSourceMgrList[0] && upSourceMgrList[0].getSource(sourceIndex); - } - - return source; - }; - /** - * - * Get a data store which can be shared across series. - * Only available for series. - * - * @param seriesDimRequest Dimensions that are generated in series. - * Should have been sorted by `storeDimIndex` asc. - */ - - - SourceManager.prototype.getSharedDataStore = function (seriesDimRequest) { - { - assert(isSeries(this._sourceHost), 'Can only call getDataStore on series source manager.'); - } - var schema = seriesDimRequest.makeStoreSchema(); - return this._innerGetDataStore(schema.dimensions, seriesDimRequest.source, schema.hash); - }; - - SourceManager.prototype._innerGetDataStore = function (storeDims, seriesSource, sourceReadKey) { - // TODO Can use other sourceIndex? - var sourceIndex = 0; - var storeList = this._storeList; - var cachedStoreMap = storeList[sourceIndex]; - - if (!cachedStoreMap) { - cachedStoreMap = storeList[sourceIndex] = {}; - } - - var cachedStore = cachedStoreMap[sourceReadKey]; - - if (!cachedStore) { - var upSourceMgr = this._getUpstreamSourceManagers()[0]; - - if (isSeries(this._sourceHost) && upSourceMgr) { - cachedStore = upSourceMgr._innerGetDataStore(storeDims, seriesSource, sourceReadKey); - } else { - cachedStore = new DataStore(); // Always create store from source of series. - - cachedStore.initData(new DefaultDataProvider(seriesSource, storeDims.length), storeDims); - } - - cachedStoreMap[sourceReadKey] = cachedStore; - } - - return cachedStore; - }; - /** - * PENDING: Is it fast enough? - * If no upstream, return empty array. - */ - - - SourceManager.prototype._getUpstreamSourceManagers = function () { - // Always get the relationship from the raw option. - // Do not cache the link of the dependency graph, so that - // there is no need to update them when change happens. - var sourceHost = this._sourceHost; - - if (isSeries(sourceHost)) { - var datasetModel = querySeriesUpstreamDatasetModel(sourceHost); - return !datasetModel ? [] : [datasetModel.getSourceManager()]; - } else { - return map$1(queryDatasetUpstreamDatasetModels(sourceHost), function (datasetModel) { - return datasetModel.getSourceManager(); - }); - } - }; - - SourceManager.prototype._getSourceMetaRawOption = function () { - var sourceHost = this._sourceHost; - var seriesLayoutBy; - var sourceHeader; - var dimensions; - - if (isSeries(sourceHost)) { - seriesLayoutBy = sourceHost.get('seriesLayoutBy', true); - sourceHeader = sourceHost.get('sourceHeader', true); - dimensions = sourceHost.get('dimensions', true); - } // See [REQUIREMENT_MEMO], `non-root-dataset` do not support them. - else if (!this._getUpstreamSourceManagers().length) { - var model = sourceHost; - seriesLayoutBy = model.get('seriesLayoutBy', true); - sourceHeader = model.get('sourceHeader', true); - dimensions = model.get('dimensions', true); - } - - return { - seriesLayoutBy: seriesLayoutBy, - sourceHeader: sourceHeader, - dimensions: dimensions - }; - }; - - return SourceManager; - }(); // Call this method after `super.init` and `super.mergeOption` to - // disable the transform merge, but do not disable transform clone from rawOption. - - - function disableTransformOptionMerge(datasetModel) { - var transformOption = datasetModel.option.transform; - transformOption && setAsPrimitive(datasetModel.option.transform); - } - - function isSeries(sourceHost) { - // Avoid circular dependency with Series.ts - return sourceHost.mainType === 'series'; - } - - function doThrow(errMsg) { - throw new Error(errMsg); - } - - var TOOLTIP_LINE_HEIGHT_CSS = 'line-height:1'; - - function getTooltipLineHeight(textStyle) { - var lineHeight = textStyle.lineHeight; - - if (lineHeight == null) { - return TOOLTIP_LINE_HEIGHT_CSS; - } else { - return "line-height:" + encodeHTML(lineHeight + '') + "px"; - } - } // TODO: more textStyle option - - - function getTooltipTextStyle(textStyle, renderMode) { - var nameFontColor = textStyle.color || tokens.color.tertiary; - var nameFontSize = textStyle.fontSize || 12; - var nameFontWeight = textStyle.fontWeight || '400'; - var valueFontColor = textStyle.color || tokens.color.secondary; - var valueFontSize = textStyle.fontSize || 14; - var valueFontWeight = textStyle.fontWeight || '900'; - - if (renderMode === 'html') { - // `textStyle` is probably from user input, should be encoded to reduce security risk. - return { - // eslint-disable-next-line max-len - nameStyle: "font-size:" + encodeHTML(nameFontSize + '') + "px;color:" + encodeHTML(nameFontColor) + ";font-weight:" + encodeHTML(nameFontWeight + ''), - // eslint-disable-next-line max-len - valueStyle: "font-size:" + encodeHTML(valueFontSize + '') + "px;color:" + encodeHTML(valueFontColor) + ";font-weight:" + encodeHTML(valueFontWeight + '') - }; - } else { - return { - nameStyle: { - fontSize: nameFontSize, - fill: nameFontColor, - fontWeight: nameFontWeight - }, - valueStyle: { - fontSize: valueFontSize, - fill: valueFontColor, - fontWeight: valueFontWeight - } - }; - } - } // See `TooltipMarkupLayoutIntent['innerGapLevel']`. - // (value from UI design) - - - var HTML_GAPS = [0, 10, 20, 30]; - var RICH_TEXT_GAPS = ['', '\n', '\n\n', '\n\n\n']; // eslint-disable-next-line max-len - - function createTooltipMarkup(type, option) { - option.type = type; - return option; - } - - function isSectionFragment(frag) { - return frag.type === 'section'; - } - - function getBuilder(frag) { - return isSectionFragment(frag) ? buildSection : buildNameValue; - } - - function getBlockGapLevel(frag) { - if (isSectionFragment(frag)) { - var gapLevel_1 = 0; - var subBlockLen = frag.blocks.length; - var hasInnerGap_1 = subBlockLen > 1 || subBlockLen > 0 && !frag.noHeader; - each$4(frag.blocks, function (subBlock) { - var subGapLevel = getBlockGapLevel(subBlock); // If the some of the sub-blocks have some gaps (like 10px) inside, this block - // should use a larger gap (like 20px) to distinguish those sub-blocks. - - if (subGapLevel >= gapLevel_1) { - gapLevel_1 = subGapLevel + +(hasInnerGap_1 && ( // 0 always can not be readable gap level. - !subGapLevel // If no header, always keep the sub gap level. Otherwise - // look weird in case `multipleSeries`. - || isSectionFragment(subBlock) && !subBlock.noHeader)); - } - }); - return gapLevel_1; - } - - return 0; - } - - function buildSection(ctx, fragment, topMarginForOuterGap, toolTipTextStyle) { - var noHeader = fragment.noHeader; - var gaps = getGap(getBlockGapLevel(fragment)); - var subMarkupTextList = []; - var subBlocks = fragment.blocks || []; - assert(!subBlocks || isArray(subBlocks)); - subBlocks = subBlocks || []; - var orderMode = ctx.orderMode; - - if (fragment.sortBlocks && orderMode) { - subBlocks = subBlocks.slice(); - var orderMap = { - valueAsc: 'asc', - valueDesc: 'desc' - }; - - if (hasOwn(orderMap, orderMode)) { - var comparator_1 = new SortOrderComparator(orderMap[orderMode], null); - subBlocks.sort(function (a, b) { - return comparator_1.evaluate(a.sortParam, b.sortParam); - }); - } // FIXME 'seriesDesc' necessary? - else if (orderMode === 'seriesDesc') { - subBlocks.reverse(); - } - } - - each$4(subBlocks, function (subBlock, idx) { - var valueFormatter = fragment.valueFormatter; - var subMarkupText = getBuilder(subBlock)( // Inherit valueFormatter - valueFormatter ? extend(extend({}, ctx), { - valueFormatter: valueFormatter - }) : ctx, subBlock, idx > 0 ? gaps.html : 0, toolTipTextStyle); - subMarkupText != null && subMarkupTextList.push(subMarkupText); - }); - var subMarkupText = ctx.renderMode === 'richText' ? subMarkupTextList.join(gaps.richText) : wrapBlockHTML(toolTipTextStyle, subMarkupTextList.join(''), noHeader ? topMarginForOuterGap : gaps.html); - - if (noHeader) { - return subMarkupText; - } - - var displayableHeader = makeValueReadable(fragment.header, 'ordinal', ctx.useUTC); - var nameStyle = getTooltipTextStyle(toolTipTextStyle, ctx.renderMode).nameStyle; - var tooltipLineHeight = getTooltipLineHeight(toolTipTextStyle); - - if (ctx.renderMode === 'richText') { - return wrapInlineNameRichText(ctx, displayableHeader, nameStyle) + gaps.richText + subMarkupText; - } else { - return wrapBlockHTML(toolTipTextStyle, "
" + encodeHTML(displayableHeader) + '
' + subMarkupText, topMarginForOuterGap); - } - } - - function buildNameValue(ctx, fragment, topMarginForOuterGap, toolTipTextStyle) { - var renderMode = ctx.renderMode; - var noName = fragment.noName; - var noValue = fragment.noValue; - var noMarker = !fragment.markerType; - var name = fragment.name; - var useUTC = ctx.useUTC; - - var valueFormatter = fragment.valueFormatter || ctx.valueFormatter || function (value) { - value = isArray(value) ? value : [value]; - return map$1(value, function (val, idx) { - return makeValueReadable(val, isArray(valueTypeOption) ? valueTypeOption[idx] : valueTypeOption, useUTC); - }); - }; - - if (noName && noValue) { - return; - } - - var markerStr = noMarker ? '' : ctx.markupStyleCreator.makeTooltipMarker(fragment.markerType, fragment.markerColor || tokens.color.secondary, renderMode); - var readableName = noName ? '' : makeValueReadable(name, 'ordinal', useUTC); - var valueTypeOption = fragment.valueType; - var readableValueList = noValue ? [] : valueFormatter(fragment.value, fragment.dataIndex); - var valueAlignRight = !noMarker || !noName; // It little weird if only value next to marker but far from marker. - - var valueCloseToMarker = !noMarker && noName; - - var _a = getTooltipTextStyle(toolTipTextStyle, renderMode), - nameStyle = _a.nameStyle, - valueStyle = _a.valueStyle; - - return renderMode === 'richText' ? (noMarker ? '' : markerStr) + (noName ? '' : wrapInlineNameRichText(ctx, readableName, nameStyle)) // Value has commas inside, so use ' ' as delimiter for multiple values. - + (noValue ? '' : wrapInlineValueRichText(ctx, readableValueList, valueAlignRight, valueCloseToMarker, valueStyle)) : wrapBlockHTML(toolTipTextStyle, (noMarker ? '' : markerStr) + (noName ? '' : wrapInlineNameHTML(readableName, !noMarker, nameStyle)) + (noValue ? '' : wrapInlineValueHTML(readableValueList, valueAlignRight, valueCloseToMarker, valueStyle)), topMarginForOuterGap); - } - /** - * @return markupText. null/undefined means no content. - */ - - - function buildTooltipMarkup(fragment, markupStyleCreator, renderMode, orderMode, useUTC, toolTipTextStyle) { - if (!fragment) { - return; - } - - var builder = getBuilder(fragment); - var ctx = { - useUTC: useUTC, - renderMode: renderMode, - orderMode: orderMode, - markupStyleCreator: markupStyleCreator, - valueFormatter: fragment.valueFormatter - }; - return builder(ctx, fragment, 0, toolTipTextStyle); - } - - function getGap(gapLevel) { - return { - html: HTML_GAPS[gapLevel], - richText: RICH_TEXT_GAPS[gapLevel] - }; - } - - function wrapBlockHTML(textStyle, encodedContent, topGap) { - var clearfix = '
'; - var marginCSS = "margin: " + topGap + "px 0 0"; - var tooltipLineHeight = getTooltipLineHeight(textStyle); - return "
" + encodedContent + clearfix + '
'; - } - - function wrapInlineNameHTML(name, leftHasMarker, style) { - var marginCss = leftHasMarker ? 'margin-left:2px' : ''; - return "" + encodeHTML(name) + ''; - } - - function wrapInlineValueHTML(valueList, alignRight, valueCloseToMarker, style) { - // Do not too close to marker, considering there are multiple values separated by spaces. - var paddingStr = valueCloseToMarker ? '10px' : '20px'; - var alignCSS = alignRight ? "float:right;margin-left:" + paddingStr : ''; - valueList = isArray(valueList) ? valueList : [valueList]; - return "" // Value has commas inside, so use ' ' as delimiter for multiple values. - + map$1(valueList, function (value) { - return encodeHTML(value); - }).join('  ') + ''; - } - - function wrapInlineNameRichText(ctx, name, style) { - return ctx.markupStyleCreator.wrapRichTextStyle(name, style); - } - - function wrapInlineValueRichText(ctx, values, alignRight, valueCloseToMarker, style) { - var styles = [style]; - var paddingLeft = valueCloseToMarker ? 10 : 20; - alignRight && styles.push({ - padding: [0, 0, 0, paddingLeft], - align: 'right' - }); // Value has commas inside, so use ' ' as delimiter for multiple values. - - return ctx.markupStyleCreator.wrapRichTextStyle(isArray(values) ? values.join(' ') : values, styles); - } - - function retrieveVisualColorForTooltipMarker(series, dataIndex) { - var style = series.getData().getItemVisual(dataIndex, 'style'); - var color = style[series.visualDrawType]; - return convertToColorString(color); - } - - function getPaddingFromTooltipModel(model, renderMode) { - var padding = model.get('padding'); - return padding != null ? padding // We give slightly different to look pretty. - : renderMode === 'richText' ? [8, 10] : 10; - } - /** - * The major feature is generate styles for `renderMode: 'richText'`. - * But it also serves `renderMode: 'html'` to provide - * "renderMode-independent" API. - */ - - - var TooltipMarkupStyleCreator = - /** @class */ - function () { - function TooltipMarkupStyleCreator() { - this.richTextStyles = {}; // Notice that "generate a style name" usually happens repeatedly when mouse is moving and - // a tooltip is displayed. So we put the `_nextStyleNameId` as a member of each creator - // rather than static shared by all creators (which will cause it increase to fast). - - this._nextStyleNameId = getRandomIdBase(); - } - - TooltipMarkupStyleCreator.prototype._generateStyleName = function () { - return '__EC_aUTo_' + this._nextStyleNameId++; - }; - - TooltipMarkupStyleCreator.prototype.makeTooltipMarker = function (markerType, colorStr, renderMode) { - var markerId = renderMode === 'richText' ? this._generateStyleName() : null; - var marker = getTooltipMarker({ - color: colorStr, - type: markerType, - renderMode: renderMode, - markerId: markerId - }); - - if (isString(marker)) { - return marker; - } else { - { - assert(markerId); - } - this.richTextStyles[markerId] = marker.style; - return marker.content; - } - }; - /** - * @usage - * ```ts - * const styledText = markupStyleCreator.wrapRichTextStyle([ - * // The styles will be auto merged. - * { - * fontSize: 12, - * color: 'blue' - * }, - * { - * padding: 20 - * } - * ]); - * ``` - */ - - - TooltipMarkupStyleCreator.prototype.wrapRichTextStyle = function (text, styles) { - var finalStl = {}; - - if (isArray(styles)) { - each$4(styles, function (stl) { - return extend(finalStl, stl); - }); - } else { - extend(finalStl, styles); - } - - var styleName = this._generateStyleName(); - - this.richTextStyles[styleName] = finalStl; - return "{" + styleName + "|" + text + "}"; - }; - - return TooltipMarkupStyleCreator; - }(); - - function defaultSeriesFormatTooltip(opt) { - var series = opt.series; - var dataIndex = opt.dataIndex; - var multipleSeries = opt.multipleSeries; - var data = series.getData(); - var tooltipDims = data.mapDimensionsAll('defaultedTooltip'); - var tooltipDimLen = tooltipDims.length; - var value = series.getRawValue(dataIndex); - var isValueArr = isArray(value); - var markerColor = retrieveVisualColorForTooltipMarker(series, dataIndex); // Complicated rule for pretty tooltip. - - var inlineValue; - var inlineValueType; - var subBlocks; - var sortParam; - - if (tooltipDimLen > 1 || isValueArr && !tooltipDimLen) { - var formatArrResult = formatTooltipArrayValue(value, series, dataIndex, tooltipDims, markerColor); - inlineValue = formatArrResult.inlineValues; - inlineValueType = formatArrResult.inlineValueTypes; - subBlocks = formatArrResult.blocks; // Only support tooltip sort by the first inline value. It's enough in most cases. - - sortParam = formatArrResult.inlineValues[0]; - } else if (tooltipDimLen) { - var dimInfo = data.getDimensionInfo(tooltipDims[0]); - sortParam = inlineValue = retrieveRawValue(data, dataIndex, tooltipDims[0]); - inlineValueType = dimInfo.type; - } else { - sortParam = inlineValue = isValueArr ? value[0] : value; - } // Do not show generated series name. It might not be readable. - - - var seriesNameSpecified = isNameSpecified(series); - var seriesName = seriesNameSpecified && series.name || ''; - var itemName = data.getName(dataIndex); - var inlineName = multipleSeries ? seriesName : itemName; - return createTooltipMarkup('section', { - header: seriesName, - // When series name is not specified, do not show a header line with only '-'. - // This case always happens in tooltip.trigger: 'item'. - noHeader: multipleSeries || !seriesNameSpecified, - sortParam: sortParam, - blocks: [createTooltipMarkup('nameValue', { - markerType: 'item', - markerColor: markerColor, - // Do not mix display seriesName and itemName in one tooltip, - // which might confuses users. - name: inlineName, - // name dimension might be auto assigned, where the name might - // be not readable. So we check trim here. - noName: !trim(inlineName), - value: inlineValue, - valueType: inlineValueType, - dataIndex: dataIndex - })].concat(subBlocks || []) - }); - } - - function formatTooltipArrayValue(value, series, dataIndex, tooltipDims, colorStr) { - // check: category-no-encode-has-axis-data in dataset.html - var data = series.getData(); - var isValueMultipleLine = reduce(value, function (isValueMultipleLine, val, idx) { - var dimItem = data.getDimensionInfo(idx); - return isValueMultipleLine = isValueMultipleLine || dimItem && dimItem.tooltip !== false && dimItem.displayName != null; - }, false); - var inlineValues = []; - var inlineValueTypes = []; - var blocks = []; - tooltipDims.length ? each$4(tooltipDims, function (dim) { - setEachItem(retrieveRawValue(data, dataIndex, dim), dim); - }) // By default, all dims is used on tooltip. - : each$4(value, setEachItem); - - function setEachItem(val, dim) { - var dimInfo = data.getDimensionInfo(dim); // If `dimInfo.tooltip` is not set, show tooltip. - - if (!dimInfo || dimInfo.otherDims.tooltip === false) { - return; - } - - if (isValueMultipleLine) { - blocks.push(createTooltipMarkup('nameValue', { - markerType: 'subItem', - markerColor: colorStr, - name: dimInfo.displayName, - value: val, - valueType: dimInfo.type - })); - } else { - inlineValues.push(val); - inlineValueTypes.push(dimInfo.type); - } - } - - return { - inlineValues: inlineValues, - inlineValueTypes: inlineValueTypes, - blocks: blocks - }; - } - - var inner$a = makeInner(); - - function getSelectionKey(data, dataIndex) { - return data.getName(dataIndex) || data.getId(dataIndex); - } - - var SERIES_UNIVERSAL_TRANSITION_PROP = '__universalTransitionEnabled'; - - var SeriesModel = - /** @class */ - function (_super) { - __extends(SeriesModel, _super); - - function SeriesModel() { - // [Caution]: Because this class or desecendants can be used as `XXX.extend(subProto)`, - // the class members must not be initialized in constructor or declaration place. - // Otherwise there is bad case: - // class A {xxx = 1;} - // enableClassExtend(A); - // class B extends A {} - // var C = B.extend({xxx: 5}); - // var c = new C(); - // console.log(c.xxx); // expect 5 but always 1. - var _this = _super !== null && _super.apply(this, arguments) || this; // --------------------------------------- - // Props about data selection - // --------------------------------------- - - - _this._selectedDataIndicesMap = {}; - return _this; - } - - SeriesModel.prototype.init = function (option, parentModel, ecModel) { - this.seriesIndex = this.componentIndex; - this.dataTask = createTask({ - count: dataTaskCount, - reset: dataTaskReset - }); - this.dataTask.context = { - model: this - }; - this.mergeDefaultAndTheme(option, ecModel); - var sourceManager = inner$a(this).sourceManager = new SourceManager(this); - sourceManager.prepareSource(); - var data = this.getInitialData(option, ecModel); - wrapData(data, this); - this.dataTask.context.data = data; - { - assert(data, 'getInitialData returned invalid data.'); - } - inner$a(this).dataBeforeProcessed = data; // If we reverse the order (make data firstly, and then make - // dataBeforeProcessed by cloneShallow), cloneShallow will - // cause data.graph.data !== data when using - // module:echarts/data/Graph or module:echarts/data/Tree. - // See module:echarts/data/helper/linkSeriesData - // Theoretically, it is unreasonable to call `seriesModel.getData()` in the model - // init or merge stage, because the data can be restored. So we do not `restoreData` - // and `setData` here, which forbids calling `seriesModel.getData()` in this stage. - // Call `seriesModel.getRawData()` instead. - // this.restoreData(); - - autoSeriesName(this); - - this._initSelectedMapFromData(data); - }; - /** - * Util for merge default and theme to option - */ - - - SeriesModel.prototype.mergeDefaultAndTheme = function (option, ecModel) { - var layoutMode = fetchLayoutMode(this); - var inputPositionParams = layoutMode ? getLayoutParams(option) : {}; // Backward compat: using subType on theme. - // But if name duplicate between series subType - // (for example: parallel) add component mainType, - // add suffix 'Series'. - - var themeSubType = this.subType; - - if (ComponentModel.hasClass(themeSubType)) { - themeSubType += 'Series'; - } - - merge(option, ecModel.getTheme().get(this.subType)); - merge(option, this.getDefaultOption()); // Default label emphasis `show` - - defaultEmphasis(option, 'label', ['show']); - this.fillDataTextStyle(option.data); - - if (layoutMode) { - mergeLayoutParam(option, inputPositionParams, layoutMode); - } - }; - - SeriesModel.prototype.mergeOption = function (newSeriesOption, ecModel) { - // this.settingTask.dirty(); - newSeriesOption = merge(this.option, newSeriesOption, true); - this.fillDataTextStyle(newSeriesOption.data); - var layoutMode = fetchLayoutMode(this); - - if (layoutMode) { - mergeLayoutParam(this.option, newSeriesOption, layoutMode); - } - - var sourceManager = inner$a(this).sourceManager; - sourceManager.dirty(); - sourceManager.prepareSource(); - var data = this.getInitialData(newSeriesOption, ecModel); - wrapData(data, this); - this.dataTask.dirty(); - this.dataTask.context.data = data; - inner$a(this).dataBeforeProcessed = data; - autoSeriesName(this); - - this._initSelectedMapFromData(data); - }; - - SeriesModel.prototype.fillDataTextStyle = function (data) { - // Default data label emphasis `show` - // FIXME Tree structure data ? - // FIXME Performance ? - if (data && !isTypedArray(data)) { - var props = ['show']; - - for (var i = 0; i < data.length; i++) { - if (data[i] && data[i].label) { - defaultEmphasis(data[i], 'label', props); - } - } - } - }; - /** - * Init a data structure from data related option in series - * Must be overridden. - */ - - - SeriesModel.prototype.getInitialData = function (option, ecModel) { - return; - }; - /** - * Append data to list - */ - - - SeriesModel.prototype.appendData = function (params) { - // FIXME ??? - // (1) If data from dataset, forbidden append. - // (2) support append data of dataset. - var data = this.getRawData(); - data.appendData(params.data); - }; - /** - * Consider some method like `filter`, `map` need make new data, - * We should make sure that `seriesModel.getData()` get correct - * data in the stream procedure. So we fetch data from upstream - * each time `task.perform` called. - */ - - - SeriesModel.prototype.getData = function (dataType) { - var task = getCurrentTask(this); - - if (task) { - var data = task.context.data; - return dataType == null || !data.getLinkedData ? data : data.getLinkedData(dataType); - } else { - // When series is not alive (that may happen when click toolbox - // restore or setOption with not merge mode), series data may - // be still need to judge animation or something when graphic - // elements want to know whether fade out. - return inner$a(this).data; - } - }; - - SeriesModel.prototype.getAllData = function () { - var mainData = this.getData(); - return mainData && mainData.getLinkedDataAll ? mainData.getLinkedDataAll() : [{ - data: mainData - }]; - }; - - SeriesModel.prototype.setData = function (data) { - var task = getCurrentTask(this); - - if (task) { - var context = task.context; // Consider case: filter, data sample. - // FIXME:TS never used, so comment it - // if (context.data !== data && task.modifyOutputEnd) { - // task.setOutputEnd(data.count()); - // } - - context.outputData = data; // Caution: setData should update context.data, - // Because getData may be called multiply in a - // single stage and expect to get the data just - // set. (For example, AxisProxy, x y both call - // getData and setDate sequentially). - // So the context.data should be fetched from - // upstream each time when a stage starts to be - // performed. - - if (task !== this.dataTask) { - context.data = data; - } - } - - inner$a(this).data = data; - }; - - SeriesModel.prototype.getEncode = function () { - var encode = this.get('encode', true); - - if (encode) { - return createHashMap(encode); - } - }; - - SeriesModel.prototype.getSourceManager = function () { - return inner$a(this).sourceManager; - }; - - SeriesModel.prototype.getSource = function () { - return this.getSourceManager().getSource(); - }; - /** - * Get data before processed - */ - - - SeriesModel.prototype.getRawData = function () { - return inner$a(this).dataBeforeProcessed; - }; - - SeriesModel.prototype.getColorBy = function () { - var colorBy = this.get('colorBy'); - return colorBy || 'series'; - }; - - SeriesModel.prototype.isColorBySeries = function () { - return this.getColorBy() === 'series'; - }; - /** - * Get base axis if has coordinate system and has axis. - * By default use coordSys.getBaseAxis(); - * Can be overridden for some chart. - * @return {type} description - */ - - - SeriesModel.prototype.getBaseAxis = function () { - var coordSys = this.coordinateSystem; // @ts-ignore - - return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis(); - }; - /** - * Retrieve the index of nearest value in the view coordinate. - * Data position is compared with each axis's dataToCoord. - * - * @param axisDim axis dimension - * @param dim data dimension - * @param value - * @param [maxDistance=Infinity] The maximum distance in view coordinate space - * @return If and only if multiple indices has - * the same value, they are put to the result. - */ - - - SeriesModel.prototype.indicesOfNearest = function (axisDim, dim, value, maxDistance) { - var data = this.getData(); - var coordSys = this.coordinateSystem; - var axis = coordSys && coordSys.getAxis(axisDim); - - if (!coordSys || !axis) { - return []; - } - - var targetCoord = axis.dataToCoord(value); - - if (maxDistance == null) { - maxDistance = Infinity; - } - - var nearestIndices = []; - var minDist = Infinity; - var minDiff = -1; - var nearestIndicesLen = 0; - data.each(dim, function (dimValue, idx) { - var dataCoord = axis.dataToCoord(dimValue); - var diff = targetCoord - dataCoord; - var dist = Math.abs(diff); - - if (dist <= maxDistance) { - // When the `value` is at the middle of `this.get(dim, i)` and `this.get(dim, i+1)`, - // we'd better not push both of them to `nearestIndices`, otherwise it is easy to - // get more than one item in `nearestIndices` (more specifically, in `tooltip`). - // So we choose the one that `diff >= 0` in this case. - // But if `this.get(dim, i)` and `this.get(dim, j)` get the same value, both of them - // should be push to `nearestIndices`. - if (dist < minDist || dist === minDist && diff >= 0 && minDiff < 0) { - minDist = dist; - minDiff = diff; - nearestIndicesLen = 0; - } - - if (diff === minDiff) { - nearestIndices[nearestIndicesLen++] = idx; - } - } - }); - nearestIndices.length = nearestIndicesLen; - return nearestIndices; - }; - /** - * Default tooltip formatter - * - * @param dataIndex - * @param multipleSeries - * @param dataType - * @param renderMode valid values: 'html'(by default) and 'richText'. - * 'html' is used for rendering tooltip in extra DOM form, and the result - * string is used as DOM HTML content. - * 'richText' is used for rendering tooltip in rich text form, for those where - * DOM operation is not supported. - * @return formatted tooltip with `html` and `markers` - * Notice: The override method can also return string - */ - - - SeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { - return defaultSeriesFormatTooltip({ - series: this, - dataIndex: dataIndex, - multipleSeries: multipleSeries - }); - }; - - SeriesModel.prototype.isAnimationEnabled = function () { - var ecModel = this.ecModel; // Disable animation if using echarts in node but not give ssr flag. - // In ssr mode, renderToString will generate svg with css animation. - - if (env.node && !(ecModel && ecModel.ssr)) { - return false; - } - - var animationEnabled = this.getShallow('animation'); - - if (animationEnabled) { - if (this.getData().count() > this.getShallow('animationThreshold')) { - animationEnabled = false; - } - } - - return !!animationEnabled; - }; - - SeriesModel.prototype.restoreData = function () { - this.dataTask.dirty(); - }; - - SeriesModel.prototype.getColorFromPalette = function (name, scope, requestColorNum) { - var ecModel = this.ecModel; // PENDING - - var color = PaletteMixin.prototype.getColorFromPalette.call(this, name, scope, requestColorNum); - - if (!color) { - color = ecModel.getColorFromPalette(name, scope, requestColorNum); - } - - return color; - }; - /** - * Use `data.mapDimensionsAll(coordDim)` instead. - * @deprecated - */ - - - SeriesModel.prototype.coordDimToDataDim = function (coordDim) { - return this.getRawData().mapDimensionsAll(coordDim); - }; - /** - * Get progressive rendering count each step - */ - - - SeriesModel.prototype.getProgressive = function () { - return this.get('progressive'); - }; - /** - * Get progressive rendering count each step - */ - - - SeriesModel.prototype.getProgressiveThreshold = function () { - return this.get('progressiveThreshold'); - }; // PENGING If selectedMode is null ? - - - SeriesModel.prototype.select = function (innerDataIndices, dataType) { - this._innerSelect(this.getData(dataType), innerDataIndices); - }; - - SeriesModel.prototype.unselect = function (innerDataIndices, dataType) { - var selectedMap = this.option.selectedMap; - - if (!selectedMap) { - return; - } - - var selectedMode = this.option.selectedMode; - var data = this.getData(dataType); - - if (selectedMode === 'series' || selectedMap === 'all') { - this.option.selectedMap = {}; - this._selectedDataIndicesMap = {}; - return; - } - - for (var i = 0; i < innerDataIndices.length; i++) { - var dataIndex = innerDataIndices[i]; - var nameOrId = getSelectionKey(data, dataIndex); - selectedMap[nameOrId] = false; - this._selectedDataIndicesMap[nameOrId] = -1; - } - }; - - SeriesModel.prototype.toggleSelect = function (innerDataIndices, dataType) { - var tmpArr = []; - - for (var i = 0; i < innerDataIndices.length; i++) { - tmpArr[0] = innerDataIndices[i]; - this.isSelected(innerDataIndices[i], dataType) ? this.unselect(tmpArr, dataType) : this.select(tmpArr, dataType); - } - }; - - SeriesModel.prototype.getSelectedDataIndices = function () { - if (this.option.selectedMap === 'all') { - return [].slice.call(this.getData().getIndices()); - } - - var selectedDataIndicesMap = this._selectedDataIndicesMap; - var nameOrIds = keys(selectedDataIndicesMap); - var dataIndices = []; - - for (var i = 0; i < nameOrIds.length; i++) { - var dataIndex = selectedDataIndicesMap[nameOrIds[i]]; - - if (dataIndex >= 0) { - dataIndices.push(dataIndex); - } - } - - return dataIndices; - }; - - SeriesModel.prototype.isSelected = function (dataIndex, dataType) { - var selectedMap = this.option.selectedMap; - - if (!selectedMap) { - return false; - } - - var data = this.getData(dataType); - return (selectedMap === 'all' || selectedMap[getSelectionKey(data, dataIndex)]) && !data.getItemModel(dataIndex).get(['select', 'disabled']); - }; - - SeriesModel.prototype.isUniversalTransitionEnabled = function () { - if (this[SERIES_UNIVERSAL_TRANSITION_PROP]) { - return true; - } - - var universalTransitionOpt = this.option.universalTransition; // Quick reject - - if (!universalTransitionOpt) { - return false; - } - - if (universalTransitionOpt === true) { - return true; - } // Can be simply 'universalTransition: true' - - - return universalTransitionOpt && universalTransitionOpt.enabled; - }; - - SeriesModel.prototype._innerSelect = function (data, innerDataIndices) { - var _a, _b; - - var option = this.option; - var selectedMode = option.selectedMode; - var len = innerDataIndices.length; - - if (!selectedMode || !len) { - return; - } - - if (selectedMode === 'series') { - option.selectedMap = 'all'; - } else if (selectedMode === 'multiple') { - if (!isObject$2(option.selectedMap)) { - option.selectedMap = {}; - } - - var selectedMap = option.selectedMap; - - for (var i = 0; i < len; i++) { - var dataIndex = innerDataIndices[i]; // TODO different types of data share same object. - - var nameOrId = getSelectionKey(data, dataIndex); - selectedMap[nameOrId] = true; - this._selectedDataIndicesMap[nameOrId] = data.getRawIndex(dataIndex); - } - } else if (selectedMode === 'single' || selectedMode === true) { - var lastDataIndex = innerDataIndices[len - 1]; - var nameOrId = getSelectionKey(data, lastDataIndex); - option.selectedMap = (_a = {}, _a[nameOrId] = true, _a); - this._selectedDataIndicesMap = (_b = {}, _b[nameOrId] = data.getRawIndex(lastDataIndex), _b); - } - }; - - SeriesModel.prototype._initSelectedMapFromData = function (data) { - // Ignore select info in data if selectedMap exists. - // NOTE It's only for legacy usage. edge data is not supported. - if (this.option.selectedMap) { - return; - } - - var dataIndices = []; - - if (data.hasItemOption) { - data.each(function (idx) { - var rawItem = data.getRawDataItem(idx); - - if (rawItem && rawItem.selected) { - dataIndices.push(idx); - } - }); - } - - if (dataIndices.length > 0) { - this._innerSelect(data, dataIndices); - } - }; // /** - // * @see {module:echarts/stream/Scheduler} - // */ - // abstract pipeTask: null - - - SeriesModel.registerClass = function (clz) { - return ComponentModel.registerClass(clz); - }; - - SeriesModel.protoInitialize = function () { - var proto = SeriesModel.prototype; - proto.type = 'series.__base__'; - proto.seriesIndex = 0; - proto.ignoreStyleOnData = false; - proto.hasSymbolVisual = false; - proto.defaultSymbol = 'circle'; // Make sure the values can be accessed! - - proto.visualStyleAccessPath = 'itemStyle'; - proto.visualDrawType = 'fill'; - }(); - - return SeriesModel; - }(ComponentModel); - - mixin(SeriesModel, DataFormatMixin); - mixin(SeriesModel, PaletteMixin); - mountExtend(SeriesModel, ComponentModel); - /** - * MUST be called after `prepareSource` called - * Here we need to make auto series, especially for auto legend. But we - * do not modify series.name in option to avoid side effects. - */ - - function autoSeriesName(seriesModel) { - // User specified name has higher priority, otherwise it may cause - // series can not be queried unexpectedly. - var name = seriesModel.name; - - if (!isNameSpecified(seriesModel)) { - seriesModel.name = getSeriesAutoName(seriesModel) || name; - } - } - - function getSeriesAutoName(seriesModel) { - var data = seriesModel.getRawData(); - var dataDims = data.mapDimensionsAll('seriesName'); - var nameArr = []; - each$4(dataDims, function (dataDim) { - var dimInfo = data.getDimensionInfo(dataDim); - dimInfo.displayName && nameArr.push(dimInfo.displayName); - }); - return nameArr.join(' '); - } - - function dataTaskCount(context) { - return context.model.getRawData().count(); - } - - function dataTaskReset(context) { - var seriesModel = context.model; - seriesModel.setData(seriesModel.getRawData().cloneShallow()); - return dataTaskProgress; - } - - function dataTaskProgress(param, context) { - // Avoid repeat cloneShallow when data just created in reset. - if (context.outputData && param.end > context.outputData.count()) { - context.model.getRawData().cloneShallow(context.outputData); - } - } // TODO refactor - - - function wrapData(data, seriesModel) { - each$4(concatArray(data.CHANGABLE_METHODS, data.DOWNSAMPLE_METHODS), function (methodName) { - data.wrapMethod(methodName, curry$1(onDataChange, seriesModel)); - }); - } - - function onDataChange(seriesModel, newList) { - var task = getCurrentTask(seriesModel); - - if (task) { - // Consider case: filter, selectRange - task.setOutputEnd((newList || this).count()); - } - - return newList; - } - - function getCurrentTask(seriesModel) { - var scheduler = (seriesModel.ecModel || {}).scheduler; - var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid); - - if (pipeline) { - // When pipline finished, the currrentTask keep the last - // task (renderTask). - var task = pipeline.currentTask; - - if (task) { - var agentStubMap = task.agentStubMap; - - if (agentStubMap) { - task = agentStubMap.get(seriesModel.uid); - } - } - - return task; - } - } - - var ComponentView = - /** @class */ - function () { - function ComponentView() { - this.group = new Group$2(); - this.uid = getUID('viewComponent'); - } - - ComponentView.prototype.init = function (ecModel, api) {}; - - ComponentView.prototype.render = function (model, ecModel, api, payload) {}; - - ComponentView.prototype.dispose = function (ecModel, api) {}; - - ComponentView.prototype.updateView = function (model, ecModel, api, payload) {// Do nothing; - }; - - ComponentView.prototype.updateLayout = function (model, ecModel, api, payload) {// Do nothing; - }; - - ComponentView.prototype.updateVisual = function (model, ecModel, api, payload) {// Do nothing; - }; - /** - * Hook for toggle blur target series. - * Can be used in marker for blur or leave blur the markers - */ - - - ComponentView.prototype.toggleBlurSeries = function (seriesModels, isBlur, ecModel) {// Do nothing; - }; - /** - * Traverse the new rendered elements. - * - * It will traverse the new added element in progressive rendering. - * And traverse all in normal rendering. - */ - - - ComponentView.prototype.eachRendered = function (cb) { - var group = this.group; - - if (group) { - group.traverse(cb); - } - }; - - return ComponentView; - }(); - - enableClassExtend(ComponentView); - enableClassManagement(ComponentView); - /** - * @return {string} If large mode changed, return string 'reset'; - */ - - function createRenderPlanner() { - var inner = makeInner(); - return function (seriesModel) { - var fields = inner(seriesModel); - var pipelineContext = seriesModel.pipelineContext; - var originalLarge = !!fields.large; - var originalProgressive = !!fields.progressiveRender; // FIXME: if the planner works on a filtered series, `pipelineContext` does not - // exists. See #11611 . Probably we need to modify this structure, see the comment - // on `performRawSeries` in `Schedular.js`. - - var large = fields.large = !!(pipelineContext && pipelineContext.large); - var progressive = fields.progressiveRender = !!(pipelineContext && pipelineContext.progressiveRender); - return !!(originalLarge !== large || originalProgressive !== progressive) && 'reset'; - }; - } - - var inner$9 = makeInner(); - var renderPlanner = createRenderPlanner(); - - var ChartView = - /** @class */ - function () { - function ChartView() { - this.group = new Group$2(); - this.uid = getUID('viewChart'); - this.renderTask = createTask({ - plan: renderTaskPlan, - reset: renderTaskReset - }); - this.renderTask.context = { - view: this - }; - } - - ChartView.prototype.init = function (ecModel, api) {}; - - ChartView.prototype.render = function (seriesModel, ecModel, api, payload) { - { - throw new Error('render method must been implemented'); - } - }; - /** - * Highlight series or specified data item. - */ - - - ChartView.prototype.highlight = function (seriesModel, ecModel, api, payload) { - var data = seriesModel.getData(payload && payload.dataType); - - if (!data) { - { - error("Unknown dataType " + payload.dataType); - } - return; - } - - toggleHighlight(data, payload, 'emphasis'); - }; - /** - * Downplay series or specified data item. - */ - - - ChartView.prototype.downplay = function (seriesModel, ecModel, api, payload) { - var data = seriesModel.getData(payload && payload.dataType); - - if (!data) { - { - error("Unknown dataType " + payload.dataType); - } - return; - } - - toggleHighlight(data, payload, 'normal'); - }; - /** - * Remove self. - */ - - - ChartView.prototype.remove = function (ecModel, api) { - this.group.removeAll(); - }; - /** - * Dispose self. - */ - - - ChartView.prototype.dispose = function (ecModel, api) {}; - - ChartView.prototype.updateView = function (seriesModel, ecModel, api, payload) { - this.render(seriesModel, ecModel, api, payload); - }; // FIXME never used? - - - ChartView.prototype.updateLayout = function (seriesModel, ecModel, api, payload) { - this.render(seriesModel, ecModel, api, payload); - }; // FIXME never used? - - - ChartView.prototype.updateVisual = function (seriesModel, ecModel, api, payload) { - this.render(seriesModel, ecModel, api, payload); - }; - /** - * Traverse the new rendered elements. - * - * It will traverse the new added element in progressive rendering. - * And traverse all in normal rendering. - */ - - - ChartView.prototype.eachRendered = function (cb) { - traverseElements(this.group, cb); - }; - - ChartView.markUpdateMethod = function (payload, methodName) { - inner$9(payload).updateMethod = methodName; - }; - - ChartView.protoInitialize = function () { - var proto = ChartView.prototype; - proto.type = 'chart'; - }(); - - return ChartView; - }(); - /** - * Set state of single element - */ - - - function elSetState(el, state, highlightDigit) { - if (el && isHighDownDispatcher(el)) { - (state === 'emphasis' ? enterEmphasis : leaveEmphasis)(el, highlightDigit); - } - } - - function toggleHighlight(data, payload, state) { - var dataIndex = queryDataIndex(data, payload); - var highlightDigit = payload && payload.highlightKey != null ? getHighlightDigit(payload.highlightKey) : null; - - if (dataIndex != null) { - each$4(normalizeToArray(dataIndex), function (dataIdx) { - elSetState(data.getItemGraphicEl(dataIdx), state, highlightDigit); - }); - } else { - data.eachItemGraphicEl(function (el) { - elSetState(el, state, highlightDigit); - }); - } - } - - enableClassExtend(ChartView, ['dispose']); - enableClassManagement(ChartView); - - function renderTaskPlan(context) { - return renderPlanner(context.model); - } - - function renderTaskReset(context) { - var seriesModel = context.model; - var ecModel = context.ecModel; - var api = context.api; - var payload = context.payload; // FIXME: remove updateView updateVisual - - var progressiveRender = seriesModel.pipelineContext.progressiveRender; - var view = context.view; - var updateMethod = payload && inner$9(payload).updateMethod; - var methodName = progressiveRender ? 'incrementalPrepareRender' : updateMethod && view[updateMethod] ? updateMethod // `appendData` is also supported when data amount - // is less than progressive threshold. - : 'render'; - - if (methodName !== 'render') { - view[methodName](seriesModel, ecModel, api, payload); - } - - return progressMethodMap[methodName]; - } - - var progressMethodMap = { - incrementalPrepareRender: { - progress: function (params, context) { - context.view.incrementalRender(params, context.model, context.ecModel, context.api, context.payload); - } - }, - render: { - // Put view.render in `progress` to support appendData. But in this case - // view.render should not be called in reset, otherwise it will be called - // twise. Use `forceFirstProgress` to make sure that view.render is called - // in any cases. - forceFirstProgress: true, - progress: function (params, context) { - context.view.render(context.model, context.ecModel, context.api, context.payload); - } - } - }; - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * AUTO-GENERATED FILE. DO NOT MODIFY. - */ - - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - var ORIGIN_METHOD = '\0__throttleOriginMethod'; - var RATE = '\0__throttleRate'; - var THROTTLE_TYPE = '\0__throttleType'; - /** - * @public - * @param {(Function)} fn - * @param {number} [delay=0] Unit: ms. - * @param {boolean} [debounce=false] - * true: If call interval less than `delay`, only the last call works. - * false: If call interval less than `delay, call works on fixed rate. - * @return {(Function)} throttled fn. - */ - - function throttle(fn, delay, debounce) { - var currCall; - var lastCall = 0; - var lastExec = 0; - var timer = null; - var diff; - var scope; - var args; - var debounceNextCall; - delay = delay || 0; - - function exec() { - lastExec = new Date().getTime(); - timer = null; - fn.apply(scope, args || []); - } - - var cb = function () { - var cbArgs = []; - - for (var _i = 0; _i < arguments.length; _i++) { - cbArgs[_i] = arguments[_i]; - } - - currCall = new Date().getTime(); - scope = this; - args = cbArgs; - var thisDelay = debounceNextCall || delay; - var thisDebounce = debounceNextCall || debounce; - debounceNextCall = null; - diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay; - clearTimeout(timer); // Here we should make sure that: the `exec` SHOULD NOT be called later - // than a new call of `cb`, that is, preserving the command order. Consider - // calculating "scale rate" when roaming as an example. When a call of `cb` - // happens, either the `exec` is called dierectly, or the call is delayed. - // But the delayed call should never be later than next call of `cb`. Under - // this assurance, we can simply update view state each time `dispatchAction` - // triggered by user roaming, but not need to add extra code to avoid the - // state being "rolled-back". - - if (thisDebounce) { - timer = setTimeout(exec, thisDelay); - } else { - if (diff >= 0) { - exec(); - } else { - timer = setTimeout(exec, -diff); - } - } - - lastCall = currCall; - }; - /** - * Clear throttle. - * @public - */ - - - cb.clear = function () { - if (timer) { - clearTimeout(timer); - timer = null; - } - }; - /** - * Enable debounce once. - */ - - - cb.debounceNextCall = function (debounceDelay) { - debounceNextCall = debounceDelay; - }; - - return cb; - } - /** - * Create throttle method or update throttle rate. - * - * @example - * ComponentView.prototype.render = function () { - * ... - * throttle.createOrUpdate( - * this, - * '_dispatchAction', - * this.model.get('throttle'), - * 'fixRate' - * ); - * }; - * ComponentView.prototype.remove = function () { - * throttle.clear(this, '_dispatchAction'); - * }; - * ComponentView.prototype.dispose = function () { - * throttle.clear(this, '_dispatchAction'); - * }; - * - */ - - - function createOrUpdate(obj, fnAttr, rate, throttleType) { - var fn = obj[fnAttr]; - - if (!fn) { - return; - } - - var originFn = fn[ORIGIN_METHOD] || fn; - var lastThrottleType = fn[THROTTLE_TYPE]; - var lastRate = fn[RATE]; - - if (lastRate !== rate || lastThrottleType !== throttleType) { - if (rate == null || !throttleType) { - return obj[fnAttr] = originFn; - } - - fn = obj[fnAttr] = throttle(originFn, rate, throttleType === 'debounce'); - fn[ORIGIN_METHOD] = originFn; - fn[THROTTLE_TYPE] = throttleType; - fn[RATE] = rate; - } - - return fn; - } - /** - * Clear throttle. Example see throttle.createOrUpdate. - */ - - - function clear(obj, fnAttr) { - var fn = obj[fnAttr]; - - if (fn && fn[ORIGIN_METHOD]) { - // Clear throttle - fn.clear && fn.clear(); - obj[fnAttr] = fn[ORIGIN_METHOD]; - } - } - - var inner$8 = makeInner(); - var defaultStyleMappers = { - itemStyle: makeStyleMapper(ITEM_STYLE_KEY_MAP, true), - lineStyle: makeStyleMapper(LINE_STYLE_KEY_MAP, true) - }; - var defaultColorKey = { - lineStyle: 'stroke', - itemStyle: 'fill' - }; - - function getStyleMapper(seriesModel, stylePath) { - var styleMapper = seriesModel.visualStyleMapper || defaultStyleMappers[stylePath]; - - if (!styleMapper) { - console.warn("Unknown style type '" + stylePath + "'."); - return defaultStyleMappers.itemStyle; - } - - return styleMapper; - } - - function getDefaultColorKey(seriesModel, stylePath) { - // return defaultColorKey[stylePath] || - var colorKey = seriesModel.visualDrawType || defaultColorKey[stylePath]; - - if (!colorKey) { - console.warn("Unknown style type '" + stylePath + "'."); - return 'fill'; - } - - return colorKey; - } - - var seriesStyleTask = { - createOnAllSeries: true, - performRawSeries: true, - reset: function (seriesModel, ecModel) { - var data = seriesModel.getData(); - var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; // Set in itemStyle - - var styleModel = seriesModel.getModel(stylePath); - var getStyle = getStyleMapper(seriesModel, stylePath); - var globalStyle = getStyle(styleModel); - var decalOption = styleModel.getShallow('decal'); - - if (decalOption) { - data.setVisual('decal', decalOption); - decalOption.dirty = true; - } // TODO - - - var colorKey = getDefaultColorKey(seriesModel, stylePath); - var color = globalStyle[colorKey]; // TODO style callback - - var colorCallback = isFunction(color) ? color : null; - var hasAutoColor = globalStyle.fill === 'auto' || globalStyle.stroke === 'auto'; // Get from color palette by default. - - if (!globalStyle[colorKey] || colorCallback || hasAutoColor) { - // Note: If some series has color specified (e.g., by itemStyle.color), we DO NOT - // make it effect palette. Because some scenarios users need to make some series - // transparent or as background, which should better not effect the palette. - var colorPalette = seriesModel.getColorFromPalette( // TODO series count changed. - seriesModel.name, null, ecModel.getSeriesCount()); - - if (!globalStyle[colorKey]) { - globalStyle[colorKey] = colorPalette; - data.setVisual('colorFromPalette', true); - } - - globalStyle.fill = globalStyle.fill === 'auto' || isFunction(globalStyle.fill) ? colorPalette : globalStyle.fill; - globalStyle.stroke = globalStyle.stroke === 'auto' || isFunction(globalStyle.stroke) ? colorPalette : globalStyle.stroke; - } - - data.setVisual('style', globalStyle); - data.setVisual('drawType', colorKey); // Only visible series has each data be visual encoded - - if (!ecModel.isSeriesFiltered(seriesModel) && colorCallback) { - data.setVisual('colorFromPalette', false); - return { - dataEach: function (data, idx) { - var dataParams = seriesModel.getDataParams(idx); - var itemStyle = extend({}, globalStyle); - itemStyle[colorKey] = colorCallback(dataParams); - data.setItemVisual(idx, 'style', itemStyle); - } - }; - } - } - }; - var sharedModel = new Model(); - var dataStyleTask = { - createOnAllSeries: true, - performRawSeries: true, - reset: function (seriesModel, ecModel) { - if (seriesModel.ignoreStyleOnData || ecModel.isSeriesFiltered(seriesModel)) { - return; - } - - var data = seriesModel.getData(); - var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; // Set in itemStyle - - var getStyle = getStyleMapper(seriesModel, stylePath); - var colorKey = data.getVisual('drawType'); - return { - dataEach: data.hasItemOption ? function (data, idx) { - // Not use getItemModel for performance considuration - var rawItem = data.getRawDataItem(idx); - - if (rawItem && rawItem[stylePath]) { - sharedModel.option = rawItem[stylePath]; - var style = getStyle(sharedModel); - var existsStyle = data.ensureUniqueItemVisual(idx, 'style'); - extend(existsStyle, style); - - if (sharedModel.option.decal) { - data.setItemVisual(idx, 'decal', sharedModel.option.decal); - sharedModel.option.decal.dirty = true; - } - - if (colorKey in style) { - data.setItemVisual(idx, 'colorFromPalette', false); - } - } - } : null - }; - } - }; // Pick color from palette for the data which has not been set with color yet. - // Note: do not support stream rendering. No such cases yet. - - var dataColorPaletteTask = { - performRawSeries: true, - overallReset: function (ecModel) { - // Each type of series uses one scope. - // Pie and funnel are using different scopes. - var paletteScopeGroupByType = createHashMap(); - ecModel.eachSeries(function (seriesModel) { - var colorBy = seriesModel.getColorBy(); - - if (seriesModel.isColorBySeries()) { - return; - } - - var key = seriesModel.type + '-' + colorBy; - var colorScope = paletteScopeGroupByType.get(key); - - if (!colorScope) { - colorScope = {}; - paletteScopeGroupByType.set(key, colorScope); - } - - inner$8(seriesModel).scope = colorScope; - }); - ecModel.eachSeries(function (seriesModel) { - if (seriesModel.isColorBySeries() || ecModel.isSeriesFiltered(seriesModel)) { - return; - } - - var dataAll = seriesModel.getRawData(); - var idxMap = {}; - var data = seriesModel.getData(); - var colorScope = inner$8(seriesModel).scope; - var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; - var colorKey = getDefaultColorKey(seriesModel, stylePath); - data.each(function (idx) { - var rawIdx = data.getRawIndex(idx); - idxMap[rawIdx] = idx; - }); // Iterate on data before filtered. To make sure color from palette can be - // Consistent when toggling legend. - - dataAll.each(function (rawIdx) { - var idx = idxMap[rawIdx]; - var fromPalette = data.getItemVisual(idx, 'colorFromPalette'); // Get color from palette for each data only when the color is inherited from series color, which is - // also picked from color palette. So following situation is not in the case: - // 1. series.itemStyle.color is set - // 2. color is encoded by visualMap - - if (fromPalette) { - var itemStyle = data.ensureUniqueItemVisual(idx, 'style'); - var name_1 = dataAll.getName(rawIdx) || rawIdx + ''; - var dataCount = dataAll.count(); - itemStyle[colorKey] = seriesModel.getColorFromPalette(name_1, colorScope, dataCount); - } - }); - }); - } - }; - var PI$1 = Math.PI; - /** - * @param {module:echarts/ExtensionAPI} api - * @param {Object} [opts] - * @param {string} [opts.text] - * @param {string} [opts.color] - * @param {string} [opts.textColor] - * @return {module:zrender/Element} - */ - - function defaultLoading(api, opts) { - opts = opts || {}; - defaults(opts, { - text: 'loading', - textColor: tokens.color.primary, - fontSize: 12, - fontWeight: 'normal', - fontStyle: 'normal', - fontFamily: 'sans-serif', - maskColor: 'rgba(255,255,255,0.8)', - showSpinner: true, - color: tokens.color.theme[0], - spinnerRadius: 10, - lineWidth: 5, - zlevel: 0 - }); - var group = new Group$2(); - var mask = new Rect({ - style: { - fill: opts.maskColor - }, - zlevel: opts.zlevel, - z: 10000 - }); - group.add(mask); - var textContent = new ZRText({ - style: { - text: opts.text, - fill: opts.textColor, - fontSize: opts.fontSize, - fontWeight: opts.fontWeight, - fontStyle: opts.fontStyle, - fontFamily: opts.fontFamily - }, - zlevel: opts.zlevel, - z: 10001 - }); - var labelRect = new Rect({ - style: { - fill: 'none' - }, - textContent: textContent, - textConfig: { - position: 'right', - distance: 10 - }, - zlevel: opts.zlevel, - z: 10001 - }); - group.add(labelRect); - var arc; - - if (opts.showSpinner) { - arc = new Arc({ - shape: { - startAngle: -PI$1 / 2, - endAngle: -PI$1 / 2 + 0.1, - r: opts.spinnerRadius - }, - style: { - stroke: opts.color, - lineCap: 'round', - lineWidth: opts.lineWidth - }, - zlevel: opts.zlevel, - z: 10001 - }); - arc.animateShape(true).when(1000, { - endAngle: PI$1 * 3 / 2 - }).start('circularInOut'); - arc.animateShape(true).when(1000, { - startAngle: PI$1 * 3 / 2 - }).delay(300).start('circularInOut'); - group.add(arc); - } // Inject resize - - - group.resize = function () { - var textWidth = textContent.getBoundingRect().width; - var r = opts.showSpinner ? opts.spinnerRadius : 0; // cx = (containerWidth - arcDiameter - textDistance - textWidth) / 2 - // textDistance needs to be calculated when both animation and text exist - - var cx = (api.getWidth() - r * 2 - (opts.showSpinner && textWidth ? 10 : 0) - textWidth) / 2 - (opts.showSpinner && textWidth ? 0 : 5 + textWidth / 2) // only show the text - + (opts.showSpinner ? 0 : textWidth / 2) // only show the spinner - + (textWidth ? 0 : r); - var cy = api.getHeight() / 2; - opts.showSpinner && arc.setShape({ - cx: cx, - cy: cy - }); - labelRect.setShape({ - x: cx - r, - y: cy - r, - width: r * 2, - height: r * 2 - }); - mask.setShape({ - x: 0, - y: 0, - width: api.getWidth(), - height: api.getHeight() - }); - }; - - group.resize(); - return group; - } - - var Scheduler = - /** @class */ - function () { - function Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) { - // key: handlerUID - this._stageTaskMap = createHashMap(); - this.ecInstance = ecInstance; - this.api = api; // Fix current processors in case that in some rear cases that - // processors might be registered after echarts instance created. - // Register processors incrementally for a echarts instance is - // not supported by this stream architecture. - - dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice(); - visualHandlers = this._visualHandlers = visualHandlers.slice(); - this._allHandlers = dataProcessorHandlers.concat(visualHandlers); - } - - Scheduler.prototype.restoreData = function (ecModel, payload) { - // TODO: Only restore needed series and components, but not all components. - // Currently `restoreData` of all of the series and component will be called. - // But some independent components like `title`, `legend`, `graphic`, `toolbox`, - // `tooltip`, `axisPointer`, etc, do not need series refresh when `setOption`, - // and some components like coordinate system, axes, dataZoom, visualMap only - // need their target series refresh. - // (1) If we are implementing this feature some day, we should consider these cases: - // if a data processor depends on a component (e.g., dataZoomProcessor depends - // on the settings of `dataZoom`), it should be re-performed if the component - // is modified by `setOption`. - // (2) If a processor depends on sevral series, speicified by its `getTargetSeries`, - // it should be re-performed when the result array of `getTargetSeries` changed. - // We use `dependencies` to cover these issues. - // (3) How to update target series when coordinate system related components modified. - // TODO: simply the dirty mechanism? Check whether only the case here can set tasks dirty, - // and this case all of the tasks will be set as dirty. - ecModel.restoreData(payload); // Theoretically an overall task not only depends on each of its target series, but also - // depends on all of the series. - // The overall task is not in pipeline, and `ecModel.restoreData` only set pipeline tasks - // dirty. If `getTargetSeries` of an overall task returns nothing, we should also ensure - // that the overall task is set as dirty and to be performed, otherwise it probably cause - // state chaos. So we have to set dirty of all of the overall tasks manually, otherwise it - // probably cause state chaos (consider `dataZoomProcessor`). - - this._stageTaskMap.each(function (taskRecord) { - var overallTask = taskRecord.overallTask; - overallTask && overallTask.dirty(); - }); - }; // If seriesModel provided, incremental threshold is check by series data. - - - Scheduler.prototype.getPerformArgs = function (task, isBlock) { - // For overall task - if (!task.__pipeline) { - return; - } - - var pipeline = this._pipelineMap.get(task.__pipeline.id); - - var pCtx = pipeline.context; - var incremental = !isBlock && pipeline.progressiveEnabled && (!pCtx || pCtx.progressiveRender) && task.__idxInPipeline > pipeline.blockIndex; - var step = incremental ? pipeline.step : null; - var modDataCount = pCtx && pCtx.modDataCount; - var modBy = modDataCount != null ? Math.ceil(modDataCount / step) : null; - return { - step: step, - modBy: modBy, - modDataCount: modDataCount - }; - }; - - Scheduler.prototype.getPipeline = function (pipelineId) { - return this._pipelineMap.get(pipelineId); - }; - /** - * Current, progressive rendering starts from visual and layout. - * Always detect render mode in the same stage, avoiding that incorrect - * detection caused by data filtering. - * Caution: - * `updateStreamModes` use `seriesModel.getData()`. - */ - - - Scheduler.prototype.updateStreamModes = function (seriesModel, view) { - var pipeline = this._pipelineMap.get(seriesModel.uid); - - var data = seriesModel.getData(); - var dataLen = data.count(); // `progressiveRender` means that can render progressively in each - // animation frame. Note that some types of series do not provide - // `view.incrementalPrepareRender` but support `chart.appendData`. We - // use the term `incremental` but not `progressive` to describe the - // case that `chart.appendData`. - - var progressiveRender = pipeline.progressiveEnabled && view.incrementalPrepareRender && dataLen >= pipeline.threshold; - var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold'); // TODO: modDataCount should not updated if `appendData`, otherwise cause whole repaint. - // see `test/candlestick-large3.html` - - var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null; - seriesModel.pipelineContext = pipeline.context = { - progressiveRender: progressiveRender, - modDataCount: modDataCount, - large: large - }; - }; - - Scheduler.prototype.restorePipelines = function (ecModel) { - var scheduler = this; - var pipelineMap = scheduler._pipelineMap = createHashMap(); - ecModel.eachSeries(function (seriesModel) { - var progressive = seriesModel.getProgressive(); - var pipelineId = seriesModel.uid; - pipelineMap.set(pipelineId, { - id: pipelineId, - head: null, - tail: null, - threshold: seriesModel.getProgressiveThreshold(), - progressiveEnabled: progressive && !(seriesModel.preventIncremental && seriesModel.preventIncremental()), - blockIndex: -1, - step: Math.round(progressive || 700), - count: 0 - }); - - scheduler._pipe(seriesModel, seriesModel.dataTask); - }); - }; - - Scheduler.prototype.prepareStageTasks = function () { - var stageTaskMap = this._stageTaskMap; - var ecModel = this.api.getModel(); - var api = this.api; - each$4(this._allHandlers, function (handler) { - var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, {}); - var errMsg = ''; - { - // Currently do not need to support to sepecify them both. - errMsg = '"reset" and "overallReset" must not be both specified.'; - } - assert(!(handler.reset && handler.overallReset), errMsg); - handler.reset && this._createSeriesStageTask(handler, record, ecModel, api); - handler.overallReset && this._createOverallStageTask(handler, record, ecModel, api); - }, this); - }; - - Scheduler.prototype.prepareView = function (view, model, ecModel, api) { - var renderTask = view.renderTask; - var context = renderTask.context; - context.model = model; - context.ecModel = ecModel; - context.api = api; - renderTask.__block = !view.incrementalPrepareRender; - - this._pipe(model, renderTask); - }; - - Scheduler.prototype.performDataProcessorTasks = function (ecModel, payload) { - // If we do not use `block` here, it should be considered when to update modes. - this._performStageTasks(this._dataProcessorHandlers, ecModel, payload, { - block: true - }); - }; - - Scheduler.prototype.performVisualTasks = function (ecModel, payload, opt) { - this._performStageTasks(this._visualHandlers, ecModel, payload, opt); - }; - - Scheduler.prototype._performStageTasks = function (stageHandlers, ecModel, payload, opt) { - opt = opt || {}; - var unfinished = false; - var scheduler = this; - each$4(stageHandlers, function (stageHandler, idx) { - if (opt.visualType && opt.visualType !== stageHandler.visualType) { - return; - } - - var stageHandlerRecord = scheduler._stageTaskMap.get(stageHandler.uid); - - var seriesTaskMap = stageHandlerRecord.seriesTaskMap; - var overallTask = stageHandlerRecord.overallTask; - - if (overallTask) { - var overallNeedDirty_1; - var agentStubMap = overallTask.agentStubMap; - agentStubMap.each(function (stub) { - if (needSetDirty(opt, stub)) { - stub.dirty(); - overallNeedDirty_1 = true; - } - }); - overallNeedDirty_1 && overallTask.dirty(); - scheduler.updatePayload(overallTask, payload); - var performArgs_1 = scheduler.getPerformArgs(overallTask, opt.block); // Execute stubs firstly, which may set the overall task dirty, - // then execute the overall task. And stub will call seriesModel.setData, - // which ensures that in the overallTask seriesModel.getData() will not - // return incorrect data. - - agentStubMap.each(function (stub) { - stub.perform(performArgs_1); - }); - - if (overallTask.perform(performArgs_1)) { - unfinished = true; - } - } else if (seriesTaskMap) { - seriesTaskMap.each(function (task, pipelineId) { - if (needSetDirty(opt, task)) { - task.dirty(); - } - - var performArgs = scheduler.getPerformArgs(task, opt.block); // FIXME - // if intending to declare `performRawSeries` in handlers, only - // stream-independent (specifically, data item independent) operations can be - // performed. Because if a series is filtered, most of the tasks will not - // be performed. A stream-dependent operation probably cause wrong biz logic. - // Perhaps we should not provide a separate callback for this case instead - // of providing the config `performRawSeries`. The stream-dependent operations - // and stream-independent operations should better not be mixed. - - performArgs.skip = !stageHandler.performRawSeries && ecModel.isSeriesFiltered(task.context.model); - scheduler.updatePayload(task, payload); - - if (task.perform(performArgs)) { - unfinished = true; - } - }); - } - }); - - function needSetDirty(opt, task) { - return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id)); - } - - this.unfinished = unfinished || this.unfinished; - }; - - Scheduler.prototype.performSeriesTasks = function (ecModel) { - var unfinished; - ecModel.eachSeries(function (seriesModel) { - // Progress to the end for dataInit and dataRestore. - unfinished = seriesModel.dataTask.perform() || unfinished; - }); - this.unfinished = unfinished || this.unfinished; - }; - - Scheduler.prototype.plan = function () { - // Travel pipelines, check block. - this._pipelineMap.each(function (pipeline) { - var task = pipeline.tail; - - do { - if (task.__block) { - pipeline.blockIndex = task.__idxInPipeline; - break; - } - - task = task.getUpstream(); - } while (task); - }); - }; - - Scheduler.prototype.updatePayload = function (task, payload) { - payload !== 'remain' && (task.context.payload = payload); - }; - - Scheduler.prototype._createSeriesStageTask = function (stageHandler, stageHandlerRecord, ecModel, api) { - var scheduler = this; - var oldSeriesTaskMap = stageHandlerRecord.seriesTaskMap; // The count of stages are totally about only several dozen, so - // do not need to reuse the map. - - var newSeriesTaskMap = stageHandlerRecord.seriesTaskMap = createHashMap(); - var seriesType = stageHandler.seriesType; - var getTargetSeries = stageHandler.getTargetSeries; // If a stageHandler should cover all series, `createOnAllSeries` should be declared mandatorily, - // to avoid some typo or abuse. Otherwise if an extension do not specify a `seriesType`, - // it works but it may cause other irrelevant charts blocked. - - if (stageHandler.createOnAllSeries) { - ecModel.eachRawSeries(create); - } else if (seriesType) { - ecModel.eachRawSeriesByType(seriesType, create); - } else if (getTargetSeries) { - getTargetSeries(ecModel, api).each(create); - } - - function create(seriesModel) { - var pipelineId = seriesModel.uid; // Init tasks for each seriesModel only once. - // Reuse original task instance. - - var task = newSeriesTaskMap.set(pipelineId, oldSeriesTaskMap && oldSeriesTaskMap.get(pipelineId) || createTask({ - plan: seriesTaskPlan, - reset: seriesTaskReset, - count: seriesTaskCount - })); - task.context = { - model: seriesModel, - ecModel: ecModel, - api: api, - // PENDING: `useClearVisual` not used? - useClearVisual: stageHandler.isVisual && !stageHandler.isLayout, - plan: stageHandler.plan, - reset: stageHandler.reset, - scheduler: scheduler - }; - - scheduler._pipe(seriesModel, task); - } - }; - - Scheduler.prototype._createOverallStageTask = function (stageHandler, stageHandlerRecord, ecModel, api) { - var scheduler = this; - var overallTask = stageHandlerRecord.overallTask = stageHandlerRecord.overallTask // For overall task, the function only be called on reset stage. - || createTask({ - reset: overallTaskReset - }); - overallTask.context = { - ecModel: ecModel, - api: api, - overallReset: stageHandler.overallReset, - scheduler: scheduler - }; - var oldAgentStubMap = overallTask.agentStubMap; // The count of stages are totally about only several dozen, so - // do not need to reuse the map. - - var newAgentStubMap = overallTask.agentStubMap = createHashMap(); - var seriesType = stageHandler.seriesType; - var getTargetSeries = stageHandler.getTargetSeries; - var overallProgress = true; - var shouldOverallTaskDirty = false; // FIXME:TS never used, so comment it - // let modifyOutputEnd = stageHandler.modifyOutputEnd; - // An overall task with seriesType detected or has `getTargetSeries`, we add - // stub in each pipelines, it will set the overall task dirty when the pipeline - // progress. Moreover, to avoid call the overall task each frame (too frequent), - // we set the pipeline block. - - var errMsg = ''; - { - errMsg = '"createOnAllSeries" is not supported for "overallReset", ' + 'because it will block all streams.'; - } - assert(!stageHandler.createOnAllSeries, errMsg); - - if (seriesType) { - ecModel.eachRawSeriesByType(seriesType, createStub); - } else if (getTargetSeries) { - getTargetSeries(ecModel, api).each(createStub); - } // Otherwise, (usually it is legacy case), the overall task will only be - // executed when upstream is dirty. Otherwise the progressive rendering of all - // pipelines will be disabled unexpectedly. But it still needs stubs to receive - // dirty info from upstream. - else { - overallProgress = false; - each$4(ecModel.getSeries(), createStub); - } - - function createStub(seriesModel) { - var pipelineId = seriesModel.uid; - var stub = newAgentStubMap.set(pipelineId, oldAgentStubMap && oldAgentStubMap.get(pipelineId) || ( // When the result of `getTargetSeries` changed, the overallTask - // should be set as dirty and re-performed. - shouldOverallTaskDirty = true, createTask({ - reset: stubReset, - onDirty: stubOnDirty - }))); - stub.context = { - model: seriesModel, - overallProgress: overallProgress // FIXME:TS never used, so comment it - // modifyOutputEnd: modifyOutputEnd - - }; - stub.agent = overallTask; - stub.__block = overallProgress; - - scheduler._pipe(seriesModel, stub); - } - - if (shouldOverallTaskDirty) { - overallTask.dirty(); - } - }; - - Scheduler.prototype._pipe = function (seriesModel, task) { - var pipelineId = seriesModel.uid; - - var pipeline = this._pipelineMap.get(pipelineId); - - !pipeline.head && (pipeline.head = task); - pipeline.tail && pipeline.tail.pipe(task); - pipeline.tail = task; - task.__idxInPipeline = pipeline.count++; - task.__pipeline = pipeline; - }; - - Scheduler.wrapStageHandler = function (stageHandler, visualType) { - if (isFunction(stageHandler)) { - stageHandler = { - overallReset: stageHandler, - seriesType: detectSeriseType(stageHandler) - }; - } - - stageHandler.uid = getUID('stageHandler'); - visualType && (stageHandler.visualType = visualType); - return stageHandler; - }; - - return Scheduler; - }(); - - function overallTaskReset(context) { - context.overallReset(context.ecModel, context.api, context.payload); - } - - function stubReset(context) { - return context.overallProgress && stubProgress; - } - - function stubProgress() { - this.agent.dirty(); - this.getDownstream().dirty(); - } - - function stubOnDirty() { - this.agent && this.agent.dirty(); - } - - function seriesTaskPlan(context) { - return context.plan ? context.plan(context.model, context.ecModel, context.api, context.payload) : null; - } - - function seriesTaskReset(context) { - if (context.useClearVisual) { - context.data.clearAllVisual(); - } - - var resetDefines = context.resetDefines = normalizeToArray(context.reset(context.model, context.ecModel, context.api, context.payload)); - return resetDefines.length > 1 ? map$1(resetDefines, function (v, idx) { - return makeSeriesTaskProgress(idx); - }) : singleSeriesTaskProgress; - } - - var singleSeriesTaskProgress = makeSeriesTaskProgress(0); - - function makeSeriesTaskProgress(resetDefineIdx) { - return function (params, context) { - var data = context.data; - var resetDefine = context.resetDefines[resetDefineIdx]; - - if (resetDefine && resetDefine.dataEach) { - for (var i = params.start; i < params.end; i++) { - resetDefine.dataEach(data, i); - } - } else if (resetDefine && resetDefine.progress) { - resetDefine.progress(params, data); - } - }; - } - - function seriesTaskCount(context) { - return context.data.count(); - } - /** - * Only some legacy stage handlers (usually in echarts extensions) are pure function. - * To ensure that they can work normally, they should work in block mode, that is, - * they should not be started util the previous tasks finished. So they cause the - * progressive rendering disabled. We try to detect the series type, to narrow down - * the block range to only the series type they concern, but not all series. - */ - - - function detectSeriseType(legacyFunc) { - seriesType = null; - - try { - // Assume there is no async when calling `eachSeriesByType`. - legacyFunc(ecModelMock, apiMock); - } catch (e) {} - - return seriesType; - } - - var ecModelMock = {}; - var apiMock = {}; - var seriesType; - mockMethods(ecModelMock, GlobalModel); - mockMethods(apiMock, ExtensionAPI); - - ecModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) { - seriesType = type; - }; - - ecModelMock.eachComponent = function (cond) { - if (cond.mainType === 'series' && cond.subType) { - seriesType = cond.subType; - } - }; - - function mockMethods(target, Clz) { - /* eslint-disable */ - for (var name_1 in Clz.prototype) { - // Do not use hasOwnProperty - target[name_1] = noop; - } - /* eslint-enable */ - - } - - var color = tokens.darkColor; - var backgroundColor = color.background; - - var axisCommon = function () { - return { - axisLine: { - lineStyle: { - color: color.axisLine - } - }, - splitLine: { - lineStyle: { - color: color.axisSplitLine - } - }, - splitArea: { - areaStyle: { - color: [color.backgroundTint, color.backgroundTransparent] - } - }, - minorSplitLine: { - lineStyle: { - color: color.axisMinorSplitLine - } - }, - axisLabel: { - color: color.axisLabel - }, - axisName: {} - }; - }; - - var matrixAxis = { - label: { - color: color.secondary - }, - itemStyle: { - borderColor: color.borderTint - }, - dividerLineStyle: { - color: color.border - } - }; - var theme = { - darkMode: true, - color: color.theme, - backgroundColor: backgroundColor, - axisPointer: { - lineStyle: { - color: color.border - }, - crossStyle: { - color: color.borderShade - }, - label: { - color: color.tertiary - } - }, - legend: { - textStyle: { - color: color.secondary - }, - pageTextStyle: { - color: color.tertiary - } - }, - textStyle: { - color: color.secondary - }, - title: { - textStyle: { - color: color.primary - }, - subtextStyle: { - color: color.quaternary - } - }, - toolbox: { - iconStyle: { - borderColor: color.accent50 - } - }, - tooltip: { - backgroundColor: color.neutral20, - defaultBorderColor: color.border, - textStyle: { - color: color.tertiary - } - }, - dataZoom: { - borderColor: color.accent10, - textStyle: { - color: color.tertiary - }, - brushStyle: { - color: color.backgroundTint - }, - handleStyle: { - color: color.neutral00, - borderColor: color.accent20 - }, - moveHandleStyle: { - color: color.accent40 - }, - emphasis: { - handleStyle: { - borderColor: color.accent50 - } - }, - dataBackground: { - lineStyle: { - color: color.accent30 - }, - areaStyle: { - color: color.accent20 - } - }, - selectedDataBackground: { - lineStyle: { - color: color.accent50 - }, - areaStyle: { - color: color.accent30 - } - } - }, - visualMap: { - textStyle: { - color: color.secondary - }, - handleStyle: { - borderColor: color.neutral30 - } - }, - timeline: { - lineStyle: { - color: color.accent10 - }, - label: { - color: color.tertiary - }, - controlStyle: { - color: color.accent30, - borderColor: color.accent30 - } - }, - calendar: { - itemStyle: { - color: color.neutral00, - borderColor: color.neutral20 - }, - dayLabel: { - color: color.tertiary - }, - monthLabel: { - color: color.secondary - }, - yearLabel: { - color: color.secondary - } - }, - matrix: { - x: matrixAxis, - y: matrixAxis, - backgroundColor: { - borderColor: color.axisLine - }, - body: { - itemStyle: { - borderColor: color.borderTint - } - } - }, - timeAxis: axisCommon(), - logAxis: axisCommon(), - valueAxis: axisCommon(), - categoryAxis: axisCommon(), - line: { - symbol: 'circle' - }, - graph: { - color: color.theme - }, - gauge: { - title: { - color: color.secondary - }, - axisLine: { - lineStyle: { - color: [[1, color.neutral05]] - } - }, - axisLabel: { - color: color.axisLabel - }, - detail: { - color: color.primary - } - }, - candlestick: { - itemStyle: { - color: '#f64e56', - color0: '#54ea92', - borderColor: '#f64e56', - borderColor0: '#54ea92' // borderColor: '#ca2824', - // borderColor0: '#09a443' - - } - }, - funnel: { - itemStyle: { - borderColor: color.background - } - }, - radar: function () { - var radar = axisCommon(); - radar.axisName = { - color: color.axisLabel - }; - radar.axisLine.lineStyle.color = color.neutral20; - return radar; - }(), - treemap: { - breadcrumb: { - itemStyle: { - color: color.neutral20, - textStyle: { - color: color.secondary - } - }, - emphasis: { - itemStyle: { - color: color.neutral30 - } - } - } - }, - sunburst: { - itemStyle: { - borderColor: color.background - } - }, - map: { - itemStyle: { - borderColor: color.border, - areaColor: color.neutral10 - }, - label: { - color: color.tertiary - }, - emphasis: { - label: { - color: color.primary - }, - itemStyle: { - areaColor: color.highlight - } - }, - select: { - label: { - color: color.primary - }, - itemStyle: { - areaColor: color.highlight - } - } - }, - geo: { - itemStyle: { - borderColor: color.border, - areaColor: color.neutral10 - }, - emphasis: { - label: { - color: color.primary - }, - itemStyle: { - areaColor: color.highlight - } - }, - select: { - label: { - color: color.primary - }, - itemStyle: { - color: color.highlight - } - } - } - }; - theme.categoryAxis.splitLine.show = false; - /** - * Usage of query: - * `chart.on('click', query, handler);` - * The `query` can be: - * + The component type query string, only `mainType` or `mainType.subType`, - * like: 'xAxis', 'series', 'xAxis.category' or 'series.line'. - * + The component query object, like: - * `{seriesIndex: 2}`, `{seriesName: 'xx'}`, `{seriesId: 'some'}`, - * `{xAxisIndex: 2}`, `{xAxisName: 'xx'}`, `{xAxisId: 'some'}`. - * + The data query object, like: - * `{dataIndex: 123}`, `{dataType: 'link'}`, `{name: 'some'}`. - * + The other query object (cmponent customized query), like: - * `{element: 'some'}` (only available in custom series). - * - * Caveat: If a prop in the `query` object is `null/undefined`, it is the - * same as there is no such prop in the `query` object. - */ - - var ECEventProcessor = - /** @class */ - function () { - function ECEventProcessor() {} - - ECEventProcessor.prototype.normalizeQuery = function (query) { - var cptQuery = {}; - var dataQuery = {}; - var otherQuery = {}; // `query` is `mainType` or `mainType.subType` of component. - - if (isString(query)) { - var condCptType = parseClassType(query); // `.main` and `.sub` may be ''. - - cptQuery.mainType = condCptType.main || null; - cptQuery.subType = condCptType.sub || null; - } // `query` is an object, convert to {mainType, index, name, id}. - else { - // `xxxIndex`, `xxxName`, `xxxId`, `name`, `dataIndex`, `dataType` is reserved, - // can not be used in `compomentModel.filterForExposedEvent`. - var suffixes_1 = ['Index', 'Name', 'Id']; - var dataKeys_1 = { - name: 1, - dataIndex: 1, - dataType: 1 - }; - each$4(query, function (val, key) { - var reserved = false; - - for (var i = 0; i < suffixes_1.length; i++) { - var propSuffix = suffixes_1[i]; - var suffixPos = key.lastIndexOf(propSuffix); - - if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) { - var mainType = key.slice(0, suffixPos); // Consider `dataIndex`. - - if (mainType !== 'data') { - cptQuery.mainType = mainType; - cptQuery[propSuffix.toLowerCase()] = val; - reserved = true; - } - } - } - - if (dataKeys_1.hasOwnProperty(key)) { - dataQuery[key] = val; - reserved = true; - } - - if (!reserved) { - otherQuery[key] = val; - } - }); - } - - return { - cptQuery: cptQuery, - dataQuery: dataQuery, - otherQuery: otherQuery - }; - }; - - ECEventProcessor.prototype.filter = function (eventType, query) { - // They should be assigned before each trigger call. - var eventInfo = this.eventInfo; - - if (!eventInfo) { - return true; - } - - var targetEl = eventInfo.targetEl; - var packedEvent = eventInfo.packedEvent; - var model = eventInfo.model; - var view = eventInfo.view; // For event like 'globalout'. - - if (!model || !view) { - return true; - } - - var cptQuery = query.cptQuery; - var dataQuery = query.dataQuery; - return check(cptQuery, model, 'mainType') && check(cptQuery, model, 'subType') && check(cptQuery, model, 'index', 'componentIndex') && check(cptQuery, model, 'name') && check(cptQuery, model, 'id') && check(dataQuery, packedEvent, 'name') && check(dataQuery, packedEvent, 'dataIndex') && check(dataQuery, packedEvent, 'dataType') && (!view.filterForExposedEvent || view.filterForExposedEvent(eventType, query.otherQuery, targetEl, packedEvent)); - - function check(query, host, prop, propOnHost) { - return query[prop] == null || host[propOnHost || prop] === query[prop]; - } - }; - - ECEventProcessor.prototype.afterTrigger = function () { - // Make sure the eventInfo won't be used in next trigger. - this.eventInfo = null; - }; - - return ECEventProcessor; - }(); - - var SYMBOL_PROPS_WITH_CB = ['symbol', 'symbolSize', 'symbolRotate', 'symbolOffset']; - var SYMBOL_PROPS = SYMBOL_PROPS_WITH_CB.concat(['symbolKeepAspect']); // Encoding visual for all series include which is filtered for legend drawing - - var seriesSymbolTask = { - createOnAllSeries: true, - // For legend. - performRawSeries: true, - reset: function (seriesModel, ecModel) { - var data = seriesModel.getData(); - - if (seriesModel.legendIcon) { - data.setVisual('legendIcon', seriesModel.legendIcon); - } - - if (!seriesModel.hasSymbolVisual) { - return; - } - - var symbolOptions = {}; - var symbolOptionsCb = {}; - var hasCallback = false; - - for (var i = 0; i < SYMBOL_PROPS_WITH_CB.length; i++) { - var symbolPropName = SYMBOL_PROPS_WITH_CB[i]; - var val = seriesModel.get(symbolPropName); - - if (isFunction(val)) { - hasCallback = true; - symbolOptionsCb[symbolPropName] = val; - } else { - symbolOptions[symbolPropName] = val; - } - } - - symbolOptions.symbol = symbolOptions.symbol || seriesModel.defaultSymbol; - data.setVisual(extend({ - legendIcon: seriesModel.legendIcon || symbolOptions.symbol, - symbolKeepAspect: seriesModel.get('symbolKeepAspect') - }, symbolOptions)); // Only visible series has each data be visual encoded - - if (ecModel.isSeriesFiltered(seriesModel)) { - return; - } - - var symbolPropsCb = keys(symbolOptionsCb); - - function dataEach(data, idx) { - var rawValue = seriesModel.getRawValue(idx); - var params = seriesModel.getDataParams(idx); - - for (var i = 0; i < symbolPropsCb.length; i++) { - var symbolPropName = symbolPropsCb[i]; - data.setItemVisual(idx, symbolPropName, symbolOptionsCb[symbolPropName](rawValue, params)); - } - } - - return { - dataEach: hasCallback ? dataEach : null - }; - } - }; - var dataSymbolTask = { - createOnAllSeries: true, - // For legend. - performRawSeries: true, - reset: function (seriesModel, ecModel) { - if (!seriesModel.hasSymbolVisual) { - return; - } // Only visible series has each data be visual encoded - - - if (ecModel.isSeriesFiltered(seriesModel)) { - return; - } - - var data = seriesModel.getData(); - - function dataEach(data, idx) { - var itemModel = data.getItemModel(idx); - - for (var i = 0; i < SYMBOL_PROPS.length; i++) { - var symbolPropName = SYMBOL_PROPS[i]; - var val = itemModel.getShallow(symbolPropName, true); - - if (val != null) { - data.setItemVisual(idx, symbolPropName, val); - } - } - } - - return { - dataEach: data.hasItemOption ? dataEach : null - }; - } - }; - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * AUTO-GENERATED FILE. DO NOT MODIFY. - */ - - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - function getItemVisualFromData(data, dataIndex, key) { - switch (key) { - case 'color': - var style = data.getItemVisual(dataIndex, 'style'); - return style[data.getVisual('drawType')]; - - case 'opacity': - return data.getItemVisual(dataIndex, 'style').opacity; - - case 'symbol': - case 'symbolSize': - case 'liftZ': - return data.getItemVisual(dataIndex, key); - - default: - { - console.warn("Unknown visual type " + key); - } - } - } - - function getVisualFromData(data, key) { - switch (key) { - case 'color': - var style = data.getVisual('style'); - return style[data.getVisual('drawType')]; - - case 'opacity': - return data.getVisual('style').opacity; - - case 'symbol': - case 'symbolSize': - case 'liftZ': - return data.getVisual(key); - - default: - { - console.warn("Unknown visual type " + key); - } - } - } - - function handleSeriesLegacySelectEvents(type, eventPostfix, ecIns, ecModel, payload) { - var legacyEventName = type + eventPostfix; - - if (!ecIns.isSilent(legacyEventName)) { - { - deprecateLog("event " + legacyEventName + " is deprecated."); - } - ecModel.eachComponent({ - mainType: 'series', - subType: 'pie' - }, function (seriesModel) { - var seriesIndex = seriesModel.seriesIndex; - var selectedMap = seriesModel.option.selectedMap; - var selected = payload.selected; - - for (var i = 0; i < selected.length; i++) { - if (selected[i].seriesIndex === seriesIndex) { - var data = seriesModel.getData(); - var dataIndex = queryDataIndex(data, payload.fromActionPayload); - ecIns.trigger(legacyEventName, { - type: legacyEventName, - seriesId: seriesModel.id, - name: isArray(dataIndex) ? data.getName(dataIndex[0]) : data.getName(dataIndex), - selected: isString(selectedMap) ? selectedMap : extend({}, selectedMap) - }); - } - } - }); - } - } - - function handleLegacySelectEvents(messageCenter, ecIns, api) { - messageCenter.on('selectchanged', function (params) { - var ecModel = api.getModel(); - - if (params.isFromClick) { - handleSeriesLegacySelectEvents('map', 'selectchanged', ecIns, ecModel, params); - handleSeriesLegacySelectEvents('pie', 'selectchanged', ecIns, ecModel, params); - } else if (params.fromAction === 'select') { - handleSeriesLegacySelectEvents('map', 'selected', ecIns, ecModel, params); - handleSeriesLegacySelectEvents('pie', 'selected', ecIns, ecModel, params); - } else if (params.fromAction === 'unselect') { - handleSeriesLegacySelectEvents('map', 'unselected', ecIns, ecModel, params); - handleSeriesLegacySelectEvents('pie', 'unselected', ecIns, ecModel, params); - } - }); - } - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * AUTO-GENERATED FILE. DO NOT MODIFY. - */ - - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - - function findEventDispatcher(target, det, returnFirstMatch) { - var found; - - while (target) { - if (det(target)) { - found = target; - - if (returnFirstMatch) { - break; - } - } - - target = target.__hostTarget || target.parent; - } - - return found; - } - - var wmUniqueIndex = Math.round(Math.random() * 9); - var supportDefineProperty = typeof Object.defineProperty === 'function'; - - var WeakMap = function () { - function WeakMap() { - this._id = '__ec_inner_' + wmUniqueIndex++; - } - - WeakMap.prototype.get = function (key) { - return this._guard(key)[this._id]; - }; - - WeakMap.prototype.set = function (key, value) { - var target = this._guard(key); - - if (supportDefineProperty) { - Object.defineProperty(target, this._id, { - value: value, - enumerable: false, - configurable: true - }); - } else { - target[this._id] = value; - } - - return this; - }; - - WeakMap.prototype["delete"] = function (key) { - if (this.has(key)) { - delete this._guard(key)[this._id]; - return true; - } - - return false; - }; - - WeakMap.prototype.has = function (key) { - return !!this._guard(key)[this._id]; - }; - - WeakMap.prototype._guard = function (key) { - if (key !== Object(key)) { - throw TypeError('Value of WeakMap is not a non-null object.'); - } - - return key; - }; - - return WeakMap; - }(); - /** - * Triangle shape - * @inner - */ - - - var Triangle = Path.extend({ - type: 'triangle', - shape: { - cx: 0, - cy: 0, - width: 0, - height: 0 - }, - buildPath: function (path, shape) { - var cx = shape.cx; - var cy = shape.cy; - var width = shape.width / 2; - var height = shape.height / 2; - path.moveTo(cx, cy - height); - path.lineTo(cx + width, cy + height); - path.lineTo(cx - width, cy + height); - path.closePath(); - } - }); - /** - * Diamond shape - * @inner - */ - - var Diamond = Path.extend({ - type: 'diamond', - shape: { - cx: 0, - cy: 0, - width: 0, - height: 0 - }, - buildPath: function (path, shape) { - var cx = shape.cx; - var cy = shape.cy; - var width = shape.width / 2; - var height = shape.height / 2; - path.moveTo(cx, cy - height); - path.lineTo(cx + width, cy); - path.lineTo(cx, cy + height); - path.lineTo(cx - width, cy); - path.closePath(); - } - }); - /** - * Pin shape - * @inner - */ - - var Pin = Path.extend({ - type: 'pin', - shape: { - // x, y on the cusp - x: 0, - y: 0, - width: 0, - height: 0 - }, - buildPath: function (path, shape) { - var x = shape.x; - var y = shape.y; - var w = shape.width / 5 * 3; // Height must be larger than width - - var h = Math.max(w, shape.height); - var r = w / 2; // Dist on y with tangent point and circle center - - var dy = r * r / (h - r); - var cy = y - h + r + dy; - var angle = Math.asin(dy / r); // Dist on x with tangent point and circle center - - var dx = Math.cos(angle) * r; - var tanX = Math.sin(angle); - var tanY = Math.cos(angle); - var cpLen = r * 0.6; - var cpLen2 = r * 0.7; - path.moveTo(x - dx, cy + dy); - path.arc(x, cy, r, Math.PI - angle, Math.PI * 2 + angle); - path.bezierCurveTo(x + dx - tanX * cpLen, cy + dy + tanY * cpLen, x, y - cpLen2, x, y); - path.bezierCurveTo(x, y - cpLen2, x - dx + tanX * cpLen, cy + dy + tanY * cpLen, x - dx, cy + dy); - path.closePath(); - } - }); - /** - * Arrow shape - * @inner - */ - - var Arrow = Path.extend({ - type: 'arrow', - shape: { - x: 0, - y: 0, - width: 0, - height: 0 - }, - buildPath: function (ctx, shape) { - var height = shape.height; - var width = shape.width; - var x = shape.x; - var y = shape.y; - var dx = width / 3 * 2; - ctx.moveTo(x, y); - ctx.lineTo(x + dx, y + height); - ctx.lineTo(x, y + height / 4 * 3); - ctx.lineTo(x - dx, y + height); - ctx.lineTo(x, y); - ctx.closePath(); - } - }); - /** - * Map of path constructors - */ - // TODO Use function to build symbol path. - - var symbolCtors = { - line: Line, - rect: Rect, - roundRect: Rect, - square: Rect, - circle: Circle, - diamond: Diamond, - pin: Pin, - arrow: Arrow, - triangle: Triangle - }; - var symbolShapeMakers = { - line: function (x, y, w, h, shape) { - shape.x1 = x; - shape.y1 = y + h / 2; - shape.x2 = x + w; - shape.y2 = y + h / 2; - }, - rect: function (x, y, w, h, shape) { - shape.x = x; - shape.y = y; - shape.width = w; - shape.height = h; - }, - roundRect: function (x, y, w, h, shape) { - shape.x = x; - shape.y = y; - shape.width = w; - shape.height = h; - shape.r = Math.min(w, h) / 4; - }, - square: function (x, y, w, h, shape) { - var size = Math.min(w, h); - shape.x = x; - shape.y = y; - shape.width = size; - shape.height = size; - }, - circle: function (x, y, w, h, shape) { - // Put circle in the center of square - shape.cx = x + w / 2; - shape.cy = y + h / 2; - shape.r = Math.min(w, h) / 2; - }, - diamond: function (x, y, w, h, shape) { - shape.cx = x + w / 2; - shape.cy = y + h / 2; - shape.width = w; - shape.height = h; - }, - pin: function (x, y, w, h, shape) { - shape.x = x + w / 2; - shape.y = y + h / 2; - shape.width = w; - shape.height = h; - }, - arrow: function (x, y, w, h, shape) { - shape.x = x + w / 2; - shape.y = y + h / 2; - shape.width = w; - shape.height = h; - }, - triangle: function (x, y, w, h, shape) { - shape.cx = x + w / 2; - shape.cy = y + h / 2; - shape.width = w; - shape.height = h; - } - }; - var symbolBuildProxies = {}; - each$4(symbolCtors, function (Ctor, name) { - symbolBuildProxies[name] = new Ctor(); - }); - var SymbolClz = Path.extend({ - type: 'symbol', - shape: { - symbolType: '', - x: 0, - y: 0, - width: 0, - height: 0 - }, - calculateTextPosition: function (out, config, rect) { - var res = calculateTextPosition(out, config, rect); - var shape = this.shape; - - if (shape && shape.symbolType === 'pin' && config.position === 'inside') { - res.y = rect.y + rect.height * 0.4; - } - - return res; - }, - buildPath: function (ctx, shape, inBundle) { - var symbolType = shape.symbolType; - - if (symbolType !== 'none') { - var proxySymbol = symbolBuildProxies[symbolType]; - - if (!proxySymbol) { - // Default rect - symbolType = 'rect'; - proxySymbol = symbolBuildProxies[symbolType]; - } - - symbolShapeMakers[symbolType](shape.x, shape.y, shape.width, shape.height, proxySymbol.shape); - proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle); - } - } - }); // Provide setColor helper method to avoid determine if set the fill or stroke outside - - function symbolPathSetColor(color, innerColor) { - if (this.type !== 'image') { - var symbolStyle = this.style; - - if (this.__isEmptyBrush) { - symbolStyle.stroke = color; - symbolStyle.fill = innerColor || tokens.color.neutral00; // TODO Same width with lineStyle in LineView - - symbolStyle.lineWidth = 2; - } else if (this.shape.symbolType === 'line') { - symbolStyle.stroke = color; - } else { - symbolStyle.fill = color; - } - - this.markRedraw(); - } - } - /** - * Create a symbol element with given symbol configuration: shape, x, y, width, height, color - */ - - - function createSymbol(symbolType, x, y, w, h, color, // whether to keep the ratio of w/h, - keepAspect) { - // TODO Support image object, DynamicImage. - var isEmpty = symbolType.indexOf('empty') === 0; - - if (isEmpty) { - symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6); - } - - var symbolPath; - - if (symbolType.indexOf('image://') === 0) { - symbolPath = makeImage(symbolType.slice(8), new BoundingRect(x, y, w, h), keepAspect ? 'center' : 'cover'); - } else if (symbolType.indexOf('path://') === 0) { - symbolPath = makePath(symbolType.slice(7), {}, new BoundingRect(x, y, w, h), keepAspect ? 'center' : 'cover'); - } else { - symbolPath = new SymbolClz({ - shape: { - symbolType: symbolType, - x: x, - y: y, - width: w, - height: h - } - }); - } - - symbolPath.__isEmptyBrush = isEmpty; // TODO Should deprecate setColor - - symbolPath.setColor = symbolPathSetColor; - - if (color) { - symbolPath.setColor(color); - } - - return symbolPath; - } - - function normalizeSymbolSize(symbolSize) { - if (!isArray(symbolSize)) { - symbolSize = [+symbolSize, +symbolSize]; - } - - return [symbolSize[0] || 0, symbolSize[1] || 0]; - } - - function normalizeSymbolOffset(symbolOffset, symbolSize) { - if (symbolOffset == null) { - return; - } - - if (!isArray(symbolOffset)) { - symbolOffset = [symbolOffset, symbolOffset]; - } - - return [parsePercent(symbolOffset[0], symbolSize[0]) || 0, parsePercent(retrieve2(symbolOffset[1], symbolOffset[0]), symbolSize[1]) || 0]; - } - - function isSafeNum(num) { - return isFinite(num); - } - - function createLinearGradient(ctx, obj, rect) { - var x = obj.x == null ? 0 : obj.x; - var x2 = obj.x2 == null ? 1 : obj.x2; - var y = obj.y == null ? 0 : obj.y; - var y2 = obj.y2 == null ? 0 : obj.y2; - - if (!obj.global) { - x = x * rect.width + rect.x; - x2 = x2 * rect.width + rect.x; - y = y * rect.height + rect.y; - y2 = y2 * rect.height + rect.y; - } - - x = isSafeNum(x) ? x : 0; - x2 = isSafeNum(x2) ? x2 : 1; - y = isSafeNum(y) ? y : 0; - y2 = isSafeNum(y2) ? y2 : 0; - var canvasGradient = ctx.createLinearGradient(x, y, x2, y2); - return canvasGradient; - } - - function createRadialGradient(ctx, obj, rect) { - var width = rect.width; - var height = rect.height; - var min = Math.min(width, height); - var x = obj.x == null ? 0.5 : obj.x; - var y = obj.y == null ? 0.5 : obj.y; - var r = obj.r == null ? 0.5 : obj.r; - - if (!obj.global) { - x = x * width + rect.x; - y = y * height + rect.y; - r = r * min; - } - - x = isSafeNum(x) ? x : 0.5; - y = isSafeNum(y) ? y : 0.5; - r = r >= 0 && isSafeNum(r) ? r : 0.5; - var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r); - return canvasGradient; - } - - function getCanvasGradient(ctx, obj, rect) { - var canvasGradient = obj.type === 'radial' ? createRadialGradient(ctx, obj, rect) : createLinearGradient(ctx, obj, rect); - var colorStops = obj.colorStops; - - for (var i = 0; i < colorStops.length; i++) { - canvasGradient.addColorStop(colorStops[i].offset, colorStops[i].color); - } - - return canvasGradient; - } - - function isClipPathChanged(clipPaths, prevClipPaths) { - if (clipPaths === prevClipPaths || !clipPaths && !prevClipPaths) { - return false; - } - - if (!clipPaths || !prevClipPaths || clipPaths.length !== prevClipPaths.length) { - return true; - } - - for (var i = 0; i < clipPaths.length; i++) { - if (clipPaths[i] !== prevClipPaths[i]) { - return true; - } - } - - return false; - } - - function parseInt10(val) { - return parseInt(val, 10); - } - - function getSize(root, whIdx, opts) { - var wh = ['width', 'height'][whIdx]; - var cwh = ['clientWidth', 'clientHeight'][whIdx]; - var plt = ['paddingLeft', 'paddingTop'][whIdx]; - var prb = ['paddingRight', 'paddingBottom'][whIdx]; - - if (opts[wh] != null && opts[wh] !== 'auto') { - return parseFloat(opts[wh]); - } - - var stl = document.defaultView.getComputedStyle(root); - return (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh])) - (parseInt10(stl[plt]) || 0) - (parseInt10(stl[prb]) || 0) | 0; - } - - function normalizeLineDash(lineType, lineWidth) { - if (!lineType || lineType === 'solid' || !(lineWidth > 0)) { - return null; - } - - return lineType === 'dashed' ? [4 * lineWidth, 2 * lineWidth] : lineType === 'dotted' ? [lineWidth] : isNumber(lineType) ? [lineType] : isArray(lineType) ? lineType : null; - } - - function getLineDash(el) { - var style = el.style; - var lineDash = style.lineDash && style.lineWidth > 0 && normalizeLineDash(style.lineDash, style.lineWidth); - var lineDashOffset = style.lineDashOffset; - - if (lineDash) { - var lineScale_1 = style.strokeNoScale && el.getLineScale ? el.getLineScale() : 1; - - if (lineScale_1 && lineScale_1 !== 1) { - lineDash = map$1(lineDash, function (rawVal) { - return rawVal / lineScale_1; - }); - lineDashOffset /= lineScale_1; - } - } - - return [lineDash, lineDashOffset]; - } - - var pathProxyForDraw = new PathProxy(true); - - function styleHasStroke(style) { - var stroke = style.stroke; - return !(stroke == null || stroke === 'none' || !(style.lineWidth > 0)); - } - - function isValidStrokeFillStyle(strokeOrFill) { - return typeof strokeOrFill === 'string' && strokeOrFill !== 'none'; - } - - function styleHasFill(style) { - var fill = style.fill; - return fill != null && fill !== 'none'; - } - - function doFillPath(ctx, style) { - if (style.fillOpacity != null && style.fillOpacity !== 1) { - var originalGlobalAlpha = ctx.globalAlpha; - ctx.globalAlpha = style.fillOpacity * style.opacity; - ctx.fill(); - ctx.globalAlpha = originalGlobalAlpha; - } else { - ctx.fill(); - } - } - - function doStrokePath(ctx, style) { - if (style.strokeOpacity != null && style.strokeOpacity !== 1) { - var originalGlobalAlpha = ctx.globalAlpha; - ctx.globalAlpha = style.strokeOpacity * style.opacity; - ctx.stroke(); - ctx.globalAlpha = originalGlobalAlpha; - } else { - ctx.stroke(); - } - } - - function createCanvasPattern(ctx, pattern, el) { - var image = createOrUpdateImage(pattern.image, pattern.__image, el); - - if (isImageReady(image)) { - var canvasPattern = ctx.createPattern(image, pattern.repeat || 'repeat'); - - if (typeof DOMMatrix === 'function' && canvasPattern && canvasPattern.setTransform) { - var matrix = new DOMMatrix(); - matrix.translateSelf(pattern.x || 0, pattern.y || 0); - matrix.rotateSelf(0, 0, (pattern.rotation || 0) * RADIAN_TO_DEGREE); - matrix.scaleSelf(pattern.scaleX || 1, pattern.scaleY || 1); - canvasPattern.setTransform(matrix); - } - - return canvasPattern; - } - } - - function brushPath(ctx, el, style, inBatch) { - var _a; - - var hasStroke = styleHasStroke(style); - var hasFill = styleHasFill(style); - var strokePercent = style.strokePercent; - var strokePart = strokePercent < 1; - var firstDraw = !el.path; - - if ((!el.silent || strokePart) && firstDraw) { - el.createPathProxy(); - } - - var path = el.path || pathProxyForDraw; - var dirtyFlag = el.__dirty; - - if (!inBatch) { - var fill = style.fill; - var stroke = style.stroke; - var hasFillGradient = hasFill && !!fill.colorStops; - var hasStrokeGradient = hasStroke && !!stroke.colorStops; - var hasFillPattern = hasFill && !!fill.image; - var hasStrokePattern = hasStroke && !!stroke.image; - var fillGradient = void 0; - var strokeGradient = void 0; - var fillPattern = void 0; - var strokePattern = void 0; - var rect = void 0; - - if (hasFillGradient || hasStrokeGradient) { - rect = el.getBoundingRect(); - } - - if (hasFillGradient) { - fillGradient = dirtyFlag ? getCanvasGradient(ctx, fill, rect) : el.__canvasFillGradient; - el.__canvasFillGradient = fillGradient; - } - - if (hasStrokeGradient) { - strokeGradient = dirtyFlag ? getCanvasGradient(ctx, stroke, rect) : el.__canvasStrokeGradient; - el.__canvasStrokeGradient = strokeGradient; - } - - if (hasFillPattern) { - fillPattern = dirtyFlag || !el.__canvasFillPattern ? createCanvasPattern(ctx, fill, el) : el.__canvasFillPattern; - el.__canvasFillPattern = fillPattern; - } - - if (hasStrokePattern) { - strokePattern = dirtyFlag || !el.__canvasStrokePattern ? createCanvasPattern(ctx, stroke, el) : el.__canvasStrokePattern; - el.__canvasStrokePattern = strokePattern; - } - - if (hasFillGradient) { - ctx.fillStyle = fillGradient; - } else if (hasFillPattern) { - if (fillPattern) { - ctx.fillStyle = fillPattern; - } else { - hasFill = false; - } - } - - if (hasStrokeGradient) { - ctx.strokeStyle = strokeGradient; - } else if (hasStrokePattern) { - if (strokePattern) { - ctx.strokeStyle = strokePattern; - } else { - hasStroke = false; - } - } - } - - var scale = el.getGlobalScale(); - path.setScale(scale[0], scale[1], el.segmentIgnoreThreshold); - var lineDash; - var lineDashOffset; - - if (ctx.setLineDash && style.lineDash) { - _a = getLineDash(el), lineDash = _a[0], lineDashOffset = _a[1]; - } - - var needsRebuild = true; - - if (firstDraw || dirtyFlag & SHAPE_CHANGED_BIT) { - path.setDPR(ctx.dpr); - - if (strokePart) { - path.setContext(null); - } else { - path.setContext(ctx); - needsRebuild = false; - } - - path.reset(); - el.buildPath(path, el.shape, inBatch); - path.toStatic(); - el.pathUpdated(); - } - - if (needsRebuild) { - path.rebuildPath(ctx, strokePart ? strokePercent : 1); - } - - if (lineDash) { - ctx.setLineDash(lineDash); - ctx.lineDashOffset = lineDashOffset; - } - - if (!inBatch) { - if (style.strokeFirst) { - if (hasStroke) { - doStrokePath(ctx, style); - } - - if (hasFill) { - doFillPath(ctx, style); - } - } else { - if (hasFill) { - doFillPath(ctx, style); - } - - if (hasStroke) { - doStrokePath(ctx, style); - } - } - } - - if (lineDash) { - ctx.setLineDash([]); - } - } - - function brushImage(ctx, el, style) { - var image = el.__image = createOrUpdateImage(style.image, el.__image, el, el.onload); - - if (!image || !isImageReady(image)) { - return; - } - - var x = style.x || 0; - var y = style.y || 0; - var width = el.getWidth(); - var height = el.getHeight(); - var aspect = image.width / image.height; - - if (width == null && height != null) { - width = height * aspect; - } else if (height == null && width != null) { - height = width / aspect; - } else if (width == null && height == null) { - width = image.width; - height = image.height; - } - - if (style.sWidth && style.sHeight) { - var sx = style.sx || 0; - var sy = style.sy || 0; - ctx.drawImage(image, sx, sy, style.sWidth, style.sHeight, x, y, width, height); - } else if (style.sx && style.sy) { - var sx = style.sx; - var sy = style.sy; - var sWidth = width - sx; - var sHeight = height - sy; - ctx.drawImage(image, sx, sy, sWidth, sHeight, x, y, width, height); - } else { - ctx.drawImage(image, x, y, width, height); - } - } - - function brushText(ctx, el, style) { - var _a; - - var text = style.text; - text != null && (text += ''); - - if (text) { - ctx.font = style.font || DEFAULT_FONT; - ctx.textAlign = style.textAlign; - ctx.textBaseline = style.textBaseline; - var lineDash = void 0; - var lineDashOffset = void 0; - - if (ctx.setLineDash && style.lineDash) { - _a = getLineDash(el), lineDash = _a[0], lineDashOffset = _a[1]; - } - - if (lineDash) { - ctx.setLineDash(lineDash); - ctx.lineDashOffset = lineDashOffset; - } - - if (style.strokeFirst) { - if (styleHasStroke(style)) { - ctx.strokeText(text, style.x, style.y); - } - - if (styleHasFill(style)) { - ctx.fillText(text, style.x, style.y); - } - } else { - if (styleHasFill(style)) { - ctx.fillText(text, style.x, style.y); - } - - if (styleHasStroke(style)) { - ctx.strokeText(text, style.x, style.y); - } - } - - if (lineDash) { - ctx.setLineDash([]); - } - } - } - - var SHADOW_NUMBER_PROPS = ['shadowBlur', 'shadowOffsetX', 'shadowOffsetY']; - var STROKE_PROPS = [['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]]; - - function bindCommonProps(ctx, style, prevStyle, forceSetAll, scope) { - var styleChanged = false; - - if (!forceSetAll) { - prevStyle = prevStyle || {}; - - if (style === prevStyle) { - return false; - } - } - - if (forceSetAll || style.opacity !== prevStyle.opacity) { - flushPathDrawn(ctx, scope); - styleChanged = true; - var opacity = Math.max(Math.min(style.opacity, 1), 0); - ctx.globalAlpha = isNaN(opacity) ? DEFAULT_COMMON_STYLE.opacity : opacity; - } - - if (forceSetAll || style.blend !== prevStyle.blend) { - if (!styleChanged) { - flushPathDrawn(ctx, scope); - styleChanged = true; - } - - ctx.globalCompositeOperation = style.blend || DEFAULT_COMMON_STYLE.blend; - } - - for (var i = 0; i < SHADOW_NUMBER_PROPS.length; i++) { - var propName = SHADOW_NUMBER_PROPS[i]; - - if (forceSetAll || style[propName] !== prevStyle[propName]) { - if (!styleChanged) { - flushPathDrawn(ctx, scope); - styleChanged = true; - } - - ctx[propName] = ctx.dpr * (style[propName] || 0); - } - } - - if (forceSetAll || style.shadowColor !== prevStyle.shadowColor) { - if (!styleChanged) { - flushPathDrawn(ctx, scope); - styleChanged = true; - } - - ctx.shadowColor = style.shadowColor || DEFAULT_COMMON_STYLE.shadowColor; - } - - return styleChanged; - } - - function bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetAll, scope) { - var style = getStyle(el, scope.inHover); - var prevStyle = forceSetAll ? null : prevEl && getStyle(prevEl, scope.inHover) || {}; - - if (style === prevStyle) { - return false; - } - - var styleChanged = bindCommonProps(ctx, style, prevStyle, forceSetAll, scope); - - if (forceSetAll || style.fill !== prevStyle.fill) { - if (!styleChanged) { - flushPathDrawn(ctx, scope); - styleChanged = true; - } - - isValidStrokeFillStyle(style.fill) && (ctx.fillStyle = style.fill); - } - - if (forceSetAll || style.stroke !== prevStyle.stroke) { - if (!styleChanged) { - flushPathDrawn(ctx, scope); - styleChanged = true; - } - - isValidStrokeFillStyle(style.stroke) && (ctx.strokeStyle = style.stroke); - } - - if (forceSetAll || style.opacity !== prevStyle.opacity) { - if (!styleChanged) { - flushPathDrawn(ctx, scope); - styleChanged = true; - } - - ctx.globalAlpha = style.opacity == null ? 1 : style.opacity; - } - - if (el.hasStroke()) { - var lineWidth = style.lineWidth; - var newLineWidth = lineWidth / (style.strokeNoScale && el.getLineScale ? el.getLineScale() : 1); - - if (ctx.lineWidth !== newLineWidth) { - if (!styleChanged) { - flushPathDrawn(ctx, scope); - styleChanged = true; - } - - ctx.lineWidth = newLineWidth; - } - } - - for (var i = 0; i < STROKE_PROPS.length; i++) { - var prop = STROKE_PROPS[i]; - var propName = prop[0]; - - if (forceSetAll || style[propName] !== prevStyle[propName]) { - if (!styleChanged) { - flushPathDrawn(ctx, scope); - styleChanged = true; - } - - ctx[propName] = style[propName] || prop[1]; - } - } - - return styleChanged; - } - - function bindImageStyle(ctx, el, prevEl, forceSetAll, scope) { - return bindCommonProps(ctx, getStyle(el, scope.inHover), prevEl && getStyle(prevEl, scope.inHover), forceSetAll, scope); - } - - function setContextTransform(ctx, el) { - var m = el.transform; - var dpr = ctx.dpr || 1; - - if (m) { - ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]); - } else { - ctx.setTransform(dpr, 0, 0, dpr, 0, 0); - } - } - - function updateClipStatus(clipPaths, ctx, scope) { - var allClipped = false; - - for (var i = 0; i < clipPaths.length; i++) { - var clipPath = clipPaths[i]; - allClipped = allClipped || clipPath.isZeroArea(); - setContextTransform(ctx, clipPath); - ctx.beginPath(); - clipPath.buildPath(ctx, clipPath.shape); - ctx.clip(); - } - - scope.allClipped = allClipped; - } - - function isTransformChanged(m0, m1) { - if (m0 && m1) { - return m0[0] !== m1[0] || m0[1] !== m1[1] || m0[2] !== m1[2] || m0[3] !== m1[3] || m0[4] !== m1[4] || m0[5] !== m1[5]; - } else if (!m0 && !m1) { - return false; - } - - return true; - } - - var DRAW_TYPE_PATH = 1; - var DRAW_TYPE_IMAGE = 2; - var DRAW_TYPE_TEXT = 3; - var DRAW_TYPE_INCREMENTAL = 4; - - function canPathBatch(style) { - var hasFill = styleHasFill(style); - var hasStroke = styleHasStroke(style); - return !(style.lineDash || !(+hasFill ^ +hasStroke) || hasFill && typeof style.fill !== 'string' || hasStroke && typeof style.stroke !== 'string' || style.strokePercent < 1 || style.strokeOpacity < 1 || style.fillOpacity < 1); - } - - function flushPathDrawn(ctx, scope) { - scope.batchFill && ctx.fill(); - scope.batchStroke && ctx.stroke(); - scope.batchFill = ''; - scope.batchStroke = ''; - } - - function getStyle(el, inHover) { - return inHover ? el.__hoverStyle || el.style : el.style; - } - - function brushSingle(ctx, el) { - brush(ctx, el, { - inHover: false, - viewWidth: 0, - viewHeight: 0 - }, true); - } - - function brush(ctx, el, scope, isLast) { - var m = el.transform; - - if (!el.shouldBePainted(scope.viewWidth, scope.viewHeight, false, false)) { - el.__dirty &= ~REDRAW_BIT; - el.__isRendered = false; - return; - } - - var clipPaths = el.__clipPaths; - var prevElClipPaths = scope.prevElClipPaths; - var forceSetTransform = false; - var forceSetStyle = false; - - if (!prevElClipPaths || isClipPathChanged(clipPaths, prevElClipPaths)) { - if (prevElClipPaths && prevElClipPaths.length) { - flushPathDrawn(ctx, scope); - ctx.restore(); - forceSetStyle = forceSetTransform = true; - scope.prevElClipPaths = null; - scope.allClipped = false; - scope.prevEl = null; - } - - if (clipPaths && clipPaths.length) { - flushPathDrawn(ctx, scope); - ctx.save(); - updateClipStatus(clipPaths, ctx, scope); - forceSetTransform = true; - } - - scope.prevElClipPaths = clipPaths; - } - - if (scope.allClipped) { - el.__isRendered = false; - return; - } - - el.beforeBrush && el.beforeBrush(); - el.innerBeforeBrush(); - var prevEl = scope.prevEl; - - if (!prevEl) { - forceSetStyle = forceSetTransform = true; - } - - var canBatchPath = el instanceof Path && el.autoBatch && canPathBatch(el.style); - - if (forceSetTransform || isTransformChanged(m, prevEl.transform)) { - flushPathDrawn(ctx, scope); - setContextTransform(ctx, el); - } else if (!canBatchPath) { - flushPathDrawn(ctx, scope); - } - - var style = getStyle(el, scope.inHover); - - if (el instanceof Path) { - if (scope.lastDrawType !== DRAW_TYPE_PATH) { - forceSetStyle = true; - scope.lastDrawType = DRAW_TYPE_PATH; - } - - bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetStyle, scope); - - if (!canBatchPath || !scope.batchFill && !scope.batchStroke) { - ctx.beginPath(); - } - - brushPath(ctx, el, style, canBatchPath); - - if (canBatchPath) { - scope.batchFill = style.fill || ''; - scope.batchStroke = style.stroke || ''; - } - } else { - if (el instanceof TSpan) { - if (scope.lastDrawType !== DRAW_TYPE_TEXT) { - forceSetStyle = true; - scope.lastDrawType = DRAW_TYPE_TEXT; - } - - bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetStyle, scope); - brushText(ctx, el, style); - } else if (el instanceof ZRImage) { - if (scope.lastDrawType !== DRAW_TYPE_IMAGE) { - forceSetStyle = true; - scope.lastDrawType = DRAW_TYPE_IMAGE; - } - - bindImageStyle(ctx, el, prevEl, forceSetStyle, scope); - brushImage(ctx, el, style); - } else if (el.getTemporalDisplayables) { - if (scope.lastDrawType !== DRAW_TYPE_INCREMENTAL) { - forceSetStyle = true; - scope.lastDrawType = DRAW_TYPE_INCREMENTAL; - } - - brushIncremental(ctx, el, scope); - } - } - - if (canBatchPath && isLast) { - flushPathDrawn(ctx, scope); - } - - el.innerAfterBrush(); - el.afterBrush && el.afterBrush(); - scope.prevEl = el; - el.__dirty = 0; - el.__isRendered = true; - } - - function brushIncremental(ctx, el, scope) { - var displayables = el.getDisplayables(); - var temporalDisplayables = el.getTemporalDisplayables(); - ctx.save(); - var innerScope = { - prevElClipPaths: null, - prevEl: null, - allClipped: false, - viewWidth: scope.viewWidth, - viewHeight: scope.viewHeight, - inHover: scope.inHover - }; - var i; - var len; - - for (i = el.getCursor(), len = displayables.length; i < len; i++) { - var displayable = displayables[i]; - displayable.beforeBrush && displayable.beforeBrush(); - displayable.innerBeforeBrush(); - brush(ctx, displayable, innerScope, i === len - 1); - displayable.innerAfterBrush(); - displayable.afterBrush && displayable.afterBrush(); - innerScope.prevEl = displayable; - } - - for (var i_1 = 0, len_1 = temporalDisplayables.length; i_1 < len_1; i_1++) { - var displayable = temporalDisplayables[i_1]; - displayable.beforeBrush && displayable.beforeBrush(); - displayable.innerBeforeBrush(); - brush(ctx, displayable, innerScope, i_1 === len_1 - 1); - displayable.innerAfterBrush(); - displayable.afterBrush && displayable.afterBrush(); - innerScope.prevEl = displayable; - } - - el.clearTemporalDisplayables(); - el.notClear = true; - ctx.restore(); - } - - var decalMap = new WeakMap(); - var decalCache = new LRU(100); - var decalKeys = ['symbol', 'symbolSize', 'symbolKeepAspect', 'color', 'backgroundColor', 'dashArrayX', 'dashArrayY', 'maxTileWidth', 'maxTileHeight']; - /** - * Create or update pattern image from decal options - * - * @param {InnerDecalObject | 'none'} decalObject decal options, 'none' if no decal - * @return {Pattern} pattern with generated image, null if no decal - */ - - function createOrUpdatePatternFromDecal(decalObject, api) { - if (decalObject === 'none') { - return null; - } - - var dpr = api.getDevicePixelRatio(); - var zr = api.getZr(); - var isSVG = zr.painter.type === 'svg'; - - if (decalObject.dirty) { - decalMap["delete"](decalObject); - } - - var oldPattern = decalMap.get(decalObject); - - if (oldPattern) { - return oldPattern; - } - - var decalOpt = defaults(decalObject, { - symbol: 'rect', - symbolSize: 1, - symbolKeepAspect: true, - color: 'rgba(0, 0, 0, 0.2)', - backgroundColor: null, - dashArrayX: 5, - dashArrayY: 5, - rotation: 0, - maxTileWidth: 512, - maxTileHeight: 512 - }); - - if (decalOpt.backgroundColor === 'none') { - decalOpt.backgroundColor = null; - } - - var pattern = { - repeat: 'repeat' - }; - setPatternnSource(pattern); - pattern.rotation = decalOpt.rotation; - pattern.scaleX = pattern.scaleY = isSVG ? 1 : 1 / dpr; - decalMap.set(decalObject, pattern); - decalObject.dirty = false; - return pattern; - - function setPatternnSource(pattern) { - var keys = [dpr]; - var isValidKey = true; - - for (var i = 0; i < decalKeys.length; ++i) { - var value = decalOpt[decalKeys[i]]; - - if (value != null && !isArray(value) && !isString(value) && !isNumber(value) && typeof value !== 'boolean') { - isValidKey = false; - break; - } - - keys.push(value); - } - - var cacheKey; - - if (isValidKey) { - cacheKey = keys.join(',') + (isSVG ? '-svg' : ''); - var cache = decalCache.get(cacheKey); - - if (cache) { - isSVG ? pattern.svgElement = cache : pattern.image = cache; - } - } - - var dashArrayX = normalizeDashArrayX(decalOpt.dashArrayX); - var dashArrayY = normalizeDashArrayY(decalOpt.dashArrayY); - var symbolArray = normalizeSymbolArray(decalOpt.symbol); - var lineBlockLengthsX = getLineBlockLengthX(dashArrayX); - var lineBlockLengthY = getLineBlockLengthY(dashArrayY); - var canvas = !isSVG && platformApi.createCanvas(); - var svgRoot = isSVG && { - tag: 'g', - attrs: {}, - key: 'dcl', - children: [] - }; - var pSize = getPatternSize(); - var ctx; - - if (canvas) { - canvas.width = pSize.width * dpr; - canvas.height = pSize.height * dpr; - ctx = canvas.getContext('2d'); - } - - brushDecal(); - - if (isValidKey) { - decalCache.put(cacheKey, canvas || svgRoot); - } - - pattern.image = canvas; - pattern.svgElement = svgRoot; - pattern.svgWidth = pSize.width; - pattern.svgHeight = pSize.height; - /** - * Get minimum length that can make a repeatable pattern. - * - * @return {Object} pattern width and height - */ - - function getPatternSize() { - /** - * For example, if dash is [[3, 2], [2, 1]] for X, it looks like - * |--- --- --- --- --- ... - * |-- -- -- -- -- -- -- -- ... - * |--- --- --- --- --- ... - * |-- -- -- -- -- -- -- -- ... - * So the minimum length of X is 15, - * which is the least common multiple of `3 + 2` and `2 + 1` - * |--- --- --- |--- --- ... - * |-- -- -- -- -- |-- -- -- ... - */ - var width = 1; - - for (var i = 0, xlen = lineBlockLengthsX.length; i < xlen; ++i) { - width = getLeastCommonMultiple(width, lineBlockLengthsX[i]); - } - - var symbolRepeats = 1; - - for (var i = 0, xlen = symbolArray.length; i < xlen; ++i) { - symbolRepeats = getLeastCommonMultiple(symbolRepeats, symbolArray[i].length); - } - - width *= symbolRepeats; - var height = lineBlockLengthY * lineBlockLengthsX.length * symbolArray.length; - { - var warn = function (attrName) { - /* eslint-disable-next-line */ - console.warn("Calculated decal size is greater than " + attrName + " due to decal option settings so " + attrName + " is used for the decal size. Please consider changing the decal option to make a smaller decal or set " + attrName + " to be larger to avoid incontinuity."); - }; - - if (width > decalOpt.maxTileWidth) { - warn('maxTileWidth'); - } - - if (height > decalOpt.maxTileHeight) { - warn('maxTileHeight'); - } - } - return { - width: Math.max(1, Math.min(width, decalOpt.maxTileWidth)), - height: Math.max(1, Math.min(height, decalOpt.maxTileHeight)) - }; - } - - function brushDecal() { - if (ctx) { - ctx.clearRect(0, 0, canvas.width, canvas.height); - - if (decalOpt.backgroundColor) { - ctx.fillStyle = decalOpt.backgroundColor; - ctx.fillRect(0, 0, canvas.width, canvas.height); - } - } - - var ySum = 0; - - for (var i = 0; i < dashArrayY.length; ++i) { - ySum += dashArrayY[i]; - } - - if (ySum <= 0) { - // dashArrayY is 0, draw nothing - return; - } - - var y = -lineBlockLengthY; - var yId = 0; - var yIdTotal = 0; - var xId0 = 0; - - while (y < pSize.height) { - if (yId % 2 === 0) { - var symbolYId = yIdTotal / 2 % symbolArray.length; - var x = 0; - var xId1 = 0; - var xId1Total = 0; - - while (x < pSize.width * 2) { - var xSum = 0; - - for (var i = 0; i < dashArrayX[xId0].length; ++i) { - xSum += dashArrayX[xId0][i]; - } - - if (xSum <= 0) { - // Skip empty line - break; - } // E.g., [15, 5, 20, 5] draws only for 15 and 20 - - - if (xId1 % 2 === 0) { - var size = (1 - decalOpt.symbolSize) * 0.5; - var left = x + dashArrayX[xId0][xId1] * size; - var top_1 = y + dashArrayY[yId] * size; - var width = dashArrayX[xId0][xId1] * decalOpt.symbolSize; - var height = dashArrayY[yId] * decalOpt.symbolSize; - var symbolXId = xId1Total / 2 % symbolArray[symbolYId].length; - brushSymbol(left, top_1, width, height, symbolArray[symbolYId][symbolXId]); - } - - x += dashArrayX[xId0][xId1]; - ++xId1Total; - ++xId1; - - if (xId1 === dashArrayX[xId0].length) { - xId1 = 0; - } - } - - ++xId0; - - if (xId0 === dashArrayX.length) { - xId0 = 0; - } - } - - y += dashArrayY[yId]; - ++yIdTotal; - ++yId; - - if (yId === dashArrayY.length) { - yId = 0; - } - } - - function brushSymbol(x, y, width, height, symbolType) { - var scale = isSVG ? 1 : dpr; - var symbol = createSymbol(symbolType, x * scale, y * scale, width * scale, height * scale, decalOpt.color, decalOpt.symbolKeepAspect); - - if (isSVG) { - var symbolVNode = zr.painter.renderOneToVNode(symbol); - - if (symbolVNode) { - svgRoot.children.push(symbolVNode); - } - } else { - // Paint to canvas for all other renderers. - brushSingle(ctx, symbol); - } - } - } - } - } - /** - * Convert symbol array into normalized array - * - * @param {string | (string | string[])[]} symbol symbol input - * @return {string[][]} normolized symbol array - */ - - - function normalizeSymbolArray(symbol) { - if (!symbol || symbol.length === 0) { - return [['rect']]; - } - - if (isString(symbol)) { - return [[symbol]]; - } - - var isAllString = true; - - for (var i = 0; i < symbol.length; ++i) { - if (!isString(symbol[i])) { - isAllString = false; - break; - } - } - - if (isAllString) { - return normalizeSymbolArray([symbol]); - } - - var result = []; - - for (var i = 0; i < symbol.length; ++i) { - if (isString(symbol[i])) { - result.push([symbol[i]]); - } else { - result.push(symbol[i]); - } - } - - return result; - } - /** - * Convert dash input into dashArray - * - * @param {DecalDashArrayX} dash dash input - * @return {number[][]} normolized dash array - */ - - - function normalizeDashArrayX(dash) { - if (!dash || dash.length === 0) { - return [[0, 0]]; - } - - if (isNumber(dash)) { - var dashValue = Math.ceil(dash); - return [[dashValue, dashValue]]; - } - /** - * [20, 5] should be normalized into [[20, 5]], - * while [20, [5, 10]] should be normalized into [[20, 20], [5, 10]] - */ - - - var isAllNumber = true; - - for (var i = 0; i < dash.length; ++i) { - if (!isNumber(dash[i])) { - isAllNumber = false; - break; - } - } - - if (isAllNumber) { - return normalizeDashArrayX([dash]); - } - - var result = []; - - for (var i = 0; i < dash.length; ++i) { - if (isNumber(dash[i])) { - var dashValue = Math.ceil(dash[i]); - result.push([dashValue, dashValue]); - } else { - var dashValue = map$1(dash[i], function (n) { - return Math.ceil(n); - }); - - if (dashValue.length % 2 === 1) { - // [4, 2, 1] means |---- - -- |---- - -- | - // so normalize it to be [4, 2, 1, 4, 2, 1] - result.push(dashValue.concat(dashValue)); - } else { - result.push(dashValue); - } - } - } - - return result; - } - /** - * Convert dash input into dashArray - * - * @param {DecalDashArrayY} dash dash input - * @return {number[]} normolized dash array - */ - - - function normalizeDashArrayY(dash) { - if (!dash || typeof dash === 'object' && dash.length === 0) { - return [0, 0]; - } - - if (isNumber(dash)) { - var dashValue_1 = Math.ceil(dash); - return [dashValue_1, dashValue_1]; - } - - var dashValue = map$1(dash, function (n) { - return Math.ceil(n); - }); - return dash.length % 2 ? dashValue.concat(dashValue) : dashValue; - } - /** - * Get block length of each line. A block is the length of dash line and space. - * For example, a line with [4, 1] has a dash line of 4 and a space of 1 after - * that, so the block length of this line is 5. - * - * @param {number[][]} dash dash array of X or Y - * @return {number[]} block length of each line - */ - - - function getLineBlockLengthX(dash) { - return map$1(dash, function (line) { - return getLineBlockLengthY(line); - }); - } - - function getLineBlockLengthY(dash) { - var blockLength = 0; - - for (var i = 0; i < dash.length; ++i) { - blockLength += dash[i]; - } - - if (dash.length % 2 === 1) { - // [4, 2, 1] means |---- - -- |---- - -- | - // So total length is (4 + 2 + 1) * 2 - return blockLength * 2; - } - - return blockLength; - } - - function decalVisual(ecModel, api) { - ecModel.eachRawSeries(function (seriesModel) { - if (ecModel.isSeriesFiltered(seriesModel)) { - return; - } - - var data = seriesModel.getData(); - - if (data.hasItemVisual()) { - data.each(function (idx) { - var decal = data.getItemVisual(idx, 'decal'); - - if (decal) { - var itemStyle = data.ensureUniqueItemVisual(idx, 'style'); - itemStyle.decal = createOrUpdatePatternFromDecal(decal, api); - } - }); - } - - var decal = data.getVisual('decal'); - - if (decal) { - var style = data.getVisual('style'); - style.decal = createOrUpdatePatternFromDecal(decal, api); - } - }); - } - - var lifecycle = new Eventful(); // Implementation of exported APIs. For example registerMap, getMap. - // The implementations will be registered when installing the component. - // Avoid these code being bundled to the core module. - - var implsStore = {}; // TODO Type - - function registerImpl(name, impl) { - { - if (implsStore[name]) { - error("Already has an implementation of " + name + "."); - } - } - implsStore[name] = impl; - } - - function getImpl(name) { - { - if (!implsStore[name]) { - error("Implementation of " + name + " doesn't exists."); - } - } - return implsStore[name]; - } - - var version = '6.0.0'; - var dependencies = { - zrender: '6.0.0' - }; - var TEST_FRAME_REMAIN_TIME = 1; - var PRIORITY_PROCESSOR_SERIES_FILTER = 800; // Some data processors depends on the stack result dimension (to calculate data extent). - // So data stack stage should be in front of data processing stage. - - var PRIORITY_PROCESSOR_DATASTACK = 900; // "Data filter" will block the stream, so it should be - // put at the beginning of data processing. - - var PRIORITY_PROCESSOR_FILTER = 1000; - var PRIORITY_PROCESSOR_DEFAULT = 2000; - var PRIORITY_PROCESSOR_STATISTIC = 5000; - var PRIORITY_VISUAL_LAYOUT = 1000; - var PRIORITY_VISUAL_PROGRESSIVE_LAYOUT = 1100; - var PRIORITY_VISUAL_GLOBAL = 2000; - var PRIORITY_VISUAL_CHART = 3000; - var PRIORITY_VISUAL_COMPONENT = 4000; // Visual property in data. Greater than `PRIORITY_VISUAL_COMPONENT` to enable to - // overwrite the viusal result of component (like `visualMap`) - // using data item specific setting (like itemStyle.xxx on data item) - - var PRIORITY_VISUAL_CHART_DATA_CUSTOM = 4500; // Greater than `PRIORITY_VISUAL_CHART_DATA_CUSTOM` to enable to layout based on - // visual result like `symbolSize`. - - var PRIORITY_VISUAL_POST_CHART_LAYOUT = 4600; - var PRIORITY_VISUAL_BRUSH = 5000; - var PRIORITY_VISUAL_ARIA = 6000; - var PRIORITY_VISUAL_DECAL = 7000; - var PRIORITY = { - PROCESSOR: { - FILTER: PRIORITY_PROCESSOR_FILTER, - SERIES_FILTER: PRIORITY_PROCESSOR_SERIES_FILTER, - STATISTIC: PRIORITY_PROCESSOR_STATISTIC - }, - VISUAL: { - LAYOUT: PRIORITY_VISUAL_LAYOUT, - PROGRESSIVE_LAYOUT: PRIORITY_VISUAL_PROGRESSIVE_LAYOUT, - GLOBAL: PRIORITY_VISUAL_GLOBAL, - CHART: PRIORITY_VISUAL_CHART, - POST_CHART_LAYOUT: PRIORITY_VISUAL_POST_CHART_LAYOUT, - COMPONENT: PRIORITY_VISUAL_COMPONENT, - BRUSH: PRIORITY_VISUAL_BRUSH, - CHART_ITEM: PRIORITY_VISUAL_CHART_DATA_CUSTOM, - ARIA: PRIORITY_VISUAL_ARIA, - DECAL: PRIORITY_VISUAL_DECAL - } - }; // Main process have three entries: `setOption`, `dispatchAction` and `resize`, - // where they must not be invoked nestedly, except the only case: invoke - // dispatchAction with updateMethod "none" in main process. - // This flag is used to carry out this rule. - // All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]). - - var IN_MAIN_PROCESS_KEY = '__flagInMainProcess'; // Useful for detecting outdated rendering results in scenarios that these issues are involved: - // - Use shortcut (such as, updateTransform, or no update) to start a main process. - // - Asynchronously update rendered view (e.g., graph force layout). - // - Multiple ChartView/ComponentView render to one group cooperatively. - - var MAIN_PROCESS_VERSION_KEY = '__mainProcessVersion'; - var PENDING_UPDATE = '__pendingUpdate'; - var STATUS_NEEDS_UPDATE_KEY = '__needsUpdateStatus'; - var ACTION_REG = /^[a-zA-Z0-9_]+$/; - var CONNECT_STATUS_KEY = '__connectUpdateStatus'; - var CONNECT_STATUS_PENDING = 0; - var CONNECT_STATUS_UPDATING = 1; - var CONNECT_STATUS_UPDATED = 2; - - function createRegisterEventWithLowercaseECharts(method) { - return function () { - var args = []; - - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - - if (this.isDisposed()) { - disposedWarning(this.id); - return; - } - - return toLowercaseNameAndCallEventful(this, method, args); - }; - } - - function createRegisterEventWithLowercaseMessageCenter(method) { - return function () { - var args = []; - - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - - return toLowercaseNameAndCallEventful(this, method, args); - }; - } - - function toLowercaseNameAndCallEventful(host, method, args) { - // `args[0]` is event name. Event name is all lowercase. - args[0] = args[0] && args[0].toLowerCase(); - return Eventful.prototype[method].apply(host, args); - } - - var MessageCenter = - /** @class */ - function (_super) { - __extends(MessageCenter, _super); - - function MessageCenter() { - return _super !== null && _super.apply(this, arguments) || this; - } - - return MessageCenter; - }(Eventful); - - var messageCenterProto = MessageCenter.prototype; - messageCenterProto.on = createRegisterEventWithLowercaseMessageCenter('on'); - messageCenterProto.off = createRegisterEventWithLowercaseMessageCenter('off'); // --------------------------------------- - // Internal method names for class ECharts - // --------------------------------------- - - var prepare; - var prepareView; - var updateDirectly; - var updateMethods; - var doConvertPixel; - var updateStreamModes; - var doDispatchAction; - var flushPendingActions; - var triggerUpdatedEvent; - var bindRenderedEvent; - var bindMouseEvent; - var render; - var renderComponents; - var renderSeries; - var createExtensionAPI; - var enableConnect; - var markStatusToUpdate; - var applyChangedStates; - var updateMainProcessVersion; - - var ECharts = - /** @class */ - function (_super) { - __extends(ECharts, _super); - - function ECharts(dom, // Theme name or themeOption. - theme, opts) { - var _this = _super.call(this, new ECEventProcessor()) || this; - - _this._chartsViews = []; - _this._chartsMap = {}; - _this._componentsViews = []; - _this._componentsMap = {}; // Can't dispatch action during rendering procedure - - _this._pendingActions = []; - opts = opts || {}; - _this._dom = dom; - var defaultRenderer = 'canvas'; - var defaultCoarsePointer = 'auto'; - var defaultUseDirtyRect = false; - _this[MAIN_PROCESS_VERSION_KEY] = 1; - { - var root = - /* eslint-disable-next-line */ - env.hasGlobalWindow ? window : global; - - if (root) { - defaultRenderer = retrieve2(root.__ECHARTS__DEFAULT__RENDERER__, defaultRenderer); - defaultCoarsePointer = retrieve2(root.__ECHARTS__DEFAULT__COARSE_POINTER, defaultCoarsePointer); - defaultUseDirtyRect = retrieve2(root.__ECHARTS__DEFAULT__USE_DIRTY_RECT__, defaultUseDirtyRect); - } - } - - if (opts.ssr) { - registerSSRDataGetter(function (el) { - var ecData = getECData(el); - var dataIndex = ecData.dataIndex; - - if (dataIndex == null) { - return; - } - - var hashMap = createHashMap(); - hashMap.set('series_index', ecData.seriesIndex); - hashMap.set('data_index', dataIndex); - ecData.ssrType && hashMap.set('ssr_type', ecData.ssrType); - return hashMap; - }); - } - - var zr = _this._zr = init$1(dom, { - renderer: opts.renderer || defaultRenderer, - devicePixelRatio: opts.devicePixelRatio, - width: opts.width, - height: opts.height, - ssr: opts.ssr, - useDirtyRect: retrieve2(opts.useDirtyRect, defaultUseDirtyRect), - useCoarsePointer: retrieve2(opts.useCoarsePointer, defaultCoarsePointer), - pointerSize: opts.pointerSize - }); - _this._ssr = opts.ssr; // Expect 60 fps. - - _this._throttledZrFlush = throttle(bind$1(zr.flush, zr), 17); - - _this._updateTheme(theme); - - _this._locale = createLocaleObject(opts.locale || SYSTEM_LANG); - _this._coordSysMgr = new CoordinateSystemManager(); - var api = _this._api = createExtensionAPI(_this); // Sort on demand - - function prioritySortFunc(a, b) { - return a.__prio - b.__prio; - } - - sort(visualFuncs, prioritySortFunc); - sort(dataProcessorFuncs, prioritySortFunc); - _this._scheduler = new Scheduler(_this, api, dataProcessorFuncs, visualFuncs); - _this._messageCenter = new MessageCenter(); // Init mouse events - - _this._initEvents(); // In case some people write `window.onresize = chart.resize` - - - _this.resize = bind$1(_this.resize, _this); - zr.animation.on('frame', _this._onframe, _this); - bindRenderedEvent(zr, _this); - bindMouseEvent(zr, _this); // ECharts instance can be used as value. - - setAsPrimitive(_this); - return _this; - } - - ECharts.prototype._onframe = function () { - if (this._disposed) { - return; - } - - applyChangedStates(this); - var scheduler = this._scheduler; // Lazy update - - if (this[PENDING_UPDATE]) { - var silent = this[PENDING_UPDATE].silent; - this[IN_MAIN_PROCESS_KEY] = true; - updateMainProcessVersion(this); - - try { - prepare(this); - updateMethods.update.call(this, null, this[PENDING_UPDATE].updateParams); - } catch (e) { - this[IN_MAIN_PROCESS_KEY] = false; - this[PENDING_UPDATE] = null; - throw e; - } // At present, in each frame, zrender performs: - // (1) animation step forward. - // (2) trigger('frame') (where this `_onframe` is called) - // (3) zrender flush (render). - // If we do nothing here, since we use `setToFinal: true`, the step (3) above - // will render the final state of the elements before the real animation started. - - - this._zr.flush(); - - this[IN_MAIN_PROCESS_KEY] = false; - this[PENDING_UPDATE] = null; - flushPendingActions.call(this, silent); - triggerUpdatedEvent.call(this, silent); - } // Avoid do both lazy update and progress in one frame. - else if (scheduler.unfinished) { - // Stream progress. - var remainTime = TEST_FRAME_REMAIN_TIME; - var ecModel = this._model; - var api = this._api; - scheduler.unfinished = false; - - do { - var startTime = +new Date(); - scheduler.performSeriesTasks(ecModel); // Currently dataProcessorFuncs do not check threshold. - - scheduler.performDataProcessorTasks(ecModel); - updateStreamModes(this, ecModel); // Do not update coordinate system here. Because that coord system update in - // each frame is not a good user experience. So we follow the rule that - // the extent of the coordinate system is determined in the first frame (the - // frame is executed immediately after task reset. - // this._coordSysMgr.update(ecModel, api); - // console.log('--- ec frame visual ---', remainTime); - - scheduler.performVisualTasks(ecModel); - renderSeries(this, this._model, api, 'remain', {}); - remainTime -= +new Date() - startTime; - } while (remainTime > 0 && scheduler.unfinished); // Call flush explicitly for trigger finished event. - - - if (!scheduler.unfinished) { - this._zr.flush(); - } // Else, zr flushing be ensue within the same frame, - // because zr flushing is after onframe event. - - } - }; - - ECharts.prototype.getDom = function () { - return this._dom; - }; - - ECharts.prototype.getId = function () { - return this.id; - }; - - ECharts.prototype.getZr = function () { - return this._zr; - }; - - ECharts.prototype.isSSR = function () { - return this._ssr; - }; - /* eslint-disable-next-line */ - - - ECharts.prototype.setOption = function (option, notMerge, lazyUpdate) { - if (this[IN_MAIN_PROCESS_KEY]) { - { - error('`setOption` should not be called during main process.'); - } - return; - } - - if (this._disposed) { - disposedWarning(this.id); - return; - } - - var silent; - var replaceMerge; - var transitionOpt; - - if (isObject$2(notMerge)) { - lazyUpdate = notMerge.lazyUpdate; - silent = notMerge.silent; - replaceMerge = notMerge.replaceMerge; - transitionOpt = notMerge.transition; - notMerge = notMerge.notMerge; - } - - this[IN_MAIN_PROCESS_KEY] = true; - updateMainProcessVersion(this); - - if (!this._model || notMerge) { - var optionManager = new OptionManager(this._api); - var theme = this._theme; - var ecModel = this._model = new GlobalModel(); - ecModel.scheduler = this._scheduler; - ecModel.ssr = this._ssr; - ecModel.init(null, null, null, theme, this._locale, optionManager); - } - - this._model.setOption(option, { - replaceMerge: replaceMerge - }, optionPreprocessorFuncs); - - var updateParams = { - seriesTransition: transitionOpt, - optionChanged: true - }; - - if (lazyUpdate) { - this[PENDING_UPDATE] = { - silent: silent, - updateParams: updateParams - }; - this[IN_MAIN_PROCESS_KEY] = false; // `setOption(option, {lazyMode: true})` may be called when zrender has been slept. - // It should wake it up to make sure zrender start to render at the next frame. - - this.getZr().wakeUp(); - } else { - try { - prepare(this); - updateMethods.update.call(this, null, updateParams); - } catch (e) { - this[PENDING_UPDATE] = null; - this[IN_MAIN_PROCESS_KEY] = false; - throw e; - } // Ensure zr refresh sychronously, and then pixel in canvas can be - // fetched after `setOption`. - - - if (!this._ssr) { - // not use flush when using ssr mode. - this._zr.flush(); - } - - this[PENDING_UPDATE] = null; - this[IN_MAIN_PROCESS_KEY] = false; - flushPendingActions.call(this, silent); - triggerUpdatedEvent.call(this, silent); - } - }; - /** - * Update theme with name or theme option and repaint the chart. - * @param theme Theme name or theme option. - * @param opts Optional settings - */ - - - ECharts.prototype.setTheme = function (theme, opts) { - if (this[IN_MAIN_PROCESS_KEY]) { - { - error('`setTheme` should not be called during main process.'); - } - return; - } - - if (this._disposed) { - disposedWarning(this.id); - return; - } - - var ecModel = this._model; - - if (!ecModel) { - return; - } - - var silent = opts && opts.silent; - var updateParams = null; - - if (this[PENDING_UPDATE]) { - if (silent == null) { - silent = this[PENDING_UPDATE].silent; - } - - updateParams = this[PENDING_UPDATE].updateParams; - this[PENDING_UPDATE] = null; - } - - this[IN_MAIN_PROCESS_KEY] = true; - updateMainProcessVersion(this); - - try { - this._updateTheme(theme); - - ecModel.setTheme(this._theme); - prepare(this); - updateMethods.update.call(this, { - type: 'setTheme' - }, updateParams); - } catch (e) { - this[IN_MAIN_PROCESS_KEY] = false; - throw e; - } - - this[IN_MAIN_PROCESS_KEY] = false; - flushPendingActions.call(this, silent); - triggerUpdatedEvent.call(this, silent); - }; - - ECharts.prototype._updateTheme = function (theme) { - if (isString(theme)) { - theme = themeStorage[theme]; - } - - if (theme) { - theme = clone$3(theme); - theme && globalBackwardCompat(theme, true); - this._theme = theme; - } - }; // We don't want developers to use getModel directly. - - - ECharts.prototype.getModel = function () { - return this._model; - }; - - ECharts.prototype.getOption = function () { - return this._model && this._model.getOption(); - }; - - ECharts.prototype.getWidth = function () { - return this._zr.getWidth(); - }; - - ECharts.prototype.getHeight = function () { - return this._zr.getHeight(); - }; - - ECharts.prototype.getDevicePixelRatio = function () { - return this._zr.painter.dpr - /* eslint-disable-next-line */ - || env.hasGlobalWindow && window.devicePixelRatio || 1; - }; - /** - * Get canvas which has all thing rendered - * @deprecated Use renderToCanvas instead. - */ - - - ECharts.prototype.getRenderedCanvas = function (opts) { - { - deprecateReplaceLog('getRenderedCanvas', 'renderToCanvas'); - } - return this.renderToCanvas(opts); - }; - - ECharts.prototype.renderToCanvas = function (opts) { - opts = opts || {}; - var painter = this._zr.painter; - { - if (painter.type !== 'canvas') { - throw new Error('renderToCanvas can only be used in the canvas renderer.'); - } - } - return painter.getRenderedCanvas({ - backgroundColor: opts.backgroundColor || this._model.get('backgroundColor'), - pixelRatio: opts.pixelRatio || this.getDevicePixelRatio() - }); - }; - - ECharts.prototype.renderToSVGString = function (opts) { - opts = opts || {}; - var painter = this._zr.painter; - { - if (painter.type !== 'svg') { - throw new Error('renderToSVGString can only be used in the svg renderer.'); - } - } - return painter.renderToString({ - useViewBox: opts.useViewBox - }); - }; - /** - * Get svg data url - */ - - - ECharts.prototype.getSvgDataURL = function () { - var zr = this._zr; - var list = zr.storage.getDisplayList(); // Stop animations - - each$4(list, function (el) { - el.stopAnimation(null, true); - }); - return zr.painter.toDataURL(); - }; - - ECharts.prototype.getDataURL = function (opts) { - if (this._disposed) { - disposedWarning(this.id); - return; - } - - opts = opts || {}; - var excludeComponents = opts.excludeComponents; - var ecModel = this._model; - var excludesComponentViews = []; - var self = this; - each$4(excludeComponents, function (componentType) { - ecModel.eachComponent({ - mainType: componentType - }, function (component) { - var view = self._componentsMap[component.__viewId]; - - if (!view.group.ignore) { - excludesComponentViews.push(view); - view.group.ignore = true; - } - }); - }); - var url = this._zr.painter.getType() === 'svg' ? this.getSvgDataURL() : this.renderToCanvas(opts).toDataURL('image/' + (opts && opts.type || 'png')); - each$4(excludesComponentViews, function (view) { - view.group.ignore = false; - }); - return url; - }; - - ECharts.prototype.getConnectedDataURL = function (opts) { - if (this._disposed) { - disposedWarning(this.id); - return; - } - - var isSvg = opts.type === 'svg'; - var groupId = this.group; - var mathMin = Math.min; - var mathMax = Math.max; - var MAX_NUMBER = Infinity; - - if (connectedGroups[groupId]) { - var left_1 = MAX_NUMBER; - var top_1 = MAX_NUMBER; - var right_1 = -MAX_NUMBER; - var bottom_1 = -MAX_NUMBER; - var canvasList_1 = []; - var dpr_1 = opts && opts.pixelRatio || this.getDevicePixelRatio(); - each$4(instances, function (chart, id) { - if (chart.group === groupId) { - var canvas = isSvg ? chart.getZr().painter.getSvgDom().innerHTML : chart.renderToCanvas(clone$3(opts)); - var boundingRect = chart.getDom().getBoundingClientRect(); - left_1 = mathMin(boundingRect.left, left_1); - top_1 = mathMin(boundingRect.top, top_1); - right_1 = mathMax(boundingRect.right, right_1); - bottom_1 = mathMax(boundingRect.bottom, bottom_1); - canvasList_1.push({ - dom: canvas, - left: boundingRect.left, - top: boundingRect.top - }); - } - }); - left_1 *= dpr_1; - top_1 *= dpr_1; - right_1 *= dpr_1; - bottom_1 *= dpr_1; - var width = right_1 - left_1; - var height = bottom_1 - top_1; - var targetCanvas = platformApi.createCanvas(); - var zr_1 = init$1(targetCanvas, { - renderer: isSvg ? 'svg' : 'canvas' - }); - zr_1.resize({ - width: width, - height: height - }); - - if (isSvg) { - var content_1 = ''; - each$4(canvasList_1, function (item) { - var x = item.left - left_1; - var y = item.top - top_1; - content_1 += '' + item.dom + ''; - }); - zr_1.painter.getSvgRoot().innerHTML = content_1; - - if (opts.connectedBackgroundColor) { - zr_1.painter.setBackgroundColor(opts.connectedBackgroundColor); - } - - zr_1.refreshImmediately(); - return zr_1.painter.toDataURL(); - } else { - // Background between the charts - if (opts.connectedBackgroundColor) { - zr_1.add(new Rect({ - shape: { - x: 0, - y: 0, - width: width, - height: height - }, - style: { - fill: opts.connectedBackgroundColor - } - })); - } - - each$4(canvasList_1, function (item) { - var img = new ZRImage({ - style: { - x: item.left * dpr_1 - left_1, - y: item.top * dpr_1 - top_1, - image: item.dom - } - }); - zr_1.add(img); - }); - zr_1.refreshImmediately(); - return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png')); - } - } else { - return this.getDataURL(opts); - } - }; - - ECharts.prototype.convertToPixel = function (finder, value, opt) { - return doConvertPixel(this, 'convertToPixel', finder, value, opt); - }; - /** - * Convert from logical coordinate system to pixel coordinate system. - * See CoordinateSystem#convertToPixel. - * - * @see CoordinateSystem['dataToLayout'] for parameters and return. - * @see CoordinateSystemDataCoord - */ - - - ECharts.prototype.convertToLayout = function (finder, value, opt) { - return doConvertPixel(this, 'convertToLayout', finder, value, opt); - }; // The above are signatures from before v6, thus they should be preserved for backward compat. - - - ECharts.prototype.convertFromPixel = function (finder, value, opt) { - return doConvertPixel(this, 'convertFromPixel', finder, value, opt); - }; - /** - * Is the specified coordinate systems or components contain the given pixel point. - * @param {Array|number} value - * @return {boolean} result - */ - - - ECharts.prototype.containPixel = function (finder, value) { - if (this._disposed) { - disposedWarning(this.id); - return; - } - - var ecModel = this._model; - var result; - var findResult = parseFinder(ecModel, finder); - each$4(findResult, function (models, key) { - key.indexOf('Models') >= 0 && each$4(models, function (model) { - var coordSys = model.coordinateSystem; - - if (coordSys && coordSys.containPoint) { - result = result || !!coordSys.containPoint(value); - } else if (key === 'seriesModels') { - var view = this._chartsMap[model.__viewId]; - - if (view && view.containPoint) { - result = result || view.containPoint(value, model); - } else { - { - warn(key + ': ' + (view ? 'The found component do not support containPoint.' : 'No view mapping to the found component.')); - } - } - } else { - { - warn(key + ': containPoint is not supported'); - } - } - }, this); - }, this); - return !!result; - }; - /** - * Get visual from series or data. - * @param finder - * If string, e.g., 'series', means {seriesIndex: 0}. - * If Object, could contain some of these properties below: - * { - * seriesIndex / seriesId / seriesName, - * dataIndex / dataIndexInside - * } - * If dataIndex is not specified, series visual will be fetched, - * but not data item visual. - * If all of seriesIndex, seriesId, seriesName are not specified, - * visual will be fetched from first series. - * @param visualType 'color', 'symbol', 'symbolSize' - */ - - - ECharts.prototype.getVisual = function (finder, visualType) { - var ecModel = this._model; - var parsedFinder = parseFinder(ecModel, finder, { - defaultMainType: 'series' - }); - var seriesModel = parsedFinder.seriesModel; - { - if (!seriesModel) { - warn('There is no specified series model'); - } - } - var data = seriesModel.getData(); - var dataIndexInside = parsedFinder.hasOwnProperty('dataIndexInside') ? parsedFinder.dataIndexInside : parsedFinder.hasOwnProperty('dataIndex') ? data.indexOfRawIndex(parsedFinder.dataIndex) : null; - return dataIndexInside != null ? getItemVisualFromData(data, dataIndexInside, visualType) : getVisualFromData(data, visualType); - }; - /** - * Get view of corresponding component model - */ - - - ECharts.prototype.getViewOfComponentModel = function (componentModel) { - return this._componentsMap[componentModel.__viewId]; - }; - /** - * Get view of corresponding series model - */ - - - ECharts.prototype.getViewOfSeriesModel = function (seriesModel) { - return this._chartsMap[seriesModel.__viewId]; - }; - - ECharts.prototype._initEvents = function () { - var _this = this; - - each$4(MOUSE_EVENT_NAMES, function (eveName) { - var handler = function (e) { - var ecModel = _this.getModel(); - - var el = e.target; - var params; - var isGlobalOut = eveName === 'globalout'; // no e.target when 'globalout'. - - if (isGlobalOut) { - params = {}; - } else { - el && findEventDispatcher(el, function (parent) { - var ecData = getECData(parent); - - if (ecData && ecData.dataIndex != null) { - var dataModel = ecData.dataModel || ecModel.getSeriesByIndex(ecData.seriesIndex); - params = dataModel && dataModel.getDataParams(ecData.dataIndex, ecData.dataType, el) || {}; - return true; - } // If element has custom eventData of components - else if (ecData.eventData) { - params = extend({}, ecData.eventData); - return true; - } - }, true); - } // Contract: if params prepared in mouse event, - // these properties must be specified: - // { - // componentType: string (component main type) - // componentIndex: number - // } - // Otherwise event query can not work. - - - if (params) { - var componentType = params.componentType; - var componentIndex = params.componentIndex; // Special handling for historic reason: when trigger by - // markLine/markPoint/markArea, the componentType is - // 'markLine'/'markPoint'/'markArea', but we should better - // enable them to be queried by seriesIndex, since their - // option is set in each series. - - if (componentType === 'markLine' || componentType === 'markPoint' || componentType === 'markArea') { - componentType = 'series'; - componentIndex = params.seriesIndex; - } - - var model = componentType && componentIndex != null && ecModel.getComponent(componentType, componentIndex); - var view = model && _this[model.mainType === 'series' ? '_chartsMap' : '_componentsMap'][model.__viewId]; - { - // `event.componentType` and `event[componentTpype + 'Index']` must not - // be missed, otherwise there is no way to distinguish source component. - // See `dataFormat.getDataParams`. - if (!isGlobalOut && !(model && view)) { - warn('model or view can not be found by params'); - } - } - params.event = e; - params.type = eveName; - _this._$eventProcessor.eventInfo = { - targetEl: el, - packedEvent: params, - model: model, - view: view - }; - - _this.trigger(eveName, params); - } - }; // Consider that some component (like tooltip, brush, ...) - // register zr event handler, but user event handler might - // do anything, such as call `setOption` or `dispatchAction`, - // which probably update any of the content and probably - // cause problem if it is called previous other inner handlers. - - - handler.zrEventfulCallAtLast = true; - - _this._zr.on(eveName, handler, _this); - }); - var messageCenter = this._messageCenter; - each$4(publicEventTypeMap, function (_, eventType) { - messageCenter.on(eventType, function (event) { - _this.trigger(eventType, event); - }); - }); - handleLegacySelectEvents(messageCenter, this, this._api); - }; - - ECharts.prototype.isDisposed = function () { - return this._disposed; - }; - - ECharts.prototype.clear = function () { - if (this._disposed) { - disposedWarning(this.id); - return; - } - - this.setOption({ - series: [] - }, true); - }; - - ECharts.prototype.dispose = function () { - if (this._disposed) { - disposedWarning(this.id); - return; - } - - this._disposed = true; - var dom = this.getDom(); - - if (dom) { - setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, ''); - } - - var chart = this; - var api = chart._api; - var ecModel = chart._model; - each$4(chart._componentsViews, function (component) { - component.dispose(ecModel, api); - }); - each$4(chart._chartsViews, function (chart) { - chart.dispose(ecModel, api); - }); // Dispose after all views disposed - - chart._zr.dispose(); // Set properties to null. - // To reduce the memory cost in case the top code still holds this instance unexpectedly. - - - chart._dom = chart._model = chart._chartsMap = chart._componentsMap = chart._chartsViews = chart._componentsViews = chart._scheduler = chart._api = chart._zr = chart._throttledZrFlush = chart._theme = chart._coordSysMgr = chart._messageCenter = null; - delete instances[chart.id]; - }; - /** - * Resize the chart - */ - - - ECharts.prototype.resize = function (opts) { - if (this[IN_MAIN_PROCESS_KEY]) { - { - error('`resize` should not be called during main process.'); - } - return; - } - - if (this._disposed) { - disposedWarning(this.id); - return; - } - - this._zr.resize(opts); - - var ecModel = this._model; // Resize loading effect - - this._loadingFX && this._loadingFX.resize(); - - if (!ecModel) { - return; - } - - var needPrepare = ecModel.resetOption('media'); - var silent = opts && opts.silent; // There is some real cases that: - // chart.setOption(option, { lazyUpdate: true }); - // chart.resize(); - - if (this[PENDING_UPDATE]) { - if (silent == null) { - silent = this[PENDING_UPDATE].silent; - } - - needPrepare = true; - this[PENDING_UPDATE] = null; - } - - this[IN_MAIN_PROCESS_KEY] = true; - updateMainProcessVersion(this); - - try { - needPrepare && prepare(this); - updateMethods.update.call(this, { - type: 'resize', - animation: extend({ - // Disable animation - duration: 0 - }, opts && opts.animation) - }); - } catch (e) { - this[IN_MAIN_PROCESS_KEY] = false; - throw e; - } - - this[IN_MAIN_PROCESS_KEY] = false; - flushPendingActions.call(this, silent); - triggerUpdatedEvent.call(this, silent); - }; - - ECharts.prototype.showLoading = function (name, cfg) { - if (this._disposed) { - disposedWarning(this.id); - return; - } - - if (isObject$2(name)) { - cfg = name; - name = ''; - } - - name = name || 'default'; - this.hideLoading(); - - if (!loadingEffects[name]) { - { - warn('Loading effects ' + name + ' not exists.'); - } - return; - } - - var el = loadingEffects[name](this._api, cfg); - var zr = this._zr; - this._loadingFX = el; - zr.add(el); - }; - /** - * Hide loading effect - */ - - - ECharts.prototype.hideLoading = function () { - if (this._disposed) { - disposedWarning(this.id); - return; - } - - this._loadingFX && this._zr.remove(this._loadingFX); - this._loadingFX = null; - }; - - ECharts.prototype.makeActionFromEvent = function (eventObj) { - var payload = extend({}, eventObj); - payload.type = connectionEventRevertMap[eventObj.type]; - return payload; - }; - /** - * @param opt If pass boolean, means opt.silent - * @param opt.silent Default `false`. Whether trigger events. - * @param opt.flush Default `undefined`. - * true: Flush immediately, and then pixel in canvas can be fetched - * immediately. Caution: it might affect performance. - * false: Not flush. - * undefined: Auto decide whether perform flush. - */ - - - ECharts.prototype.dispatchAction = function (payload, opt) { - if (this._disposed) { - disposedWarning(this.id); - return; - } - - if (!isObject$2(opt)) { - opt = { - silent: !!opt - }; - } - - if (!actions[payload.type]) { - return; - } // Avoid dispatch action before setOption. Especially in `connect`. - - - if (!this._model) { - return; - } // May dispatchAction in rendering procedure - - - if (this[IN_MAIN_PROCESS_KEY]) { - this._pendingActions.push(payload); - - return; - } - - var silent = opt.silent; - doDispatchAction.call(this, payload, silent); - var flush = opt.flush; - - if (flush) { - this._zr.flush(); - } else if (flush !== false && env.browser.weChat) { - // In WeChat embedded browser, `requestAnimationFrame` and `setInterval` - // hang when sliding page (on touch event), which cause that zr does not - // refresh until user interaction finished, which is not expected. - // But `dispatchAction` may be called too frequently when pan on touch - // screen, which impacts performance if do not throttle them. - this._throttledZrFlush(); - } - - flushPendingActions.call(this, silent); - triggerUpdatedEvent.call(this, silent); - }; - - ECharts.prototype.updateLabelLayout = function () { - lifecycle.trigger('series:layoutlabels', this._model, this._api, { - // Not adding series labels. - // TODO - updatedSeries: [] - }); - }; - - ECharts.prototype.appendData = function (params) { - if (this._disposed) { - disposedWarning(this.id); - return; - } - - var seriesIndex = params.seriesIndex; - var ecModel = this.getModel(); - var seriesModel = ecModel.getSeriesByIndex(seriesIndex); - { - assert(params.data && seriesModel); - } - seriesModel.appendData(params); // Note: `appendData` does not support that update extent of coordinate - // system, util some scenario require that. In the expected usage of - // `appendData`, the initial extent of coordinate system should better - // be fixed by axis `min`/`max` setting or initial data, otherwise if - // the extent changed while `appendData`, the location of the painted - // graphic elements have to be changed, which make the usage of - // `appendData` meaningless. - - this._scheduler.unfinished = true; - this.getZr().wakeUp(); - }; // A work around for no `internal` modifier in ts yet but - // need to strictly hide private methods to JS users. - - - ECharts.internalField = function () { - prepare = function (ecIns) { - var scheduler = ecIns._scheduler; - scheduler.restorePipelines(ecIns._model); - scheduler.prepareStageTasks(); - prepareView(ecIns, true); - prepareView(ecIns, false); - scheduler.plan(); - }; - /** - * Prepare view instances of charts and components - */ - - - prepareView = function (ecIns, isComponent) { - var ecModel = ecIns._model; - var scheduler = ecIns._scheduler; - var viewList = isComponent ? ecIns._componentsViews : ecIns._chartsViews; - var viewMap = isComponent ? ecIns._componentsMap : ecIns._chartsMap; - var zr = ecIns._zr; - var api = ecIns._api; - - for (var i = 0; i < viewList.length; i++) { - viewList[i].__alive = false; - } - - isComponent ? ecModel.eachComponent(function (componentType, model) { - componentType !== 'series' && doPrepare(model); - }) : ecModel.eachSeries(doPrepare); - - function doPrepare(model) { - // By default view will be reused if possible for the case that `setOption` with "notMerge" - // mode and need to enable transition animation. (Usually, when they have the same id, or - // especially no id but have the same type & name & index. See the `model.id` generation - // rule in `makeIdAndName` and `viewId` generation rule here). - // But in `replaceMerge` mode, this feature should be able to disabled when it is clear that - // the new model has nothing to do with the old model. - var requireNewView = model.__requireNewView; // This command should not work twice. - - model.__requireNewView = false; // Consider: id same and type changed. - - var viewId = '_ec_' + model.id + '_' + model.type; - var view = !requireNewView && viewMap[viewId]; - - if (!view) { - var classType = parseClassType(model.type); - var Clazz = isComponent ? ComponentView.getClass(classType.main, classType.sub) : // FIXME:TS - // (ChartView as ChartViewConstructor).getClass('series', classType.sub) - // For backward compat, still support a chart type declared as only subType - // like "liquidfill", but recommend "series.liquidfill" - // But need a base class to make a type series. - ChartView.getClass(classType.sub); - { - assert(Clazz, classType.sub + ' does not exist.'); - } - view = new Clazz(); - view.init(ecModel, api); - viewMap[viewId] = view; - viewList.push(view); - zr.add(view.group); - } - - model.__viewId = view.__id = viewId; - view.__alive = true; - view.__model = model; - view.group.__ecComponentInfo = { - mainType: model.mainType, - index: model.componentIndex - }; - !isComponent && scheduler.prepareView(view, model, ecModel, api); - } - - for (var i = 0; i < viewList.length;) { - var view = viewList[i]; - - if (!view.__alive) { - !isComponent && view.renderTask.dispose(); - zr.remove(view.group); - view.dispose(ecModel, api); - viewList.splice(i, 1); - - if (viewMap[view.__id] === view) { - delete viewMap[view.__id]; - } - - view.__id = view.group.__ecComponentInfo = null; - } else { - i++; - } - } - }; - - updateDirectly = function (ecIns, method, payload, mainType, subType) { - var ecModel = ecIns._model; - ecModel.setUpdatePayload(payload); // broadcast - - if (!mainType) { - // FIXME - // Chart will not be update directly here, except set dirty. - // But there is no such scenario now. - each$4([].concat(ecIns._componentsViews).concat(ecIns._chartsViews), callView); - return; - } - - var query = {}; - query[mainType + 'Id'] = payload[mainType + 'Id']; - query[mainType + 'Index'] = payload[mainType + 'Index']; - query[mainType + 'Name'] = payload[mainType + 'Name']; - var condition = { - mainType: mainType, - query: query - }; - subType && (condition.subType = subType); // subType may be '' by parseClassType; - - var excludeSeriesId = payload.excludeSeriesId; - var excludeSeriesIdMap; - - if (excludeSeriesId != null) { - excludeSeriesIdMap = createHashMap(); - each$4(normalizeToArray(excludeSeriesId), function (id) { - var modelId = convertOptionIdName(id, null); - - if (modelId != null) { - excludeSeriesIdMap.set(modelId, true); - } - }); - } // If dispatchAction before setOption, do nothing. - - - ecModel && ecModel.eachComponent(condition, function (model) { - var isExcluded = excludeSeriesIdMap && excludeSeriesIdMap.get(model.id) != null; - - if (isExcluded) { - return; - } - - if (isHighDownPayload(payload)) { - if (model instanceof SeriesModel) { - if (payload.type === HIGHLIGHT_ACTION_TYPE && !payload.notBlur && !model.get(['emphasis', 'disabled'])) { - blurSeriesFromHighlightPayload(model, payload, ecIns._api); - } - } else { - var _a = findComponentHighDownDispatchers(model.mainType, model.componentIndex, payload.name, ecIns._api), - focusSelf = _a.focusSelf, - dispatchers = _a.dispatchers; - - if (payload.type === HIGHLIGHT_ACTION_TYPE && focusSelf && !payload.notBlur) { - blurComponent(model.mainType, model.componentIndex, ecIns._api); - } // PENDING: - // Whether to put this "enter emphasis" code in `ComponentView`, - // which will be the same as `ChartView` but might be not necessary - // and will be far from this logic. - - - if (dispatchers) { - each$4(dispatchers, function (dispatcher) { - payload.type === HIGHLIGHT_ACTION_TYPE ? enterEmphasis(dispatcher) : leaveEmphasis(dispatcher); - }); - } - } - } else if (isSelectChangePayload(payload)) { - // TODO geo - if (model instanceof SeriesModel) { - toggleSelectionFromPayload(model, payload, ecIns._api); - updateSeriesElementSelection(model); - markStatusToUpdate(ecIns); - } - } - }, ecIns); - ecModel && ecModel.eachComponent(condition, function (model) { - var isExcluded = excludeSeriesIdMap && excludeSeriesIdMap.get(model.id) != null; - - if (isExcluded) { - return; - } - - callView(ecIns[mainType === 'series' ? '_chartsMap' : '_componentsMap'][model.__viewId]); - }, ecIns); - - function callView(view) { - view && view.__alive && view[method] && view[method](view.__model, ecModel, ecIns._api, payload); - } - }; - - updateMethods = { - prepareAndUpdate: function (payload) { - prepare(this); - updateMethods.update.call(this, payload, payload && { - // Needs to mark option changed if newOption is given. - // It's from MagicType. - // TODO If use a separate flag optionChanged in payload? - optionChanged: payload.newOption != null - }); - }, - update: function (payload, updateParams) { - var ecModel = this._model; - var api = this._api; - var zr = this._zr; - var coordSysMgr = this._coordSysMgr; - var scheduler = this._scheduler; // update before setOption - - if (!ecModel) { - return; - } - - ecModel.setUpdatePayload(payload); - scheduler.restoreData(ecModel, payload); - scheduler.performSeriesTasks(ecModel); // TODO - // Save total ecModel here for undo/redo (after restoring data and before processing data). - // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call. - // Create new coordinate system each update - // In LineView may save the old coordinate system and use it to get the original point. - - coordSysMgr.create(ecModel, api); - scheduler.performDataProcessorTasks(ecModel, payload); // Current stream render is not supported in data process. So we can update - // stream modes after data processing, where the filtered data is used to - // determine whether to use progressive rendering. - - updateStreamModes(this, ecModel); // We update stream modes before coordinate system updated, then the modes info - // can be fetched when coord sys updating (consider the barGrid extent fix). But - // the drawback is the full coord info can not be fetched. Fortunately this full - // coord is not required in stream mode updater currently. - - coordSysMgr.update(ecModel, api); - clearColorPalette(ecModel); - scheduler.performVisualTasks(ecModel, payload); // Set background and dark mode before rendering, because they affect auto-color-determination - // in zrender Text, and consequently affect the bounding rect if stroke is added. - - var backgroundColor = ecModel.get('backgroundColor') || 'transparent'; - zr.setBackgroundColor(backgroundColor); // Force set dark mode. - - var darkMode = ecModel.get('darkMode'); - - if (darkMode != null && darkMode !== 'auto') { - zr.setDarkMode(darkMode); - } - - render(this, ecModel, api, payload, updateParams); - lifecycle.trigger('afterupdate', ecModel, api); - }, - updateTransform: function (payload) { - var _this = this; - - var ecModel = this._model; - var api = this._api; // update before setOption - - if (!ecModel) { - return; - } - - ecModel.setUpdatePayload(payload); // ChartView.markUpdateMethod(payload, 'updateTransform'); - - var componentDirtyList = []; - ecModel.eachComponent(function (componentType, componentModel) { - if (componentType === 'series') { - return; - } - - var componentView = _this.getViewOfComponentModel(componentModel); - - if (componentView && componentView.__alive) { - if (componentView.updateTransform) { - var result = componentView.updateTransform(componentModel, ecModel, api, payload); - result && result.update && componentDirtyList.push(componentView); - } else { - componentDirtyList.push(componentView); - } - } - }); - var seriesDirtyMap = createHashMap(); - ecModel.eachSeries(function (seriesModel) { - var chartView = _this._chartsMap[seriesModel.__viewId]; - - if (chartView.updateTransform) { - var result = chartView.updateTransform(seriesModel, ecModel, api, payload); - result && result.update && seriesDirtyMap.set(seriesModel.uid, 1); - } else { - seriesDirtyMap.set(seriesModel.uid, 1); - } - }); - clearColorPalette(ecModel); // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline. - // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true); - - this._scheduler.performVisualTasks(ecModel, payload, { - setDirty: true, - dirtyMap: seriesDirtyMap - }); // Currently, not call render of components. Geo render cost a lot. - // renderComponents(ecIns, ecModel, api, payload, componentDirtyList); - - - renderSeries(this, ecModel, api, payload, {}, seriesDirtyMap); - lifecycle.trigger('afterupdate', ecModel, api); - }, - updateView: function (payload) { - var ecModel = this._model; // update before setOption - - if (!ecModel) { - return; - } - - ecModel.setUpdatePayload(payload); - ChartView.markUpdateMethod(payload, 'updateView'); - clearColorPalette(ecModel); // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline. - - this._scheduler.performVisualTasks(ecModel, payload, { - setDirty: true - }); - - render(this, ecModel, this._api, payload, {}); - lifecycle.trigger('afterupdate', ecModel, this._api); - }, - updateVisual: function (payload) { - // updateMethods.update.call(this, payload); - var _this = this; - - var ecModel = this._model; // update before setOption - - if (!ecModel) { - return; - } - - ecModel.setUpdatePayload(payload); // clear all visual - - ecModel.eachSeries(function (seriesModel) { - seriesModel.getData().clearAllVisual(); - }); // Perform visual - - ChartView.markUpdateMethod(payload, 'updateVisual'); - clearColorPalette(ecModel); // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline. - - this._scheduler.performVisualTasks(ecModel, payload, { - visualType: 'visual', - setDirty: true - }); - - ecModel.eachComponent(function (componentType, componentModel) { - if (componentType !== 'series') { - var componentView = _this.getViewOfComponentModel(componentModel); - - componentView && componentView.__alive && componentView.updateVisual(componentModel, ecModel, _this._api, payload); - } - }); - ecModel.eachSeries(function (seriesModel) { - var chartView = _this._chartsMap[seriesModel.__viewId]; - chartView.updateVisual(seriesModel, ecModel, _this._api, payload); - }); - lifecycle.trigger('afterupdate', ecModel, this._api); - }, - updateLayout: function (payload) { - updateMethods.update.call(this, payload); - } - }; - - function doConvertPixelImpl(ecIns, methodName, finder, value, opt) { - if (ecIns._disposed) { - disposedWarning(ecIns.id); - return; - } - - var ecModel = ecIns._model; - - var coordSysList = ecIns._coordSysMgr.getCoordinateSystems(); - - var result; - var parsedFinder = parseFinder(ecModel, finder); - - for (var i = 0; i < coordSysList.length; i++) { - var coordSys = coordSysList[i]; - - if (coordSys[methodName] && (result = coordSys[methodName](ecModel, parsedFinder, value, opt)) != null) { - return result; - } - } - - { - warn('No coordinate system that supports ' + methodName + ' found by the given finder.'); - } - } - - doConvertPixel = doConvertPixelImpl; - - updateStreamModes = function (ecIns, ecModel) { - var chartsMap = ecIns._chartsMap; - var scheduler = ecIns._scheduler; - ecModel.eachSeries(function (seriesModel) { - scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]); - }); - }; - - doDispatchAction = function (payload, silent) { - var _this = this; - - var ecModel = this.getModel(); - var payloadType = payload.type; - var escapeConnect = payload.escapeConnect; - var actionInfo = actions[payloadType]; - var cptTypeTmp = (actionInfo.update || 'update').split(':'); - var updateMethod = cptTypeTmp.pop(); - var cptType = cptTypeTmp[0] != null && parseClassType(cptTypeTmp[0]); - this[IN_MAIN_PROCESS_KEY] = true; - updateMainProcessVersion(this); - var payloads = [payload]; - var batched = false; // Batch action - - if (payload.batch) { - batched = true; - payloads = map$1(payload.batch, function (item) { - item = defaults(extend({}, item), payload); - item.batch = null; - return item; - }); - } - - var eventObjBatch = []; - var eventObj; - var actionResultBatch = []; - var nonRefinedEventType = actionInfo.nonRefinedEventType; - var isSelectChange = isSelectChangePayload(payload); - var isHighDown = isHighDownPayload(payload); // Only leave blur once if there are multiple batches. - - if (isHighDown) { - allLeaveBlur(this._api); - } - - each$4(payloads, function (batchItem) { - // Action can specify the event by return it. - var actionResult = actionInfo.action(batchItem, ecModel, _this._api); - - if (actionInfo.refineEvent) { - actionResultBatch.push(actionResult); - } else { - eventObj = actionResult; - } - - eventObj = eventObj || extend({}, batchItem); - eventObj.type = nonRefinedEventType; - eventObjBatch.push(eventObj); // light update does not perform data process, layout and visual. - - if (isHighDown) { - var _a = preParseFinder(payload), - queryOptionMap = _a.queryOptionMap, - mainTypeSpecified = _a.mainTypeSpecified; - - var componentMainType = mainTypeSpecified ? queryOptionMap.keys()[0] : 'series'; - updateDirectly(_this, updateMethod, batchItem, componentMainType); - markStatusToUpdate(_this); - } else if (isSelectChange) { - // At present `dispatchAction({ type: 'select', ... })` is not supported on components. - // geo still use 'geoselect'. - updateDirectly(_this, updateMethod, batchItem, 'series'); - markStatusToUpdate(_this); - } else if (cptType) { - updateDirectly(_this, updateMethod, batchItem, cptType.main, cptType.sub); - } - }); - - if (updateMethod !== 'none' && !isHighDown && !isSelectChange && !cptType) { - try { - // Still dirty - if (this[PENDING_UPDATE]) { - prepare(this); - updateMethods.update.call(this, payload); - this[PENDING_UPDATE] = null; - } else { - updateMethods[updateMethod].call(this, payload); - } - } catch (e) { - this[IN_MAIN_PROCESS_KEY] = false; - throw e; - } - } // Follow the rule of action batch - - - if (batched) { - eventObj = { - type: nonRefinedEventType, - escapeConnect: escapeConnect, - batch: eventObjBatch - }; - } else { - eventObj = eventObjBatch[0]; - } - - this[IN_MAIN_PROCESS_KEY] = false; - - if (!silent) { - var refinedEvent = void 0; - - if (actionInfo.refineEvent) { - var eventContent = actionInfo.refineEvent(actionResultBatch, payload, ecModel, this._api).eventContent; - assert(isObject$2(eventContent)); - refinedEvent = defaults({ - type: actionInfo.refinedEventType - }, eventContent); - refinedEvent.fromAction = payload.type; - refinedEvent.fromActionPayload = payload; - refinedEvent.escapeConnect = true; - } - - var messageCenter = this._messageCenter; // - If `refineEvent` created a `refinedEvent`, `eventObj` (replicated from the original payload) - // is still needed to be triggered for the feature `connect`. But it will not be triggered to - // users in this case. - // - If no `refineEvent` used, `eventObj` will be triggered for both `connect` and users. - - messageCenter.trigger(eventObj.type, eventObj); - - if (refinedEvent) { - messageCenter.trigger(refinedEvent.type, refinedEvent); - } - } - }; - - flushPendingActions = function (silent) { - var pendingActions = this._pendingActions; - - while (pendingActions.length) { - var payload = pendingActions.shift(); - doDispatchAction.call(this, payload, silent); - } - }; - - triggerUpdatedEvent = function (silent) { - !silent && this.trigger('updated'); - }; - /** - * Event `rendered` is triggered when zr - * rendered. It is useful for realtime - * snapshot (reflect animation). - * - * Event `finished` is triggered when: - * (1) zrender rendering finished. - * (2) initial animation finished. - * (3) progressive rendering finished. - * (4) no pending action. - * (5) no delayed setOption needs to be processed. - */ - - - bindRenderedEvent = function (zr, ecIns) { - zr.on('rendered', function (params) { - ecIns.trigger('rendered', params); // The `finished` event should not be triggered repeatedly, - // so it should only be triggered when rendering indeed happens - // in zrender. (Consider the case that dipatchAction is keep - // triggering when mouse move). - - if ( // Although zr is dirty if initial animation is not finished - // and this checking is called on frame, we also check - // animation finished for robustness. - zr.animation.isFinished() && !ecIns[PENDING_UPDATE] && !ecIns._scheduler.unfinished && !ecIns._pendingActions.length) { - ecIns.trigger('finished'); - } - }); - }; - - bindMouseEvent = function (zr, ecIns) { - zr.on('mouseover', function (e) { - var el = e.target; - var dispatcher = findEventDispatcher(el, isHighDownDispatcher); - - if (dispatcher) { - handleGlobalMouseOverForHighDown(dispatcher, e, ecIns._api); - markStatusToUpdate(ecIns); - } - }).on('mouseout', function (e) { - var el = e.target; - var dispatcher = findEventDispatcher(el, isHighDownDispatcher); - - if (dispatcher) { - handleGlobalMouseOutForHighDown(dispatcher, e, ecIns._api); - markStatusToUpdate(ecIns); - } - }).on('click', function (e) { - var el = e.target; - var dispatcher = findEventDispatcher(el, function (target) { - return getECData(target).dataIndex != null; - }, true); - - if (dispatcher) { - var actionType = dispatcher.selected ? 'unselect' : 'select'; - var ecData = getECData(dispatcher); - - ecIns._api.dispatchAction({ - type: actionType, - dataType: ecData.dataType, - dataIndexInside: ecData.dataIndex, - seriesIndex: ecData.seriesIndex, - isFromClick: true - }); - } - }); - }; - - function clearColorPalette(ecModel) { - ecModel.clearColorPalette(); - ecModel.eachSeries(function (seriesModel) { - seriesModel.clearColorPalette(); - }); - } // Allocate zlevels for series and components - - - function allocateZlevels(ecModel) { - var componentZLevels = []; - var seriesZLevels = []; - var hasSeparateZLevel = false; - ecModel.eachComponent(function (componentType, componentModel) { - var zlevel = componentModel.get('zlevel') || 0; - var z = componentModel.get('z') || 0; - var zlevelKey = componentModel.getZLevelKey(); - hasSeparateZLevel = hasSeparateZLevel || !!zlevelKey; - (componentType === 'series' ? seriesZLevels : componentZLevels).push({ - zlevel: zlevel, - z: z, - idx: componentModel.componentIndex, - type: componentType, - key: zlevelKey - }); - }); - - if (hasSeparateZLevel) { - // Series after component - var zLevels = componentZLevels.concat(seriesZLevels); - var lastSeriesZLevel_1; - var lastSeriesKey_1; - sort(zLevels, function (a, b) { - if (a.zlevel === b.zlevel) { - return a.z - b.z; - } - - return a.zlevel - b.zlevel; - }); - each$4(zLevels, function (item) { - var componentModel = ecModel.getComponent(item.type, item.idx); - var zlevel = item.zlevel; - var key = item.key; - - if (lastSeriesZLevel_1 != null) { - zlevel = Math.max(lastSeriesZLevel_1, zlevel); - } - - if (key) { - if (zlevel === lastSeriesZLevel_1 && key !== lastSeriesKey_1) { - zlevel++; - } - - lastSeriesKey_1 = key; - } else if (lastSeriesKey_1) { - if (zlevel === lastSeriesZLevel_1) { - zlevel++; - } - - lastSeriesKey_1 = ''; - } - - lastSeriesZLevel_1 = zlevel; - componentModel.setZLevel(zlevel); - }); - } - } - - render = function (ecIns, ecModel, api, payload, updateParams) { - allocateZlevels(ecModel); - renderComponents(ecIns, ecModel, api, payload, updateParams); - each$4(ecIns._chartsViews, function (chart) { - chart.__alive = false; - }); - renderSeries(ecIns, ecModel, api, payload, updateParams); // Remove groups of unrendered charts - - each$4(ecIns._chartsViews, function (chart) { - if (!chart.__alive) { - chart.remove(ecModel, api); - } - }); - }; - - renderComponents = function (ecIns, ecModel, api, payload, updateParams, dirtyList) { - each$4(dirtyList || ecIns._componentsViews, function (componentView) { - var componentModel = componentView.__model; - clearStates(componentModel, componentView); - componentView.render(componentModel, ecModel, api, payload); - updateZ(componentModel, componentView); - updateStates(componentModel, componentView); - }); - }; - /** - * Render each chart and component - */ - - - renderSeries = function (ecIns, ecModel, api, payload, updateParams, dirtyMap) { - // Render all charts - var scheduler = ecIns._scheduler; - updateParams = extend(updateParams || {}, { - updatedSeries: ecModel.getSeries() - }); // TODO progressive? - - lifecycle.trigger('series:beforeupdate', ecModel, api, updateParams); - var unfinished = false; - ecModel.eachSeries(function (seriesModel) { - var chartView = ecIns._chartsMap[seriesModel.__viewId]; - chartView.__alive = true; - var renderTask = chartView.renderTask; - scheduler.updatePayload(renderTask, payload); // TODO states on marker. - - clearStates(seriesModel, chartView); - - if (dirtyMap && dirtyMap.get(seriesModel.uid)) { - renderTask.dirty(); - } - - if (renderTask.perform(scheduler.getPerformArgs(renderTask))) { - unfinished = true; - } - - chartView.group.silent = !!seriesModel.get('silent'); // Should not call markRedraw on group, because it will disable zrender - // incremental render (always render from the __startIndex each frame) - // chartView.group.markRedraw(); - - updateBlend(seriesModel, chartView); - updateSeriesElementSelection(seriesModel); - }); - scheduler.unfinished = unfinished || scheduler.unfinished; - lifecycle.trigger('series:layoutlabels', ecModel, api, updateParams); // transition after label is layouted. - - lifecycle.trigger('series:transition', ecModel, api, updateParams); - ecModel.eachSeries(function (seriesModel) { - var chartView = ecIns._chartsMap[seriesModel.__viewId]; // Update Z after labels updated. Before applying states. - - updateZ(seriesModel, chartView); // NOTE: Update states after label is updated. - // label should be in normal status when layouting. - - updateStates(seriesModel, chartView); - }); // If use hover layer - - updateHoverLayerStatus(ecIns, ecModel); - lifecycle.trigger('series:afterupdate', ecModel, api, updateParams); - }; - - markStatusToUpdate = function (ecIns) { - ecIns[STATUS_NEEDS_UPDATE_KEY] = true; // Wake up zrender if it's sleep. Let it update states in the next frame. - - ecIns.getZr().wakeUp(); - }; - - updateMainProcessVersion = function (ecIns) { - ecIns[MAIN_PROCESS_VERSION_KEY] = (ecIns[MAIN_PROCESS_VERSION_KEY] + 1) % 1000; - }; - - applyChangedStates = function (ecIns) { - if (!ecIns[STATUS_NEEDS_UPDATE_KEY]) { - return; - } - - ecIns.getZr().storage.traverse(function (el) { - // Not applied on removed elements, it may still in fading. - if (isElementRemoved(el)) { - return; - } - - applyElementStates(el); - }); - ecIns[STATUS_NEEDS_UPDATE_KEY] = false; - }; - - function applyElementStates(el) { - var newStates = []; - var oldStates = el.currentStates; // Keep other states. - - for (var i = 0; i < oldStates.length; i++) { - var stateName = oldStates[i]; - - if (!(stateName === 'emphasis' || stateName === 'blur' || stateName === 'select')) { - newStates.push(stateName); - } - } // Only use states when it's exists. - - - if (el.selected && el.states.select) { - newStates.push('select'); - } - - if (el.hoverState === HOVER_STATE_EMPHASIS && el.states.emphasis) { - newStates.push('emphasis'); - } else if (el.hoverState === HOVER_STATE_BLUR && el.states.blur) { - newStates.push('blur'); - } - - el.useStates(newStates); - } - - function updateHoverLayerStatus(ecIns, ecModel) { - var zr = ecIns._zr; - var storage = zr.storage; - var elCount = 0; - storage.traverse(function (el) { - if (!el.isGroup) { - elCount++; - } - }); - - if (elCount > ecModel.get('hoverLayerThreshold') && !env.node && !env.worker) { - ecModel.eachSeries(function (seriesModel) { - if (seriesModel.preventUsingHoverLayer) { - return; - } - - var chartView = ecIns._chartsMap[seriesModel.__viewId]; - - if (chartView.__alive) { - chartView.eachRendered(function (el) { - if (el.states.emphasis) { - el.states.emphasis.hoverLayer = true; - } - }); - } - }); - } - } - /** - * Update chart and blend. - */ - - - function updateBlend(seriesModel, chartView) { - var blendMode = seriesModel.get('blendMode') || null; - chartView.eachRendered(function (el) { - // FIXME marker and other components - if (!el.isGroup) { - // DON'T mark the element dirty. In case element is incremental and don't want to rerender. - el.style.blend = blendMode; - } - }); - } - - function updateZ(model, view) { - if (model.preventAutoZ) { - return; - } - - var zInfo = retrieveZInfo(model); // Set z and zlevel - - view.eachRendered(function (el) { - traverseUpdateZ(el, zInfo.z, zInfo.zlevel); // Don't traverse the children because it has been traversed in _updateZ. - - return true; - }); - } // Clear states without animation. - // TODO States on component. - - - function clearStates(model, view) { - view.eachRendered(function (el) { - // Not applied on removed elements, it may still in fading. - if (isElementRemoved(el)) { - return; - } - - var textContent = el.getTextContent(); - var textGuide = el.getTextGuideLine(); - - if (el.stateTransition) { - el.stateTransition = null; - } - - if (textContent && textContent.stateTransition) { - textContent.stateTransition = null; - } - - if (textGuide && textGuide.stateTransition) { - textGuide.stateTransition = null; - } // TODO If el is incremental. - - - if (el.hasState()) { - el.prevStates = el.currentStates; - el.clearStates(); - } else if (el.prevStates) { - el.prevStates = null; - } - }); - } - - function updateStates(model, view) { - var stateAnimationModel = model.getModel('stateAnimation'); - var enableAnimation = model.isAnimationEnabled(); - var duration = stateAnimationModel.get('duration'); - var stateTransition = duration > 0 ? { - duration: duration, - delay: stateAnimationModel.get('delay'), - easing: stateAnimationModel.get('easing') // additive: stateAnimationModel.get('additive') - - } : null; - view.eachRendered(function (el) { - if (el.states && el.states.emphasis) { - // Not applied on removed elements, it may still in fading. - if (isElementRemoved(el)) { - return; - } - - if (el instanceof Path) { - savePathStates(el); - } // Only updated on changed element. In case element is incremental and don't want to rerender. - // TODO, a more proper way? - - - if (el.__dirty) { - var prevStates = el.prevStates; // Restore states without animation - - if (prevStates) { - el.useStates(prevStates); - } - } // Update state transition and enable animation again. - - - if (enableAnimation) { - el.stateTransition = stateTransition; - var textContent = el.getTextContent(); - var textGuide = el.getTextGuideLine(); // TODO Is it necessary to animate label? - - if (textContent) { - textContent.stateTransition = stateTransition; - } - - if (textGuide) { - textGuide.stateTransition = stateTransition; - } - } // Use highlighted and selected flag to toggle states. - - - if (el.__dirty) { - applyElementStates(el); - } - } - }); - } - - createExtensionAPI = function (ecIns) { - return new ( - /** @class */ - function (_super) { - __extends(class_1, _super); - - function class_1() { - return _super !== null && _super.apply(this, arguments) || this; - } - - class_1.prototype.getCoordinateSystems = function () { - return ecIns._coordSysMgr.getCoordinateSystems(); - }; - - class_1.prototype.getComponentByElement = function (el) { - while (el) { - var modelInfo = el.__ecComponentInfo; - - if (modelInfo != null) { - return ecIns._model.getComponent(modelInfo.mainType, modelInfo.index); - } - - el = el.parent; - } - }; - - class_1.prototype.enterEmphasis = function (el, highlightDigit) { - enterEmphasis(el, highlightDigit); - markStatusToUpdate(ecIns); - }; - - class_1.prototype.leaveEmphasis = function (el, highlightDigit) { - leaveEmphasis(el, highlightDigit); - markStatusToUpdate(ecIns); - }; - - class_1.prototype.enterBlur = function (el) { - enterBlur(el); - markStatusToUpdate(ecIns); - }; - - class_1.prototype.leaveBlur = function (el) { - leaveBlur(el); - markStatusToUpdate(ecIns); - }; - - class_1.prototype.enterSelect = function (el) { - enterSelect(el); - markStatusToUpdate(ecIns); - }; - - class_1.prototype.leaveSelect = function (el) { - leaveSelect(el); - markStatusToUpdate(ecIns); - }; - - class_1.prototype.getModel = function () { - return ecIns.getModel(); - }; - - class_1.prototype.getViewOfComponentModel = function (componentModel) { - return ecIns.getViewOfComponentModel(componentModel); - }; - - class_1.prototype.getViewOfSeriesModel = function (seriesModel) { - return ecIns.getViewOfSeriesModel(seriesModel); - }; - - class_1.prototype.getMainProcessVersion = function () { - return ecIns[MAIN_PROCESS_VERSION_KEY]; - }; - - return class_1; - }(ExtensionAPI))(ecIns); - }; - - enableConnect = function (chart) { - function updateConnectedChartsStatus(charts, status) { - for (var i = 0; i < charts.length; i++) { - var otherChart = charts[i]; - otherChart[CONNECT_STATUS_KEY] = status; - } - } - - each$4(connectionEventRevertMap, function (_, eventType) { - chart._messageCenter.on(eventType, function (event) { - if (connectedGroups[chart.group] && chart[CONNECT_STATUS_KEY] !== CONNECT_STATUS_PENDING) { - if (event && event.escapeConnect) { - return; - } - - var action_1 = chart.makeActionFromEvent(event); - var otherCharts_1 = []; - each$4(instances, function (otherChart) { - if (otherChart !== chart && otherChart.group === chart.group) { - otherCharts_1.push(otherChart); - } - }); - updateConnectedChartsStatus(otherCharts_1, CONNECT_STATUS_PENDING); - each$4(otherCharts_1, function (otherChart) { - if (otherChart[CONNECT_STATUS_KEY] !== CONNECT_STATUS_UPDATING) { - otherChart.dispatchAction(action_1); - } - }); - updateConnectedChartsStatus(otherCharts_1, CONNECT_STATUS_UPDATED); - } - }); - }); - }; - }(); - - return ECharts; - }(Eventful); - - var echartsProto = ECharts.prototype; - echartsProto.on = createRegisterEventWithLowercaseECharts('on'); - echartsProto.off = createRegisterEventWithLowercaseECharts('off'); - /** - * @deprecated - */ - // @ts-ignore - - echartsProto.one = function (eventName, cb, ctx) { - var self = this; - deprecateLog('ECharts#one is deprecated.'); - - function wrapped() { - var args2 = []; - - for (var _i = 0; _i < arguments.length; _i++) { - args2[_i] = arguments[_i]; - } - - cb && cb.apply && cb.apply(this, args2); // @ts-ignore - - self.off(eventName, wrapped); - } // @ts-ignore - - - this.on.call(this, eventName, wrapped, ctx); - }; - - var MOUSE_EVENT_NAMES = ['click', 'dblclick', 'mouseover', 'mouseout', 'mousemove', 'mousedown', 'mouseup', 'globalout', 'contextmenu']; - - function disposedWarning(id) { - { - warn('Instance ' + id + ' has been disposed'); - } - } - - var actions = {}; - /** - * Map event type to action type for reproducing action from event for `connect`. - */ - - var connectionEventRevertMap = {}; - /** - * To remove duplication. - */ - - var publicEventTypeMap = {}; - var dataProcessorFuncs = []; - var optionPreprocessorFuncs = []; - var visualFuncs = []; - var themeStorage = {}; - var loadingEffects = {}; - var instances = {}; - var connectedGroups = {}; - var idBase = +new Date() - 0; - var groupIdBase = +new Date() - 0; - var DOM_ATTRIBUTE_KEY = '_echarts_instance_'; - /** - * @param opts.devicePixelRatio Use window.devicePixelRatio by default - * @param opts.renderer Can choose 'canvas' or 'svg' to render the chart. - * @param opts.width Use clientWidth of the input `dom` by default. - * Can be 'auto' (the same as null/undefined) - * @param opts.height Use clientHeight of the input `dom` by default. - * Can be 'auto' (the same as null/undefined) - * @param opts.locale Specify the locale. - * @param opts.useDirtyRect Enable dirty rectangle rendering or not. - */ - - function init(dom, theme, opts) { - var isClient = !(opts && opts.ssr); - - if (isClient) { - { - if (!dom) { - throw new Error('Initialize failed: invalid dom.'); - } - } - var existInstance = getInstanceByDom(dom); - - if (existInstance) { - { - warn('There is a chart instance already initialized on the dom.'); - } - return existInstance; - } - - { - if (isDom(dom) && dom.nodeName.toUpperCase() !== 'CANVAS' && (!dom.clientWidth && (!opts || opts.width == null) || !dom.clientHeight && (!opts || opts.height == null))) { - warn('Can\'t get DOM width or height. Please check ' + 'dom.clientWidth and dom.clientHeight. They should not be 0.' + 'For example, you may need to call this in the callback ' + 'of window.onload.'); - } - } - } - - var chart = new ECharts(dom, theme, opts); - chart.id = 'ec_' + idBase++; - instances[chart.id] = chart; - isClient && setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id); - enableConnect(chart); - lifecycle.trigger('afterinit', chart); - return chart; - } - /** - * @usage - * (A) - * ```js - * let chart1 = echarts.init(dom1); - * let chart2 = echarts.init(dom2); - * chart1.group = 'xxx'; - * chart2.group = 'xxx'; - * echarts.connect('xxx'); - * ``` - * (B) - * ```js - * let chart1 = echarts.init(dom1); - * let chart2 = echarts.init(dom2); - * echarts.connect('xxx', [chart1, chart2]); - * ``` - */ - - - function connect(groupId) { - // Is array of charts - if (isArray(groupId)) { - var charts = groupId; - groupId = null; // If any chart has group - - each$4(charts, function (chart) { - if (chart.group != null) { - groupId = chart.group; - } - }); - groupId = groupId || 'g_' + groupIdBase++; - each$4(charts, function (chart) { - chart.group = groupId; - }); - } - - connectedGroups[groupId] = true; - return groupId; - } - - function disconnect(groupId) { - connectedGroups[groupId] = false; - } - /** - * Alias and backward compatibility - * @deprecated - */ - - - var disConnect = disconnect; - /** - * Dispose a chart instance - */ - - function dispose(chart) { - if (isString(chart)) { - chart = instances[chart]; - } else if (!(chart instanceof ECharts)) { - // Try to treat as dom - chart = getInstanceByDom(chart); - } - - if (chart instanceof ECharts && !chart.isDisposed()) { - chart.dispose(); - } - } - - function getInstanceByDom(dom) { - return instances[getAttribute(dom, DOM_ATTRIBUTE_KEY)]; - } - - function getInstanceById(key) { - return instances[key]; - } - /** - * Register theme - */ - - - function registerTheme(name, theme) { - themeStorage[name] = theme; - } - /** - * Register option preprocessor - */ - - - function registerPreprocessor(preprocessorFunc) { - if (indexOf(optionPreprocessorFuncs, preprocessorFunc) < 0) { - optionPreprocessorFuncs.push(preprocessorFunc); - } - } - - function registerProcessor(priority, processor) { - normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_DEFAULT); - } - /** - * Register postIniter - * @param {Function} postInitFunc - */ - - - function registerPostInit(postInitFunc) { - registerUpdateLifecycle('afterinit', postInitFunc); - } - /** - * Register postUpdater - * @param {Function} postUpdateFunc - */ - - - function registerPostUpdate(postUpdateFunc) { - registerUpdateLifecycle('afterupdate', postUpdateFunc); - } - - function registerUpdateLifecycle(name, cb) { - lifecycle.on(name, cb); - } - - function registerAction(arg0, arg1, action) { - var actionType; - var publicEventType; - var refineEvent; - var update; - var publishNonRefinedEvent; - - if (isFunction(arg1)) { - action = arg1; - arg1 = ''; - } - - if (isObject$2(arg0)) { - actionType = arg0.type; - publicEventType = arg0.event; - update = arg0.update; - publishNonRefinedEvent = arg0.publishNonRefinedEvent; - - if (!action) { - action = arg0.action; - } - - refineEvent = arg0.refineEvent; - } else { - actionType = arg0; - publicEventType = arg1; - } - - function createEventType(actionOrEventType) { - // Event type should be all lowercase - return actionOrEventType.toLowerCase(); - } - - publicEventType = createEventType(publicEventType || actionType); // See comments on {ActionInfo} for the reason. - - var nonRefinedEventType = refineEvent ? createEventType(actionType) : publicEventType; // Support calling `registerAction` multiple times with the same action - // type; subsequent calls have no effect. - - if (actions[actionType]) { - return; - } // Validate action type and event name. - - - assert(ACTION_REG.test(actionType) && ACTION_REG.test(publicEventType)); - - if (refineEvent) { - // An event replicated from the action will be triggered internally for `connect` in this case. - assert(publicEventType !== actionType); - } - - actions[actionType] = { - actionType: actionType, - refinedEventType: publicEventType, - nonRefinedEventType: nonRefinedEventType, - update: update, - action: action, - refineEvent: refineEvent - }; - publicEventTypeMap[publicEventType] = 1; - - if (refineEvent && publishNonRefinedEvent) { - publicEventTypeMap[nonRefinedEventType] = 1; - } - - if (connectionEventRevertMap[nonRefinedEventType]) { - error(nonRefinedEventType + " must not be shared; use \"refineEvent\" if you intend to share an event name."); - } - - connectionEventRevertMap[nonRefinedEventType] = actionType; - } - - function registerCoordinateSystem(type, coordSysCreator) { - CoordinateSystemManager.register(type, coordSysCreator); - } - /** - * Get dimensions of specified coordinate system. - * @param {string} type - * @return {Array.} - */ - - - function getCoordinateSystemDimensions(type) { - var coordSysCreator = CoordinateSystemManager.get(type); - - if (coordSysCreator) { - return coordSysCreator.getDimensionsInfo ? coordSysCreator.getDimensionsInfo() : coordSysCreator.dimensions.slice(); - } - } - - function registerCustomSeries(seriesType, renderItem) {} - - function registerLayout(priority, layoutTask) { - normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout'); - } - - function registerVisual(priority, visualTask) { - normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual'); - } - - var registeredTasks = []; - - function normalizeRegister(targetList, priority, fn, defaultPriority, visualType) { - if (isFunction(priority) || isObject$2(priority)) { - fn = priority; - priority = defaultPriority; - } - - { - if (isNaN(priority) || priority == null) { - throw new Error('Illegal priority'); - } // Check duplicate - - - each$4(targetList, function (wrap) { - assert(wrap.__raw !== fn); - }); - } // Already registered - - if (indexOf(registeredTasks, fn) >= 0) { - return; - } - - registeredTasks.push(fn); - var stageHandler = Scheduler.wrapStageHandler(fn, visualType); - stageHandler.__prio = priority; - stageHandler.__raw = fn; - targetList.push(stageHandler); - } - - function registerLoading(name, loadingFx) { - loadingEffects[name] = loadingFx; - } - /** - * ZRender need a canvas context to do measureText. - * But in node environment canvas may be created by node-canvas. - * So we need to specify how to create a canvas instead of using document.createElement('canvas') - * - * - * @deprecated use setPlatformAPI({ createCanvas }) instead. - * - * @example - * let Canvas = require('canvas'); - * let echarts = require('echarts'); - * echarts.setCanvasCreator(function () { - * // Small size is enough. - * return new Canvas(32, 32); - * }); - */ - - - function setCanvasCreator(creator) { - { - deprecateLog('setCanvasCreator is deprecated. Use setPlatformAPI({ createCanvas }) instead.'); - } - setPlatformAPI({ - createCanvas: creator - }); - } - /** - * The parameters and usage: see `geoSourceManager.registerMap`. - * Compatible with previous `echarts.registerMap`. - */ - - - function registerMap(mapName, geoJson, specialAreas) { - var registerMap = getImpl('registerMap'); - registerMap && registerMap(mapName, geoJson, specialAreas); - } - - function getMap(mapName) { - var getMap = getImpl('getMap'); - return getMap && getMap(mapName); - } - - var registerTransform = registerExternalTransform; - /** - * Globa dispatchAction to a specified chart instance. - */ - // export function dispatchAction(payload: { chartId: string } & Payload, opt?: Parameters[1]) { - // if (!payload || !payload.chartId) { - // // Must have chartId to find chart - // return; - // } - // const chart = instances[payload.chartId]; - // if (chart) { - // chart.dispatchAction(payload, opt); - // } - // } - // Builtin global visual - - registerVisual(PRIORITY_VISUAL_GLOBAL, seriesStyleTask); - registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataStyleTask); - registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataColorPaletteTask); - registerVisual(PRIORITY_VISUAL_GLOBAL, seriesSymbolTask); - registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataSymbolTask); - registerVisual(PRIORITY_VISUAL_DECAL, decalVisual); - registerPreprocessor(globalBackwardCompat); - registerProcessor(PRIORITY_PROCESSOR_DATASTACK, dataStack$1); - registerLoading('default', defaultLoading); // Default actions - - registerAction({ - type: HIGHLIGHT_ACTION_TYPE, - event: HIGHLIGHT_ACTION_TYPE, - update: HIGHLIGHT_ACTION_TYPE - }, noop); - registerAction({ - type: DOWNPLAY_ACTION_TYPE, - event: DOWNPLAY_ACTION_TYPE, - update: DOWNPLAY_ACTION_TYPE - }, noop); - registerAction({ - type: SELECT_ACTION_TYPE, - event: SELECT_CHANGED_EVENT_TYPE, - update: SELECT_ACTION_TYPE, - action: noop, - refineEvent: makeSelectChangedEvent, - publishNonRefinedEvent: true - }); - registerAction({ - type: UNSELECT_ACTION_TYPE, - event: SELECT_CHANGED_EVENT_TYPE, - update: UNSELECT_ACTION_TYPE, - action: noop, - refineEvent: makeSelectChangedEvent, - publishNonRefinedEvent: true - }); - registerAction({ - type: TOGGLE_SELECT_ACTION_TYPE, - event: SELECT_CHANGED_EVENT_TYPE, - update: TOGGLE_SELECT_ACTION_TYPE, - action: noop, - refineEvent: makeSelectChangedEvent, - publishNonRefinedEvent: true - }); - - function makeSelectChangedEvent(actionResultBatch, payload, ecModel, api) { - return { - eventContent: { - selected: getAllSelectedIndices(ecModel), - isFromClick: payload.isFromClick || false - } - }; - } // Default theme, so that we can use `chart.setTheme('default')` to revert to - // the default theme after changing to other themes. - - - registerTheme('default', {}); - registerTheme('dark', theme); // For backward compatibility, where the namespace `dataTool` will - // be mounted on `echarts` is the extension `dataTool` is imported. - - var dataTool = {}; - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * AUTO-GENERATED FILE. DO NOT MODIFY. - */ - - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - function dataIndexMapValueLength(valNumOrArrLengthMoreThan2) { - return valNumOrArrLengthMoreThan2 == null ? 0 : valNumOrArrLengthMoreThan2.length || 1; - } - - function defaultKeyGetter(item) { - return item; - } - - var DataDiffer = - /** @class */ - function () { - /** - * @param context Can be visited by this.context in callback. - */ - function DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter, context, // By default: 'oneToOne'. - diffMode) { - this._old = oldArr; - this._new = newArr; - this._oldKeyGetter = oldKeyGetter || defaultKeyGetter; - this._newKeyGetter = newKeyGetter || defaultKeyGetter; // Visible in callback via `this.context`; - - this.context = context; - this._diffModeMultiple = diffMode === 'multiple'; - } - /** - * Callback function when add a data - */ - - - DataDiffer.prototype.add = function (func) { - this._add = func; - return this; - }; - /** - * Callback function when update a data - */ - - - DataDiffer.prototype.update = function (func) { - this._update = func; - return this; - }; - /** - * Callback function when update a data and only work in `cbMode: 'byKey'`. - */ - - - DataDiffer.prototype.updateManyToOne = function (func) { - this._updateManyToOne = func; - return this; - }; - /** - * Callback function when update a data and only work in `cbMode: 'byKey'`. - */ - - - DataDiffer.prototype.updateOneToMany = function (func) { - this._updateOneToMany = func; - return this; - }; - /** - * Callback function when update a data and only work in `cbMode: 'byKey'`. - */ - - - DataDiffer.prototype.updateManyToMany = function (func) { - this._updateManyToMany = func; - return this; - }; - /** - * Callback function when remove a data - */ - - - DataDiffer.prototype.remove = function (func) { - this._remove = func; - return this; - }; - - DataDiffer.prototype.execute = function () { - this[this._diffModeMultiple ? '_executeMultiple' : '_executeOneToOne'](); - }; - - DataDiffer.prototype._executeOneToOne = function () { - var oldArr = this._old; - var newArr = this._new; - var newDataIndexMap = {}; - var oldDataKeyArr = new Array(oldArr.length); - var newDataKeyArr = new Array(newArr.length); - - this._initIndexMap(oldArr, null, oldDataKeyArr, '_oldKeyGetter'); - - this._initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter'); - - for (var i = 0; i < oldArr.length; i++) { - var oldKey = oldDataKeyArr[i]; - var newIdxMapVal = newDataIndexMap[oldKey]; - var newIdxMapValLen = dataIndexMapValueLength(newIdxMapVal); // idx can never be empty array here. see 'set null' logic below. - - if (newIdxMapValLen > 1) { - // Consider there is duplicate key (for example, use dataItem.name as key). - // We should make sure every item in newArr and oldArr can be visited. - var newIdx = newIdxMapVal.shift(); - - if (newIdxMapVal.length === 1) { - newDataIndexMap[oldKey] = newIdxMapVal[0]; - } - - this._update && this._update(newIdx, i); - } else if (newIdxMapValLen === 1) { - newDataIndexMap[oldKey] = null; - this._update && this._update(newIdxMapVal, i); - } else { - this._remove && this._remove(i); - } - } - - this._performRestAdd(newDataKeyArr, newDataIndexMap); - }; - /** - * For example, consider the case: - * oldData: [o0, o1, o2, o3, o4, o5, o6, o7], - * newData: [n0, n1, n2, n3, n4, n5, n6, n7, n8], - * Where: - * o0, o1, n0 has key 'a' (many to one) - * o5, n4, n5, n6 has key 'b' (one to many) - * o2, n1 has key 'c' (one to one) - * n2, n3 has key 'd' (add) - * o3, o4 has key 'e' (remove) - * o6, o7, n7, n8 has key 'f' (many to many, treated as add and remove) - * Then: - * (The order of the following directives are not ensured.) - * this._updateManyToOne(n0, [o0, o1]); - * this._updateOneToMany([n4, n5, n6], o5); - * this._update(n1, o2); - * this._remove(o3); - * this._remove(o4); - * this._remove(o6); - * this._remove(o7); - * this._add(n2); - * this._add(n3); - * this._add(n7); - * this._add(n8); - */ - - - DataDiffer.prototype._executeMultiple = function () { - var oldArr = this._old; - var newArr = this._new; - var oldDataIndexMap = {}; - var newDataIndexMap = {}; - var oldDataKeyArr = []; - var newDataKeyArr = []; - - this._initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter'); - - this._initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter'); - - for (var i = 0; i < oldDataKeyArr.length; i++) { - var oldKey = oldDataKeyArr[i]; - var oldIdxMapVal = oldDataIndexMap[oldKey]; - var newIdxMapVal = newDataIndexMap[oldKey]; - var oldIdxMapValLen = dataIndexMapValueLength(oldIdxMapVal); - var newIdxMapValLen = dataIndexMapValueLength(newIdxMapVal); - - if (oldIdxMapValLen > 1 && newIdxMapValLen === 1) { - this._updateManyToOne && this._updateManyToOne(newIdxMapVal, oldIdxMapVal); - newDataIndexMap[oldKey] = null; - } else if (oldIdxMapValLen === 1 && newIdxMapValLen > 1) { - this._updateOneToMany && this._updateOneToMany(newIdxMapVal, oldIdxMapVal); - newDataIndexMap[oldKey] = null; - } else if (oldIdxMapValLen === 1 && newIdxMapValLen === 1) { - this._update && this._update(newIdxMapVal, oldIdxMapVal); - newDataIndexMap[oldKey] = null; - } else if (oldIdxMapValLen > 1 && newIdxMapValLen > 1) { - this._updateManyToMany && this._updateManyToMany(newIdxMapVal, oldIdxMapVal); - newDataIndexMap[oldKey] = null; - } else if (oldIdxMapValLen > 1) { - for (var i_1 = 0; i_1 < oldIdxMapValLen; i_1++) { - this._remove && this._remove(oldIdxMapVal[i_1]); - } - } else { - this._remove && this._remove(oldIdxMapVal); - } - } - - this._performRestAdd(newDataKeyArr, newDataIndexMap); - }; - - DataDiffer.prototype._performRestAdd = function (newDataKeyArr, newDataIndexMap) { - for (var i = 0; i < newDataKeyArr.length; i++) { - var newKey = newDataKeyArr[i]; - var newIdxMapVal = newDataIndexMap[newKey]; - var idxMapValLen = dataIndexMapValueLength(newIdxMapVal); - - if (idxMapValLen > 1) { - for (var j = 0; j < idxMapValLen; j++) { - this._add && this._add(newIdxMapVal[j]); - } - } else if (idxMapValLen === 1) { - this._add && this._add(newIdxMapVal); - } // Support both `newDataKeyArr` are duplication removed or not removed. - - - newDataIndexMap[newKey] = null; - } - }; - - DataDiffer.prototype._initIndexMap = function (arr, // Can be null. - map, // In 'byKey', the output `keyArr` is duplication removed. - // In 'byIndex', the output `keyArr` is not duplication removed and - // its indices are accurately corresponding to `arr`. - keyArr, keyGetterName) { - var cbModeMultiple = this._diffModeMultiple; - - for (var i = 0; i < arr.length; i++) { - // Add prefix to avoid conflict with Object.prototype. - var key = '_ec_' + this[keyGetterName](arr[i], i); - - if (!cbModeMultiple) { - keyArr[i] = key; - } - - if (!map) { - continue; - } - - var idxMapVal = map[key]; - var idxMapValLen = dataIndexMapValueLength(idxMapVal); - - if (idxMapValLen === 0) { - // Simple optimize: in most cases, one index has one key, - // do not need array. - map[key] = i; - - if (cbModeMultiple) { - keyArr.push(key); - } - } else if (idxMapValLen === 1) { - map[key] = [idxMapVal, i]; - } else { - idxMapVal.push(i); - } - } - }; - - return DataDiffer; - }(); - - var DimensionUserOuput = - /** @class */ - function () { - function DimensionUserOuput(encode, dimRequest) { - this._encode = encode; - this._schema = dimRequest; - } - - DimensionUserOuput.prototype.get = function () { - return { - // Do not generate full dimension name until fist used. - fullDimensions: this._getFullDimensionNames(), - encode: this._encode - }; - }; - /** - * Get all data store dimension names. - * Theoretically a series data store is defined both by series and used dataset (if any). - * If some dimensions are omitted for performance reason in `this.dimensions`, - * the dimension name may not be auto-generated if user does not specify a dimension name. - * In this case, the dimension name is `null`/`undefined`. - */ - - - DimensionUserOuput.prototype._getFullDimensionNames = function () { - if (!this._cachedDimNames) { - this._cachedDimNames = this._schema ? this._schema.makeOutputDimensionNames() : []; - } - - return this._cachedDimNames; - }; - - return DimensionUserOuput; - }(); - - function summarizeDimensions(data, schema) { - var summary = {}; - var encode = summary.encode = {}; - var notExtraCoordDimMap = createHashMap(); - var defaultedLabel = []; - var defaultedTooltip = []; - var userOutputEncode = {}; - each$4(data.dimensions, function (dimName) { - var dimItem = data.getDimensionInfo(dimName); - var coordDim = dimItem.coordDim; - - if (coordDim) { - { - assert(VISUAL_DIMENSIONS.get(coordDim) == null); - } - var coordDimIndex = dimItem.coordDimIndex; - getOrCreateEncodeArr(encode, coordDim)[coordDimIndex] = dimName; - - if (!dimItem.isExtraCoord) { - notExtraCoordDimMap.set(coordDim, 1); // Use the last coord dim (and label friendly) as default label, - // because when dataset is used, it is hard to guess which dimension - // can be value dimension. If both show x, y on label is not look good, - // and conventionally y axis is focused more. - - if (mayLabelDimType(dimItem.type)) { - defaultedLabel[0] = dimName; - } // User output encode do not contain generated coords. - // And it only has index. User can use index to retrieve value from the raw item array. - - - getOrCreateEncodeArr(userOutputEncode, coordDim)[coordDimIndex] = data.getDimensionIndex(dimItem.name); - } - - if (dimItem.defaultTooltip) { - defaultedTooltip.push(dimName); - } - } - - VISUAL_DIMENSIONS.each(function (v, otherDim) { - var encodeArr = getOrCreateEncodeArr(encode, otherDim); - var dimIndex = dimItem.otherDims[otherDim]; - - if (dimIndex != null && dimIndex !== false) { - encodeArr[dimIndex] = dimItem.name; - } - }); - }); - var dataDimsOnCoord = []; - var encodeFirstDimNotExtra = {}; - notExtraCoordDimMap.each(function (v, coordDim) { - var dimArr = encode[coordDim]; - encodeFirstDimNotExtra[coordDim] = dimArr[0]; // Not necessary to remove duplicate, because a data - // dim canot on more than one coordDim. - - dataDimsOnCoord = dataDimsOnCoord.concat(dimArr); - }); - summary.dataDimsOnCoord = dataDimsOnCoord; - summary.dataDimIndicesOnCoord = map$1(dataDimsOnCoord, function (dimName) { - return data.getDimensionInfo(dimName).storeDimIndex; - }); - summary.encodeFirstDimNotExtra = encodeFirstDimNotExtra; - var encodeLabel = encode.label; // FIXME `encode.label` is not recommended, because formatter cannot be set - // in this way. Use label.formatter instead. Maybe remove this approach someday. - - if (encodeLabel && encodeLabel.length) { - defaultedLabel = encodeLabel.slice(); - } - - var encodeTooltip = encode.tooltip; - - if (encodeTooltip && encodeTooltip.length) { - defaultedTooltip = encodeTooltip.slice(); - } else if (!defaultedTooltip.length) { - defaultedTooltip = defaultedLabel.slice(); - } - - encode.defaultedLabel = defaultedLabel; - encode.defaultedTooltip = defaultedTooltip; - summary.userOutput = new DimensionUserOuput(userOutputEncode, schema); - return summary; - } - - function getOrCreateEncodeArr(encode, dim) { - if (!encode.hasOwnProperty(dim)) { - encode[dim] = []; - } - - return encode[dim]; - } // FIXME:TS should be type `AxisType` - - - function getDimensionTypeByAxis(axisType) { - return axisType === 'category' ? 'ordinal' : axisType === 'time' ? 'time' : 'float'; - } - - function mayLabelDimType(dimType) { - // In most cases, ordinal and time do not suitable for label. - // Ordinal info can be displayed on axis. Time is too long. - return !(dimType === 'ordinal' || dimType === 'time'); - } // function findTheLastDimMayLabel(data) { - // // Get last value dim - // let dimensions = data.dimensions.slice(); - // let valueType; - // let valueDim; - // while (dimensions.length && ( - // valueDim = dimensions.pop(), - // valueType = data.getDimensionInfo(valueDim).type, - // valueType === 'ordinal' || valueType === 'time' - // )) {} // jshint ignore:line - // return valueDim; - // } - - - var SeriesDimensionDefine = - /** @class */ - function () { - /** - * @param opt All of the fields will be shallow copied. - */ - function SeriesDimensionDefine(opt) { - /** - * The format of `otherDims` is: - * ```js - * { - * tooltip?: number - * label?: number - * itemName?: number - * seriesName?: number - * } - * ``` - * - * A `series.encode` can specified these fields: - * ```js - * encode: { - * // "3, 1, 5" is the index of data dimension. - * tooltip: [3, 1, 5], - * label: [0, 3], - * ... - * } - * ``` - * `otherDims` is the parse result of the `series.encode` above, like: - * ```js - * // Suppose the index of this data dimension is `3`. - * this.otherDims = { - * // `3` is at the index `0` of the `encode.tooltip` - * tooltip: 0, - * // `3` is at the index `1` of the `encode.label` - * label: 1 - * }; - * ``` - * - * This prop should never be `null`/`undefined` after initialized. - */ - this.otherDims = {}; - - if (opt != null) { - extend(this, opt); - } - } - - return SeriesDimensionDefine; - }(); - - var inner$7 = makeInner(); - var dimTypeShort = { - float: 'f', - int: 'i', - ordinal: 'o', - number: 'n', - time: 't' - }; - /** - * Represents the dimension requirement of a series. - * - * NOTICE: - * When there are too many dimensions in dataset and many series, only the used dimensions - * (i.e., used by coord sys and declared in `series.encode`) are add to `dimensionDefineList`. - * But users may query data by other unused dimension names. - * In this case, users can only query data if and only if they have defined dimension names - * via ec option, so we provide `getDimensionIndexFromSource`, which only query them from - * `source` dimensions. - */ - - var SeriesDataSchema = - /** @class */ - function () { - function SeriesDataSchema(opt) { - this.dimensions = opt.dimensions; - this._dimOmitted = opt.dimensionOmitted; - this.source = opt.source; - this._fullDimCount = opt.fullDimensionCount; - - this._updateDimOmitted(opt.dimensionOmitted); - } - - SeriesDataSchema.prototype.isDimensionOmitted = function () { - return this._dimOmitted; - }; - - SeriesDataSchema.prototype._updateDimOmitted = function (dimensionOmitted) { - this._dimOmitted = dimensionOmitted; - - if (!dimensionOmitted) { - return; - } - - if (!this._dimNameMap) { - this._dimNameMap = ensureSourceDimNameMap(this.source); - } - }; - /** - * @caution Can only be used when `dimensionOmitted: true`. - * - * Get index by user defined dimension name (i.e., not internal generate name). - * That is, get index from `dimensionsDefine`. - * If no `dimensionsDefine`, or no name get, return -1. - */ - - - SeriesDataSchema.prototype.getSourceDimensionIndex = function (dimName) { - return retrieve2(this._dimNameMap.get(dimName), -1); - }; - /** - * @caution Can only be used when `dimensionOmitted: true`. - * - * Notice: may return `null`/`undefined` if user not specify dimension names. - */ - - - SeriesDataSchema.prototype.getSourceDimension = function (dimIndex) { - var dimensionsDefine = this.source.dimensionsDefine; - - if (dimensionsDefine) { - return dimensionsDefine[dimIndex]; - } - }; - - SeriesDataSchema.prototype.makeStoreSchema = function () { - var dimCount = this._fullDimCount; - var willRetrieveDataByName = shouldRetrieveDataByName(this.source); - var makeHashStrict = !shouldOmitUnusedDimensions(dimCount); // If source don't have dimensions or series don't omit unsed dimensions. - // Generate from seriesDimList directly - - var dimHash = ''; - var dims = []; - - for (var fullDimIdx = 0, seriesDimIdx = 0; fullDimIdx < dimCount; fullDimIdx++) { - var property = void 0; - var type = void 0; - var ordinalMeta = void 0; - var seriesDimDef = this.dimensions[seriesDimIdx]; // The list has been sorted by `storeDimIndex` asc. - - if (seriesDimDef && seriesDimDef.storeDimIndex === fullDimIdx) { - property = willRetrieveDataByName ? seriesDimDef.name : null; - type = seriesDimDef.type; - ordinalMeta = seriesDimDef.ordinalMeta; - seriesDimIdx++; - } else { - var sourceDimDef = this.getSourceDimension(fullDimIdx); - - if (sourceDimDef) { - property = willRetrieveDataByName ? sourceDimDef.name : null; - type = sourceDimDef.type; - } - } - - dims.push({ - property: property, - type: type, - ordinalMeta: ordinalMeta - }); // If retrieving data by index, - // use to determine whether data can be shared. - // (Because in this case there might be no dimension name defined in dataset, but indices always exists). - // (Indices are always 0, 1, 2, ..., so we can ignore them to shorten the hash). - // Otherwise if retrieving data by property name (like `data: [{aa: 123, bb: 765}, ...]`), - // use in hash. - - if (willRetrieveDataByName && property != null // For data stack, we have make sure each series has its own dim on this store. - // So we do not add property to hash to make sure they can share this store. - && (!seriesDimDef || !seriesDimDef.isCalculationCoord)) { - dimHash += makeHashStrict // Use escape character '`' in case that property name contains '$'. - ? property.replace(/\`/g, '`1').replace(/\$/g, '`2') // For better performance, when there are large dimensions, tolerant this defects that hardly meet. - : property; - } - - dimHash += '$'; - dimHash += dimTypeShort[type] || 'f'; - - if (ordinalMeta) { - dimHash += ordinalMeta.uid; - } - - dimHash += '$'; - } // Source from endpoint(usually series) will be read differently - // when seriesLayoutBy or startIndex(which is affected by sourceHeader) are different. - // So we use this three props as key. - - - var source = this.source; - var hash = [source.seriesLayoutBy, source.startIndex, dimHash].join('$$'); - return { - dimensions: dims, - hash: hash - }; - }; - - SeriesDataSchema.prototype.makeOutputDimensionNames = function () { - var result = []; - - for (var fullDimIdx = 0, seriesDimIdx = 0; fullDimIdx < this._fullDimCount; fullDimIdx++) { - var name_1 = void 0; - var seriesDimDef = this.dimensions[seriesDimIdx]; // The list has been sorted by `storeDimIndex` asc. - - if (seriesDimDef && seriesDimDef.storeDimIndex === fullDimIdx) { - if (!seriesDimDef.isCalculationCoord) { - name_1 = seriesDimDef.name; - } - - seriesDimIdx++; - } else { - var sourceDimDef = this.getSourceDimension(fullDimIdx); - - if (sourceDimDef) { - name_1 = sourceDimDef.name; - } - } - - result.push(name_1); - } - - return result; - }; - - SeriesDataSchema.prototype.appendCalculationDimension = function (dimDef) { - this.dimensions.push(dimDef); - dimDef.isCalculationCoord = true; - this._fullDimCount++; // If append dimension on a data store, consider the store - // might be shared by different series, series dimensions not - // really map to store dimensions. - - this._updateDimOmitted(true); - }; - - return SeriesDataSchema; - }(); - - function isSeriesDataSchema(schema) { - return schema instanceof SeriesDataSchema; - } - - function createDimNameMap(dimsDef) { - var dataDimNameMap = createHashMap(); - - for (var i = 0; i < (dimsDef || []).length; i++) { - var dimDefItemRaw = dimsDef[i]; - var userDimName = isObject$2(dimDefItemRaw) ? dimDefItemRaw.name : dimDefItemRaw; - - if (userDimName != null && dataDimNameMap.get(userDimName) == null) { - dataDimNameMap.set(userDimName, i); - } - } - - return dataDimNameMap; - } - - function ensureSourceDimNameMap(source) { - var innerSource = inner$7(source); - return innerSource.dimNameMap || (innerSource.dimNameMap = createDimNameMap(source.dimensionsDefine)); - } - - function shouldOmitUnusedDimensions(dimCount) { - return dimCount > 30; - } - - var isObject = isObject$2; - var map = map$1; - var CtorInt32Array = typeof Int32Array === 'undefined' ? Array : Int32Array; // Use prefix to avoid index to be the same as otherIdList[idx], - // which will cause weird update animation. - - var ID_PREFIX = 'e\0\0'; - var INDEX_NOT_FOUND = -1; // type SeriesDimensionIndex = DimensionIndex; - - var TRANSFERABLE_PROPERTIES = ['hasItemOption', '_nameList', '_idList', '_invertedIndicesMap', '_dimSummary', 'userOutput', '_rawData', '_dimValueGetter', '_nameDimIdx', '_idDimIdx', '_nameRepeatCount']; - var CLONE_PROPERTIES = ['_approximateExtent']; // ----------------------------- - // Internal method declarations: - // ----------------------------- - - var prepareInvertedIndex; - var getId; - var getIdNameFromStore; - var normalizeDimensions; - var transferProperties; - var cloneListForMapAndSample; - var makeIdFromName; - - var SeriesData = - /** @class */ - function () { - /** - * @param dimensionsInput.dimensions - * For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...]. - * Dimensions should be concrete names like x, y, z, lng, lat, angle, radius - */ - function SeriesData(dimensionsInput, hostModel) { - this.type = 'list'; - this._dimOmitted = false; - this._nameList = []; - this._idList = []; // Models of data option is stored sparse for optimizing memory cost - // Never used yet (not used yet). - // private _optionModels: Model[] = []; - // Global visual properties after visual coding - - this._visual = {}; // Global layout properties. - - this._layout = {}; // Item visual properties after visual coding - - this._itemVisuals = []; // Item layout properties after layout - - this._itemLayouts = []; // Graphic elements - - this._graphicEls = []; // key: dim, value: extent - - this._approximateExtent = {}; - this._calculationInfo = {}; // Having detected that there is data item is non primitive type - // (in type `OptionDataItemObject`). - // Like `data: [ { value: xx, itemStyle: {...} }, ...]` - // At present it only happen in `SOURCE_FORMAT_ORIGINAL`. - - this.hasItemOption = false; // Methods that create a new list based on this list should be listed here. - // Notice that those method should `RETURN` the new list. - - this.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'minmaxDownSample', 'lttbDownSample', 'map']; // Methods that change indices of this list should be listed here. - - this.CHANGABLE_METHODS = ['filterSelf', 'selectRange']; - this.DOWNSAMPLE_METHODS = ['downSample', 'minmaxDownSample', 'lttbDownSample']; - var dimensions; - var assignStoreDimIdx = false; - - if (isSeriesDataSchema(dimensionsInput)) { - dimensions = dimensionsInput.dimensions; - this._dimOmitted = dimensionsInput.isDimensionOmitted(); - this._schema = dimensionsInput; - } else { - assignStoreDimIdx = true; - dimensions = dimensionsInput; - } - - dimensions = dimensions || ['x', 'y']; - var dimensionInfos = {}; - var dimensionNames = []; - var invertedIndicesMap = {}; - var needsHasOwn = false; - var emptyObj = {}; - - for (var i = 0; i < dimensions.length; i++) { - // Use the original dimensions[i], where other flag props may exists. - var dimInfoInput = dimensions[i]; - var dimensionInfo = isString(dimInfoInput) ? new SeriesDimensionDefine({ - name: dimInfoInput - }) : !(dimInfoInput instanceof SeriesDimensionDefine) ? new SeriesDimensionDefine(dimInfoInput) : dimInfoInput; - var dimensionName = dimensionInfo.name; - dimensionInfo.type = dimensionInfo.type || 'float'; - - if (!dimensionInfo.coordDim) { - dimensionInfo.coordDim = dimensionName; - dimensionInfo.coordDimIndex = 0; - } - - var otherDims = dimensionInfo.otherDims = dimensionInfo.otherDims || {}; - dimensionNames.push(dimensionName); - dimensionInfos[dimensionName] = dimensionInfo; - - if (emptyObj[dimensionName] != null) { - needsHasOwn = true; - } - - if (dimensionInfo.createInvertedIndices) { - invertedIndicesMap[dimensionName] = []; - } - - var dimIdx = i; - - if (isNumber(dimensionInfo.storeDimIndex)) { - dimIdx = dimensionInfo.storeDimIndex; - } - - if (otherDims.itemName === 0) { - this._nameDimIdx = dimIdx; - } - - if (otherDims.itemId === 0) { - this._idDimIdx = dimIdx; - } - - { - assert(assignStoreDimIdx || dimensionInfo.storeDimIndex >= 0); - } - - if (assignStoreDimIdx) { - dimensionInfo.storeDimIndex = i; - } - } - - this.dimensions = dimensionNames; - this._dimInfos = dimensionInfos; - - this._initGetDimensionInfo(needsHasOwn); - - this.hostModel = hostModel; - this._invertedIndicesMap = invertedIndicesMap; - - if (this._dimOmitted) { - var dimIdxToName_1 = this._dimIdxToName = createHashMap(); - each$4(dimensionNames, function (dimName) { - dimIdxToName_1.set(dimensionInfos[dimName].storeDimIndex, dimName); - }); - } - } - /** - * - * Get concrete dimension name by dimension name or dimension index. - * If input a dimension name, do not validate whether the dimension name exits. - * - * @caution - * @param dim Must make sure the dimension is `SeriesDimensionLoose`. - * Because only those dimensions will have auto-generated dimension names if not - * have a user-specified name, and other dimensions will get a return of null/undefined. - * - * @notice Because of this reason, should better use `getDimensionIndex` instead, for examples: - * ```js - * const val = data.getStore().get(data.getDimensionIndex(dim), dataIdx); - * ``` - * - * @return Concrete dim name. - */ - - - SeriesData.prototype.getDimension = function (dim) { - var dimIdx = this._recognizeDimIndex(dim); - - if (dimIdx == null) { - return dim; - } - - dimIdx = dim; - - if (!this._dimOmitted) { - return this.dimensions[dimIdx]; - } // Retrieve from series dimension definition because it probably contains - // generated dimension name (like 'x', 'y'). - - - var dimName = this._dimIdxToName.get(dimIdx); - - if (dimName != null) { - return dimName; - } - - var sourceDimDef = this._schema.getSourceDimension(dimIdx); - - if (sourceDimDef) { - return sourceDimDef.name; - } - }; - /** - * Get dimension index in data store. Return -1 if not found. - * Can be used to index value from getRawValue. - */ - - - SeriesData.prototype.getDimensionIndex = function (dim) { - var dimIdx = this._recognizeDimIndex(dim); - - if (dimIdx != null) { - return dimIdx; - } - - if (dim == null) { - return -1; - } - - var dimInfo = this._getDimInfo(dim); - - return dimInfo ? dimInfo.storeDimIndex : this._dimOmitted ? this._schema.getSourceDimensionIndex(dim) : -1; - }; - /** - * The meanings of the input parameter `dim`: - * - * + If dim is a number (e.g., `1`), it means the index of the dimension. - * For example, `getDimension(0)` will return 'x' or 'lng' or 'radius'. - * + If dim is a number-like string (e.g., `"1"`): - * + If there is the same concrete dim name defined in `series.dimensions` or `dataset.dimensions`, - * it means that concrete name. - * + If not, it will be converted to a number, which means the index of the dimension. - * (why? because of the backward compatibility. We have been tolerating number-like string in - * dimension setting, although now it seems that it is not a good idea.) - * For example, `visualMap[i].dimension: "1"` is the same meaning as `visualMap[i].dimension: 1`, - * if no dimension name is defined as `"1"`. - * + If dim is a not-number-like string, it means the concrete dim name. - * For example, it can be be default name `"x"`, `"y"`, `"z"`, `"lng"`, `"lat"`, `"angle"`, `"radius"`, - * or customized in `dimensions` property of option like `"age"`. - * - * @return recognized `DimensionIndex`. Otherwise return null/undefined (means that dim is `DimensionName`). - */ - - - SeriesData.prototype._recognizeDimIndex = function (dim) { - if (isNumber(dim) // If being a number-like string but not being defined as a dimension name. - || dim != null && !isNaN(dim) && !this._getDimInfo(dim) && (!this._dimOmitted || this._schema.getSourceDimensionIndex(dim) < 0)) { - return +dim; - } - }; - - SeriesData.prototype._getStoreDimIndex = function (dim) { - var dimIdx = this.getDimensionIndex(dim); - { - if (dimIdx == null) { - throw new Error('Unknown dimension ' + dim); - } - } - return dimIdx; - }; - /** - * Get type and calculation info of particular dimension - * @param dim - * Dimension can be concrete names like x, y, z, lng, lat, angle, radius - * Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius' - */ - - - SeriesData.prototype.getDimensionInfo = function (dim) { - // Do not clone, because there may be categories in dimInfo. - return this._getDimInfo(this.getDimension(dim)); - }; - - SeriesData.prototype._initGetDimensionInfo = function (needsHasOwn) { - var dimensionInfos = this._dimInfos; - this._getDimInfo = needsHasOwn ? function (dimName) { - return dimensionInfos.hasOwnProperty(dimName) ? dimensionInfos[dimName] : undefined; - } : function (dimName) { - return dimensionInfos[dimName]; - }; - }; - /** - * concrete dimension name list on coord. - */ - - - SeriesData.prototype.getDimensionsOnCoord = function () { - return this._dimSummary.dataDimsOnCoord.slice(); - }; - - SeriesData.prototype.mapDimension = function (coordDim, idx) { - var dimensionsSummary = this._dimSummary; - - if (idx == null) { - return dimensionsSummary.encodeFirstDimNotExtra[coordDim]; - } - - var dims = dimensionsSummary.encode[coordDim]; - return dims ? dims[idx] : null; - }; - - SeriesData.prototype.mapDimensionsAll = function (coordDim) { - var dimensionsSummary = this._dimSummary; - var dims = dimensionsSummary.encode[coordDim]; - return (dims || []).slice(); - }; - - SeriesData.prototype.getStore = function () { - return this._store; - }; - /** - * Initialize from data - * @param data source or data or data store. - * @param nameList The name of a datum is used on data diff and - * default label/tooltip. - * A name can be specified in encode.itemName, - * or dataItem.name (only for series option data), - * or provided in nameList from outside. - */ - - - SeriesData.prototype.initData = function (data, nameList, dimValueGetter) { - var _this = this; - - var store; - - if (data instanceof DataStore) { - store = data; - } - - if (!store) { - var dimensions = this.dimensions; - var provider = isSourceInstance(data) || isArrayLike(data) ? new DefaultDataProvider(data, dimensions.length) : data; - store = new DataStore(); - var dimensionInfos = map(dimensions, function (dimName) { - return { - type: _this._dimInfos[dimName].type, - property: dimName - }; - }); - store.initData(provider, dimensionInfos, dimValueGetter); - } - - this._store = store; // Reset - - this._nameList = (nameList || []).slice(); - this._idList = []; - this._nameRepeatCount = {}; - - this._doInit(0, store.count()); // Cache summary info for fast visit. See "dimensionHelper". - // Needs to be initialized after store is prepared. - - - this._dimSummary = summarizeDimensions(this, this._schema); - this.userOutput = this._dimSummary.userOutput; - }; - /** - * Caution: Can be only called on raw data (before `this._indices` created). - */ - - - SeriesData.prototype.appendData = function (data) { - var range = this._store.appendData(data); - - this._doInit(range[0], range[1]); - }; - /** - * Caution: Can be only called on raw data (before `this._indices` created). - * This method does not modify `rawData` (`dataProvider`), but only - * add values to store. - * - * The final count will be increased by `Math.max(values.length, names.length)`. - * - * @param values That is the SourceType: 'arrayRows', like - * [ - * [12, 33, 44], - * [NaN, 43, 1], - * ['-', 'asdf', 0] - * ] - * Each item is exactly corresponding to a dimension. - */ - - - SeriesData.prototype.appendValues = function (values, names) { - var _a = this._store.appendValues(values, names && names.length), - start = _a.start, - end = _a.end; - - var shouldMakeIdFromName = this._shouldMakeIdFromName(); - - this._updateOrdinalMeta(); - - if (names) { - for (var idx = start; idx < end; idx++) { - var sourceIdx = idx - start; - this._nameList[idx] = names[sourceIdx]; - - if (shouldMakeIdFromName) { - makeIdFromName(this, idx); - } - } - } - }; - - SeriesData.prototype._updateOrdinalMeta = function () { - var store = this._store; - var dimensions = this.dimensions; - - for (var i = 0; i < dimensions.length; i++) { - var dimInfo = this._dimInfos[dimensions[i]]; - - if (dimInfo.ordinalMeta) { - store.collectOrdinalMeta(dimInfo.storeDimIndex, dimInfo.ordinalMeta); - } - } - }; - - SeriesData.prototype._shouldMakeIdFromName = function () { - var provider = this._store.getProvider(); - - return this._idDimIdx == null && provider.getSource().sourceFormat !== SOURCE_FORMAT_TYPED_ARRAY && !provider.fillStorage; - }; - - SeriesData.prototype._doInit = function (start, end) { - if (start >= end) { - return; - } - - var store = this._store; - var provider = store.getProvider(); - - this._updateOrdinalMeta(); - - var nameList = this._nameList; - var idList = this._idList; - var sourceFormat = provider.getSource().sourceFormat; - var isFormatOriginal = sourceFormat === SOURCE_FORMAT_ORIGINAL; // Each data item is value - // [1, 2] - // 2 - // Bar chart, line chart which uses category axis - // only gives the 'y' value. 'x' value is the indices of category - // Use a tempValue to normalize the value to be a (x, y) value - // If dataItem is {name: ...} or {id: ...}, it has highest priority. - // This kind of ids and names are always stored `_nameList` and `_idList`. - - if (isFormatOriginal && !provider.pure) { - var sharedDataItem = []; - - for (var idx = start; idx < end; idx++) { - // NOTICE: Try not to write things into dataItem - var dataItem = provider.getItem(idx, sharedDataItem); - - if (!this.hasItemOption && isDataItemOption(dataItem)) { - this.hasItemOption = true; - } - - if (dataItem) { - var itemName = dataItem.name; - - if (nameList[idx] == null && itemName != null) { - nameList[idx] = convertOptionIdName(itemName, null); - } - - var itemId = dataItem.id; - - if (idList[idx] == null && itemId != null) { - idList[idx] = convertOptionIdName(itemId, null); - } - } - } - } - - if (this._shouldMakeIdFromName()) { - for (var idx = start; idx < end; idx++) { - makeIdFromName(this, idx); - } - } - - prepareInvertedIndex(this); - }; - /** - * PENDING: In fact currently this function is only used to short-circuit - * the calling of `scale.unionExtentFromData` when data have been filtered by modules - * like "dataZoom". `scale.unionExtentFromData` is used to calculate data extent for series on - * an axis, but if a "axis related data filter module" is used, the extent of the axis have - * been fixed and no need to calling `scale.unionExtentFromData` actually. - * But if we add "custom data filter" in future, which is not "axis related", this method may - * be still needed. - * - * Optimize for the scenario that data is filtered by a given extent. - * Consider that if data amount is more than hundreds of thousand, - * extent calculation will cost more than 10ms and the cache will - * be erased because of the filtering. - */ - - - SeriesData.prototype.getApproximateExtent = function (dim) { - return this._approximateExtent[dim] || this._store.getDataExtent(this._getStoreDimIndex(dim)); - }; - /** - * Calculate extent on a filtered data might be time consuming. - * Approximate extent is only used for: calculate extent of filtered data outside. - */ - - - SeriesData.prototype.setApproximateExtent = function (extent, dim) { - dim = this.getDimension(dim); - this._approximateExtent[dim] = extent.slice(); - }; - - SeriesData.prototype.getCalculationInfo = function (key) { - return this._calculationInfo[key]; - }; - - SeriesData.prototype.setCalculationInfo = function (key, value) { - isObject(key) ? extend(this._calculationInfo, key) : this._calculationInfo[key] = value; - }; - /** - * @return Never be null/undefined. `number` will be converted to string. Because: - * In most cases, name is used in display, where returning a string is more convenient. - * In other cases, name is used in query (see `indexOfName`), where we can keep the - * rule that name `2` equals to name `'2'`. - */ - - - SeriesData.prototype.getName = function (idx) { - var rawIndex = this.getRawIndex(idx); - var name = this._nameList[rawIndex]; - - if (name == null && this._nameDimIdx != null) { - name = getIdNameFromStore(this, this._nameDimIdx, rawIndex); - } - - if (name == null) { - name = ''; - } - - return name; - }; - - SeriesData.prototype._getCategory = function (dimIdx, idx) { - var ordinal = this._store.get(dimIdx, idx); - - var ordinalMeta = this._store.getOrdinalMeta(dimIdx); - - if (ordinalMeta) { - return ordinalMeta.categories[ordinal]; - } - - return ordinal; - }; - /** - * @return Never null/undefined. `number` will be converted to string. Because: - * In all cases having encountered at present, id is used in making diff comparison, which - * are usually based on hash map. We can keep the rule that the internal id are always string - * (treat `2` is the same as `'2'`) to make the related logic simple. - */ - - - SeriesData.prototype.getId = function (idx) { - return getId(this, this.getRawIndex(idx)); - }; - - SeriesData.prototype.count = function () { - return this._store.count(); - }; - /** - * Get value. Return NaN if idx is out of range. - * - * @notice Should better to use `data.getStore().get(dimIndex, dataIdx)` instead. - */ - - - SeriesData.prototype.get = function (dim, idx) { - var store = this._store; - var dimInfo = this._dimInfos[dim]; - - if (dimInfo) { - return store.get(dimInfo.storeDimIndex, idx); - } - }; - /** - * @notice Should better to use `data.getStore().getByRawIndex(dimIndex, dataIdx)` instead. - */ - - - SeriesData.prototype.getByRawIndex = function (dim, rawIdx) { - var store = this._store; - var dimInfo = this._dimInfos[dim]; - - if (dimInfo) { - return store.getByRawIndex(dimInfo.storeDimIndex, rawIdx); - } - }; - - SeriesData.prototype.getIndices = function () { - return this._store.getIndices(); - }; - - SeriesData.prototype.getDataExtent = function (dim) { - return this._store.getDataExtent(this._getStoreDimIndex(dim)); - }; - - SeriesData.prototype.getSum = function (dim) { - return this._store.getSum(this._getStoreDimIndex(dim)); - }; - - SeriesData.prototype.getMedian = function (dim) { - return this._store.getMedian(this._getStoreDimIndex(dim)); - }; - - SeriesData.prototype.getValues = function (dimensions, idx) { - var _this = this; - - var store = this._store; - return isArray(dimensions) ? store.getValues(map(dimensions, function (dim) { - return _this._getStoreDimIndex(dim); - }), idx) : store.getValues(dimensions); - }; - /** - * If value is NaN. Including '-' - * Only check the coord dimensions. - */ - - - SeriesData.prototype.hasValue = function (idx) { - var dataDimIndicesOnCoord = this._dimSummary.dataDimIndicesOnCoord; - - for (var i = 0, len = dataDimIndicesOnCoord.length; i < len; i++) { - // Ordinal type originally can be string or number. - // But when an ordinal type is used on coord, it can - // not be string but only number. So we can also use isNaN. - if (isNaN(this._store.get(dataDimIndicesOnCoord[i], idx))) { - return false; - } - } - - return true; - }; - /** - * Retrieve the index with given name - */ - - - SeriesData.prototype.indexOfName = function (name) { - for (var i = 0, len = this._store.count(); i < len; i++) { - if (this.getName(i) === name) { - return i; - } - } - - return -1; - }; - - SeriesData.prototype.getRawIndex = function (idx) { - return this._store.getRawIndex(idx); - }; - - SeriesData.prototype.indexOfRawIndex = function (rawIndex) { - return this._store.indexOfRawIndex(rawIndex); - }; - /** - * Only support the dimension which inverted index created. - * Do not support other cases until required. - * @param dim concrete dim - * @param value ordinal index - * @return rawIndex - */ - - - SeriesData.prototype.rawIndexOf = function (dim, value) { - var invertedIndices = dim && this._invertedIndicesMap[dim]; - { - if (!invertedIndices) { - throw new Error('Do not supported yet'); - } - } - var rawIndex = invertedIndices && invertedIndices[value]; - - if (rawIndex == null || isNaN(rawIndex)) { - return INDEX_NOT_FOUND; - } - - return rawIndex; - }; - - SeriesData.prototype.each = function (dims, cb, ctx) { - if (isFunction(dims)) { - ctx = cb; - cb = dims; - dims = []; - } // ctxCompat just for compat echarts3 - - - var fCtx = ctx || this; - var dimIndices = map(normalizeDimensions(dims), this._getStoreDimIndex, this); - - this._store.each(dimIndices, fCtx ? bind$1(cb, fCtx) : cb); - }; - - SeriesData.prototype.filterSelf = function (dims, cb, ctx) { - if (isFunction(dims)) { - ctx = cb; - cb = dims; - dims = []; - } // ctxCompat just for compat echarts3 - - - var fCtx = ctx || this; - var dimIndices = map(normalizeDimensions(dims), this._getStoreDimIndex, this); - this._store = this._store.filter(dimIndices, fCtx ? bind$1(cb, fCtx) : cb); - return this; - }; - /** - * Select data in range. (For optimization of filter) - * (Manually inline code, support 5 million data filtering in data zoom.) - */ - - - SeriesData.prototype.selectRange = function (range) { - var _this = this; - - var innerRange = {}; - var dims = keys(range); - each$4(dims, function (dim) { - var dimIdx = _this._getStoreDimIndex(dim); - - innerRange[dimIdx] = range[dim]; - }); - this._store = this._store.selectRange(innerRange); - return this; - }; - /* eslint-enable max-len */ - - - SeriesData.prototype.mapArray = function (dims, cb, ctx) { - if (isFunction(dims)) { - ctx = cb; - cb = dims; - dims = []; - } // ctxCompat just for compat echarts3 - - - ctx = ctx || this; - var result = []; - this.each(dims, function () { - result.push(cb && cb.apply(this, arguments)); - }, ctx); - return result; - }; - - SeriesData.prototype.map = function (dims, cb, ctx, ctxCompat) { - // ctxCompat just for compat echarts3 - var fCtx = ctx || ctxCompat || this; - var dimIndices = map(normalizeDimensions(dims), this._getStoreDimIndex, this); - var list = cloneListForMapAndSample(this); - list._store = this._store.map(dimIndices, fCtx ? bind$1(cb, fCtx) : cb); - return list; - }; - - SeriesData.prototype.modify = function (dims, cb, ctx, ctxCompat) { - var _this = this; // ctxCompat just for compat echarts3 - - - var fCtx = ctx || ctxCompat || this; - { - each$4(normalizeDimensions(dims), function (dim) { - var dimInfo = _this.getDimensionInfo(dim); - - if (!dimInfo.isCalculationCoord) { - console.error('Danger: only stack dimension can be modified'); - } - }); - } - var dimIndices = map(normalizeDimensions(dims), this._getStoreDimIndex, this); // If do shallow clone here, if there are too many stacked series, - // it still cost lots of memory, because `_store.dimensions` are not shared. - // We should consider there probably be shallow clone happen in each series - // in consequent filter/map. - - this._store.modify(dimIndices, fCtx ? bind$1(cb, fCtx) : cb); - }; - /** - * Large data down sampling on given dimension - * @param sampleIndex Sample index for name and id - */ - - - SeriesData.prototype.downSample = function (dimension, rate, sampleValue, sampleIndex) { - var list = cloneListForMapAndSample(this); - list._store = this._store.downSample(this._getStoreDimIndex(dimension), rate, sampleValue, sampleIndex); - return list; - }; - /** - * Large data down sampling using min-max - * @param {string} valueDimension - * @param {number} rate - */ - - - SeriesData.prototype.minmaxDownSample = function (valueDimension, rate) { - var list = cloneListForMapAndSample(this); - list._store = this._store.minmaxDownSample(this._getStoreDimIndex(valueDimension), rate); - return list; - }; - /** - * Large data down sampling using largest-triangle-three-buckets - * @param {string} valueDimension - * @param {number} targetCount - */ - - - SeriesData.prototype.lttbDownSample = function (valueDimension, rate) { - var list = cloneListForMapAndSample(this); - list._store = this._store.lttbDownSample(this._getStoreDimIndex(valueDimension), rate); - return list; - }; - - SeriesData.prototype.getRawDataItem = function (idx) { - return this._store.getRawDataItem(idx); - }; - /** - * Get model of one data item. - */ - // TODO: Type of data item - - - SeriesData.prototype.getItemModel = function (idx) { - var hostModel = this.hostModel; - var dataItem = this.getRawDataItem(idx); - return new Model(dataItem, hostModel, hostModel && hostModel.ecModel); - }; - /** - * Create a data differ - */ - - - SeriesData.prototype.diff = function (otherList) { - var thisList = this; - return new DataDiffer(otherList ? otherList.getStore().getIndices() : [], this.getStore().getIndices(), function (idx) { - return getId(otherList, idx); - }, function (idx) { - return getId(thisList, idx); - }); - }; - /** - * Get visual property. - */ - - - SeriesData.prototype.getVisual = function (key) { - var visual = this._visual; - return visual && visual[key]; - }; - - SeriesData.prototype.setVisual = function (kvObj, val) { - this._visual = this._visual || {}; - - if (isObject(kvObj)) { - extend(this._visual, kvObj); - } else { - this._visual[kvObj] = val; - } - }; - /** - * Get visual property of single data item - */ - // eslint-disable-next-line - - - SeriesData.prototype.getItemVisual = function (idx, key) { - var itemVisual = this._itemVisuals[idx]; - var val = itemVisual && itemVisual[key]; - - if (val == null) { - // Use global visual property - return this.getVisual(key); - } - - return val; - }; - /** - * If exists visual property of single data item - */ - - - SeriesData.prototype.hasItemVisual = function () { - return this._itemVisuals.length > 0; - }; - /** - * Make sure itemVisual property is unique - */ - // TODO: use key to save visual to reduce memory. - - - SeriesData.prototype.ensureUniqueItemVisual = function (idx, key) { - var itemVisuals = this._itemVisuals; - var itemVisual = itemVisuals[idx]; - - if (!itemVisual) { - itemVisual = itemVisuals[idx] = {}; - } - - var val = itemVisual[key]; - - if (val == null) { - val = this.getVisual(key); // TODO Performance? - - if (isArray(val)) { - val = val.slice(); - } else if (isObject(val)) { - val = extend({}, val); - } - - itemVisual[key] = val; - } - - return val; - }; // eslint-disable-next-line - - - SeriesData.prototype.setItemVisual = function (idx, key, value) { - var itemVisual = this._itemVisuals[idx] || {}; - this._itemVisuals[idx] = itemVisual; - - if (isObject(key)) { - extend(itemVisual, key); - } else { - itemVisual[key] = value; - } - }; - /** - * Clear itemVisuals and list visual. - */ - - - SeriesData.prototype.clearAllVisual = function () { - this._visual = {}; - this._itemVisuals = []; - }; - - SeriesData.prototype.setLayout = function (key, val) { - isObject(key) ? extend(this._layout, key) : this._layout[key] = val; - }; - /** - * Get layout property. - */ - - - SeriesData.prototype.getLayout = function (key) { - return this._layout[key]; - }; - /** - * Get layout of single data item - */ - - - SeriesData.prototype.getItemLayout = function (idx) { - return this._itemLayouts[idx]; - }; - /** - * Set layout of single data item - */ - - - SeriesData.prototype.setItemLayout = function (idx, layout, merge) { - this._itemLayouts[idx] = merge ? extend(this._itemLayouts[idx] || {}, layout) : layout; - }; - /** - * Clear all layout of single data item - */ - - - SeriesData.prototype.clearItemLayouts = function () { - this._itemLayouts.length = 0; - }; - /** - * Set graphic element relative to data. It can be set as null - */ - - - SeriesData.prototype.setItemGraphicEl = function (idx, el) { - var seriesIndex = this.hostModel && this.hostModel.seriesIndex; - setCommonECData(seriesIndex, this.dataType, idx, el); - this._graphicEls[idx] = el; - }; - - SeriesData.prototype.getItemGraphicEl = function (idx) { - return this._graphicEls[idx]; - }; - - SeriesData.prototype.eachItemGraphicEl = function (cb, context) { - each$4(this._graphicEls, function (el, idx) { - if (el) { - cb && cb.call(context, el, idx); - } - }); - }; - /** - * Shallow clone a new list except visual and layout properties, and graph elements. - * New list only change the indices. - */ - - - SeriesData.prototype.cloneShallow = function (list) { - if (!list) { - list = new SeriesData(this._schema ? this._schema : map(this.dimensions, this._getDimInfo, this), this.hostModel); - } - - transferProperties(list, this); - list._store = this._store; - return list; - }; - /** - * Wrap some method to add more feature - */ - - - SeriesData.prototype.wrapMethod = function (methodName, injectFunction) { - var originalMethod = this[methodName]; - - if (!isFunction(originalMethod)) { - return; - } - - this.__wrappedMethods = this.__wrappedMethods || []; - - this.__wrappedMethods.push(methodName); - - this[methodName] = function () { - var res = originalMethod.apply(this, arguments); - return injectFunction.apply(this, [res].concat(slice(arguments))); - }; - }; // ---------------------------------------------------------- - // A work around for internal method visiting private member. - // ---------------------------------------------------------- - - - SeriesData.internalField = function () { - prepareInvertedIndex = function (data) { - var invertedIndicesMap = data._invertedIndicesMap; - each$4(invertedIndicesMap, function (invertedIndices, dim) { - var dimInfo = data._dimInfos[dim]; // Currently, only dimensions that has ordinalMeta can create inverted indices. - - var ordinalMeta = dimInfo.ordinalMeta; - var store = data._store; - - if (ordinalMeta) { - invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array(ordinalMeta.categories.length); // The default value of TypedArray is 0. To avoid miss - // mapping to 0, we should set it as INDEX_NOT_FOUND. - - for (var i = 0; i < invertedIndices.length; i++) { - invertedIndices[i] = INDEX_NOT_FOUND; - } - - for (var i = 0; i < store.count(); i++) { - // Only support the case that all values are distinct. - invertedIndices[store.get(dimInfo.storeDimIndex, i)] = i; - } - } - }); - }; - - getIdNameFromStore = function (data, dimIdx, idx) { - return convertOptionIdName(data._getCategory(dimIdx, idx), null); - }; - /** - * @see the comment of `List['getId']`. - */ - - - getId = function (data, rawIndex) { - var id = data._idList[rawIndex]; - - if (id == null && data._idDimIdx != null) { - id = getIdNameFromStore(data, data._idDimIdx, rawIndex); - } - - if (id == null) { - id = ID_PREFIX + rawIndex; - } - - return id; - }; - - normalizeDimensions = function (dimensions) { - if (!isArray(dimensions)) { - dimensions = dimensions != null ? [dimensions] : []; - } - - return dimensions; - }; - /** - * Data in excludeDimensions is copied, otherwise transferred. - */ - - - cloneListForMapAndSample = function (original) { - var list = new SeriesData(original._schema ? original._schema : map(original.dimensions, original._getDimInfo, original), original.hostModel); // FIXME If needs stackedOn, value may already been stacked - - transferProperties(list, original); - return list; - }; - - transferProperties = function (target, source) { - each$4(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) { - if (source.hasOwnProperty(propName)) { - target[propName] = source[propName]; - } - }); - target.__wrappedMethods = source.__wrappedMethods; - each$4(CLONE_PROPERTIES, function (propName) { - target[propName] = clone$3(source[propName]); - }); - target._calculationInfo = extend({}, source._calculationInfo); - }; - - makeIdFromName = function (data, idx) { - var nameList = data._nameList; - var idList = data._idList; - var nameDimIdx = data._nameDimIdx; - var idDimIdx = data._idDimIdx; - var name = nameList[idx]; - var id = idList[idx]; - - if (name == null && nameDimIdx != null) { - nameList[idx] = name = getIdNameFromStore(data, nameDimIdx, idx); - } - - if (id == null && idDimIdx != null) { - idList[idx] = id = getIdNameFromStore(data, idDimIdx, idx); - } - - if (id == null && name != null) { - var nameRepeatCount = data._nameRepeatCount; - var nmCnt = nameRepeatCount[name] = (nameRepeatCount[name] || 0) + 1; - id = name; - - if (nmCnt > 1) { - id += '__ec__' + nmCnt; - } - - idList[idx] = id; - } - }; - }(); - - return SeriesData; - }(); - /** - * For outside usage compat (like echarts-gl are using it). - */ - - - function createDimensions(source, opt) { - return prepareSeriesDataSchema(source, opt).dimensions; - } - /** - * This method builds the relationship between: - * + "what the coord sys or series requires (see `coordDimensions`)", - * + "what the user defines (in `encode` and `dimensions`, see `opt.dimensionsDefine` and `opt.encodeDefine`)" - * + "what the data source provids (see `source`)". - * - * Some guess strategy will be adapted if user does not define something. - * If no 'value' dimension specified, the first no-named dimension will be - * named as 'value'. - * - * @return The results are always sorted by `storeDimIndex` asc. - */ - - - function prepareSeriesDataSchema( // TODO: TYPE completeDimensions type - source, opt) { - if (!isSourceInstance(source)) { - source = createSourceFromSeriesDataOption(source); - } - - opt = opt || {}; - var sysDims = opt.coordDimensions || []; - var dimsDef = opt.dimensionsDefine || source.dimensionsDefine || []; - var coordDimNameMap = createHashMap(); - var resultList = []; - var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimensionsCount); // Try to ignore unused dimensions if sharing a high dimension datastore - // 30 is an experience value. - - var omitUnusedDimensions = opt.canOmitUnusedDimensions && shouldOmitUnusedDimensions(dimCount); - var isUsingSourceDimensionsDef = dimsDef === source.dimensionsDefine; - var dataDimNameMap = isUsingSourceDimensionsDef ? ensureSourceDimNameMap(source) : createDimNameMap(dimsDef); - var encodeDef = opt.encodeDefine; - - if (!encodeDef && opt.encodeDefaulter) { - encodeDef = opt.encodeDefaulter(source, dimCount); - } - - var encodeDefMap = createHashMap(encodeDef); - var indicesMap = new CtorInt32Array$1(dimCount); - - for (var i = 0; i < indicesMap.length; i++) { - indicesMap[i] = -1; - } - - function getResultItem(dimIdx) { - var idx = indicesMap[dimIdx]; - - if (idx < 0) { - var dimDefItemRaw = dimsDef[dimIdx]; - var dimDefItem = isObject$2(dimDefItemRaw) ? dimDefItemRaw : { - name: dimDefItemRaw - }; - var resultItem = new SeriesDimensionDefine(); - var userDimName = dimDefItem.name; - - if (userDimName != null && dataDimNameMap.get(userDimName) != null) { - // Only if `series.dimensions` is defined in option - // displayName, will be set, and dimension will be displayed vertically in - // tooltip by default. - resultItem.name = resultItem.displayName = userDimName; - } - - dimDefItem.type != null && (resultItem.type = dimDefItem.type); - dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName); - var newIdx = resultList.length; - indicesMap[dimIdx] = newIdx; - resultItem.storeDimIndex = dimIdx; - resultList.push(resultItem); - return resultItem; - } - - return resultList[idx]; - } - - if (!omitUnusedDimensions) { - for (var i = 0; i < dimCount; i++) { - getResultItem(i); - } - } // Set `coordDim` and `coordDimIndex` by `encodeDefMap` and normalize `encodeDefMap`. - - - encodeDefMap.each(function (dataDimsRaw, coordDim) { - var dataDims = normalizeToArray(dataDimsRaw).slice(); // Note: It is allowed that `dataDims.length` is `0`, e.g., options is - // `{encode: {x: -1, y: 1}}`. Should not filter anything in - // this case. - - if (dataDims.length === 1 && !isString(dataDims[0]) && dataDims[0] < 0) { - encodeDefMap.set(coordDim, false); - return; - } - - var validDataDims = encodeDefMap.set(coordDim, []); - each$4(dataDims, function (resultDimIdxOrName, idx) { - // The input resultDimIdx can be dim name or index. - var resultDimIdx = isString(resultDimIdxOrName) ? dataDimNameMap.get(resultDimIdxOrName) : resultDimIdxOrName; - - if (resultDimIdx != null && resultDimIdx < dimCount) { - validDataDims[idx] = resultDimIdx; - applyDim(getResultItem(resultDimIdx), coordDim, idx); - } - }); - }); // Apply templates and default order from `sysDims`. - - var availDimIdx = 0; - each$4(sysDims, function (sysDimItemRaw) { - var coordDim; - var sysDimItemDimsDef; - var sysDimItemOtherDims; - var sysDimItem; - - if (isString(sysDimItemRaw)) { - coordDim = sysDimItemRaw; - sysDimItem = {}; - } else { - sysDimItem = sysDimItemRaw; - coordDim = sysDimItem.name; - var ordinalMeta = sysDimItem.ordinalMeta; - sysDimItem.ordinalMeta = null; - sysDimItem = extend({}, sysDimItem); - sysDimItem.ordinalMeta = ordinalMeta; // `coordDimIndex` should not be set directly. - - sysDimItemDimsDef = sysDimItem.dimsDef; - sysDimItemOtherDims = sysDimItem.otherDims; - sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex = sysDimItem.dimsDef = sysDimItem.otherDims = null; - } - - var dataDims = encodeDefMap.get(coordDim); // negative resultDimIdx means no need to mapping. - - if (dataDims === false) { - return; - } - - dataDims = normalizeToArray(dataDims); // dimensions provides default dim sequences. - - if (!dataDims.length) { - for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) { - while (availDimIdx < dimCount && getResultItem(availDimIdx).coordDim != null) { - availDimIdx++; - } - - availDimIdx < dimCount && dataDims.push(availDimIdx++); - } - } // Apply templates. - - - each$4(dataDims, function (resultDimIdx, coordDimIndex) { - var resultItem = getResultItem(resultDimIdx); // Coordinate system has a higher priority on dim type than source. - - if (isUsingSourceDimensionsDef && sysDimItem.type != null) { - resultItem.type = sysDimItem.type; - } - - applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex); - - if (resultItem.name == null && sysDimItemDimsDef) { - var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex]; - !isObject$2(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = { - name: sysDimItemDimsDefItem - }); - resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name; - resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip; - } // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}} - - - sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims); - }); - }); - - function applyDim(resultItem, coordDim, coordDimIndex) { - if (VISUAL_DIMENSIONS.get(coordDim) != null) { - resultItem.otherDims[coordDim] = coordDimIndex; - } else { - resultItem.coordDim = coordDim; - resultItem.coordDimIndex = coordDimIndex; - coordDimNameMap.set(coordDim, true); - } - } // Make sure the first extra dim is 'value'. - - - var generateCoord = opt.generateCoord; - var generateCoordCount = opt.generateCoordCount; - var fromZero = generateCoordCount != null; - generateCoordCount = generateCoord ? generateCoordCount || 1 : 0; - var extra = generateCoord || 'value'; - - function ifNoNameFillWithCoordName(resultItem) { - if (resultItem.name == null) { - // Duplication will be removed in the next step. - resultItem.name = resultItem.coordDim; - } - } // Set dim `name` and other `coordDim` and other props. - - - if (!omitUnusedDimensions) { - for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) { - var resultItem = getResultItem(resultDimIdx); - var coordDim = resultItem.coordDim; - - if (coordDim == null) { - // TODO no need to generate coordDim for isExtraCoord? - resultItem.coordDim = genCoordDimName(extra, coordDimNameMap, fromZero); - resultItem.coordDimIndex = 0; // Series specified generateCoord is using out. - - if (!generateCoord || generateCoordCount <= 0) { - resultItem.isExtraCoord = true; - } - - generateCoordCount--; - } - - ifNoNameFillWithCoordName(resultItem); - - if (resultItem.type == null && (guessOrdinal(source, resultDimIdx) === BE_ORDINAL.Must // Consider the case: - // { - // dataset: {source: [ - // ['2001', 123], - // ['2002', 456], - // ... - // ['The others', 987], - // ]}, - // series: {type: 'pie'} - // } - // The first column should better be treated as a "ordinal" although it - // might not be detected as an "ordinal" by `guessOrdinal`. - || resultItem.isExtraCoord && (resultItem.otherDims.itemName != null || resultItem.otherDims.seriesName != null))) { - resultItem.type = 'ordinal'; - } - } - } else { - each$4(resultList, function (resultItem) { - // PENDING: guessOrdinal or let user specify type: 'ordinal' manually? - ifNoNameFillWithCoordName(resultItem); - }); // Sort dimensions: there are some rule that use the last dim as label, - // and for some latter travel process easier. - - resultList.sort(function (item0, item1) { - return item0.storeDimIndex - item1.storeDimIndex; - }); - } - - removeDuplication(resultList); - return new SeriesDataSchema({ - source: source, - dimensions: resultList, - fullDimensionCount: dimCount, - dimensionOmitted: omitUnusedDimensions - }); - } - - function removeDuplication(result) { - var duplicationMap = createHashMap(); - - for (var i = 0; i < result.length; i++) { - var dim = result[i]; - var dimOriginalName = dim.name; - var count = duplicationMap.get(dimOriginalName) || 0; - - if (count > 0) { - // Starts from 0. - dim.name = dimOriginalName + (count - 1); - } - - count++; - duplicationMap.set(dimOriginalName, count); - } - } // ??? TODO - // Originally detect dimCount by data[0]. Should we - // optimize it to only by sysDims and dimensions and encode. - // So only necessary dims will be initialized. - // But - // (1) custom series should be considered. where other dims - // may be visited. - // (2) sometimes user need to calculate bubble size or use visualMap - // on other dimensions besides coordSys needed. - // So, dims that is not used by system, should be shared in data store? - - - function getDimCount(source, sysDims, dimsDef, optDimCount) { - // Note that the result dimCount should not small than columns count - // of data, otherwise `dataDimNameMap` checking will be incorrect. - var dimCount = Math.max(source.dimensionsDetectedCount || 1, sysDims.length, dimsDef.length, optDimCount || 0); - each$4(sysDims, function (sysDimItem) { - var sysDimItemDimsDef; - - if (isObject$2(sysDimItem) && (sysDimItemDimsDef = sysDimItem.dimsDef)) { - dimCount = Math.max(dimCount, sysDimItemDimsDef.length); - } - }); - return dimCount; - } - - function genCoordDimName(name, map, fromZero) { - if (fromZero || map.hasKey(name)) { - var i = 0; - - while (map.hasKey(name + i)) { - i++; - } - - name += i; - } - - map.set(name, true); - return name; - } - /** - * @class - * For example: - * { - * coordSysName: 'cartesian2d', - * coordSysDims: ['x', 'y', ...], - * axisMap: HashMap({ - * x: xAxisModel, - * y: yAxisModel - * }), - * categoryAxisMap: HashMap({ - * x: xAxisModel, - * y: undefined - * }), - * // The index of the first category axis in `coordSysDims`. - * // `null/undefined` means no category axis exists. - * firstCategoryDimIndex: 1, - * // To replace user specified encode. - * } - */ - - - var CoordSysInfo = - /** @class */ - function () { - function CoordSysInfo(coordSysName) { - this.coordSysDims = []; - this.axisMap = createHashMap(); - this.categoryAxisMap = createHashMap(); - this.coordSysName = coordSysName; - } - - return CoordSysInfo; - }(); - - function getCoordSysInfoBySeries(seriesModel) { - var coordSysName = seriesModel.get('coordinateSystem'); - var result = new CoordSysInfo(coordSysName); - var fetch = fetchers[coordSysName]; - - if (fetch) { - fetch(seriesModel, result, result.axisMap, result.categoryAxisMap); - return result; - } - } // TODO: refactor them to static member of each coord sys, rather than hard code here. - - - var fetchers = { - cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) { - var xAxisModel = seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0]; - var yAxisModel = seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[0]; - { - if (!xAxisModel) { - throw new Error('xAxis "' + retrieve(seriesModel.get('xAxisIndex'), seriesModel.get('xAxisId'), 0) + '" not found'); - } - - if (!yAxisModel) { - throw new Error('yAxis "' + retrieve(seriesModel.get('xAxisIndex'), seriesModel.get('yAxisId'), 0) + '" not found'); - } - } - result.coordSysDims = ['x', 'y']; - axisMap.set('x', xAxisModel); - axisMap.set('y', yAxisModel); - - if (isCategory(xAxisModel)) { - categoryAxisMap.set('x', xAxisModel); - result.firstCategoryDimIndex = 0; - } - - if (isCategory(yAxisModel)) { - categoryAxisMap.set('y', yAxisModel); - result.firstCategoryDimIndex == null && (result.firstCategoryDimIndex = 1); - } - }, - singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) { - var singleAxisModel = seriesModel.getReferringComponents('singleAxis', SINGLE_REFERRING).models[0]; - { - if (!singleAxisModel) { - throw new Error('singleAxis should be specified.'); - } - } - result.coordSysDims = ['single']; - axisMap.set('single', singleAxisModel); - - if (isCategory(singleAxisModel)) { - categoryAxisMap.set('single', singleAxisModel); - result.firstCategoryDimIndex = 0; - } - }, - polar: function (seriesModel, result, axisMap, categoryAxisMap) { - var polarModel = seriesModel.getReferringComponents('polar', SINGLE_REFERRING).models[0]; - var radiusAxisModel = polarModel.findAxisModel('radiusAxis'); - var angleAxisModel = polarModel.findAxisModel('angleAxis'); - { - if (!angleAxisModel) { - throw new Error('angleAxis option not found'); - } - - if (!radiusAxisModel) { - throw new Error('radiusAxis option not found'); - } - } - result.coordSysDims = ['radius', 'angle']; - axisMap.set('radius', radiusAxisModel); - axisMap.set('angle', angleAxisModel); - - if (isCategory(radiusAxisModel)) { - categoryAxisMap.set('radius', radiusAxisModel); - result.firstCategoryDimIndex = 0; - } - - if (isCategory(angleAxisModel)) { - categoryAxisMap.set('angle', angleAxisModel); - result.firstCategoryDimIndex == null && (result.firstCategoryDimIndex = 1); - } - }, - geo: function (seriesModel, result, axisMap, categoryAxisMap) { - result.coordSysDims = ['lng', 'lat']; - }, - parallel: function (seriesModel, result, axisMap, categoryAxisMap) { - var ecModel = seriesModel.ecModel; - var parallelModel = ecModel.getComponent('parallel', seriesModel.get('parallelIndex')); - var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice(); - each$4(parallelModel.parallelAxisIndex, function (axisIndex, index) { - var axisModel = ecModel.getComponent('parallelAxis', axisIndex); - var axisDim = coordSysDims[index]; - axisMap.set(axisDim, axisModel); - - if (isCategory(axisModel)) { - categoryAxisMap.set(axisDim, axisModel); - - if (result.firstCategoryDimIndex == null) { - result.firstCategoryDimIndex = index; - } - } - }); - }, - matrix: function (seriesModel, result, axisMap, categoryAxisMap) { - var matrixModel = seriesModel.getReferringComponents('matrix', SINGLE_REFERRING).models[0]; - { - if (!matrixModel) { - throw new Error('matrix coordinate system should be specified.'); - } - } - result.coordSysDims = ['x', 'y']; - var xModel = matrixModel.getDimensionModel('x'); - var yModel = matrixModel.getDimensionModel('y'); - axisMap.set('x', xModel); - axisMap.set('y', yModel); - categoryAxisMap.set('x', xModel); - categoryAxisMap.set('y', yModel); - } - }; - - function isCategory(axisModel) { - return axisModel.get('type') === 'category'; - } - /** - * Note that it is too complicated to support 3d stack by value - * (have to create two-dimension inverted index), so in 3d case - * we just support that stacked by index. - * - * @param seriesModel - * @param dimensionsInput The same as the input of . - * The input will be modified. - * @param opt - * @param opt.stackedCoordDimension Specify a coord dimension if needed. - * @param opt.byIndex=false - * @return calculationInfo - * { - * stackedDimension: string - * stackedByDimension: string - * isStackedByIndex: boolean - * stackedOverDimension: string - * stackResultDimension: string - * } - */ - - - function enableDataStack(seriesModel, dimensionsInput, opt) { - opt = opt || {}; - var byIndex = opt.byIndex; - var stackedCoordDimension = opt.stackedCoordDimension; - var dimensionDefineList; - var schema; - var store; - - if (isLegacyDimensionsInput(dimensionsInput)) { - dimensionDefineList = dimensionsInput; - } else { - schema = dimensionsInput.schema; - dimensionDefineList = schema.dimensions; - store = dimensionsInput.store; - } // Compatibal: when `stack` is set as '', do not stack. - - - var mayStack = !!(seriesModel && seriesModel.get('stack')); - var stackedByDimInfo; - var stackedDimInfo; - var stackResultDimension; - var stackedOverDimension; - each$4(dimensionDefineList, function (dimensionInfo, index) { - if (isString(dimensionInfo)) { - dimensionDefineList[index] = dimensionInfo = { - name: dimensionInfo - }; - } - - if (mayStack && !dimensionInfo.isExtraCoord) { - // Find the first ordinal dimension as the stackedByDimInfo. - if (!byIndex && !stackedByDimInfo && dimensionInfo.ordinalMeta) { - stackedByDimInfo = dimensionInfo; - } // Find the first stackable dimension as the stackedDimInfo. - - - if (!stackedDimInfo && dimensionInfo.type !== 'ordinal' && dimensionInfo.type !== 'time' && (!stackedCoordDimension || stackedCoordDimension === dimensionInfo.coordDim)) { - stackedDimInfo = dimensionInfo; - } - } - }); - - if (stackedDimInfo && !byIndex && !stackedByDimInfo) { - // Compatible with previous design, value axis (time axis) only stack by index. - // It may make sense if the user provides elaborately constructed data. - byIndex = true; - } // Add stack dimension, they can be both calculated by coordinate system in `unionExtent`. - // That put stack logic in List is for using conveniently in echarts extensions, but it - // might not be a good way. - - - if (stackedDimInfo) { - // Use a weird name that not duplicated with other names. - // Also need to use seriesModel.id as postfix because different - // series may share same data store. The stack dimension needs to be distinguished. - stackResultDimension = '__\0ecstackresult_' + seriesModel.id; - stackedOverDimension = '__\0ecstackedover_' + seriesModel.id; // Create inverted index to fast query index by value. - - if (stackedByDimInfo) { - stackedByDimInfo.createInvertedIndices = true; - } - - var stackedDimCoordDim_1 = stackedDimInfo.coordDim; - var stackedDimType = stackedDimInfo.type; - var stackedDimCoordIndex_1 = 0; - each$4(dimensionDefineList, function (dimensionInfo) { - if (dimensionInfo.coordDim === stackedDimCoordDim_1) { - stackedDimCoordIndex_1++; - } - }); - var stackedOverDimensionDefine = { - name: stackResultDimension, - coordDim: stackedDimCoordDim_1, - coordDimIndex: stackedDimCoordIndex_1, - type: stackedDimType, - isExtraCoord: true, - isCalculationCoord: true, - storeDimIndex: dimensionDefineList.length - }; - var stackResultDimensionDefine = { - name: stackedOverDimension, - // This dimension contains stack base (generally, 0), so do not set it as - // `stackedDimCoordDim` to avoid extent calculation, consider log scale. - coordDim: stackedOverDimension, - coordDimIndex: stackedDimCoordIndex_1 + 1, - type: stackedDimType, - isExtraCoord: true, - isCalculationCoord: true, - storeDimIndex: dimensionDefineList.length + 1 - }; - - if (schema) { - if (store) { - stackedOverDimensionDefine.storeDimIndex = store.ensureCalculationDimension(stackedOverDimension, stackedDimType); - stackResultDimensionDefine.storeDimIndex = store.ensureCalculationDimension(stackResultDimension, stackedDimType); - } - - schema.appendCalculationDimension(stackedOverDimensionDefine); - schema.appendCalculationDimension(stackResultDimensionDefine); - } else { - dimensionDefineList.push(stackedOverDimensionDefine); - dimensionDefineList.push(stackResultDimensionDefine); - } - } - - return { - stackedDimension: stackedDimInfo && stackedDimInfo.name, - stackedByDimension: stackedByDimInfo && stackedByDimInfo.name, - isStackedByIndex: byIndex, - stackedOverDimension: stackedOverDimension, - stackResultDimension: stackResultDimension - }; - } - - function isLegacyDimensionsInput(dimensionsInput) { - return !isSeriesDataSchema(dimensionsInput.schema); - } - - function isDimensionStacked(data, stackedDim) { - // Each single series only maps to one pair of axis. So we do not need to - // check stackByDim, whatever stacked by a dimension or stacked by index. - return !!stackedDim && stackedDim === data.getCalculationInfo('stackedDimension'); - } - - function getStackedDimension(data, targetDim) { - return isDimensionStacked(data, targetDim) ? data.getCalculationInfo('stackResultDimension') : targetDim; - } - - function getCoordSysDimDefs(seriesModel, coordSysInfo) { - var coordSysName = seriesModel.get('coordinateSystem'); - var registeredCoordSys = CoordinateSystemManager.get(coordSysName); - var coordSysDimDefs; - - if (coordSysInfo && coordSysInfo.coordSysDims) { - coordSysDimDefs = map$1(coordSysInfo.coordSysDims, function (dim) { - var dimInfo = { - name: dim - }; - var axisModel = coordSysInfo.axisMap.get(dim); - - if (axisModel) { - var axisType = axisModel.get('type'); - dimInfo.type = getDimensionTypeByAxis(axisType); - } - - return dimInfo; - }); - } - - if (!coordSysDimDefs) { - // Get dimensions from registered coordinate system - coordSysDimDefs = registeredCoordSys && (registeredCoordSys.getDimensionsInfo ? registeredCoordSys.getDimensionsInfo() : registeredCoordSys.dimensions.slice()) || ['x', 'y']; - } - - return coordSysDimDefs; - } - - function injectOrdinalMeta(dimInfoList, createInvertedIndices, coordSysInfo) { - var firstCategoryDimIndex; - var hasNameEncode; - coordSysInfo && each$4(dimInfoList, function (dimInfo, dimIndex) { - var coordDim = dimInfo.coordDim; - var categoryAxisModel = coordSysInfo.categoryAxisMap.get(coordDim); - - if (categoryAxisModel) { - if (firstCategoryDimIndex == null) { - firstCategoryDimIndex = dimIndex; - } - - dimInfo.ordinalMeta = categoryAxisModel.getOrdinalMeta(); - - if (createInvertedIndices) { - dimInfo.createInvertedIndices = true; - } - } - - if (dimInfo.otherDims.itemName != null) { - hasNameEncode = true; - } - }); - - if (!hasNameEncode && firstCategoryDimIndex != null) { - dimInfoList[firstCategoryDimIndex].otherDims.itemName = 0; - } - - return firstCategoryDimIndex; - } - /** - * Caution: there are side effects to `sourceManager` in this method. - * Should better only be called in `Series['getInitialData']`. - */ - - - function createSeriesData(sourceRaw, seriesModel, opt) { - opt = opt || {}; - var sourceManager = seriesModel.getSourceManager(); - var source; - var isOriginalSource = false; - - if (sourceRaw) { - isOriginalSource = true; - source = createSourceFromSeriesDataOption(sourceRaw); - } else { - source = sourceManager.getSource(); // Is series.data. not dataset. - - isOriginalSource = source.sourceFormat === SOURCE_FORMAT_ORIGINAL; - } - - var coordSysInfo = getCoordSysInfoBySeries(seriesModel); - var coordSysDimDefs = getCoordSysDimDefs(seriesModel, coordSysInfo); - var useEncodeDefaulter = opt.useEncodeDefaulter; - var encodeDefaulter = isFunction(useEncodeDefaulter) ? useEncodeDefaulter : useEncodeDefaulter ? curry$1(makeSeriesEncodeForAxisCoordSys, coordSysDimDefs, seriesModel) : null; - var createDimensionOptions = { - coordDimensions: coordSysDimDefs, - generateCoord: opt.generateCoord, - encodeDefine: seriesModel.getEncode(), - encodeDefaulter: encodeDefaulter, - canOmitUnusedDimensions: !isOriginalSource - }; - var schema = prepareSeriesDataSchema(source, createDimensionOptions); - var firstCategoryDimIndex = injectOrdinalMeta(schema.dimensions, opt.createInvertedIndices, coordSysInfo); - var store = !isOriginalSource ? sourceManager.getSharedDataStore(schema) : null; - var stackCalculationInfo = enableDataStack(seriesModel, { - schema: schema, - store: store - }); - var data = new SeriesData(schema, seriesModel); - data.setCalculationInfo(stackCalculationInfo); - var dimValueGetter = firstCategoryDimIndex != null && isNeedCompleteOrdinalData(source) - /** - * This serves this case: - * var echarts_option = { - * xAxis: { data: ['a', 'b', 'c'] }, - * yAxis: {} - * series: { data: [555, 666, 777] } - * }; - * The `series.data` is completed to: - * [[0, 555], [1, 666], [2, 777]] - */ - ? function (itemOpt, dimName, dataIndex, dimIndex) { - // Use dataIndex as ordinal value in categoryAxis - return dimIndex === firstCategoryDimIndex ? dataIndex : this.defaultDimValueGetter(itemOpt, dimName, dataIndex, dimIndex); - } : null; - data.hasItemOption = false; - data.initData( // Try to reuse the data store in sourceManager if using dataset. - isOriginalSource ? source : store, null, dimValueGetter); - return data; - } - - function isNeedCompleteOrdinalData(source) { - if (source.sourceFormat === SOURCE_FORMAT_ORIGINAL) { - var sampleItem = firstDataNotNull(source.data || []); - return !isArray(getDataItemValue(sampleItem)); - } - } - - function firstDataNotNull(arr) { - var i = 0; - - while (i < arr.length && arr[i] == null) { - i++; - } - - return arr[i]; - } - - function isValueNice(val) { - var exp10 = Math.pow(10, quantityExponent(Math.abs(val))); - var f = Math.abs(val / exp10); - return f === 0 || f === 1 || f === 2 || f === 3 || f === 5; - } - - function isIntervalOrLogScale(scale) { - return scale.type === 'interval' || scale.type === 'log'; - } - /** - * @param extent Both extent[0] and extent[1] should be valid number. - * Should be extent[0] < extent[1]. - * @param splitNumber splitNumber should be >= 1. - */ - - - function intervalScaleNiceTicks(extent, spanWithBreaks, splitNumber, minInterval, maxInterval) { - var result = {}; - var interval = result.interval = nice(spanWithBreaks / splitNumber, true); - - if (minInterval != null && interval < minInterval) { - interval = result.interval = minInterval; - } - - if (maxInterval != null && interval > maxInterval) { - interval = result.interval = maxInterval; - } // Tow more digital for tick. - - - var precision = result.intervalPrecision = getIntervalPrecision(interval); // Niced extent inside original extent - - var niceTickExtent = result.niceTickExtent = [round$1(Math.ceil(extent[0] / interval) * interval, precision), round$1(Math.floor(extent[1] / interval) * interval, precision)]; - fixExtent(niceTickExtent, extent); - return result; - } - - function increaseInterval(interval) { - var exp10 = Math.pow(10, quantityExponent(interval)); // Increase interval - - var f = interval / exp10; - - if (!f) { - f = 1; - } else if (f === 2) { - f = 3; - } else if (f === 3) { - f = 5; - } else { - // f is 1 or 5 - f *= 2; - } - - return round$1(f * exp10); - } - /** - * @return interval precision - */ - - - function getIntervalPrecision(interval) { - // Tow more digital for tick. - return getPrecision(interval) + 2; - } - - function clamp(niceTickExtent, idx, extent) { - niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]); - } // In some cases (e.g., splitNumber is 1), niceTickExtent may be out of extent. - - - function fixExtent(niceTickExtent, extent) { - !isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]); - !isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]); - clamp(niceTickExtent, 0, extent); - clamp(niceTickExtent, 1, extent); - - if (niceTickExtent[0] > niceTickExtent[1]) { - niceTickExtent[0] = niceTickExtent[1]; - } - } - - function contain$1(val, extent) { - return val >= extent[0] && val <= extent[1]; - } - - var ScaleCalculator = - /** @class */ - function () { - function ScaleCalculator() { - this.normalize = normalize; - this.scale = scale; - } - - ScaleCalculator.prototype.updateMethods = function (brkCtx) { - if (brkCtx.hasBreaks()) { - this.normalize = bind$1(brkCtx.normalize, brkCtx); - this.scale = bind$1(brkCtx.scale, brkCtx); - } else { - this.normalize = normalize; - this.scale = scale; - } - }; - - return ScaleCalculator; - }(); - - function normalize(val, extent) { - if (extent[1] === extent[0]) { - return 0.5; - } - - return (val - extent[0]) / (extent[1] - extent[0]); - } - - function scale(val, extent) { - return val * (extent[1] - extent[0]) + extent[0]; - } - - function logTransform(base, extent, noClampNegative) { - var loggedBase = Math.log(base); - return [// log(negative) is NaN, so safe guard here. - // PENDING: But even getting a -Infinity still does not make sense in extent. - // Just keep it as is, getting a NaN to make some previous cases works by coincidence. - Math.log(noClampNegative ? extent[0] : Math.max(0, extent[0])) / loggedBase, Math.log(noClampNegative ? extent[1] : Math.max(0, extent[1])) / loggedBase]; - } - - var Scale = - /** @class */ - function () { - function Scale(setting) { - this._calculator = new ScaleCalculator(); - this._setting = setting || {}; - this._extent = [Infinity, -Infinity]; - } - - Scale.prototype.getSetting = function (name) { - return this._setting[name]; - }; - /** - * [CAVEAT]: It should not be overridden! - */ - - - Scale.prototype._innerUnionExtent = function (other) { - var extent = this._extent; // Considered that number could be NaN and should not write into the extent. - - this._innerSetExtent(other[0] < extent[0] ? other[0] : extent[0], other[1] > extent[1] ? other[1] : extent[1]); - }; - /** - * Set extent from data - */ - - - Scale.prototype.unionExtentFromData = function (data, dim) { - this._innerUnionExtent(data.getApproximateExtent(dim)); - }; - /** - * Get a new slice of extent. - * Extent is always in increase order. - */ - - - Scale.prototype.getExtent = function () { - return this._extent.slice(); - }; - - Scale.prototype.setExtent = function (start, end) { - this._innerSetExtent(start, end); - }; - /** - * [CAVEAT]: It should not be overridden! - */ - - - Scale.prototype._innerSetExtent = function (start, end) { - var thisExtent = this._extent; - - if (!isNaN(start)) { - thisExtent[0] = start; - } - - if (!isNaN(end)) { - thisExtent[1] = end; - } - - this._brkCtx && this._brkCtx.update(thisExtent); - }; - /** - * Prerequisite: Scale#parse is ready. - */ - - - Scale.prototype.setBreaksFromOption = function (breakOptionList) {}; - /** - * [CAVEAT]: It should not be overridden! - */ - - - Scale.prototype._innerSetBreak = function (parsed) { - if (this._brkCtx) { - this._brkCtx.setBreaks(parsed); - - this._calculator.updateMethods(this._brkCtx); - - this._brkCtx.update(this._extent); - } - }; - /** - * [CAVEAT]: It should not be overridden! - */ - - - Scale.prototype._innerGetBreaks = function () { - return this._brkCtx ? this._brkCtx.breaks : []; - }; - /** - * Do not expose the internal `_breaks` unless necessary. - */ - - - Scale.prototype.hasBreaks = function () { - return this._brkCtx ? this._brkCtx.hasBreaks() : false; - }; - - Scale.prototype._getExtentSpanWithBreaks = function () { - return this._brkCtx && this._brkCtx.hasBreaks() ? this._brkCtx.getExtentSpan() : this._extent[1] - this._extent[0]; - }; - /** - * If value is in extent range - */ - - - Scale.prototype.isInExtentRange = function (value) { - return this._extent[0] <= value && this._extent[1] >= value; - }; - /** - * When axis extent depends on data and no data exists, - * axis ticks should not be drawn, which is named 'blank'. - */ - - - Scale.prototype.isBlank = function () { - return this._isBlank; - }; - /** - * When axis extent depends on data and no data exists, - * axis ticks should not be drawn, which is named 'blank'. - */ - - - Scale.prototype.setBlank = function (isBlank) { - this._isBlank = isBlank; - }; - - return Scale; - }(); - - enableClassManagement(Scale); - var uidBase = 0; - - var OrdinalMeta = - /** @class */ - function () { - /** - * PENDING - Regarding forcibly converting to string: - * In the early days, the underlying hash map impl used JS plain object and converted the key to - * string; later in https://github.com/ecomfe/zrender/pull/966 it was changed to a JS Map (in supported - * platforms), which does not require string keys. But consider any input that `scale/Ordinal['parse']` - * is involved, a number input represents an `OrdinalNumber` (i.e., an index), and affect the query - * behavior: - * - If forcbily converting to string: - * pros: users can use numeric string (such as, '123') to query the raw data (123), tho it's probably - * still confusing. - * cons: NaN/null/undefined in data will be equals to 'NaN'/'null'/'undefined', if simply using - * `val + ''` to convert them, like currently `getName` does. - * - Otherwise: - * pros: see NaN/null/undefined case above. - * cons: users cannot query the raw data (123) any more. - * There are two inconsistent behaviors in the current impl: - * - Force conversion is applied on the case `xAxis{data: ['aaa', 'bbb', ...]}`, - * but no conversion applied to the case `xAxis{data: [{value: 'aaa'}, ...]}` and - * the case `dataset: {source: [['aaa', 123], ['bbb', 234], ...]}`. - * - behaves differently according to whether JS Map is supported (the polyfill is simply using JS - * plain object) (tho it seems rare platform that do not support it). - * Since there's no sufficient good solution to offset cost of the breaking change, we preserve the - * current behavior, until real issues is reported. - */ - function OrdinalMeta(opt) { - this.categories = opt.categories || []; - this._needCollect = opt.needCollect; - this._deduplication = opt.deduplication; - this.uid = ++uidBase; - this._onCollect = opt.onCollect; - } - - OrdinalMeta.createByAxisModel = function (axisModel) { - var option = axisModel.option; - var data = option.data; - var categories = data && map$1(data, getName); - return new OrdinalMeta({ - categories: categories, - needCollect: !categories, - // deduplication is default in axis. - deduplication: option.dedplication !== false - }); - }; - - OrdinalMeta.prototype.getOrdinal = function (category) { - return this._getOrCreateMap().get(category); - }; - /** - * @return The ordinal. If not found, return NaN. - */ - - - OrdinalMeta.prototype.parseAndCollect = function (category) { - var index; - var needCollect = this._needCollect; // The value of category dim can be the index of the given category set. - // This feature is only supported when !needCollect, because we should - // consider a common case: a value is 2017, which is a number but is - // expected to be tread as a category. This case usually happen in dataset, - // where it happent to be no need of the index feature. - - if (!isString(category) && !needCollect) { - return category; - } // Optimize for the scenario: - // category is ['2012-01-01', '2012-01-02', ...], where the input - // data has been ensured not duplicate and is large data. - // Notice, if a dataset dimension provide categroies, usually echarts - // should remove duplication except user tell echarts dont do that - // (set axis.deduplication = false), because echarts do not know whether - // the values in the category dimension has duplication (consider the - // parallel-aqi example) - - - if (needCollect && !this._deduplication) { - index = this.categories.length; - this.categories[index] = category; - this._onCollect && this._onCollect(category, index); - return index; - } - - var map = this._getOrCreateMap(); - - index = map.get(category); - - if (index == null) { - if (needCollect) { - index = this.categories.length; - this.categories[index] = category; - map.set(category, index); - this._onCollect && this._onCollect(category, index); - } else { - index = NaN; - } - } - - return index; - }; // Consider big data, do not create map until needed. - - - OrdinalMeta.prototype._getOrCreateMap = function () { - return this._map || (this._map = createHashMap(this.categories)); - }; - - return OrdinalMeta; - }(); - - function getName(obj) { - if (isObject$2(obj) && obj.value != null) { - return obj.value; - } else { - return obj + ''; - } - } - - var OrdinalScale = - /** @class */ - function (_super) { - __extends(OrdinalScale, _super); - - function OrdinalScale(setting) { - var _this = _super.call(this, setting) || this; - - _this.type = 'ordinal'; - - var ordinalMeta = _this.getSetting('ordinalMeta'); // Caution: Should not use instanceof, consider ec-extensions using - // import approach to get OrdinalMeta class. - - - if (!ordinalMeta) { - ordinalMeta = new OrdinalMeta({}); - } - - if (isArray(ordinalMeta)) { - ordinalMeta = new OrdinalMeta({ - categories: map$1(ordinalMeta, function (item) { - return isObject$2(item) ? item.value : item; - }) - }); - } - - _this._ordinalMeta = ordinalMeta; - _this._extent = _this.getSetting('extent') || [0, ordinalMeta.categories.length - 1]; - return _this; - } - - OrdinalScale.prototype.parse = function (val) { - // Caution: Math.round(null) will return `0` rather than `NaN` - if (val == null) { - return NaN; - } - - return isString(val) ? this._ordinalMeta.getOrdinal(val) // val might be float. - : Math.round(val); - }; - - OrdinalScale.prototype.contain = function (val) { - return contain$1(val, this._extent) && val >= 0 && val < this._ordinalMeta.categories.length; - }; - /** - * Normalize given rank or name to linear [0, 1] - * @param val raw ordinal number. - * @return normalized value in [0, 1]. - */ - - - OrdinalScale.prototype.normalize = function (val) { - val = this._getTickNumber(val); - return this._calculator.normalize(val, this._extent); - }; - /** - * @param val normalized value in [0, 1]. - * @return raw ordinal number. - */ - - - OrdinalScale.prototype.scale = function (val) { - val = Math.round(this._calculator.scale(val, this._extent)); - return this.getRawOrdinalNumber(val); - }; - - OrdinalScale.prototype.getTicks = function () { - var ticks = []; - var extent = this._extent; - var rank = extent[0]; - - while (rank <= extent[1]) { - ticks.push({ - value: rank - }); - rank++; - } - - return ticks; - }; - - OrdinalScale.prototype.getMinorTicks = function (splitNumber) { - // Not support. - return; - }; - /** - * @see `Ordinal['_ordinalNumbersByTick']` - */ - - - OrdinalScale.prototype.setSortInfo = function (info) { - if (info == null) { - this._ordinalNumbersByTick = this._ticksByOrdinalNumber = null; - return; - } - - var infoOrdinalNumbers = info.ordinalNumbers; - var ordinalsByTick = this._ordinalNumbersByTick = []; - var ticksByOrdinal = this._ticksByOrdinalNumber = []; // Unnecessary support negative tick in `realtimeSort`. - - var tickNum = 0; - var allCategoryLen = this._ordinalMeta.categories.length; - - for (var len = Math.min(allCategoryLen, infoOrdinalNumbers.length); tickNum < len; ++tickNum) { - var ordinalNumber = infoOrdinalNumbers[tickNum]; - ordinalsByTick[tickNum] = ordinalNumber; - ticksByOrdinal[ordinalNumber] = tickNum; - } // Handle that `series.data` only covers part of the `axis.category.data`. - - - var unusedOrdinal = 0; - - for (; tickNum < allCategoryLen; ++tickNum) { - while (ticksByOrdinal[unusedOrdinal] != null) { - unusedOrdinal++; - } - - ordinalsByTick.push(unusedOrdinal); - ticksByOrdinal[unusedOrdinal] = tickNum; - } - }; - - OrdinalScale.prototype._getTickNumber = function (ordinal) { - var ticksByOrdinalNumber = this._ticksByOrdinalNumber; // also support ordinal out of range of `ordinalMeta.categories.length`, - // where ordinal numbers are used as tick value directly. - - return ticksByOrdinalNumber && ordinal >= 0 && ordinal < ticksByOrdinalNumber.length ? ticksByOrdinalNumber[ordinal] : ordinal; - }; - /** - * @usage - * ```js - * const ordinalNumber = ordinalScale.getRawOrdinalNumber(tickVal); - * - * // case0 - * const rawOrdinalValue = axisModel.getCategories()[ordinalNumber]; - * // case1 - * const rawOrdinalValue = this._ordinalMeta.categories[ordinalNumber]; - * // case2 - * const coord = axis.dataToCoord(ordinalNumber); - * ``` - * - * @param {OrdinalNumber} tickNumber index of display - */ - - - OrdinalScale.prototype.getRawOrdinalNumber = function (tickNumber) { - var ordinalNumbersByTick = this._ordinalNumbersByTick; // tickNumber may be out of range, e.g., when axis max is larger than `ordinalMeta.categories.length`., - // where ordinal numbers are used as tick value directly. - - return ordinalNumbersByTick && tickNumber >= 0 && tickNumber < ordinalNumbersByTick.length ? ordinalNumbersByTick[tickNumber] : tickNumber; - }; - /** - * Get item on tick - */ - - - OrdinalScale.prototype.getLabel = function (tick) { - if (!this.isBlank()) { - var ordinalNumber = this.getRawOrdinalNumber(tick.value); - var cateogry = this._ordinalMeta.categories[ordinalNumber]; // Note that if no data, ordinalMeta.categories is an empty array. - // Return empty if it's not exist. - - return cateogry == null ? '' : cateogry + ''; - } - }; - - OrdinalScale.prototype.count = function () { - return this._extent[1] - this._extent[0] + 1; - }; - /** - * @override - * If value is in extent range - */ - - - OrdinalScale.prototype.isInExtentRange = function (value) { - value = this._getTickNumber(value); - return this._extent[0] <= value && this._extent[1] >= value; - }; - - OrdinalScale.prototype.getOrdinalMeta = function () { - return this._ordinalMeta; - }; - - OrdinalScale.prototype.calcNiceTicks = function () {}; - - OrdinalScale.prototype.calcNiceExtent = function () {}; - - OrdinalScale.type = 'ordinal'; - return OrdinalScale; - }(Scale); - - Scale.registerClass(OrdinalScale); - var roundNumber = round$1; - - var IntervalScale = - /** @class */ - function (_super) { - __extends(IntervalScale, _super); - - function IntervalScale() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = 'interval'; // Step is calculated in adjustExtent. - - _this._interval = 0; - _this._intervalPrecision = 2; - return _this; - } - - IntervalScale.prototype.parse = function (val) { - // `Scale#parse` (and its overrids) are typically applied at the axis values input - // in echarts option. e.g., `axis.min/max`, `dataZoom.min/max`, etc. - // but `series.data` is not included, which uses `dataValueHelper.ts`#`parseDataValue`. - // `Scale#parse` originally introduced in fb8c813215098b9d2458966229bb95c510883d5e - // at 2016 for dataZoom start/end settings (See `parseAxisModelMinMax`). - // - // Historically `scale/Interval.ts` returns the input value directly. But numeric - // values (such as a number-like string '123') effectively passed through here and - // were involved in calculations, which was error-prone and inconsistent with the - // declared TS return type. Previously such issues are fixed separately in different - // places case by case (such as #2475). - // - // Now, we perform actual parse to ensure its `number` type here. The parsing rule - // follows the series data parsing rule (`dataValueHelper.ts`#`parseDataValue`) - // and maintains compatibility as much as possible (thus a more strict parsing - // `number.ts`#`numericToNumber` is not used here.) - // - // FIXME: `ScaleDataValue` also need to be modified to include numeric string type, - // since it effectively does. - return val == null || val === '' ? NaN // If string (like '-'), using '+' parse to NaN - // If object, also parse to NaN - : Number(val); - }; - - IntervalScale.prototype.contain = function (val) { - return contain$1(val, this._extent); - }; - - IntervalScale.prototype.normalize = function (val) { - return this._calculator.normalize(val, this._extent); - }; - - IntervalScale.prototype.scale = function (val) { - return this._calculator.scale(val, this._extent); - }; - - IntervalScale.prototype.getInterval = function () { - return this._interval; - }; - - IntervalScale.prototype.setInterval = function (interval) { - this._interval = interval; // Dropped auto calculated niceExtent and use user-set extent. - // We assume user wants to set both interval, min, max to get a better result. - - this._niceExtent = this._extent.slice(); - this._intervalPrecision = getIntervalPrecision(interval); - }; - /** - * @override - */ - - - IntervalScale.prototype.getTicks = function (opt) { - opt = opt || {}; - var interval = this._interval; - var extent = this._extent; - var niceTickExtent = this._niceExtent; - var intervalPrecision = this._intervalPrecision; - var scaleBreakHelper = getScaleBreakHelper(); - var ticks = []; // If interval is 0, return []; - - if (!interval) { - return ticks; - } - - if (opt.breakTicks === 'only_break' && scaleBreakHelper) { - scaleBreakHelper.addBreaksToTicks(ticks, this._brkCtx.breaks, this._extent); - return ticks; - } // Consider this case: using dataZoom toolbox, zoom and zoom. - - - var safeLimit = 10000; - - if (extent[0] < niceTickExtent[0]) { - if (opt.expandToNicedExtent) { - ticks.push({ - value: roundNumber(niceTickExtent[0] - interval, intervalPrecision) - }); - } else { - ticks.push({ - value: extent[0] - }); - } - } - - var estimateNiceMultiple = function (tickVal, targetTick) { - return Math.round((targetTick - tickVal) / interval); - }; - - var tick = niceTickExtent[0]; - - while (tick <= niceTickExtent[1]) { - ticks.push({ - value: tick - }); // Avoid rounding error - - tick = roundNumber(tick + interval, intervalPrecision); - - if (this._brkCtx) { - var moreMultiple = this._brkCtx.calcNiceTickMultiple(tick, estimateNiceMultiple); - - if (moreMultiple >= 0) { - tick = roundNumber(tick + moreMultiple * interval, intervalPrecision); - } - } - - if (ticks.length > 0 && tick === ticks[ticks.length - 1].value) { - // Consider out of safe float point, e.g., - // -3711126.9907707 + 2e-10 === -3711126.9907707 - break; - } - - if (ticks.length > safeLimit) { - return []; - } - } // Consider this case: the last item of ticks is smaller - // than niceTickExtent[1] and niceTickExtent[1] === extent[1]. - - - var lastNiceTick = ticks.length ? ticks[ticks.length - 1].value : niceTickExtent[1]; - - if (extent[1] > lastNiceTick) { - if (opt.expandToNicedExtent) { - ticks.push({ - value: roundNumber(lastNiceTick + interval, intervalPrecision) - }); - } else { - ticks.push({ - value: extent[1] - }); - } - } - - if (opt.breakTicks !== 'none' && scaleBreakHelper) { - scaleBreakHelper.addBreaksToTicks(ticks, this._brkCtx.breaks, this._extent); - } - - return ticks; - }; - - IntervalScale.prototype.getMinorTicks = function (splitNumber) { - var ticks = this.getTicks({ - expandToNicedExtent: true - }); // NOTE: In log-scale, do not support minor ticks when breaks exist. - // because currently log-scale minor ticks is calculated based on raw values - // rather than log-transformed value, due to an odd effect when breaks exist. - - var minorTicks = []; - var extent = this.getExtent(); - - for (var i = 1; i < ticks.length; i++) { - var nextTick = ticks[i]; - var prevTick = ticks[i - 1]; - - if (prevTick["break"] || nextTick["break"]) { - // Do not build minor ticks to the adjacent ticks to breaks ticks, - // since the interval might be irregular. - continue; - } - - var count = 0; - var minorTicksGroup = []; - var interval = nextTick.value - prevTick.value; - var minorInterval = interval / splitNumber; - var minorIntervalPrecision = getIntervalPrecision(minorInterval); - - while (count < splitNumber - 1) { - var minorTick = roundNumber(prevTick.value + (count + 1) * minorInterval, minorIntervalPrecision); // For the first and last interval. The count may be less than splitNumber. - - if (minorTick > extent[0] && minorTick < extent[1]) { - minorTicksGroup.push(minorTick); - } - - count++; - } - - var scaleBreakHelper = getScaleBreakHelper(); - scaleBreakHelper && scaleBreakHelper.pruneTicksByBreak('auto', minorTicksGroup, this._getNonTransBreaks(), function (value) { - return value; - }, this._interval, extent); - minorTicks.push(minorTicksGroup); - } - - return minorTicks; - }; - - IntervalScale.prototype._getNonTransBreaks = function () { - return this._brkCtx ? this._brkCtx.breaks : []; - }; - /** - * @param opt.precision If 'auto', use nice presision. - * @param opt.pad returns 1.50 but not 1.5 if precision is 2. - */ - - - IntervalScale.prototype.getLabel = function (data, opt) { - if (data == null) { - return ''; - } - - var precision = opt && opt.precision; - - if (precision == null) { - precision = getPrecision(data.value) || 0; - } else if (precision === 'auto') { - // Should be more precise then tick. - precision = this._intervalPrecision; - } // (1) If `precision` is set, 12.005 should be display as '12.00500'. - // (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'. - - - var dataNum = roundNumber(data.value, precision, true); - return addCommas(dataNum); - }; - /** - * FIXME: refactor - disallow override, use composition instead. - * - * The override of `calcNiceTicks` should ensure these members are provided: - * this._intervalPrecision - * this._interval - * - * @param splitNumber By default `5`. - */ - - - IntervalScale.prototype.calcNiceTicks = function (splitNumber, minInterval, maxInterval) { - splitNumber = splitNumber || 5; - - var extent = this._extent.slice(); - - var span = this._getExtentSpanWithBreaks(); - - if (!isFinite(span)) { - return; - } // User may set axis min 0 and data are all negative - // FIXME If it needs to reverse ? - - - if (span < 0) { - span = -span; - extent.reverse(); - - this._innerSetExtent(extent[0], extent[1]); - - extent = this._extent.slice(); - } - - var result = intervalScaleNiceTicks(extent, span, splitNumber, minInterval, maxInterval); - this._intervalPrecision = result.intervalPrecision; - this._interval = result.interval; - this._niceExtent = result.niceTickExtent; - }; - - IntervalScale.prototype.calcNiceExtent = function (opt) { - var extent = this._extent.slice(); // If extent start and end are same, expand them - - - if (extent[0] === extent[1]) { - if (extent[0] !== 0) { - // Expand extent - // Note that extents can be both negative. See #13154 - var expandSize = Math.abs(extent[0]); // In the fowllowing case - // Axis has been fixed max 100 - // Plus data are all 100 and axis extent are [100, 100]. - // Extend to the both side will cause expanded max is larger than fixed max. - // So only expand to the smaller side. - - if (!opt.fixMax) { - extent[1] += expandSize / 2; - extent[0] -= expandSize / 2; - } else { - extent[0] -= expandSize / 2; - } - } else { - extent[1] = 1; - } - } - - var span = extent[1] - extent[0]; // If there are no data and extent are [Infinity, -Infinity] - - if (!isFinite(span)) { - extent[0] = 0; - extent[1] = 1; - } - - this._innerSetExtent(extent[0], extent[1]); - - extent = this._extent.slice(); - this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval); - var interval = this._interval; - var intervalPrecition = this._intervalPrecision; - - if (!opt.fixMin) { - extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval, intervalPrecition); - } - - if (!opt.fixMax) { - extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval, intervalPrecition); - } - - this._innerSetExtent(extent[0], extent[1]); - }; - - IntervalScale.prototype.setNiceExtent = function (min, max) { - this._niceExtent = [min, max]; - }; - - IntervalScale.type = 'interval'; - return IntervalScale; - }(Scale); - - Scale.registerClass(IntervalScale); - /* global Float32Array */ - - var supportFloat32Array = typeof Float32Array !== 'undefined'; - var Float32ArrayCtor = !supportFloat32Array ? Array : Float32Array; - - function createFloat32Array(arg) { - if (isArray(arg)) { - // Return self directly if don't support TypedArray. - return supportFloat32Array ? new Float32Array(arg) : arg; - } // Else is number - - - return new Float32ArrayCtor(arg); - } - - var STACK_PREFIX = '__ec_stack_'; - - function getSeriesStackId(seriesModel) { - return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex; - } - - function getAxisKey(axis) { - return axis.dim + axis.index; - } - - function prepareLayoutBarSeries(seriesType, ecModel) { - var seriesModels = []; - ecModel.eachSeriesByType(seriesType, function (seriesModel) { - // Check series coordinate, do layout for cartesian2d only - if (isOnCartesian(seriesModel)) { - seriesModels.push(seriesModel); - } - }); - return seriesModels; - } - /** - * Map from (baseAxis.dim + '_' + baseAxis.index) to min gap of two adjacent - * values. - * This works for time axes, value axes, and log axes. - * For a single time axis, return value is in the form like - * {'x_0': [1000000]}. - * The value of 1000000 is in milliseconds. - */ - - - function getValueAxesMinGaps(barSeries) { - /** - * Map from axis.index to values. - * For a single time axis, axisValues is in the form like - * {'x_0': [1495555200000, 1495641600000, 1495728000000]}. - * Items in axisValues[x], e.g. 1495555200000, are time values of all - * series. - */ - var axisValues = {}; - each$4(barSeries, function (seriesModel) { - var cartesian = seriesModel.coordinateSystem; - var baseAxis = cartesian.getBaseAxis(); - - if (baseAxis.type !== 'time' && baseAxis.type !== 'value') { - return; - } - - var data = seriesModel.getData(); - var key = baseAxis.dim + '_' + baseAxis.index; - var dimIdx = data.getDimensionIndex(data.mapDimension(baseAxis.dim)); - var store = data.getStore(); - - for (var i = 0, cnt = store.count(); i < cnt; ++i) { - var value = store.get(dimIdx, i); - - if (!axisValues[key]) { - // No previous data for the axis - axisValues[key] = [value]; - } else { - // No value in previous series - axisValues[key].push(value); - } // Ignore duplicated time values in the same axis - - } - }); - var axisMinGaps = {}; - - for (var key in axisValues) { - if (axisValues.hasOwnProperty(key)) { - var valuesInAxis = axisValues[key]; - - if (valuesInAxis) { - // Sort axis values into ascending order to calculate gaps - valuesInAxis.sort(function (a, b) { - return a - b; - }); - var min = null; - - for (var j = 1; j < valuesInAxis.length; ++j) { - var delta = valuesInAxis[j] - valuesInAxis[j - 1]; - - if (delta > 0) { - // Ignore 0 delta because they are of the same axis value - min = min === null ? delta : Math.min(min, delta); - } - } // Set to null if only have one data - - - axisMinGaps[key] = min; - } - } - } - - return axisMinGaps; - } - - function makeColumnLayout(barSeries) { - var axisMinGaps = getValueAxesMinGaps(barSeries); - var seriesInfoList = []; - each$4(barSeries, function (seriesModel) { - var cartesian = seriesModel.coordinateSystem; - var baseAxis = cartesian.getBaseAxis(); - var axisExtent = baseAxis.getExtent(); - var bandWidth; - - if (baseAxis.type === 'category') { - bandWidth = baseAxis.getBandWidth(); - } else if (baseAxis.type === 'value' || baseAxis.type === 'time') { - var key = baseAxis.dim + '_' + baseAxis.index; - var minGap = axisMinGaps[key]; - var extentSpan = Math.abs(axisExtent[1] - axisExtent[0]); - var scale = baseAxis.scale.getExtent(); - var scaleSpan = Math.abs(scale[1] - scale[0]); - bandWidth = minGap ? extentSpan / scaleSpan * minGap : extentSpan; // When there is only one data value - } else { - var data = seriesModel.getData(); - bandWidth = Math.abs(axisExtent[1] - axisExtent[0]) / data.count(); - } - - var barWidth = parsePercent(seriesModel.get('barWidth'), bandWidth); - var barMaxWidth = parsePercent(seriesModel.get('barMaxWidth'), bandWidth); - var barMinWidth = parsePercent( // barMinWidth by default is 0.5 / 1 in cartesian. Because in value axis, - // the auto-calculated bar width might be less than 0.5 / 1. - seriesModel.get('barMinWidth') || (isInLargeMode(seriesModel) ? 0.5 : 1), bandWidth); - var barGap = seriesModel.get('barGap'); - var barCategoryGap = seriesModel.get('barCategoryGap'); - var defaultBarGap = seriesModel.get('defaultBarGap'); - seriesInfoList.push({ - bandWidth: bandWidth, - barWidth: barWidth, - barMaxWidth: barMaxWidth, - barMinWidth: barMinWidth, - barGap: barGap, - barCategoryGap: barCategoryGap, - defaultBarGap: defaultBarGap, - axisKey: getAxisKey(baseAxis), - stackId: getSeriesStackId(seriesModel) - }); - }); - return doCalBarWidthAndOffset(seriesInfoList); - } - - function doCalBarWidthAndOffset(seriesInfoList) { - // Columns info on each category axis. Key is cartesian name - var columnsMap = {}; - each$4(seriesInfoList, function (seriesInfo, idx) { - var axisKey = seriesInfo.axisKey; - var bandWidth = seriesInfo.bandWidth; - var columnsOnAxis = columnsMap[axisKey] || { - bandWidth: bandWidth, - remainedWidth: bandWidth, - autoWidthCount: 0, - categoryGap: null, - gap: seriesInfo.defaultBarGap || 0, - stacks: {} - }; - var stacks = columnsOnAxis.stacks; - columnsMap[axisKey] = columnsOnAxis; - var stackId = seriesInfo.stackId; - - if (!stacks[stackId]) { - columnsOnAxis.autoWidthCount++; - } - - stacks[stackId] = stacks[stackId] || { - width: 0, - maxWidth: 0 - }; // Caution: In a single coordinate system, these barGrid attributes - // will be shared by series. Consider that they have default values, - // only the attributes set on the last series will work. - // Do not change this fact unless there will be a break change. - - var barWidth = seriesInfo.barWidth; - - if (barWidth && !stacks[stackId].width) { - // See #6312, do not restrict width. - stacks[stackId].width = barWidth; - barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth); - columnsOnAxis.remainedWidth -= barWidth; - } - - var barMaxWidth = seriesInfo.barMaxWidth; - barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth); - var barMinWidth = seriesInfo.barMinWidth; - barMinWidth && (stacks[stackId].minWidth = barMinWidth); - var barGap = seriesInfo.barGap; - barGap != null && (columnsOnAxis.gap = barGap); - var barCategoryGap = seriesInfo.barCategoryGap; - barCategoryGap != null && (columnsOnAxis.categoryGap = barCategoryGap); - }); - var result = {}; - each$4(columnsMap, function (columnsOnAxis, coordSysName) { - result[coordSysName] = {}; - var stacks = columnsOnAxis.stacks; - var bandWidth = columnsOnAxis.bandWidth; - var categoryGapPercent = columnsOnAxis.categoryGap; - - if (categoryGapPercent == null) { - var columnCount = keys(stacks).length; // More columns in one group - // the spaces between group is smaller. Or the column will be too thin. - - categoryGapPercent = Math.max(35 - columnCount * 4, 15) + '%'; - } - - var categoryGap = parsePercent(categoryGapPercent, bandWidth); - var barGapPercent = parsePercent(columnsOnAxis.gap, 1); - var remainedWidth = columnsOnAxis.remainedWidth; - var autoWidthCount = columnsOnAxis.autoWidthCount; - var autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent); - autoWidth = Math.max(autoWidth, 0); // Find if any auto calculated bar exceeded maxBarWidth - - each$4(stacks, function (column) { - var maxWidth = column.maxWidth; - var minWidth = column.minWidth; - - if (!column.width) { - var finalWidth = autoWidth; - - if (maxWidth && maxWidth < finalWidth) { - finalWidth = Math.min(maxWidth, remainedWidth); - } // `minWidth` has higher priority. `minWidth` decide that whether the - // bar is able to be visible. So `minWidth` should not be restricted - // by `maxWidth` or `remainedWidth` (which is from `bandWidth`). In - // the extreme cases for `value` axis, bars are allowed to overlap - // with each other if `minWidth` specified. - - - if (minWidth && minWidth > finalWidth) { - finalWidth = minWidth; - } - - if (finalWidth !== autoWidth) { - column.width = finalWidth; - remainedWidth -= finalWidth + barGapPercent * finalWidth; - autoWidthCount--; - } - } else { - // `barMinWidth/barMaxWidth` has higher priority than `barWidth`, as - // CSS does. Because barWidth can be a percent value, where - // `barMaxWidth` can be used to restrict the final width. - var finalWidth = column.width; - - if (maxWidth) { - finalWidth = Math.min(finalWidth, maxWidth); - } // `minWidth` has higher priority, as described above - - - if (minWidth) { - finalWidth = Math.max(finalWidth, minWidth); - } - - column.width = finalWidth; - remainedWidth -= finalWidth + barGapPercent * finalWidth; - autoWidthCount--; - } - }); // Recalculate width again - - autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent); - autoWidth = Math.max(autoWidth, 0); - var widthSum = 0; - var lastColumn; - each$4(stacks, function (column, idx) { - if (!column.width) { - column.width = autoWidth; - } - - lastColumn = column; - widthSum += column.width * (1 + barGapPercent); - }); - - if (lastColumn) { - widthSum -= lastColumn.width * barGapPercent; - } - - var offset = -widthSum / 2; - each$4(stacks, function (column, stackId) { - result[coordSysName][stackId] = result[coordSysName][stackId] || { - bandWidth: bandWidth, - offset: offset, - width: column.width - }; - offset += column.width * (1 + barGapPercent); - }); - }); - return result; - } - - function retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) { - if (barWidthAndOffset && axis) { - var result = barWidthAndOffset[getAxisKey(axis)]; - - if (result != null && seriesModel != null) { - return result[getSeriesStackId(seriesModel)]; - } - - return result; - } - } - - function layout$1(seriesType, ecModel) { - var seriesModels = prepareLayoutBarSeries(seriesType, ecModel); - var barWidthAndOffset = makeColumnLayout(seriesModels); - each$4(seriesModels, function (seriesModel) { - var data = seriesModel.getData(); - var cartesian = seriesModel.coordinateSystem; - var baseAxis = cartesian.getBaseAxis(); - var stackId = getSeriesStackId(seriesModel); - var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId]; - var columnOffset = columnLayoutInfo.offset; - var columnWidth = columnLayoutInfo.width; - data.setLayout({ - bandWidth: columnLayoutInfo.bandWidth, - offset: columnOffset, - size: columnWidth - }); - }); - } // TODO: Do not support stack in large mode yet. - - - function createProgressiveLayout(seriesType) { - return { - seriesType: seriesType, - plan: createRenderPlanner(), - reset: function (seriesModel) { - if (!isOnCartesian(seriesModel)) { - return; - } - - var data = seriesModel.getData(); - var cartesian = seriesModel.coordinateSystem; - var baseAxis = cartesian.getBaseAxis(); - var valueAxis = cartesian.getOtherAxis(baseAxis); - var valueDimIdx = data.getDimensionIndex(data.mapDimension(valueAxis.dim)); - var baseDimIdx = data.getDimensionIndex(data.mapDimension(baseAxis.dim)); - var drawBackground = seriesModel.get('showBackground', true); - var valueDim = data.mapDimension(valueAxis.dim); - var stackResultDim = data.getCalculationInfo('stackResultDimension'); - var stacked = isDimensionStacked(data, valueDim) && !!data.getCalculationInfo('stackedOnSeries'); - var isValueAxisH = valueAxis.isHorizontal(); - var valueAxisStart = getValueAxisStart(baseAxis, valueAxis); - var isLarge = isInLargeMode(seriesModel); - var barMinHeight = seriesModel.get('barMinHeight') || 0; - var stackedDimIdx = stackResultDim && data.getDimensionIndex(stackResultDim); // Layout info. - - var columnWidth = data.getLayout('size'); - var columnOffset = data.getLayout('offset'); - return { - progress: function (params, data) { - var count = params.count; - var largePoints = isLarge && createFloat32Array(count * 3); - var largeBackgroundPoints = isLarge && drawBackground && createFloat32Array(count * 3); - var largeDataIndices = isLarge && createFloat32Array(count); - var coordLayout = cartesian.master.getRect(); - var bgSize = isValueAxisH ? coordLayout.width : coordLayout.height; - var dataIndex; - var store = data.getStore(); - var idxOffset = 0; - - while ((dataIndex = params.next()) != null) { - var value = store.get(stacked ? stackedDimIdx : valueDimIdx, dataIndex); - var baseValue = store.get(baseDimIdx, dataIndex); - var baseCoord = valueAxisStart; - var stackStartValue = void 0; // Because of the barMinHeight, we can not use the value in - // stackResultDimension directly. - - if (stacked) { - stackStartValue = +value - store.get(valueDimIdx, dataIndex); - } - - var x = void 0; - var y = void 0; - var width = void 0; - var height = void 0; - - if (isValueAxisH) { - var coord = cartesian.dataToPoint([value, baseValue]); - - if (stacked) { - var startCoord = cartesian.dataToPoint([stackStartValue, baseValue]); - baseCoord = startCoord[0]; - } - - x = baseCoord; - y = coord[1] + columnOffset; - width = coord[0] - baseCoord; - height = columnWidth; - - if (Math.abs(width) < barMinHeight) { - width = (width < 0 ? -1 : 1) * barMinHeight; - } - } else { - var coord = cartesian.dataToPoint([baseValue, value]); - - if (stacked) { - var startCoord = cartesian.dataToPoint([baseValue, stackStartValue]); - baseCoord = startCoord[1]; - } - - x = coord[0] + columnOffset; - y = baseCoord; - width = columnWidth; - height = coord[1] - baseCoord; - - if (Math.abs(height) < barMinHeight) { - // Include zero to has a positive bar - height = (height <= 0 ? -1 : 1) * barMinHeight; - } - } - - if (!isLarge) { - data.setItemLayout(dataIndex, { - x: x, - y: y, - width: width, - height: height - }); - } else { - largePoints[idxOffset] = x; - largePoints[idxOffset + 1] = y; - largePoints[idxOffset + 2] = isValueAxisH ? width : height; - - if (largeBackgroundPoints) { - largeBackgroundPoints[idxOffset] = isValueAxisH ? coordLayout.x : x; - largeBackgroundPoints[idxOffset + 1] = isValueAxisH ? y : coordLayout.y; - largeBackgroundPoints[idxOffset + 2] = bgSize; - } - - largeDataIndices[dataIndex] = dataIndex; - } - - idxOffset += 3; - } - - if (isLarge) { - data.setLayout({ - largePoints: largePoints, - largeDataIndices: largeDataIndices, - largeBackgroundPoints: largeBackgroundPoints, - valueAxisHorizontal: isValueAxisH - }); - } - } - }; - } - }; - } - - function isOnCartesian(seriesModel) { - return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d'; - } - - function isInLargeMode(seriesModel) { - return seriesModel.pipelineContext && seriesModel.pipelineContext.large; - } // See cases in `test/bar-start.html` and `#7412`, `#8747`. - - - function getValueAxisStart(baseAxis, valueAxis) { - var startValue = valueAxis.model.get('startValue'); - - if (!startValue) { - startValue = 0; - } - - return valueAxis.toGlobalCoord(valueAxis.dataToCoord(valueAxis.type === 'log' ? startValue > 0 ? startValue : 1 : startValue)); - } // FIXME 公用? - - - var bisect = function (a, x, lo, hi) { - while (lo < hi) { - var mid = lo + hi >>> 1; - - if (a[mid][1] < x) { - lo = mid + 1; - } else { - hi = mid; - } - } - - return lo; - }; - - var TimeScale = - /** @class */ - function (_super) { - __extends(TimeScale, _super); - - function TimeScale(settings) { - var _this = _super.call(this, settings) || this; - - _this.type = 'time'; - return _this; - } - /** - * Get label is mainly for other components like dataZoom, tooltip. - */ - - - TimeScale.prototype.getLabel = function (tick) { - var useUTC = this.getSetting('useUTC'); - return format$1(tick.value, fullLeveledFormatter[getDefaultFormatPrecisionOfInterval(getPrimaryTimeUnit(this._minLevelUnit))] || fullLeveledFormatter.second, useUTC, this.getSetting('locale')); - }; - - TimeScale.prototype.getFormattedLabel = function (tick, idx, labelFormatter) { - var isUTC = this.getSetting('useUTC'); - var lang = this.getSetting('locale'); - return leveledFormat(tick, idx, labelFormatter, lang, isUTC); - }; - /** - * @override - */ - - - TimeScale.prototype.getTicks = function (opt) { - var interval = this._interval; - var extent = this._extent; - var ticks = []; // If interval is 0, return []; - - if (!interval) { - return ticks; - } - - var useUTC = this.getSetting('useUTC'); - var extent0Unit = getUnitFromValue(extent[1], useUTC); - ticks.push({ - value: extent[0], - time: { - level: 0, - upperTimeUnit: extent0Unit, - lowerTimeUnit: extent0Unit - } - }); - var innerTicks = getIntervalTicks(this._minLevelUnit, this._approxInterval, useUTC, extent, this._getExtentSpanWithBreaks(), this._brkCtx); - ticks = ticks.concat(innerTicks); - var extent1Unit = getUnitFromValue(extent[1], useUTC); - ticks.push({ - value: extent[1], - time: { - level: 0, - upperTimeUnit: extent1Unit, - lowerTimeUnit: extent1Unit - } - }); - this.getSetting('useUTC'); - var upperUnitIndex = primaryTimeUnits.length - 1; - var maxLevel = 0; - each$4(ticks, function (tick) { - upperUnitIndex = Math.min(upperUnitIndex, indexOf(primaryTimeUnits, tick.time.upperTimeUnit)); - maxLevel = Math.max(maxLevel, tick.time.level); - }); - return ticks; - }; - - TimeScale.prototype.calcNiceExtent = function (opt) { - var extent = this.getExtent(); // If extent start and end are same, expand them - - if (extent[0] === extent[1]) { - // Expand extent - extent[0] -= ONE_DAY; - extent[1] += ONE_DAY; - } // If there are no data and extent are [Infinity, -Infinity] - - - if (extent[1] === -Infinity && extent[0] === Infinity) { - var d = new Date(); - extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate()); - extent[0] = extent[1] - ONE_DAY; - } - - this._innerSetExtent(extent[0], extent[1]); - - this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval); - }; - - TimeScale.prototype.calcNiceTicks = function (approxTickNum, minInterval, maxInterval) { - approxTickNum = approxTickNum || 10; - - var span = this._getExtentSpanWithBreaks(); - - this._approxInterval = span / approxTickNum; - - if (minInterval != null && this._approxInterval < minInterval) { - this._approxInterval = minInterval; - } - - if (maxInterval != null && this._approxInterval > maxInterval) { - this._approxInterval = maxInterval; - } - - var scaleIntervalsLen = scaleIntervals.length; - var idx = Math.min(bisect(scaleIntervals, this._approxInterval, 0, scaleIntervalsLen), scaleIntervalsLen - 1); // Interval that can be used to calculate ticks - - this._interval = scaleIntervals[idx][1]; - this._intervalPrecision = getIntervalPrecision(this._interval); // Min level used when picking ticks from top down. - // We check one more level to avoid the ticks are to sparse in some case. - - this._minLevelUnit = scaleIntervals[Math.max(idx - 1, 0)][0]; - }; - - TimeScale.prototype.parse = function (val) { - // val might be float. - return isNumber(val) ? val : +parseDate(val); - }; - - TimeScale.prototype.contain = function (val) { - return contain$1(val, this._extent); - }; - - TimeScale.prototype.normalize = function (val) { - return this._calculator.normalize(val, this._extent); - }; - - TimeScale.prototype.scale = function (val) { - return this._calculator.scale(val, this._extent); - }; - - TimeScale.type = 'time'; - return TimeScale; - }(IntervalScale); - /** - * This implementation was originally copied from "d3.js" - * - * with some modifications made for this program. - * See the license statement at the head of this file. - */ - - - var scaleIntervals = [// Format interval - ['second', ONE_SECOND], ['minute', ONE_MINUTE], ['hour', ONE_HOUR], ['quarter-day', ONE_HOUR * 6], ['half-day', ONE_HOUR * 12], ['day', ONE_DAY * 1.2], ['half-week', ONE_DAY * 3.5], ['week', ONE_DAY * 7], ['month', ONE_DAY * 31], ['quarter', ONE_DAY * 95], ['half-year', ONE_YEAR / 2], ['year', ONE_YEAR] // 1Y - ]; - - function isPrimaryUnitValueAndGreaterSame(unit, valueA, valueB, isUTC) { - return roundTime(new Date(valueA), unit, isUTC).getTime() === roundTime(new Date(valueB), unit, isUTC).getTime(); - } // function isUnitValueSame( - // unit: PrimaryTimeUnit, - // valueA: number, - // valueB: number, - // isUTC: boolean - // ): boolean { - // const dateA = numberUtil.parseDate(valueA) as any; - // const dateB = numberUtil.parseDate(valueB) as any; - // const isSame = (unit: PrimaryTimeUnit) => { - // return getUnitValue(dateA, unit, isUTC) - // === getUnitValue(dateB, unit, isUTC); - // }; - // const isSameYear = () => isSame('year'); - // // const isSameHalfYear = () => isSameYear() && isSame('half-year'); - // // const isSameQuater = () => isSameYear() && isSame('quarter'); - // const isSameMonth = () => isSameYear() && isSame('month'); - // const isSameDay = () => isSameMonth() && isSame('day'); - // // const isSameHalfDay = () => isSameDay() && isSame('half-day'); - // const isSameHour = () => isSameDay() && isSame('hour'); - // const isSameMinute = () => isSameHour() && isSame('minute'); - // const isSameSecond = () => isSameMinute() && isSame('second'); - // const isSameMilliSecond = () => isSameSecond() && isSame('millisecond'); - // switch (unit) { - // case 'year': - // return isSameYear(); - // case 'month': - // return isSameMonth(); - // case 'day': - // return isSameDay(); - // case 'hour': - // return isSameHour(); - // case 'minute': - // return isSameMinute(); - // case 'second': - // return isSameSecond(); - // case 'millisecond': - // return isSameMilliSecond(); - // } - // } - // const primaryUnitGetters = { - // year: fullYearGetterName(), - // month: monthGetterName(), - // day: dateGetterName(), - // hour: hoursGetterName(), - // minute: minutesGetterName(), - // second: secondsGetterName(), - // millisecond: millisecondsGetterName() - // }; - // const primaryUnitUTCGetters = { - // year: fullYearGetterName(true), - // month: monthGetterName(true), - // day: dateGetterName(true), - // hour: hoursGetterName(true), - // minute: minutesGetterName(true), - // second: secondsGetterName(true), - // millisecond: millisecondsGetterName(true) - // }; - // function moveTick(date: Date, unitName: TimeUnit, step: number, isUTC: boolean) { - // step = step || 1; - // switch (getPrimaryTimeUnit(unitName)) { - // case 'year': - // date[fullYearSetterName(isUTC)](date[fullYearGetterName(isUTC)]() + step); - // break; - // case 'month': - // date[monthSetterName(isUTC)](date[monthGetterName(isUTC)]() + step); - // break; - // case 'day': - // date[dateSetterName(isUTC)](date[dateGetterName(isUTC)]() + step); - // break; - // case 'hour': - // date[hoursSetterName(isUTC)](date[hoursGetterName(isUTC)]() + step); - // break; - // case 'minute': - // date[minutesSetterName(isUTC)](date[minutesGetterName(isUTC)]() + step); - // break; - // case 'second': - // date[secondsSetterName(isUTC)](date[secondsGetterName(isUTC)]() + step); - // break; - // case 'millisecond': - // date[millisecondsSetterName(isUTC)](date[millisecondsGetterName(isUTC)]() + step); - // break; - // } - // return date.getTime(); - // } - // const DATE_INTERVALS = [[8, 7.5], [4, 3.5], [2, 1.5]]; - // const MONTH_INTERVALS = [[6, 5.5], [3, 2.5], [2, 1.5]]; - // const MINUTES_SECONDS_INTERVALS = [[30, 30], [20, 20], [15, 15], [10, 10], [5, 5], [2, 2]]; - - - function getDateInterval(approxInterval, daysInMonth) { - approxInterval /= ONE_DAY; - return approxInterval > 16 ? 16 // Math.floor(daysInMonth / 2) + 1 // In this case we only want one tick between two months. - : approxInterval > 7.5 ? 7 // TODO week 7 or day 8? - : approxInterval > 3.5 ? 4 : approxInterval > 1.5 ? 2 : 1; - } - - function getMonthInterval(approxInterval) { - var APPROX_ONE_MONTH = 30 * ONE_DAY; - approxInterval /= APPROX_ONE_MONTH; - return approxInterval > 6 ? 6 : approxInterval > 3 ? 3 : approxInterval > 2 ? 2 : 1; - } - - function getHourInterval(approxInterval) { - approxInterval /= ONE_HOUR; - return approxInterval > 12 ? 12 : approxInterval > 6 ? 6 : approxInterval > 3.5 ? 4 : approxInterval > 2 ? 2 : 1; - } - - function getMinutesAndSecondsInterval(approxInterval, isMinutes) { - approxInterval /= isMinutes ? ONE_MINUTE : ONE_SECOND; - return approxInterval > 30 ? 30 : approxInterval > 20 ? 20 : approxInterval > 15 ? 15 : approxInterval > 10 ? 10 : approxInterval > 5 ? 5 : approxInterval > 2 ? 2 : 1; - } - - function getMillisecondsInterval(approxInterval) { - return nice(approxInterval, true); - } // e.g., if the input unit is 'day', start calculate ticks from the first day of - // that month to make ticks "nice". - - - function getFirstTimestampOfUnit(timestamp, unitName, isUTC) { - var upperUnitIdx = Math.max(0, indexOf(primaryTimeUnits, unitName) - 1); - return roundTime(new Date(timestamp), primaryTimeUnits[upperUnitIdx], isUTC).getTime(); - } - - function createEstimateNiceMultiple(setMethodName, dateMethodInterval) { - var tmpDate = new Date(0); - tmpDate[setMethodName](1); - var tmpTime = tmpDate.getTime(); - tmpDate[setMethodName](1 + dateMethodInterval); - var approxTimeInterval = tmpDate.getTime() - tmpTime; - return function (tickVal, targetValue) { - // Only in month that accurate result can not get by division of - // timestamp interval, but no need accurate here. - return Math.max(0, Math.round((targetValue - tickVal) / approxTimeInterval)); - }; - } - - function getIntervalTicks(bottomUnitName, approxInterval, isUTC, extent, extentSpanWithBreaks, brkCtx) { - var safeLimit = 10000; - var unitNames = timeUnits; - var iter = 0; - - function addTicksInSpan(interval, minTimestamp, maxTimestamp, getMethodName, setMethodName, isDate, out) { - var estimateNiceMultiple = createEstimateNiceMultiple(setMethodName, interval); - var dateTime = minTimestamp; - var date = new Date(dateTime); // if (isDate) { - // d -= 1; // Starts with 0; PENDING - // } - - while (dateTime < maxTimestamp && dateTime <= extent[1]) { - out.push({ - value: dateTime - }); - - if (iter++ > safeLimit) { - { - warn('Exceed safe limit in time scale.'); - } - break; - } - - date[setMethodName](date[getMethodName]() + interval); - dateTime = date.getTime(); - - if (brkCtx) { - var moreMultiple = brkCtx.calcNiceTickMultiple(dateTime, estimateNiceMultiple); - - if (moreMultiple > 0) { - date[setMethodName](date[getMethodName]() + moreMultiple * interval); - dateTime = date.getTime(); - } - } - } // This extra tick is for calcuating ticks of next level. Will not been added to the final result - - - out.push({ - value: dateTime, - notAdd: true - }); - } - - function addLevelTicks(unitName, lastLevelTicks, levelTicks) { - var newAddedTicks = []; - var isFirstLevel = !lastLevelTicks.length; - - if (isPrimaryUnitValueAndGreaterSame(getPrimaryTimeUnit(unitName), extent[0], extent[1], isUTC)) { - return; - } - - if (isFirstLevel) { - lastLevelTicks = [{ - value: getFirstTimestampOfUnit(extent[0], unitName, isUTC) - }, { - value: extent[1] - }]; - } - - for (var i = 0; i < lastLevelTicks.length - 1; i++) { - var startTick = lastLevelTicks[i].value; - var endTick = lastLevelTicks[i + 1].value; - - if (startTick === endTick) { - continue; - } - - var interval = void 0; - var getterName = void 0; - var setterName = void 0; - var isDate = false; - - switch (unitName) { - case 'year': - interval = Math.max(1, Math.round(approxInterval / ONE_DAY / 365)); - getterName = fullYearGetterName(isUTC); - setterName = fullYearSetterName(isUTC); - break; - - case 'half-year': - case 'quarter': - case 'month': - interval = getMonthInterval(approxInterval); - getterName = monthGetterName(isUTC); - setterName = monthSetterName(isUTC); - break; - - case 'week': // PENDING If week is added. Ignore day. - - case 'half-week': - case 'day': - interval = getDateInterval(approxInterval); // Use 32 days and let interval been 16 - - getterName = dateGetterName(isUTC); - setterName = dateSetterName(isUTC); - isDate = true; - break; - - case 'half-day': - case 'quarter-day': - case 'hour': - interval = getHourInterval(approxInterval); - getterName = hoursGetterName(isUTC); - setterName = hoursSetterName(isUTC); - break; - - case 'minute': - interval = getMinutesAndSecondsInterval(approxInterval, true); - getterName = minutesGetterName(isUTC); - setterName = minutesSetterName(isUTC); - break; - - case 'second': - interval = getMinutesAndSecondsInterval(approxInterval, false); - getterName = secondsGetterName(isUTC); - setterName = secondsSetterName(isUTC); - break; - - case 'millisecond': - interval = getMillisecondsInterval(approxInterval); - getterName = millisecondsGetterName(isUTC); - setterName = millisecondsSetterName(isUTC); - break; - } // Notice: This expansion by `getFirstTimestampOfUnit` may cause too many ticks and - // iteration. e.g., when three levels of ticks is displayed, which can be caused by - // data zoom and axis breaks. Thus trim them here. - - - if (endTick >= extent[0] && startTick <= extent[1]) { - addTicksInSpan(interval, startTick, endTick, getterName, setterName, isDate, newAddedTicks); - } - - if (unitName === 'year' && levelTicks.length > 1 && i === 0) { - // Add nearest years to the left extent. - levelTicks.unshift({ - value: levelTicks[0].value - interval - }); - } - } - - for (var i = 0; i < newAddedTicks.length; i++) { - levelTicks.push(newAddedTicks[i]); - } - } - - var levelsTicks = []; - var currentLevelTicks = []; - var tickCount = 0; - var lastLevelTickCount = 0; - - for (var i = 0; i < unitNames.length; ++i) { - var primaryTimeUnit = getPrimaryTimeUnit(unitNames[i]); - - if (!isPrimaryTimeUnit(unitNames[i])) { - // TODO - continue; - } - - addLevelTicks(unitNames[i], levelsTicks[levelsTicks.length - 1] || [], currentLevelTicks); - var nextPrimaryTimeUnit = unitNames[i + 1] ? getPrimaryTimeUnit(unitNames[i + 1]) : null; - - if (primaryTimeUnit !== nextPrimaryTimeUnit) { - if (currentLevelTicks.length) { - lastLevelTickCount = tickCount; // Remove the duplicate so the tick count can be precisely. - - currentLevelTicks.sort(function (a, b) { - return a.value - b.value; - }); - var levelTicksRemoveDuplicated = []; - - for (var i_1 = 0; i_1 < currentLevelTicks.length; ++i_1) { - var tickValue = currentLevelTicks[i_1].value; - - if (i_1 === 0 || currentLevelTicks[i_1 - 1].value !== tickValue) { - levelTicksRemoveDuplicated.push(currentLevelTicks[i_1]); - - if (tickValue >= extent[0] && tickValue <= extent[1]) { - tickCount++; - } - } - } - - var targetTickNum = extentSpanWithBreaks / approxInterval; // Added too much in this level and not too less in last level - - if (tickCount > targetTickNum * 1.5 && lastLevelTickCount > targetTickNum / 1.5) { - break; - } // Only treat primary time unit as one level. - - - levelsTicks.push(levelTicksRemoveDuplicated); - - if (tickCount > targetTickNum || bottomUnitName === unitNames[i]) { - break; - } - } // Reset if next unitName is primary - - - currentLevelTicks = []; - } - } - - var levelsTicksInExtent = filter(map$1(levelsTicks, function (levelTicks) { - return filter(levelTicks, function (tick) { - return tick.value >= extent[0] && tick.value <= extent[1] && !tick.notAdd; - }); - }), function (levelTicks) { - return levelTicks.length > 0; - }); - var ticks = []; - var maxLevel = levelsTicksInExtent.length - 1; - - for (var i = 0; i < levelsTicksInExtent.length; ++i) { - var levelTicks = levelsTicksInExtent[i]; - - for (var k = 0; k < levelTicks.length; ++k) { - var unit = getUnitFromValue(levelTicks[k].value, isUTC); - ticks.push({ - value: levelTicks[k].value, - time: { - level: maxLevel - i, - upperTimeUnit: unit, - lowerTimeUnit: unit - } - }); - } - } - - ticks.sort(function (a, b) { - return a.value - b.value; - }); // Remove duplicates - - var result = []; - - for (var i = 0; i < ticks.length; ++i) { - if (i === 0 || ticks[i].value !== ticks[i - 1].value) { - result.push(ticks[i]); - } - } - - return result; - } - - Scale.registerClass(TimeScale); - var fixRound = round$1; - var mathFloor = Math.floor; - var mathCeil = Math.ceil; - var mathPow = Math.pow; - var mathLog = Math.log; - - var LogScale = - /** @class */ - function (_super) { - __extends(LogScale, _super); - - function LogScale() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = 'log'; - _this.base = 10; - _this._originalScale = new IntervalScale(); - return _this; - } - /** - * @param Whether expand the ticks to niced extent. - */ - - - LogScale.prototype.getTicks = function (opt) { - opt = opt || {}; - - var extent = this._extent.slice(); - - var originalExtent = this._originalScale.getExtent(); - - var ticks = _super.prototype.getTicks.call(this, opt); - - var base = this.base; - - this._originalScale._innerGetBreaks(); - - return map$1(ticks, function (tick) { - var val = tick.value; - var roundingCriterion = null; - var powVal = mathPow(base, val); // Fix #4158 - - if (val === extent[0] && this._fixMin) { - roundingCriterion = originalExtent[0]; - } else if (val === extent[1] && this._fixMax) { - roundingCriterion = originalExtent[1]; - } - - var vBreak; - - if (roundingCriterion != null) { - powVal = fixRoundingError(powVal, roundingCriterion); - } - - return { - value: powVal, - "break": vBreak - }; - }, this); - }; - - LogScale.prototype._getNonTransBreaks = function () { - return this._originalScale._innerGetBreaks(); - }; - - LogScale.prototype.setExtent = function (start, end) { - this._originalScale.setExtent(start, end); - - var loggedExtent = logTransform(this.base, [start, end]); - - _super.prototype.setExtent.call(this, loggedExtent[0], loggedExtent[1]); - }; - /** - * @return {number} end - */ - - - LogScale.prototype.getExtent = function () { - var base = this.base; - - var extent = _super.prototype.getExtent.call(this); - - extent[0] = mathPow(base, extent[0]); - extent[1] = mathPow(base, extent[1]); // Fix #4158 - - var originalExtent = this._originalScale.getExtent(); - - this._fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0])); - this._fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1])); - return extent; - }; - - LogScale.prototype.unionExtentFromData = function (data, dim) { - this._originalScale.unionExtentFromData(data, dim); - - var loggedOther = logTransform(this.base, data.getApproximateExtent(dim), true); - - this._innerUnionExtent(loggedOther); - }; - /** - * Update interval and extent of intervals for nice ticks - * @param approxTickNum default 10 Given approx tick number - */ - - - LogScale.prototype.calcNiceTicks = function (approxTickNum) { - approxTickNum = approxTickNum || 10; - - var extent = this._extent.slice(); - - var span = this._getExtentSpanWithBreaks(); - - if (!isFinite(span) || span <= 0) { - return; - } - - var interval = quantity(span); - var err = approxTickNum / span * interval; // Filter ticks to get closer to the desired count. - - if (err <= 0.5) { - interval *= 10; - } // Interval should be integer - - - while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) { - interval *= 10; - } - - var niceExtent = [fixRound(mathCeil(extent[0] / interval) * interval), fixRound(mathFloor(extent[1] / interval) * interval)]; - this._interval = interval; - this._intervalPrecision = getIntervalPrecision(interval); - this._niceExtent = niceExtent; - }; - - LogScale.prototype.calcNiceExtent = function (opt) { - _super.prototype.calcNiceExtent.call(this, opt); - - this._fixMin = opt.fixMin; - this._fixMax = opt.fixMax; - }; - - LogScale.prototype.contain = function (val) { - val = mathLog(val) / mathLog(this.base); - return _super.prototype.contain.call(this, val); - }; - - LogScale.prototype.normalize = function (val) { - val = mathLog(val) / mathLog(this.base); - return _super.prototype.normalize.call(this, val); - }; - - LogScale.prototype.scale = function (val) { - val = _super.prototype.scale.call(this, val); - return mathPow(this.base, val); - }; - - LogScale.prototype.setBreaksFromOption = function (breakOptionList) { - { - return; - } - }; - - LogScale.type = 'log'; - return LogScale; - }(IntervalScale); - - function fixRoundingError(val, originalVal) { - return fixRound(val, getPrecision(originalVal)); - } - - Scale.registerClass(LogScale); - - var ScaleRawExtentInfo = - /** @class */ - function () { - function ScaleRawExtentInfo(scale, model, // Usually: data extent from all series on this axis. - originalExtent) { - this._prepareParams(scale, model, originalExtent); - } - /** - * Parameters depending on outside (like model, user callback) - * are prepared and fixed here. - */ - - - ScaleRawExtentInfo.prototype._prepareParams = function (scale, model, // Usually: data extent from all series on this axis. - dataExtent) { - if (dataExtent[1] < dataExtent[0]) { - dataExtent = [NaN, NaN]; - } - - this._dataMin = dataExtent[0]; - this._dataMax = dataExtent[1]; - var isOrdinal = this._isOrdinal = scale.type === 'ordinal'; - this._needCrossZero = scale.type === 'interval' && model.getNeedCrossZero && model.getNeedCrossZero(); - var axisMinValue = model.get('min', true); - - if (axisMinValue == null) { - axisMinValue = model.get('startValue', true); - } - - var modelMinRaw = this._modelMinRaw = axisMinValue; - - if (isFunction(modelMinRaw)) { - // This callback always provides users the full data extent (before data is filtered). - this._modelMinNum = parseAxisModelMinMax(scale, modelMinRaw({ - min: dataExtent[0], - max: dataExtent[1] - })); - } else if (modelMinRaw !== 'dataMin') { - this._modelMinNum = parseAxisModelMinMax(scale, modelMinRaw); - } - - var modelMaxRaw = this._modelMaxRaw = model.get('max', true); - - if (isFunction(modelMaxRaw)) { - // This callback always provides users the full data extent (before data is filtered). - this._modelMaxNum = parseAxisModelMinMax(scale, modelMaxRaw({ - min: dataExtent[0], - max: dataExtent[1] - })); - } else if (modelMaxRaw !== 'dataMax') { - this._modelMaxNum = parseAxisModelMinMax(scale, modelMaxRaw); - } - - if (isOrdinal) { - // FIXME: there is a flaw here: if there is no "block" data processor like `dataZoom`, - // and progressive rendering is using, here the category result might just only contain - // the processed chunk rather than the entire result. - this._axisDataLen = model.getCategories().length; - } else { - var boundaryGap = model.get('boundaryGap'); - var boundaryGapArr = isArray(boundaryGap) ? boundaryGap : [boundaryGap || 0, boundaryGap || 0]; - - if (typeof boundaryGapArr[0] === 'boolean' || typeof boundaryGapArr[1] === 'boolean') { - { - console.warn('Boolean type for boundaryGap is only ' + 'allowed for ordinal axis. Please use string in ' + 'percentage instead, e.g., "20%". Currently, ' + 'boundaryGap is set to be 0.'); - } - this._boundaryGapInner = [0, 0]; - } else { - this._boundaryGapInner = [parsePercent$1(boundaryGapArr[0], 1), parsePercent$1(boundaryGapArr[1], 1)]; - } - } - }; - /** - * Calculate extent by prepared parameters. - * This method has no external dependency and can be called duplicatedly, - * getting the same result. - * If parameters changed, should call this method to recalcuate. - */ - - - ScaleRawExtentInfo.prototype.calculate = function () { - // Notice: When min/max is not set (that is, when there are null/undefined, - // which is the most common case), these cases should be ensured: - // (1) For 'ordinal', show all axis.data. - // (2) For others: - // + `boundaryGap` is applied (if min/max set, boundaryGap is - // disabled). - // + If `needCrossZero`, min/max should be zero, otherwise, min/max should - // be the result that originalExtent enlarged by boundaryGap. - // (3) If no data, it should be ensured that `scale.setBlank` is set. - var isOrdinal = this._isOrdinal; - var dataMin = this._dataMin; - var dataMax = this._dataMax; - var axisDataLen = this._axisDataLen; - var boundaryGapInner = this._boundaryGapInner; - var span = !isOrdinal ? dataMax - dataMin || Math.abs(dataMin) : null; // Currently if a `'value'` axis model min is specified as 'dataMin'/'dataMax', - // `boundaryGap` will not be used. It's the different from specifying as `null`/`undefined`. - - var min = this._modelMinRaw === 'dataMin' ? dataMin : this._modelMinNum; - var max = this._modelMaxRaw === 'dataMax' ? dataMax : this._modelMaxNum; // If `_modelMinNum`/`_modelMaxNum` is `null`/`undefined`, should not be fixed. - - var minFixed = min != null; - var maxFixed = max != null; - - if (min == null) { - min = isOrdinal ? axisDataLen ? 0 : NaN : dataMin - boundaryGapInner[0] * span; - } - - if (max == null) { - max = isOrdinal ? axisDataLen ? axisDataLen - 1 : NaN : dataMax + boundaryGapInner[1] * span; - } - - (min == null || !isFinite(min)) && (min = NaN); - (max == null || !isFinite(max)) && (max = NaN); - var isBlank = eqNaN(min) || eqNaN(max) || isOrdinal && !axisDataLen; // If data extent modified, need to recalculated to ensure cross zero. - - if (this._needCrossZero) { - // Axis is over zero and min is not set - if (min > 0 && max > 0 && !minFixed) { - min = 0; // minFixed = true; - } // Axis is under zero and max is not set - - - if (min < 0 && max < 0 && !maxFixed) { - max = 0; // maxFixed = true; - } // PENDING: - // When `needCrossZero` and all data is positive/negative, should it be ensured - // that the results processed by boundaryGap are positive/negative? - // If so, here `minFixed`/`maxFixed` need to be set. - - } - - var determinedMin = this._determinedMin; - var determinedMax = this._determinedMax; - - if (determinedMin != null) { - min = determinedMin; - minFixed = true; - } - - if (determinedMax != null) { - max = determinedMax; - maxFixed = true; - } // Ensure min/max be finite number or NaN here. (not to be null/undefined) - // `NaN` means min/max axis is blank. - - - return { - min: min, - max: max, - minFixed: minFixed, - maxFixed: maxFixed, - isBlank: isBlank - }; - }; - - ScaleRawExtentInfo.prototype.modifyDataMinMax = function (minMaxName, val) { - { - assert(!this.frozen); - } - this[DATA_MIN_MAX_ATTR[minMaxName]] = val; - }; - - ScaleRawExtentInfo.prototype.setDeterminedMinMax = function (minMaxName, val) { - var attr = DETERMINED_MIN_MAX_ATTR[minMaxName]; - { - assert(!this.frozen // Earse them usually means logic flaw. - && this[attr] == null); - } - this[attr] = val; - }; - - ScaleRawExtentInfo.prototype.freeze = function () { - // @ts-ignore - this.frozen = true; - }; - - return ScaleRawExtentInfo; - }(); - - var DETERMINED_MIN_MAX_ATTR = { - min: '_determinedMin', - max: '_determinedMax' - }; - var DATA_MIN_MAX_ATTR = { - min: '_dataMin', - max: '_dataMax' - }; - /** - * Get scale min max and related info only depends on model settings. - * This method can be called after coordinate system created. - * For example, in data processing stage. - * - * Scale extent info probably be required multiple times during a workflow. - * For example: - * (1) `dataZoom` depends it to get the axis extent in "100%" state. - * (2) `processor/extentCalculator` depends it to make sure whether axis extent is specified. - * (3) `coordSys.update` use it to finally decide the scale extent. - * But the callback of `min`/`max` should not be called multiple times. - * The code below should not be implemented repeatedly either. - * So we cache the result in the scale instance, which will be recreated at the beginning - * of the workflow (because `scale` instance will be recreated each round of the workflow). - */ - - function ensureScaleRawExtentInfo(scale, model, // Usually: data extent from all series on this axis. - originalExtent) { - // Do not permit to recreate. - var rawExtentInfo = scale.rawExtentInfo; - - if (rawExtentInfo) { - return rawExtentInfo; - } - - rawExtentInfo = new ScaleRawExtentInfo(scale, model, originalExtent); // @ts-ignore - - scale.rawExtentInfo = rawExtentInfo; - return rawExtentInfo; - } - - function parseAxisModelMinMax(scale, minMax) { - return minMax == null ? null : eqNaN(minMax) ? NaN : scale.parse(minMax); - } - /** - * Get axis scale extent before niced. - * Item of returned array can only be number (including Infinity and NaN). - * - * Caution: - * Precondition of calling this method: - * The scale extent has been initialized using series data extent via - * `scale.setExtent` or `scale.unionExtentFromData`; - */ - - - function getScaleExtent(scale, model) { - var scaleType = scale.type; - var rawExtentResult = ensureScaleRawExtentInfo(scale, model, scale.getExtent()).calculate(); - scale.setBlank(rawExtentResult.isBlank); - var min = rawExtentResult.min; - var max = rawExtentResult.max; // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis - // is base axis - // FIXME - // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly. - // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent? - // Should not depend on series type `bar`? - // (3) Fix that might overlap when using dataZoom. - // (4) Consider other chart types using `barGrid`? - // See #6728, #4862, `test/bar-overflow-time-plot.html` - - var ecModel = model.ecModel; - - if (ecModel && scaleType === 'time' - /* || scaleType === 'interval' */ - ) { - var barSeriesModels = prepareLayoutBarSeries('bar', ecModel); - var isBaseAxisAndHasBarSeries_1 = false; - each$4(barSeriesModels, function (seriesModel) { - isBaseAxisAndHasBarSeries_1 = isBaseAxisAndHasBarSeries_1 || seriesModel.getBaseAxis() === model.axis; - }); - - if (isBaseAxisAndHasBarSeries_1) { - // Calculate placement of bars on axis. TODO should be decoupled - // with barLayout - var barWidthAndOffset = makeColumnLayout(barSeriesModels); // Adjust axis min and max to account for overflow - - var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset); - min = adjustedScale.min; - max = adjustedScale.max; - } - } - - return { - extent: [min, max], - // "fix" means "fixed", the value should not be - // changed in the subsequent steps. - fixMin: rawExtentResult.minFixed, - fixMax: rawExtentResult.maxFixed - }; - } - - function adjustScaleForOverflow(min, max, model, // Only support cartesian coord yet. - barWidthAndOffset) { - // Get Axis Length - var axisExtent = model.axis.getExtent(); - var axisLength = Math.abs(axisExtent[1] - axisExtent[0]); // Get bars on current base axis and calculate min and max overflow - - var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis); - - if (barsOnCurrentAxis === undefined) { - return { - min: min, - max: max - }; - } - - var minOverflow = Infinity; - each$4(barsOnCurrentAxis, function (item) { - minOverflow = Math.min(item.offset, minOverflow); - }); - var maxOverflow = -Infinity; - each$4(barsOnCurrentAxis, function (item) { - maxOverflow = Math.max(item.offset + item.width, maxOverflow); - }); - minOverflow = Math.abs(minOverflow); - maxOverflow = Math.abs(maxOverflow); - var totalOverFlow = minOverflow + maxOverflow; // Calculate required buffer based on old range and overflow - - var oldRange = max - min; - var oldRangePercentOfNew = 1 - (minOverflow + maxOverflow) / axisLength; - var overflowBuffer = oldRange / oldRangePercentOfNew - oldRange; - max += overflowBuffer * (maxOverflow / totalOverFlow); - min -= overflowBuffer * (minOverflow / totalOverFlow); - return { - min: min, - max: max - }; - } // Precondition of calling this method: - // The scale extent has been initialized using series data extent via - // `scale.setExtent` or `scale.unionExtentFromData`; - - - function niceScaleExtent(scale, inModel) { - var model = inModel; - var extentInfo = getScaleExtent(scale, model); - var extent = extentInfo.extent; - var splitNumber = model.get('splitNumber'); - - if (scale instanceof LogScale) { - scale.base = model.get('logBase'); - } - - var scaleType = scale.type; - var interval = model.get('interval'); - var isIntervalOrTime = scaleType === 'interval' || scaleType === 'time'; - scale.setBreaksFromOption(retrieveAxisBreaksOption(model)); - scale.setExtent(extent[0], extent[1]); - scale.calcNiceExtent({ - splitNumber: splitNumber, - fixMin: extentInfo.fixMin, - fixMax: extentInfo.fixMax, - minInterval: isIntervalOrTime ? model.get('minInterval') : null, - maxInterval: isIntervalOrTime ? model.get('maxInterval') : null - }); // If some one specified the min, max. And the default calculated interval - // is not good enough. He can specify the interval. It is often appeared - // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard - // to be 60. - // FIXME - - if (interval != null) { - scale.setInterval && scale.setInterval(interval); - } - } - /** - * @param axisType Default retrieve from model.type - */ - - - function createScaleByModel(model, axisType) { - axisType = axisType || model.get('type'); - - if (axisType) { - switch (axisType) { - // Buildin scale - case 'category': - return new OrdinalScale({ - ordinalMeta: model.getOrdinalMeta ? model.getOrdinalMeta() : model.getCategories(), - extent: [Infinity, -Infinity] - }); - - case 'time': - return new TimeScale({ - locale: model.ecModel.getLocaleModel(), - useUTC: model.ecModel.get('useUTC') - }); - - default: - // case 'value'/'interval', 'log', or others. - return new (Scale.getClass(axisType) || IntervalScale)(); - } - } - } - /** - * Check if the axis cross 0 - */ - - - function ifAxisCrossZero(axis) { - var dataExtent = axis.scale.getExtent(); - var min = dataExtent[0]; - var max = dataExtent[1]; - return !(min > 0 && max > 0 || min < 0 && max < 0); - } - /** - * @param axis - * @return Label formatter function. - * param: {number} tickValue, - * param: {number} idx, the index in all ticks. - * If category axis, this param is not required. - * return: {string} label string. - */ - - - function makeLabelFormatter(axis) { - var labelFormatter = axis.getLabelModel().get('formatter'); - - if (axis.type === 'time') { - var parsed_1 = parseTimeAxisLabelFormatter(labelFormatter); - return function (tick, idx) { - return axis.scale.getFormattedLabel(tick, idx, parsed_1); - }; - } else if (isString(labelFormatter)) { - return function (tick) { - // For category axis, get raw value; for numeric axis, - // get formatted label like '1,333,444'. - var label = axis.scale.getLabel(tick); - var text = labelFormatter.replace('{value}', label != null ? label : ''); - return text; - }; - } else if (isFunction(labelFormatter)) { - if (axis.type === 'category') { - return function (tick, idx) { - // The original intention of `idx` is "the index of the tick in all ticks". - // But the previous implementation of category axis do not consider the - // `axisLabel.interval`, which cause that, for example, the `interval` is - // `1`, then the ticks "name5", "name7", "name9" are displayed, where the - // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep - // the definition here for back compatibility. - return labelFormatter(getAxisRawValue(axis, tick), tick.value - axis.scale.getExtent()[0], null // Using `null` just for backward compat. - ); - }; - } - - var scaleBreakHelper_1 = getScaleBreakHelper(); - return function (tick, idx) { - // Using `null` just for backward compat. It's been found that in the `test/axis-customTicks.html`, - // there is a formatter `function (value, index, revers = true) { ... }`. Although the third param - // `revers` is incorrect and always `null`, changing it might introduce a breaking change. - var extra = null; - - if (scaleBreakHelper_1) { - extra = scaleBreakHelper_1.makeAxisLabelFormatterParamBreak(extra, tick["break"]); - } - - return labelFormatter(getAxisRawValue(axis, tick), idx, extra); - }; - } else { - return function (tick) { - return axis.scale.getLabel(tick); - }; - } - } - - function getAxisRawValue(axis, tick) { - // In category axis with data zoom, tick is not the original - // index of axis.data. So tick should not be exposed to user - // in category axis. - return axis.type === 'category' ? axis.scale.getLabel(tick) : tick.value; - } - /** - * @param model axisLabelModel or axisTickModel - * @return {number|String} Can be null|'auto'|number|function - */ - - - function getOptionCategoryInterval(model) { - var interval = model.get('interval'); - return interval == null ? 'auto' : interval; - } - /** - * Set `categoryInterval` as 0 implicitly indicates that - * show all labels regardless of overlap. - * @param {Object} axis axisModel.axis - */ - - - function shouldShowAllLabels(axis) { - return axis.type === 'category' && getOptionCategoryInterval(axis.getLabelModel()) === 0; - } - - function getDataDimensionsOnAxis(data, axisDim) { - // Remove duplicated dat dimensions caused by `getStackedDimension`. - var dataDimMap = {}; // Currently `mapDimensionsAll` will contain stack result dimension ('__\0ecstackresult'). - // PENDING: is it reasonable? Do we need to remove the original dim from "coord dim" since - // there has been stacked result dim? - - each$4(data.mapDimensionsAll(axisDim), function (dataDim) { - // For example, the extent of the original dimension - // is [0.1, 0.5], the extent of the `stackResultDimension` - // is [7, 9], the final extent should NOT include [0.1, 0.5], - // because there is no graphic corresponding to [0.1, 0.5]. - // See the case in `test/area-stack.html` `main1`, where area line - // stack needs `yAxis` not start from 0. - dataDimMap[getStackedDimension(data, dataDim)] = true; - }); - return keys(dataDimMap); - } - - function isNameLocationCenter(nameLocation) { - return nameLocation === 'middle' || nameLocation === 'center'; - } - - function shouldAxisShow(axisModel) { - return axisModel.getShallow('show'); - } - - function retrieveAxisBreaksOption(model) { - var option = model.get('breaks', true); - - if (option != null) { - { - { - error('Must `import {AxisBreak} from "echarts/features.js"; use(AxisBreak);` first if using breaks option.'); - } - return undefined; - } - } - } - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * AUTO-GENERATED FILE. DO NOT MODIFY. - */ - - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - // eslint-disable-next-line @typescript-eslint/no-unused-vars - - - var AxisModelCommonMixin = - /** @class */ - function () { - function AxisModelCommonMixin() {} - - AxisModelCommonMixin.prototype.getNeedCrossZero = function () { - var option = this.option; - return !option.scale; - }; - /** - * Should be implemented by each axis model if necessary. - * @return coordinate system model - */ - - - AxisModelCommonMixin.prototype.getCoordSysModel = function () { - return; - }; - - return AxisModelCommonMixin; - }(); - /** - * Create a multi dimension List structure from seriesModel. - */ - - - function createList$1(seriesModel) { - return createSeriesData(null, seriesModel); - } - - var dataStack = { - isDimensionStacked: isDimensionStacked, - enableDataStack: enableDataStack, - getStackedDimension: getStackedDimension - }; - /** - * Create scale - * @param {Array.} dataExtent - * @param {Object|module:echarts/Model} option If `optoin.type` - * is secified, it can only be `'value'` currently. - */ - - function createScale(dataExtent, option) { - var axisModel = option; - - if (!(option instanceof Model)) { - axisModel = new Model(option); // FIXME - // Currently AxisModelCommonMixin has nothing to do with the - // the requirements of `axisHelper.createScaleByModel`. For - // example the methods `getCategories` and `getOrdinalMeta` - // are required for `'category'` axis, and ecModel is required - // for `'time'` axis. But occasionally echarts-gl happened - // to only use `'value'` axis. - // zrUtil.mixin(axisModel, AxisModelCommonMixin); - } - - var scale = createScaleByModel(axisModel); - scale.setExtent(dataExtent[0], dataExtent[1]); - niceScaleExtent(scale, axisModel); - return scale; - } - /** - * Mixin common methods to axis model, - * - * Include methods - * `getFormattedLabels() => Array.` - * `getCategories() => Array.` - * `getMin(origin: boolean) => number` - * `getMax(origin: boolean) => number` - * `getNeedCrossZero() => boolean` - */ - - - function mixinAxisModelCommonMethods(Model) { - mixin(Model, AxisModelCommonMixin); - } - - function createTextStyle(textStyleModel, opts) { - opts = opts || {}; - return createTextStyle$1(textStyleModel, null, null, opts.state !== 'normal'); - } - - var helper = /*#__PURE__*/Object.freeze({ - __proto__: null, - createDimensions: createDimensions, - createList: createList$1, - createScale: createScale, - createSymbol: createSymbol, - createTextStyle: createTextStyle, - dataStack: dataStack, - enableHoverEmphasis: enableHoverEmphasis, - getECData: getECData, - getLayoutRect: getLayoutRect, - mixinAxisModelCommonMethods: mixinAxisModelCommonMethods - }); - var extensions = []; - var extensionRegisters = { - registerPreprocessor: registerPreprocessor, - registerProcessor: registerProcessor, - registerPostInit: registerPostInit, - registerPostUpdate: registerPostUpdate, - registerUpdateLifecycle: registerUpdateLifecycle, - registerAction: registerAction, - registerCoordinateSystem: registerCoordinateSystem, - registerLayout: registerLayout, - registerVisual: registerVisual, - registerTransform: registerTransform, - registerLoading: registerLoading, - registerMap: registerMap, - registerImpl: registerImpl, - PRIORITY: PRIORITY, - ComponentModel: ComponentModel, - ComponentView: ComponentView, - SeriesModel: SeriesModel, - ChartView: ChartView, - // TODO Use ComponentModel and SeriesModel instead of Constructor - registerComponentModel: function (ComponentModelClass) { - ComponentModel.registerClass(ComponentModelClass); - }, - registerComponentView: function (ComponentViewClass) { - ComponentView.registerClass(ComponentViewClass); - }, - registerSeriesModel: function (SeriesModelClass) { - SeriesModel.registerClass(SeriesModelClass); - }, - registerChartView: function (ChartViewClass) { - ChartView.registerClass(ChartViewClass); - }, - registerCustomSeries: function (seriesType, renderItem) {}, - registerSubTypeDefaulter: function (componentType, defaulter) { - ComponentModel.registerSubTypeDefaulter(componentType, defaulter); - }, - registerPainter: function (painterType, PainterCtor) { - registerPainter(painterType, PainterCtor); - } - }; - - function use(ext) { - if (isArray(ext)) { - // use([ChartLine, ChartBar]); - each$4(ext, function (singleExt) { - use(singleExt); - }); - return; - } - - if (indexOf(extensions, ext) >= 0) { - return; - } - - extensions.push(ext); - - if (isFunction(ext)) { - ext = { - install: ext - }; - } - - ext.install(extensionRegisters); - } - - var EPSILON = 1e-8; - - function isAroundEqual(a, b) { - return Math.abs(a - b) < EPSILON; - } - - function contain(points, x, y) { - var w = 0; - var p = points[0]; - - if (!p) { - return false; - } - - for (var i = 1; i < points.length; i++) { - var p2 = points[i]; - w += windingLine(p[0], p[1], p2[0], p2[1], x, y); - p = p2; - } - - var p0 = points[0]; - - if (!isAroundEqual(p[0], p0[0]) || !isAroundEqual(p[1], p0[1])) { - w += windingLine(p[0], p[1], p0[0], p0[1], x, y); - } - - return w !== 0; - } - - var TMP_TRANSFORM = []; - - function transformPoints(points, transform) { - for (var p = 0; p < points.length; p++) { - applyTransform$1(points[p], points[p], transform); - } - } - - function updateBBoxFromPoints(points, min, max, projection) { - for (var i = 0; i < points.length; i++) { - var p = points[i]; - - if (projection) { - // projection may return null point. - p = projection.project(p); - } - - if (p && isFinite(p[0]) && isFinite(p[1])) { - min$1(min, min, p); - max$1(max, max, p); - } - } - } - - function centroid(points) { - var signedArea = 0; - var cx = 0; - var cy = 0; - var len = points.length; - var x0 = points[len - 1][0]; - var y0 = points[len - 1][1]; // Polygon should been closed. - - for (var i = 0; i < len; i++) { - var x1 = points[i][0]; - var y1 = points[i][1]; - var a = x0 * y1 - x1 * y0; - signedArea += a; - cx += (x0 + x1) * a; - cy += (y0 + y1) * a; - x0 = x1; - y0 = y1; - } - - return signedArea ? [cx / signedArea / 3, cy / signedArea / 3, signedArea] : [points[0][0] || 0, points[0][1] || 0]; - } - - var Region = - /** @class */ - function () { - function Region(name) { - this.name = name; - } - - Region.prototype.setCenter = function (center) { - this._center = center; - }; - /** - * Get center point in data unit. That is, - * for GeoJSONRegion, the unit is lat/lng, - * for GeoSVGRegion, the unit is SVG local coord. - */ - - - Region.prototype.getCenter = function () { - var center = this._center; - - if (!center) { - // In most cases there are no need to calculate this center. - // So calculate only when called. - center = this._center = this.calcCenter(); - } - - return center; - }; - - return Region; - }(); - - var GeoJSONPolygonGeometry = - /** @class */ - function () { - function GeoJSONPolygonGeometry(exterior, interiors) { - this.type = 'polygon'; - this.exterior = exterior; - this.interiors = interiors; - } - - return GeoJSONPolygonGeometry; - }(); - - var GeoJSONLineStringGeometry = - /** @class */ - function () { - function GeoJSONLineStringGeometry(points) { - this.type = 'linestring'; - this.points = points; - } - - return GeoJSONLineStringGeometry; - }(); - - var GeoJSONRegion = - /** @class */ - function (_super) { - __extends(GeoJSONRegion, _super); - - function GeoJSONRegion(name, geometries, cp) { - var _this = _super.call(this, name) || this; - - _this.type = 'geoJSON'; - _this.geometries = geometries; - _this._center = cp && [cp[0], cp[1]]; - return _this; - } - - GeoJSONRegion.prototype.calcCenter = function () { - var geometries = this.geometries; - var largestGeo; - var largestGeoSize = 0; - - for (var i = 0; i < geometries.length; i++) { - var geo = geometries[i]; - var exterior = geo.exterior; // Simple trick to use points count instead of polygon area as region size. - // Ignore linestring - - var size = exterior && exterior.length; - - if (size > largestGeoSize) { - largestGeo = geo; - largestGeoSize = size; - } - } - - if (largestGeo) { - return centroid(largestGeo.exterior); - } // from bounding rect by default. - - - var rect = this.getBoundingRect(); - return [rect.x + rect.width / 2, rect.y + rect.height / 2]; - }; - - GeoJSONRegion.prototype.getBoundingRect = function (projection) { - var rect = this._rect; // Always recalculate if using projection. - - if (rect && !projection) { - return rect; - } - - var min = [Infinity, Infinity]; - var max = [-Infinity, -Infinity]; - var geometries = this.geometries; - each$4(geometries, function (geo) { - if (geo.type === 'polygon') { - // Doesn't consider hole - updateBBoxFromPoints(geo.exterior, min, max, projection); - } else { - each$4(geo.points, function (points) { - updateBBoxFromPoints(points, min, max, projection); - }); - } - }); // Normalie invalid bounding. - - if (!(isFinite(min[0]) && isFinite(min[1]) && isFinite(max[0]) && isFinite(max[1]))) { - min[0] = min[1] = max[0] = max[1] = 0; - } - - rect = new BoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]); - - if (!projection) { - this._rect = rect; - } - - return rect; - }; - - GeoJSONRegion.prototype.contain = function (coord) { - var rect = this.getBoundingRect(); - var geometries = this.geometries; - - if (!rect.contain(coord[0], coord[1])) { - return false; - } - - loopGeo: for (var i = 0, len = geometries.length; i < len; i++) { - var geo = geometries[i]; // Only support polygon. - - if (geo.type !== 'polygon') { - continue; - } - - var exterior = geo.exterior; - var interiors = geo.interiors; - - if (contain(exterior, coord[0], coord[1])) { - // Not in the region if point is in the hole. - for (var k = 0; k < (interiors ? interiors.length : 0); k++) { - if (contain(interiors[k], coord[0], coord[1])) { - continue loopGeo; - } - } - - return true; - } - } - - return false; - }; - /** - * Transform the raw coords to target bounding. - * @param x - * @param y - * @param width - * @param height - */ - - - GeoJSONRegion.prototype.transformTo = function (x, y, width, height) { - var rect = this.getBoundingRect(); - var aspect = rect.width / rect.height; - - if (!width) { - width = aspect * height; - } else if (!height) { - height = width / aspect; - } - - var target = new BoundingRect(x, y, width, height); - var transform = rect.calculateTransform(target); - var geometries = this.geometries; - - for (var i = 0; i < geometries.length; i++) { - var geo = geometries[i]; - - if (geo.type === 'polygon') { - transformPoints(geo.exterior, transform); - each$4(geo.interiors, function (interior) { - transformPoints(interior, transform); - }); - } else { - each$4(geo.points, function (points) { - transformPoints(points, transform); - }); - } - } - - rect = this._rect; - rect.copy(target); // Update center - - this._center = [rect.x + rect.width / 2, rect.y + rect.height / 2]; - }; - - GeoJSONRegion.prototype.cloneShallow = function (name) { - name == null && (name = this.name); - var newRegion = new GeoJSONRegion(name, this.geometries, this._center); - newRegion._rect = this._rect; - newRegion.transformTo = null; // Simply avoid to be called. - - return newRegion; - }; - - return GeoJSONRegion; - }(Region); - /** @class */ - - - (function (_super) { - __extends(GeoSVGRegion, _super); - - function GeoSVGRegion(name, elOnlyForCalculate) { - var _this = _super.call(this, name) || this; - - _this.type = 'geoSVG'; - _this._elOnlyForCalculate = elOnlyForCalculate; - return _this; - } - - GeoSVGRegion.prototype.calcCenter = function () { - var el = this._elOnlyForCalculate; - var rect = el.getBoundingRect(); - var center = [rect.x + rect.width / 2, rect.y + rect.height / 2]; - var mat = identity(TMP_TRANSFORM); - var target = el; - - while (target && !target.isGeoSVGGraphicRoot) { - mul(mat, target.getLocalTransform(), mat); - target = target.parent; - } - - invert(mat, mat); - applyTransform$1(center, center, mat); - return center; - }; - - return GeoSVGRegion; - })(Region); - - function decode(json) { - if (!json.UTF8Encoding) { - return json; - } - - var jsonCompressed = json; - var encodeScale = jsonCompressed.UTF8Scale; - - if (encodeScale == null) { - encodeScale = 1024; - } - - var features = jsonCompressed.features; - each$4(features, function (feature) { - var geometry = feature.geometry; - var encodeOffsets = geometry.encodeOffsets; - var coordinates = geometry.coordinates; // Geometry may be appeded manually in the script after json loaded. - // In this case this geometry is usually not encoded. - - if (!encodeOffsets) { - return; - } - - switch (geometry.type) { - case 'LineString': - geometry.coordinates = decodeRing(coordinates, encodeOffsets, encodeScale); - break; - - case 'Polygon': - decodeRings(coordinates, encodeOffsets, encodeScale); - break; - - case 'MultiLineString': - decodeRings(coordinates, encodeOffsets, encodeScale); - break; - - case 'MultiPolygon': - each$4(coordinates, function (rings, idx) { - return decodeRings(rings, encodeOffsets[idx], encodeScale); - }); - } - }); // Has been decoded - - jsonCompressed.UTF8Encoding = false; - return jsonCompressed; - } - - function decodeRings(rings, encodeOffsets, encodeScale) { - for (var c = 0; c < rings.length; c++) { - rings[c] = decodeRing(rings[c], encodeOffsets[c], encodeScale); - } - } - - function decodeRing(coordinate, encodeOffsets, encodeScale) { - var result = []; - var prevX = encodeOffsets[0]; - var prevY = encodeOffsets[1]; - - for (var i = 0; i < coordinate.length; i += 2) { - var x = coordinate.charCodeAt(i) - 64; - var y = coordinate.charCodeAt(i + 1) - 64; // ZigZag decoding - - x = x >> 1 ^ -(x & 1); - y = y >> 1 ^ -(y & 1); // Delta deocding - - x += prevX; - y += prevY; - prevX = x; - prevY = y; // Dequantize - - result.push([x / encodeScale, y / encodeScale]); - } - - return result; - } - - function parseGeoJSON(geoJson, nameProperty) { - geoJson = decode(geoJson); - return map$1(filter(geoJson.features, function (featureObj) { - // Output of mapshaper may have geometry null - return featureObj.geometry && featureObj.properties && featureObj.geometry.coordinates.length > 0; - }), function (featureObj) { - var properties = featureObj.properties; - var geo = featureObj.geometry; - var geometries = []; - - switch (geo.type) { - case 'Polygon': - var coordinates = geo.coordinates; // According to the GeoJSON specification. - // First must be exterior, and the rest are all interior(holes). - - geometries.push(new GeoJSONPolygonGeometry(coordinates[0], coordinates.slice(1))); - break; - - case 'MultiPolygon': - each$4(geo.coordinates, function (item) { - if (item[0]) { - geometries.push(new GeoJSONPolygonGeometry(item[0], item.slice(1))); - } - }); - break; - - case 'LineString': - geometries.push(new GeoJSONLineStringGeometry([geo.coordinates])); - break; - - case 'MultiLineString': - geometries.push(new GeoJSONLineStringGeometry(geo.coordinates)); - } - - var region = new GeoJSONRegion(properties[nameProperty || 'name'], geometries, properties.cp); - region.properties = properties; - return region; - }); - } - - var number = /*#__PURE__*/Object.freeze({ - __proto__: null, - MAX_SAFE_INTEGER: MAX_SAFE_INTEGER, - asc: asc, - getPercentWithPrecision: getPercentWithPrecision, - getPixelPrecision: getPixelPrecision, - getPrecision: getPrecision, - getPrecisionSafe: getPrecisionSafe, - isNumeric: isNumeric, - isRadianAroundZero: isRadianAroundZero, - linearMap: linearMap, - nice: nice, - numericToNumber: numericToNumber, - parseDate: parseDate, - parsePercent: parsePercent, - quantile: quantile, - quantity: quantity, - quantityExponent: quantityExponent, - reformIntervals: reformIntervals, - remRadian: remRadian, - round: round$1 - }); - var time = /*#__PURE__*/Object.freeze({ - __proto__: null, - format: format$1, - parse: parseDate, - roundTime: roundTime - }); - var graphic = /*#__PURE__*/Object.freeze({ - __proto__: null, - Arc: Arc, - BezierCurve: BezierCurve, - BoundingRect: BoundingRect, - Circle: Circle, - CompoundPath: CompoundPath, - Ellipse: Ellipse, - Group: Group$2, - Image: ZRImage, - IncrementalDisplayable: IncrementalDisplayable, - Line: Line, - LinearGradient: LinearGradient, - Polygon: Polygon, - Polyline: Polyline, - RadialGradient: RadialGradient, - Rect: Rect, - Ring: Ring, - Sector: Sector, - Text: ZRText, - clipPointsByRect: clipPointsByRect, - clipRectByRect: clipRectByRect, - createIcon: createIcon, - extendPath: extendPath, - extendShape: extendShape, - getShapeClass: getShapeClass, - getTransform: getTransform, - initProps: initProps, - makeImage: makeImage, - makePath: makePath, - mergePath: mergePath, - registerShape: registerShape, - resizePath: resizePath, - updateProps: updateProps$1 - }); - var format = /*#__PURE__*/Object.freeze({ - __proto__: null, - addCommas: addCommas, - capitalFirst: capitalFirst, - encodeHTML: encodeHTML, - formatTime: formatTime, - formatTpl: formatTpl, - getTextRect: getTextRect, - getTooltipMarker: getTooltipMarker, - normalizeCssArray: normalizeCssArray, - toCamelCase: toCamelCase, - truncateText: truncateText - }); - var util = /*#__PURE__*/Object.freeze({ - __proto__: null, - bind: bind$1, - clone: clone$3, - curry: curry$1, - defaults: defaults, - each: each$4, - extend: extend, - filter: filter, - indexOf: indexOf, - inherits: inherits, - isArray: isArray, - isFunction: isFunction, - isObject: isObject$2, - isString: isString, - map: map$1, - merge: merge, - reduce: reduce - }); - var modelInner = makeInner(); - var axisInner = makeInner(); - var AxisTickLabelComputingKind = { - estimate: 1, - determine: 2 - }; - - function createAxisLabelsComputingContext(kind) { - return { - out: { - noPxChangeTryDetermine: [] - }, - kind: kind - }; - } - - function tickValuesToNumbers(axis, values) { - var nums = map$1(values, function (val) { - return axis.scale.parse(val); - }); - - if (axis.type === 'time' && nums.length > 0) { - // Time axis needs duplicate first/last tick (see TimeScale.getTicks()) - // The first and last tick/label don't get drawn - nums.sort(); - nums.unshift(nums[0]); - nums.push(nums[nums.length - 1]); - } - - return nums; - } - - function createAxisLabels(axis, ctx) { - var custom = axis.getLabelModel().get('customValues'); - - if (custom) { - var labelFormatter_1 = makeLabelFormatter(axis); - var extent_1 = axis.scale.getExtent(); - var tickNumbers = tickValuesToNumbers(axis, custom); - var ticks = filter(tickNumbers, function (val) { - return val >= extent_1[0] && val <= extent_1[1]; - }); - return { - labels: map$1(ticks, function (numval) { - var tick = { - value: numval - }; - return { - formattedLabel: labelFormatter_1(tick), - rawLabel: axis.scale.getLabel(tick), - tickValue: numval, - time: undefined, - "break": undefined - }; - }) - }; - } // Only ordinal scale support tick interval - - - return axis.type === 'category' ? makeCategoryLabels(axis, ctx) : makeRealNumberLabels(axis); - } - /** - * @param tickModel For example, can be axisTick, splitLine, splitArea. - */ - - - function createAxisTicks(axis, tickModel, opt) { - var custom = axis.getTickModel().get('customValues'); - - if (custom) { - var extent_2 = axis.scale.getExtent(); - var tickNumbers = tickValuesToNumbers(axis, custom); - return { - ticks: filter(tickNumbers, function (val) { - return val >= extent_2[0] && val <= extent_2[1]; - }) - }; - } // Only ordinal scale support tick interval - - - return axis.type === 'category' ? makeCategoryTicks(axis, tickModel) : { - ticks: map$1(axis.scale.getTicks(opt), function (tick) { - return tick.value; - }) - }; - } - - function makeCategoryLabels(axis, ctx) { - var labelModel = axis.getLabelModel(); - var result = makeCategoryLabelsActually(axis, labelModel, ctx); - return !labelModel.get('show') || axis.scale.isBlank() ? { - labels: [] - } : result; - } - - function makeCategoryLabelsActually(axis, labelModel, ctx) { - var labelsCache = ensureCategoryLabelCache(axis); - var optionLabelInterval = getOptionCategoryInterval(labelModel); - var isEstimate = ctx.kind === AxisTickLabelComputingKind.estimate; // In AxisTickLabelComputingKind.estimate, the result likely varies during a single - // pass of ec main process,due to the change of axisExtent, and will not be shared with - // splitLine. Therefore no cache is used. - - if (!isEstimate) { - // PENDING: check necessary? - var result_1 = axisCacheGet(labelsCache, optionLabelInterval); - - if (result_1) { - return result_1; - } - } - - var labels; - var numericLabelInterval; - - if (isFunction(optionLabelInterval)) { - labels = makeLabelsByCustomizedCategoryInterval(axis, optionLabelInterval); - } else { - numericLabelInterval = optionLabelInterval === 'auto' ? makeAutoCategoryInterval(axis, ctx) : optionLabelInterval; - labels = makeLabelsByNumericCategoryInterval(axis, numericLabelInterval); - } - - var result = { - labels: labels, - labelCategoryInterval: numericLabelInterval - }; - - if (!isEstimate) { - axisCacheSet(labelsCache, optionLabelInterval, result); - } else { - ctx.out.noPxChangeTryDetermine.push(function () { - axisCacheSet(labelsCache, optionLabelInterval, result); - return true; - }); - } - - return result; - } - - function makeCategoryTicks(axis, tickModel) { - var ticksCache = ensureCategoryTickCache(axis); - var optionTickInterval = getOptionCategoryInterval(tickModel); - var result = axisCacheGet(ticksCache, optionTickInterval); - - if (result) { - return result; - } - - var ticks; - var tickCategoryInterval; // Optimize for the case that large category data and no label displayed, - // we should not return all ticks. - - if (!tickModel.get('show') || axis.scale.isBlank()) { - ticks = []; - } - - if (isFunction(optionTickInterval)) { - ticks = makeLabelsByCustomizedCategoryInterval(axis, optionTickInterval, true); - } // Always use label interval by default despite label show. Consider this - // scenario, Use multiple grid with the xAxis sync, and only one xAxis shows - // labels. `splitLine` and `axisTick` should be consistent in this case. - else if (optionTickInterval === 'auto') { - var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel(), createAxisLabelsComputingContext(AxisTickLabelComputingKind.determine)); - tickCategoryInterval = labelsResult.labelCategoryInterval; - ticks = map$1(labelsResult.labels, function (labelItem) { - return labelItem.tickValue; - }); - } else { - tickCategoryInterval = optionTickInterval; - ticks = makeLabelsByNumericCategoryInterval(axis, tickCategoryInterval, true); - } // Cache to avoid calling interval function repeatedly. - - - return axisCacheSet(ticksCache, optionTickInterval, { - ticks: ticks, - tickCategoryInterval: tickCategoryInterval - }); - } - - function makeRealNumberLabels(axis) { - var ticks = axis.scale.getTicks(); - var labelFormatter = makeLabelFormatter(axis); - return { - labels: map$1(ticks, function (tick, idx) { - return { - formattedLabel: labelFormatter(tick, idx), - rawLabel: axis.scale.getLabel(tick), - tickValue: tick.value, - time: tick.time, - "break": tick["break"] - }; - }) - }; - } // Large category data calculation is performance sensitive, and ticks and label probably will - // be fetched multiple times (e.g. shared by splitLine and axisTick). So we cache the result. - // axis is created each time during a ec process, so we do not need to clear cache. - - - var ensureCategoryTickCache = initAxisCacheMethod('axisTick'); - var ensureCategoryLabelCache = initAxisCacheMethod('axisLabel'); - /** - * PENDING: refactor to JS Map? Because key can be a function or more complicated object, and - * cache size always is small, and currently no JS Map object key polyfill, we use a simple - * array cache instead of plain object hash. - */ - - function initAxisCacheMethod(prop) { - return function ensureCache(axis) { - return axisInner(axis)[prop] || (axisInner(axis)[prop] = { - list: [] - }); - }; - } - - function axisCacheGet(cache, key) { - for (var i = 0; i < cache.list.length; i++) { - if (cache.list[i].key === key) { - return cache.list[i].value; - } - } - } - - function axisCacheSet(cache, key, value) { - cache.list.push({ - key: key, - value: value - }); - return value; - } - - function makeAutoCategoryInterval(axis, ctx) { - if (ctx.kind === AxisTickLabelComputingKind.estimate) { - // Currently axisTick is not involved in estimate kind, and the result likely varies during a - // single pass of ec main process, due to the change of axisExtent. Therefore no cache is used. - var result_2 = axis.calculateCategoryInterval(ctx); - ctx.out.noPxChangeTryDetermine.push(function () { - axisInner(axis).autoInterval = result_2; - return true; - }); - return result_2; - } // Both tick and label uses this result, cacah it to avoid recompute. - - - var result = axisInner(axis).autoInterval; - return result != null ? result : axisInner(axis).autoInterval = axis.calculateCategoryInterval(ctx); - } - /** - * Calculate interval for category axis ticks and labels. - * Use a stretegy to try to avoid overlapping. - * To get precise result, at least one of `getRotate` and `isHorizontal` - * should be implemented in axis. - */ - - - function calculateCategoryInterval(axis, ctx) { - var kind = ctx.kind; - var params = fetchAutoCategoryIntervalCalculationParams(axis); - var labelFormatter = makeLabelFormatter(axis); - var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI; - var ordinalScale = axis.scale; - var ordinalExtent = ordinalScale.getExtent(); // Providing this method is for optimization: - // avoid generating a long array by `getTicks` - // in large category data case. - - var tickCount = ordinalScale.count(); - - if (ordinalExtent[1] - ordinalExtent[0] < 1) { - return 0; - } - - var step = 1; // Simple optimization. Arbitrary value. - - var maxCount = 40; - - if (tickCount > maxCount) { - step = Math.max(1, Math.floor(tickCount / maxCount)); - } - - var tickValue = ordinalExtent[0]; - var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue); - var unitW = Math.abs(unitSpan * Math.cos(rotation)); - var unitH = Math.abs(unitSpan * Math.sin(rotation)); - var maxW = 0; - var maxH = 0; // Caution: Performance sensitive for large category data. - // Consider dataZoom, we should make appropriate step to avoid O(n) loop. - - for (; tickValue <= ordinalExtent[1]; tickValue += step) { - var width = 0; - var height = 0; // Not precise, do not consider align and vertical align - // and each distance from axis line yet. - - var rect = getBoundingRect(labelFormatter({ - value: tickValue - }), params.font, 'center', 'top'); // Magic number - - width = rect.width * 1.3; - height = rect.height * 1.3; // Min size, void long loop. - - maxW = Math.max(maxW, width, 7); - maxH = Math.max(maxH, height, 7); - } - - var dw = maxW / unitW; - var dh = maxH / unitH; // 0/0 is NaN, 1/0 is Infinity. - - isNaN(dw) && (dw = Infinity); - isNaN(dh) && (dh = Infinity); - var interval = Math.max(0, Math.floor(Math.min(dw, dh))); - - if (kind === AxisTickLabelComputingKind.estimate) { - // In estimate kind, the inteval likely varies, thus do not erase the cache. - ctx.out.noPxChangeTryDetermine.push(bind$1(calculateCategoryIntervalTryDetermine, null, axis, interval, tickCount)); - return interval; - } - - var lastInterval = calculateCategoryIntervalDealCache(axis, interval, tickCount); - return lastInterval != null ? lastInterval : interval; - } - - function calculateCategoryIntervalTryDetermine(axis, interval, tickCount) { - return calculateCategoryIntervalDealCache(axis, interval, tickCount) == null; - } // Return the lastInterval if need to use it, otherwise return NullUndefined and save cache. - - - function calculateCategoryIntervalDealCache(axis, interval, tickCount) { - var cache = modelInner(axis.model); - var axisExtent = axis.getExtent(); - var lastAutoInterval = cache.lastAutoInterval; - var lastTickCount = cache.lastTickCount; // Use cache to keep interval stable while moving zoom window, - // otherwise the calculated interval might jitter when the zoom - // window size is close to the interval-changing size. - // For example, if all of the axis labels are `a, b, c, d, e, f, g`. - // The jitter will cause that sometimes the displayed labels are - // `a, d, g` (interval: 2) sometimes `a, c, e`(interval: 1). - - if (lastAutoInterval != null && lastTickCount != null && Math.abs(lastAutoInterval - interval) <= 1 && Math.abs(lastTickCount - tickCount) <= 1 // Always choose the bigger one, otherwise the critical - // point is not the same when zooming in or zooming out. - && lastAutoInterval > interval // If the axis change is caused by chart resize, the cache should not - // be used. Otherwise some hidden labels might not be shown again. - && cache.axisExtent0 === axisExtent[0] && cache.axisExtent1 === axisExtent[1]) { - return lastAutoInterval; - } // Only update cache if cache not used, otherwise the - // changing of interval is too insensitive. - else { - cache.lastTickCount = tickCount; - cache.lastAutoInterval = interval; - cache.axisExtent0 = axisExtent[0]; - cache.axisExtent1 = axisExtent[1]; - } - } - - function fetchAutoCategoryIntervalCalculationParams(axis) { - var labelModel = axis.getLabelModel(); - return { - axisRotate: axis.getRotate ? axis.getRotate() : axis.isHorizontal && !axis.isHorizontal() ? 90 : 0, - labelRotate: labelModel.get('rotate') || 0, - font: labelModel.getFont() - }; - } - - function makeLabelsByNumericCategoryInterval(axis, categoryInterval, onlyTick) { - var labelFormatter = makeLabelFormatter(axis); - var ordinalScale = axis.scale; - var ordinalExtent = ordinalScale.getExtent(); - var labelModel = axis.getLabelModel(); - var result = []; // TODO: axisType: ordinalTime, pick the tick from each month/day/year/... - - var step = Math.max((categoryInterval || 0) + 1, 1); - var startTick = ordinalExtent[0]; - var tickCount = ordinalScale.count(); // Calculate start tick based on zero if possible to keep label consistent - // while zooming and moving while interval > 0. Otherwise the selection - // of displayable ticks and symbols probably keep changing. - // 3 is empirical value. - - if (startTick !== 0 && step > 1 && tickCount / step > 2) { - startTick = Math.round(Math.ceil(startTick / step) * step); - } // (1) Only add min max label here but leave overlap checking - // to render stage, which also ensure the returned list - // suitable for splitLine and splitArea rendering. - // (2) Scales except category always contain min max label so - // do not need to perform this process. - - - var showAllLabel = shouldShowAllLabels(axis); - var includeMinLabel = labelModel.get('showMinLabel') || showAllLabel; - var includeMaxLabel = labelModel.get('showMaxLabel') || showAllLabel; - - if (includeMinLabel && startTick !== ordinalExtent[0]) { - addItem(ordinalExtent[0]); - } // Optimize: avoid generating large array by `ordinalScale.getTicks()`. - - - var tickValue = startTick; - - for (; tickValue <= ordinalExtent[1]; tickValue += step) { - addItem(tickValue); - } - - if (includeMaxLabel && tickValue - step !== ordinalExtent[1]) { - addItem(ordinalExtent[1]); - } - - function addItem(tickValue) { - var tickObj = { - value: tickValue - }; - result.push(onlyTick ? tickValue : { - formattedLabel: labelFormatter(tickObj), - rawLabel: ordinalScale.getLabel(tickObj), - tickValue: tickValue, - time: undefined, - "break": undefined - }); - } - - return result; - } - - function makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) { - var ordinalScale = axis.scale; - var labelFormatter = makeLabelFormatter(axis); - var result = []; - each$4(ordinalScale.getTicks(), function (tick) { - var rawLabel = ordinalScale.getLabel(tick); - var tickValue = tick.value; - - if (categoryInterval(tick.value, rawLabel)) { - result.push(onlyTick ? tickValue : { - formattedLabel: labelFormatter(tick), - rawLabel: rawLabel, - tickValue: tickValue, - time: undefined, - "break": undefined - }); - } - }); - return result; - } - - var NORMALIZED_EXTENT = [0, 1]; - /** - * Base class of Axis. - * - * Lifetime: recreate for each main process. - * [NOTICE]: Some caches is stored on the axis instance (see `axisTickLabelBuilder.ts`) - * which is based on this lifetime. - */ - - var Axis = - /** @class */ - function () { - function Axis(dim, scale, extent) { - this.onBand = false; // Make sure that `extent[0] > extent[1]` only if `inverse: true`. - // `inverse` can be inferred by `extent` unless `extent[0] === extent[1]`. - - this.inverse = false; - this.dim = dim; - this.scale = scale; - this._extent = extent || [0, 0]; - } - /** - * If axis extent contain given coord - */ - - - Axis.prototype.contain = function (coord) { - var extent = this._extent; - var min = Math.min(extent[0], extent[1]); - var max = Math.max(extent[0], extent[1]); - return coord >= min && coord <= max; - }; - /** - * If axis extent contain given data - */ - - - Axis.prototype.containData = function (data) { - return this.scale.contain(this.scale.parse(data)); - }; - /** - * Get coord extent. - */ - - - Axis.prototype.getExtent = function () { - return this._extent.slice(); - }; - /** - * Get precision used for formatting - */ - - - Axis.prototype.getPixelPrecision = function (dataExtent) { - return getPixelPrecision(dataExtent || this.scale.getExtent(), this._extent); - }; - /** - * Set coord extent - */ - - - Axis.prototype.setExtent = function (start, end) { - var extent = this._extent; - extent[0] = start; - extent[1] = end; - }; - /** - * Convert data to coord. Data is the rank if it has an ordinal scale - */ - - - Axis.prototype.dataToCoord = function (data, clamp) { - var extent = this._extent; - var scale = this.scale; - data = scale.normalize(scale.parse(data)); - - if (this.onBand && scale.type === 'ordinal') { - extent = extent.slice(); - fixExtentWithBands(extent, scale.count()); - } - - return linearMap(data, NORMALIZED_EXTENT, extent, clamp); - }; - /** - * Convert coord to data. Data is the rank if it has an ordinal scale - */ - - - Axis.prototype.coordToData = function (coord, clamp) { - var extent = this._extent; - var scale = this.scale; - - if (this.onBand && scale.type === 'ordinal') { - extent = extent.slice(); - fixExtentWithBands(extent, scale.count()); - } - - var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp); - return this.scale.scale(t); - }; - /** - * Convert pixel point to data in axis - */ - - - Axis.prototype.pointToData = function (point, clamp) { - // Should be implemented in derived class if necessary. - return; - }; - /** - * Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`, - * `axis.getTicksCoords` considers `onBand`, which is used by - * `boundaryGap:true` of category axis and splitLine and splitArea. - * @param opt.tickModel default: axis.model.getModel('axisTick') - * @param opt.clamp If `true`, the first and the last - * tick must be at the axis end points. Otherwise, clip ticks - * that outside the axis extent. - */ - - - Axis.prototype.getTicksCoords = function (opt) { - opt = opt || {}; - var tickModel = opt.tickModel || this.getTickModel(); - var result = createAxisTicks(this, tickModel, { - breakTicks: opt.breakTicks, - pruneByBreak: opt.pruneByBreak - }); - var ticks = result.ticks; - var ticksCoords = map$1(ticks, function (tickVal) { - return { - coord: this.dataToCoord(this.scale.type === 'ordinal' ? this.scale.getRawOrdinalNumber(tickVal) : tickVal), - tickValue: tickVal - }; - }, this); - var alignWithLabel = tickModel.get('alignWithLabel'); - fixOnBandTicksCoords(this, ticksCoords, alignWithLabel, opt.clamp); - return ticksCoords; - }; - - Axis.prototype.getMinorTicksCoords = function () { - if (this.scale.type === 'ordinal') { - // Category axis doesn't support minor ticks - return []; - } - - var minorTickModel = this.model.getModel('minorTick'); - var splitNumber = minorTickModel.get('splitNumber'); // Protection. - - if (!(splitNumber > 0 && splitNumber < 100)) { - splitNumber = 5; - } - - var minorTicks = this.scale.getMinorTicks(splitNumber); - var minorTicksCoords = map$1(minorTicks, function (minorTicksGroup) { - return map$1(minorTicksGroup, function (minorTick) { - return { - coord: this.dataToCoord(minorTick), - tickValue: minorTick - }; - }, this); - }, this); - return minorTicksCoords; - }; - - Axis.prototype.getViewLabels = function (ctx) { - ctx = ctx || createAxisLabelsComputingContext(AxisTickLabelComputingKind.determine); - return createAxisLabels(this, ctx).labels; - }; - - Axis.prototype.getLabelModel = function () { - return this.model.getModel('axisLabel'); - }; - /** - * Notice here we only get the default tick model. For splitLine - * or splitArea, we should pass the splitLineModel or splitAreaModel - * manually when calling `getTicksCoords`. - * In GL, this method may be overridden to: - * `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));` - */ - - - Axis.prototype.getTickModel = function () { - return this.model.getModel('axisTick'); - }; - /** - * Get width of band - */ - - - Axis.prototype.getBandWidth = function () { - var axisExtent = this._extent; - var dataExtent = this.scale.getExtent(); - var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0); // Fix #2728, avoid NaN when only one data. - - len === 0 && (len = 1); - var size = Math.abs(axisExtent[1] - axisExtent[0]); - return Math.abs(size) / len; - }; - /** - * Only be called in category axis. - * Can be overridden, consider other axes like in 3D. - * @return Auto interval for cateogry axis tick and label - */ - - - Axis.prototype.calculateCategoryInterval = function (ctx) { - ctx = ctx || createAxisLabelsComputingContext(AxisTickLabelComputingKind.determine); - return calculateCategoryInterval(this, ctx); - }; - - return Axis; - }(); - - function fixExtentWithBands(extent, nTick) { - var size = extent[1] - extent[0]; - var len = nTick; - var margin = size / len / 2; - extent[0] += margin; - extent[1] -= margin; - } // If axis has labels [1, 2, 3, 4]. Bands on the axis are - // |---1---|---2---|---3---|---4---|. - // So the displayed ticks and splitLine/splitArea should between - // each data item, otherwise cause misleading (e.g., split tow bars - // of a single data item when there are two bar series). - // Also consider if tickCategoryInterval > 0 and onBand, ticks and - // splitLine/spliteArea should layout appropriately corresponding - // to displayed labels. (So we should not use `getBandWidth` in this - // case). - - - function fixOnBandTicksCoords(axis, ticksCoords, alignWithLabel, clamp) { - var ticksLen = ticksCoords.length; - - if (!axis.onBand || alignWithLabel || !ticksLen) { - return; - } - - var axisExtent = axis.getExtent(); - var last; - var diffSize; - - if (ticksLen === 1) { - ticksCoords[0].coord = axisExtent[0]; - ticksCoords[0].onBand = true; - last = ticksCoords[1] = { - coord: axisExtent[1], - tickValue: ticksCoords[0].tickValue, - onBand: true - }; - } else { - var crossLen = ticksCoords[ticksLen - 1].tickValue - ticksCoords[0].tickValue; - var shift_1 = (ticksCoords[ticksLen - 1].coord - ticksCoords[0].coord) / crossLen; - each$4(ticksCoords, function (ticksItem) { - ticksItem.coord -= shift_1 / 2; - ticksItem.onBand = true; - }); - var dataExtent = axis.scale.getExtent(); - diffSize = 1 + dataExtent[1] - ticksCoords[ticksLen - 1].tickValue; - last = { - coord: ticksCoords[ticksLen - 1].coord + shift_1 * diffSize, - tickValue: dataExtent[1] + 1, - onBand: true - }; - ticksCoords.push(last); - } - - var inverse = axisExtent[0] > axisExtent[1]; // Handling clamp. - - if (littleThan(ticksCoords[0].coord, axisExtent[0])) { - clamp ? ticksCoords[0].coord = axisExtent[0] : ticksCoords.shift(); - } - - if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) { - ticksCoords.unshift({ - coord: axisExtent[0], - onBand: true - }); - } - - if (littleThan(axisExtent[1], last.coord)) { - clamp ? last.coord = axisExtent[1] : ticksCoords.pop(); - } - - if (clamp && littleThan(last.coord, axisExtent[1])) { - ticksCoords.push({ - coord: axisExtent[1], - onBand: true - }); - } - - function littleThan(a, b) { - // Avoid rounding error cause calculated tick coord different with extent. - // It may cause an extra unnecessary tick added. - a = round$1(a); - b = round$1(b); - return inverse ? a > b : a < b; - } - } // --------------------- Deprecated Extension Methods --------------------- - // Should use `ComponentModel.extend` or `class XXXX extend ComponentModel` to create class. - // Then use `registerComponentModel` in `install` parameter when `use` this extension. For example: - // class Bar3DModel extends ComponentModel {} - // export function install(registers) { registers.registerComponentModel(Bar3DModel); } - // echarts.use(install); - - - function extendComponentModel(proto) { - var Model = ComponentModel.extend(proto); - ComponentModel.registerClass(Model); - return Model; - } - - function extendComponentView(proto) { - var View = ComponentView.extend(proto); - ComponentView.registerClass(View); - return View; - } - - function extendSeriesModel(proto) { - var Model = SeriesModel.extend(proto); - SeriesModel.registerClass(Model); - return Model; - } - - function extendChartView(proto) { - var View = ChartView.extend(proto); - ChartView.registerClass(View); - return View; - } - - var PI2 = Math.PI * 2; - var CMD = PathProxy.CMD; - var DEFAULT_SEARCH_SPACE = ['top', 'right', 'bottom', 'left']; - - function getCandidateAnchor(pos, distance, rect, outPt, outDir) { - var width = rect.width; - var height = rect.height; - - switch (pos) { - case 'top': - outPt.set(rect.x + width / 2, rect.y - distance); - outDir.set(0, -1); - break; - - case 'bottom': - outPt.set(rect.x + width / 2, rect.y + height + distance); - outDir.set(0, 1); - break; - - case 'left': - outPt.set(rect.x - distance, rect.y + height / 2); - outDir.set(-1, 0); - break; - - case 'right': - outPt.set(rect.x + width + distance, rect.y + height / 2); - outDir.set(1, 0); - break; - } - } - - function projectPointToArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y, out) { - x -= cx; - y -= cy; - var d = Math.sqrt(x * x + y * y); - x /= d; - y /= d; // Intersect point. - - var ox = x * r + cx; - var oy = y * r + cy; - - if (Math.abs(startAngle - endAngle) % PI2 < 1e-4) { - // Is a circle - out[0] = ox; - out[1] = oy; - return d - r; - } - - if (anticlockwise) { - var tmp = startAngle; - startAngle = normalizeRadian(endAngle); - endAngle = normalizeRadian(tmp); - } else { - startAngle = normalizeRadian(startAngle); - endAngle = normalizeRadian(endAngle); - } - - if (startAngle > endAngle) { - endAngle += PI2; - } - - var angle = Math.atan2(y, x); - - if (angle < 0) { - angle += PI2; - } - - if (angle >= startAngle && angle <= endAngle || angle + PI2 >= startAngle && angle + PI2 <= endAngle) { - // Project point is on the arc. - out[0] = ox; - out[1] = oy; - return d - r; - } - - var x1 = r * Math.cos(startAngle) + cx; - var y1 = r * Math.sin(startAngle) + cy; - var x2 = r * Math.cos(endAngle) + cx; - var y2 = r * Math.sin(endAngle) + cy; - var d1 = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y); - var d2 = (x2 - x) * (x2 - x) + (y2 - y) * (y2 - y); - - if (d1 < d2) { - out[0] = x1; - out[1] = y1; - return Math.sqrt(d1); - } else { - out[0] = x2; - out[1] = y2; - return Math.sqrt(d2); - } - } - - function projectPointToLine(x1, y1, x2, y2, x, y, out, limitToEnds) { - var dx = x - x1; - var dy = y - y1; - var dx1 = x2 - x1; - var dy1 = y2 - y1; - var lineLen = Math.sqrt(dx1 * dx1 + dy1 * dy1); - dx1 /= lineLen; - dy1 /= lineLen; // dot product - - var projectedLen = dx * dx1 + dy * dy1; - var t = projectedLen / lineLen; - - if (limitToEnds) { - t = Math.min(Math.max(t, 0), 1); - } - - t *= lineLen; - var ox = out[0] = x1 + t * dx1; - var oy = out[1] = y1 + t * dy1; - return Math.sqrt((ox - x) * (ox - x) + (oy - y) * (oy - y)); - } - - function projectPointToRect(x1, y1, width, height, x, y, out) { - if (width < 0) { - x1 = x1 + width; - width = -width; - } - - if (height < 0) { - y1 = y1 + height; - height = -height; - } - - var x2 = x1 + width; - var y2 = y1 + height; - var ox = out[0] = Math.min(Math.max(x, x1), x2); - var oy = out[1] = Math.min(Math.max(y, y1), y2); - return Math.sqrt((ox - x) * (ox - x) + (oy - y) * (oy - y)); - } - - var tmpPt = []; - - function nearestPointOnRect(pt, rect, out) { - var dist = projectPointToRect(rect.x, rect.y, rect.width, rect.height, pt.x, pt.y, tmpPt); - out.set(tmpPt[0], tmpPt[1]); - return dist; - } - /** - * Calculate min distance corresponding point. - * This method won't evaluate if point is in the path. - */ - - - function nearestPointOnPath(pt, path, out) { - var xi = 0; - var yi = 0; - var x0 = 0; - var y0 = 0; - var x1; - var y1; - var minDist = Infinity; - var data = path.data; - var x = pt.x; - var y = pt.y; - - for (var i = 0; i < data.length;) { - var cmd = data[i++]; - - if (i === 1) { - xi = data[i]; - yi = data[i + 1]; - x0 = xi; - y0 = yi; - } - - var d = minDist; - - switch (cmd) { - case CMD.M: - // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点 - // 在 closePath 的时候使用 - x0 = data[i++]; - y0 = data[i++]; - xi = x0; - yi = y0; - break; - - case CMD.L: - d = projectPointToLine(xi, yi, data[i], data[i + 1], x, y, tmpPt, true); - xi = data[i++]; - yi = data[i++]; - break; - - case CMD.C: - d = cubicProjectPoint(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y, tmpPt); - xi = data[i++]; - yi = data[i++]; - break; - - case CMD.Q: - d = quadraticProjectPoint(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y, tmpPt); - xi = data[i++]; - yi = data[i++]; - break; - - case CMD.A: - // TODO Arc 判断的开销比较大 - var cx = data[i++]; - var cy = data[i++]; - var rx = data[i++]; - var ry = data[i++]; - var theta = data[i++]; - var dTheta = data[i++]; // TODO Arc 旋转 - - i += 1; - var anticlockwise = !!(1 - data[i++]); - x1 = Math.cos(theta) * rx + cx; - y1 = Math.sin(theta) * ry + cy; // 不是直接使用 arc 命令 - - if (i <= 1) { - // 第一个命令起点还未定义 - x0 = x1; - y0 = y1; - } // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放 - - - var _x = (x - cx) * ry / rx + cx; - - d = projectPointToArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y, tmpPt); - xi = Math.cos(theta + dTheta) * rx + cx; - yi = Math.sin(theta + dTheta) * ry + cy; - break; - - case CMD.R: - x0 = xi = data[i++]; - y0 = yi = data[i++]; - var width = data[i++]; - var height = data[i++]; - d = projectPointToRect(x0, y0, width, height, x, y, tmpPt); - break; - - case CMD.Z: - d = projectPointToLine(xi, yi, x0, y0, x, y, tmpPt, true); - xi = x0; - yi = y0; - break; - } - - if (d < minDist) { - minDist = d; - out.set(tmpPt[0], tmpPt[1]); - } - } - - return minDist; - } // Temporal variable for intermediate usage. - - - var pt0 = new Point(); - var pt1 = new Point(); - var pt2 = new Point(); - var dir = new Point(); - var dir2 = new Point(); - /** - * Calculate a proper guide line based on the label position and graphic element definition - * @param label - * @param labelRect - * @param target - * @param targetRect - */ - - function updateLabelLinePoints(target, labelLineModel) { - if (!target) { - return; - } - - var labelLine = target.getTextGuideLine(); - var label = target.getTextContent(); // Needs to create text guide in each charts. - - if (!(label && labelLine)) { - return; - } - - var labelGuideConfig = target.textGuideLineConfig || {}; - var points = [[0, 0], [0, 0], [0, 0]]; - var searchSpace = labelGuideConfig.candidates || DEFAULT_SEARCH_SPACE; - var labelRect = label.getBoundingRect().clone(); - labelRect.applyTransform(label.getComputedTransform()); - var minDist = Infinity; - var anchorPoint = labelGuideConfig.anchor; - var targetTransform = target.getComputedTransform(); - var targetInversedTransform = targetTransform && invert([], targetTransform); - var len = labelLineModel.get('length2') || 0; - - if (anchorPoint) { - pt2.copy(anchorPoint); - } - - for (var i = 0; i < searchSpace.length; i++) { - var candidate = searchSpace[i]; - getCandidateAnchor(candidate, 0, labelRect, pt0, dir); - Point.scaleAndAdd(pt1, pt0, dir, len); // Transform to target coord space. - - pt1.transform(targetInversedTransform); // Note: getBoundingRect will ensure the `path` being created. - - var boundingRect = target.getBoundingRect(); - var dist = anchorPoint ? anchorPoint.distance(pt1) : target instanceof Path ? nearestPointOnPath(pt1, target.path, pt2) : nearestPointOnRect(pt1, boundingRect, pt2); // TODO pt2 is in the path - - if (dist < minDist) { - minDist = dist; // Transform back to global space. - - pt1.transform(targetTransform); - pt2.transform(targetTransform); - pt2.toArray(points[0]); - pt1.toArray(points[1]); - pt0.toArray(points[2]); - } - } - - limitTurnAngle(points, labelLineModel.get('minTurnAngle')); - labelLine.setShape({ - points: points - }); - } // Temporal variable for the limitTurnAngle function - - - var tmpArr = []; - var tmpProjPoint = new Point(); - /** - * Reduce the line segment attached to the label to limit the turn angle between two segments. - * @param linePoints - * @param minTurnAngle Radian of minimum turn angle. 0 - 180 - */ - - function limitTurnAngle(linePoints, minTurnAngle) { - if (!(minTurnAngle <= 180 && minTurnAngle > 0)) { - return; - } - - minTurnAngle = minTurnAngle / 180 * Math.PI; // The line points can be - // /pt1----pt2 (label) - // / - // pt0/ - - pt0.fromArray(linePoints[0]); - pt1.fromArray(linePoints[1]); - pt2.fromArray(linePoints[2]); - Point.sub(dir, pt0, pt1); - Point.sub(dir2, pt2, pt1); - var len1 = dir.len(); - var len2 = dir2.len(); - - if (len1 < 1e-3 || len2 < 1e-3) { - return; - } - - dir.scale(1 / len1); - dir2.scale(1 / len2); - var angleCos = dir.dot(dir2); - var minTurnAngleCos = Math.cos(minTurnAngle); - - if (minTurnAngleCos < angleCos) { - // Smaller than minTurnAngle - // Calculate project point of pt0 on pt1-pt2 - var d = projectPointToLine(pt1.x, pt1.y, pt2.x, pt2.y, pt0.x, pt0.y, tmpArr, false); - tmpProjPoint.fromArray(tmpArr); // Calculate new projected length with limited minTurnAngle and get the new connect point - - tmpProjPoint.scaleAndAdd(dir2, d / Math.tan(Math.PI - minTurnAngle)); // Limit the new calculated connect point between pt1 and pt2. - - var t = pt2.x !== pt1.x ? (tmpProjPoint.x - pt1.x) / (pt2.x - pt1.x) : (tmpProjPoint.y - pt1.y) / (pt2.y - pt1.y); - - if (isNaN(t)) { - return; - } - - if (t < 0) { - Point.copy(tmpProjPoint, pt1); - } else if (t > 1) { - Point.copy(tmpProjPoint, pt2); - } - - tmpProjPoint.toArray(linePoints[1]); - } - } - - function setLabelLineState(labelLine, ignore, stateName, stateModel) { - var isNormal = stateName === 'normal'; - var stateObj = isNormal ? labelLine : labelLine.ensureState(stateName); // Make sure display. - - stateObj.ignore = ignore; // Set smooth - - var smooth = stateModel.get('smooth'); - - if (smooth && smooth === true) { - smooth = 0.3; - } - - stateObj.shape = stateObj.shape || {}; - - if (smooth > 0) { - stateObj.shape.smooth = smooth; - } - - var styleObj = stateModel.getModel('lineStyle').getLineStyle(); - isNormal ? labelLine.useStyle(styleObj) : stateObj.style = styleObj; - } - - function buildLabelLinePath(path, shape) { - var smooth = shape.smooth; - var points = shape.points; - - if (!points) { - return; - } - - path.moveTo(points[0][0], points[0][1]); - - if (smooth > 0 && points.length >= 3) { - var len1 = dist$1(points[0], points[1]); - var len2 = dist$1(points[1], points[2]); - - if (!len1 || !len2) { - path.lineTo(points[1][0], points[1][1]); - path.lineTo(points[2][0], points[2][1]); - return; - } - - var moveLen = Math.min(len1, len2) * smooth; - var midPoint0 = lerp$1([], points[1], points[0], moveLen / len1); - var midPoint2 = lerp$1([], points[1], points[2], moveLen / len2); - var midPoint1 = lerp$1([], midPoint0, midPoint2, 0.5); - path.bezierCurveTo(midPoint0[0], midPoint0[1], midPoint0[0], midPoint0[1], midPoint1[0], midPoint1[1]); - path.bezierCurveTo(midPoint2[0], midPoint2[1], midPoint2[0], midPoint2[1], points[2][0], points[2][1]); - } else { - for (var i = 1; i < points.length; i++) { - path.lineTo(points[i][0], points[i][1]); - } - } - } - /** - * Create a label line if necessary and set it's style. - */ - - - function setLabelLineStyle(targetEl, statesModels, defaultStyle) { - var labelLine = targetEl.getTextGuideLine(); - var label = targetEl.getTextContent(); - - if (!label) { - // Not show label line if there is no label. - if (labelLine) { - targetEl.removeTextGuideLine(); - } - - return; - } - - var normalModel = statesModels.normal; - var showNormal = normalModel.get('show'); - var labelIgnoreNormal = label.ignore; - - for (var i = 0; i < DISPLAY_STATES.length; i++) { - var stateName = DISPLAY_STATES[i]; - var stateModel = statesModels[stateName]; - var isNormal = stateName === 'normal'; - - if (stateModel) { - var stateShow = stateModel.get('show'); - var isLabelIgnored = isNormal ? labelIgnoreNormal : retrieve2(label.states[stateName] && label.states[stateName].ignore, labelIgnoreNormal); - - if (isLabelIgnored // Not show when label is not shown in this state. - || !retrieve2(stateShow, showNormal) // Use normal state by default if not set. - ) { - var stateObj = isNormal ? labelLine : labelLine && labelLine.states[stateName]; - - if (stateObj) { - stateObj.ignore = true; - } - - if (!!labelLine) { - setLabelLineState(labelLine, true, stateName, stateModel); - } - - continue; - } // Create labelLine if not exists - - - if (!labelLine) { - labelLine = new Polyline(); - targetEl.setTextGuideLine(labelLine); // Reset state of normal because it's new created. - // NOTE: NORMAL should always been the first! - - if (!isNormal && (labelIgnoreNormal || !showNormal)) { - setLabelLineState(labelLine, true, 'normal', statesModels.normal); - } // Use same state proxy. - - - if (targetEl.stateProxy) { - labelLine.stateProxy = targetEl.stateProxy; - } - } - - setLabelLineState(labelLine, false, stateName, stateModel); - } - } - - if (labelLine) { - defaults(labelLine.style, defaultStyle); // Not fill. - - labelLine.style.fill = null; - var showAbove = normalModel.get('showAbove'); - var labelLineConfig = targetEl.textGuideLineConfig = targetEl.textGuideLineConfig || {}; - labelLineConfig.showAbove = showAbove || false; // Custom the buildPath. - - labelLine.buildPath = buildLabelLinePath; - } - } - - function getLabelLineStatesModels(itemModel, labelLineName) { - labelLineName = labelLineName || 'labelLine'; - var statesModels = { - normal: itemModel.getModel(labelLineName) - }; - - for (var i = 0; i < SPECIAL_STATES.length; i++) { - var stateName = SPECIAL_STATES[i]; - statesModels[stateName] = itemModel.getModel([stateName, labelLineName]); - } - - return statesModels; - } - - var LABEL_LAYOUT_BASE_PROPS = ['label', 'labelLine', 'layoutOption', 'priority', 'defaultAttr', 'marginForce', 'minMarginForce', 'marginDefault', 'suggestIgnore']; - var LABEL_LAYOUT_DIRTY_BIT_OTHERS = 1; - var LABEL_LAYOUT_DIRTY_BIT_OBB = 2; - var LABEL_LAYOUT_DIRTY_ALL = LABEL_LAYOUT_DIRTY_BIT_OTHERS | LABEL_LAYOUT_DIRTY_BIT_OBB; - - function setLabelLayoutDirty(labelGeometry, dirtyOrClear, dirtyBits) { - dirtyBits = dirtyBits || LABEL_LAYOUT_DIRTY_ALL; - dirtyOrClear ? labelGeometry.dirty |= dirtyBits : labelGeometry.dirty &= ~dirtyBits; - } - - function isLabelLayoutDirty(labelGeometry, dirtyBits) { - dirtyBits = dirtyBits || LABEL_LAYOUT_DIRTY_ALL; - return labelGeometry.dirty == null || !!(labelGeometry.dirty & dirtyBits); - } - /** - * [CAUTION] - * - No auto dirty propagation mechanism yet. If the transform of the raw label or any of its ancestors is - * changed, must sync the changes to the props of `LabelGeometry` by: - * either explicitly call: - * `setLabelLayoutDirty(labelLayout, true); ensureLabelLayoutWithGeometry(labelLayout);` - * or call (if only translation is performed): - * `labelLayoutApplyTranslation(labelLayout);` - * - `label.ignore` is not necessarily falsy, and not considered in computing `LabelGeometry`, - * since it might be modified by some overlap resolving handling. - * - To duplicate or make a variation: - * use `newLabelLayoutWithGeometry`. - * - * The result can also be the input of this method. - * @return `NullUndefined` if and only if `labelLayout` is `NullUndefined`. - */ - - - function ensureLabelLayoutWithGeometry(labelLayout) { - if (!labelLayout) { - return; - } - - if (isLabelLayoutDirty(labelLayout)) { - computeLabelGeometry(labelLayout, labelLayout.label, labelLayout); - } - - return labelLayout; - } - /** - * The props in `out` will be filled if existing, or created. - */ - - - function computeLabelGeometry(out, label, opt) { - // [CAUTION] These props may be modified directly for performance consideration, - // therefore, do not output the internal data structure of zrender Element. - var rawTransform = label.getComputedTransform(); - out.transform = ensureCopyTransform(out.transform, rawTransform); // NOTE: should call `getBoundingRect` after `getComputedTransform`, or may get an inaccurate bounding rect. - // The reason is that `getComputedTransform` calls `__host.updateInnerText()` internally, which updates the label - // by `textConfig` mounted on the host. - // PENDING: add a dirty bit for that in zrender? - - var outLocalRect = out.localRect = ensureCopyRect(out.localRect, label.getBoundingRect()); - var labelStyleExt = label.style; - var margin = labelStyleExt.margin; - var marginForce = opt && opt.marginForce; - var minMarginForce = opt && opt.minMarginForce; - var marginDefault = opt && opt.marginDefault; - var marginType = labelStyleExt.__marginType; - - if (marginType == null && marginDefault) { - margin = marginDefault; - marginType = LabelMarginType.textMargin; - } // `textMargin` and `minMargin` can not exist both. - - - for (var i = 0; i < 4; i++) { - _tmpLabelMargin[i] = marginType === LabelMarginType.minMargin && minMarginForce && minMarginForce[i] != null ? minMarginForce[i] : marginForce && marginForce[i] != null ? marginForce[i] : margin ? margin[i] : 0; - } - - if (marginType === LabelMarginType.textMargin) { - expandOrShrinkRect(outLocalRect, _tmpLabelMargin, false, false); - } - - var outGlobalRect = out.rect = ensureCopyRect(out.rect, outLocalRect); - - if (rawTransform) { - outGlobalRect.applyTransform(rawTransform); - } // Notice: label.style.margin is actually `minMargin / 2`, handled by `setTextStyleCommon`. - - - if (marginType === LabelMarginType.minMargin) { - expandOrShrinkRect(outGlobalRect, _tmpLabelMargin, false, false); - } - - out.axisAligned = isBoundingRectAxisAligned(rawTransform); - (out.label = out.label || {}).ignore = label.ignore; - setLabelLayoutDirty(out, false); - setLabelLayoutDirty(out, true, LABEL_LAYOUT_DIRTY_BIT_OBB); // Do not remove `obb` (if existing) for reuse, just reset the dirty bit. - - return out; - } - - var _tmpLabelMargin = [0, 0, 0, 0]; - /** - * The props in `out` will be filled if existing, or created. - */ - - function computeLabelGeometry2(out, rawLocalRect, rawTransform) { - out.transform = ensureCopyTransform(out.transform, rawTransform); - out.localRect = ensureCopyRect(out.localRect, rawLocalRect); - out.rect = ensureCopyRect(out.rect, rawLocalRect); - - if (rawTransform) { - out.rect.applyTransform(rawTransform); - } - - out.axisAligned = isBoundingRectAxisAligned(rawTransform); - out.obb = undefined; // Reset to undefined, will be created by `ensureOBB` when using. - - (out.label = out.label || {}).ignore = false; - return out; - } - /** - * This is a shortcut of - * ```js - * labelLayout.label.x = newX; - * labelLayout.label.y = newY; - * setLabelLayoutDirty(labelLayout, true); - * ensureLabelLayoutWithGeometry(labelLayout); - * ``` - * and provide better performance in this common case. - */ - - - function labelLayoutApplyTranslation(labelLayout, offset) { - if (!labelLayout) { - return; - } - - labelLayout.label.x += offset.x; - labelLayout.label.y += offset.y; - labelLayout.label.markRedraw(); - var transform = labelLayout.transform; - - if (transform) { - transform[4] += offset.x; - transform[5] += offset.y; - } - - var globalRect = labelLayout.rect; - - if (globalRect) { - globalRect.x += offset.x; - globalRect.y += offset.y; - } - - var obb = labelLayout.obb; - - if (obb) { - obb.fromBoundingRect(labelLayout.localRect, transform); - } - } - /** - * To duplicate or make a variation of a label layout. - * Copy the only relevant properties to avoid the conflict or wrongly reuse of the props of `LabelLayoutWithGeometry`. - */ - - - function newLabelLayoutWithGeometry(newBaseWithDefaults, source) { - for (var i = 0; i < LABEL_LAYOUT_BASE_PROPS.length; i++) { - var prop = LABEL_LAYOUT_BASE_PROPS[i]; - - if (newBaseWithDefaults[prop] == null) { - newBaseWithDefaults[prop] = source[prop]; - } - } - - return ensureLabelLayoutWithGeometry(newBaseWithDefaults); - } - /** - * Create obb if no one, can cache it. - */ - - - function ensureOBB(labelGeometry) { - var obb = labelGeometry.obb; - - if (!obb || isLabelLayoutDirty(labelGeometry, LABEL_LAYOUT_DIRTY_BIT_OBB)) { - labelGeometry.obb = obb = obb || new OrientedBoundingRect(); - obb.fromBoundingRect(labelGeometry.localRect, labelGeometry.transform); - setLabelLayoutDirty(labelGeometry, false, LABEL_LAYOUT_DIRTY_BIT_OBB); - } - - return obb; - } - /** - * Adjust labels on x/y direction to avoid overlap. - * - * PENDING: the current implementation is based on the global bounding rect rather than the local rect, - * which may be not preferable in some edge cases when the label has rotation, but works for most cases, - * since rotation is unnecessary when there is sufficient space, while squeezing is applied regardless - * of overlapping when there is no enough space. - * - * NOTICE: - * - The input `list` and its content will be modified (sort, label.x/y, rect). - * - The caller should sync the modifications to the other parts by - * `setLabelLayoutDirty` and `ensureLabelLayoutWithGeometry` if needed. - * - * @return adjusted - */ - - - function shiftLayoutOnXY(list, xyDimIdx, // 0 for x, 1 for y - minBound, // for x, leftBound; for y, topBound - maxBound, // for x, rightBound; for y, bottomBound - // If average the shifts on all labels and add them to 0 - // TODO: Not sure if should enable it. - // Pros: The angle of lines will distribute more equally - // Cons: In some layout. It may not what user wanted. like in pie. the label of last sector is usually changed unexpectedly. - balanceShift) { - var len = list.length; - var xyDim = XY$1[xyDimIdx]; - var sizeDim = WH$1[xyDimIdx]; - - if (len < 2) { - return false; - } - - list.sort(function (a, b) { - return a.rect[xyDim] - b.rect[xyDim]; - }); - var lastPos = 0; - var delta; - var adjusted = false; // const shifts = []; - - var totalShifts = 0; - - for (var i = 0; i < len; i++) { - var item = list[i]; - var rect = item.rect; - delta = rect[xyDim] - lastPos; - - if (delta < 0) { - // shiftForward(i, len, -delta); - rect[xyDim] -= delta; - item.label[xyDim] -= delta; - adjusted = true; - } - - var shift = Math.max(-delta, 0); // shifts.push(shift); - - totalShifts += shift; - lastPos = rect[xyDim] + rect[sizeDim]; - } - - if (totalShifts > 0 && balanceShift) { - // Shift back to make the distribution more equally. - shiftList(-totalShifts / len, 0, len); - } // TODO bleedMargin? - - - var first = list[0]; - var last = list[len - 1]; - var minGap; - var maxGap; - updateMinMaxGap(); // If ends exceed two bounds, squeeze at most 80%, then take the gap of two bounds. - - minGap < 0 && squeezeGaps(-minGap, 0.8); - maxGap < 0 && squeezeGaps(maxGap, 0.8); - updateMinMaxGap(); - takeBoundsGap(minGap, maxGap, 1); - takeBoundsGap(maxGap, minGap, -1); // Handle bailout when there is not enough space. - - updateMinMaxGap(); - - if (minGap < 0) { - squeezeWhenBailout(-minGap); - } - - if (maxGap < 0) { - squeezeWhenBailout(maxGap); - } - - function updateMinMaxGap() { - minGap = first.rect[xyDim] - minBound; - maxGap = maxBound - last.rect[xyDim] - last.rect[sizeDim]; - } - - function takeBoundsGap(gapThisBound, gapOtherBound, moveDir) { - if (gapThisBound < 0) { - // Move from other gap if can. - var moveFromMaxGap = Math.min(gapOtherBound, -gapThisBound); - - if (moveFromMaxGap > 0) { - shiftList(moveFromMaxGap * moveDir, 0, len); - var remained = moveFromMaxGap + gapThisBound; - - if (remained < 0) { - squeezeGaps(-remained * moveDir, 1); - } - } else { - squeezeGaps(-gapThisBound * moveDir, 1); - } - } - } - - function shiftList(delta, start, end) { - if (delta !== 0) { - adjusted = true; - } - - for (var i = start; i < end; i++) { - var item = list[i]; - var rect = item.rect; - rect[xyDim] += delta; - item.label[xyDim] += delta; - } - } // Squeeze gaps if the labels exceed margin. - - - function squeezeGaps(delta, maxSqeezePercent) { - var gaps = []; - var totalGaps = 0; - - for (var i = 1; i < len; i++) { - var prevItemRect = list[i - 1].rect; - var gap = Math.max(list[i].rect[xyDim] - prevItemRect[xyDim] - prevItemRect[sizeDim], 0); - gaps.push(gap); - totalGaps += gap; - } - - if (!totalGaps) { - return; - } - - var squeezePercent = Math.min(Math.abs(delta) / totalGaps, maxSqeezePercent); - - if (delta > 0) { - for (var i = 0; i < len - 1; i++) { - // Distribute the shift delta to all gaps. - var movement = gaps[i] * squeezePercent; // Forward - - shiftList(movement, 0, i + 1); - } - } else { - // Backward - for (var i = len - 1; i > 0; i--) { - // Distribute the shift delta to all gaps. - var movement = gaps[i - 1] * squeezePercent; - shiftList(-movement, i, len); - } - } - } - /** - * Squeeze to allow overlap if there is no more space available. - * Let other overlapping strategy like hideOverlap do the job instead of keep exceeding the bounds. - */ - - - function squeezeWhenBailout(delta) { - var dir = delta < 0 ? -1 : 1; - delta = Math.abs(delta); - var moveForEachLabel = Math.ceil(delta / (len - 1)); - - for (var i = 0; i < len - 1; i++) { - if (dir > 0) { - // Forward - shiftList(moveForEachLabel, 0, i + 1); - } else { - // Backward - shiftList(-moveForEachLabel, len - i - 1, len); - } - - delta -= moveForEachLabel; - - if (delta <= 0) { - return; - } - } - } - - return adjusted; - } - /** - * @see `SavedLabelAttr` in `LabelManager.ts` - * @see `hideOverlap` - */ - - - function restoreIgnore(labelList) { - for (var i = 0; i < labelList.length; i++) { - var labelItem = labelList[i]; - var defaultAttr = labelItem.defaultAttr; - var labelLine = labelItem.labelLine; - labelItem.label.attr('ignore', defaultAttr.ignore); - labelLine && labelLine.attr('ignore', defaultAttr.labelGuideIgnore); - } - } - /** - * [NOTICE - restore]: - * 'series:layoutlabels' may be triggered during some shortcut passes, such as zooming in series.graph/geo - * (`updateLabelLayout`), where the modified `Element` props should be restorable from `defaultAttr`. - * @see `SavedLabelAttr` in `LabelManager.ts` - * `restoreIgnore` can be called to perform the restore, if needed. - * - * [NOTICE - state]: - * Regarding Element's states, this method is only designed for the normal state. - * PENDING: although currently this method is effectively called in other states in `updateLabelLayout` case, - * the bad case is not noticeable in the zooming scenario. - */ - - - function hideOverlap(labelList) { - var displayedLabels = []; // TODO, render overflow visible first, put in the displayedLabels. - - labelList.sort(function (a, b) { - return (b.suggestIgnore ? 1 : 0) - (a.suggestIgnore ? 1 : 0) || b.priority - a.priority; - }); - - function hideEl(el) { - if (!el.ignore) { - // Show on emphasis. - var emphasisState = el.ensureState('emphasis'); - - if (emphasisState.ignore == null) { - emphasisState.ignore = false; - } - } - - el.ignore = true; - } - - for (var i = 0; i < labelList.length; i++) { - var labelItem = ensureLabelLayoutWithGeometry(labelList[i]); // The current `el.ignore` is involved, since some previous overlap - // resolving strategies may have set `el.ignore` to true. - - if (labelItem.label.ignore) { - continue; - } - - var label = labelItem.label; - var labelLine = labelItem.labelLine; // NOTICE: even when the with/height of globalRect of a label is 0, the label line should - // still be displayed, since we should follow the concept of "truncation", meaning that - // something exists even if it cannot be fully displayed. A visible label line is necessary - // to allow users to get a tooltip with label info on hover. - - var overlapped = false; - - for (var j = 0; j < displayedLabels.length; j++) { - if (labelIntersect(labelItem, displayedLabels[j], null, { - touchThreshold: 0.05 - })) { - overlapped = true; - break; - } - } // TODO Callback to determine if this overlap should be handled? - - - if (overlapped) { - hideEl(label); - labelLine && hideEl(labelLine); - } else { - displayedLabels.push(labelItem); - } - } - } - /** - * Enable fast check for performance; use obb if inevitable. - * If `mtv` is used, `targetLayoutInfo` can be moved based on the values filled into `mtv`. - * - * This method is based only on the current `Element` states (regardless of other states). - * Typically this method (and the entire layout process) is performed in normal state. - */ - - - function labelIntersect(baseLayoutInfo, targetLayoutInfo, mtv, intersectOpt) { - if (!baseLayoutInfo || !targetLayoutInfo) { - return false; - } - - if (baseLayoutInfo.label && baseLayoutInfo.label.ignore || targetLayoutInfo.label && targetLayoutInfo.label.ignore) { - return false; - } // Fast rejection. - - - if (!baseLayoutInfo.rect.intersect(targetLayoutInfo.rect, mtv, intersectOpt)) { - return false; - } - - if (baseLayoutInfo.axisAligned && targetLayoutInfo.axisAligned) { - return true; // obb is the same as the normal bounding rect. - } - - return ensureOBB(baseLayoutInfo).intersect(ensureOBB(targetLayoutInfo), mtv, intersectOpt); - } - - function cloneArr(points) { - if (points) { - var newPoints = []; - - for (var i = 0; i < points.length; i++) { - newPoints.push(points[i].slice()); - } - - return newPoints; - } - } - - function prepareLayoutCallbackParams(labelItem, hostEl) { - var label = labelItem.label; - var labelLine = hostEl && hostEl.getTextGuideLine(); - return { - dataIndex: labelItem.dataIndex, - dataType: labelItem.dataType, - seriesIndex: labelItem.seriesModel.seriesIndex, - text: labelItem.label.style.text, - rect: labelItem.hostRect, - labelRect: labelItem.rect, - // x: labelAttr.x, - // y: labelAttr.y, - align: label.style.align, - verticalAlign: label.style.verticalAlign, - labelLinePoints: cloneArr(labelLine && labelLine.shape.points) - }; - } - - var LABEL_OPTION_TO_STYLE_KEYS = ['align', 'verticalAlign', 'width', 'height', 'fontSize']; - var dummyTransformable = new Transformable(); - var labelLayoutInnerStore = makeInner(); - var labelLineAnimationStore = makeInner(); - - function extendWithKeys(target, source, keys) { - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - - if (source[key] != null) { - target[key] = source[key]; - } - } - } - - var LABEL_LAYOUT_PROPS = ['x', 'y', 'rotation']; - - var LabelManager = - /** @class */ - function () { - function LabelManager() { - this._labelList = []; - this._chartViewList = []; - } - - LabelManager.prototype.clearLabels = function () { - this._labelList = []; - this._chartViewList = []; - }; - /** - * Add label to manager - */ - - - LabelManager.prototype._addLabel = function (dataIndex, dataType, seriesModel, label, layoutOptionOrCb) { - var labelStyle = label.style; - var hostEl = label.__hostTarget; - var textConfig = hostEl.textConfig || {}; // TODO: If label is in other state. - - var labelTransform = label.getComputedTransform(); - var labelRect = label.getBoundingRect().plain(); - BoundingRect.applyTransform(labelRect, labelRect, labelTransform); - - if (labelTransform) { - dummyTransformable.setLocalTransform(labelTransform); - } else { - // Identity transform. - dummyTransformable.x = dummyTransformable.y = dummyTransformable.rotation = dummyTransformable.originX = dummyTransformable.originY = 0; - dummyTransformable.scaleX = dummyTransformable.scaleY = 1; - } - - dummyTransformable.rotation = normalizeRadian(dummyTransformable.rotation); - var host = label.__hostTarget; - var hostRect; - - if (host) { - hostRect = host.getBoundingRect().plain(); - var transform = host.getComputedTransform(); - BoundingRect.applyTransform(hostRect, hostRect, transform); - } - - var labelGuide = hostRect && host.getTextGuideLine(); - - this._labelList.push({ - label: label, - labelLine: labelGuide, - seriesModel: seriesModel, - dataIndex: dataIndex, - dataType: dataType, - layoutOptionOrCb: layoutOptionOrCb, - layoutOption: null, - rect: labelRect, - hostRect: hostRect, - // Label with lower priority will be hidden when overlapped - // Use rect size as default priority - priority: hostRect ? hostRect.width * hostRect.height : 0, - // Save default label attributes. - // For restore if developers want get back to default value in callback. - defaultAttr: { - ignore: label.ignore, - labelGuideIgnore: labelGuide && labelGuide.ignore, - x: dummyTransformable.x, - y: dummyTransformable.y, - scaleX: dummyTransformable.scaleX, - scaleY: dummyTransformable.scaleY, - rotation: dummyTransformable.rotation, - style: { - x: labelStyle.x, - y: labelStyle.y, - align: labelStyle.align, - verticalAlign: labelStyle.verticalAlign, - width: labelStyle.width, - height: labelStyle.height, - fontSize: labelStyle.fontSize - }, - cursor: label.cursor, - attachedPos: textConfig.position, - attachedRot: textConfig.rotation - } - }); - }; - - LabelManager.prototype.addLabelsOfSeries = function (chartView) { - var _this = this; - - this._chartViewList.push(chartView); - - var seriesModel = chartView.__model; - var layoutOption = seriesModel.get('labelLayout'); - /** - * Ignore layouting if it's not specified anything. - */ - - if (!(isFunction(layoutOption) || keys(layoutOption).length)) { - return; - } - - chartView.group.traverse(function (child) { - if (child.ignore) { - return true; // Stop traverse descendants. - } // Only support label being hosted on graphic elements. - - - var textEl = child.getTextContent(); - var ecData = getECData(child); // Can only attach the text on the element with dataIndex - - if (textEl && !textEl.disableLabelLayout) { - _this._addLabel(ecData.dataIndex, ecData.dataType, seriesModel, textEl, layoutOption); - } - }); - }; - - LabelManager.prototype.updateLayoutConfig = function (api) { - var width = api.getWidth(); - var height = api.getHeight(); - - function createDragHandler(el, labelLineModel) { - return function () { - updateLabelLinePoints(el, labelLineModel); - }; - } - - for (var i = 0; i < this._labelList.length; i++) { - var labelItem = this._labelList[i]; - var label = labelItem.label; - var hostEl = label.__hostTarget; - var defaultLabelAttr = labelItem.defaultAttr; - var layoutOption = void 0; // TODO A global layout option? - - if (isFunction(labelItem.layoutOptionOrCb)) { - layoutOption = labelItem.layoutOptionOrCb(prepareLayoutCallbackParams(labelItem, hostEl)); - } else { - layoutOption = labelItem.layoutOptionOrCb; - } - - layoutOption = layoutOption || {}; - labelItem.layoutOption = layoutOption; - var degreeToRadian = Math.PI / 180; // TODO hostEl should always exists. - // Or label should not have parent because the x, y is all in global space. - - if (hostEl) { - hostEl.setTextConfig({ - // Force to set local false. - local: false, - // Ignore position and rotation config on the host el if x or y is changed. - position: layoutOption.x != null || layoutOption.y != null ? null : defaultLabelAttr.attachedPos, - // Ignore rotation config on the host el if rotation is changed. - rotation: layoutOption.rotate != null ? layoutOption.rotate * degreeToRadian : defaultLabelAttr.attachedRot, - offset: [layoutOption.dx || 0, layoutOption.dy || 0] - }); - } - - var needsUpdateLabelLine = false; - - if (layoutOption.x != null) { - // TODO width of chart view. - label.x = parsePercent(layoutOption.x, width); - label.setStyle('x', 0); // Ignore movement in style. TODO: origin. - - needsUpdateLabelLine = true; - } else { - label.x = defaultLabelAttr.x; - label.setStyle('x', defaultLabelAttr.style.x); - } - - if (layoutOption.y != null) { - // TODO height of chart view. - label.y = parsePercent(layoutOption.y, height); - label.setStyle('y', 0); // Ignore movement in style. - - needsUpdateLabelLine = true; - } else { - label.y = defaultLabelAttr.y; - label.setStyle('y', defaultLabelAttr.style.y); - } - - if (layoutOption.labelLinePoints) { - var guideLine = hostEl.getTextGuideLine(); - - if (guideLine) { - guideLine.setShape({ - points: layoutOption.labelLinePoints - }); // Not update - - needsUpdateLabelLine = false; - } - } - - var labelLayoutStore = labelLayoutInnerStore(label); - labelLayoutStore.needsUpdateLabelLine = needsUpdateLabelLine; - label.rotation = layoutOption.rotate != null ? layoutOption.rotate * degreeToRadian : defaultLabelAttr.rotation; - label.scaleX = defaultLabelAttr.scaleX; - label.scaleY = defaultLabelAttr.scaleY; - - for (var k = 0; k < LABEL_OPTION_TO_STYLE_KEYS.length; k++) { - var key = LABEL_OPTION_TO_STYLE_KEYS[k]; - label.setStyle(key, layoutOption[key] != null ? layoutOption[key] : defaultLabelAttr.style[key]); - } - - if (layoutOption.draggable) { - label.draggable = true; - label.cursor = 'move'; - - if (hostEl) { - var hostModel = labelItem.seriesModel; - - if (labelItem.dataIndex != null) { - var data = labelItem.seriesModel.getData(labelItem.dataType); - hostModel = data.getItemModel(labelItem.dataIndex); - } - - label.on('drag', createDragHandler(hostEl, hostModel.getModel('labelLine'))); - } - } else { - // TODO Other drag functions? - label.off('drag'); - label.cursor = defaultLabelAttr.cursor; - } - } - }; - - LabelManager.prototype.layout = function (api) { - var width = api.getWidth(); - var height = api.getHeight(); - var labelList = []; - each$4(this._labelList, function (inputItem) { - if (!inputItem.defaultAttr.ignore) { - labelList.push(newLabelLayoutWithGeometry({}, inputItem)); - } - }); - var labelsNeedsAdjustOnX = filter(labelList, function (item) { - return item.layoutOption.moveOverlap === 'shiftX'; - }); - var labelsNeedsAdjustOnY = filter(labelList, function (item) { - return item.layoutOption.moveOverlap === 'shiftY'; - }); - shiftLayoutOnXY(labelsNeedsAdjustOnX, 0, 0, width); - shiftLayoutOnXY(labelsNeedsAdjustOnY, 1, 0, height); - var labelsNeedsHideOverlap = filter(labelList, function (item) { - return item.layoutOption.hideOverlap; - }); - restoreIgnore(labelsNeedsHideOverlap); - hideOverlap(labelsNeedsHideOverlap); - }; - /** - * Process all labels. Not only labels with layoutOption. - */ - - - LabelManager.prototype.processLabelsOverall = function () { - var _this = this; - - each$4(this._chartViewList, function (chartView) { - var seriesModel = chartView.__model; - var ignoreLabelLineUpdate = chartView.ignoreLabelLineUpdate; - var animationEnabled = seriesModel.isAnimationEnabled(); - chartView.group.traverse(function (child) { - if (child.ignore && !child.forceLabelAnimation) { - return true; // Stop traverse descendants. - } - - var needsUpdateLabelLine = !ignoreLabelLineUpdate; - var label = child.getTextContent(); - - if (!needsUpdateLabelLine && label) { - needsUpdateLabelLine = labelLayoutInnerStore(label).needsUpdateLabelLine; - } - - if (needsUpdateLabelLine) { - _this._updateLabelLine(child, seriesModel); - } - - if (animationEnabled) { - _this._animateLabels(child, seriesModel); - } - }); - }); - }; - - LabelManager.prototype._updateLabelLine = function (el, seriesModel) { - // Only support label being hosted on graphic elements. - var textEl = el.getTextContent(); // Update label line style. - - var ecData = getECData(el); - var dataIndex = ecData.dataIndex; // Only support labelLine on the labels represent data. - - if (textEl && dataIndex != null) { - var data = seriesModel.getData(ecData.dataType); - var itemModel = data.getItemModel(dataIndex); - var defaultStyle = {}; - var visualStyle = data.getItemVisual(dataIndex, 'style'); - - if (visualStyle) { - var visualType = data.getVisual('drawType'); // Default to be same with main color - - defaultStyle.stroke = visualStyle[visualType]; - } - - var labelLineModel = itemModel.getModel('labelLine'); - setLabelLineStyle(el, getLabelLineStatesModels(itemModel), defaultStyle); - updateLabelLinePoints(el, labelLineModel); - } - }; - - LabelManager.prototype._animateLabels = function (el, seriesModel) { - var textEl = el.getTextContent(); - var guideLine = el.getTextGuideLine(); // Animate - - if (textEl // `forceLabelAnimation` has the highest priority - && (el.forceLabelAnimation || !textEl.ignore && !textEl.invisible && !el.disableLabelAnimation && !isElementRemoved(el))) { - var layoutStore = labelLayoutInnerStore(textEl); - var oldLayout = layoutStore.oldLayout; - var ecData = getECData(el); - var dataIndex = ecData.dataIndex; - var newProps = { - x: textEl.x, - y: textEl.y, - rotation: textEl.rotation - }; - var data = seriesModel.getData(ecData.dataType); - - if (!oldLayout) { - textEl.attr(newProps); // Disable fade in animation if value animation is enabled. - - if (!labelInner(textEl).valueAnimation) { - var oldOpacity = retrieve2(textEl.style.opacity, 1); // Fade in animation - - textEl.style.opacity = 0; - initProps(textEl, { - style: { - opacity: oldOpacity - } - }, seriesModel, dataIndex); - } - } else { - textEl.attr(oldLayout); // Make sure the animation from is in the right status. - - var prevStates = el.prevStates; - - if (prevStates) { - if (indexOf(prevStates, 'select') >= 0) { - textEl.attr(layoutStore.oldLayoutSelect); - } - - if (indexOf(prevStates, 'emphasis') >= 0) { - textEl.attr(layoutStore.oldLayoutEmphasis); - } - } - - updateProps$1(textEl, newProps, seriesModel, dataIndex); - } - - layoutStore.oldLayout = newProps; - - if (textEl.states.select) { - var layoutSelect = layoutStore.oldLayoutSelect = {}; - extendWithKeys(layoutSelect, newProps, LABEL_LAYOUT_PROPS); - extendWithKeys(layoutSelect, textEl.states.select, LABEL_LAYOUT_PROPS); - } - - if (textEl.states.emphasis) { - var layoutEmphasis = layoutStore.oldLayoutEmphasis = {}; - extendWithKeys(layoutEmphasis, newProps, LABEL_LAYOUT_PROPS); - extendWithKeys(layoutEmphasis, textEl.states.emphasis, LABEL_LAYOUT_PROPS); - } - - animateLabelValue(textEl, dataIndex, data, seriesModel, seriesModel); - } - - if (guideLine && !guideLine.ignore && !guideLine.invisible) { - var layoutStore = labelLineAnimationStore(guideLine); - var oldLayout = layoutStore.oldLayout; - var newLayout = { - points: guideLine.shape.points - }; - - if (!oldLayout) { - guideLine.setShape(newLayout); - guideLine.style.strokePercent = 0; - initProps(guideLine, { - style: { - strokePercent: 1 - } - }, seriesModel); - } else { - guideLine.attr({ - shape: oldLayout - }); - updateProps$1(guideLine, { - shape: newLayout - }, seriesModel); - } - - layoutStore.oldLayout = newLayout; - } - }; - - return LabelManager; - }(); - - var getLabelManager = makeInner(); - - function installLabelLayout(registers) { - registers.registerUpdateLifecycle('series:beforeupdate', function (ecModel, api, params) { - // TODO api provide an namespace that can save stuff per instance - var labelManager = getLabelManager(api).labelManager; - - if (!labelManager) { - labelManager = getLabelManager(api).labelManager = new LabelManager(); - } - - labelManager.clearLabels(); - }); - registers.registerUpdateLifecycle('series:layoutlabels', function (ecModel, api, params) { - var labelManager = getLabelManager(api).labelManager; - params.updatedSeries.forEach(function (series) { - labelManager.addLabelsOfSeries(api.getViewOfSeriesModel(series)); - }); - labelManager.updateLayoutConfig(api); - labelManager.layout(api); - labelManager.processLabelsOverall(); - }); - } - - use(installLabelLayout); - - function createDom(id, painter, dpr) { - var newDom = platformApi.createCanvas(); - var width = painter.getWidth(); - var height = painter.getHeight(); - var newDomStyle = newDom.style; - - if (newDomStyle) { - newDomStyle.position = 'absolute'; - newDomStyle.left = '0'; - newDomStyle.top = '0'; - newDomStyle.width = width + 'px'; - newDomStyle.height = height + 'px'; - newDom.setAttribute('data-zr-dom-id', id); - } - - newDom.width = width * dpr; - newDom.height = height * dpr; - return newDom; - } - - var Layer = function (_super) { - __extends(Layer, _super); - - function Layer(id, painter, dpr) { - var _this = _super.call(this) || this; - - _this.motionBlur = false; - _this.lastFrameAlpha = 0.7; - _this.dpr = 1; - _this.virtual = false; - _this.config = {}; - _this.incremental = false; - _this.zlevel = 0; - _this.maxRepaintRectCount = 5; - _this.__dirty = true; - _this.__firstTimePaint = true; - _this.__used = false; - _this.__drawIndex = 0; - _this.__startIndex = 0; - _this.__endIndex = 0; - _this.__prevStartIndex = null; - _this.__prevEndIndex = null; - var dom; - dpr = dpr || devicePixelRatio; - - if (typeof id === 'string') { - dom = createDom(id, painter, dpr); - } else if (isObject$2(id)) { - dom = id; - id = dom.id; - } - - _this.id = id; - _this.dom = dom; - var domStyle = dom.style; - - if (domStyle) { - disableUserSelect(dom); - - dom.onselectstart = function () { - return false; - }; - - domStyle.padding = '0'; - domStyle.margin = '0'; - domStyle.borderWidth = '0'; - } - - _this.painter = painter; - _this.dpr = dpr; - return _this; - } - - Layer.prototype.getElementCount = function () { - return this.__endIndex - this.__startIndex; - }; - - Layer.prototype.afterBrush = function () { - this.__prevStartIndex = this.__startIndex; - this.__prevEndIndex = this.__endIndex; - }; - - Layer.prototype.initContext = function () { - this.ctx = this.dom.getContext('2d'); - this.ctx.dpr = this.dpr; - }; - - Layer.prototype.setUnpainted = function () { - this.__firstTimePaint = true; - }; - - Layer.prototype.createBackBuffer = function () { - var dpr = this.dpr; - this.domBack = createDom('back-' + this.id, this.painter, dpr); - this.ctxBack = this.domBack.getContext('2d'); - - if (dpr !== 1) { - this.ctxBack.scale(dpr, dpr); - } - }; - - Layer.prototype.createRepaintRects = function (displayList, prevList, viewWidth, viewHeight) { - if (this.__firstTimePaint) { - this.__firstTimePaint = false; - return null; - } - - var mergedRepaintRects = []; - var maxRepaintRectCount = this.maxRepaintRectCount; - var full = false; - var pendingRect = new BoundingRect(0, 0, 0, 0); - - function addRectToMergePool(rect) { - if (!rect.isFinite() || rect.isZero()) { - return; - } - - if (mergedRepaintRects.length === 0) { - var boundingRect = new BoundingRect(0, 0, 0, 0); - boundingRect.copy(rect); - mergedRepaintRects.push(boundingRect); - } else { - var isMerged = false; - var minDeltaArea = Infinity; - var bestRectToMergeIdx = 0; - - for (var i = 0; i < mergedRepaintRects.length; ++i) { - var mergedRect = mergedRepaintRects[i]; - - if (mergedRect.intersect(rect)) { - var pendingRect_1 = new BoundingRect(0, 0, 0, 0); - pendingRect_1.copy(mergedRect); - pendingRect_1.union(rect); - mergedRepaintRects[i] = pendingRect_1; - isMerged = true; - break; - } else if (full) { - pendingRect.copy(rect); - pendingRect.union(mergedRect); - var aArea = rect.width * rect.height; - var bArea = mergedRect.width * mergedRect.height; - var pendingArea = pendingRect.width * pendingRect.height; - var deltaArea = pendingArea - aArea - bArea; - - if (deltaArea < minDeltaArea) { - minDeltaArea = deltaArea; - bestRectToMergeIdx = i; - } - } - } - - if (full) { - mergedRepaintRects[bestRectToMergeIdx].union(rect); - isMerged = true; - } - - if (!isMerged) { - var boundingRect = new BoundingRect(0, 0, 0, 0); - boundingRect.copy(rect); - mergedRepaintRects.push(boundingRect); - } - - if (!full) { - full = mergedRepaintRects.length >= maxRepaintRectCount; - } - } - } - - for (var i = this.__startIndex; i < this.__endIndex; ++i) { - var el = displayList[i]; - - if (el) { - var shouldPaint = el.shouldBePainted(viewWidth, viewHeight, true, true); - var prevRect = el.__isRendered && (el.__dirty & REDRAW_BIT || !shouldPaint) ? el.getPrevPaintRect() : null; - - if (prevRect) { - addRectToMergePool(prevRect); - } - - var curRect = shouldPaint && (el.__dirty & REDRAW_BIT || !el.__isRendered) ? el.getPaintRect() : null; - - if (curRect) { - addRectToMergePool(curRect); - } - } - } - - for (var i = this.__prevStartIndex; i < this.__prevEndIndex; ++i) { - var el = prevList[i]; - var shouldPaint = el && el.shouldBePainted(viewWidth, viewHeight, true, true); - - if (el && (!shouldPaint || !el.__zr) && el.__isRendered) { - var prevRect = el.getPrevPaintRect(); - - if (prevRect) { - addRectToMergePool(prevRect); - } - } - } - - var hasIntersections; - - do { - hasIntersections = false; - - for (var i = 0; i < mergedRepaintRects.length;) { - if (mergedRepaintRects[i].isZero()) { - mergedRepaintRects.splice(i, 1); - continue; - } - - for (var j = i + 1; j < mergedRepaintRects.length;) { - if (mergedRepaintRects[i].intersect(mergedRepaintRects[j])) { - hasIntersections = true; - mergedRepaintRects[i].union(mergedRepaintRects[j]); - mergedRepaintRects.splice(j, 1); - } else { - j++; - } - } - - i++; - } - } while (hasIntersections); - - this._paintRects = mergedRepaintRects; - return mergedRepaintRects; - }; - - Layer.prototype.debugGetPaintRects = function () { - return (this._paintRects || []).slice(); - }; - - Layer.prototype.resize = function (width, height) { - var dpr = this.dpr; - var dom = this.dom; - var domStyle = dom.style; - var domBack = this.domBack; - - if (domStyle) { - domStyle.width = width + 'px'; - domStyle.height = height + 'px'; - } - - dom.width = width * dpr; - dom.height = height * dpr; - - if (domBack) { - domBack.width = width * dpr; - domBack.height = height * dpr; - - if (dpr !== 1) { - this.ctxBack.scale(dpr, dpr); - } - } - }; - - Layer.prototype.clear = function (clearAll, clearColor, repaintRects) { - var dom = this.dom; - var ctx = this.ctx; - var width = dom.width; - var height = dom.height; - clearColor = clearColor || this.clearColor; - var haveMotionBLur = this.motionBlur && !clearAll; - var lastFrameAlpha = this.lastFrameAlpha; - var dpr = this.dpr; - var self = this; - - if (haveMotionBLur) { - if (!this.domBack) { - this.createBackBuffer(); - } - - this.ctxBack.globalCompositeOperation = 'copy'; - this.ctxBack.drawImage(dom, 0, 0, width / dpr, height / dpr); - } - - var domBack = this.domBack; - - function doClear(x, y, width, height) { - ctx.clearRect(x, y, width, height); - - if (clearColor && clearColor !== 'transparent') { - var clearColorGradientOrPattern = void 0; - - if (isGradientObject(clearColor)) { - var shouldCache = clearColor.global || clearColor.__width === width && clearColor.__height === height; - clearColorGradientOrPattern = shouldCache && clearColor.__canvasGradient || getCanvasGradient(ctx, clearColor, { - x: 0, - y: 0, - width: width, - height: height - }); - clearColor.__canvasGradient = clearColorGradientOrPattern; - clearColor.__width = width; - clearColor.__height = height; - } else if (isImagePatternObject(clearColor)) { - clearColor.scaleX = clearColor.scaleX || dpr; - clearColor.scaleY = clearColor.scaleY || dpr; - clearColorGradientOrPattern = createCanvasPattern(ctx, clearColor, { - dirty: function () { - self.setUnpainted(); - self.painter.refresh(); - } - }); - } - - ctx.save(); - ctx.fillStyle = clearColorGradientOrPattern || clearColor; - ctx.fillRect(x, y, width, height); - ctx.restore(); - } - - if (haveMotionBLur) { - ctx.save(); - ctx.globalAlpha = lastFrameAlpha; - ctx.drawImage(domBack, x, y, width, height); - ctx.restore(); - } - } - - if (!repaintRects || haveMotionBLur) { - doClear(0, 0, width, height); - } else if (repaintRects.length) { - each$4(repaintRects, function (rect) { - doClear(rect.x * dpr, rect.y * dpr, rect.width * dpr, rect.height * dpr); - }); - } - }; - - return Layer; - }(Eventful); - - var HOVER_LAYER_ZLEVEL = 1e5; - var CANVAS_ZLEVEL = 314159; - var EL_AFTER_INCREMENTAL_INC = 0.01; - var INCREMENTAL_INC = 0.001; - - function isLayerValid(layer) { - if (!layer) { - return false; - } - - if (layer.__builtin__) { - return true; - } - - if (typeof layer.resize !== 'function' || typeof layer.refresh !== 'function') { - return false; - } - - return true; - } - - function createRoot(width, height) { - var domRoot = document.createElement('div'); - domRoot.style.cssText = ['position:relative', 'width:' + width + 'px', 'height:' + height + 'px', 'padding:0', 'margin:0', 'border-width:0'].join(';') + ';'; - return domRoot; - } - - var CanvasPainter = function () { - function CanvasPainter(root, storage, opts, id) { - this.type = 'canvas'; - this._zlevelList = []; - this._prevDisplayList = []; - this._layers = {}; - this._layerConfig = {}; - this._needsManuallyCompositing = false; - this.type = 'canvas'; - var singleCanvas = !root.nodeName || root.nodeName.toUpperCase() === 'CANVAS'; - this._opts = opts = extend({}, opts || {}); - this.dpr = opts.devicePixelRatio || devicePixelRatio; - this._singleCanvas = singleCanvas; - this.root = root; - var rootStyle = root.style; - - if (rootStyle) { - disableUserSelect(root); - root.innerHTML = ''; - } - - this.storage = storage; - var zlevelList = this._zlevelList; - this._prevDisplayList = []; - var layers = this._layers; - - if (!singleCanvas) { - this._width = getSize(root, 0, opts); - this._height = getSize(root, 1, opts); - var domRoot = this._domRoot = createRoot(this._width, this._height); - root.appendChild(domRoot); - } else { - var rootCanvas = root; - var width = rootCanvas.width; - var height = rootCanvas.height; - - if (opts.width != null) { - width = opts.width; - } - - if (opts.height != null) { - height = opts.height; - } - - this.dpr = opts.devicePixelRatio || 1; - rootCanvas.width = width * this.dpr; - rootCanvas.height = height * this.dpr; - this._width = width; - this._height = height; - var mainLayer = new Layer(rootCanvas, this, this.dpr); - mainLayer.__builtin__ = true; - mainLayer.initContext(); - layers[CANVAS_ZLEVEL] = mainLayer; - mainLayer.zlevel = CANVAS_ZLEVEL; - zlevelList.push(CANVAS_ZLEVEL); - this._domRoot = root; - } - } - - CanvasPainter.prototype.getType = function () { - return 'canvas'; - }; - - CanvasPainter.prototype.isSingleCanvas = function () { - return this._singleCanvas; - }; - - CanvasPainter.prototype.getViewportRoot = function () { - return this._domRoot; - }; - - CanvasPainter.prototype.getViewportRootOffset = function () { - var viewportRoot = this.getViewportRoot(); - - if (viewportRoot) { - return { - offsetLeft: viewportRoot.offsetLeft || 0, - offsetTop: viewportRoot.offsetTop || 0 - }; - } - }; - - CanvasPainter.prototype.refresh = function (paintAll) { - var list = this.storage.getDisplayList(true); - var prevList = this._prevDisplayList; - var zlevelList = this._zlevelList; - this._redrawId = Math.random(); - - this._paintList(list, prevList, paintAll, this._redrawId); - - for (var i = 0; i < zlevelList.length; i++) { - var z = zlevelList[i]; - var layer = this._layers[z]; - - if (!layer.__builtin__ && layer.refresh) { - var clearColor = i === 0 ? this._backgroundColor : null; - layer.refresh(clearColor); - } - } - - if (this._opts.useDirtyRect) { - this._prevDisplayList = list.slice(); - } - - return this; - }; - - CanvasPainter.prototype.refreshHover = function () { - this._paintHoverList(this.storage.getDisplayList(false)); - }; - - CanvasPainter.prototype._paintHoverList = function (list) { - var len = list.length; - var hoverLayer = this._hoverlayer; - hoverLayer && hoverLayer.clear(); - - if (!len) { - return; - } - - var scope = { - inHover: true, - viewWidth: this._width, - viewHeight: this._height - }; - var ctx; - - for (var i = 0; i < len; i++) { - var el = list[i]; - - if (el.__inHover) { - if (!hoverLayer) { - hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL); - } - - if (!ctx) { - ctx = hoverLayer.ctx; - ctx.save(); - } - - brush(ctx, el, scope, i === len - 1); - } - } - - if (ctx) { - ctx.restore(); - } - }; - - CanvasPainter.prototype.getHoverLayer = function () { - return this.getLayer(HOVER_LAYER_ZLEVEL); - }; - - CanvasPainter.prototype.paintOne = function (ctx, el) { - brushSingle(ctx, el); - }; - - CanvasPainter.prototype._paintList = function (list, prevList, paintAll, redrawId) { - if (this._redrawId !== redrawId) { - return; - } - - paintAll = paintAll || false; - - this._updateLayerStatus(list); - - var _a = this._doPaintList(list, prevList, paintAll), - finished = _a.finished, - needsRefreshHover = _a.needsRefreshHover; - - if (this._needsManuallyCompositing) { - this._compositeManually(); - } - - if (needsRefreshHover) { - this._paintHoverList(list); - } - - if (!finished) { - var self_1 = this; - requestAnimationFrame$1(function () { - self_1._paintList(list, prevList, paintAll, redrawId); - }); - } else { - this.eachLayer(function (layer) { - layer.afterBrush && layer.afterBrush(); - }); - } - }; - - CanvasPainter.prototype._compositeManually = function () { - var ctx = this.getLayer(CANVAS_ZLEVEL).ctx; - var width = this._domRoot.width; - var height = this._domRoot.height; - ctx.clearRect(0, 0, width, height); - this.eachBuiltinLayer(function (layer) { - if (layer.virtual) { - ctx.drawImage(layer.dom, 0, 0, width, height); - } - }); - }; - - CanvasPainter.prototype._doPaintList = function (list, prevList, paintAll) { - var _this = this; - - var layerList = []; - var useDirtyRect = this._opts.useDirtyRect; - - for (var zi = 0; zi < this._zlevelList.length; zi++) { - var zlevel = this._zlevelList[zi]; - var layer = this._layers[zlevel]; - - if (layer.__builtin__ && layer !== this._hoverlayer && (layer.__dirty || paintAll)) { - layerList.push(layer); - } - } - - var finished = true; - var needsRefreshHover = false; - - var _loop_1 = function (k) { - var layer = layerList[k]; - var ctx = layer.ctx; - var repaintRects = useDirtyRect && layer.createRepaintRects(list, prevList, this_1._width, this_1._height); - var start = paintAll ? layer.__startIndex : layer.__drawIndex; - var useTimer = !paintAll && layer.incremental && Date.now; - var startTime = useTimer && Date.now(); - var clearColor = layer.zlevel === this_1._zlevelList[0] ? this_1._backgroundColor : null; - - if (layer.__startIndex === layer.__endIndex) { - layer.clear(false, clearColor, repaintRects); - } else if (start === layer.__startIndex) { - var firstEl = list[start]; - - if (!firstEl.incremental || !firstEl.notClear || paintAll) { - layer.clear(false, clearColor, repaintRects); - } - } - - if (start === -1) { - console.error('For some unknown reason. drawIndex is -1'); - start = layer.__startIndex; - } - - var i; - - var repaint = function (repaintRect) { - var scope = { - inHover: false, - allClipped: false, - prevEl: null, - viewWidth: _this._width, - viewHeight: _this._height - }; - - for (i = start; i < layer.__endIndex; i++) { - var el = list[i]; - - if (el.__inHover) { - needsRefreshHover = true; - } - - _this._doPaintEl(el, layer, useDirtyRect, repaintRect, scope, i === layer.__endIndex - 1); - - if (useTimer) { - var dTime = Date.now() - startTime; - - if (dTime > 15) { - break; - } - } - } - - if (scope.prevElClipPaths) { - ctx.restore(); - } - }; - - if (repaintRects) { - if (repaintRects.length === 0) { - i = layer.__endIndex; - } else { - var dpr = this_1.dpr; - - for (var r = 0; r < repaintRects.length; ++r) { - var rect = repaintRects[r]; - ctx.save(); - ctx.beginPath(); - ctx.rect(rect.x * dpr, rect.y * dpr, rect.width * dpr, rect.height * dpr); - ctx.clip(); - repaint(rect); - ctx.restore(); - } - } - } else { - ctx.save(); - repaint(); - ctx.restore(); - } - - layer.__drawIndex = i; - - if (layer.__drawIndex < layer.__endIndex) { - finished = false; - } - }; - - var this_1 = this; - - for (var k = 0; k < layerList.length; k++) { - _loop_1(k); - } - - if (env.wxa) { - each$4(this._layers, function (layer) { - if (layer && layer.ctx && layer.ctx.draw) { - layer.ctx.draw(); - } - }); - } - - return { - finished: finished, - needsRefreshHover: needsRefreshHover - }; - }; - - CanvasPainter.prototype._doPaintEl = function (el, currentLayer, useDirtyRect, repaintRect, scope, isLast) { - var ctx = currentLayer.ctx; - - if (useDirtyRect) { - var paintRect = el.getPaintRect(); - - if (!repaintRect || paintRect && paintRect.intersect(repaintRect)) { - brush(ctx, el, scope, isLast); - el.setPrevPaintRect(paintRect); - } - } else { - brush(ctx, el, scope, isLast); - } - }; - - CanvasPainter.prototype.getLayer = function (zlevel, virtual) { - if (this._singleCanvas && !this._needsManuallyCompositing) { - zlevel = CANVAS_ZLEVEL; - } - - var layer = this._layers[zlevel]; - - if (!layer) { - layer = new Layer('zr_' + zlevel, this, this.dpr); - layer.zlevel = zlevel; - layer.__builtin__ = true; - - if (this._layerConfig[zlevel]) { - merge(layer, this._layerConfig[zlevel], true); - } else if (this._layerConfig[zlevel - EL_AFTER_INCREMENTAL_INC]) { - merge(layer, this._layerConfig[zlevel - EL_AFTER_INCREMENTAL_INC], true); - } - - if (virtual) { - layer.virtual = virtual; - } - - this.insertLayer(zlevel, layer); - layer.initContext(); - } - - return layer; - }; - - CanvasPainter.prototype.insertLayer = function (zlevel, layer) { - var layersMap = this._layers; - var zlevelList = this._zlevelList; - var len = zlevelList.length; - var domRoot = this._domRoot; - var prevLayer = null; - var i = -1; - - if (layersMap[zlevel]) { - { - logError('ZLevel ' + zlevel + ' has been used already'); - } - return; - } - - if (!isLayerValid(layer)) { - { - logError('Layer of zlevel ' + zlevel + ' is not valid'); - } - return; - } - - if (len > 0 && zlevel > zlevelList[0]) { - for (i = 0; i < len - 1; i++) { - if (zlevelList[i] < zlevel && zlevelList[i + 1] > zlevel) { - break; - } - } - - prevLayer = layersMap[zlevelList[i]]; - } - - zlevelList.splice(i + 1, 0, zlevel); - layersMap[zlevel] = layer; - - if (!layer.virtual) { - if (prevLayer) { - var prevDom = prevLayer.dom; - - if (prevDom.nextSibling) { - domRoot.insertBefore(layer.dom, prevDom.nextSibling); - } else { - domRoot.appendChild(layer.dom); - } - } else { - if (domRoot.firstChild) { - domRoot.insertBefore(layer.dom, domRoot.firstChild); - } else { - domRoot.appendChild(layer.dom); - } - } - } - - layer.painter || (layer.painter = this); - }; - - CanvasPainter.prototype.eachLayer = function (cb, context) { - var zlevelList = this._zlevelList; - - for (var i = 0; i < zlevelList.length; i++) { - var z = zlevelList[i]; - cb.call(context, this._layers[z], z); - } - }; - - CanvasPainter.prototype.eachBuiltinLayer = function (cb, context) { - var zlevelList = this._zlevelList; - - for (var i = 0; i < zlevelList.length; i++) { - var z = zlevelList[i]; - var layer = this._layers[z]; - - if (layer.__builtin__) { - cb.call(context, layer, z); - } - } - }; - - CanvasPainter.prototype.eachOtherLayer = function (cb, context) { - var zlevelList = this._zlevelList; - - for (var i = 0; i < zlevelList.length; i++) { - var z = zlevelList[i]; - var layer = this._layers[z]; - - if (!layer.__builtin__) { - cb.call(context, layer, z); - } - } - }; - - CanvasPainter.prototype.getLayers = function () { - return this._layers; - }; - - CanvasPainter.prototype._updateLayerStatus = function (list) { - this.eachBuiltinLayer(function (layer, z) { - layer.__dirty = layer.__used = false; - }); - - function updatePrevLayer(idx) { - if (prevLayer) { - if (prevLayer.__endIndex !== idx) { - prevLayer.__dirty = true; - } - - prevLayer.__endIndex = idx; - } - } - - if (this._singleCanvas) { - for (var i_1 = 1; i_1 < list.length; i_1++) { - var el = list[i_1]; - - if (el.zlevel !== list[i_1 - 1].zlevel || el.incremental) { - this._needsManuallyCompositing = true; - break; - } - } - } - - var prevLayer = null; - var incrementalLayerCount = 0; - var prevZlevel; - var i; - - for (i = 0; i < list.length; i++) { - var el = list[i]; - var zlevel = el.zlevel; - var layer = void 0; - - if (prevZlevel !== zlevel) { - prevZlevel = zlevel; - incrementalLayerCount = 0; - } - - if (el.incremental) { - layer = this.getLayer(zlevel + INCREMENTAL_INC, this._needsManuallyCompositing); - layer.incremental = true; - incrementalLayerCount = 1; - } else { - layer = this.getLayer(zlevel + (incrementalLayerCount > 0 ? EL_AFTER_INCREMENTAL_INC : 0), this._needsManuallyCompositing); - } - - if (!layer.__builtin__) { - logError('ZLevel ' + zlevel + ' has been used by unkown layer ' + layer.id); - } - - if (layer !== prevLayer) { - layer.__used = true; - - if (layer.__startIndex !== i) { - layer.__dirty = true; - } - - layer.__startIndex = i; - - if (!layer.incremental) { - layer.__drawIndex = i; - } else { - layer.__drawIndex = -1; - } - - updatePrevLayer(i); - prevLayer = layer; - } - - if (el.__dirty & REDRAW_BIT && !el.__inHover) { - layer.__dirty = true; - - if (layer.incremental && layer.__drawIndex < 0) { - layer.__drawIndex = i; - } - } - } - - updatePrevLayer(i); - this.eachBuiltinLayer(function (layer, z) { - if (!layer.__used && layer.getElementCount() > 0) { - layer.__dirty = true; - layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0; - } - - if (layer.__dirty && layer.__drawIndex < 0) { - layer.__drawIndex = layer.__startIndex; - } - }); - }; - - CanvasPainter.prototype.clear = function () { - this.eachBuiltinLayer(this._clearLayer); - return this; - }; - - CanvasPainter.prototype._clearLayer = function (layer) { - layer.clear(); - }; - - CanvasPainter.prototype.setBackgroundColor = function (backgroundColor) { - this._backgroundColor = backgroundColor; - each$4(this._layers, function (layer) { - layer.setUnpainted(); - }); - }; - - CanvasPainter.prototype.configLayer = function (zlevel, config) { - if (config) { - var layerConfig = this._layerConfig; - - if (!layerConfig[zlevel]) { - layerConfig[zlevel] = config; - } else { - merge(layerConfig[zlevel], config, true); - } - - for (var i = 0; i < this._zlevelList.length; i++) { - var _zlevel = this._zlevelList[i]; - - if (_zlevel === zlevel || _zlevel === zlevel + EL_AFTER_INCREMENTAL_INC) { - var layer = this._layers[_zlevel]; - merge(layer, layerConfig[zlevel], true); - } - } - } - }; - - CanvasPainter.prototype.delLayer = function (zlevel) { - var layers = this._layers; - var zlevelList = this._zlevelList; - var layer = layers[zlevel]; - - if (!layer) { - return; - } - - layer.dom.parentNode.removeChild(layer.dom); - delete layers[zlevel]; - zlevelList.splice(indexOf(zlevelList, zlevel), 1); - }; - - CanvasPainter.prototype.resize = function (width, height) { - if (!this._domRoot.style) { - if (width == null || height == null) { - return; - } - - this._width = width; - this._height = height; - this.getLayer(CANVAS_ZLEVEL).resize(width, height); - } else { - var domRoot = this._domRoot; - domRoot.style.display = 'none'; - var opts = this._opts; - var root = this.root; - width != null && (opts.width = width); - height != null && (opts.height = height); - width = getSize(root, 0, opts); - height = getSize(root, 1, opts); - domRoot.style.display = ''; - - if (this._width !== width || height !== this._height) { - domRoot.style.width = width + 'px'; - domRoot.style.height = height + 'px'; - - for (var id in this._layers) { - if (this._layers.hasOwnProperty(id)) { - this._layers[id].resize(width, height); - } - } - - this.refresh(true); - } - - this._width = width; - this._height = height; - } - - return this; - }; - - CanvasPainter.prototype.clearLayer = function (zlevel) { - var layer = this._layers[zlevel]; - - if (layer) { - layer.clear(); - } - }; - - CanvasPainter.prototype.dispose = function () { - this.root.innerHTML = ''; - this.root = this.storage = this._domRoot = this._layers = null; - }; - - CanvasPainter.prototype.getRenderedCanvas = function (opts) { - opts = opts || {}; - - if (this._singleCanvas && !this._compositeManually) { - return this._layers[CANVAS_ZLEVEL].dom; - } - - var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr); - imageLayer.initContext(); - imageLayer.clear(false, opts.backgroundColor || this._backgroundColor); - var ctx = imageLayer.ctx; - - if (opts.pixelRatio <= this.dpr) { - this.refresh(); - var width_1 = imageLayer.dom.width; - var height_1 = imageLayer.dom.height; - this.eachLayer(function (layer) { - if (layer.__builtin__) { - ctx.drawImage(layer.dom, 0, 0, width_1, height_1); - } else if (layer.renderToCanvas) { - ctx.save(); - layer.renderToCanvas(ctx); - ctx.restore(); - } - }); - } else { - var scope = { - inHover: false, - viewWidth: this._width, - viewHeight: this._height - }; - var displayList = this.storage.getDisplayList(true); - - for (var i = 0, len = displayList.length; i < len; i++) { - var el = displayList[i]; - brush(ctx, el, scope, i === len - 1); - } - } - - return imageLayer.dom; - }; - - CanvasPainter.prototype.getWidth = function () { - return this._width; - }; - - CanvasPainter.prototype.getHeight = function () { - return this._height; - }; - - return CanvasPainter; - }(); - - function install$b(registers) { - registers.registerPainter('canvas', CanvasPainter); - } - - var DatasetModel = - /** @class */ - function (_super) { - __extends(DatasetModel, _super); - - function DatasetModel() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = 'dataset'; - return _this; - } - - DatasetModel.prototype.init = function (option, parentModel, ecModel) { - _super.prototype.init.call(this, option, parentModel, ecModel); - - this._sourceManager = new SourceManager(this); - disableTransformOptionMerge(this); - }; - - DatasetModel.prototype.mergeOption = function (newOption, ecModel) { - _super.prototype.mergeOption.call(this, newOption, ecModel); - - disableTransformOptionMerge(this); - }; - - DatasetModel.prototype.optionUpdated = function () { - this._sourceManager.dirty(); - }; - - DatasetModel.prototype.getSourceManager = function () { - return this._sourceManager; - }; - - DatasetModel.type = 'dataset'; - DatasetModel.defaultOption = { - seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN - }; - return DatasetModel; - }(ComponentModel); - - var DatasetView = - /** @class */ - function (_super) { - __extends(DatasetView, _super); - - function DatasetView() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = 'dataset'; - return _this; - } - - DatasetView.type = 'dataset'; - return DatasetView; - }(ComponentView); - - function install$a(registers) { - registers.registerComponentModel(DatasetModel); - registers.registerComponentView(DatasetView); - } // Default to have canvas renderer and dataset for compitatble reason. - - - use([install$b, install$a]); - use(installLabelLayout); - var samplers = { - average: function (frame) { - var sum = 0; - var count = 0; - - for (var i = 0; i < frame.length; i++) { - if (!isNaN(frame[i])) { - sum += frame[i]; - count++; - } - } // Return NaN if count is 0 - - - return count === 0 ? NaN : sum / count; - }, - sum: function (frame) { - var sum = 0; - - for (var i = 0; i < frame.length; i++) { - // Ignore NaN - sum += frame[i] || 0; - } - - return sum; - }, - max: function (frame) { - var max = -Infinity; - - for (var i = 0; i < frame.length; i++) { - frame[i] > max && (max = frame[i]); - } // NaN will cause illegal axis extent. - - - return isFinite(max) ? max : NaN; - }, - min: function (frame) { - var min = Infinity; - - for (var i = 0; i < frame.length; i++) { - frame[i] < min && (min = frame[i]); - } // NaN will cause illegal axis extent. - - - return isFinite(min) ? min : NaN; - }, - // TODO - // Median - nearest: function (frame) { - return frame[0]; - } - }; - - var indexSampler = function (frame) { - return Math.round(frame.length / 2); - }; - - function dataSample(seriesType) { - return { - seriesType: seriesType, - // FIXME:TS never used, so comment it - // modifyOutputEnd: true, - reset: function (seriesModel, ecModel, api) { - var data = seriesModel.getData(); - var sampling = seriesModel.get('sampling'); - var coordSys = seriesModel.coordinateSystem; - var count = data.count(); // Only cartesian2d support down sampling. Disable it when there is few data. - - if (count > 10 && coordSys.type === 'cartesian2d' && sampling) { - var baseAxis = coordSys.getBaseAxis(); - var valueAxis = coordSys.getOtherAxis(baseAxis); - var extent = baseAxis.getExtent(); - var dpr = api.getDevicePixelRatio(); // Coordinste system has been resized - - var size = Math.abs(extent[1] - extent[0]) * (dpr || 1); - var rate = Math.round(count / size); - - if (isFinite(rate) && rate > 1) { - if (sampling === 'lttb') { - seriesModel.setData(data.lttbDownSample(data.mapDimension(valueAxis.dim), 1 / rate)); - } else if (sampling === 'minmax') { - seriesModel.setData(data.minmaxDownSample(data.mapDimension(valueAxis.dim), 1 / rate)); - } - - var sampler = void 0; - - if (isString(sampling)) { - sampler = samplers[sampling]; - } else if (isFunction(sampling)) { - sampler = sampling; - } - - if (sampler) { - // Only support sample the first dim mapped from value axis. - seriesModel.setData(data.downSample(data.mapDimension(valueAxis.dim), 1 / rate, sampler, indexSampler)); - } - } - } - } - }; - } - - var BaseBarSeriesModel = - /** @class */ - function (_super) { - __extends(BaseBarSeriesModel, _super); - - function BaseBarSeriesModel() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = BaseBarSeriesModel.type; - return _this; - } - - BaseBarSeriesModel.prototype.getInitialData = function (option, ecModel) { - return createSeriesData(null, this, { - useEncodeDefaulter: true - }); - }; - - BaseBarSeriesModel.prototype.getMarkerPosition = function (value, dims, startingAtTick) { - var coordSys = this.coordinateSystem; - - if (coordSys && coordSys.clampData) { - // PENDING if clamp ? - var clampData_1 = coordSys.clampData(value); - var pt_1 = coordSys.dataToPoint(clampData_1); - - if (startingAtTick) { - each$4(coordSys.getAxes(), function (axis, idx) { - // If axis type is category, use tick coords instead - if (axis.type === 'category' && dims != null) { - var tickCoords = axis.getTicksCoords(); - var alignTicksWithLabel = axis.getTickModel().get('alignWithLabel'); - var targetTickId = clampData_1[idx]; // The index of rightmost tick of markArea is 1 larger than x1/y1 index - - var isEnd = dims[idx] === 'x1' || dims[idx] === 'y1'; - - if (isEnd && !alignTicksWithLabel) { - targetTickId += 1; - } // The only contains one tick, tickCoords is - // like [{coord: 0, tickValue: 0}, {coord: 0}] - // to the length should always be larger than 1 - - - if (tickCoords.length < 2) { - return; - } else if (tickCoords.length === 2) { - // The left value and right value of the axis are - // the same. coord is 0 in both items. Use the max - // value of the axis as the coord - pt_1[idx] = axis.toGlobalCoord(axis.getExtent()[isEnd ? 1 : 0]); - return; - } - - var leftCoord = void 0; - var coord = void 0; - var stepTickValue = 1; - - for (var i = 0; i < tickCoords.length; i++) { - var tickCoord = tickCoords[i].coord; // The last item of tickCoords doesn't contain - // tickValue - - var tickValue = i === tickCoords.length - 1 ? tickCoords[i - 1].tickValue + stepTickValue : tickCoords[i].tickValue; - - if (tickValue === targetTickId) { - coord = tickCoord; - break; - } else if (tickValue < targetTickId) { - leftCoord = tickCoord; - } else if (leftCoord != null && tickValue > targetTickId) { - coord = (tickCoord + leftCoord) / 2; - break; - } - - if (i === 1) { - // Here we assume the step of category axes is - // the same - stepTickValue = tickValue - tickCoords[0].tickValue; - } - } - - if (coord == null) { - if (!leftCoord) { - // targetTickId is smaller than all tick ids in the - // visible area, use the leftmost tick coord - coord = tickCoords[0].coord; - } else if (leftCoord) { - // targetTickId is larger than all tick ids in the - // visible area, use the rightmost tick coord - coord = tickCoords[tickCoords.length - 1].coord; - } - } - - pt_1[idx] = axis.toGlobalCoord(coord); - } - }); - } else { - var data = this.getData(); - var offset = data.getLayout('offset'); - var size = data.getLayout('size'); - var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1; - pt_1[offsetIndex] += offset + size / 2; - } - - return pt_1; - } - - return [NaN, NaN]; - }; - - BaseBarSeriesModel.type = 'series.__base_bar__'; - BaseBarSeriesModel.defaultOption = { - // zlevel: 0, - z: 2, - coordinateSystem: 'cartesian2d', - legendHoverLink: true, - // stack: null - // Cartesian coordinate system - // xAxisIndex: 0, - // yAxisIndex: 0, - barMinHeight: 0, - barMinAngle: 0, - // cursor: null, - large: false, - largeThreshold: 400, - progressive: 3e3, - progressiveChunkMode: 'mod', - defaultBarGap: '10%' - }; - return BaseBarSeriesModel; - }(SeriesModel); - - SeriesModel.registerClass(BaseBarSeriesModel); - - var BarSeriesModel = - /** @class */ - function (_super) { - __extends(BarSeriesModel, _super); - - function BarSeriesModel() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = BarSeriesModel.type; - return _this; - } - - BarSeriesModel.prototype.getInitialData = function () { - return createSeriesData(null, this, { - useEncodeDefaulter: true, - createInvertedIndices: !!this.get('realtimeSort', true) || null - }); - }; - /** - * @override - */ - - - BarSeriesModel.prototype.getProgressive = function () { - // Do not support progressive in normal mode. - return this.get('large') ? this.get('progressive') : false; - }; - /** - * @override - */ - - - BarSeriesModel.prototype.getProgressiveThreshold = function () { - // Do not support progressive in normal mode. - var progressiveThreshold = this.get('progressiveThreshold'); - var largeThreshold = this.get('largeThreshold'); - - if (largeThreshold > progressiveThreshold) { - progressiveThreshold = largeThreshold; - } - - return progressiveThreshold; - }; - - BarSeriesModel.prototype.brushSelector = function (dataIndex, data, selectors) { - return selectors.rect(data.getItemLayout(dataIndex)); - }; - - BarSeriesModel.type = 'series.bar'; - BarSeriesModel.dependencies = ['grid', 'polar']; - BarSeriesModel.defaultOption = inheritDefaultOption(BaseBarSeriesModel.defaultOption, { - // If clipped - // Only available on cartesian2d - clip: true, - roundCap: false, - showBackground: false, - backgroundStyle: { - color: 'rgba(180, 180, 180, 0.2)', - borderColor: null, - borderWidth: 0, - borderType: 'solid', - borderRadius: 0, - shadowBlur: 0, - shadowColor: null, - shadowOffsetX: 0, - shadowOffsetY: 0, - opacity: 1 - }, - select: { - itemStyle: { - borderColor: tokens.color.primary, - borderWidth: 2 - } - }, - realtimeSort: false - }); - return BarSeriesModel; - }(BaseBarSeriesModel); - - function createGridClipPath(cartesian, hasAnimation, seriesModel, done, during) { - var rect = cartesian.getArea(); - var x = rect.x; - var y = rect.y; - var width = rect.width; - var height = rect.height; - var lineWidth = seriesModel.get(['lineStyle', 'width']) || 0; // Expand the clip path a bit to avoid the border is clipped and looks thinner - - x -= lineWidth / 2; - y -= lineWidth / 2; - width += lineWidth; - height += lineWidth; // fix: https://github.com/apache/incubator-echarts/issues/11369 - - width = Math.ceil(width); - - if (x !== Math.floor(x)) { - x = Math.floor(x); // if no extra 1px on `width`, it will still be clipped since `x` is floored - - width++; - } - - var clipPath = new Rect({ - shape: { - x: x, - y: y, - width: width, - height: height - } - }); - - if (hasAnimation) { - var baseAxis = cartesian.getBaseAxis(); - var isHorizontal = baseAxis.isHorizontal(); - var isAxisInversed = baseAxis.inverse; - - if (isHorizontal) { - if (isAxisInversed) { - clipPath.shape.x += width; - } - - clipPath.shape.width = 0; - } else { - if (!isAxisInversed) { - clipPath.shape.y += height; - } - - clipPath.shape.height = 0; - } - - var duringCb = isFunction(during) ? function (percent) { - during(percent, clipPath); - } : null; - initProps(clipPath, { - shape: { - width: width, - height: height, - x: x, - y: y - } - }, seriesModel, null, done, duringCb); - } - - return clipPath; - } - - function createPolarClipPath(polar, hasAnimation, seriesModel) { - var sectorArea = polar.getArea(); // Avoid float number rounding error for symbol on the edge of axis extent. - - var r0 = round$1(sectorArea.r0, 1); - var r = round$1(sectorArea.r, 1); - var clipPath = new Sector({ - shape: { - cx: round$1(polar.cx, 1), - cy: round$1(polar.cy, 1), - r0: r0, - r: r, - startAngle: sectorArea.startAngle, - endAngle: sectorArea.endAngle, - clockwise: sectorArea.clockwise - } - }); - - if (hasAnimation) { - var isRadial = polar.getBaseAxis().dim === 'angle'; - - if (isRadial) { - clipPath.shape.endAngle = sectorArea.startAngle; - } else { - clipPath.shape.r = r0; - } - - initProps(clipPath, { - shape: { - endAngle: sectorArea.endAngle, - r: r - } - }, seriesModel); - } - - return clipPath; - } - - function createClipPath(coordSys, hasAnimation, seriesModel, done, during) { - if (!coordSys) { - return null; - } else if (coordSys.type === 'polar') { - return createPolarClipPath(coordSys, hasAnimation, seriesModel); - } else if (coordSys.type === 'cartesian2d') { - return createGridClipPath(coordSys, hasAnimation, seriesModel, done, during); - } - - return null; - } - /** - * Sausage: similar to sector, but have half circle on both sides - */ - - - var SausageShape = - /** @class */ - function () { - function SausageShape() { - this.cx = 0; - this.cy = 0; - this.r0 = 0; - this.r = 0; - this.startAngle = 0; - this.endAngle = Math.PI * 2; - this.clockwise = true; - } - - return SausageShape; - }(); - - var SausagePath = - /** @class */ - function (_super) { - __extends(SausagePath, _super); - - function SausagePath(opts) { - var _this = _super.call(this, opts) || this; - - _this.type = 'sausage'; - return _this; - } - - SausagePath.prototype.getDefaultShape = function () { - return new SausageShape(); - }; - - SausagePath.prototype.buildPath = function (ctx, shape) { - var cx = shape.cx; - var cy = shape.cy; - var r0 = Math.max(shape.r0 || 0, 0); - var r = Math.max(shape.r, 0); - var dr = (r - r0) * 0.5; - var rCenter = r0 + dr; - var startAngle = shape.startAngle; - var endAngle = shape.endAngle; - var clockwise = shape.clockwise; - var PI2 = Math.PI * 2; - var lessThanCircle = clockwise ? endAngle - startAngle < PI2 : startAngle - endAngle < PI2; - - if (!lessThanCircle) { - // Normalize angles - startAngle = endAngle - (clockwise ? PI2 : -PI2); - } - - var unitStartX = Math.cos(startAngle); - var unitStartY = Math.sin(startAngle); - var unitEndX = Math.cos(endAngle); - var unitEndY = Math.sin(endAngle); - - if (lessThanCircle) { - ctx.moveTo(unitStartX * r0 + cx, unitStartY * r0 + cy); - ctx.arc(unitStartX * rCenter + cx, unitStartY * rCenter + cy, dr, -Math.PI + startAngle, startAngle, !clockwise); - } else { - ctx.moveTo(unitStartX * r + cx, unitStartY * r + cy); - } - - ctx.arc(cx, cy, r, startAngle, endAngle, !clockwise); - ctx.arc(unitEndX * rCenter + cx, unitEndY * rCenter + cy, dr, endAngle - Math.PI * 2, endAngle - Math.PI, !clockwise); - - if (r0 !== 0) { - ctx.arc(cx, cy, r0, endAngle, startAngle, clockwise); - } // ctx.closePath(); - - }; - - return SausagePath; - }(Path); - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * AUTO-GENERATED FILE. DO NOT MODIFY. - */ - - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - - function isCoordinateSystemType(coordSys, type) { - return coordSys.type === type; - } - /** - * @return label string. Not null/undefined - */ - - - function getDefaultLabel(data, dataIndex) { - var labelDims = data.mapDimensionsAll('defaultedLabel'); - var len = labelDims.length; // Simple optimization (in lots of cases, label dims length is 1) - - if (len === 1) { - var rawVal = retrieveRawValue(data, dataIndex, labelDims[0]); - return rawVal != null ? rawVal + '' : null; - } else if (len) { - var vals = []; - - for (var i = 0; i < labelDims.length; i++) { - vals.push(retrieveRawValue(data, dataIndex, labelDims[i])); - } - - return vals.join(' '); - } - } - - function getDefaultInterpolatedLabel(data, interpolatedValue) { - var labelDims = data.mapDimensionsAll('defaultedLabel'); - - if (!isArray(interpolatedValue)) { - return interpolatedValue + ''; - } - - var vals = []; - - for (var i = 0; i < labelDims.length; i++) { - var dimIndex = data.getDimensionIndex(labelDims[i]); - - if (dimIndex >= 0) { - vals.push(interpolatedValue[dimIndex]); - } - } - - return vals.join(' '); - } - - function createSectorCalculateTextPosition(positionMapping, opts) { - opts = opts || {}; - var isRoundCap = opts.isRoundCap; - return function (out, opts, boundingRect) { - var textPosition = opts.position; - - if (!textPosition || textPosition instanceof Array) { - return calculateTextPosition(out, opts, boundingRect); - } - - var mappedSectorPosition = positionMapping(textPosition); - var distance = opts.distance != null ? opts.distance : 5; - var sector = this.shape; - var cx = sector.cx; - var cy = sector.cy; - var r = sector.r; - var r0 = sector.r0; - var middleR = (r + r0) / 2; - var startAngle = sector.startAngle; - var endAngle = sector.endAngle; - var middleAngle = (startAngle + endAngle) / 2; - var extraDist = isRoundCap ? Math.abs(r - r0) / 2 : 0; - var mathCos = Math.cos; - var mathSin = Math.sin; // base position: top-left - - var x = cx + r * mathCos(startAngle); - var y = cy + r * mathSin(startAngle); - var textAlign = 'left'; - var textVerticalAlign = 'top'; - - switch (mappedSectorPosition) { - case 'startArc': - x = cx + (r0 - distance) * mathCos(middleAngle); - y = cy + (r0 - distance) * mathSin(middleAngle); - textAlign = 'center'; - textVerticalAlign = 'top'; - break; - - case 'insideStartArc': - x = cx + (r0 + distance) * mathCos(middleAngle); - y = cy + (r0 + distance) * mathSin(middleAngle); - textAlign = 'center'; - textVerticalAlign = 'bottom'; - break; - - case 'startAngle': - x = cx + middleR * mathCos(startAngle) + adjustAngleDistanceX(startAngle, distance + extraDist, false); - y = cy + middleR * mathSin(startAngle) + adjustAngleDistanceY(startAngle, distance + extraDist, false); - textAlign = 'right'; - textVerticalAlign = 'middle'; - break; - - case 'insideStartAngle': - x = cx + middleR * mathCos(startAngle) + adjustAngleDistanceX(startAngle, -distance + extraDist, false); - y = cy + middleR * mathSin(startAngle) + adjustAngleDistanceY(startAngle, -distance + extraDist, false); - textAlign = 'left'; - textVerticalAlign = 'middle'; - break; - - case 'middle': - x = cx + middleR * mathCos(middleAngle); - y = cy + middleR * mathSin(middleAngle); - textAlign = 'center'; - textVerticalAlign = 'middle'; - break; - - case 'endArc': - x = cx + (r + distance) * mathCos(middleAngle); - y = cy + (r + distance) * mathSin(middleAngle); - textAlign = 'center'; - textVerticalAlign = 'bottom'; - break; - - case 'insideEndArc': - x = cx + (r - distance) * mathCos(middleAngle); - y = cy + (r - distance) * mathSin(middleAngle); - textAlign = 'center'; - textVerticalAlign = 'top'; - break; - - case 'endAngle': - x = cx + middleR * mathCos(endAngle) + adjustAngleDistanceX(endAngle, distance + extraDist, true); - y = cy + middleR * mathSin(endAngle) + adjustAngleDistanceY(endAngle, distance + extraDist, true); - textAlign = 'left'; - textVerticalAlign = 'middle'; - break; - - case 'insideEndAngle': - x = cx + middleR * mathCos(endAngle) + adjustAngleDistanceX(endAngle, -distance + extraDist, true); - y = cy + middleR * mathSin(endAngle) + adjustAngleDistanceY(endAngle, -distance + extraDist, true); - textAlign = 'right'; - textVerticalAlign = 'middle'; - break; - - default: - return calculateTextPosition(out, opts, boundingRect); - } - - out = out || {}; - out.x = x; - out.y = y; - out.align = textAlign; - out.verticalAlign = textVerticalAlign; - return out; - }; - } - - function setSectorTextRotation(sector, textPosition, positionMapping, rotateType) { - if (isNumber(rotateType)) { - // user-set rotation - sector.setTextConfig({ - rotation: rotateType - }); - return; - } else if (isArray(textPosition)) { - // user-set position, use 0 as auto rotation - sector.setTextConfig({ - rotation: 0 - }); - return; - } - - var shape = sector.shape; - var startAngle = shape.clockwise ? shape.startAngle : shape.endAngle; - var endAngle = shape.clockwise ? shape.endAngle : shape.startAngle; - var middleAngle = (startAngle + endAngle) / 2; - var anchorAngle; - var mappedSectorPosition = positionMapping(textPosition); - - switch (mappedSectorPosition) { - case 'startArc': - case 'insideStartArc': - case 'middle': - case 'insideEndArc': - case 'endArc': - anchorAngle = middleAngle; - break; - - case 'startAngle': - case 'insideStartAngle': - anchorAngle = startAngle; - break; - - case 'endAngle': - case 'insideEndAngle': - anchorAngle = endAngle; - break; - - default: - sector.setTextConfig({ - rotation: 0 - }); - return; - } - - var rotate = Math.PI * 1.5 - anchorAngle; - /** - * TODO: labels with rotate > Math.PI / 2 should be rotate another - * half round flipped to increase readability. However, only middle - * position supports this for now, because in other positions, the - * anchor point is not at the center of the text, so the positions - * after rotating is not as expected. - */ - - if (mappedSectorPosition === 'middle' && rotate > Math.PI / 2 && rotate < Math.PI * 1.5) { - rotate -= Math.PI; - } - - sector.setTextConfig({ - rotation: rotate - }); - } - - function adjustAngleDistanceX(angle, distance, isEnd) { - return distance * Math.sin(angle) * (isEnd ? -1 : 1); - } - - function adjustAngleDistanceY(angle, distance, isEnd) { - return distance * Math.cos(angle) * (isEnd ? 1 : -1); - } - - function getSectorCornerRadius(model, shape, zeroIfNull) { - var cornerRadius = model.get('borderRadius'); - - if (cornerRadius == null) { - return zeroIfNull ? { - cornerRadius: 0 - } : null; - } - - if (!isArray(cornerRadius)) { - cornerRadius = [cornerRadius, cornerRadius, cornerRadius, cornerRadius]; - } - - var dr = Math.abs(shape.r || 0 - shape.r0 || 0); - return { - cornerRadius: map$1(cornerRadius, function (cr) { - return parsePercent$1(cr, dr); - }) - }; - } - - var mathMax$1 = Math.max; - var mathMin$1 = Math.min; - - function getClipArea(coord, data) { - var coordSysClipArea = coord.getArea && coord.getArea(); - - if (isCoordinateSystemType(coord, 'cartesian2d')) { - var baseAxis = coord.getBaseAxis(); // When boundaryGap is false or using time axis. bar may exceed the grid. - // We should not clip this part. - // See test/bar2.html - - if (baseAxis.type !== 'category' || !baseAxis.onBand) { - var expandWidth = data.getLayout('bandWidth'); - - if (baseAxis.isHorizontal()) { - coordSysClipArea.x -= expandWidth; - coordSysClipArea.width += expandWidth * 2; - } else { - coordSysClipArea.y -= expandWidth; - coordSysClipArea.height += expandWidth * 2; - } - } - } - - return coordSysClipArea; - } - - var BarView = - /** @class */ - function (_super) { - __extends(BarView, _super); - - function BarView() { - var _this = _super.call(this) || this; - - _this.type = BarView.type; - _this._isFirstFrame = true; - return _this; - } - - BarView.prototype.render = function (seriesModel, ecModel, api, payload) { - this._model = seriesModel; - - this._removeOnRenderedListener(api); - - this._updateDrawMode(seriesModel); - - var coordinateSystemType = seriesModel.get('coordinateSystem'); - - if (coordinateSystemType === 'cartesian2d' || coordinateSystemType === 'polar') { - // Clear previously rendered progressive elements. - this._progressiveEls = null; - this._isLargeDraw ? this._renderLarge(seriesModel, ecModel, api) : this._renderNormal(seriesModel, ecModel, api, payload); - } else { - warn('Only cartesian2d and polar supported for bar.'); - } - }; - - BarView.prototype.incrementalPrepareRender = function (seriesModel) { - this._clear(); - - this._updateDrawMode(seriesModel); // incremental also need to clip, otherwise might be overlow. - // But must not set clip in each frame, otherwise all of the children will be marked redraw. - - - this._updateLargeClip(seriesModel); - }; - - BarView.prototype.incrementalRender = function (params, seriesModel) { - // Reset - this._progressiveEls = []; // Do not support progressive in normal mode. - - this._incrementalRenderLarge(params, seriesModel); - }; - - BarView.prototype.eachRendered = function (cb) { - traverseElements(this._progressiveEls || this.group, cb); - }; - - BarView.prototype._updateDrawMode = function (seriesModel) { - var isLargeDraw = seriesModel.pipelineContext.large; - - if (this._isLargeDraw == null || isLargeDraw !== this._isLargeDraw) { - this._isLargeDraw = isLargeDraw; - - this._clear(); - } - }; - - BarView.prototype._renderNormal = function (seriesModel, ecModel, api, payload) { - var group = this.group; - var data = seriesModel.getData(); - var oldData = this._data; - var coord = seriesModel.coordinateSystem; - var baseAxis = coord.getBaseAxis(); - var isHorizontalOrRadial; - - if (coord.type === 'cartesian2d') { - isHorizontalOrRadial = baseAxis.isHorizontal(); - } else if (coord.type === 'polar') { - isHorizontalOrRadial = baseAxis.dim === 'angle'; - } - - var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null; - var realtimeSortCfg = shouldRealtimeSort(seriesModel, coord); - - if (realtimeSortCfg) { - this._enableRealtimeSort(realtimeSortCfg, data, api); - } - - var needsClip = seriesModel.get('clip', true) || realtimeSortCfg; - var coordSysClipArea = getClipArea(coord, data); // If there is clipPath created in large mode. Remove it. - - group.removeClipPath(); // We don't use clipPath in normal mode because we needs a perfect animation - // And don't want the label are clipped. - - var roundCap = seriesModel.get('roundCap', true); - var drawBackground = seriesModel.get('showBackground', true); - var backgroundModel = seriesModel.getModel('backgroundStyle'); - var barBorderRadius = backgroundModel.get('borderRadius') || 0; - var bgEls = []; - var oldBgEls = this._backgroundEls; - var isInitSort = payload && payload.isInitSort; - var isChangeOrder = payload && payload.type === 'changeAxisOrder'; - - function createBackground(dataIndex) { - var bgLayout = getLayout[coord.type](data, dataIndex); - - if (!bgLayout) { - return null; - } - - var bgEl = createBackgroundEl(coord, isHorizontalOrRadial, bgLayout); - bgEl.useStyle(backgroundModel.getItemStyle()); // Only cartesian2d support borderRadius. - - if (coord.type === 'cartesian2d') { - bgEl.setShape('r', barBorderRadius); - } else { - bgEl.setShape('cornerRadius', barBorderRadius); - } - - bgEls[dataIndex] = bgEl; - return bgEl; - } - - data.diff(oldData).add(function (dataIndex) { - var itemModel = data.getItemModel(dataIndex); - var layout = getLayout[coord.type](data, dataIndex, itemModel); - - if (!layout) { - return; - } - - if (drawBackground) { - createBackground(dataIndex); - } // If dataZoom in filteMode: 'empty', the baseValue can be set as NaN in "axisProxy". - - - if (!data.hasValue(dataIndex) || !isValidLayout[coord.type](layout)) { - return; - } - - var isClipped = false; - - if (needsClip) { - // Clip will modify the layout params. - // And return a boolean to determine if the shape are fully clipped. - isClipped = clip[coord.type](coordSysClipArea, layout); - } - - var el = elementCreator[coord.type](seriesModel, data, dataIndex, layout, isHorizontalOrRadial, animationModel, baseAxis.model, false, roundCap); - - if (realtimeSortCfg) { - /** - * Force label animation because even if the element is - * ignored because it's clipped, it may not be clipped after - * changing order. Then, if not using forceLabelAnimation, - * the label animation was never started, in which case, - * the label will be the final value and doesn't have label - * animation. - */ - el.forceLabelAnimation = true; - } - - updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar'); - - if (isInitSort) { - el.attr({ - shape: layout - }); - } else if (realtimeSortCfg) { - updateRealtimeAnimation(realtimeSortCfg, animationModel, el, layout, dataIndex, isHorizontalOrRadial, false, false); - } else { - initProps(el, { - shape: layout - }, seriesModel, dataIndex); - } - - data.setItemGraphicEl(dataIndex, el); - group.add(el); - el.ignore = isClipped; - }).update(function (newIndex, oldIndex) { - var itemModel = data.getItemModel(newIndex); - var layout = getLayout[coord.type](data, newIndex, itemModel); - - if (!layout) { - return; - } - - if (drawBackground) { - var bgEl = void 0; - - if (oldBgEls.length === 0) { - bgEl = createBackground(oldIndex); - } else { - bgEl = oldBgEls[oldIndex]; - bgEl.useStyle(backgroundModel.getItemStyle()); // Only cartesian2d support borderRadius. - - if (coord.type === 'cartesian2d') { - bgEl.setShape('r', barBorderRadius); - } else { - bgEl.setShape('cornerRadius', barBorderRadius); - } - - bgEls[newIndex] = bgEl; - } - - var bgLayout = getLayout[coord.type](data, newIndex); - var shape = createBackgroundShape(isHorizontalOrRadial, bgLayout, coord); - updateProps$1(bgEl, { - shape: shape - }, animationModel, newIndex); - } - - var el = oldData.getItemGraphicEl(oldIndex); - - if (!data.hasValue(newIndex) || !isValidLayout[coord.type](layout)) { - group.remove(el); - return; - } - - var isClipped = false; - - if (needsClip) { - isClipped = clip[coord.type](coordSysClipArea, layout); - - if (isClipped) { - group.remove(el); - } - } - - var roundCapChanged = el && (el.type === 'sector' && roundCap || el.type === 'sausage' && !roundCap); - - if (roundCapChanged) { - // roundCap changed, there is no way to use animation from a `sector` to a `sausage` shape, - // so remove the old one and create a new shape - el && removeElementWithFadeOut(el, seriesModel, oldIndex); - el = null; - } - - if (!el) { - el = elementCreator[coord.type](seriesModel, data, newIndex, layout, isHorizontalOrRadial, animationModel, baseAxis.model, true, roundCap); - } else { - saveOldStyle(el); - } - - if (realtimeSortCfg) { - el.forceLabelAnimation = true; - } - - if (isChangeOrder) { - var textEl = el.getTextContent(); - - if (textEl) { - var labelInnerStore = labelInner(textEl); - - if (labelInnerStore.prevValue != null) { - /** - * Set preValue to be value so that no new label - * should be started, otherwise, it will take a full - * `animationDurationUpdate` time to finish the - * animation, which is not expected. - */ - labelInnerStore.prevValue = labelInnerStore.value; - } - } - } // Not change anything if only order changed. - // Especially not change label. - else { - updateStyle(el, data, newIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar'); - } - - if (isInitSort) { - el.attr({ - shape: layout - }); - } else if (realtimeSortCfg) { - updateRealtimeAnimation(realtimeSortCfg, animationModel, el, layout, newIndex, isHorizontalOrRadial, true, isChangeOrder); - } else { - updateProps$1(el, { - shape: layout - }, seriesModel, newIndex, null); - } - - data.setItemGraphicEl(newIndex, el); - el.ignore = isClipped; - group.add(el); - }).remove(function (dataIndex) { - var el = oldData.getItemGraphicEl(dataIndex); - el && removeElementWithFadeOut(el, seriesModel, dataIndex); - }).execute(); - var bgGroup = this._backgroundGroup || (this._backgroundGroup = new Group$2()); - bgGroup.removeAll(); - - for (var i = 0; i < bgEls.length; ++i) { - bgGroup.add(bgEls[i]); - } - - group.add(bgGroup); - this._backgroundEls = bgEls; - this._data = data; - }; - - BarView.prototype._renderLarge = function (seriesModel, ecModel, api) { - this._clear(); - - createLarge(seriesModel, this.group); - - this._updateLargeClip(seriesModel); - }; - - BarView.prototype._incrementalRenderLarge = function (params, seriesModel) { - this._removeBackground(); - - createLarge(seriesModel, this.group, this._progressiveEls, true); - }; - - BarView.prototype._updateLargeClip = function (seriesModel) { - // Use clipPath in large mode. - var clipPath = seriesModel.get('clip', true) && createClipPath(seriesModel.coordinateSystem, false, seriesModel); - var group = this.group; - - if (clipPath) { - group.setClipPath(clipPath); - } else { - group.removeClipPath(); - } - }; - - BarView.prototype._enableRealtimeSort = function (realtimeSortCfg, data, api) { - var _this = this; // If no data in the first frame, wait for data to initSort - - - if (!data.count()) { - return; - } - - var baseAxis = realtimeSortCfg.baseAxis; - - if (this._isFirstFrame) { - this._dispatchInitSort(data, realtimeSortCfg, api); - - this._isFirstFrame = false; - } else { - var orderMapping_1 = function (idx) { - var el = data.getItemGraphicEl(idx); - var shape = el && el.shape; - return shape && // The result should be consistent with the initial sort by data value. - // Do not support the case that both positive and negative exist. - Math.abs(baseAxis.isHorizontal() ? shape.height : shape.width) // If data is NaN, shape.xxx may be NaN, so use || 0 here in case - || 0; - }; - - this._onRendered = function () { - _this._updateSortWithinSameData(data, orderMapping_1, baseAxis, api); - }; - - api.getZr().on('rendered', this._onRendered); - } - }; - - BarView.prototype._dataSort = function (data, baseAxis, orderMapping) { - var info = []; - data.each(data.mapDimension(baseAxis.dim), function (ordinalNumber, dataIdx) { - var mappedValue = orderMapping(dataIdx); - mappedValue = mappedValue == null ? NaN : mappedValue; - info.push({ - dataIndex: dataIdx, - mappedValue: mappedValue, - ordinalNumber: ordinalNumber - }); - }); - info.sort(function (a, b) { - // If NaN, it will be treated as min val. - return b.mappedValue - a.mappedValue; - }); - return { - ordinalNumbers: map$1(info, function (item) { - return item.ordinalNumber; - }) - }; - }; - - BarView.prototype._isOrderChangedWithinSameData = function (data, orderMapping, baseAxis) { - var scale = baseAxis.scale; - var ordinalDataDim = data.mapDimension(baseAxis.dim); - var lastValue = Number.MAX_VALUE; - - for (var tickNum = 0, len = scale.getOrdinalMeta().categories.length; tickNum < len; ++tickNum) { - var rawIdx = data.rawIndexOf(ordinalDataDim, scale.getRawOrdinalNumber(tickNum)); - var value = rawIdx < 0 // If some tick have no bar, the tick will be treated as min. - ? Number.MIN_VALUE // PENDING: if dataZoom on baseAxis exits, is it a performance issue? - : orderMapping(data.indexOfRawIndex(rawIdx)); - - if (value > lastValue) { - return true; - } - - lastValue = value; - } - - return false; - }; - /* - * Consider the case when A and B changed order, whose representing - * bars are both out of sight, we don't wish to trigger reorder action - * as long as the order in the view doesn't change. - */ - - - BarView.prototype._isOrderDifferentInView = function (orderInfo, baseAxis) { - var scale = baseAxis.scale; - var extent = scale.getExtent(); - var tickNum = Math.max(0, extent[0]); - var tickMax = Math.min(extent[1], scale.getOrdinalMeta().categories.length - 1); - - for (; tickNum <= tickMax; ++tickNum) { - if (orderInfo.ordinalNumbers[tickNum] !== scale.getRawOrdinalNumber(tickNum)) { - return true; - } - } - }; - - BarView.prototype._updateSortWithinSameData = function (data, orderMapping, baseAxis, api) { - if (!this._isOrderChangedWithinSameData(data, orderMapping, baseAxis)) { - return; - } - - var sortInfo = this._dataSort(data, baseAxis, orderMapping); - - if (this._isOrderDifferentInView(sortInfo, baseAxis)) { - this._removeOnRenderedListener(api); - - api.dispatchAction({ - type: 'changeAxisOrder', - componentType: baseAxis.dim + 'Axis', - axisId: baseAxis.index, - sortInfo: sortInfo - }); - } - }; - - BarView.prototype._dispatchInitSort = function (data, realtimeSortCfg, api) { - var baseAxis = realtimeSortCfg.baseAxis; - - var sortResult = this._dataSort(data, baseAxis, function (dataIdx) { - return data.get(data.mapDimension(realtimeSortCfg.otherAxis.dim), dataIdx); - }); - - api.dispatchAction({ - type: 'changeAxisOrder', - componentType: baseAxis.dim + 'Axis', - isInitSort: true, - axisId: baseAxis.index, - sortInfo: sortResult - }); - }; - - BarView.prototype.remove = function (ecModel, api) { - this._clear(this._model); - - this._removeOnRenderedListener(api); - }; - - BarView.prototype.dispose = function (ecModel, api) { - this._removeOnRenderedListener(api); - }; - - BarView.prototype._removeOnRenderedListener = function (api) { - if (this._onRendered) { - api.getZr().off('rendered', this._onRendered); - this._onRendered = null; - } - }; - - BarView.prototype._clear = function (model) { - var group = this.group; - var data = this._data; - - if (model && model.isAnimationEnabled() && data && !this._isLargeDraw) { - this._removeBackground(); - - this._backgroundEls = []; - data.eachItemGraphicEl(function (el) { - removeElementWithFadeOut(el, model, getECData(el).dataIndex); - }); - } else { - group.removeAll(); - } - - this._data = null; - this._isFirstFrame = true; - }; - - BarView.prototype._removeBackground = function () { - this.group.remove(this._backgroundGroup); - this._backgroundGroup = null; - }; - - BarView.type = 'bar'; - return BarView; - }(ChartView); - - var clip = { - cartesian2d: function (coordSysBoundingRect, layout) { - var signWidth = layout.width < 0 ? -1 : 1; - var signHeight = layout.height < 0 ? -1 : 1; // Needs positive width and height - - if (signWidth < 0) { - layout.x += layout.width; - layout.width = -layout.width; - } - - if (signHeight < 0) { - layout.y += layout.height; - layout.height = -layout.height; - } - - var coordSysX2 = coordSysBoundingRect.x + coordSysBoundingRect.width; - var coordSysY2 = coordSysBoundingRect.y + coordSysBoundingRect.height; - var x = mathMax$1(layout.x, coordSysBoundingRect.x); - var x2 = mathMin$1(layout.x + layout.width, coordSysX2); - var y = mathMax$1(layout.y, coordSysBoundingRect.y); - var y2 = mathMin$1(layout.y + layout.height, coordSysY2); - var xClipped = x2 < x; - var yClipped = y2 < y; // When xClipped or yClipped, the element will be marked as `ignore`. - // But we should also place the element at the edge of the coord sys bounding rect. - // Because if data changed and the bar shows again, its transition animation - // will begin at this place. - - layout.x = xClipped && x > coordSysX2 ? x2 : x; - layout.y = yClipped && y > coordSysY2 ? y2 : y; - layout.width = xClipped ? 0 : x2 - x; - layout.height = yClipped ? 0 : y2 - y; // Reverse back - - if (signWidth < 0) { - layout.x += layout.width; - layout.width = -layout.width; - } - - if (signHeight < 0) { - layout.y += layout.height; - layout.height = -layout.height; - } - - return xClipped || yClipped; - }, - polar: function (coordSysClipArea, layout) { - var signR = layout.r0 <= layout.r ? 1 : -1; // Make sure r is larger than r0 - - if (signR < 0) { - var tmp = layout.r; - layout.r = layout.r0; - layout.r0 = tmp; - } - - var r = mathMin$1(layout.r, coordSysClipArea.r); - var r0 = mathMax$1(layout.r0, coordSysClipArea.r0); - layout.r = r; - layout.r0 = r0; - var clipped = r - r0 < 0; // Reverse back - - if (signR < 0) { - var tmp = layout.r; - layout.r = layout.r0; - layout.r0 = tmp; - } - - return clipped; - } - }; - var elementCreator = { - cartesian2d: function (seriesModel, data, newIndex, layout, isHorizontal, animationModel, axisModel, isUpdate, roundCap) { - var rect = new Rect({ - shape: extend({}, layout), - z2: 1 - }); - rect.__dataIndex = newIndex; - rect.name = 'item'; - - if (animationModel) { - var rectShape = rect.shape; - var animateProperty = isHorizontal ? 'height' : 'width'; - rectShape[animateProperty] = 0; - } - - return rect; - }, - polar: function (seriesModel, data, newIndex, layout, isRadial, animationModel, axisModel, isUpdate, roundCap) { - var ShapeClass = !isRadial && roundCap ? SausagePath : Sector; - var sector = new ShapeClass({ - shape: layout, - z2: 1 - }); - sector.name = 'item'; - var positionMap = createPolarPositionMapping(isRadial); - sector.calculateTextPosition = createSectorCalculateTextPosition(positionMap, { - isRoundCap: ShapeClass === SausagePath - }); // Animation - - if (animationModel) { - var sectorShape = sector.shape; - var animateProperty = isRadial ? 'r' : 'endAngle'; - var animateTarget = {}; - sectorShape[animateProperty] = isRadial ? layout.r0 : layout.startAngle; - animateTarget[animateProperty] = layout[animateProperty]; - (isUpdate ? updateProps$1 : initProps)(sector, { - shape: animateTarget // __value: typeof dataValue === 'string' ? parseInt(dataValue, 10) : dataValue - - }, animationModel); - } - - return sector; - } - }; - - function shouldRealtimeSort(seriesModel, coordSys) { - var realtimeSortOption = seriesModel.get('realtimeSort', true); - var baseAxis = coordSys.getBaseAxis(); - { - if (realtimeSortOption) { - if (baseAxis.type !== 'category') { - warn('`realtimeSort` will not work because this bar series is not based on a category axis.'); - } - - if (coordSys.type !== 'cartesian2d') { - warn('`realtimeSort` will not work because this bar series is not on cartesian2d.'); - } - } - } - - if (realtimeSortOption && baseAxis.type === 'category' && coordSys.type === 'cartesian2d') { - return { - baseAxis: baseAxis, - otherAxis: coordSys.getOtherAxis(baseAxis) - }; - } - } - - function updateRealtimeAnimation(realtimeSortCfg, seriesAnimationModel, el, layout, newIndex, isHorizontal, isUpdate, isChangeOrder) { - var seriesTarget; - var axisTarget; - - if (isHorizontal) { - axisTarget = { - x: layout.x, - width: layout.width - }; - seriesTarget = { - y: layout.y, - height: layout.height - }; - } else { - axisTarget = { - y: layout.y, - height: layout.height - }; - seriesTarget = { - x: layout.x, - width: layout.width - }; - } - - if (!isChangeOrder) { - // Keep the original growth animation if only axis order changed. - // Not start a new animation. - (isUpdate ? updateProps$1 : initProps)(el, { - shape: seriesTarget - }, seriesAnimationModel, newIndex, null); - } - - var axisAnimationModel = seriesAnimationModel ? realtimeSortCfg.baseAxis.model : null; - (isUpdate ? updateProps$1 : initProps)(el, { - shape: axisTarget - }, axisAnimationModel, newIndex); - } - - function checkPropertiesNotValid(obj, props) { - for (var i = 0; i < props.length; i++) { - if (!isFinite(obj[props[i]])) { - return true; - } - } - - return false; - } - - var rectPropties = ['x', 'y', 'width', 'height']; - var polarPropties = ['cx', 'cy', 'r', 'startAngle', 'endAngle']; - var isValidLayout = { - cartesian2d: function (layout) { - return !checkPropertiesNotValid(layout, rectPropties); - }, - polar: function (layout) { - return !checkPropertiesNotValid(layout, polarPropties); - } - }; - var getLayout = { - // itemModel is only used to get borderWidth, which is not needed - // when calculating bar background layout. - cartesian2d: function (data, dataIndex, itemModel) { - var layout = data.getItemLayout(dataIndex); - - if (!layout) { - return null; - } - - var fixedLineWidth = itemModel ? getLineWidth(itemModel, layout) : 0; // fix layout with lineWidth - - var signX = layout.width > 0 ? 1 : -1; - var signY = layout.height > 0 ? 1 : -1; - return { - x: layout.x + signX * fixedLineWidth / 2, - y: layout.y + signY * fixedLineWidth / 2, - width: layout.width - signX * fixedLineWidth, - height: layout.height - signY * fixedLineWidth - }; - }, - polar: function (data, dataIndex, itemModel) { - var layout = data.getItemLayout(dataIndex); - return { - cx: layout.cx, - cy: layout.cy, - r0: layout.r0, - r: layout.r, - startAngle: layout.startAngle, - endAngle: layout.endAngle, - clockwise: layout.clockwise - }; - } - }; - - function isZeroOnPolar(layout) { - return layout.startAngle != null && layout.endAngle != null && layout.startAngle === layout.endAngle; - } - - function createPolarPositionMapping(isRadial) { - return function (isRadial) { - var arcOrAngle = isRadial ? 'Arc' : 'Angle'; - return function (position) { - switch (position) { - case 'start': - case 'insideStart': - case 'end': - case 'insideEnd': - return position + arcOrAngle; - - default: - return position; - } - }; - }(isRadial); - } - - function updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, isPolar) { - var style = data.getItemVisual(dataIndex, 'style'); - - if (!isPolar) { - var borderRadius = itemModel.get(['itemStyle', 'borderRadius']) || 0; - el.setShape('r', borderRadius); - } else if (!seriesModel.get('roundCap')) { - var sectorShape = el.shape; - var cornerRadius = getSectorCornerRadius(itemModel.getModel('itemStyle'), sectorShape, true); - extend(sectorShape, cornerRadius); - el.setShape(sectorShape); - } - - el.useStyle(style); - var cursorStyle = itemModel.getShallow('cursor'); - cursorStyle && el.attr('cursor', cursorStyle); - var labelPositionOutside = isPolar ? isHorizontalOrRadial ? layout.r >= layout.r0 ? 'endArc' : 'startArc' : layout.endAngle >= layout.startAngle ? 'endAngle' : 'startAngle' : isHorizontalOrRadial ? layout.height >= 0 ? 'bottom' : 'top' : layout.width >= 0 ? 'right' : 'left'; - var labelStatesModels = getLabelStatesModels(itemModel); - setLabelStyle(el, labelStatesModels, { - labelFetcher: seriesModel, - labelDataIndex: dataIndex, - defaultText: getDefaultLabel(seriesModel.getData(), dataIndex), - inheritColor: style.fill, - defaultOpacity: style.opacity, - defaultOutsidePosition: labelPositionOutside - }); - var label = el.getTextContent(); - - if (isPolar && label) { - var position = itemModel.get(['label', 'position']); - el.textConfig.inside = position === 'middle' ? true : null; - setSectorTextRotation(el, position === 'outside' ? labelPositionOutside : position, createPolarPositionMapping(isHorizontalOrRadial), itemModel.get(['label', 'rotate'])); - } - - setLabelValueAnimation(label, labelStatesModels, seriesModel.getRawValue(dataIndex), function (value) { - return getDefaultInterpolatedLabel(data, value); - }); - var emphasisModel = itemModel.getModel(['emphasis']); - toggleHoverEmphasis(el, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled')); - setStatesStylesFromModel(el, itemModel); - - if (isZeroOnPolar(layout)) { - el.style.fill = 'none'; - el.style.stroke = 'none'; - each$4(el.states, function (state) { - if (state.style) { - state.style.fill = state.style.stroke = 'none'; - } - }); - } - } // In case width or height are too small. - - - function getLineWidth(itemModel, rawLayout) { - // Has no border. - var borderColor = itemModel.get(['itemStyle', 'borderColor']); - - if (!borderColor || borderColor === 'none') { - return 0; - } - - var lineWidth = itemModel.get(['itemStyle', 'borderWidth']) || 0; // width or height may be NaN for empty data - - var width = isNaN(rawLayout.width) ? Number.MAX_VALUE : Math.abs(rawLayout.width); - var height = isNaN(rawLayout.height) ? Number.MAX_VALUE : Math.abs(rawLayout.height); - return Math.min(lineWidth, width, height); - } - - var LagePathShape = - /** @class */ - function () { - function LagePathShape() {} - - return LagePathShape; - }(); - - var LargePath = - /** @class */ - function (_super) { - __extends(LargePath, _super); - - function LargePath(opts) { - var _this = _super.call(this, opts) || this; - - _this.type = 'largeBar'; - return _this; - } - - LargePath.prototype.getDefaultShape = function () { - return new LagePathShape(); - }; - - LargePath.prototype.buildPath = function (ctx, shape) { - // Drawing lines is more efficient than drawing - // a whole line or drawing rects. - var points = shape.points; - var baseDimIdx = this.baseDimIdx; - var valueDimIdx = 1 - this.baseDimIdx; - var startPoint = []; - var size = []; - var barWidth = this.barWidth; - - for (var i = 0; i < points.length; i += 3) { - size[baseDimIdx] = barWidth; - size[valueDimIdx] = points[i + 2]; - startPoint[baseDimIdx] = points[i + baseDimIdx]; - startPoint[valueDimIdx] = points[i + valueDimIdx]; - ctx.rect(startPoint[0], startPoint[1], size[0], size[1]); - } - }; - - return LargePath; - }(Path); - - function createLarge(seriesModel, group, progressiveEls, incremental) { - // TODO support polar - var data = seriesModel.getData(); - var baseDimIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0; - var largeDataIndices = data.getLayout('largeDataIndices'); - var barWidth = data.getLayout('size'); - var backgroundModel = seriesModel.getModel('backgroundStyle'); - var bgPoints = data.getLayout('largeBackgroundPoints'); - - if (bgPoints) { - var bgEl = new LargePath({ - shape: { - points: bgPoints - }, - incremental: !!incremental, - silent: true, - z2: 0 - }); - bgEl.baseDimIdx = baseDimIdx; - bgEl.largeDataIndices = largeDataIndices; - bgEl.barWidth = barWidth; - bgEl.useStyle(backgroundModel.getItemStyle()); - group.add(bgEl); - progressiveEls && progressiveEls.push(bgEl); - } - - var el = new LargePath({ - shape: { - points: data.getLayout('largePoints') - }, - incremental: !!incremental, - ignoreCoarsePointer: true, - z2: 1 - }); - el.baseDimIdx = baseDimIdx; - el.largeDataIndices = largeDataIndices; - el.barWidth = barWidth; - group.add(el); - el.useStyle(data.getVisual('style')); // Stroke is rendered first to avoid overlapping with fill - - el.style.stroke = null; // Enable tooltip and user mouse/touch event handlers. - - getECData(el).seriesIndex = seriesModel.seriesIndex; - - if (!seriesModel.get('silent')) { - el.on('mousedown', largePathUpdateDataIndex); - el.on('mousemove', largePathUpdateDataIndex); - } - - progressiveEls && progressiveEls.push(el); - } // Use throttle to avoid frequently traverse to find dataIndex. - - - var largePathUpdateDataIndex = throttle(function (event) { - var largePath = this; - var dataIndex = largePathFindDataIndex(largePath, event.offsetX, event.offsetY); - getECData(largePath).dataIndex = dataIndex >= 0 ? dataIndex : null; - }, 30, false); - - function largePathFindDataIndex(largePath, x, y) { - var baseDimIdx = largePath.baseDimIdx; - var valueDimIdx = 1 - baseDimIdx; - var points = largePath.shape.points; - var largeDataIndices = largePath.largeDataIndices; - var startPoint = []; - var size = []; - var barWidth = largePath.barWidth; - - for (var i = 0, len = points.length / 3; i < len; i++) { - var ii = i * 3; - size[baseDimIdx] = barWidth; - size[valueDimIdx] = points[ii + 2]; - startPoint[baseDimIdx] = points[ii + baseDimIdx]; - startPoint[valueDimIdx] = points[ii + valueDimIdx]; - - if (size[valueDimIdx] < 0) { - startPoint[valueDimIdx] += size[valueDimIdx]; - size[valueDimIdx] = -size[valueDimIdx]; - } - - if (x >= startPoint[0] && x <= startPoint[0] + size[0] && y >= startPoint[1] && y <= startPoint[1] + size[1]) { - return largeDataIndices[i]; - } - } - - return -1; - } - - function createBackgroundShape(isHorizontalOrRadial, layout, coord) { - if (isCoordinateSystemType(coord, 'cartesian2d')) { - var rectShape = layout; - var coordLayout = coord.getArea(); - return { - x: isHorizontalOrRadial ? rectShape.x : coordLayout.x, - y: isHorizontalOrRadial ? coordLayout.y : rectShape.y, - width: isHorizontalOrRadial ? rectShape.width : coordLayout.width, - height: isHorizontalOrRadial ? coordLayout.height : rectShape.height - }; - } else { - var coordLayout = coord.getArea(); - var sectorShape = layout; - return { - cx: coordLayout.cx, - cy: coordLayout.cy, - r0: isHorizontalOrRadial ? coordLayout.r0 : sectorShape.r0, - r: isHorizontalOrRadial ? coordLayout.r : sectorShape.r, - startAngle: isHorizontalOrRadial ? sectorShape.startAngle : 0, - endAngle: isHorizontalOrRadial ? sectorShape.endAngle : Math.PI * 2 - }; - } - } - - function createBackgroundEl(coord, isHorizontalOrRadial, layout) { - var ElementClz = coord.type === 'polar' ? Sector : Rect; - return new ElementClz({ - shape: createBackgroundShape(isHorizontalOrRadial, layout, coord), - silent: true, - z2: 0 - }); - } - - function install$9(registers) { - registers.registerChartView(BarView); - registers.registerSeriesModel(BarSeriesModel); - registers.registerLayout(registers.PRIORITY.VISUAL.LAYOUT, curry$1(layout$1, 'bar')); // Do layout after other overall layout, which can prepare some information. - - registers.registerLayout(registers.PRIORITY.VISUAL.PROGRESSIVE_LAYOUT, createProgressiveLayout('bar')); // Down sample after filter - - registers.registerProcessor(registers.PRIORITY.PROCESSOR.STATISTIC, dataSample('bar')); - /** - * @payload - * @property {string} [componentType=series] - * @property {number} [dx] - * @property {number} [dy] - * @property {number} [zoom] - * @property {number} [originX] - * @property {number} [originY] - */ - - registers.registerAction({ - type: 'changeAxisOrder', - event: 'changeAxisOrder', - update: 'update' - }, function (payload, ecModel) { - var componentType = payload.componentType || 'series'; - ecModel.eachComponent({ - mainType: componentType, - query: payload - }, function (componentModel) { - if (payload.sortInfo) { - componentModel.axis.setCategorySortInfo(payload.sortInfo); - } - }); - }); - } - - use(install$9); - - var LineSeriesModel = - /** @class */ - function (_super) { - __extends(LineSeriesModel, _super); - - function LineSeriesModel() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = LineSeriesModel.type; - _this.hasSymbolVisual = true; - return _this; - } - - LineSeriesModel.prototype.getInitialData = function (option) { - { - var coordSys = option.coordinateSystem; - - if (coordSys !== 'polar' && coordSys !== 'cartesian2d') { - throw new Error('Line not support coordinateSystem besides cartesian and polar'); - } - } - return createSeriesData(null, this, { - useEncodeDefaulter: true - }); - }; - - LineSeriesModel.prototype.getLegendIcon = function (opt) { - var group = new Group$2(); - var line = createSymbol('line', 0, opt.itemHeight / 2, opt.itemWidth, 0, opt.lineStyle.stroke, false); - group.add(line); - line.setStyle(opt.lineStyle); - var visualType = this.getData().getVisual('symbol'); - var visualRotate = this.getData().getVisual('symbolRotate'); - var symbolType = visualType === 'none' ? 'circle' : visualType; // Symbol size is 80% when there is a line - - var size = opt.itemHeight * 0.8; - var symbol = createSymbol(symbolType, (opt.itemWidth - size) / 2, (opt.itemHeight - size) / 2, size, size, opt.itemStyle.fill); - group.add(symbol); - symbol.setStyle(opt.itemStyle); - var symbolRotate = opt.iconRotate === 'inherit' ? visualRotate : opt.iconRotate || 0; - symbol.rotation = symbolRotate * Math.PI / 180; - symbol.setOrigin([opt.itemWidth / 2, opt.itemHeight / 2]); - - if (symbolType.indexOf('empty') > -1) { - symbol.style.stroke = symbol.style.fill; - symbol.style.fill = tokens.color.neutral00; - symbol.style.lineWidth = 2; - } - - return group; - }; - - LineSeriesModel.type = 'series.line'; - LineSeriesModel.dependencies = ['grid', 'polar']; - LineSeriesModel.defaultOption = { - // zlevel: 0, - z: 3, - coordinateSystem: 'cartesian2d', - legendHoverLink: true, - clip: true, - label: { - position: 'top' - }, - // itemStyle: { - // }, - endLabel: { - show: false, - valueAnimation: true, - distance: 8 - }, - lineStyle: { - width: 2, - type: 'solid' - }, - emphasis: { - scale: true - }, - // areaStyle: { - // origin of areaStyle. Valid values: - // `'auto'/null/undefined`: from axisLine to data - // `'start'`: from min to data - // `'end'`: from data to max - // origin: 'auto' - // }, - // false, 'start', 'end', 'middle' - step: false, - // Disabled if step is true - smooth: false, - smoothMonotone: null, - symbol: 'emptyCircle', - symbolSize: 6, - symbolRotate: null, - showSymbol: true, - // `false`: follow the label interval strategy. - // `true`: show all symbols. - // `'auto'`: If possible, show all symbols, otherwise - // follow the label interval strategy. - showAllSymbol: 'auto', - // Whether to connect break point. - connectNulls: false, - // Sampling for large data. Can be: 'average', 'max', 'min', 'sum', 'lttb'. - sampling: 'none', - animationEasing: 'linear', - // Disable progressive - progressive: 0, - hoverLayerThreshold: Infinity, - universalTransition: { - divideShape: 'clone' - }, - triggerLineEvent: false - }; - return LineSeriesModel; - }(SeriesModel); - - var Symbol = - /** @class */ - function (_super) { - __extends(Symbol, _super); - - function Symbol(data, idx, seriesScope, opts) { - var _this = _super.call(this) || this; - - _this.updateData(data, idx, seriesScope, opts); - - return _this; - } - - Symbol.prototype._createSymbol = function (symbolType, data, idx, symbolSize, z2, keepAspect) { - // Remove paths created before - this.removeAll(); // let symbolPath = createSymbol( - // symbolType, -0.5, -0.5, 1, 1, color - // ); - // If width/height are set too small (e.g., set to 1) on ios10 - // and macOS Sierra, a circle stroke become a rect, no matter what - // the scale is set. So we set width/height as 2. See #4150. - - var symbolPath = createSymbol(symbolType, -1, -1, 2, 2, null, keepAspect); - symbolPath.attr({ - z2: retrieve2(z2, 100), - culling: true, - scaleX: symbolSize[0] / 2, - scaleY: symbolSize[1] / 2 - }); // Rewrite drift method - - symbolPath.drift = driftSymbol; - this._symbolType = symbolType; - this.add(symbolPath); - }; - /** - * Stop animation - * @param {boolean} toLastFrame - */ - - - Symbol.prototype.stopSymbolAnimation = function (toLastFrame) { - this.childAt(0).stopAnimation(null, toLastFrame); - }; - - Symbol.prototype.getSymbolType = function () { - return this._symbolType; - }; - /** - * FIXME: - * Caution: This method breaks the encapsulation of this module, - * but it indeed brings convenience. So do not use the method - * unless you detailedly know all the implements of `Symbol`, - * especially animation. - * - * Get symbol path element. - */ - - - Symbol.prototype.getSymbolPath = function () { - return this.childAt(0); - }; - /** - * Highlight symbol - */ - - - Symbol.prototype.highlight = function () { - enterEmphasis(this.childAt(0)); - }; - /** - * Downplay symbol - */ - - - Symbol.prototype.downplay = function () { - leaveEmphasis(this.childAt(0)); - }; - /** - * @param {number} zlevel - * @param {number} z - */ - - - Symbol.prototype.setZ = function (zlevel, z) { - var symbolPath = this.childAt(0); - symbolPath.zlevel = zlevel; - symbolPath.z = z; - }; - - Symbol.prototype.setDraggable = function (draggable, hasCursorOption) { - var symbolPath = this.childAt(0); - symbolPath.draggable = draggable; - symbolPath.cursor = !hasCursorOption && draggable ? 'move' : symbolPath.cursor; - }; - /** - * Update symbol properties - */ - - - Symbol.prototype.updateData = function (data, idx, seriesScope, opts) { - this.silent = false; - var symbolType = data.getItemVisual(idx, 'symbol') || 'circle'; - var seriesModel = data.hostModel; - var symbolSize = Symbol.getSymbolSize(data, idx); - var z2 = Symbol.getSymbolZ2(data, idx); - var isInit = symbolType !== this._symbolType; - var disableAnimation = opts && opts.disableAnimation; - - if (isInit) { - var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect'); - - this._createSymbol(symbolType, data, idx, symbolSize, z2, keepAspect); - } else { - var symbolPath = this.childAt(0); - symbolPath.silent = false; - var target = { - scaleX: symbolSize[0] / 2, - scaleY: symbolSize[1] / 2 - }; - disableAnimation ? symbolPath.attr(target) : updateProps$1(symbolPath, target, seriesModel, idx); - saveOldStyle(symbolPath); - } - - this._updateCommon(data, idx, symbolSize, seriesScope, opts); - - if (isInit) { - var symbolPath = this.childAt(0); - - if (!disableAnimation) { - var target = { - scaleX: this._sizeX, - scaleY: this._sizeY, - style: { - // Always fadeIn. Because it has fadeOut animation when symbol is removed.. - opacity: symbolPath.style.opacity - } - }; - symbolPath.scaleX = symbolPath.scaleY = 0; - symbolPath.style.opacity = 0; - initProps(symbolPath, target, seriesModel, idx); - } - } - - if (disableAnimation) { - // Must stop leave transition manually if don't call initProps or updateProps. - this.childAt(0).stopAnimation('leave'); - } - }; - - Symbol.prototype._updateCommon = function (data, idx, symbolSize, seriesScope, opts) { - var symbolPath = this.childAt(0); - var seriesModel = data.hostModel; - var emphasisItemStyle; - var blurItemStyle; - var selectItemStyle; - var focus; - var blurScope; - var emphasisDisabled; - var labelStatesModels; - var hoverScale; - var cursorStyle; - - if (seriesScope) { - emphasisItemStyle = seriesScope.emphasisItemStyle; - blurItemStyle = seriesScope.blurItemStyle; - selectItemStyle = seriesScope.selectItemStyle; - focus = seriesScope.focus; - blurScope = seriesScope.blurScope; - labelStatesModels = seriesScope.labelStatesModels; - hoverScale = seriesScope.hoverScale; - cursorStyle = seriesScope.cursorStyle; - emphasisDisabled = seriesScope.emphasisDisabled; - } - - if (!seriesScope || data.hasItemOption) { - var itemModel = seriesScope && seriesScope.itemModel ? seriesScope.itemModel : data.getItemModel(idx); - var emphasisModel = itemModel.getModel('emphasis'); - emphasisItemStyle = emphasisModel.getModel('itemStyle').getItemStyle(); - selectItemStyle = itemModel.getModel(['select', 'itemStyle']).getItemStyle(); - blurItemStyle = itemModel.getModel(['blur', 'itemStyle']).getItemStyle(); - focus = emphasisModel.get('focus'); - blurScope = emphasisModel.get('blurScope'); - emphasisDisabled = emphasisModel.get('disabled'); - labelStatesModels = getLabelStatesModels(itemModel); - hoverScale = emphasisModel.getShallow('scale'); - cursorStyle = itemModel.getShallow('cursor'); - } - - var symbolRotate = data.getItemVisual(idx, 'symbolRotate'); - symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0); - var symbolOffset = normalizeSymbolOffset(data.getItemVisual(idx, 'symbolOffset'), symbolSize); - - if (symbolOffset) { - symbolPath.x = symbolOffset[0]; - symbolPath.y = symbolOffset[1]; - } - - cursorStyle && symbolPath.attr('cursor', cursorStyle); - var symbolStyle = data.getItemVisual(idx, 'style'); - var visualColor = symbolStyle.fill; - - if (symbolPath instanceof ZRImage) { - var pathStyle = symbolPath.style; - symbolPath.useStyle(extend({ - // TODO other properties like x, y ? - image: pathStyle.image, - x: pathStyle.x, - y: pathStyle.y, - width: pathStyle.width, - height: pathStyle.height - }, symbolStyle)); - } else { - if (symbolPath.__isEmptyBrush) { - // fill and stroke will be swapped if it's empty. - // So we cloned a new style to avoid it affecting the original style in visual storage. - // TODO Better implementation. No empty logic! - symbolPath.useStyle(extend({}, symbolStyle)); - } else { - symbolPath.useStyle(symbolStyle); - } // Disable decal because symbol scale will been applied on the decal. - - - symbolPath.style.decal = null; - symbolPath.setColor(visualColor, opts && opts.symbolInnerColor); - symbolPath.style.strokeNoScale = true; - } - - var liftZ = data.getItemVisual(idx, 'liftZ'); - var z2Origin = this._z2; - - if (liftZ != null) { - if (z2Origin == null) { - this._z2 = symbolPath.z2; - symbolPath.z2 += liftZ; - } - } else if (z2Origin != null) { - symbolPath.z2 = z2Origin; - this._z2 = null; - } - - var useNameLabel = opts && opts.useNameLabel; - setLabelStyle(symbolPath, labelStatesModels, { - labelFetcher: seriesModel, - labelDataIndex: idx, - defaultText: getLabelDefaultText, - inheritColor: visualColor, - defaultOpacity: symbolStyle.opacity - }); // Do not execute util needed. - - function getLabelDefaultText(idx) { - return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx); - } - - this._sizeX = symbolSize[0] / 2; - this._sizeY = symbolSize[1] / 2; - var emphasisState = symbolPath.ensureState('emphasis'); - emphasisState.style = emphasisItemStyle; - symbolPath.ensureState('select').style = selectItemStyle; - symbolPath.ensureState('blur').style = blurItemStyle; // null / undefined / true means to use default strategy. - // 0 / false / negative number / NaN / Infinity means no scale. - - var scaleRatio = hoverScale == null || hoverScale === true ? Math.max(1.1, 3 / this._sizeY) // PENDING: restrict hoverScale > 1? It seems unreasonable to scale down - : isFinite(hoverScale) && hoverScale > 0 ? +hoverScale : 1; // always set scale to allow resetting - - emphasisState.scaleX = this._sizeX * scaleRatio; - emphasisState.scaleY = this._sizeY * scaleRatio; - this.setSymbolScale(1); - toggleHoverEmphasis(this, focus, blurScope, emphasisDisabled); - }; - - Symbol.prototype.setSymbolScale = function (scale) { - this.scaleX = this.scaleY = scale; - }; - - Symbol.prototype.fadeOut = function (cb, seriesModel, opt) { - var symbolPath = this.childAt(0); - var dataIndex = getECData(this).dataIndex; - var animationOpt = opt && opt.animation; // Avoid mistaken hover when fading out - - this.silent = symbolPath.silent = true; // Not show text when animating - - if (opt && opt.fadeLabel) { - var textContent = symbolPath.getTextContent(); - - if (textContent) { - removeElement(textContent, { - style: { - opacity: 0 - } - }, seriesModel, { - dataIndex: dataIndex, - removeOpt: animationOpt, - cb: function () { - symbolPath.removeTextContent(); - } - }); - } - } else { - symbolPath.removeTextContent(); - } - - removeElement(symbolPath, { - style: { - opacity: 0 - }, - scaleX: 0, - scaleY: 0 - }, seriesModel, { - dataIndex: dataIndex, - cb: cb, - removeOpt: animationOpt - }); - }; - - Symbol.getSymbolSize = function (data, idx) { - return normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize')); - }; - - Symbol.getSymbolZ2 = function (data, idx) { - return data.getItemVisual(idx, 'z2'); - }; - - return Symbol; - }(Group$2); - - function driftSymbol(dx, dy) { - this.parent.drift(dx, dy); - } - - function symbolNeedsDraw(data, point, idx, opt) { - return point && !isNaN(point[0]) && !isNaN(point[1]) && !(opt.isIgnore && opt.isIgnore(idx)) // We do not set clipShape on group, because it will cut part of - // the symbol element shape. We use the same clip shape here as - // the line clip. - && !(opt.clipShape && !opt.clipShape.contain(point[0], point[1])) && data.getItemVisual(idx, 'symbol') !== 'none'; - } - - function normalizeUpdateOpt(opt) { - if (opt != null && !isObject$2(opt)) { - opt = { - isIgnore: opt - }; - } - - return opt || {}; - } - - function makeSeriesScope(data) { - var seriesModel = data.hostModel; - var emphasisModel = seriesModel.getModel('emphasis'); - return { - emphasisItemStyle: emphasisModel.getModel('itemStyle').getItemStyle(), - blurItemStyle: seriesModel.getModel(['blur', 'itemStyle']).getItemStyle(), - selectItemStyle: seriesModel.getModel(['select', 'itemStyle']).getItemStyle(), - focus: emphasisModel.get('focus'), - blurScope: emphasisModel.get('blurScope'), - emphasisDisabled: emphasisModel.get('disabled'), - hoverScale: emphasisModel.get('scale'), - labelStatesModels: getLabelStatesModels(seriesModel), - cursorStyle: seriesModel.get('cursor') - }; - } - - var SymbolDraw = - /** @class */ - function () { - function SymbolDraw(SymbolCtor) { - this.group = new Group$2(); - this._SymbolCtor = SymbolCtor || Symbol; - } - /** - * Update symbols draw by new data - */ - - - SymbolDraw.prototype.updateData = function (data, opt) { - // Remove progressive els. - this._progressiveEls = null; - opt = normalizeUpdateOpt(opt); - var group = this.group; - var seriesModel = data.hostModel; - var oldData = this._data; - var SymbolCtor = this._SymbolCtor; - var disableAnimation = opt.disableAnimation; - var seriesScope = makeSeriesScope(data); - var symbolUpdateOpt = { - disableAnimation: disableAnimation - }; - - var getSymbolPoint = opt.getSymbolPoint || function (idx) { - return data.getItemLayout(idx); - }; // There is no oldLineData only when first rendering or switching from - // stream mode to normal mode, where previous elements should be removed. - - - if (!oldData) { - group.removeAll(); - } - - data.diff(oldData).add(function (newIdx) { - var point = getSymbolPoint(newIdx); - - if (symbolNeedsDraw(data, point, newIdx, opt)) { - var symbolEl = new SymbolCtor(data, newIdx, seriesScope, symbolUpdateOpt); - symbolEl.setPosition(point); - data.setItemGraphicEl(newIdx, symbolEl); - group.add(symbolEl); - } - }).update(function (newIdx, oldIdx) { - var symbolEl = oldData.getItemGraphicEl(oldIdx); - var point = getSymbolPoint(newIdx); - - if (!symbolNeedsDraw(data, point, newIdx, opt)) { - group.remove(symbolEl); - return; - } - - var newSymbolType = data.getItemVisual(newIdx, 'symbol') || 'circle'; - var oldSymbolType = symbolEl && symbolEl.getSymbolType && symbolEl.getSymbolType(); - - if (!symbolEl // Create a new if symbol type changed. - || oldSymbolType && oldSymbolType !== newSymbolType) { - group.remove(symbolEl); - symbolEl = new SymbolCtor(data, newIdx, seriesScope, symbolUpdateOpt); - symbolEl.setPosition(point); - } else { - symbolEl.updateData(data, newIdx, seriesScope, symbolUpdateOpt); - var target = { - x: point[0], - y: point[1] - }; - disableAnimation ? symbolEl.attr(target) : updateProps$1(symbolEl, target, seriesModel); - } // Add back - - - group.add(symbolEl); - data.setItemGraphicEl(newIdx, symbolEl); - }).remove(function (oldIdx) { - var el = oldData.getItemGraphicEl(oldIdx); - el && el.fadeOut(function () { - group.remove(el); - }, seriesModel); - }).execute(); - this._getSymbolPoint = getSymbolPoint; - this._data = data; - }; - - SymbolDraw.prototype.updateLayout = function () { - var _this = this; - - var data = this._data; - - if (data) { - // Not use animation - data.eachItemGraphicEl(function (el, idx) { - var point = _this._getSymbolPoint(idx); - - el.setPosition(point); - el.markRedraw(); - }); - } - }; - - SymbolDraw.prototype.incrementalPrepareUpdate = function (data) { - this._seriesScope = makeSeriesScope(data); - this._data = null; - this.group.removeAll(); - }; - /** - * Update symbols draw by new data - */ - - - SymbolDraw.prototype.incrementalUpdate = function (taskParams, data, opt) { - // Clear - this._progressiveEls = []; - opt = normalizeUpdateOpt(opt); - - function updateIncrementalAndHover(el) { - if (!el.isGroup) { - el.incremental = true; - el.ensureState('emphasis').hoverLayer = true; - } - } - - for (var idx = taskParams.start; idx < taskParams.end; idx++) { - var point = data.getItemLayout(idx); - - if (symbolNeedsDraw(data, point, idx, opt)) { - var el = new this._SymbolCtor(data, idx, this._seriesScope); - el.traverse(updateIncrementalAndHover); - el.setPosition(point); - this.group.add(el); - data.setItemGraphicEl(idx, el); - - this._progressiveEls.push(el); - } - } - }; - - SymbolDraw.prototype.eachRendered = function (cb) { - traverseElements(this._progressiveEls || this.group, cb); - }; - - SymbolDraw.prototype.remove = function (enableAnimation) { - var group = this.group; - var data = this._data; // Incremental model do not have this._data. - - if (data && enableAnimation) { - data.eachItemGraphicEl(function (el) { - el.fadeOut(function () { - group.remove(el); - }, data.hostModel); - }); - } else { - group.removeAll(); - } - }; - - return SymbolDraw; - }(); - - function prepareDataCoordInfo(coordSys, data, valueOrigin) { - var baseAxis = coordSys.getBaseAxis(); - var valueAxis = coordSys.getOtherAxis(baseAxis); - var valueStart = getValueStart(valueAxis, valueOrigin); - var baseAxisDim = baseAxis.dim; - var valueAxisDim = valueAxis.dim; - var valueDim = data.mapDimension(valueAxisDim); - var baseDim = data.mapDimension(baseAxisDim); - var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0; - var dims = map$1(coordSys.dimensions, function (coordDim) { - return data.mapDimension(coordDim); - }); - var stacked = false; - var stackResultDim = data.getCalculationInfo('stackResultDimension'); - - if (isDimensionStacked(data, dims[0] - /* , dims[1] */ - )) { - // jshint ignore:line - stacked = true; - dims[0] = stackResultDim; - } - - if (isDimensionStacked(data, dims[1] - /* , dims[0] */ - )) { - // jshint ignore:line - stacked = true; - dims[1] = stackResultDim; - } - - return { - dataDimsForPoint: dims, - valueStart: valueStart, - valueAxisDim: valueAxisDim, - baseAxisDim: baseAxisDim, - stacked: !!stacked, - valueDim: valueDim, - baseDim: baseDim, - baseDataOffset: baseDataOffset, - stackedOverDimension: data.getCalculationInfo('stackedOverDimension') - }; - } - - function getValueStart(valueAxis, valueOrigin) { - var valueStart = 0; - var extent = valueAxis.scale.getExtent(); - - if (valueOrigin === 'start') { - valueStart = extent[0]; - } else if (valueOrigin === 'end') { - valueStart = extent[1]; - } // If origin is specified as a number, use it as - // valueStart directly - else if (isNumber(valueOrigin) && !isNaN(valueOrigin)) { - valueStart = valueOrigin; - } // auto - else { - // Both positive - if (extent[0] > 0) { - valueStart = extent[0]; - } // Both negative - else if (extent[1] < 0) { - valueStart = extent[1]; - } // If is one positive, and one negative, onZero shall be true - - } - - return valueStart; - } - - function getStackedOnPoint(dataCoordInfo, coordSys, data, idx) { - var value = NaN; - - if (dataCoordInfo.stacked) { - value = data.get(data.getCalculationInfo('stackedOverDimension'), idx); - } - - if (isNaN(value)) { - value = dataCoordInfo.valueStart; - } - - var baseDataOffset = dataCoordInfo.baseDataOffset; - var stackedData = []; - stackedData[baseDataOffset] = data.get(dataCoordInfo.baseDim, idx); - stackedData[1 - baseDataOffset] = value; - return coordSys.dataToPoint(stackedData); - } - - function diffData(oldData, newData) { - var diffResult = []; - newData.diff(oldData).add(function (idx) { - diffResult.push({ - cmd: '+', - idx: idx - }); - }).update(function (newIdx, oldIdx) { - diffResult.push({ - cmd: '=', - idx: oldIdx, - idx1: newIdx - }); - }).remove(function (idx) { - diffResult.push({ - cmd: '-', - idx: idx - }); - }).execute(); - return diffResult; - } - - function lineAnimationDiff(oldData, newData, oldStackedOnPoints, newStackedOnPoints, oldCoordSys, newCoordSys, oldValueOrigin, newValueOrigin) { - var diff = diffData(oldData, newData); // let newIdList = newData.mapArray(newData.getId); - // let oldIdList = oldData.mapArray(oldData.getId); - // convertToIntId(newIdList, oldIdList); - // // FIXME One data ? - // diff = arrayDiff(oldIdList, newIdList); - - var currPoints = []; - var nextPoints = []; // Points for stacking base line - - var currStackedPoints = []; - var nextStackedPoints = []; - var status = []; - var sortedIndices = []; - var rawIndices = []; - var newDataOldCoordInfo = prepareDataCoordInfo(oldCoordSys, newData, oldValueOrigin); // const oldDataNewCoordInfo = prepareDataCoordInfo(newCoordSys, oldData, newValueOrigin); - - var oldPoints = oldData.getLayout('points') || []; - var newPoints = newData.getLayout('points') || []; - - for (var i = 0; i < diff.length; i++) { - var diffItem = diff[i]; - var pointAdded = true; - var oldIdx2 = void 0; - var newIdx2 = void 0; // FIXME, animation is not so perfect when dataZoom window moves fast - // Which is in case remvoing or add more than one data in the tail or head - - switch (diffItem.cmd) { - case '=': - oldIdx2 = diffItem.idx * 2; - newIdx2 = diffItem.idx1 * 2; - var currentX = oldPoints[oldIdx2]; - var currentY = oldPoints[oldIdx2 + 1]; - var nextX = newPoints[newIdx2]; - var nextY = newPoints[newIdx2 + 1]; // If previous data is NaN, use next point directly - - if (isNaN(currentX) || isNaN(currentY)) { - currentX = nextX; - currentY = nextY; - } - - currPoints.push(currentX, currentY); - nextPoints.push(nextX, nextY); - currStackedPoints.push(oldStackedOnPoints[oldIdx2], oldStackedOnPoints[oldIdx2 + 1]); - nextStackedPoints.push(newStackedOnPoints[newIdx2], newStackedOnPoints[newIdx2 + 1]); - rawIndices.push(newData.getRawIndex(diffItem.idx1)); - break; - - case '+': - var newIdx = diffItem.idx; - var newDataDimsForPoint = newDataOldCoordInfo.dataDimsForPoint; - var oldPt = oldCoordSys.dataToPoint([newData.get(newDataDimsForPoint[0], newIdx), newData.get(newDataDimsForPoint[1], newIdx)]); - newIdx2 = newIdx * 2; - currPoints.push(oldPt[0], oldPt[1]); - nextPoints.push(newPoints[newIdx2], newPoints[newIdx2 + 1]); - var stackedOnPoint = getStackedOnPoint(newDataOldCoordInfo, oldCoordSys, newData, newIdx); - currStackedPoints.push(stackedOnPoint[0], stackedOnPoint[1]); - nextStackedPoints.push(newStackedOnPoints[newIdx2], newStackedOnPoints[newIdx2 + 1]); - rawIndices.push(newData.getRawIndex(newIdx)); - break; - - case '-': - pointAdded = false; - } // Original indices - - - if (pointAdded) { - status.push(diffItem); - sortedIndices.push(sortedIndices.length); - } - } // Diff result may be crossed if all items are changed - // Sort by data index - - - sortedIndices.sort(function (a, b) { - return rawIndices[a] - rawIndices[b]; - }); - var len = currPoints.length; - var sortedCurrPoints = createFloat32Array(len); - var sortedNextPoints = createFloat32Array(len); - var sortedCurrStackedPoints = createFloat32Array(len); - var sortedNextStackedPoints = createFloat32Array(len); - var sortedStatus = []; - - for (var i = 0; i < sortedIndices.length; i++) { - var idx = sortedIndices[i]; - var i2 = i * 2; - var idx2 = idx * 2; - sortedCurrPoints[i2] = currPoints[idx2]; - sortedCurrPoints[i2 + 1] = currPoints[idx2 + 1]; - sortedNextPoints[i2] = nextPoints[idx2]; - sortedNextPoints[i2 + 1] = nextPoints[idx2 + 1]; - sortedCurrStackedPoints[i2] = currStackedPoints[idx2]; - sortedCurrStackedPoints[i2 + 1] = currStackedPoints[idx2 + 1]; - sortedNextStackedPoints[i2] = nextStackedPoints[idx2]; - sortedNextStackedPoints[i2 + 1] = nextStackedPoints[idx2 + 1]; - sortedStatus[i] = status[idx]; - } - - return { - current: sortedCurrPoints, - next: sortedNextPoints, - stackedOnCurrent: sortedCurrStackedPoints, - stackedOnNext: sortedNextStackedPoints, - status: sortedStatus - }; - } - - var mathMin = Math.min; - var mathMax = Math.max; - - function isPointNull$1(x, y) { - return isNaN(x) || isNaN(y); - } - /** - * Draw smoothed line in non-monotone, in may cause undesired curve in extreme - * situations. This should be used when points are non-monotone neither in x or - * y dimension. - */ - - - function drawSegment(ctx, points, start, segLen, allLen, dir, smooth, smoothMonotone, connectNulls) { - var prevX; - var prevY; - var cpx0; - var cpy0; - var cpx1; - var cpy1; - var idx = start; - var k = 0; - - for (; k < segLen; k++) { - var x = points[idx * 2]; - var y = points[idx * 2 + 1]; - - if (idx >= allLen || idx < 0) { - break; - } - - if (isPointNull$1(x, y)) { - if (connectNulls) { - idx += dir; - continue; - } - - break; - } - - if (idx === start) { - ctx[dir > 0 ? 'moveTo' : 'lineTo'](x, y); - cpx0 = x; - cpy0 = y; - } else { - var dx = x - prevX; - var dy = y - prevY; // Ignore tiny segment. - - if (dx * dx + dy * dy < 0.5) { - idx += dir; - continue; - } - - if (smooth > 0) { - var nextIdx = idx + dir; - var nextX = points[nextIdx * 2]; - var nextY = points[nextIdx * 2 + 1]; // Ignore duplicate point - - while (nextX === x && nextY === y && k < segLen) { - k++; - nextIdx += dir; - idx += dir; - nextX = points[nextIdx * 2]; - nextY = points[nextIdx * 2 + 1]; - x = points[idx * 2]; - y = points[idx * 2 + 1]; - dx = x - prevX; - dy = y - prevY; - } - - var tmpK = k + 1; - - if (connectNulls) { - // Find next point not null - while (isPointNull$1(nextX, nextY) && tmpK < segLen) { - tmpK++; - nextIdx += dir; - nextX = points[nextIdx * 2]; - nextY = points[nextIdx * 2 + 1]; - } - } - - var ratioNextSeg = 0.5; - var vx = 0; - var vy = 0; - var nextCpx0 = void 0; - var nextCpy0 = void 0; // Is last point - - if (tmpK >= segLen || isPointNull$1(nextX, nextY)) { - cpx1 = x; - cpy1 = y; - } else { - vx = nextX - prevX; - vy = nextY - prevY; - var dx0 = x - prevX; - var dx1 = nextX - x; - var dy0 = y - prevY; - var dy1 = nextY - y; - var lenPrevSeg = void 0; - var lenNextSeg = void 0; - - if (smoothMonotone === 'x') { - lenPrevSeg = Math.abs(dx0); - lenNextSeg = Math.abs(dx1); - var dir_1 = vx > 0 ? 1 : -1; - cpx1 = x - dir_1 * lenPrevSeg * smooth; - cpy1 = y; - nextCpx0 = x + dir_1 * lenNextSeg * smooth; - nextCpy0 = y; - } else if (smoothMonotone === 'y') { - lenPrevSeg = Math.abs(dy0); - lenNextSeg = Math.abs(dy1); - var dir_2 = vy > 0 ? 1 : -1; - cpx1 = x; - cpy1 = y - dir_2 * lenPrevSeg * smooth; - nextCpx0 = x; - nextCpy0 = y + dir_2 * lenNextSeg * smooth; - } else { - lenPrevSeg = Math.sqrt(dx0 * dx0 + dy0 * dy0); - lenNextSeg = Math.sqrt(dx1 * dx1 + dy1 * dy1); // Use ratio of seg length - - ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg); - cpx1 = x - vx * smooth * (1 - ratioNextSeg); - cpy1 = y - vy * smooth * (1 - ratioNextSeg); // cp0 of next segment - - nextCpx0 = x + vx * smooth * ratioNextSeg; - nextCpy0 = y + vy * smooth * ratioNextSeg; // Smooth constraint between point and next point. - // Avoid exceeding extreme after smoothing. - - nextCpx0 = mathMin(nextCpx0, mathMax(nextX, x)); - nextCpy0 = mathMin(nextCpy0, mathMax(nextY, y)); - nextCpx0 = mathMax(nextCpx0, mathMin(nextX, x)); - nextCpy0 = mathMax(nextCpy0, mathMin(nextY, y)); // Reclaculate cp1 based on the adjusted cp0 of next seg. - - vx = nextCpx0 - x; - vy = nextCpy0 - y; - cpx1 = x - vx * lenPrevSeg / lenNextSeg; - cpy1 = y - vy * lenPrevSeg / lenNextSeg; // Smooth constraint between point and prev point. - // Avoid exceeding extreme after smoothing. - - cpx1 = mathMin(cpx1, mathMax(prevX, x)); - cpy1 = mathMin(cpy1, mathMax(prevY, y)); - cpx1 = mathMax(cpx1, mathMin(prevX, x)); - cpy1 = mathMax(cpy1, mathMin(prevY, y)); // Adjust next cp0 again. - - vx = x - cpx1; - vy = y - cpy1; - nextCpx0 = x + vx * lenNextSeg / lenPrevSeg; - nextCpy0 = y + vy * lenNextSeg / lenPrevSeg; - } - } - - ctx.bezierCurveTo(cpx0, cpy0, cpx1, cpy1, x, y); - cpx0 = nextCpx0; - cpy0 = nextCpy0; - } else { - ctx.lineTo(x, y); - } - } - - prevX = x; - prevY = y; - idx += dir; - } - - return k; - } - - var ECPolylineShape = - /** @class */ - function () { - function ECPolylineShape() { - this.smooth = 0; - this.smoothConstraint = true; - } - - return ECPolylineShape; - }(); - - var ECPolyline = - /** @class */ - function (_super) { - __extends(ECPolyline, _super); - - function ECPolyline(opts) { - var _this = _super.call(this, opts) || this; - - _this.type = 'ec-polyline'; - return _this; - } - - ECPolyline.prototype.getDefaultStyle = function () { - return { - stroke: tokens.color.neutral99, - fill: null - }; - }; - - ECPolyline.prototype.getDefaultShape = function () { - return new ECPolylineShape(); - }; - - ECPolyline.prototype.buildPath = function (ctx, shape) { - var points = shape.points; - var i = 0; - var len = points.length / 2; // const result = getBoundingBox(points, shape.smoothConstraint); - - if (shape.connectNulls) { - // Must remove first and last null values avoid draw error in polygon - for (; len > 0; len--) { - if (!isPointNull$1(points[len * 2 - 2], points[len * 2 - 1])) { - break; - } - } - - for (; i < len; i++) { - if (!isPointNull$1(points[i * 2], points[i * 2 + 1])) { - break; - } - } - } - - while (i < len) { - i += drawSegment(ctx, points, i, len, len, 1, shape.smooth, shape.smoothMonotone, shape.connectNulls) + 1; - } - }; - - ECPolyline.prototype.getPointOn = function (xOrY, dim) { - if (!this.path) { - this.createPathProxy(); - this.buildPath(this.path, this.shape); - } - - var path = this.path; - var data = path.data; - var CMD = PathProxy.CMD; - var x0; - var y0; - var isDimX = dim === 'x'; - var roots = []; - - for (var i = 0; i < data.length;) { - var cmd = data[i++]; - var x = void 0; - var y = void 0; - var x2 = void 0; - var y2 = void 0; - var x3 = void 0; - var y3 = void 0; - var t = void 0; - - switch (cmd) { - case CMD.M: - x0 = data[i++]; - y0 = data[i++]; - break; - - case CMD.L: - x = data[i++]; - y = data[i++]; - t = isDimX ? (xOrY - x0) / (x - x0) : (xOrY - y0) / (y - y0); - - if (t <= 1 && t >= 0) { - var val = isDimX ? (y - y0) * t + y0 : (x - x0) * t + x0; - return isDimX ? [xOrY, val] : [val, xOrY]; - } - - x0 = x; - y0 = y; - break; - - case CMD.C: - x = data[i++]; - y = data[i++]; - x2 = data[i++]; - y2 = data[i++]; - x3 = data[i++]; - y3 = data[i++]; - var nRoot = isDimX ? cubicRootAt(x0, x, x2, x3, xOrY, roots) : cubicRootAt(y0, y, y2, y3, xOrY, roots); - - if (nRoot > 0) { - for (var i_1 = 0; i_1 < nRoot; i_1++) { - var t_1 = roots[i_1]; - - if (t_1 <= 1 && t_1 >= 0) { - var val = isDimX ? cubicAt(y0, y, y2, y3, t_1) : cubicAt(x0, x, x2, x3, t_1); - return isDimX ? [xOrY, val] : [val, xOrY]; - } - } - } - - x0 = x3; - y0 = y3; - break; - } - } - }; - - return ECPolyline; - }(Path); - - var ECPolygonShape = - /** @class */ - function (_super) { - __extends(ECPolygonShape, _super); - - function ECPolygonShape() { - return _super !== null && _super.apply(this, arguments) || this; - } - - return ECPolygonShape; - }(ECPolylineShape); - - var ECPolygon = - /** @class */ - function (_super) { - __extends(ECPolygon, _super); - - function ECPolygon(opts) { - var _this = _super.call(this, opts) || this; - - _this.type = 'ec-polygon'; - return _this; - } - - ECPolygon.prototype.getDefaultShape = function () { - return new ECPolygonShape(); - }; - - ECPolygon.prototype.buildPath = function (ctx, shape) { - var points = shape.points; - var stackedOnPoints = shape.stackedOnPoints; - var i = 0; - var len = points.length / 2; - var smoothMonotone = shape.smoothMonotone; - - if (shape.connectNulls) { - // Must remove first and last null values avoid draw error in polygon - for (; len > 0; len--) { - if (!isPointNull$1(points[len * 2 - 2], points[len * 2 - 1])) { - break; - } - } - - for (; i < len; i++) { - if (!isPointNull$1(points[i * 2], points[i * 2 + 1])) { - break; - } - } - } - - while (i < len) { - var k = drawSegment(ctx, points, i, len, len, 1, shape.smooth, smoothMonotone, shape.connectNulls); - drawSegment(ctx, stackedOnPoints, i + k - 1, k, len, -1, shape.stackedOnSmooth, smoothMonotone, shape.connectNulls); - i += k + 1; - ctx.closePath(); - } - }; - - return ECPolygon; - }(Path); - - function isPointsSame(points1, points2) { - if (points1.length !== points2.length) { - return; - } - - for (var i = 0; i < points1.length; i++) { - if (points1[i] !== points2[i]) { - return; - } - } - - return true; - } - - function bboxFromPoints(points) { - var minX = Infinity; - var minY = Infinity; - var maxX = -Infinity; - var maxY = -Infinity; - - for (var i = 0; i < points.length;) { - var x = points[i++]; - var y = points[i++]; - - if (!isNaN(x)) { - minX = Math.min(x, minX); - maxX = Math.max(x, maxX); - } - - if (!isNaN(y)) { - minY = Math.min(y, minY); - maxY = Math.max(y, maxY); - } - } - - return [[minX, minY], [maxX, maxY]]; - } - - function getBoundingDiff(points1, points2) { - var _a = bboxFromPoints(points1), - min1 = _a[0], - max1 = _a[1]; - - var _b = bboxFromPoints(points2), - min2 = _b[0], - max2 = _b[1]; // Get a max value from each corner of two boundings. - - - return Math.max(Math.abs(min1[0] - min2[0]), Math.abs(min1[1] - min2[1]), Math.abs(max1[0] - max2[0]), Math.abs(max1[1] - max2[1])); - } - - function getSmooth(smooth) { - return isNumber(smooth) ? smooth : smooth ? 0.5 : 0; - } - - function getStackedOnPoints(coordSys, data, dataCoordInfo) { - if (!dataCoordInfo.valueDim) { - return []; - } - - var len = data.count(); - var points = createFloat32Array(len * 2); - - for (var idx = 0; idx < len; idx++) { - var pt = getStackedOnPoint(dataCoordInfo, coordSys, data, idx); - points[idx * 2] = pt[0]; - points[idx * 2 + 1] = pt[1]; - } - - return points; - } - /** - * Filter the null data and extend data for step considering `stepTurnAt` - * - * @param points data to convert, that may containing null - * @param basePoints base data to reference, used only for areaStyle points - * @param coordSys coordinate system - * @param stepTurnAt 'start' | 'end' | 'middle' | true - * @param connectNulls whether to connect nulls - * @returns converted point positions - */ - - - function turnPointsIntoStep(points, basePoints, coordSys, stepTurnAt, connectNulls) { - var baseAxis = coordSys.getBaseAxis(); - var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1; - var stepPoints = []; - var i = 0; - var stepPt = []; - var pt = []; - var nextPt = []; - var filteredPoints = []; - - if (connectNulls) { - for (i = 0; i < points.length; i += 2) { - /** - * For areaStyle of stepped lines, `stackedOnPoints` should be - * filtered the same as `points` so that the base axis values - * should stay the same as the lines above. See #20021 - */ - var reference = basePoints || points; - - if (!isNaN(reference[i]) && !isNaN(reference[i + 1])) { - filteredPoints.push(points[i], points[i + 1]); - } - } - - points = filteredPoints; - } - - for (i = 0; i < points.length - 2; i += 2) { - nextPt[0] = points[i + 2]; - nextPt[1] = points[i + 3]; - pt[0] = points[i]; - pt[1] = points[i + 1]; - stepPoints.push(pt[0], pt[1]); - - switch (stepTurnAt) { - case 'end': - stepPt[baseIndex] = nextPt[baseIndex]; - stepPt[1 - baseIndex] = pt[1 - baseIndex]; - stepPoints.push(stepPt[0], stepPt[1]); - break; - - case 'middle': - var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2; - var stepPt2 = []; - stepPt[baseIndex] = stepPt2[baseIndex] = middle; - stepPt[1 - baseIndex] = pt[1 - baseIndex]; - stepPt2[1 - baseIndex] = nextPt[1 - baseIndex]; - stepPoints.push(stepPt[0], stepPt[1]); - stepPoints.push(stepPt2[0], stepPt2[1]); - break; - - default: - // default is start - stepPt[baseIndex] = pt[baseIndex]; - stepPt[1 - baseIndex] = nextPt[1 - baseIndex]; - stepPoints.push(stepPt[0], stepPt[1]); - } - } // Last points - - - stepPoints.push(points[i++], points[i++]); - return stepPoints; - } - /** - * Clip color stops to edge. Avoid creating too large gradients. - * Which may lead to blurry when GPU acceleration is enabled. See #15680 - * - * The stops has been sorted from small to large. - */ - - - function clipColorStops(colorStops, maxSize) { - var newColorStops = []; - var len = colorStops.length; // coord will always < 0 in prevOutOfRangeColorStop. - - var prevOutOfRangeColorStop; - var prevInRangeColorStop; - - function lerpStop(stop0, stop1, clippedCoord) { - var coord0 = stop0.coord; - var p = (clippedCoord - coord0) / (stop1.coord - coord0); - var color = lerp(p, [stop0.color, stop1.color]); - return { - coord: clippedCoord, - color: color - }; - } - - for (var i = 0; i < len; i++) { - var stop_1 = colorStops[i]; - var coord = stop_1.coord; - - if (coord < 0) { - prevOutOfRangeColorStop = stop_1; - } else if (coord > maxSize) { - if (prevInRangeColorStop) { - newColorStops.push(lerpStop(prevInRangeColorStop, stop_1, maxSize)); - } else if (prevOutOfRangeColorStop) { - // If there are two stops and coord range is between these two stops - newColorStops.push(lerpStop(prevOutOfRangeColorStop, stop_1, 0), lerpStop(prevOutOfRangeColorStop, stop_1, maxSize)); - } // All following stop will be out of range. So just ignore them. - - - break; - } else { - if (prevOutOfRangeColorStop) { - newColorStops.push(lerpStop(prevOutOfRangeColorStop, stop_1, 0)); // Reset - - prevOutOfRangeColorStop = null; - } - - newColorStops.push(stop_1); - prevInRangeColorStop = stop_1; - } - } - - return newColorStops; - } - - function getVisualGradient(data, coordSys, api) { - var visualMetaList = data.getVisual('visualMeta'); - - if (!visualMetaList || !visualMetaList.length || !data.count()) { - // When data.count() is 0, gradient range can not be calculated. - return; - } - - if (coordSys.type !== 'cartesian2d') { - { - console.warn('Visual map on line style is only supported on cartesian2d.'); - } - return; - } - - var coordDim; - var visualMeta; - - for (var i = visualMetaList.length - 1; i >= 0; i--) { - var dimInfo = data.getDimensionInfo(visualMetaList[i].dimension); - coordDim = dimInfo && dimInfo.coordDim; // Can only be x or y - - if (coordDim === 'x' || coordDim === 'y') { - visualMeta = visualMetaList[i]; - break; - } - } - - if (!visualMeta) { - { - console.warn('Visual map on line style only support x or y dimension.'); - } - return; - } // If the area to be rendered is bigger than area defined by LinearGradient, - // the canvas spec prescribes that the color of the first stop and the last - // stop should be used. But if two stops are added at offset 0, in effect - // browsers use the color of the second stop to render area outside - // LinearGradient. So we can only infinitesimally extend area defined in - // LinearGradient to render `outerColors`. - - - var axis = coordSys.getAxis(coordDim); // dataToCoord mapping may not be linear, but must be monotonic. - - var colorStops = map$1(visualMeta.stops, function (stop) { - // offset will be calculated later. - return { - coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)), - color: stop.color - }; - }); - var stopLen = colorStops.length; - var outerColors = visualMeta.outerColors.slice(); - - if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) { - colorStops.reverse(); - outerColors.reverse(); - } - - var colorStopsInRange = clipColorStops(colorStops, coordDim === 'x' ? api.getWidth() : api.getHeight()); - var inRangeStopLen = colorStopsInRange.length; - - if (!inRangeStopLen && stopLen) { - // All stops are out of range. All will be the same color. - return colorStops[0].coord < 0 ? outerColors[1] ? outerColors[1] : colorStops[stopLen - 1].color : outerColors[0] ? outerColors[0] : colorStops[0].color; - } - - var tinyExtent = 10; // Arbitrary value: 10px - - var minCoord = colorStopsInRange[0].coord - tinyExtent; - var maxCoord = colorStopsInRange[inRangeStopLen - 1].coord + tinyExtent; - var coordSpan = maxCoord - minCoord; - - if (coordSpan < 1e-3) { - return 'transparent'; - } - - each$4(colorStopsInRange, function (stop) { - stop.offset = (stop.coord - minCoord) / coordSpan; - }); - colorStopsInRange.push({ - // NOTE: inRangeStopLen may still be 0 if stoplen is zero. - offset: inRangeStopLen ? colorStopsInRange[inRangeStopLen - 1].offset : 0.5, - color: outerColors[1] || 'transparent' - }); - colorStopsInRange.unshift({ - offset: inRangeStopLen ? colorStopsInRange[0].offset : 0.5, - color: outerColors[0] || 'transparent' - }); - var gradient = new LinearGradient(0, 0, 0, 0, colorStopsInRange, true); - gradient[coordDim] = minCoord; - gradient[coordDim + '2'] = maxCoord; - return gradient; - } - - function getIsIgnoreFunc(seriesModel, data, coordSys) { - var showAllSymbol = seriesModel.get('showAllSymbol'); - var isAuto = showAllSymbol === 'auto'; - - if (showAllSymbol && !isAuto) { - return; - } - - var categoryAxis = coordSys.getAxesByScale('ordinal')[0]; - - if (!categoryAxis) { - return; - } // Note that category label interval strategy might bring some weird effect - // in some scenario: users may wonder why some of the symbols are not - // displayed. So we show all symbols as possible as we can. - - - if (isAuto // Simplify the logic, do not determine label overlap here. - && canShowAllSymbolForCategory(categoryAxis, data)) { - return; - } // Otherwise follow the label interval strategy on category axis. - - - var categoryDataDim = data.mapDimension(categoryAxis.dim); - var labelMap = {}; - each$4(categoryAxis.getViewLabels(), function (labelItem) { - var ordinalNumber = categoryAxis.scale.getRawOrdinalNumber(labelItem.tickValue); - labelMap[ordinalNumber] = 1; - }); - return function (dataIndex) { - return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex)); - }; - } - - function canShowAllSymbolForCategory(categoryAxis, data) { - // In most cases, line is monotonous on category axis, and the label size - // is close with each other. So we check the symbol size and some of the - // label size alone with the category axis to estimate whether all symbol - // can be shown without overlap. - var axisExtent = categoryAxis.getExtent(); - var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count(); - isNaN(availSize) && (availSize = 0); // 0/0 is NaN. - // Sampling some points, max 5. - - var dataLen = data.count(); - var step = Math.max(1, Math.round(dataLen / 5)); - - for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) { - if (Symbol.getSymbolSize(data, dataIndex // Only for cartesian, where `isHorizontal` exists. - )[categoryAxis.isHorizontal() ? 1 : 0] // Empirical number - * 1.5 > availSize) { - return false; - } - } - - return true; - } - - function isPointNull(x, y) { - return isNaN(x) || isNaN(y); - } - - function getLastIndexNotNull(points) { - var len = points.length / 2; - - for (; len > 0; len--) { - if (!isPointNull(points[len * 2 - 2], points[len * 2 - 1])) { - break; - } - } - - return len - 1; - } - - function getPointAtIndex(points, idx) { - return [points[idx * 2], points[idx * 2 + 1]]; - } - - function getIndexRange(points, xOrY, dim) { - var len = points.length / 2; - var dimIdx = dim === 'x' ? 0 : 1; - var a; - var b; - var prevIndex = 0; - var nextIndex = -1; - - for (var i = 0; i < len; i++) { - b = points[i * 2 + dimIdx]; - - if (isNaN(b) || isNaN(points[i * 2 + 1 - dimIdx])) { - continue; - } - - if (i === 0) { - a = b; - continue; - } - - if (a <= xOrY && b >= xOrY || a >= xOrY && b <= xOrY) { - nextIndex = i; - break; - } - - prevIndex = i; - a = b; - } - - return { - range: [prevIndex, nextIndex], - t: (xOrY - a) / (b - a) - }; - } - - function anyStateShowEndLabel(seriesModel) { - if (seriesModel.get(['endLabel', 'show'])) { - return true; - } - - for (var i = 0; i < SPECIAL_STATES.length; i++) { - if (seriesModel.get([SPECIAL_STATES[i], 'endLabel', 'show'])) { - return true; - } - } - - return false; - } - - function createLineClipPath(lineView, coordSys, hasAnimation, seriesModel) { - if (isCoordinateSystemType(coordSys, 'cartesian2d')) { - var endLabelModel_1 = seriesModel.getModel('endLabel'); - var valueAnimation_1 = endLabelModel_1.get('valueAnimation'); - var data_1 = seriesModel.getData(); - var labelAnimationRecord_1 = { - lastFrameIndex: 0 - }; - var during = anyStateShowEndLabel(seriesModel) ? function (percent, clipRect) { - lineView._endLabelOnDuring(percent, clipRect, data_1, labelAnimationRecord_1, valueAnimation_1, endLabelModel_1, coordSys); - } : null; - var isHorizontal = coordSys.getBaseAxis().isHorizontal(); - var clipPath = createGridClipPath(coordSys, hasAnimation, seriesModel, function () { - var endLabel = lineView._endLabel; - - if (endLabel && hasAnimation) { - if (labelAnimationRecord_1.originalX != null) { - endLabel.attr({ - x: labelAnimationRecord_1.originalX, - y: labelAnimationRecord_1.originalY - }); - } - } - }, during); // Expand clip shape to avoid clipping when line value exceeds axis - - if (!seriesModel.get('clip', true)) { - var rectShape = clipPath.shape; - var expandSize = Math.max(rectShape.width, rectShape.height); - - if (isHorizontal) { - rectShape.y -= expandSize; - rectShape.height += expandSize * 2; - } else { - rectShape.x -= expandSize; - rectShape.width += expandSize * 2; - } - } // Set to the final frame. To make sure label layout is right. - - - if (during) { - during(1, clipPath); - } - - return clipPath; - } else { - { - if (seriesModel.get(['endLabel', 'show'])) { - console.warn('endLabel is not supported for lines in polar systems.'); - } - } - return createPolarClipPath(coordSys, hasAnimation, seriesModel); - } - } - - function getEndLabelStateSpecified(endLabelModel, coordSys) { - var baseAxis = coordSys.getBaseAxis(); - var isHorizontal = baseAxis.isHorizontal(); - var isBaseInversed = baseAxis.inverse; - var align = isHorizontal ? isBaseInversed ? 'right' : 'left' : 'center'; - var verticalAlign = isHorizontal ? 'middle' : isBaseInversed ? 'top' : 'bottom'; - return { - normal: { - align: endLabelModel.get('align') || align, - verticalAlign: endLabelModel.get('verticalAlign') || verticalAlign - } - }; - } - - var LineView = - /** @class */ - function (_super) { - __extends(LineView, _super); - - function LineView() { - return _super !== null && _super.apply(this, arguments) || this; - } - - LineView.prototype.init = function () { - var lineGroup = new Group$2(); - var symbolDraw = new SymbolDraw(); - this.group.add(symbolDraw.group); - this._symbolDraw = symbolDraw; - this._lineGroup = lineGroup; - this._changePolyState = bind$1(this._changePolyState, this); - }; - - LineView.prototype.render = function (seriesModel, ecModel, api) { - var coordSys = seriesModel.coordinateSystem; - var group = this.group; - var data = seriesModel.getData(); - var lineStyleModel = seriesModel.getModel('lineStyle'); - var areaStyleModel = seriesModel.getModel('areaStyle'); - var points = data.getLayout('points') || []; - var isCoordSysPolar = coordSys.type === 'polar'; - var prevCoordSys = this._coordSys; - var symbolDraw = this._symbolDraw; - var polyline = this._polyline; - var polygon = this._polygon; - var lineGroup = this._lineGroup; - var hasAnimation = !ecModel.ssr && seriesModel.get('animation'); - var isAreaChart = !areaStyleModel.isEmpty(); - var valueOrigin = areaStyleModel.get('origin'); - var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin); - var stackedOnPoints = isAreaChart && getStackedOnPoints(coordSys, data, dataCoordInfo); - var showSymbol = seriesModel.get('showSymbol'); - var connectNulls = seriesModel.get('connectNulls'); - var isIgnoreFunc = showSymbol && !isCoordSysPolar && getIsIgnoreFunc(seriesModel, data, coordSys); // Remove temporary symbols - - var oldData = this._data; - oldData && oldData.eachItemGraphicEl(function (el, idx) { - if (el.__temp) { - group.remove(el); - oldData.setItemGraphicEl(idx, null); - } - }); // Remove previous created symbols if showSymbol changed to false - - if (!showSymbol) { - symbolDraw.remove(); - } - - group.add(lineGroup); // FIXME step not support polar - - var step = !isCoordSysPolar ? seriesModel.get('step') : false; - var clipShapeForSymbol; - - if (coordSys && coordSys.getArea && seriesModel.get('clip', true)) { - clipShapeForSymbol = coordSys.getArea(); // Avoid float number rounding error for symbol on the edge of axis extent. - // See #7913 and `test/dataZoom-clip.html`. - - if (clipShapeForSymbol.width != null) { - clipShapeForSymbol.x -= 0.1; - clipShapeForSymbol.y -= 0.1; - clipShapeForSymbol.width += 0.2; - clipShapeForSymbol.height += 0.2; - } else if (clipShapeForSymbol.r0) { - clipShapeForSymbol.r0 -= 0.5; - clipShapeForSymbol.r += 0.5; - } - } - - this._clipShapeForSymbol = clipShapeForSymbol; - var visualColor = getVisualGradient(data, coordSys, api) || data.getVisual('style')[data.getVisual('drawType')]; // Initialization animation or coordinate system changed - - if (!(polyline && prevCoordSys.type === coordSys.type && step === this._step)) { - showSymbol && symbolDraw.updateData(data, { - isIgnore: isIgnoreFunc, - clipShape: clipShapeForSymbol, - disableAnimation: true, - getSymbolPoint: function (idx) { - return [points[idx * 2], points[idx * 2 + 1]]; - } - }); - hasAnimation && this._initSymbolLabelAnimation(data, coordSys, clipShapeForSymbol); - - if (step) { - if (stackedOnPoints) { - stackedOnPoints = turnPointsIntoStep(stackedOnPoints, points, coordSys, step, connectNulls); - } // TODO If stacked series is not step - - - points = turnPointsIntoStep(points, null, coordSys, step, connectNulls); - } - - polyline = this._newPolyline(points); - - if (isAreaChart) { - polygon = this._newPolygon(points, stackedOnPoints); - } // If areaStyle is removed - else if (polygon) { - lineGroup.remove(polygon); - polygon = this._polygon = null; - } // NOTE: Must update _endLabel before setClipPath. - - - if (!isCoordSysPolar) { - this._initOrUpdateEndLabel(seriesModel, coordSys, convertToColorString(visualColor)); - } - - lineGroup.setClipPath(createLineClipPath(this, coordSys, true, seriesModel)); - } else { - if (isAreaChart && !polygon) { - // If areaStyle is added - polygon = this._newPolygon(points, stackedOnPoints); - } else if (polygon && !isAreaChart) { - // If areaStyle is removed - lineGroup.remove(polygon); - polygon = this._polygon = null; - } // NOTE: Must update _endLabel before setClipPath. - - - if (!isCoordSysPolar) { - this._initOrUpdateEndLabel(seriesModel, coordSys, convertToColorString(visualColor)); - } // Update clipPath - - - var oldClipPath = lineGroup.getClipPath(); - - if (oldClipPath) { - var newClipPath = createLineClipPath(this, coordSys, false, seriesModel); - initProps(oldClipPath, { - shape: newClipPath.shape - }, seriesModel); - } else { - lineGroup.setClipPath(createLineClipPath(this, coordSys, true, seriesModel)); - } // Always update, or it is wrong in the case turning on legend - // because points are not changed. - - - showSymbol && symbolDraw.updateData(data, { - isIgnore: isIgnoreFunc, - clipShape: clipShapeForSymbol, - disableAnimation: true, - getSymbolPoint: function (idx) { - return [points[idx * 2], points[idx * 2 + 1]]; - } - }); // In the case data zoom triggered refreshing frequently - // Data may not change if line has a category axis. So it should animate nothing. - - if (!isPointsSame(this._stackedOnPoints, stackedOnPoints) || !isPointsSame(this._points, points)) { - if (hasAnimation) { - this._doUpdateAnimation(data, stackedOnPoints, coordSys, api, step, valueOrigin, connectNulls); - } else { - // Not do it in update with animation - if (step) { - if (stackedOnPoints) { - stackedOnPoints = turnPointsIntoStep(stackedOnPoints, points, coordSys, step, connectNulls); - } // TODO If stacked series is not step - - - points = turnPointsIntoStep(points, null, coordSys, step, connectNulls); - } - - polyline.setShape({ - points: points - }); - polygon && polygon.setShape({ - points: points, - stackedOnPoints: stackedOnPoints - }); - } - } - } - - var emphasisModel = seriesModel.getModel('emphasis'); - var focus = emphasisModel.get('focus'); - var blurScope = emphasisModel.get('blurScope'); - var emphasisDisabled = emphasisModel.get('disabled'); - polyline.useStyle(defaults( // Use color in lineStyle first - lineStyleModel.getLineStyle(), { - fill: 'none', - stroke: visualColor, - lineJoin: 'bevel' - })); - setStatesStylesFromModel(polyline, seriesModel, 'lineStyle'); - - if (polyline.style.lineWidth > 0 && seriesModel.get(['emphasis', 'lineStyle', 'width']) === 'bolder') { - var emphasisLineStyle = polyline.getState('emphasis').style; - emphasisLineStyle.lineWidth = +polyline.style.lineWidth + 1; - } // Needs seriesIndex for focus - - - getECData(polyline).seriesIndex = seriesModel.seriesIndex; - toggleHoverEmphasis(polyline, focus, blurScope, emphasisDisabled); - var smooth = getSmooth(seriesModel.get('smooth')); - var smoothMonotone = seriesModel.get('smoothMonotone'); - polyline.setShape({ - smooth: smooth, - smoothMonotone: smoothMonotone, - connectNulls: connectNulls - }); - - if (polygon) { - var stackedOnSeries = data.getCalculationInfo('stackedOnSeries'); - var stackedOnSmooth = 0; - polygon.useStyle(defaults(areaStyleModel.getAreaStyle(), { - fill: visualColor, - opacity: 0.7, - lineJoin: 'bevel', - decal: data.getVisual('style').decal - })); - - if (stackedOnSeries) { - stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth')); - } - - polygon.setShape({ - smooth: smooth, - stackedOnSmooth: stackedOnSmooth, - smoothMonotone: smoothMonotone, - connectNulls: connectNulls - }); - setStatesStylesFromModel(polygon, seriesModel, 'areaStyle'); // Needs seriesIndex for focus - - getECData(polygon).seriesIndex = seriesModel.seriesIndex; - toggleHoverEmphasis(polygon, focus, blurScope, emphasisDisabled); - } - - var changePolyState = this._changePolyState; - data.eachItemGraphicEl(function (el) { - // Switch polyline / polygon state if element changed its state. - el && (el.onHoverStateChange = changePolyState); - }); - this._polyline.onHoverStateChange = changePolyState; - this._data = data; // Save the coordinate system for transition animation when data changed - - this._coordSys = coordSys; - this._stackedOnPoints = stackedOnPoints; - this._points = points; - this._step = step; - this._valueOrigin = valueOrigin; - - if (seriesModel.get('triggerLineEvent')) { - this.packEventData(seriesModel, polyline); - polygon && this.packEventData(seriesModel, polygon); - } - }; - - LineView.prototype.packEventData = function (seriesModel, el) { - getECData(el).eventData = { - componentType: 'series', - componentSubType: 'line', - componentIndex: seriesModel.componentIndex, - seriesIndex: seriesModel.seriesIndex, - seriesName: seriesModel.name, - seriesType: 'line' - }; - }; - - LineView.prototype.highlight = function (seriesModel, ecModel, api, payload) { - var data = seriesModel.getData(); - var dataIndex = queryDataIndex(data, payload); - - this._changePolyState('emphasis'); - - if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) { - var points = data.getLayout('points'); - var symbol = data.getItemGraphicEl(dataIndex); - - if (!symbol) { - // Create a temporary symbol if it is not exists - var x = points[dataIndex * 2]; - var y = points[dataIndex * 2 + 1]; - - if (isNaN(x) || isNaN(y)) { - // Null data - return; - } // fix #11360: shouldn't draw symbol outside clipShapeForSymbol - - - if (this._clipShapeForSymbol && !this._clipShapeForSymbol.contain(x, y)) { - return; - } - - var zlevel = seriesModel.get('zlevel') || 0; - var z = seriesModel.get('z') || 0; - symbol = new Symbol(data, dataIndex); - symbol.x = x; - symbol.y = y; - symbol.setZ(zlevel, z); // ensure label text of the temporary symbol is in front of line and area polygon - - var symbolLabel = symbol.getSymbolPath().getTextContent(); - - if (symbolLabel) { - symbolLabel.zlevel = zlevel; - symbolLabel.z = z; - symbolLabel.z2 = this._polyline.z2 + 1; - } - - symbol.__temp = true; - data.setItemGraphicEl(dataIndex, symbol); // Stop scale animation - - symbol.stopSymbolAnimation(true); - this.group.add(symbol); - } - - symbol.highlight(); - } else { - // Highlight whole series - ChartView.prototype.highlight.call(this, seriesModel, ecModel, api, payload); - } - }; - - LineView.prototype.downplay = function (seriesModel, ecModel, api, payload) { - var data = seriesModel.getData(); - var dataIndex = queryDataIndex(data, payload); - - this._changePolyState('normal'); - - if (dataIndex != null && dataIndex >= 0) { - var symbol = data.getItemGraphicEl(dataIndex); - - if (symbol) { - if (symbol.__temp) { - data.setItemGraphicEl(dataIndex, null); - this.group.remove(symbol); - } else { - symbol.downplay(); - } - } - } else { - // FIXME - // can not downplay completely. - // Downplay whole series - ChartView.prototype.downplay.call(this, seriesModel, ecModel, api, payload); - } - }; - - LineView.prototype._changePolyState = function (toState) { - var polygon = this._polygon; - setStatesFlag(this._polyline, toState); - polygon && setStatesFlag(polygon, toState); - }; - - LineView.prototype._newPolyline = function (points) { - var polyline = this._polyline; // Remove previous created polyline - - if (polyline) { - this._lineGroup.remove(polyline); - } - - polyline = new ECPolyline({ - shape: { - points: points - }, - segmentIgnoreThreshold: 2, - z2: 10 - }); - - this._lineGroup.add(polyline); - - this._polyline = polyline; - return polyline; - }; - - LineView.prototype._newPolygon = function (points, stackedOnPoints) { - var polygon = this._polygon; // Remove previous created polygon - - if (polygon) { - this._lineGroup.remove(polygon); - } - - polygon = new ECPolygon({ - shape: { - points: points, - stackedOnPoints: stackedOnPoints - }, - segmentIgnoreThreshold: 2 - }); - - this._lineGroup.add(polygon); - - this._polygon = polygon; - return polygon; - }; - - LineView.prototype._initSymbolLabelAnimation = function (data, coordSys, clipShape) { - var isHorizontalOrRadial; - var isCoordSysPolar; - var baseAxis = coordSys.getBaseAxis(); - var isAxisInverse = baseAxis.inverse; - - if (coordSys.type === 'cartesian2d') { - isHorizontalOrRadial = baseAxis.isHorizontal(); - isCoordSysPolar = false; - } else if (coordSys.type === 'polar') { - isHorizontalOrRadial = baseAxis.dim === 'angle'; - isCoordSysPolar = true; - } - - var seriesModel = data.hostModel; - var seriesDuration = seriesModel.get('animationDuration'); - - if (isFunction(seriesDuration)) { - seriesDuration = seriesDuration(null); - } - - var seriesDelay = seriesModel.get('animationDelay') || 0; - var seriesDelayValue = isFunction(seriesDelay) ? seriesDelay(null) : seriesDelay; - data.eachItemGraphicEl(function (symbol, idx) { - var el = symbol; - - if (el) { - var point = [symbol.x, symbol.y]; - var start = void 0; - var end = void 0; - var current = void 0; - - if (clipShape) { - if (isCoordSysPolar) { - var polarClip = clipShape; - var coord = coordSys.pointToCoord(point); - - if (isHorizontalOrRadial) { - start = polarClip.startAngle; - end = polarClip.endAngle; - current = -coord[1] / 180 * Math.PI; - } else { - start = polarClip.r0; - end = polarClip.r; - current = coord[0]; - } - } else { - var gridClip = clipShape; - - if (isHorizontalOrRadial) { - start = gridClip.x; - end = gridClip.x + gridClip.width; - current = symbol.x; - } else { - start = gridClip.y + gridClip.height; - end = gridClip.y; - current = symbol.y; - } - } - } - - var ratio = end === start ? 0 : (current - start) / (end - start); - - if (isAxisInverse) { - ratio = 1 - ratio; - } - - var delay = isFunction(seriesDelay) ? seriesDelay(idx) : seriesDuration * ratio + seriesDelayValue; - var symbolPath = el.getSymbolPath(); - var text = symbolPath.getTextContent(); - el.attr({ - scaleX: 0, - scaleY: 0 - }); - el.animateTo({ - scaleX: 1, - scaleY: 1 - }, { - duration: 200, - setToFinal: true, - delay: delay - }); - - if (text) { - text.animateFrom({ - style: { - opacity: 0 - } - }, { - duration: 300, - delay: delay - }); - } - - symbolPath.disableLabelAnimation = true; - } - }); - }; - - LineView.prototype._initOrUpdateEndLabel = function (seriesModel, coordSys, inheritColor) { - var endLabelModel = seriesModel.getModel('endLabel'); - - if (anyStateShowEndLabel(seriesModel)) { - var data_2 = seriesModel.getData(); - var polyline = this._polyline; // series may be filtered. - - var points = data_2.getLayout('points'); - - if (!points) { - polyline.removeTextContent(); - this._endLabel = null; - return; - } - - var endLabel = this._endLabel; - - if (!endLabel) { - endLabel = this._endLabel = new ZRText({ - z2: 200 // should be higher than item symbol - - }); - endLabel.ignoreClip = true; - polyline.setTextContent(this._endLabel); - polyline.disableLabelAnimation = true; - } // Find last non-NaN data to display data - - - var dataIndex = getLastIndexNotNull(points); - - if (dataIndex >= 0) { - setLabelStyle(polyline, getLabelStatesModels(seriesModel, 'endLabel'), { - inheritColor: inheritColor, - labelFetcher: seriesModel, - labelDataIndex: dataIndex, - defaultText: function (dataIndex, opt, interpolatedValue) { - return interpolatedValue != null ? getDefaultInterpolatedLabel(data_2, interpolatedValue) : getDefaultLabel(data_2, dataIndex); - }, - enableTextSetter: true - }, getEndLabelStateSpecified(endLabelModel, coordSys)); - polyline.textConfig.position = null; - } - } else if (this._endLabel) { - this._polyline.removeTextContent(); - - this._endLabel = null; - } - }; - - LineView.prototype._endLabelOnDuring = function (percent, clipRect, data, animationRecord, valueAnimation, endLabelModel, coordSys) { - var endLabel = this._endLabel; - var polyline = this._polyline; - - if (endLabel) { - // NOTE: Don't remove percent < 1. percent === 1 means the first frame during render. - // The label is not prepared at this time. - if (percent < 1 && animationRecord.originalX == null) { - animationRecord.originalX = endLabel.x; - animationRecord.originalY = endLabel.y; - } - - var points = data.getLayout('points'); - var seriesModel = data.hostModel; - var connectNulls = seriesModel.get('connectNulls'); - var precision = endLabelModel.get('precision'); - var distance = endLabelModel.get('distance') || 0; - var baseAxis = coordSys.getBaseAxis(); - var isHorizontal = baseAxis.isHorizontal(); - var isBaseInversed = baseAxis.inverse; - var clipShape = clipRect.shape; - var xOrY = isBaseInversed ? isHorizontal ? clipShape.x : clipShape.y + clipShape.height : isHorizontal ? clipShape.x + clipShape.width : clipShape.y; - var distanceX = (isHorizontal ? distance : 0) * (isBaseInversed ? -1 : 1); - var distanceY = (isHorizontal ? 0 : -distance) * (isBaseInversed ? -1 : 1); - var dim = isHorizontal ? 'x' : 'y'; - var dataIndexRange = getIndexRange(points, xOrY, dim); - var indices = dataIndexRange.range; - var diff = indices[1] - indices[0]; - var value = void 0; - - if (diff >= 1) { - // diff > 1 && connectNulls, which is on the null data. - if (diff > 1 && !connectNulls) { - var pt = getPointAtIndex(points, indices[0]); - endLabel.attr({ - x: pt[0] + distanceX, - y: pt[1] + distanceY - }); - valueAnimation && (value = seriesModel.getRawValue(indices[0])); - } else { - var pt = polyline.getPointOn(xOrY, dim); - pt && endLabel.attr({ - x: pt[0] + distanceX, - y: pt[1] + distanceY - }); - var startValue = seriesModel.getRawValue(indices[0]); - var endValue = seriesModel.getRawValue(indices[1]); - valueAnimation && (value = interpolateRawValues(data, precision, startValue, endValue, dataIndexRange.t)); - } - - animationRecord.lastFrameIndex = indices[0]; - } else { - // If diff <= 0, which is the range is not found(Include NaN) - // Choose the first point or last point. - var idx = percent === 1 || animationRecord.lastFrameIndex > 0 ? indices[0] : 0; - var pt = getPointAtIndex(points, idx); - valueAnimation && (value = seriesModel.getRawValue(idx)); - endLabel.attr({ - x: pt[0] + distanceX, - y: pt[1] + distanceY - }); - } - - if (valueAnimation) { - var inner = labelInner(endLabel); - - if (typeof inner.setLabelText === 'function') { - inner.setLabelText(value); - } - } - } - }; - /** - * @private - */ - // FIXME Two value axis - - - LineView.prototype._doUpdateAnimation = function (data, stackedOnPoints, coordSys, api, step, valueOrigin, connectNulls) { - var polyline = this._polyline; - var polygon = this._polygon; - var seriesModel = data.hostModel; - var diff = lineAnimationDiff(this._data, data, this._stackedOnPoints, stackedOnPoints, this._coordSys, coordSys, this._valueOrigin); - var current = diff.current; - var stackedOnCurrent = diff.stackedOnCurrent; - var next = diff.next; - var stackedOnNext = diff.stackedOnNext; - - if (step) { - // TODO If stacked series is not step - stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, diff.current, coordSys, step, connectNulls); - current = turnPointsIntoStep(diff.current, null, coordSys, step, connectNulls); - stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, diff.next, coordSys, step, connectNulls); - next = turnPointsIntoStep(diff.next, null, coordSys, step, connectNulls); - } // Don't apply animation if diff is large. - // For better result and avoid memory explosion problems like - // https://github.com/apache/incubator-echarts/issues/12229 - - - if (getBoundingDiff(current, next) > 3000 || polygon && getBoundingDiff(stackedOnCurrent, stackedOnNext) > 3000) { - polyline.stopAnimation(); - polyline.setShape({ - points: next - }); - - if (polygon) { - polygon.stopAnimation(); - polygon.setShape({ - points: next, - stackedOnPoints: stackedOnNext - }); - } - - return; - } - - polyline.shape.__points = diff.current; - polyline.shape.points = current; - var target = { - shape: { - points: next - } - }; // Also animate the original points. - // If points reference is changed when turning into step line. - - if (diff.current !== current) { - target.shape.__points = diff.next; - } // Stop previous animation. - - - polyline.stopAnimation(); - updateProps$1(polyline, target, seriesModel); - - if (polygon) { - polygon.setShape({ - // Reuse the points with polyline. - points: current, - stackedOnPoints: stackedOnCurrent - }); - polygon.stopAnimation(); - updateProps$1(polygon, { - shape: { - stackedOnPoints: stackedOnNext - } - }, seriesModel); // If use attr directly in updateProps. - - if (polyline.shape.points !== polygon.shape.points) { - polygon.shape.points = polyline.shape.points; - } - } - - var updatedDataInfo = []; - var diffStatus = diff.status; - - for (var i = 0; i < diffStatus.length; i++) { - var cmd = diffStatus[i].cmd; - - if (cmd === '=') { - var el = data.getItemGraphicEl(diffStatus[i].idx1); - - if (el) { - updatedDataInfo.push({ - el: el, - ptIdx: i // Index of points - - }); - } - } - } - - if (polyline.animators && polyline.animators.length) { - polyline.animators[0].during(function () { - polygon && polygon.dirtyShape(); - var points = polyline.shape.__points; - - for (var i = 0; i < updatedDataInfo.length; i++) { - var el = updatedDataInfo[i].el; - var offset = updatedDataInfo[i].ptIdx * 2; - el.x = points[offset]; - el.y = points[offset + 1]; - el.markRedraw(); - } - }); - } - }; - - LineView.prototype.remove = function (ecModel) { - var group = this.group; - var oldData = this._data; - - this._lineGroup.removeAll(); - - this._symbolDraw.remove(true); // Remove temporary created elements when highlighting - - - oldData && oldData.eachItemGraphicEl(function (el, idx) { - if (el.__temp) { - group.remove(el); - oldData.setItemGraphicEl(idx, null); - } - }); - this._polyline = this._polygon = this._coordSys = this._points = this._stackedOnPoints = this._endLabel = this._data = null; - }; - - LineView.type = 'line'; - return LineView; - }(ChartView); - - function pointsLayout(seriesType, forceStoreInTypedArray) { - return { - seriesType: seriesType, - plan: createRenderPlanner(), - reset: function (seriesModel) { - var data = seriesModel.getData(); - var coordSys = seriesModel.coordinateSystem; - var pipelineContext = seriesModel.pipelineContext; - var useTypedArray = forceStoreInTypedArray || pipelineContext.large; - - if (!coordSys) { - return; - } - - var dims = map$1(coordSys.dimensions, function (dim) { - return data.mapDimension(dim); - }).slice(0, 2); - var dimLen = dims.length; - var stackResultDim = data.getCalculationInfo('stackResultDimension'); - - if (isDimensionStacked(data, dims[0])) { - dims[0] = stackResultDim; - } - - if (isDimensionStacked(data, dims[1])) { - dims[1] = stackResultDim; - } - - var store = data.getStore(); - var dimIdx0 = data.getDimensionIndex(dims[0]); - var dimIdx1 = data.getDimensionIndex(dims[1]); - return dimLen && { - progress: function (params, data) { - var segCount = params.end - params.start; - var points = useTypedArray && createFloat32Array(segCount * dimLen); - var tmpIn = []; - var tmpOut = []; - - for (var i = params.start, offset = 0; i < params.end; i++) { - var point = void 0; - - if (dimLen === 1) { - var x = store.get(dimIdx0, i); // NOTE: Make sure the second parameter is null to use default strategy. - - point = coordSys.dataToPoint(x, null, tmpOut); - } else { - tmpIn[0] = store.get(dimIdx0, i); - tmpIn[1] = store.get(dimIdx1, i); // Let coordinate system to handle the NaN data. - - point = coordSys.dataToPoint(tmpIn, null, tmpOut); - } - - if (useTypedArray) { - points[offset++] = point[0]; - points[offset++] = point[1]; - } else { - data.setItemLayout(i, point.slice()); - } - } - - useTypedArray && data.setLayout('points', points); - } - }; - } - }; - } - - function install$8(registers) { - registers.registerChartView(LineView); - registers.registerSeriesModel(LineSeriesModel); - registers.registerLayout(pointsLayout('line', true)); - registers.registerVisual({ - seriesType: 'line', - reset: function (seriesModel) { - var data = seriesModel.getData(); // Visual coding for legend - - var lineStyle = seriesModel.getModel('lineStyle').getLineStyle(); - - if (lineStyle && !lineStyle.stroke) { - // Fill in visual should be palette color if - // has color callback - lineStyle.stroke = data.getVisual('style').fill; - } - - data.setVisual('legendLineStyle', lineStyle); - } - }); // Down sample after filter - - registers.registerProcessor(registers.PRIORITY.PROCESSOR.STATISTIC, dataSample('line')); - } - - use(install$8); // For backward compatibility, do not use a margin. Although the labels might touch the edge of - // the canvas, the chart canvas probably does not have an border or a different background color within a page. - - var OUTER_BOUNDS_DEFAULT = { - left: 0, - right: 0, - top: 0, - bottom: 0 - }; - var OUTER_BOUNDS_CLAMP_DEFAULT = ['25%', '25%']; - - var GridModel = - /** @class */ - function (_super) { - __extends(GridModel, _super); - - function GridModel() { - return _super !== null && _super.apply(this, arguments) || this; - } - - GridModel.prototype.mergeDefaultAndTheme = function (option, ecModel) { - var outerBoundsCp = getLayoutParams(option.outerBounds); - - _super.prototype.mergeDefaultAndTheme.apply(this, arguments); - - if (outerBoundsCp && option.outerBounds) { - mergeLayoutParam(option.outerBounds, outerBoundsCp); - } - }; - - GridModel.prototype.mergeOption = function (newOption, ecModel) { - _super.prototype.mergeOption.apply(this, arguments); - - if (this.option.outerBounds && newOption.outerBounds) { - mergeLayoutParam(this.option.outerBounds, newOption.outerBounds); - } - }; - - GridModel.type = 'grid'; - GridModel.dependencies = ['xAxis', 'yAxis']; - GridModel.layoutMode = 'box'; - GridModel.defaultOption = { - show: false, - // zlevel: 0, - z: 0, - left: '15%', - top: 65, - right: '10%', - bottom: 80, - // If grid size contain label - containLabel: false, - outerBoundsMode: 'auto', - outerBounds: OUTER_BOUNDS_DEFAULT, - outerBoundsContain: 'all', - outerBoundsClampWidth: OUTER_BOUNDS_CLAMP_DEFAULT[0], - outerBoundsClampHeight: OUTER_BOUNDS_CLAMP_DEFAULT[1], - // width: {totalWidth} - left - right, - // height: {totalHeight} - top - bottom, - backgroundColor: tokens.color.transparent, - borderWidth: 1, - borderColor: tokens.color.neutral30 - }; - return GridModel; - }(ComponentModel); - - var CartesianAxisModel = - /** @class */ - function (_super) { - __extends(CartesianAxisModel, _super); - - function CartesianAxisModel() { - return _super !== null && _super.apply(this, arguments) || this; - } - - CartesianAxisModel.prototype.getCoordSysModel = function () { - return this.getReferringComponents('grid', SINGLE_REFERRING).models[0]; - }; - - CartesianAxisModel.type = 'cartesian2dAxis'; - return CartesianAxisModel; - }(ComponentModel); - - mixin(CartesianAxisModel, AxisModelCommonMixin); - var defaultOption = { - show: true, - // zlevel: 0, - z: 0, - // Inverse the axis. - inverse: false, - // Axis name displayed. - name: '', - // 'start' | 'middle' | 'end' - nameLocation: 'end', - // By degree. By default auto rotate by nameLocation. - nameRotate: null, - nameTruncate: { - maxWidth: null, - ellipsis: '...', - placeholder: '.' - }, - // Use global text style by default. - nameTextStyle: {// textMargin: never, // The default value will be specified based on `nameLocation`. - }, - // The gap between axisName and axisLine. - nameGap: 15, - // Default `false` to support tooltip. - silent: false, - // Default `false` to avoid legacy user event listener fail. - triggerEvent: false, - tooltip: { - show: false - }, - axisPointer: {}, - axisLine: { - show: true, - onZero: true, - onZeroAxisIndex: null, - lineStyle: { - color: tokens.color.axisLine, - width: 1, - type: 'solid' - }, - // The arrow at both ends the the axis. - symbol: ['none', 'none'], - symbolSize: [10, 15], - breakLine: true - }, - axisTick: { - show: true, - // Whether axisTick is inside the grid or outside the grid. - inside: false, - // The length of axisTick. - length: 5, - lineStyle: { - width: 1 - } - }, - axisLabel: { - show: true, - // Whether axisLabel is inside the grid or outside the grid. - inside: false, - rotate: 0, - // true | false | null/undefined (auto) - showMinLabel: null, - // true | false | null/undefined (auto) - showMaxLabel: null, - margin: 8, - // formatter: null, - fontSize: 12, - color: tokens.color.axisLabel, - // In scenarios like axis labels, when labels text's progression direction matches the label - // layout direction (e.g., when all letters are in a single line), extra start/end margin is - // needed to prevent the text from appearing visually joined. In the other case, when lables - // are stacked (e.g., having rotation or horizontal labels on yAxis), the layout needs to be - // compact, so NO extra top/bottom margin should be applied. - textMargin: [0, 3] - }, - splitLine: { - show: true, - showMinLine: true, - showMaxLine: true, - lineStyle: { - color: tokens.color.axisSplitLine, - width: 1, - type: 'solid' - } - }, - splitArea: { - show: false, - areaStyle: { - color: [tokens.color.backgroundTint, tokens.color.backgroundTransparent] - } - }, - breakArea: { - show: true, - itemStyle: { - color: tokens.color.neutral00, - // Break border color should be darker than the splitLine - // because it has opacity and should be more prominent - borderColor: tokens.color.border, - borderWidth: 1, - borderType: [3, 3], - opacity: 0.6 - }, - zigzagAmplitude: 4, - zigzagMinSpan: 4, - zigzagMaxSpan: 20, - zigzagZ: 100, - expandOnClick: true - }, - breakLabelLayout: { - moveOverlap: 'auto' - } - }; - var categoryAxis = merge({ - // The gap at both ends of the axis. For categoryAxis, boolean. - boundaryGap: true, - // Set false to faster category collection. - deduplication: null, - jitter: 0, - jitterOverlap: true, - jitterMargin: 2, - // splitArea: { - // show: false - // }, - splitLine: { - show: false - }, - axisTick: { - // If tick is align with label when boundaryGap is true - alignWithLabel: false, - interval: 'auto', - show: 'auto' - }, - axisLabel: { - interval: 'auto' - } - }, defaultOption); - var valueAxis = merge({ - boundaryGap: [0, 0], - axisLine: { - // Not shown when other axis is categoryAxis in cartesian - show: 'auto' - }, - axisTick: { - // Not shown when other axis is categoryAxis in cartesian - show: 'auto' - }, - // TODO - // min/max: [30, datamin, 60] or [20, datamin] or [datamin, 60] - splitNumber: 5, - minorTick: { - // Minor tick, not available for cateogry axis. - show: false, - // Split number of minor ticks. The value should be in range of (0, 100) - splitNumber: 5, - // Length of minor tick - length: 3, - // Line style - lineStyle: {// Default to be same with axisTick - } - }, - minorSplitLine: { - show: false, - lineStyle: { - color: tokens.color.axisMinorSplitLine, - width: 1 - } - } - }, defaultOption); - var timeAxis = merge({ - splitNumber: 6, - axisLabel: { - // To eliminate labels that are not nice - showMinLabel: false, - showMaxLabel: false, - rich: { - primary: { - fontWeight: 'bold' - } - } - }, - splitLine: { - show: false - } - }, valueAxis); - var logAxis = defaults({ - logBase: 10 - }, valueAxis); - var axisDefault = { - category: categoryAxis, - value: valueAxis, - time: timeAxis, - log: logAxis - }; - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * AUTO-GENERATED FILE. DO NOT MODIFY. - */ - - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - var AXIS_TYPES = { - value: 1, - category: 1, - time: 1, - log: 1 - }; - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * AUTO-GENERATED FILE. DO NOT MODIFY. - */ - - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - var _impl = null; - - function getAxisBreakHelper() { - return _impl; - } - /** - * Generate sub axis model class - * @param axisName 'x' 'y' 'radius' 'angle' 'parallel' ... - */ - - - function axisModelCreator(registers, axisName, BaseAxisModelClass, extraDefaultOption) { - each$4(AXIS_TYPES, function (v, axisType) { - var defaultOption = merge(merge({}, axisDefault[axisType], true), extraDefaultOption, true); - - var AxisModel = - /** @class */ - function (_super) { - __extends(AxisModel, _super); - - function AxisModel() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = axisName + 'Axis.' + axisType; - return _this; - } - - AxisModel.prototype.mergeDefaultAndTheme = function (option, ecModel) { - var layoutMode = fetchLayoutMode(this); - var inputPositionParams = layoutMode ? getLayoutParams(option) : {}; - var themeModel = ecModel.getTheme(); - merge(option, themeModel.get(axisType + 'Axis')); - merge(option, this.getDefaultOption()); - option.type = getAxisType(option); - - if (layoutMode) { - mergeLayoutParam(option, inputPositionParams, layoutMode); - } - }; - - AxisModel.prototype.optionUpdated = function () { - var thisOption = this.option; - - if (thisOption.type === 'category') { - this.__ordinalMeta = OrdinalMeta.createByAxisModel(this); - } - }; - /** - * Should not be called before all of 'getInitailData' finished. - * Because categories are collected during initializing data. - */ - - - AxisModel.prototype.getCategories = function (rawData) { - var option = this.option; // FIXME - // warning if called before all of 'getInitailData' finished. - - if (option.type === 'category') { - if (rawData) { - return option.data; - } - - return this.__ordinalMeta.categories; - } - }; - - AxisModel.prototype.getOrdinalMeta = function () { - return this.__ordinalMeta; - }; - - AxisModel.prototype.updateAxisBreaks = function (payload) { - var axisBreakHelper = getAxisBreakHelper(); - return axisBreakHelper ? axisBreakHelper.updateModelAxisBreak(this, payload) : { - breaks: [] - }; - }; - - AxisModel.type = axisName + 'Axis.' + axisType; - AxisModel.defaultOption = defaultOption; - return AxisModel; - }(BaseAxisModelClass); - - registers.registerComponentModel(AxisModel); - }); - registers.registerSubTypeDefaulter(axisName + 'Axis', getAxisType); - } - - function getAxisType(option) { - // Default axis with data is category axis - return option.type || (option.data ? 'category' : 'value'); - } - - var Cartesian = - /** @class */ - function () { - function Cartesian(name) { - this.type = 'cartesian'; - this._dimList = []; - this._axes = {}; - this.name = name || ''; - } - - Cartesian.prototype.getAxis = function (dim) { - return this._axes[dim]; - }; - - Cartesian.prototype.getAxes = function () { - return map$1(this._dimList, function (dim) { - return this._axes[dim]; - }, this); - }; - - Cartesian.prototype.getAxesByScale = function (scaleType) { - scaleType = scaleType.toLowerCase(); - return filter(this.getAxes(), function (axis) { - return axis.scale.type === scaleType; - }); - }; - - Cartesian.prototype.addAxis = function (axis) { - var dim = axis.dim; - this._axes[dim] = axis; - - this._dimList.push(dim); - }; - - return Cartesian; - }(); - - var cartesian2DDimensions = ['x', 'y']; - - function canCalculateAffineTransform(scale) { - return (scale.type === 'interval' || scale.type === 'time') && !scale.hasBreaks(); - } - - var Cartesian2D = - /** @class */ - function (_super) { - __extends(Cartesian2D, _super); - - function Cartesian2D() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = 'cartesian2d'; - _this.dimensions = cartesian2DDimensions; - return _this; - } - /** - * Calculate an affine transform matrix if two axes are time or value. - * It's mainly for accelartion on the large time series data. - */ - - - Cartesian2D.prototype.calcAffineTransform = function () { - this._transform = this._invTransform = null; - var xAxisScale = this.getAxis('x').scale; - var yAxisScale = this.getAxis('y').scale; - - if (!canCalculateAffineTransform(xAxisScale) || !canCalculateAffineTransform(yAxisScale)) { - return; - } - - var xScaleExtent = xAxisScale.getExtent(); - var yScaleExtent = yAxisScale.getExtent(); - var start = this.dataToPoint([xScaleExtent[0], yScaleExtent[0]]); - var end = this.dataToPoint([xScaleExtent[1], yScaleExtent[1]]); - var xScaleSpan = xScaleExtent[1] - xScaleExtent[0]; - var yScaleSpan = yScaleExtent[1] - yScaleExtent[0]; - - if (!xScaleSpan || !yScaleSpan) { - return; - } // Accelerate data to point calculation on the special large time series data. - - - var scaleX = (end[0] - start[0]) / xScaleSpan; - var scaleY = (end[1] - start[1]) / yScaleSpan; - var translateX = start[0] - xScaleExtent[0] * scaleX; - var translateY = start[1] - yScaleExtent[0] * scaleY; - var m = this._transform = [scaleX, 0, 0, scaleY, translateX, translateY]; - this._invTransform = invert([], m); - }; - /** - * Base axis will be used on stacking. - */ - - - Cartesian2D.prototype.getBaseAxis = function () { - return this.getAxesByScale('ordinal')[0] || this.getAxesByScale('time')[0] || this.getAxis('x'); - }; - - Cartesian2D.prototype.containPoint = function (point) { - var axisX = this.getAxis('x'); - var axisY = this.getAxis('y'); - return axisX.contain(axisX.toLocalCoord(point[0])) && axisY.contain(axisY.toLocalCoord(point[1])); - }; - - Cartesian2D.prototype.containData = function (data) { - return this.getAxis('x').containData(data[0]) && this.getAxis('y').containData(data[1]); - }; - - Cartesian2D.prototype.containZone = function (data1, data2) { - var zoneDiag1 = this.dataToPoint(data1); - var zoneDiag2 = this.dataToPoint(data2); - var area = this.getArea(); - var zone = new BoundingRect(zoneDiag1[0], zoneDiag1[1], zoneDiag2[0] - zoneDiag1[0], zoneDiag2[1] - zoneDiag1[1]); - return area.intersect(zone); - }; - - Cartesian2D.prototype.dataToPoint = function (data, clamp, out) { - out = out || []; - var xVal = data[0]; - var yVal = data[1]; // [CAVEAT]: Do not add time consuming operation within and before fast path. - // Fast path. - - if (this._transform // It's supported that if data is like `[Inifity, 123]`, where only Y pixel calculated. - && xVal != null && isFinite(xVal) && yVal != null && isFinite(yVal)) { - return applyTransform$1(out, data, this._transform); - } - - var xAxis = this.getAxis('x'); - var yAxis = this.getAxis('y'); - out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(xVal, clamp)); - out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(yVal, clamp)); - return out; - }; - - Cartesian2D.prototype.clampData = function (data, out) { - var xScale = this.getAxis('x').scale; - var yScale = this.getAxis('y').scale; - var xAxisExtent = xScale.getExtent(); - var yAxisExtent = yScale.getExtent(); - var x = xScale.parse(data[0]); - var y = yScale.parse(data[1]); - out = out || []; - out[0] = Math.min(Math.max(Math.min(xAxisExtent[0], xAxisExtent[1]), x), Math.max(xAxisExtent[0], xAxisExtent[1])); - out[1] = Math.min(Math.max(Math.min(yAxisExtent[0], yAxisExtent[1]), y), Math.max(yAxisExtent[0], yAxisExtent[1])); - return out; - }; - - Cartesian2D.prototype.pointToData = function (point, clamp, out) { - out = out || []; - - if (this._invTransform) { - return applyTransform$1(out, point, this._invTransform); - } - - var xAxis = this.getAxis('x'); - var yAxis = this.getAxis('y'); - out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0]), clamp); - out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1]), clamp); - return out; - }; - - Cartesian2D.prototype.getOtherAxis = function (axis) { - return this.getAxis(axis.dim === 'x' ? 'y' : 'x'); - }; - /** - * Get rect area of cartesian. - * Area will have a contain function to determine if a point is in the coordinate system. - */ - - - Cartesian2D.prototype.getArea = function (tolerance) { - tolerance = tolerance || 0; - var xExtent = this.getAxis('x').getGlobalExtent(); - var yExtent = this.getAxis('y').getGlobalExtent(); - var x = Math.min(xExtent[0], xExtent[1]) - tolerance; - var y = Math.min(yExtent[0], yExtent[1]) - tolerance; - var width = Math.max(xExtent[0], xExtent[1]) - x + tolerance; - var height = Math.max(yExtent[0], yExtent[1]) - y + tolerance; - return new BoundingRect(x, y, width, height); - }; - - return Cartesian2D; - }(Cartesian); - - var Axis2D = - /** @class */ - function (_super) { - __extends(Axis2D, _super); - - function Axis2D(dim, scale, coordExtent, axisType, position) { - var _this = _super.call(this, dim, scale, coordExtent) || this; - /** - * Index of axis, can be used as key - * Injected outside. - */ - - - _this.index = 0; - _this.type = axisType || 'value'; - _this.position = position || 'bottom'; - return _this; - } - - Axis2D.prototype.isHorizontal = function () { - var position = this.position; - return position === 'top' || position === 'bottom'; - }; - /** - * Each item cooresponds to this.getExtent(), which - * means globalExtent[0] may greater than globalExtent[1], - * unless `asc` is input. - * - * @param {boolean} [asc] - * @return {Array.} - */ - - - Axis2D.prototype.getGlobalExtent = function (asc) { - var ret = this.getExtent(); - ret[0] = this.toGlobalCoord(ret[0]); - ret[1] = this.toGlobalCoord(ret[1]); - asc && ret[0] > ret[1] && ret.reverse(); - return ret; - }; - - Axis2D.prototype.pointToData = function (point, clamp) { - return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp); - }; - /** - * Set ordinalSortInfo - * @param info new OrdinalSortInfo - */ - - - Axis2D.prototype.setCategorySortInfo = function (info) { - if (this.type !== 'category') { - return false; - } - - this.model.option.categorySortInfo = info; - this.scale.setSortInfo(info); - }; - - return Axis2D; - }(Axis); - - var AXIS_BREAK_EXPAND_ACTION_TYPE = 'expandAxisBreak'; - var PI = Math.PI; - var DEFAULT_CENTER_NAME_MARGIN_LEVELS = [[1, 2, 1, 2], [5, 3, 5, 3], [8, 3, 8, 3]]; - var DEFAULT_ENDS_NAME_MARGIN_LEVELS = [[0, 1, 0, 1], [0, 3, 0, 3], [0, 3, 0, 3]]; - var getLabelInner = makeInner(); - var getTickInner = makeInner(); - /** - * A context shared by difference axisBuilder instances. - * For cross-axes overlap resolving. - * - * Lifecycle constraint: should not over a pass of ec main process. - * If model is changed, the context must be disposed. - * - * @see AxisBuilderLocalContext - */ - - var AxisBuilderSharedContext = - /** @class */ - function () { - function AxisBuilderSharedContext(resolveAxisNameOverlap) { - /** - * [CAUTION] Do not modify this data structure outside this class. - */ - this.recordMap = {}; - this.resolveAxisNameOverlap = resolveAxisNameOverlap; - } - - AxisBuilderSharedContext.prototype.ensureRecord = function (axisModel) { - var dim = axisModel.axis.dim; - var idx = axisModel.componentIndex; - var recordMap = this.recordMap; - var records = recordMap[dim] || (recordMap[dim] = []); - return records[idx] || (records[idx] = { - ready: {} - }); - }; - - return AxisBuilderSharedContext; - }(); - /** - * [CAUTION] - * 1. The call of this function must be after axisLabel overlap handlings - * (such as `hideOverlap`, `fixMinMaxLabelShow`) and after transform calculating. - * 2. Can be called multiple times and should be idempotent. - */ - - - function resetOverlapRecordToShared(cfg, shared, axisModel, labelLayoutList) { - var axis = axisModel.axis; - var record = shared.ensureRecord(axisModel); - var labelInfoList = []; - var stOccupiedRect; - var useStOccupiedRect = hasAxisName(cfg.axisName) && isNameLocationCenter(cfg.nameLocation); - each$4(labelLayoutList, function (layout) { - var layoutInfo = ensureLabelLayoutWithGeometry(layout); - - if (!layoutInfo || layoutInfo.label.ignore) { - return; - } - - labelInfoList.push(layoutInfo); - var transGroup = record.transGroup; - - if (useStOccupiedRect) { - // Transform to "standard axis" for creating stOccupiedRect (the label rects union). - transGroup.transform ? invert(_stTransTmp, transGroup.transform) : identity(_stTransTmp); - - if (layoutInfo.transform) { - mul(_stTransTmp, _stTransTmp, layoutInfo.transform); - } - - BoundingRect.copy(_stLabelRectTmp, layoutInfo.localRect); - - _stLabelRectTmp.applyTransform(_stTransTmp); - - stOccupiedRect ? stOccupiedRect.union(_stLabelRectTmp) : BoundingRect.copy(stOccupiedRect = new BoundingRect(0, 0, 0, 0), _stLabelRectTmp); - } - }); - var sortByDim = Math.abs(record.dirVec.x) > 0.1 ? 'x' : 'y'; - var sortByValue = record.transGroup[sortByDim]; - labelInfoList.sort(function (info1, info2) { - return Math.abs(info1.label[sortByDim] - sortByValue) - Math.abs(info2.label[sortByDim] - sortByValue); - }); - - if (useStOccupiedRect && stOccupiedRect) { - var extent = axis.getExtent(); - var axisLineX = Math.min(extent[0], extent[1]); - var axisLineWidth = Math.max(extent[0], extent[1]) - axisLineX; // If `nameLocation` is 'middle', enlarge axis labels boundingRect to axisLine to avoid bad - // case like that axis name is placed in the gap between axis labels and axis line. - // If only one label exists, the entire band should be occupied for - // visual consistency, so extent it to [0, canvas width]. - - stOccupiedRect.union(new BoundingRect(axisLineX, 0, axisLineWidth, 1)); - } - - record.stOccupiedRect = stOccupiedRect; - record.labelInfoList = labelInfoList; - } - - var _stTransTmp = create(); - - var _stLabelRectTmp = new BoundingRect(0, 0, 0, 0); - /** - * The default resolver does not involve other axes within the same coordinate system. - */ - - - var resolveAxisNameOverlapDefault = function (cfg, ctx, axisModel, nameLayoutInfo, nameMoveDirVec, thisRecord) { - if (isNameLocationCenter(cfg.nameLocation)) { - var stOccupiedRect = thisRecord.stOccupiedRect; - - if (stOccupiedRect) { - moveIfOverlap(computeLabelGeometry2({}, stOccupiedRect, thisRecord.transGroup.transform), nameLayoutInfo, nameMoveDirVec); - } - } else { - moveIfOverlapByLinearLabels(thisRecord.labelInfoList, thisRecord.dirVec, nameLayoutInfo, nameMoveDirVec); - } - }; // [NOTICE] not consider ignore. - - - function moveIfOverlap(basedLayoutInfo, movableLayoutInfo, moveDirVec) { - var mtv = new Point(); - - if (labelIntersect(basedLayoutInfo, movableLayoutInfo, mtv, { - direction: Math.atan2(moveDirVec.y, moveDirVec.x), - bidirectional: false, - touchThreshold: 0.05 - })) { - labelLayoutApplyTranslation(movableLayoutInfo, mtv); - } - } - - function moveIfOverlapByLinearLabels(baseLayoutInfoList, baseDirVec, movableLayoutInfo, moveDirVec) { - // Detect and move from far to close. - var sameDir = Point.dot(moveDirVec, baseDirVec) >= 0; - - for (var idx = 0, len = baseLayoutInfoList.length; idx < len; idx++) { - var labelInfo = baseLayoutInfoList[sameDir ? idx : len - 1 - idx]; - - if (!labelInfo.label.ignore) { - moveIfOverlap(labelInfo, movableLayoutInfo, moveDirVec); - } - } - } - /** - * @caution - * - Ensure it is called after the data processing stage finished. - * - It might be called before `CahrtView#render`, sush as called at `CoordinateSystem#update`, - * thus ensure the result the same whenever it is called. - * - * A builder for a straight-line axis. - * - * A final axis is translated and rotated from a "standard axis". - * So opt.position and opt.rotation is required. - * - * A "standard axis" is the axis [0,0]-->[abs(axisExtent[1]-axisExtent[0]),0] - * for example: [0,0]-->[50,0] - */ - - - var AxisBuilder = - /** @class */ - function () { - /** - * [CAUTION]: axisModel.axis.extent/scale must be ready to use. - */ - function AxisBuilder(axisModel, api, opt, shared) { - this.group = new Group$2(); - this._axisModel = axisModel; - this._api = api; - this._local = {}; - this._shared = shared || new AxisBuilderSharedContext(resolveAxisNameOverlapDefault); - - this._resetCfgDetermined(opt); - } - /** - * Regarding axis label related configurations, only the change of label.x/y is supported; other - * changes are not necessary and not performant. To be specific, only `axis.position` - * (and consequently `labelOffset`) and `axis.extent` can be changed, and assume everything in - * `axisModel` are not changed. - * Axis line related configurations can be changed since this method can only be called - * before they are created. - */ - - - AxisBuilder.prototype.updateCfg = function (opt) { - { - var ready = this._shared.ensureRecord(this._axisModel).ready; // After that, changing cfg is not supported; avoid unnecessary complexity. - - - assert(!ready.axisLine && !ready.axisTickLabelDetermine); // Have to be called again if cfg changed. - - ready.axisName = ready.axisTickLabelEstimate = false; - } - var raw = this._cfg.raw; - raw.position = opt.position; - raw.labelOffset = opt.labelOffset; - - this._resetCfgDetermined(raw); - }; - /** - * [CAUTION] For debug usage. Never change it outside! - */ - - - AxisBuilder.prototype.__getRawCfg = function () { - return this._cfg.raw; - }; - - AxisBuilder.prototype._resetCfgDetermined = function (raw) { - var axisModel = this._axisModel; // FIXME: - // Currently there is no uniformed way to set default values if an option - // is specified null/undefined by user (intentionally or unintentionally), - // e.g. null/undefined is not a illegal value for `nameLocation`. - // Try to use `getDefaultOption` to address it. But radar has no `getDefaultOption`. - - var axisModelDefaultOption = axisModel.getDefaultOption ? axisModel.getDefaultOption() : {}; // Default value - - var axisName = retrieve2(raw.axisName, axisModel.get('name')); - var nameMoveOverlapOption = axisModel.get('nameMoveOverlap'); - - if (nameMoveOverlapOption == null || nameMoveOverlapOption === 'auto') { - nameMoveOverlapOption = retrieve2(raw.defaultNameMoveOverlap, true); - } - - var cfg = { - raw: raw, - position: raw.position, - rotation: raw.rotation, - nameDirection: retrieve2(raw.nameDirection, 1), - tickDirection: retrieve2(raw.tickDirection, 1), - labelDirection: retrieve2(raw.labelDirection, 1), - labelOffset: retrieve2(raw.labelOffset, 0), - silent: retrieve2(raw.silent, true), - axisName: axisName, - nameLocation: retrieve3(axisModel.get('nameLocation'), axisModelDefaultOption.nameLocation, 'end'), - shouldNameMoveOverlap: hasAxisName(axisName) && nameMoveOverlapOption, - optionHideOverlap: axisModel.get(['axisLabel', 'hideOverlap']), - showMinorTicks: axisModel.get(['minorTick', 'show']) - }; - { - assert(cfg.position != null); - assert(cfg.rotation != null); - } - this._cfg = cfg; // FIXME Not use a separate text group? - - var transformGroup = new Group$2({ - x: cfg.position[0], - y: cfg.position[1], - rotation: cfg.rotation - }); - transformGroup.updateTransform(); - this._transformGroup = transformGroup; - - var record = this._shared.ensureRecord(axisModel); - - record.transGroup = this._transformGroup; - record.dirVec = new Point(Math.cos(-cfg.rotation), Math.sin(-cfg.rotation)); - }; - - AxisBuilder.prototype.build = function (axisPartNameMap, extraParams) { - var _this = this; - - if (!axisPartNameMap) { - axisPartNameMap = { - axisLine: true, - axisTickLabelEstimate: false, - axisTickLabelDetermine: true, - axisName: true - }; - } - - each$4(AXIS_BUILDER_AXIS_PART_NAMES, function (partName) { - if (axisPartNameMap[partName]) { - builders[partName](_this._cfg, _this._local, _this._shared, _this._axisModel, _this.group, _this._transformGroup, _this._api, extraParams || {}); - } - }); - return this; - }; - /** - * Currently only get text align/verticalAlign by rotation. - * NO `position` is involved, otherwise it have to be performed for each `updateAxisLabelChangableProps`. - */ - - - AxisBuilder.innerTextLayout = function (axisRotation, textRotation, direction) { - var rotationDiff = remRadian(textRotation - axisRotation); - var textAlign; - var textVerticalAlign; - - if (isRadianAroundZero(rotationDiff)) { - // Label is parallel with axis line. - textVerticalAlign = direction > 0 ? 'top' : 'bottom'; - textAlign = 'center'; - } else if (isRadianAroundZero(rotationDiff - PI)) { - // Label is inverse parallel with axis line. - textVerticalAlign = direction > 0 ? 'bottom' : 'top'; - textAlign = 'center'; - } else { - textVerticalAlign = 'middle'; - - if (rotationDiff > 0 && rotationDiff < PI) { - textAlign = direction > 0 ? 'right' : 'left'; - } else { - textAlign = direction > 0 ? 'left' : 'right'; - } - } - - return { - rotation: rotationDiff, - textAlign: textAlign, - textVerticalAlign: textVerticalAlign - }; - }; - - AxisBuilder.makeAxisEventDataBase = function (axisModel) { - var eventData = { - componentType: axisModel.mainType, - componentIndex: axisModel.componentIndex - }; - eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex; - return eventData; - }; - - AxisBuilder.isLabelSilent = function (axisModel) { - var tooltipOpt = axisModel.get('tooltip'); - return axisModel.get('silent') // Consider mouse cursor, add these restrictions. - || !(axisModel.get('triggerEvent') || tooltipOpt && tooltipOpt.show); - }; - - return AxisBuilder; - }(); // Sorted by dependency order. - - - var AXIS_BUILDER_AXIS_PART_NAMES = ['axisLine', 'axisTickLabelEstimate', 'axisTickLabelDetermine', 'axisName']; - var builders = { - axisLine: function (cfg, local, shared, axisModel, group, transformGroup, api) { - { - var ready = shared.ensureRecord(axisModel).ready; - assert(!ready.axisLine); - ready.axisLine = true; - } - var shown = axisModel.get(['axisLine', 'show']); - - if (shown === 'auto') { - shown = true; - - if (cfg.raw.axisLineAutoShow != null) { - shown = !!cfg.raw.axisLineAutoShow; - } - } - - if (!shown) { - return; - } - - var extent = axisModel.axis.getExtent(); - var matrix = transformGroup.transform; - var pt1 = [extent[0], 0]; - var pt2 = [extent[1], 0]; - var inverse = pt1[0] > pt2[0]; - - if (matrix) { - applyTransform$1(pt1, pt1, matrix); - applyTransform$1(pt2, pt2, matrix); - } - - var lineStyle = extend({ - lineCap: 'round' - }, axisModel.getModel(['axisLine', 'lineStyle']).getLineStyle()); - var pathBaseProp = { - strokeContainThreshold: cfg.raw.strokeContainThreshold || 5, - silent: true, - z2: 1, - style: lineStyle - }; - - if (axisModel.get(['axisLine', 'breakLine']) && axisModel.axis.scale.hasBreaks()) { - getAxisBreakHelper().buildAxisBreakLine(axisModel, group, transformGroup, pathBaseProp); - } else { - var line = new Line(extend({ - shape: { - x1: pt1[0], - y1: pt1[1], - x2: pt2[0], - y2: pt2[1] - } - }, pathBaseProp)); - subPixelOptimizeLine(line.shape, line.style.lineWidth); - line.anid = 'line'; - group.add(line); - } - - var arrows = axisModel.get(['axisLine', 'symbol']); - - if (arrows != null) { - var arrowSize = axisModel.get(['axisLine', 'symbolSize']); - - if (isString(arrows)) { - // Use the same arrow for start and end point - arrows = [arrows, arrows]; - } - - if (isString(arrowSize) || isNumber(arrowSize)) { - // Use the same size for width and height - arrowSize = [arrowSize, arrowSize]; - } - - var arrowOffset = normalizeSymbolOffset(axisModel.get(['axisLine', 'symbolOffset']) || 0, arrowSize); - var symbolWidth_1 = arrowSize[0]; - var symbolHeight_1 = arrowSize[1]; - each$4([{ - rotate: cfg.rotation + Math.PI / 2, - offset: arrowOffset[0], - r: 0 - }, { - rotate: cfg.rotation - Math.PI / 2, - offset: arrowOffset[1], - r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0]) + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1])) - }], function (point, index) { - if (arrows[index] !== 'none' && arrows[index] != null) { - var symbol = createSymbol(arrows[index], -symbolWidth_1 / 2, -symbolHeight_1 / 2, symbolWidth_1, symbolHeight_1, lineStyle.stroke, true); // Calculate arrow position with offset - - var r = point.r + point.offset; - var pt = inverse ? pt2 : pt1; - symbol.attr({ - rotation: point.rotate, - x: pt[0] + r * Math.cos(cfg.rotation), - y: pt[1] - r * Math.sin(cfg.rotation), - silent: true, - z2: 11 - }); - group.add(symbol); - } - }); - } - }, - - /** - * [CAUTION] This method can be called multiple times, following the change due to `resetCfg` called - * in size measurement. Thus this method should be idempotent, and should be performant. - */ - axisTickLabelEstimate: function (cfg, local, shared, axisModel, group, transformGroup, api, extraParams) { - { - var ready = shared.ensureRecord(axisModel).ready; - assert(!ready.axisTickLabelDetermine); - ready.axisTickLabelEstimate = true; - } - var needCallLayout = dealLastTickLabelResultReusable(local, group, extraParams); - - if (needCallLayout) { - layOutAxisTickLabel(cfg, local, shared, axisModel, group, transformGroup, api, AxisTickLabelComputingKind.estimate); - } - }, - - /** - * Finish axis tick label build. - * Can be only called once. - */ - axisTickLabelDetermine: function (cfg, local, shared, axisModel, group, transformGroup, api, extraParams) { - { - var ready = shared.ensureRecord(axisModel).ready; - ready.axisTickLabelDetermine = true; - } - var needCallLayout = dealLastTickLabelResultReusable(local, group, extraParams); - - if (needCallLayout) { - layOutAxisTickLabel(cfg, local, shared, axisModel, group, transformGroup, api, AxisTickLabelComputingKind.determine); - } - - var ticksEls = buildAxisMajorTicks(cfg, group, transformGroup, axisModel); - syncLabelIgnoreToMajorTicks(cfg, local.labelLayoutList, ticksEls); - buildAxisMinorTicks(cfg, group, transformGroup, axisModel, cfg.tickDirection); - }, - - /** - * [CAUTION] This method can be called multiple times, following the change due to `resetCfg` called - * in size measurement. Thus this method should be idempotent, and should be performant. - */ - axisName: function (cfg, local, shared, axisModel, group, transformGroup, api, extraParams) { - var sharedRecord = shared.ensureRecord(axisModel); - { - var ready = sharedRecord.ready; - assert(ready.axisTickLabelEstimate || ready.axisTickLabelDetermine); - ready.axisName = true; - } // Remove the existing name result created in estimation phase. - - if (local.nameEl) { - group.remove(local.nameEl); - local.nameEl = sharedRecord.nameLayout = sharedRecord.nameLocation = null; - } - - var name = cfg.axisName; - - if (!hasAxisName(name)) { - return; - } - - var nameLocation = cfg.nameLocation; - var nameDirection = cfg.nameDirection; - var textStyleModel = axisModel.getModel('nameTextStyle'); - var gap = axisModel.get('nameGap') || 0; - var extent = axisModel.axis.getExtent(); - var gapStartEndSignal = axisModel.axis.inverse ? -1 : 1; - var pos = new Point(0, 0); - var nameMoveDirVec = new Point(0, 0); - - if (nameLocation === 'start') { - pos.x = extent[0] - gapStartEndSignal * gap; - nameMoveDirVec.x = -gapStartEndSignal; - } else if (nameLocation === 'end') { - pos.x = extent[1] + gapStartEndSignal * gap; - nameMoveDirVec.x = gapStartEndSignal; - } else { - // 'middle' or 'center' - pos.x = (extent[0] + extent[1]) / 2; - pos.y = cfg.labelOffset + nameDirection * gap; - nameMoveDirVec.y = nameDirection; - } - - var mt = create(); - nameMoveDirVec.transform(rotate(mt, mt, cfg.rotation)); - var nameRotation = axisModel.get('nameRotate'); - - if (nameRotation != null) { - nameRotation = nameRotation * PI / 180; // To radian. - } - - var labelLayout; - var axisNameAvailableWidth; - - if (isNameLocationCenter(nameLocation)) { - labelLayout = AxisBuilder.innerTextLayout(cfg.rotation, nameRotation != null ? nameRotation : cfg.rotation, // Adapt to axis. - nameDirection); - } else { - labelLayout = endTextLayout(cfg.rotation, nameLocation, nameRotation || 0, extent); - axisNameAvailableWidth = cfg.raw.axisNameAvailableWidth; - - if (axisNameAvailableWidth != null) { - axisNameAvailableWidth = Math.abs(axisNameAvailableWidth / Math.sin(labelLayout.rotation)); - !isFinite(axisNameAvailableWidth) && (axisNameAvailableWidth = null); - } - } - - var textFont = textStyleModel.getFont(); - var truncateOpt = axisModel.get('nameTruncate', true) || {}; - var ellipsis = truncateOpt.ellipsis; - var maxWidth = retrieve(cfg.raw.nameTruncateMaxWidth, truncateOpt.maxWidth, axisNameAvailableWidth); - var nameMarginLevel = extraParams.nameMarginLevel || 0; - var textEl = new ZRText({ - x: pos.x, - y: pos.y, - rotation: labelLayout.rotation, - silent: AxisBuilder.isLabelSilent(axisModel), - style: createTextStyle$1(textStyleModel, { - text: name, - font: textFont, - overflow: 'truncate', - width: maxWidth, - ellipsis: ellipsis, - fill: textStyleModel.getTextColor() || axisModel.get(['axisLine', 'lineStyle', 'color']), - align: textStyleModel.get('align') || labelLayout.textAlign, - verticalAlign: textStyleModel.get('verticalAlign') || labelLayout.textVerticalAlign - }), - z2: 1 - }); - setTooltipConfig({ - el: textEl, - componentModel: axisModel, - itemName: name - }); - textEl.__fullText = name; // Id for animation - - textEl.anid = 'name'; - - if (axisModel.get('triggerEvent')) { - var eventData = AxisBuilder.makeAxisEventDataBase(axisModel); - eventData.targetType = 'axisName'; - eventData.name = name; - getECData(textEl).eventData = eventData; - } - - transformGroup.add(textEl); - textEl.updateTransform(); - local.nameEl = textEl; - var nameLayout = sharedRecord.nameLayout = ensureLabelLayoutWithGeometry({ - label: textEl, - priority: textEl.z2, - defaultAttr: { - ignore: textEl.ignore - }, - marginDefault: isNameLocationCenter(nameLocation) // Make axis name visually far from axis labels. - // (but not too aggressive, consider multiple small charts) - ? DEFAULT_CENTER_NAME_MARGIN_LEVELS[nameMarginLevel] // top/button margin is set to `0` to inserted the xAxis name into the indention - // above the axis labels to save space. (see example below.) - : DEFAULT_ENDS_NAME_MARGIN_LEVELS[nameMarginLevel] - }); - sharedRecord.nameLocation = nameLocation; - group.add(textEl); - textEl.decomposeTransform(); - - if (cfg.shouldNameMoveOverlap && nameLayout) { - var record = shared.ensureRecord(axisModel); - { - assert(record.labelInfoList); - } - shared.resolveAxisNameOverlap(cfg, shared, axisModel, nameLayout, nameMoveDirVec, record); - } - } - }; - - function layOutAxisTickLabel(cfg, local, shared, axisModel, group, transformGroup, api, kind) { - if (!axisLabelBuildResultExists(local)) { - buildAxisLabel(cfg, local, group, kind, axisModel, api); - } - - var labelLayoutList = local.labelLayoutList; - updateAxisLabelChangableProps(cfg, axisModel, labelLayoutList, transformGroup); - adjustBreakLabels(axisModel, cfg.rotation); - var optionHideOverlap = cfg.optionHideOverlap; - fixMinMaxLabelShow(axisModel, labelLayoutList, optionHideOverlap); - - if (optionHideOverlap) { - // This bit fixes the label overlap issue for the time chart. - // See https://github.com/apache/echarts/issues/14266 for more. - hideOverlap( // Filter the already ignored labels by the previous overlap resolving methods. - filter(labelLayoutList, function (layout) { - return layout && !layout.label.ignore; - })); - } // Always call it even this axis has no name, since it serves in overlapping detection - // and grid outerBounds on other axis. - - - resetOverlapRecordToShared(cfg, shared, axisModel, labelLayoutList); - } - - function endTextLayout(rotation, textPosition, textRotate, extent) { - var rotationDiff = remRadian(textRotate - rotation); - var textAlign; - var textVerticalAlign; - var inverse = extent[0] > extent[1]; - var onLeft = textPosition === 'start' && !inverse || textPosition !== 'start' && inverse; - - if (isRadianAroundZero(rotationDiff - PI / 2)) { - textVerticalAlign = onLeft ? 'bottom' : 'top'; - textAlign = 'center'; - } else if (isRadianAroundZero(rotationDiff - PI * 1.5)) { - textVerticalAlign = onLeft ? 'top' : 'bottom'; - textAlign = 'center'; - } else { - textVerticalAlign = 'middle'; - - if (rotationDiff < PI * 1.5 && rotationDiff > PI / 2) { - textAlign = onLeft ? 'left' : 'right'; - } else { - textAlign = onLeft ? 'right' : 'left'; - } - } - - return { - rotation: rotationDiff, - textAlign: textAlign, - textVerticalAlign: textVerticalAlign - }; - } - /** - * Assume `labelLayoutList` has no `label.ignore: true`. - * Assume `labelLayoutList` have been sorted by value ascending order. - */ - - - function fixMinMaxLabelShow(axisModel, labelLayoutList, optionHideOverlap) { - if (shouldShowAllLabels(axisModel.axis)) { - return; - } // FIXME - // Have not consider onBand yet, where tick els is more than label els. - // Assert no ignore in labels. - - - function deal(showMinMaxLabel, outmostLabelIdx, innerLabelIdx) { - var outmostLabelLayout = ensureLabelLayoutWithGeometry(labelLayoutList[outmostLabelIdx]); - var innerLabelLayout = ensureLabelLayoutWithGeometry(labelLayoutList[innerLabelIdx]); - - if (!outmostLabelLayout || !innerLabelLayout) { - return; - } - - if (showMinMaxLabel === false || outmostLabelLayout.suggestIgnore) { - ignoreEl(outmostLabelLayout.label); - return; - } - - if (innerLabelLayout.suggestIgnore) { - ignoreEl(innerLabelLayout.label); - return; - } // PENDING: Originally we thought `optionHideOverlap === false` means do not hide anything, - // since currently the bounding rect of text might not accurate enough and might slightly bigger, - // which causes false positive. But `optionHideOverlap: null/undfined` is falsy and likely - // be treated as false. - // In most fonts the glyph does not reach the boundary of the bounding rect. - // This is needed to avoid too aggressive to hide two elements that meet at the edge - // due to compact layout by the same bounding rect or OBB. - - - var touchThreshold = 0.1; // This treatment is for backward compatibility. And `!optionHideOverlap` implies that - // the user accepts the visual touch between adjacent labels, thus "hide min/max label" - // should be conservative, since the space might be sufficient in this case. - - if (!optionHideOverlap) { - var marginForce = [0, 0, 0, 0]; // Make a copy to apply `ignoreMargin`. - - outmostLabelLayout = newLabelLayoutWithGeometry({ - marginForce: marginForce - }, outmostLabelLayout); - innerLabelLayout = newLabelLayoutWithGeometry({ - marginForce: marginForce - }, innerLabelLayout); - } - - if (labelIntersect(outmostLabelLayout, innerLabelLayout, null, { - touchThreshold: touchThreshold - })) { - if (showMinMaxLabel) { - ignoreEl(innerLabelLayout.label); - } else { - ignoreEl(outmostLabelLayout.label); - } - } - } // If min or max are user set, we need to check - // If the tick on min(max) are overlap on their neighbour tick - // If they are overlapped, we need to hide the min(max) tick label - - - var showMinLabel = axisModel.get(['axisLabel', 'showMinLabel']); - var showMaxLabel = axisModel.get(['axisLabel', 'showMaxLabel']); - var labelsLen = labelLayoutList.length; - deal(showMinLabel, 0, 1); - deal(showMaxLabel, labelsLen - 1, labelsLen - 2); - } // PENDING: Is it necessary to display a tick while the corresponding label is ignored? - - - function syncLabelIgnoreToMajorTicks(cfg, labelLayoutList, tickEls) { - if (cfg.showMinorTicks) { - // It probably unreaasonable to hide major ticks when show minor ticks. - return; - } - - each$4(labelLayoutList, function (labelLayout) { - if (labelLayout && labelLayout.label.ignore) { - for (var idx = 0; idx < tickEls.length; idx++) { - var tickEl = tickEls[idx]; // Assume small array, linear search is fine for performance. - // PENDING: measure? - - var tickInner = getTickInner(tickEl); - var labelInner = getLabelInner(labelLayout.label); - - if (tickInner.tickValue != null && !tickInner.onBand && tickInner.tickValue === labelInner.tickValue) { - ignoreEl(tickEl); - return; - } - } - } - }); - } - - function ignoreEl(el) { - el && (el.ignore = true); - } - - function createTicks(ticksCoords, tickTransform, tickEndCoord, tickLineStyle, anidPrefix) { - var tickEls = []; - var pt1 = []; - var pt2 = []; - - for (var i = 0; i < ticksCoords.length; i++) { - var tickCoord = ticksCoords[i].coord; - pt1[0] = tickCoord; - pt1[1] = 0; - pt2[0] = tickCoord; - pt2[1] = tickEndCoord; - - if (tickTransform) { - applyTransform$1(pt1, pt1, tickTransform); - applyTransform$1(pt2, pt2, tickTransform); - } // Tick line, Not use group transform to have better line draw - - - var tickEl = new Line({ - shape: { - x1: pt1[0], - y1: pt1[1], - x2: pt2[0], - y2: pt2[1] - }, - style: tickLineStyle, - z2: 2, - autoBatch: true, - silent: true - }); - subPixelOptimizeLine(tickEl.shape, tickEl.style.lineWidth); - tickEl.anid = anidPrefix + '_' + ticksCoords[i].tickValue; - tickEls.push(tickEl); - var inner = getTickInner(tickEl); - inner.onBand = !!ticksCoords[i].onBand; - inner.tickValue = ticksCoords[i].tickValue; - } - - return tickEls; - } - - function buildAxisMajorTicks(cfg, group, transformGroup, axisModel) { - var axis = axisModel.axis; - var tickModel = axisModel.getModel('axisTick'); - var shown = tickModel.get('show'); - - if (shown === 'auto') { - shown = true; - - if (cfg.raw.axisTickAutoShow != null) { - shown = !!cfg.raw.axisTickAutoShow; - } - } - - if (!shown || axis.scale.isBlank()) { - return []; - } - - var lineStyleModel = tickModel.getModel('lineStyle'); - var tickEndCoord = cfg.tickDirection * tickModel.get('length'); - var ticksCoords = axis.getTicksCoords(); - var ticksEls = createTicks(ticksCoords, transformGroup.transform, tickEndCoord, defaults(lineStyleModel.getLineStyle(), { - stroke: axisModel.get(['axisLine', 'lineStyle', 'color']) - }), 'ticks'); - - for (var i = 0; i < ticksEls.length; i++) { - group.add(ticksEls[i]); - } - - return ticksEls; - } - - function buildAxisMinorTicks(cfg, group, transformGroup, axisModel, tickDirection) { - var axis = axisModel.axis; - var minorTickModel = axisModel.getModel('minorTick'); - - if (!cfg.showMinorTicks || axis.scale.isBlank()) { - return; - } - - var minorTicksCoords = axis.getMinorTicksCoords(); - - if (!minorTicksCoords.length) { - return; - } - - var lineStyleModel = minorTickModel.getModel('lineStyle'); - var tickEndCoord = tickDirection * minorTickModel.get('length'); - var minorTickLineStyle = defaults(lineStyleModel.getLineStyle(), defaults(axisModel.getModel('axisTick').getLineStyle(), { - stroke: axisModel.get(['axisLine', 'lineStyle', 'color']) - })); - - for (var i = 0; i < minorTicksCoords.length; i++) { - var minorTicksEls = createTicks(minorTicksCoords[i], transformGroup.transform, tickEndCoord, minorTickLineStyle, 'minorticks_' + i); - - for (var k = 0; k < minorTicksEls.length; k++) { - group.add(minorTicksEls[k]); - } - } - } // Return whether need to call `layOutAxisTickLabel` again. - - - function dealLastTickLabelResultReusable(local, group, extraParams) { - if (axisLabelBuildResultExists(local)) { - var axisLabelsCreationContext = local.axisLabelsCreationContext; - { - assert(local.labelGroup && axisLabelsCreationContext); - } - var noPxChangeTryDetermine = axisLabelsCreationContext.out.noPxChangeTryDetermine; - - if (extraParams.noPxChange) { - var canDetermine = true; - - for (var idx = 0; idx < noPxChangeTryDetermine.length; idx++) { - canDetermine = canDetermine && noPxChangeTryDetermine[idx](); - } - - if (canDetermine) { - return false; - } - } - - if (noPxChangeTryDetermine.length) { - // Remove the result of `buildAxisLabel` - group.remove(local.labelGroup); - axisLabelBuildResultSet(local, null, null, null); - } - } - - return true; - } - - function buildAxisLabel(cfg, local, group, kind, axisModel, api) { - var axis = axisModel.axis; - var show = retrieve(cfg.raw.axisLabelShow, axisModel.get(['axisLabel', 'show'])); - var labelGroup = new Group$2(); - group.add(labelGroup); - var axisLabelCreationCtx = createAxisLabelsComputingContext(kind); - - if (!show || axis.scale.isBlank()) { - axisLabelBuildResultSet(local, [], labelGroup, axisLabelCreationCtx); - return; - } - - var labelModel = axisModel.getModel('axisLabel'); - var labels = axis.getViewLabels(axisLabelCreationCtx); // Special label rotate. - - var labelRotation = (retrieve(cfg.raw.labelRotate, labelModel.get('rotate')) || 0) * PI / 180; - var labelLayout = AxisBuilder.innerTextLayout(cfg.rotation, labelRotation, cfg.labelDirection); - var rawCategoryData = axisModel.getCategories && axisModel.getCategories(true); - var labelEls = []; - var triggerEvent = axisModel.get('triggerEvent'); - var z2Min = Infinity; - var z2Max = -Infinity; - each$4(labels, function (labelItem, index) { - var _a; - - var tickValue = axis.scale.type === 'ordinal' ? axis.scale.getRawOrdinalNumber(labelItem.tickValue) : labelItem.tickValue; - var formattedLabel = labelItem.formattedLabel; - var rawLabel = labelItem.rawLabel; - var itemLabelModel = labelModel; - - if (rawCategoryData && rawCategoryData[tickValue]) { - var rawCategoryItem = rawCategoryData[tickValue]; - - if (isObject$2(rawCategoryItem) && rawCategoryItem.textStyle) { - itemLabelModel = new Model(rawCategoryItem.textStyle, labelModel, axisModel.ecModel); - } - } - - var textColor = itemLabelModel.getTextColor() || axisModel.get(['axisLine', 'lineStyle', 'color']); - var align = itemLabelModel.getShallow('align', true) || labelLayout.textAlign; - var alignMin = retrieve2(itemLabelModel.getShallow('alignMinLabel', true), align); - var alignMax = retrieve2(itemLabelModel.getShallow('alignMaxLabel', true), align); - var verticalAlign = itemLabelModel.getShallow('verticalAlign', true) || itemLabelModel.getShallow('baseline', true) || labelLayout.textVerticalAlign; - var verticalAlignMin = retrieve2(itemLabelModel.getShallow('verticalAlignMinLabel', true), verticalAlign); - var verticalAlignMax = retrieve2(itemLabelModel.getShallow('verticalAlignMaxLabel', true), verticalAlign); - var z2 = 10 + (((_a = labelItem.time) === null || _a === void 0 ? void 0 : _a.level) || 0); - z2Min = Math.min(z2Min, z2); - z2Max = Math.max(z2Max, z2); - var textEl = new ZRText({ - // --- transform props start --- - // All of the transform props MUST not be set here, but should be set in - // `updateAxisLabelChangableProps`, because they may change in estimation, - // and need to calculate based on global coord sys by `decomposeTransform`. - x: 0, - y: 0, - rotation: 0, - // --- transform props end --- - silent: AxisBuilder.isLabelSilent(axisModel), - z2: z2, - style: createTextStyle$1(itemLabelModel, { - text: formattedLabel, - align: index === 0 ? alignMin : index === labels.length - 1 ? alignMax : align, - verticalAlign: index === 0 ? verticalAlignMin : index === labels.length - 1 ? verticalAlignMax : verticalAlign, - fill: isFunction(textColor) ? textColor( // (1) In category axis with data zoom, tick is not the original - // index of axis.data. So tick should not be exposed to user - // in category axis. - // (2) Compatible with previous version, which always use formatted label as - // input. But in interval scale the formatted label is like '223,445', which - // maked user replace ','. So we modify it to return original val but remain - // it as 'string' to avoid error in replacing. - axis.type === 'category' ? rawLabel : axis.type === 'value' ? tickValue + '' : tickValue, index) : textColor - }) - }); - textEl.anid = 'label_' + tickValue; - var inner = getLabelInner(textEl); - inner["break"] = labelItem["break"]; - inner.tickValue = tickValue; - inner.layoutRotation = labelLayout.rotation; - setTooltipConfig({ - el: textEl, - componentModel: axisModel, - itemName: formattedLabel, - formatterParamsExtra: { - isTruncated: function () { - return textEl.isTruncated; - }, - value: rawLabel, - tickIndex: index - } - }); // Pack data for mouse event - - if (triggerEvent) { - var eventData = AxisBuilder.makeAxisEventDataBase(axisModel); - eventData.targetType = 'axisLabel'; - eventData.value = rawLabel; - eventData.tickIndex = index; - - if (labelItem["break"]) { - eventData["break"] = { - // type: labelItem.break.type, - start: labelItem["break"].parsedBreak.vmin, - end: labelItem["break"].parsedBreak.vmax - }; - } - - if (axis.type === 'category') { - eventData.dataIndex = tickValue; - } - - getECData(textEl).eventData = eventData; - - if (labelItem["break"]) { - addBreakEventHandler(axisModel, api, textEl, labelItem["break"]); - } - } - - labelEls.push(textEl); - labelGroup.add(textEl); - }); - var labelLayoutList = map$1(labelEls, function (label) { - return { - label: label, - priority: getLabelInner(label)["break"] ? label.z2 + (z2Max - z2Min + 1) // Make break labels be highest priority. - : label.z2, - defaultAttr: { - ignore: label.ignore - } - }; - }); - axisLabelBuildResultSet(local, labelLayoutList, labelGroup, axisLabelCreationCtx); - } // Indicate that `layOutAxisTickLabel` has been called. - - - function axisLabelBuildResultExists(local) { - return !!local.labelLayoutList; - } - - function axisLabelBuildResultSet(local, labelLayoutList, labelGroup, axisLabelsCreationContext) { - // Ensure the same lifetime. - local.labelLayoutList = labelLayoutList; - local.labelGroup = labelGroup; - local.axisLabelsCreationContext = axisLabelsCreationContext; - } - - function updateAxisLabelChangableProps(cfg, axisModel, labelLayoutList, transformGroup) { - var labelMargin = axisModel.get(['axisLabel', 'margin']); - each$4(labelLayoutList, function (layout, idx) { - var geometry = ensureLabelLayoutWithGeometry(layout); - - if (!geometry) { - return; - } - - var labelEl = geometry.label; - var inner = getLabelInner(labelEl); // See the comment in `suggestIgnore`. - - geometry.suggestIgnore = labelEl.ignore; // Currently no `ignore:true` is set in `buildAxisLabel` - // But `ignore:true` may be set subsequently for overlap handling, thus reset it here. - - labelEl.ignore = false; - copyTransform(_tmpLayoutEl, _tmpLayoutElReset); - _tmpLayoutEl.x = axisModel.axis.dataToCoord(inner.tickValue); - _tmpLayoutEl.y = cfg.labelOffset + cfg.labelDirection * labelMargin; - _tmpLayoutEl.rotation = inner.layoutRotation; - transformGroup.add(_tmpLayoutEl); - - _tmpLayoutEl.updateTransform(); - - transformGroup.remove(_tmpLayoutEl); - - _tmpLayoutEl.decomposeTransform(); - - copyTransform(labelEl, _tmpLayoutEl); - labelEl.markRedraw(); - setLabelLayoutDirty(geometry, true); - ensureLabelLayoutWithGeometry(geometry); - }); - } - - var _tmpLayoutEl = new Rect(); - - var _tmpLayoutElReset = new Rect(); - - function hasAxisName(axisName) { - return !!axisName; - } - - function addBreakEventHandler(axisModel, api, textEl, visualBreak) { - textEl.on('click', function (params) { - var payload = { - type: AXIS_BREAK_EXPAND_ACTION_TYPE, - breaks: [{ - start: visualBreak.parsedBreak.breakOption.start, - end: visualBreak.parsedBreak.breakOption.end - }] - }; - payload[axisModel.axis.dim + "AxisIndex"] = axisModel.componentIndex; - api.dispatchAction(payload); - }); - } - - function adjustBreakLabels(axisModel, axisRotation, labelLayoutList) { - { - return; - } - } - /** - * [__CAUTION__] - * MUST guarantee: if only the input `rect` and `axis.extent` changed, - * only `layout.position` changes. - * This character is replied on `grid.contain` calculation in `AxisBuilder`. - * @see updateCartesianAxisViewCommonPartBuilder - * - * Can only be called after coordinate system creation stage. - * (Can be called before coordinate system update stage). - */ - - - function layout(rect, axisModel, opt) { - opt = opt || {}; - var axis = axisModel.axis; - var layout = {}; - var otherAxisOnZeroOf = axis.getAxesOnZeroOf()[0]; - var rawAxisPosition = axis.position; - var axisPosition = otherAxisOnZeroOf ? 'onZero' : rawAxisPosition; - var axisDim = axis.dim; - var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height]; - var idx = { - left: 0, - right: 1, - top: 0, - bottom: 1, - onZero: 2 - }; - var axisOffset = axisModel.get('offset') || 0; - var posBound = axisDim === 'x' ? [rectBound[2] - axisOffset, rectBound[3] + axisOffset] : [rectBound[0] - axisOffset, rectBound[1] + axisOffset]; - - if (otherAxisOnZeroOf) { - var onZeroCoord = otherAxisOnZeroOf.toGlobalCoord(otherAxisOnZeroOf.dataToCoord(0)); - posBound[idx.onZero] = Math.max(Math.min(onZeroCoord, posBound[1]), posBound[0]); - } // Axis position - - - layout.position = [axisDim === 'y' ? posBound[idx[axisPosition]] : rectBound[0], axisDim === 'x' ? posBound[idx[axisPosition]] : rectBound[3]]; // Axis rotation - - layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1); // Tick and label direction, x y is axisDim - - var dirMap = { - top: -1, - bottom: 1, - left: -1, - right: 1 - }; - layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition]; - layout.labelOffset = otherAxisOnZeroOf ? posBound[idx[rawAxisPosition]] - posBound[idx.onZero] : 0; - - if (axisModel.get(['axisTick', 'inside'])) { - layout.tickDirection = -layout.tickDirection; - } - - if (retrieve(opt.labelInside, axisModel.get(['axisLabel', 'inside']))) { - layout.labelDirection = -layout.labelDirection; - } // Special label rotation - - - var labelRotate = axisModel.get(['axisLabel', 'rotate']); - layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate; // Over splitLine and splitArea - - layout.z2 = 1; - return layout; - } - /** - * Note: If pie (or other similar series) use cartesian2d, here - * option `seriesModel.get('coordinateSystem') === 'cartesian2d'` - * and `seriesModel.coordinateSystem !== cartesian2dCoordSysInstance` - * and `seriesModel.boxCoordinateSystem === cartesian2dCoordSysInstance`, - * the logic below is probably wrong, therefore skip it temporarily. - */ - - - function isCartesian2DInjectedAsDataCoordSys(seriesModel) { - return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d'; - } - - function findAxisModels(seriesModel) { - var axisModelMap = { - xAxisModel: null, - yAxisModel: null - }; - each$4(axisModelMap, function (v, key) { - var axisType = key.replace(/Model$/, ''); - var axisModel = seriesModel.getReferringComponents(axisType, SINGLE_REFERRING).models[0]; - { - if (!axisModel) { - throw new Error(axisType + ' "' + retrieve3(seriesModel.get(axisType + 'Index'), seriesModel.get(axisType + 'Id'), 0) + '" not found'); - } - } - axisModelMap[key] = axisModel; - }); - return axisModelMap; - } - - function createCartesianAxisViewCommonPartBuilder(gridRect, cartesians, axisModel, api, ctx, defaultNameMoveOverlap) { - var layoutResult = layout(gridRect, axisModel); - var axisLineAutoShow = false; - var axisTickAutoShow = false; // Not show axisTick or axisLine if other axis is category / time - - for (var i = 0; i < cartesians.length; i++) { - if (isIntervalOrLogScale(cartesians[i].getOtherAxis(axisModel.axis).scale)) { - // Still show axis tick or axisLine if other axis is value / log - axisLineAutoShow = axisTickAutoShow = true; - - if (axisModel.axis.type === 'category' && axisModel.axis.onBand) { - axisTickAutoShow = false; - } - } - } - - layoutResult.axisLineAutoShow = axisLineAutoShow; - layoutResult.axisTickAutoShow = axisTickAutoShow; - layoutResult.defaultNameMoveOverlap = defaultNameMoveOverlap; - return new AxisBuilder(axisModel, api, layoutResult, ctx); - } - - function updateCartesianAxisViewCommonPartBuilder(axisBuilder, gridRect, axisModel) { - var newRaw = layout(gridRect, axisModel); - { - var oldRaw_1 = axisBuilder.__getRawCfg(); - - each$4(keys(newRaw), function (prop) { - if (prop !== 'position' && prop !== 'labelOffset') { - assert(newRaw[prop] === oldRaw_1[prop]); - } - }); - } - axisBuilder.updateCfg(newRaw); - } - - function alignScaleTicks(scale, axisModel, alignToScale) { - var _a; - - var intervalScaleProto = IntervalScale.prototype; // NOTE: There is a precondition for log scale here: - // In log scale we store _interval and _extent of exponent value. - // So if we use the method of InternalScale to set/get these data. - // It process the exponent value, which is linear and what we want here. - - var alignToTicks = intervalScaleProto.getTicks.call(alignToScale); - var alignToNicedTicks = intervalScaleProto.getTicks.call(alignToScale, { - expandToNicedExtent: true - }); - var alignToSplitNumber = alignToTicks.length - 1; - var alignToInterval = intervalScaleProto.getInterval.call(alignToScale); - var scaleExtent = getScaleExtent(scale, axisModel); - var rawExtent = scaleExtent.extent; - var isMinFixed = scaleExtent.fixMin; - var isMaxFixed = scaleExtent.fixMax; - - if (scale.type === 'log') { - rawExtent = logTransform(scale.base, rawExtent, true); - } - - scale.setBreaksFromOption(retrieveAxisBreaksOption(axisModel)); - scale.setExtent(rawExtent[0], rawExtent[1]); - scale.calcNiceExtent({ - splitNumber: alignToSplitNumber, - fixMin: isMinFixed, - fixMax: isMaxFixed - }); - var extent = intervalScaleProto.getExtent.call(scale); // Need to update the rawExtent. - // Because value in rawExtent may be not parsed. e.g. 'dataMin', 'dataMax' - - if (isMinFixed) { - rawExtent[0] = extent[0]; - } - - if (isMaxFixed) { - rawExtent[1] = extent[1]; - } - - var interval = intervalScaleProto.getInterval.call(scale); - var min = rawExtent[0]; - var max = rawExtent[1]; - - if (isMinFixed && isMaxFixed) { - // User set min, max, divide to get new interval - interval = (max - min) / alignToSplitNumber; - } else if (isMinFixed) { - max = rawExtent[0] + interval * alignToSplitNumber; // User set min, expand extent on the other side - - while (max < rawExtent[1] && isFinite(max) && isFinite(rawExtent[1])) { - interval = increaseInterval(interval); - max = rawExtent[0] + interval * alignToSplitNumber; - } - } else if (isMaxFixed) { - // User set max, expand extent on the other side - min = rawExtent[1] - interval * alignToSplitNumber; - - while (min > rawExtent[0] && isFinite(min) && isFinite(rawExtent[0])) { - interval = increaseInterval(interval); - min = rawExtent[1] - interval * alignToSplitNumber; - } - } else { - var nicedSplitNumber = scale.getTicks().length - 1; - - if (nicedSplitNumber > alignToSplitNumber) { - interval = increaseInterval(interval); - } - - var range = interval * alignToSplitNumber; - max = Math.ceil(rawExtent[1] / interval) * interval; - min = round$1(max - range); // Not change the result that crossing zero. - - if (min < 0 && rawExtent[0] >= 0) { - min = 0; - max = round$1(range); - } else if (max > 0 && rawExtent[1] <= 0) { - max = 0; - min = -round$1(range); - } - } // Adjust min, max based on the extent of alignTo. When min or max is set in alignTo scale - - - var t0 = (alignToTicks[0].value - alignToNicedTicks[0].value) / alignToInterval; - var t1 = (alignToTicks[alignToSplitNumber].value - alignToNicedTicks[alignToSplitNumber].value) / alignToInterval; // NOTE: Must in setExtent -> setInterval -> setNiceExtent order. - - intervalScaleProto.setExtent.call(scale, min + interval * t0, max + interval * t1); - intervalScaleProto.setInterval.call(scale, interval); - - if (t0 || t1) { - intervalScaleProto.setNiceExtent.call(scale, min + interval, max - interval); - } - - { - var ticks = intervalScaleProto.getTicks.call(scale); - - if (ticks[1] && (!isValueNice(interval) || getPrecisionSafe(ticks[1].value) > getPrecisionSafe(interval))) { - warn("The ticks may be not readable when set min: " + axisModel.get('min') + ", max: " + axisModel.get('max') + (" and alignTicks: true. (" + ((_a = axisModel.axis) === null || _a === void 0 ? void 0 : _a.dim) + "AxisIndex: " + axisModel.componentIndex + ")"), true); - } - } - } // margin is [top, right, bottom, left] - - - var XY_TO_MARGIN_IDX = [[3, 1], [0, 2] // xyIdx 1 => 'y' - ]; - - var Grid = - /** @class */ - function () { - function Grid(gridModel, ecModel, api) { - // FIXME:TS where used (different from registered type 'cartesian2d')? - this.type = 'grid'; - this._coordsMap = {}; - this._coordsList = []; - this._axesMap = {}; - this._axesList = []; - this.axisPointerEnabled = true; - this.dimensions = cartesian2DDimensions; - - this._initCartesian(gridModel, ecModel, api); - - this.model = gridModel; - } - - Grid.prototype.getRect = function () { - return this._rect; - }; - - Grid.prototype.update = function (ecModel, api) { - var axesMap = this._axesMap; - - this._updateScale(ecModel, this.model); - - function updateAxisTicks(axes) { - var alignTo; // Axis is added in order of axisIndex. - - var axesIndices = keys(axes); - var len = axesIndices.length; - - if (!len) { - return; - } - - var axisNeedsAlign = []; // Process once and calculate the ticks for those don't use alignTicks. - - for (var i = len - 1; i >= 0; i--) { - var idx = +axesIndices[i]; // Convert to number. - - var axis = axes[idx]; - var model = axis.model; - var scale = axis.scale; - - if ( // Only value and log axis without interval support alignTicks. - isIntervalOrLogScale(scale) && model.get('alignTicks') && model.get('interval') == null) { - axisNeedsAlign.push(axis); - } else { - niceScaleExtent(scale, model); - - if (isIntervalOrLogScale(scale)) { - // Can only align to interval or log axis. - alignTo = axis; - } - } - } // All axes has set alignTicks. Pick the first one. - // PENDING. Should we find the axis that both set interval, min, max and align to this one? - - - if (axisNeedsAlign.length) { - if (!alignTo) { - alignTo = axisNeedsAlign.pop(); - niceScaleExtent(alignTo.scale, alignTo.model); - } - - each$4(axisNeedsAlign, function (axis) { - alignScaleTicks(axis.scale, axis.model, alignTo.scale); - }); - } - } - - updateAxisTicks(axesMap.x); - updateAxisTicks(axesMap.y); // Key: axisDim_axisIndex, value: boolean, whether onZero target. - - var onZeroRecords = {}; - each$4(axesMap.x, function (xAxis) { - fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords); - }); - each$4(axesMap.y, function (yAxis) { - fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords); - }); // Resize again if containLabel is enabled - // FIXME It may cause getting wrong grid size in data processing stage - - this.resize(this.model, api); - }; - /** - * Resize the grid. - * - * [NOTE] - * If both "grid.containLabel/grid.contain" and pixel-required-data-processing (such as, "dataSampling") - * exist, circular dependency occurs in logic. - * The final compromised sequence is: - * 1. Calculate "axis.extent" (pixel extent) and AffineTransform based on only "grid layout options". - * Not accurate if "grid.containLabel/grid.contain" is required, but it is a compromise to avoid - * circular dependency. - * 2. Perform "series data processing" (where "dataSampling" requires "axis.extent"). - * 3. Calculate "scale.extent" (data extent) based on "processed series data". - * 4. Modify "axis.extent" for "grid.containLabel/grid.contain": - * 4.1. Calculate "axis labels" based on "scale.extent". - * 4.2. Modify "axis.extent" by the bounding rects of "axis labels and names". - */ - - - Grid.prototype.resize = function (gridModel, api, beforeDataProcessing) { - var layoutRef = createBoxLayoutReference(gridModel, api); - var gridRect = this._rect = getLayoutRect(gridModel.getBoxLayoutParams(), layoutRef.refContainer); // PENDING: whether to support that if the input `coord` is out of the base coord sys, - // do not render anything. At present, the behavior is undefined. - - var axesMap = this._axesMap; - var coordsList = this._coordsList; - var optionContainLabel = gridModel.get('containLabel'); // No `.get(, true)` for backward compat. - - updateAllAxisExtentTransByGridRect(axesMap, gridRect); - - if (!beforeDataProcessing) { - var axisBuilderSharedCtx = createAxisBiulders(gridRect, coordsList, axesMap, optionContainLabel, api); - var noPxChange = void 0; - - if (optionContainLabel) { - { - { - log('Specified `grid.containLabel` but no `use(LegacyGridContainLabel)`;' + 'use `grid.outerBounds` instead.', true); - } - noPxChange = layOutGridByOuterBounds(gridRect.clone(), 'axisLabel', null, gridRect, axesMap, axisBuilderSharedCtx, layoutRef); - } - } else { - var _a = prepareOuterBounds(gridModel, gridRect, layoutRef), - outerBoundsRect = _a.outerBoundsRect, - parsedOuterBoundsContain = _a.parsedOuterBoundsContain, - outerBoundsClamp = _a.outerBoundsClamp; - - if (outerBoundsRect) { - // console.time('layOutGridByOuterBounds'); - noPxChange = layOutGridByOuterBounds(outerBoundsRect, parsedOuterBoundsContain, outerBoundsClamp, gridRect, axesMap, axisBuilderSharedCtx, layoutRef); // console.timeEnd('layOutGridByOuterBounds'); - } - } // console.time('buildAxesView_determine'); - - - createOrUpdateAxesView(gridRect, axesMap, AxisTickLabelComputingKind.determine, null, noPxChange, layoutRef); // console.timeEnd('buildAxesView_determine'); - } // End of beforeDataProcessing - - - each$4(this._coordsList, function (coord) { - // Calculate affine matrix to accelerate the data to point transform. - // If all the axes scales are time or value. - coord.calcAffineTransform(); - }); - }; - - Grid.prototype.getAxis = function (dim, axisIndex) { - var axesMapOnDim = this._axesMap[dim]; - - if (axesMapOnDim != null) { - return axesMapOnDim[axisIndex || 0]; - } - }; - - Grid.prototype.getAxes = function () { - return this._axesList.slice(); - }; - - Grid.prototype.getCartesian = function (xAxisIndex, yAxisIndex) { - if (xAxisIndex != null && yAxisIndex != null) { - var key = 'x' + xAxisIndex + 'y' + yAxisIndex; - return this._coordsMap[key]; - } - - if (isObject$2(xAxisIndex)) { - yAxisIndex = xAxisIndex.yAxisIndex; - xAxisIndex = xAxisIndex.xAxisIndex; - } - - for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) { - if (coordList[i].getAxis('x').index === xAxisIndex || coordList[i].getAxis('y').index === yAxisIndex) { - return coordList[i]; - } - } - }; - - Grid.prototype.getCartesians = function () { - return this._coordsList.slice(); - }; - /** - * @implements - */ - - - Grid.prototype.convertToPixel = function (ecModel, finder, value) { - var target = this._findConvertTarget(finder); - - return target.cartesian ? target.cartesian.dataToPoint(value) : target.axis ? target.axis.toGlobalCoord(target.axis.dataToCoord(value)) : null; - }; - /** - * @implements - */ - - - Grid.prototype.convertFromPixel = function (ecModel, finder, value) { - var target = this._findConvertTarget(finder); - - return target.cartesian ? target.cartesian.pointToData(value) : target.axis ? target.axis.coordToData(target.axis.toLocalCoord(value)) : null; - }; - - Grid.prototype._findConvertTarget = function (finder) { - var seriesModel = finder.seriesModel; - var xAxisModel = finder.xAxisModel || seriesModel && seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0]; - var yAxisModel = finder.yAxisModel || seriesModel && seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[0]; - var gridModel = finder.gridModel; - var coordsList = this._coordsList; - var cartesian; - var axis; - - if (seriesModel) { - cartesian = seriesModel.coordinateSystem; - indexOf(coordsList, cartesian) < 0 && (cartesian = null); - } else if (xAxisModel && yAxisModel) { - cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex); - } else if (xAxisModel) { - axis = this.getAxis('x', xAxisModel.componentIndex); - } else if (yAxisModel) { - axis = this.getAxis('y', yAxisModel.componentIndex); - } // Lowest priority. - else if (gridModel) { - var grid = gridModel.coordinateSystem; - - if (grid === this) { - cartesian = this._coordsList[0]; - } - } - - return { - cartesian: cartesian, - axis: axis - }; - }; - /** - * @implements - */ - - - Grid.prototype.containPoint = function (point) { - var coord = this._coordsList[0]; - - if (coord) { - return coord.containPoint(point); - } - }; - /** - * Initialize cartesian coordinate systems - */ - - - Grid.prototype._initCartesian = function (gridModel, ecModel, api) { - var _this = this; - - var grid = this; - var axisPositionUsed = { - left: false, - right: false, - top: false, - bottom: false - }; - var axesMap = { - x: {}, - y: {} - }; - var axesCount = { - x: 0, - y: 0 - }; // Create axis - - ecModel.eachComponent('xAxis', createAxisCreator('x'), this); - ecModel.eachComponent('yAxis', createAxisCreator('y'), this); - - if (!axesCount.x || !axesCount.y) { - // Roll back when there no either x or y axis - this._axesMap = {}; - this._axesList = []; - return; - } - - this._axesMap = axesMap; // Create cartesian2d - - each$4(axesMap.x, function (xAxis, xAxisIndex) { - each$4(axesMap.y, function (yAxis, yAxisIndex) { - var key = 'x' + xAxisIndex + 'y' + yAxisIndex; - var cartesian = new Cartesian2D(key); - cartesian.master = _this; - cartesian.model = gridModel; - _this._coordsMap[key] = cartesian; - - _this._coordsList.push(cartesian); - - cartesian.addAxis(xAxis); - cartesian.addAxis(yAxis); - }); - }); - - function createAxisCreator(dimName) { - return function (axisModel, idx) { - if (!isAxisUsedInTheGrid(axisModel, gridModel)) { - return; - } - - var axisPosition = axisModel.get('position'); - - if (dimName === 'x') { - // Fix position - if (axisPosition !== 'top' && axisPosition !== 'bottom') { - // Default bottom of X - axisPosition = axisPositionUsed.bottom ? 'top' : 'bottom'; - } - } else { - // Fix position - if (axisPosition !== 'left' && axisPosition !== 'right') { - // Default left of Y - axisPosition = axisPositionUsed.left ? 'right' : 'left'; - } - } - - axisPositionUsed[axisPosition] = true; - var axis = new Axis2D(dimName, createScaleByModel(axisModel), [0, 0], axisModel.get('type'), axisPosition); - var isCategory = axis.type === 'category'; - axis.onBand = isCategory && axisModel.get('boundaryGap'); - axis.inverse = axisModel.get('inverse'); // Inject axis into axisModel - - axisModel.axis = axis; // Inject axisModel into axis - - axis.model = axisModel; // Inject grid info axis - - axis.grid = grid; // Index of axis, can be used as key - - axis.index = idx; - - grid._axesList.push(axis); - - axesMap[dimName][idx] = axis; - axesCount[dimName]++; - }; - } - }; - /** - * Update cartesian properties from series. - */ - - - Grid.prototype._updateScale = function (ecModel, gridModel) { - // Reset scale - each$4(this._axesList, function (axis) { - axis.scale.setExtent(Infinity, -Infinity); - - if (axis.type === 'category') { - var categorySortInfo = axis.model.get('categorySortInfo'); - axis.scale.setSortInfo(categorySortInfo); - } - }); - ecModel.eachSeries(function (seriesModel) { - // If pie (or other similar series) use cartesian2d, the unionExtent logic below is - // wrong, therefore skip it temporarily. See also in `defaultAxisExtentFromData.ts`. - // TODO: support union extent in this case. - if (isCartesian2DInjectedAsDataCoordSys(seriesModel)) { - var axesModelMap = findAxisModels(seriesModel); - var xAxisModel = axesModelMap.xAxisModel; - var yAxisModel = axesModelMap.yAxisModel; - - if (!isAxisUsedInTheGrid(xAxisModel, gridModel) || !isAxisUsedInTheGrid(yAxisModel, gridModel)) { - return; - } - - var cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex); - var data = seriesModel.getData(); - var xAxis = cartesian.getAxis('x'); - var yAxis = cartesian.getAxis('y'); - unionExtent(data, xAxis); - unionExtent(data, yAxis); - } - }, this); - - function unionExtent(data, axis) { - each$4(getDataDimensionsOnAxis(data, axis.dim), function (dim) { - axis.scale.unionExtentFromData(data, dim); - }); - } - }; - /** - * @param dim 'x' or 'y' or 'auto' or null/undefined - */ - - - Grid.prototype.getTooltipAxes = function (dim) { - var baseAxes = []; - var otherAxes = []; - each$4(this.getCartesians(), function (cartesian) { - var baseAxis = dim != null && dim !== 'auto' ? cartesian.getAxis(dim) : cartesian.getBaseAxis(); - var otherAxis = cartesian.getOtherAxis(baseAxis); - indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis); - indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis); - }); - return { - baseAxes: baseAxes, - otherAxes: otherAxes - }; - }; - - Grid.create = function (ecModel, api) { - var grids = []; - ecModel.eachComponent('grid', function (gridModel, idx) { - var grid = new Grid(gridModel, ecModel, api); - grid.name = 'grid_' + idx; // dataSampling requires axis extent, so resize - // should be performed in create stage. - - grid.resize(gridModel, api, true); - gridModel.coordinateSystem = grid; - grids.push(grid); - }); // Inject the coordinateSystems into seriesModel - - ecModel.eachSeries(function (seriesModel) { - injectCoordSysByOption({ - targetModel: seriesModel, - coordSysType: 'cartesian2d', - coordSysProvider: coordSysProvider - }); - - function coordSysProvider() { - var axesModelMap = findAxisModels(seriesModel); - var xAxisModel = axesModelMap.xAxisModel; - var yAxisModel = axesModelMap.yAxisModel; - var gridModel = xAxisModel.getCoordSysModel(); - { - if (!gridModel) { - throw new Error('Grid "' + retrieve3(xAxisModel.get('gridIndex'), xAxisModel.get('gridId'), 0) + '" not found'); - } - - if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) { - throw new Error('xAxis and yAxis must use the same grid'); - } - } - var grid = gridModel.coordinateSystem; - return grid.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex); - } - }); - return grids; - }; // For deciding which dimensions to use when creating list data - - - Grid.dimensions = cartesian2DDimensions; - return Grid; - }(); - /** - * Check if the axis is used in the specified grid. - */ - - - function isAxisUsedInTheGrid(axisModel, gridModel) { - return axisModel.getCoordSysModel() === gridModel; - } - - function fixAxisOnZero(axesMap, otherAxisDim, axis, // Key: see `getOnZeroRecordKey` - onZeroRecords) { - axis.getAxesOnZeroOf = function () { - // TODO: onZero of multiple axes. - return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : []; - }; // onZero can not be enabled in these two situations: - // 1. When any other axis is a category axis. - // 2. When no axis is cross 0 point. - - - var otherAxes = axesMap[otherAxisDim]; - var otherAxisOnZeroOf; - var axisModel = axis.model; - var onZero = axisModel.get(['axisLine', 'onZero']); - var onZeroAxisIndex = axisModel.get(['axisLine', 'onZeroAxisIndex']); - - if (!onZero) { - return; - } // If target axis is specified. - - - if (onZeroAxisIndex != null) { - if (canOnZeroToAxis(otherAxes[onZeroAxisIndex])) { - otherAxisOnZeroOf = otherAxes[onZeroAxisIndex]; - } - } else { - // Find the first available other axis. - for (var idx in otherAxes) { - if (otherAxes.hasOwnProperty(idx) && canOnZeroToAxis(otherAxes[idx]) // Consider that two Y axes on one value axis, - // if both onZero, the two Y axes overlap. - && !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]) { - otherAxisOnZeroOf = otherAxes[idx]; - break; - } - } - } - - if (otherAxisOnZeroOf) { - onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true; - } - - function getOnZeroRecordKey(axis) { - return axis.dim + '_' + axis.index; - } - } - - function canOnZeroToAxis(axis) { - return axis && axis.type !== 'category' && axis.type !== 'time' && ifAxisCrossZero(axis); - } - - function updateAxisTransform(axis, coordBase) { - var axisExtent = axis.getExtent(); - var axisExtentSum = axisExtent[0] + axisExtent[1]; // Fast transform - - axis.toGlobalCoord = axis.dim === 'x' ? function (coord) { - return coord + coordBase; - } : function (coord) { - return axisExtentSum - coord + coordBase; - }; - axis.toLocalCoord = axis.dim === 'x' ? function (coord) { - return coord - coordBase; - } : function (coord) { - return axisExtentSum - coord + coordBase; - }; - } - - function updateAllAxisExtentTransByGridRect(axesMap, gridRect) { - each$4(axesMap.x, function (axis) { - return updateAxisExtentTransByGridRect(axis, gridRect.x, gridRect.width); - }); - each$4(axesMap.y, function (axis) { - return updateAxisExtentTransByGridRect(axis, gridRect.y, gridRect.height); - }); - } - - function updateAxisExtentTransByGridRect(axis, gridXY, gridWH) { - var extent = [0, gridWH]; - var idx = axis.inverse ? 1 : 0; - axis.setExtent(extent[idx], extent[1 - idx]); - updateAxisTransform(axis, gridXY); - } // Return noPxChange. - - - function layOutGridByOuterBounds(outerBoundsRect, outerBoundsContain, outerBoundsClamp, gridRect, axesMap, axisBuilderSharedCtx, layoutRef) { - { - assert(outerBoundsContain === 'all' || outerBoundsContain === 'axisLabel'); - } // Assume `updateAllAxisExtentTransByGridRect` has been performed once before this call. - // [NOTE]: - // - The bounding rect of the axis elements might be sensitve to variations in `axis.extent` due to strategies - // like hideOverlap/moveOverlap. @see the comment in `LabelLayoutBase['suggestIgnore']`. - // - The final `gridRect` might be slightly smaller than the ideally expected result if labels are giant and - // get hidden due to overlapping. More iterations could improve precision, but not performant. We consider - // the current result acceptable, since no alignment among charts can be guaranteed when using this feature. - - createOrUpdateAxesView(gridRect, axesMap, AxisTickLabelComputingKind.estimate, outerBoundsContain, false, layoutRef); - var margin = [0, 0, 0, 0]; - fillLabelNameOverflowOnOneDimension(0); - fillLabelNameOverflowOnOneDimension(1); // If axis is blank, no label can be used to detect overflow. - // gridRect itself should not overflow. - - fillMarginOnOneDimension(gridRect, 0, NaN); - fillMarginOnOneDimension(gridRect, 1, NaN); - var noPxChange = find(margin, function (item) { - return item > 0; - }) == null; - expandOrShrinkRect(gridRect, margin, true, true, outerBoundsClamp); - updateAllAxisExtentTransByGridRect(axesMap, gridRect); - return noPxChange; - - function fillLabelNameOverflowOnOneDimension(xyIdx) { - each$4(axesMap[XY$1[xyIdx]], function (axis) { - if (!shouldAxisShow(axis.model)) { - return; - } // FIXME: zr Group.union may wrongly union (0, 0, 0, 0) and not performant. - // unionRect.union(axis.axisBuilder.group.getBoundingRect()); - // If ussing Group.getBoundingRect to calculate shrink space, it is not strictly accurate when - // the outermost label is ignored and the secondary label is very long and contribute to the - // union extension: - // -|---|---|---| - // 1,000,000,000 - // Therefore we calculate them one by one. - // Also considered axis may be blank or no labels. - - - var sharedRecord = axisBuilderSharedCtx.ensureRecord(axis.model); - var labelInfoList = sharedRecord.labelInfoList; - - if (labelInfoList) { - for (var idx = 0; idx < labelInfoList.length; idx++) { - var labelInfo = labelInfoList[idx]; - var proportion = axis.scale.normalize(getLabelInner(labelInfo.label).tickValue); - proportion = xyIdx === 1 ? 1 - proportion : proportion; // xAxis use proportion on x, yAxis use proprotion on y, otherwise not. - - fillMarginOnOneDimension(labelInfo.rect, xyIdx, proportion); - fillMarginOnOneDimension(labelInfo.rect, 1 - xyIdx, NaN); - } - } - - var nameLayout = sharedRecord.nameLayout; - - if (nameLayout) { - var proportion = isNameLocationCenter(sharedRecord.nameLocation) ? 0.5 : NaN; - fillMarginOnOneDimension(nameLayout.rect, xyIdx, proportion); - fillMarginOnOneDimension(nameLayout.rect, 1 - xyIdx, NaN); - } - }); - } - - function fillMarginOnOneDimension(itemRect, xyIdx, proportion // NaN mean no use proportion - ) { - var overflow1 = outerBoundsRect[XY$1[xyIdx]] - itemRect[XY$1[xyIdx]]; - var overflow2 = itemRect[WH$1[xyIdx]] + itemRect[XY$1[xyIdx]] - (outerBoundsRect[WH$1[xyIdx]] + outerBoundsRect[XY$1[xyIdx]]); - overflow1 = applyProportion(overflow1, 1 - proportion); - overflow2 = applyProportion(overflow2, proportion); - var minIdx = XY_TO_MARGIN_IDX[xyIdx][0]; - var maxIdx = XY_TO_MARGIN_IDX[xyIdx][1]; - margin[minIdx] = mathMax$6(margin[minIdx], overflow1); - margin[maxIdx] = mathMax$6(margin[maxIdx], overflow2); - } - - function applyProportion(overflow, proportion) { - // proportion is not likely to near zero. If so, give up shrink - if (overflow > 0 && !eqNaN(proportion) && proportion > 1e-4) { - overflow /= proportion; - } - - return overflow; - } - } - - function createAxisBiulders(gridRect, cartesians, axesMap, optionContainLabel, api) { - var axisBuilderSharedCtx = new AxisBuilderSharedContext(resolveAxisNameOverlapForGrid); - each$4(axesMap, function (axisList) { - return each$4(axisList, function (axis) { - if (shouldAxisShow(axis.model)) { - // See `AxisBaseOptionCommon['nameMoveOverlap']`. - var defaultNameMoveOverlap = !optionContainLabel; - axis.axisBuilder = createCartesianAxisViewCommonPartBuilder(gridRect, cartesians, axis.model, api, axisBuilderSharedCtx, defaultNameMoveOverlap); - } - }); - }); - return axisBuilderSharedCtx; - } - /** - * Promote the axis-elements-building from "view render" stage to "coordinate system resize" stage. - * This is aimed to resovle overlap across multiple axes, since currently it's hard to reconcile - * multiple axes in "view render" stage. - * - * [CAUTION] But this promotion assumes that the subsequent "visual mapping" stage does not affect - * this axis-elements-building; otherwise we have to refactor it again. - */ - - - function createOrUpdateAxesView(gridRect, axesMap, kind, outerBoundsContain, noPxChange, layoutRef) { - var isDetermine = kind === AxisTickLabelComputingKind.determine; - each$4(axesMap, function (axisList) { - return each$4(axisList, function (axis) { - if (shouldAxisShow(axis.model)) { - updateCartesianAxisViewCommonPartBuilder(axis.axisBuilder, gridRect, axis.model); - axis.axisBuilder.build(isDetermine ? { - axisTickLabelDetermine: true - } : { - axisTickLabelEstimate: true - }, { - noPxChange: noPxChange - }); - } - }); - }); - var nameMarginLevelMap = { - x: 0, - y: 0 - }; - calcNameMarginLevel(0); - calcNameMarginLevel(1); - - function calcNameMarginLevel(xyIdx) { - nameMarginLevelMap[XY$1[1 - xyIdx]] = gridRect[WH$1[xyIdx]] <= layoutRef.refContainer[WH$1[xyIdx]] * 0.5 ? 0 : 1 - xyIdx === 1 ? 2 : 1; - } - - each$4(axesMap, function (axisList, xy) { - return each$4(axisList, function (axis) { - if (shouldAxisShow(axis.model)) { - if (outerBoundsContain === 'all' || isDetermine) { - // To resolve overlap, `axisName` layout depends on `axisTickLabel` layout result - // (all of the axes of the same `grid`; consider multiple x or y axes). - axis.axisBuilder.build({ - axisName: true - }, { - nameMarginLevel: nameMarginLevelMap[xy] - }); - } - - if (isDetermine) { - axis.axisBuilder.build({ - axisLine: true - }); - } - } - }); - }); - } - - function prepareOuterBounds(gridModel, rawRridRect, layoutRef) { - var outerBoundsRect; - var optionOuterBoundsMode = gridModel.get('outerBoundsMode', true); - - if (optionOuterBoundsMode === 'same') { - outerBoundsRect = rawRridRect.clone(); - } else if (optionOuterBoundsMode == null || optionOuterBoundsMode === 'auto') { - outerBoundsRect = getLayoutRect(gridModel.get('outerBounds', true) || OUTER_BOUNDS_DEFAULT, layoutRef.refContainer); - } else if (optionOuterBoundsMode !== 'none') { - { - error("Invalid grid[" + gridModel.componentIndex + "].outerBoundsMode."); - } - } - - var optionOuterBoundsContain = gridModel.get('outerBoundsContain', true); - var parsedOuterBoundsContain; - - if (optionOuterBoundsContain == null || optionOuterBoundsContain === 'auto') { - parsedOuterBoundsContain = 'all'; - } else if (indexOf(['all', 'axisLabel'], optionOuterBoundsContain) < 0) { - { - error("Invalid grid[" + gridModel.componentIndex + "].outerBoundsContain."); - } - parsedOuterBoundsContain = 'all'; - } else { - parsedOuterBoundsContain = optionOuterBoundsContain; - } - - var outerBoundsClamp = [parsePositionSizeOption(retrieve2(gridModel.get('outerBoundsClampWidth', true), OUTER_BOUNDS_CLAMP_DEFAULT[0]), rawRridRect.width), parsePositionSizeOption(retrieve2(gridModel.get('outerBoundsClampHeight', true), OUTER_BOUNDS_CLAMP_DEFAULT[1]), rawRridRect.height)]; - return { - outerBoundsRect: outerBoundsRect, - parsedOuterBoundsContain: parsedOuterBoundsContain, - outerBoundsClamp: outerBoundsClamp - }; - } - - var resolveAxisNameOverlapForGrid = function (cfg, ctx, axisModel, nameLayoutInfo, nameMoveDirVec, thisRecord) { - var perpendicularDim = axisModel.axis.dim === 'x' ? 'y' : 'x'; - resolveAxisNameOverlapDefault(cfg, ctx, axisModel, nameLayoutInfo, nameMoveDirVec, thisRecord); // If nameLocation 'center', and there are multiple axes parallel to this axis, do not adjust by - // other axes, because the axis name should be close to its axis line as much as possible even - // if overlapping; otherwise it might cause misleading. - // If nameLocation 'center', do not adjust by perpendicular axes, since they are not likely to overlap. - // If nameLocation 'start'/'end', move name within the same direction to escape overlap with the - // perpendicular axes. - - if (!isNameLocationCenter(cfg.nameLocation)) { - each$4(ctx.recordMap[perpendicularDim], function (perpenRecord) { - // perpendicular axis may be no name. - if (perpenRecord && perpenRecord.labelInfoList && perpenRecord.dirVec) { - moveIfOverlapByLinearLabels(perpenRecord.labelInfoList, perpenRecord.dirVec, nameLayoutInfo, nameMoveDirVec); - } - }); - } - }; // Build axisPointerModel, mergin tooltip.axisPointer model for each axis. - // allAxesInfo should be updated when setOption performed. - - - function collect(ecModel, api) { - var result = { - /** - * key: makeKey(axis.model) - * value: { - * axis, - * coordSys, - * axisPointerModel, - * triggerTooltip, - * triggerEmphasis, - * involveSeries, - * snap, - * seriesModels, - * seriesDataCount - * } - */ - axesInfo: {}, - seriesInvolved: false, - - /** - * key: makeKey(coordSys.model) - * value: Object: key makeKey(axis.model), value: axisInfo - */ - coordSysAxesInfo: {}, - coordSysMap: {} - }; - collectAxesInfo(result, ecModel, api); // Check seriesInvolved for performance, in case too many series in some chart. - - result.seriesInvolved && collectSeriesInfo(result, ecModel); - return result; - } - - function collectAxesInfo(result, ecModel, api) { - var globalTooltipModel = ecModel.getComponent('tooltip'); - var globalAxisPointerModel = ecModel.getComponent('axisPointer'); // links can only be set on global. - - var linksOption = globalAxisPointerModel.get('link', true) || []; - var linkGroups = []; // Collect axes info. - - each$4(api.getCoordinateSystems(), function (coordSys) { - // Some coordinate system do not support axes, like geo. - if (!coordSys.axisPointerEnabled) { - return; - } - - var coordSysKey = makeKey(coordSys.model); - var axesInfoInCoordSys = result.coordSysAxesInfo[coordSysKey] = {}; - result.coordSysMap[coordSysKey] = coordSys; // Set tooltip (like 'cross') is a convenient way to show axisPointer - // for user. So we enable setting tooltip on coordSys model. - - var coordSysModel = coordSys.model; - var baseTooltipModel = coordSysModel.getModel('tooltip', globalTooltipModel); - each$4(coordSys.getAxes(), curry$1(saveTooltipAxisInfo, false, null)); // If axis tooltip used, choose tooltip axis for each coordSys. - // Notice this case: coordSys is `grid` but not `cartesian2D` here. - - if (coordSys.getTooltipAxes && globalTooltipModel // If tooltip.showContent is set as false, tooltip will not - // show but axisPointer will show as normal. - && baseTooltipModel.get('show')) { - // Compatible with previous logic. But series.tooltip.trigger: 'axis' - // or series.data[n].tooltip.trigger: 'axis' are not support any more. - var triggerAxis = baseTooltipModel.get('trigger') === 'axis'; - var cross = baseTooltipModel.get(['axisPointer', 'type']) === 'cross'; - var tooltipAxes = coordSys.getTooltipAxes(baseTooltipModel.get(['axisPointer', 'axis'])); - - if (triggerAxis || cross) { - each$4(tooltipAxes.baseAxes, curry$1(saveTooltipAxisInfo, cross ? 'cross' : true, triggerAxis)); - } - - if (cross) { - each$4(tooltipAxes.otherAxes, curry$1(saveTooltipAxisInfo, 'cross', false)); - } - } // fromTooltip: true | false | 'cross' - // triggerTooltip: true | false | null - - - function saveTooltipAxisInfo(fromTooltip, triggerTooltip, axis) { - var axisPointerModel = axis.model.getModel('axisPointer', globalAxisPointerModel); - var axisPointerShow = axisPointerModel.get('show'); - - if (!axisPointerShow || axisPointerShow === 'auto' && !fromTooltip && !isHandleTrigger(axisPointerModel)) { - return; - } - - if (triggerTooltip == null) { - triggerTooltip = axisPointerModel.get('triggerTooltip'); - } - - axisPointerModel = fromTooltip ? makeAxisPointerModel(axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip) : axisPointerModel; - var snap = axisPointerModel.get('snap'); - var triggerEmphasis = axisPointerModel.get('triggerEmphasis'); - var axisKey = makeKey(axis.model); - var involveSeries = triggerTooltip || snap || axis.type === 'category'; // If result.axesInfo[key] exist, override it (tooltip has higher priority). - - var axisInfo = result.axesInfo[axisKey] = { - key: axisKey, - axis: axis, - coordSys: coordSys, - axisPointerModel: axisPointerModel, - triggerTooltip: triggerTooltip, - triggerEmphasis: triggerEmphasis, - involveSeries: involveSeries, - snap: snap, - useHandle: isHandleTrigger(axisPointerModel), - seriesModels: [], - linkGroup: null - }; - axesInfoInCoordSys[axisKey] = axisInfo; - result.seriesInvolved = result.seriesInvolved || involveSeries; - var groupIndex = getLinkGroupIndex(linksOption, axis); - - if (groupIndex != null) { - var linkGroup = linkGroups[groupIndex] || (linkGroups[groupIndex] = { - axesInfo: {} - }); - linkGroup.axesInfo[axisKey] = axisInfo; - linkGroup.mapper = linksOption[groupIndex].mapper; - axisInfo.linkGroup = linkGroup; - } - } - }); - } - - function makeAxisPointerModel(axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip) { - var tooltipAxisPointerModel = baseTooltipModel.getModel('axisPointer'); - var fields = ['type', 'snap', 'lineStyle', 'shadowStyle', 'label', 'animation', 'animationDurationUpdate', 'animationEasingUpdate', 'z']; - var volatileOption = {}; - each$4(fields, function (field) { - volatileOption[field] = clone$3(tooltipAxisPointerModel.get(field)); - }); // category axis do not auto snap, otherwise some tick that do not - // has value can not be hovered. value/time/log axis default snap if - // triggered from tooltip and trigger tooltip. - - volatileOption.snap = axis.type !== 'category' && !!triggerTooltip; // Compatible with previous behavior, tooltip axis does not show label by default. - // Only these properties can be overridden from tooltip to axisPointer. - - if (tooltipAxisPointerModel.get('type') === 'cross') { - volatileOption.type = 'line'; - } - - var labelOption = volatileOption.label || (volatileOption.label = {}); // Follow the convention, do not show label when triggered by tooltip by default. - - labelOption.show == null && (labelOption.show = false); - - if (fromTooltip === 'cross') { - // When 'cross', both axes show labels. - var tooltipAxisPointerLabelShow = tooltipAxisPointerModel.get(['label', 'show']); - labelOption.show = tooltipAxisPointerLabelShow != null ? tooltipAxisPointerLabelShow : true; // If triggerTooltip, this is a base axis, which should better not use cross style - // (cross style is dashed by default) - - if (!triggerTooltip) { - var crossStyle = volatileOption.lineStyle = tooltipAxisPointerModel.get('crossStyle'); - crossStyle && defaults(labelOption, crossStyle.textStyle); - } - } - - return axis.model.getModel('axisPointer', new Model(volatileOption, globalAxisPointerModel, ecModel)); - } - - function collectSeriesInfo(result, ecModel) { - // Prepare data for axis trigger - ecModel.eachSeries(function (seriesModel) { - // Notice this case: this coordSys is `cartesian2D` but not `grid`. - var coordSys = seriesModel.coordinateSystem; - var seriesTooltipTrigger = seriesModel.get(['tooltip', 'trigger'], true); - var seriesTooltipShow = seriesModel.get(['tooltip', 'show'], true); - - if (!coordSys || !coordSys.model // PENDING: radar do not have a model. - || seriesTooltipTrigger === 'none' || seriesTooltipTrigger === false || seriesTooltipTrigger === 'item' || seriesTooltipShow === false || seriesModel.get(['axisPointer', 'show'], true) === false) { - return; - } - - each$4(result.coordSysAxesInfo[makeKey(coordSys.model)], function (axisInfo) { - var axis = axisInfo.axis; - - if (coordSys.getAxis(axis.dim) === axis) { - axisInfo.seriesModels.push(seriesModel); - axisInfo.seriesDataCount == null && (axisInfo.seriesDataCount = 0); - axisInfo.seriesDataCount += seriesModel.getData().count(); - } - }); - }); - } - /** - * For example: - * { - * axisPointer: { - * links: [{ - * xAxisIndex: [2, 4], - * yAxisIndex: 'all' - * }, { - * xAxisId: ['a5', 'a7'], - * xAxisName: 'xxx' - * }] - * } - * } - */ - - - function getLinkGroupIndex(linksOption, axis) { - var axisModel = axis.model; - var dim = axis.dim; - - for (var i = 0; i < linksOption.length; i++) { - var linkOption = linksOption[i] || {}; - - if (checkPropInLink(linkOption[dim + 'AxisId'], axisModel.id) || checkPropInLink(linkOption[dim + 'AxisIndex'], axisModel.componentIndex) || checkPropInLink(linkOption[dim + 'AxisName'], axisModel.name)) { - return i; - } - } - } - - function checkPropInLink(linkPropValue, axisPropValue) { - return linkPropValue === 'all' || isArray(linkPropValue) && indexOf(linkPropValue, axisPropValue) >= 0 || linkPropValue === axisPropValue; - } - - function fixValue(axisModel) { - var axisInfo = getAxisInfo$1(axisModel); - - if (!axisInfo) { - return; - } - - var axisPointerModel = axisInfo.axisPointerModel; - var scale = axisInfo.axis.scale; - var option = axisPointerModel.option; - var status = axisPointerModel.get('status'); - var value = axisPointerModel.get('value'); // Parse init value for category and time axis. - - if (value != null) { - value = scale.parse(value); - } - - var useHandle = isHandleTrigger(axisPointerModel); // If `handle` used, `axisPointer` will always be displayed, so value - // and status should be initialized. - - if (status == null) { - option.status = useHandle ? 'show' : 'hide'; - } - - var extent = scale.getExtent().slice(); - extent[0] > extent[1] && extent.reverse(); - - if ( // Pick a value on axis when initializing. - value == null // If both `handle` and `dataZoom` are used, value may be out of axis extent, - // where we should re-pick a value to keep `handle` displaying normally. - || value > extent[1]) { - // Make handle displayed on the end of the axis when init, which looks better. - value = extent[1]; - } - - if (value < extent[0]) { - value = extent[0]; - } - - option.value = value; - - if (useHandle) { - option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show'; - } - } - - function getAxisInfo$1(axisModel) { - var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo; - return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)]; - } - - function getAxisPointerModel(axisModel) { - var axisInfo = getAxisInfo$1(axisModel); - return axisInfo && axisInfo.axisPointerModel; - } - - function isHandleTrigger(axisPointerModel) { - return !!axisPointerModel.get(['handle', 'show']); - } - /** - * @param {module:echarts/model/Model} model - * @return {string} unique key - */ - - - function makeKey(model) { - return model.type + '||' + model.id; - } - - var axisPointerClazz = {}; - /** - * Base class of AxisView. - */ - - var AxisView = - /** @class */ - function (_super) { - __extends(AxisView, _super); - - function AxisView() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = AxisView.type; - return _this; - } - /** - * @override - */ - - - AxisView.prototype.render = function (axisModel, ecModel, api, payload) { - // FIXME - // This process should proformed after coordinate systems updated - // (axis scale updated), and should be performed each time update. - // So put it here temporarily, although it is not appropriate to - // put a model-writing procedure in `view`. - this.axisPointerClass && fixValue(axisModel); - - _super.prototype.render.apply(this, arguments); - - this._doUpdateAxisPointerClass(axisModel, api, true); - }; - /** - * Action handler. - */ - - - AxisView.prototype.updateAxisPointer = function (axisModel, ecModel, api, payload) { - this._doUpdateAxisPointerClass(axisModel, api, false); - }; - /** - * @override - */ - - - AxisView.prototype.remove = function (ecModel, api) { - var axisPointer = this._axisPointer; - axisPointer && axisPointer.remove(api); - }; - /** - * @override - */ - - - AxisView.prototype.dispose = function (ecModel, api) { - this._disposeAxisPointer(api); - - _super.prototype.dispose.apply(this, arguments); - }; - - AxisView.prototype._doUpdateAxisPointerClass = function (axisModel, api, forceRender) { - var Clazz = AxisView.getAxisPointerClass(this.axisPointerClass); - - if (!Clazz) { - return; - } - - var axisPointerModel = getAxisPointerModel(axisModel); - axisPointerModel ? (this._axisPointer || (this._axisPointer = new Clazz())).render(axisModel, axisPointerModel, api, forceRender) : this._disposeAxisPointer(api); - }; - - AxisView.prototype._disposeAxisPointer = function (api) { - this._axisPointer && this._axisPointer.dispose(api); - this._axisPointer = null; - }; - - AxisView.registerAxisPointerClass = function (type, clazz) { - { - if (axisPointerClazz[type]) { - throw new Error('axisPointer ' + type + ' exists'); - } - } - axisPointerClazz[type] = clazz; - }; - - AxisView.getAxisPointerClass = function (type) { - return type && axisPointerClazz[type]; - }; - - AxisView.type = 'axis'; - return AxisView; - }(ComponentView); - - var inner$6 = makeInner(); - - function rectCoordAxisBuildSplitArea(axisView, axisGroup, axisModel, gridModel) { - var axis = axisModel.axis; - - if (axis.scale.isBlank()) { - return; - } // TODO: TYPE - - - var splitAreaModel = axisModel.getModel('splitArea'); - var areaStyleModel = splitAreaModel.getModel('areaStyle'); - var areaColors = areaStyleModel.get('color'); - var gridRect = gridModel.coordinateSystem.getRect(); - var ticksCoords = axis.getTicksCoords({ - tickModel: splitAreaModel, - clamp: true, - breakTicks: 'none', - pruneByBreak: 'preserve_extent_bound' - }); - - if (!ticksCoords.length) { - return; - } // For Making appropriate splitArea animation, the color and anid - // should be corresponding to previous one if possible. - - - var areaColorsLen = areaColors.length; - var lastSplitAreaColors = inner$6(axisView).splitAreaColors; - var newSplitAreaColors = createHashMap(); - var colorIndex = 0; - - if (lastSplitAreaColors) { - for (var i = 0; i < ticksCoords.length; i++) { - var cIndex = lastSplitAreaColors.get(ticksCoords[i].tickValue); - - if (cIndex != null) { - colorIndex = (cIndex + (areaColorsLen - 1) * i) % areaColorsLen; - break; - } - } - } - - var prev = axis.toGlobalCoord(ticksCoords[0].coord); - var areaStyle = areaStyleModel.getAreaStyle(); - areaColors = isArray(areaColors) ? areaColors : [areaColors]; - - for (var i = 1; i < ticksCoords.length; i++) { - var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord); - var x = void 0; - var y = void 0; - var width = void 0; - var height = void 0; - - if (axis.isHorizontal()) { - x = prev; - y = gridRect.y; - width = tickCoord - x; - height = gridRect.height; - prev = x + width; - } else { - x = gridRect.x; - y = prev; - width = gridRect.width; - height = tickCoord - y; - prev = y + height; - } - - var tickValue = ticksCoords[i - 1].tickValue; - tickValue != null && newSplitAreaColors.set(tickValue, colorIndex); - axisGroup.add(new Rect({ - anid: tickValue != null ? 'area_' + tickValue : null, - shape: { - x: x, - y: y, - width: width, - height: height - }, - style: defaults({ - fill: areaColors[colorIndex] - }, areaStyle), - autoBatch: true, - silent: true - })); - colorIndex = (colorIndex + 1) % areaColorsLen; - } - - inner$6(axisView).splitAreaColors = newSplitAreaColors; - } - - function rectCoordAxisHandleRemove(axisView) { - inner$6(axisView).splitAreaColors = null; - } - - var selfBuilderAttrs = ['splitArea', 'splitLine', 'minorSplitLine', 'breakArea']; - - var CartesianAxisView = - /** @class */ - function (_super) { - __extends(CartesianAxisView, _super); - - function CartesianAxisView() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = CartesianAxisView.type; - _this.axisPointerClass = 'CartesianAxisPointer'; - return _this; - } - /** - * @override - */ - - - CartesianAxisView.prototype.render = function (axisModel, ecModel, api, payload) { - this.group.removeAll(); - var oldAxisGroup = this._axisGroup; - this._axisGroup = new Group$2(); - this.group.add(this._axisGroup); - - if (!shouldAxisShow(axisModel)) { - return; - } - - this._axisGroup.add(axisModel.axis.axisBuilder.group); - - each$4(selfBuilderAttrs, function (name) { - if (axisModel.get([name, 'show'])) { - axisElementBuilders[name](this, this._axisGroup, axisModel, axisModel.getCoordSysModel(), api); - } - }, this); // THIS is a special case for bar racing chart. - // Update the axis label from the natural initial layout to - // sorted layout should has no animation. - - var isInitialSortFromBarRacing = payload && payload.type === 'changeAxisOrder' && payload.isInitSort; - - if (!isInitialSortFromBarRacing) { - groupTransition(oldAxisGroup, this._axisGroup, axisModel); - } - - _super.prototype.render.call(this, axisModel, ecModel, api, payload); - }; - - CartesianAxisView.prototype.remove = function () { - rectCoordAxisHandleRemove(this); - }; - - CartesianAxisView.type = 'cartesianAxis'; - return CartesianAxisView; - }(AxisView); - - var axisElementBuilders = { - splitLine: function (axisView, axisGroup, axisModel, gridModel, api) { - var axis = axisModel.axis; - - if (axis.scale.isBlank()) { - return; - } - - var splitLineModel = axisModel.getModel('splitLine'); - var lineStyleModel = splitLineModel.getModel('lineStyle'); - var lineColors = lineStyleModel.get('color'); - var showMinLine = splitLineModel.get('showMinLine') !== false; - var showMaxLine = splitLineModel.get('showMaxLine') !== false; - lineColors = isArray(lineColors) ? lineColors : [lineColors]; - var gridRect = gridModel.coordinateSystem.getRect(); - var isHorizontal = axis.isHorizontal(); - var lineCount = 0; - var ticksCoords = axis.getTicksCoords({ - tickModel: splitLineModel, - breakTicks: 'none', - pruneByBreak: 'preserve_extent_bound' - }); - var p1 = []; - var p2 = []; - var lineStyle = lineStyleModel.getLineStyle(); - - for (var i = 0; i < ticksCoords.length; i++) { - var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord); - - if (i === 0 && !showMinLine || i === ticksCoords.length - 1 && !showMaxLine) { - continue; - } - - var tickValue = ticksCoords[i].tickValue; - - if (isHorizontal) { - p1[0] = tickCoord; - p1[1] = gridRect.y; - p2[0] = tickCoord; - p2[1] = gridRect.y + gridRect.height; - } else { - p1[0] = gridRect.x; - p1[1] = tickCoord; - p2[0] = gridRect.x + gridRect.width; - p2[1] = tickCoord; - } - - var colorIndex = lineCount++ % lineColors.length; - var line = new Line({ - anid: tickValue != null ? 'line_' + tickValue : null, - autoBatch: true, - shape: { - x1: p1[0], - y1: p1[1], - x2: p2[0], - y2: p2[1] - }, - style: defaults({ - stroke: lineColors[colorIndex] - }, lineStyle), - silent: true - }); - subPixelOptimizeLine(line.shape, lineStyle.lineWidth); - axisGroup.add(line); - } - }, - minorSplitLine: function (axisView, axisGroup, axisModel, gridModel, api) { - var axis = axisModel.axis; - var minorSplitLineModel = axisModel.getModel('minorSplitLine'); - var lineStyleModel = minorSplitLineModel.getModel('lineStyle'); - var gridRect = gridModel.coordinateSystem.getRect(); - var isHorizontal = axis.isHorizontal(); - var minorTicksCoords = axis.getMinorTicksCoords(); - - if (!minorTicksCoords.length) { - return; - } - - var p1 = []; - var p2 = []; - var lineStyle = lineStyleModel.getLineStyle(); - - for (var i = 0; i < minorTicksCoords.length; i++) { - for (var k = 0; k < minorTicksCoords[i].length; k++) { - var tickCoord = axis.toGlobalCoord(minorTicksCoords[i][k].coord); - - if (isHorizontal) { - p1[0] = tickCoord; - p1[1] = gridRect.y; - p2[0] = tickCoord; - p2[1] = gridRect.y + gridRect.height; - } else { - p1[0] = gridRect.x; - p1[1] = tickCoord; - p2[0] = gridRect.x + gridRect.width; - p2[1] = tickCoord; - } - - var line = new Line({ - anid: 'minor_line_' + minorTicksCoords[i][k].tickValue, - autoBatch: true, - shape: { - x1: p1[0], - y1: p1[1], - x2: p2[0], - y2: p2[1] - }, - style: lineStyle, - silent: true - }); - subPixelOptimizeLine(line.shape, lineStyle.lineWidth); - axisGroup.add(line); - } - } - }, - splitArea: function (axisView, axisGroup, axisModel, gridModel, api) { - rectCoordAxisBuildSplitArea(axisView, axisGroup, axisModel, gridModel); - }, - breakArea: function (axisView, axisGroup, axisModel, gridModel, api) { - axisModel.axis.scale; - } - }; - - var CartesianXAxisView = - /** @class */ - function (_super) { - __extends(CartesianXAxisView, _super); - - function CartesianXAxisView() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = CartesianXAxisView.type; - return _this; - } - - CartesianXAxisView.type = 'xAxis'; - return CartesianXAxisView; - }(CartesianAxisView); - - var CartesianYAxisView = - /** @class */ - function (_super) { - __extends(CartesianYAxisView, _super); - - function CartesianYAxisView() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = CartesianXAxisView.type; - return _this; - } - - CartesianYAxisView.type = 'yAxis'; - return CartesianYAxisView; - }(CartesianAxisView); // Grid view - - - var GridView = - /** @class */ - function (_super) { - __extends(GridView, _super); - - function GridView() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = 'grid'; - return _this; - } - - GridView.prototype.render = function (gridModel, ecModel) { - this.group.removeAll(); - - if (gridModel.get('show')) { - this.group.add(new Rect({ - shape: gridModel.coordinateSystem.getRect(), - style: defaults({ - fill: gridModel.get('backgroundColor') - }, gridModel.getItemStyle()), - silent: true, - z2: -1 - })); - } - }; - - GridView.type = 'grid'; - return GridView; - }(ComponentView); - - var extraOption = { - // gridIndex: 0, - // gridId: '', - offset: 0 - }; - - function install$7(registers) { - registers.registerComponentView(GridView); - registers.registerComponentModel(GridModel); - registers.registerCoordinateSystem('cartesian2d', Grid); - axisModelCreator(registers, 'x', CartesianAxisModel, extraOption); - axisModelCreator(registers, 'y', CartesianAxisModel, extraOption); - registers.registerComponentView(CartesianXAxisView); - registers.registerComponentView(CartesianYAxisView); - registers.registerPreprocessor(function (option) { - // Only create grid when need - if (option.xAxis && option.yAxis && !option.grid) { - option.grid = {}; - } - }); - } - - use(install$7); - - var TitleModel = - /** @class */ - function (_super) { - __extends(TitleModel, _super); - - function TitleModel() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = TitleModel.type; - _this.layoutMode = { - type: 'box', - ignoreSize: true - }; - return _this; - } - - TitleModel.type = 'title'; - TitleModel.defaultOption = { - // zlevel: 0, - z: 6, - show: true, - text: '', - target: 'blank', - subtext: '', - subtarget: 'blank', - left: 'center', - top: tokens.size.m, - backgroundColor: tokens.color.transparent, - borderColor: tokens.color.primary, - borderWidth: 0, - padding: 5, - itemGap: 10, - textStyle: { - fontSize: 18, - fontWeight: 'bold', - color: tokens.color.primary - }, - subtextStyle: { - fontSize: 12, - color: tokens.color.quaternary - } - }; - return TitleModel; - }(ComponentModel); // View - - - var TitleView = - /** @class */ - function (_super) { - __extends(TitleView, _super); - - function TitleView() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = TitleView.type; - return _this; - } - - TitleView.prototype.render = function (titleModel, ecModel, api) { - this.group.removeAll(); - - if (!titleModel.get('show')) { - return; - } - - var group = this.group; - var textStyleModel = titleModel.getModel('textStyle'); - var subtextStyleModel = titleModel.getModel('subtextStyle'); - var textAlign = titleModel.get('textAlign'); - var textVerticalAlign = retrieve2(titleModel.get('textBaseline'), titleModel.get('textVerticalAlign')); - var textEl = new ZRText({ - style: createTextStyle$1(textStyleModel, { - text: titleModel.get('text'), - fill: textStyleModel.getTextColor() - }, { - disableBox: true - }), - z2: 10 - }); - var textRect = textEl.getBoundingRect(); - var subText = titleModel.get('subtext'); - var subTextEl = new ZRText({ - style: createTextStyle$1(subtextStyleModel, { - text: subText, - fill: subtextStyleModel.getTextColor(), - y: textRect.height + titleModel.get('itemGap'), - verticalAlign: 'top' - }, { - disableBox: true - }), - z2: 10 - }); - var link = titleModel.get('link'); - var sublink = titleModel.get('sublink'); - var triggerEvent = titleModel.get('triggerEvent', true); - textEl.silent = !link && !triggerEvent; - subTextEl.silent = !sublink && !triggerEvent; - - if (link) { - textEl.on('click', function () { - windowOpen(link, '_' + titleModel.get('target')); - }); - } - - if (sublink) { - subTextEl.on('click', function () { - windowOpen(sublink, '_' + titleModel.get('subtarget')); - }); - } - - getECData(textEl).eventData = getECData(subTextEl).eventData = triggerEvent ? { - componentType: 'title', - componentIndex: titleModel.componentIndex - } : null; - group.add(textEl); - subText && group.add(subTextEl); // If no subText, but add subTextEl, there will be an empty line. - - var groupRect = group.getBoundingRect(); - var layoutOption = titleModel.getBoxLayoutParams(); - layoutOption.width = groupRect.width; - layoutOption.height = groupRect.height; - var layoutRef = createBoxLayoutReference(titleModel, api); - var layoutRect = getLayoutRect(layoutOption, layoutRef.refContainer, titleModel.get('padding')); // Adjust text align based on position - - if (!textAlign) { - // Align left if title is on the left. center and right is same - textAlign = titleModel.get('left') || titleModel.get('right'); // @ts-ignore - - if (textAlign === 'middle') { - textAlign = 'center'; - } // Adjust layout by text align - - - if (textAlign === 'right') { - layoutRect.x += layoutRect.width; - } else if (textAlign === 'center') { - layoutRect.x += layoutRect.width / 2; - } - } - - if (!textVerticalAlign) { - textVerticalAlign = titleModel.get('top') || titleModel.get('bottom'); // @ts-ignore - - if (textVerticalAlign === 'center') { - textVerticalAlign = 'middle'; - } - - if (textVerticalAlign === 'bottom') { - layoutRect.y += layoutRect.height; - } else if (textVerticalAlign === 'middle') { - layoutRect.y += layoutRect.height / 2; - } - - textVerticalAlign = textVerticalAlign || 'top'; - } - - group.x = layoutRect.x; - group.y = layoutRect.y; - group.markRedraw(); - var alignStyle = { - align: textAlign, - verticalAlign: textVerticalAlign - }; - textEl.setStyle(alignStyle); - subTextEl.setStyle(alignStyle); // Render background - // Get groupRect again because textAlign has been changed - - groupRect = group.getBoundingRect(); - var padding = layoutRect.margin; - var style = titleModel.getItemStyle(['color', 'opacity']); - style.fill = titleModel.get('backgroundColor'); - var rect = new Rect({ - shape: { - x: groupRect.x - padding[3], - y: groupRect.y - padding[0], - width: groupRect.width + padding[1] + padding[3], - height: groupRect.height + padding[0] + padding[2], - r: titleModel.get('borderRadius') - }, - style: style, - subPixelOptimize: true, - silent: true - }); - group.add(rect); - }; - - TitleView.type = 'title'; - return TitleView; - }(ComponentView); - - function install$6(registers) { - registers.registerComponentModel(TitleModel); - registers.registerComponentView(TitleView); - } - - use(install$6); - - var getDefaultSelectorOptions = function (ecModel, type) { - if (type === 'all') { - return { - type: 'all', - title: ecModel.getLocaleModel().get(['legend', 'selector', 'all']) - }; - } else if (type === 'inverse') { - return { - type: 'inverse', - title: ecModel.getLocaleModel().get(['legend', 'selector', 'inverse']) - }; - } - }; - - var LegendModel = - /** @class */ - function (_super) { - __extends(LegendModel, _super); - - function LegendModel() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = LegendModel.type; - _this.layoutMode = { - type: 'box', - // legend.width/height are maxWidth/maxHeight actually, - // whereas real width/height is calculated by its content. - // (Setting {left: 10, right: 10} does not make sense). - // So consider the case: - // `setOption({legend: {left: 10});` - // then `setOption({legend: {right: 10});` - // The previous `left` should be cleared by setting `ignoreSize`. - ignoreSize: true - }; - return _this; - } - - LegendModel.prototype.init = function (option, parentModel, ecModel) { - this.mergeDefaultAndTheme(option, ecModel); - option.selected = option.selected || {}; - - this._updateSelector(option); - }; - - LegendModel.prototype.mergeOption = function (option, ecModel) { - _super.prototype.mergeOption.call(this, option, ecModel); - - this._updateSelector(option); - }; - - LegendModel.prototype._updateSelector = function (option) { - var selector = option.selector; - var ecModel = this.ecModel; - - if (selector === true) { - selector = option.selector = ['all', 'inverse']; - } - - if (isArray(selector)) { - each$4(selector, function (item, index) { - isString(item) && (item = { - type: item - }); - selector[index] = merge(item, getDefaultSelectorOptions(ecModel, item.type)); - }); - } - }; - - LegendModel.prototype.optionUpdated = function () { - this._updateData(this.ecModel); - - var legendData = this._data; // If selectedMode is single, try to select one - - if (legendData[0] && this.get('selectedMode') === 'single') { - var hasSelected = false; // If has any selected in option.selected - - for (var i = 0; i < legendData.length; i++) { - var name_1 = legendData[i].get('name'); - - if (this.isSelected(name_1)) { - // Force to unselect others - this.select(name_1); - hasSelected = true; - break; - } - } // Try select the first if selectedMode is single - - - !hasSelected && this.select(legendData[0].get('name')); - } - }; - - LegendModel.prototype._updateData = function (ecModel) { - var potentialData = []; - var availableNames = []; - ecModel.eachRawSeries(function (seriesModel) { - var seriesName = seriesModel.name; - availableNames.push(seriesName); - var isPotential; - - if (seriesModel.legendVisualProvider) { - var provider = seriesModel.legendVisualProvider; - var names = provider.getAllNames(); - - if (!ecModel.isSeriesFiltered(seriesModel)) { - availableNames = availableNames.concat(names); - } - - if (names.length) { - potentialData = potentialData.concat(names); - } else { - isPotential = true; - } - } else { - isPotential = true; - } - - if (isPotential && isNameSpecified(seriesModel)) { - potentialData.push(seriesModel.name); - } - }); - /** - * @type {Array.} - * @private - */ - - this._availableNames = availableNames; // If legend.data is not specified in option, use availableNames as data, - // which is convenient for user preparing option. - - var rawData = this.get('data') || potentialData; - var legendNameMap = createHashMap(); - var legendData = map$1(rawData, function (dataItem) { - // Can be string or number - if (isString(dataItem) || isNumber(dataItem)) { - dataItem = { - name: dataItem - }; - } - - if (legendNameMap.get(dataItem.name)) { - // remove legend name duplicate - return null; - } - - legendNameMap.set(dataItem.name, true); - return new Model(dataItem, this, this.ecModel); - }, this); - /** - * @type {Array.} - * @private - */ - - this._data = filter(legendData, function (item) { - return !!item; - }); - }; - - LegendModel.prototype.getData = function () { - return this._data; - }; - - LegendModel.prototype.select = function (name) { - var selected = this.option.selected; - var selectedMode = this.get('selectedMode'); - - if (selectedMode === 'single') { - var data = this._data; - each$4(data, function (dataItem) { - selected[dataItem.get('name')] = false; - }); - } - - selected[name] = true; - }; - - LegendModel.prototype.unSelect = function (name) { - if (this.get('selectedMode') !== 'single') { - this.option.selected[name] = false; - } - }; - - LegendModel.prototype.toggleSelected = function (name) { - var selected = this.option.selected; // Default is true - - if (!selected.hasOwnProperty(name)) { - selected[name] = true; - } - - this[selected[name] ? 'unSelect' : 'select'](name); - }; - - LegendModel.prototype.allSelect = function () { - var data = this._data; - var selected = this.option.selected; - each$4(data, function (dataItem) { - selected[dataItem.get('name', true)] = true; - }); - }; - - LegendModel.prototype.inverseSelect = function () { - var data = this._data; - var selected = this.option.selected; - each$4(data, function (dataItem) { - var name = dataItem.get('name', true); // Initially, default value is true - - if (!selected.hasOwnProperty(name)) { - selected[name] = true; - } - - selected[name] = !selected[name]; - }); - }; - - LegendModel.prototype.isSelected = function (name) { - var selected = this.option.selected; - return !(selected.hasOwnProperty(name) && !selected[name]) && indexOf(this._availableNames, name) >= 0; - }; - - LegendModel.prototype.getOrient = function () { - return this.get('orient') === 'vertical' ? { - index: 1, - name: 'vertical' - } : { - index: 0, - name: 'horizontal' - }; - }; - - LegendModel.type = 'legend.plain'; - LegendModel.dependencies = ['series']; - LegendModel.defaultOption = { - // zlevel: 0, - z: 4, - show: true, - orient: 'horizontal', - left: 'center', - // right: 'center', - // top: 0, - bottom: tokens.size.m, - align: 'auto', - backgroundColor: tokens.color.transparent, - borderColor: tokens.color.border, - borderRadius: 0, - borderWidth: 0, - padding: 5, - itemGap: 8, - itemWidth: 25, - itemHeight: 14, - symbolRotate: 'inherit', - symbolKeepAspect: true, - inactiveColor: tokens.color.disabled, - inactiveBorderColor: tokens.color.disabled, - inactiveBorderWidth: 'auto', - itemStyle: { - color: 'inherit', - opacity: 'inherit', - borderColor: 'inherit', - borderWidth: 'auto', - borderCap: 'inherit', - borderJoin: 'inherit', - borderDashOffset: 'inherit', - borderMiterLimit: 'inherit' - }, - lineStyle: { - width: 'auto', - color: 'inherit', - inactiveColor: tokens.color.disabled, - inactiveWidth: 2, - opacity: 'inherit', - type: 'inherit', - cap: 'inherit', - join: 'inherit', - dashOffset: 'inherit', - miterLimit: 'inherit' - }, - textStyle: { - color: tokens.color.secondary - }, - selectedMode: true, - selector: false, - selectorLabel: { - show: true, - borderRadius: 10, - padding: [3, 5, 3, 5], - fontSize: 12, - fontFamily: 'sans-serif', - color: tokens.color.tertiary, - borderWidth: 1, - borderColor: tokens.color.border - }, - emphasis: { - selectorLabel: { - show: true, - color: tokens.color.quaternary - } - }, - selectorPosition: 'auto', - selectorItemGap: 7, - selectorButtonGap: 10, - tooltip: { - show: false - }, - triggerEvent: false - }; - return LegendModel; - }(ComponentModel); - - function makeBackground(rect, componentModel) { - var padding = normalizeCssArray(componentModel.get('padding')); - var style = componentModel.getItemStyle(['color', 'opacity']); - style.fill = componentModel.get('backgroundColor'); - var bgRect = new Rect({ - shape: { - x: rect.x - padding[3], - y: rect.y - padding[0], - width: rect.width + padding[1] + padding[3], - height: rect.height + padding[0] + padding[2], - r: componentModel.get('borderRadius') - }, - style: style, - silent: true, - z2: -1 - }); // FIXME - // `subPixelOptimizeRect` may bring some gap between edge of viewpart - // and background rect when setting like `left: 0`, `top: 0`. - // graphic.subPixelOptimizeRect(rect); - - return bgRect; - } - - var curry = curry$1; - var each$1 = each$4; - var Group$1 = Group$2; - - var LegendView = - /** @class */ - function (_super) { - __extends(LegendView, _super); - - function LegendView() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = LegendView.type; - _this.newlineDisabled = false; - return _this; - } - - LegendView.prototype.init = function () { - this.group.add(this._contentGroup = new Group$1()); - this.group.add(this._selectorGroup = new Group$1()); - this._isFirstRender = true; - }; - /** - * @protected - */ - - - LegendView.prototype.getContentGroup = function () { - return this._contentGroup; - }; - /** - * @protected - */ - - - LegendView.prototype.getSelectorGroup = function () { - return this._selectorGroup; - }; - /** - * @override - */ - - - LegendView.prototype.render = function (legendModel, ecModel, api) { - var isFirstRender = this._isFirstRender; - this._isFirstRender = false; - this.resetInner(); - - if (!legendModel.get('show', true)) { - return; - } - - var itemAlign = legendModel.get('align'); - var orient = legendModel.get('orient'); - - if (!itemAlign || itemAlign === 'auto') { - itemAlign = legendModel.get('left') === 'right' && orient === 'vertical' ? 'right' : 'left'; - } // selector has been normalized to an array in model - - - var selector = legendModel.get('selector', true); - var selectorPosition = legendModel.get('selectorPosition', true); - - if (selector && (!selectorPosition || selectorPosition === 'auto')) { - selectorPosition = orient === 'horizontal' ? 'end' : 'start'; - } - - this.renderInner(itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition); // Perform layout. - - var refContainer = createBoxLayoutReference(legendModel, api).refContainer; - var positionInfo = legendModel.getBoxLayoutParams(); - var padding = legendModel.get('padding'); - var maxSize = getLayoutRect(positionInfo, refContainer, padding); - var mainRect = this.layoutInner(legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition); // Place mainGroup, based on the calculated `mainRect`. - - var layoutRect = getLayoutRect(defaults({ - width: mainRect.width, - height: mainRect.height - }, positionInfo), refContainer, padding); - this.group.x = layoutRect.x - mainRect.x; - this.group.y = layoutRect.y - mainRect.y; - this.group.markRedraw(); // Render background after group is layout. - - this.group.add(this._backgroundEl = makeBackground(mainRect, // FXIME: most itemStyle options does not work in background because inherit is not handled yet. - legendModel)); - }; - - LegendView.prototype.resetInner = function () { - this.getContentGroup().removeAll(); - this._backgroundEl && this.group.remove(this._backgroundEl); - this.getSelectorGroup().removeAll(); - }; - - LegendView.prototype.renderInner = function (itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition) { - var contentGroup = this.getContentGroup(); - var legendDrawnMap = createHashMap(); - var selectMode = legendModel.get('selectedMode'); - var triggerEvent = legendModel.get('triggerEvent'); - var excludeSeriesId = []; - ecModel.eachRawSeries(function (seriesModel) { - !seriesModel.get('legendHoverLink') && excludeSeriesId.push(seriesModel.id); - }); - each$1(legendModel.getData(), function (legendItemModel, dataIndex) { - var _this = this; - - var name = legendItemModel.get('name'); // Use empty string or \n as a newline string - - if (!this.newlineDisabled && (name === '' || name === '\n')) { - var g = new Group$1(); // @ts-ignore - - g.newline = true; - contentGroup.add(g); - return; - } // Representitive series. - - - var seriesModel = ecModel.getSeriesByName(name)[0]; - - if (legendDrawnMap.get(name)) { - // Have been drawn - return; - } // Legend to control series. - - - if (seriesModel) { - var data = seriesModel.getData(); - var lineVisualStyle = data.getVisual('legendLineStyle') || {}; - var legendIcon = data.getVisual('legendIcon'); - /** - * `data.getVisual('style')` may be the color from the register - * in series. For example, for line series, - */ - - var style = data.getVisual('style'); - - var itemGroup = this._createItem(seriesModel, name, dataIndex, legendItemModel, legendModel, itemAlign, lineVisualStyle, style, legendIcon, selectMode, api); - - itemGroup.on('click', curry(dispatchSelectAction, name, null, api, excludeSeriesId)).on('mouseover', curry(dispatchHighlightAction, seriesModel.name, null, api, excludeSeriesId)).on('mouseout', curry(dispatchDownplayAction, seriesModel.name, null, api, excludeSeriesId)); - - if (ecModel.ssr) { - itemGroup.eachChild(function (child) { - var ecData = getECData(child); - ecData.seriesIndex = seriesModel.seriesIndex; - ecData.dataIndex = dataIndex; - ecData.ssrType = 'legend'; - }); - } - - if (triggerEvent) { - itemGroup.eachChild(function (child) { - _this.packEventData(child, legendModel, seriesModel, dataIndex, name); - }); - } - - legendDrawnMap.set(name, true); - } else { - // Legend to control data. In pie and funnel. - ecModel.eachRawSeries(function (seriesModel) { - var _this = this; // In case multiple series has same data name - - - if (legendDrawnMap.get(name)) { - return; - } - - if (seriesModel.legendVisualProvider) { - var provider = seriesModel.legendVisualProvider; - - if (!provider.containName(name)) { - return; - } - - var idx = provider.indexOfName(name); - var style = provider.getItemVisual(idx, 'style'); - var legendIcon = provider.getItemVisual(idx, 'legendIcon'); - var colorArr = parse(style.fill); // Color may be set to transparent in visualMap when data is out of range. - // Do not show nothing. - - if (colorArr && colorArr[3] === 0) { - colorArr[3] = 0.2; // TODO color is set to 0, 0, 0, 0. Should show correct RGBA - - style = extend(extend({}, style), { - fill: stringify(colorArr, 'rgba') - }); - } - - var itemGroup = this._createItem(seriesModel, name, dataIndex, legendItemModel, legendModel, itemAlign, {}, style, legendIcon, selectMode, api); // FIXME: consider different series has items with the same name. - - - itemGroup.on('click', curry(dispatchSelectAction, null, name, api, excludeSeriesId)) // Should not specify the series name, consider legend controls - // more than one pie series. - .on('mouseover', curry(dispatchHighlightAction, null, name, api, excludeSeriesId)).on('mouseout', curry(dispatchDownplayAction, null, name, api, excludeSeriesId)); - - if (ecModel.ssr) { - itemGroup.eachChild(function (child) { - var ecData = getECData(child); - ecData.seriesIndex = seriesModel.seriesIndex; - ecData.dataIndex = dataIndex; - ecData.ssrType = 'legend'; - }); - } - - if (triggerEvent) { - itemGroup.eachChild(function (child) { - _this.packEventData(child, legendModel, seriesModel, dataIndex, name); - }); - } - - legendDrawnMap.set(name, true); - } - }, this); - } - - { - if (!legendDrawnMap.get(name)) { - console.warn(name + ' series not exists. Legend data should be same with series name or data name.'); - } - } - }, this); - - if (selector) { - this._createSelector(selector, legendModel, api, orient, selectorPosition); - } - }; - - LegendView.prototype.packEventData = function (el, legendModel, seriesModel, dataIndex, name) { - var eventData = { - componentType: 'legend', - componentIndex: legendModel.componentIndex, - dataIndex: dataIndex, - value: name, - seriesIndex: seriesModel.seriesIndex - }; - getECData(el).eventData = eventData; - }; - - LegendView.prototype._createSelector = function (selector, legendModel, api, orient, selectorPosition) { - var selectorGroup = this.getSelectorGroup(); - each$1(selector, function createSelectorButton(selectorItem) { - var type = selectorItem.type; - var labelText = new ZRText({ - style: { - x: 0, - y: 0, - align: 'center', - verticalAlign: 'middle' - }, - onclick: function () { - api.dispatchAction({ - type: type === 'all' ? 'legendAllSelect' : 'legendInverseSelect', - legendId: legendModel.id - }); - } - }); - selectorGroup.add(labelText); - var labelModel = legendModel.getModel('selectorLabel'); - var emphasisLabelModel = legendModel.getModel(['emphasis', 'selectorLabel']); - setLabelStyle(labelText, { - normal: labelModel, - emphasis: emphasisLabelModel - }, { - defaultText: selectorItem.title - }); - enableHoverEmphasis(labelText); - }); - }; - - LegendView.prototype._createItem = function (seriesModel, name, dataIndex, legendItemModel, legendModel, itemAlign, lineVisualStyle, itemVisualStyle, legendIcon, selectMode, api) { - var drawType = seriesModel.visualDrawType; - var itemWidth = legendModel.get('itemWidth'); - var itemHeight = legendModel.get('itemHeight'); - var isSelected = legendModel.isSelected(name); - var iconRotate = legendItemModel.get('symbolRotate'); - var symbolKeepAspect = legendItemModel.get('symbolKeepAspect'); - var legendIconType = legendItemModel.get('icon'); - legendIcon = legendIconType || legendIcon || 'roundRect'; - var style = getLegendStyle(legendIcon, legendItemModel, lineVisualStyle, itemVisualStyle, drawType, isSelected, api); - var itemGroup = new Group$1(); - var textStyleModel = legendItemModel.getModel('textStyle'); - - if (isFunction(seriesModel.getLegendIcon) && (!legendIconType || legendIconType === 'inherit')) { - // Series has specific way to define legend icon - itemGroup.add(seriesModel.getLegendIcon({ - itemWidth: itemWidth, - itemHeight: itemHeight, - icon: legendIcon, - iconRotate: iconRotate, - itemStyle: style.itemStyle, - lineStyle: style.lineStyle, - symbolKeepAspect: symbolKeepAspect - })); - } else { - // Use default legend icon policy for most series - var rotate = legendIconType === 'inherit' && seriesModel.getData().getVisual('symbol') ? iconRotate === 'inherit' ? seriesModel.getData().getVisual('symbolRotate') : iconRotate : 0; // No rotation for no icon - - itemGroup.add(getDefaultLegendIcon({ - itemWidth: itemWidth, - itemHeight: itemHeight, - icon: legendIcon, - iconRotate: rotate, - itemStyle: style.itemStyle, - lineStyle: style.lineStyle, - symbolKeepAspect: symbolKeepAspect - })); - } - - var textX = itemAlign === 'left' ? itemWidth + 5 : -5; - var textAlign = itemAlign; - var formatter = legendModel.get('formatter'); - var content = name; - - if (isString(formatter) && formatter) { - content = formatter.replace('{name}', name != null ? name : ''); - } else if (isFunction(formatter)) { - content = formatter(name); - } - - var textColor = isSelected ? textStyleModel.getTextColor() : legendItemModel.get('inactiveColor'); - itemGroup.add(new ZRText({ - style: createTextStyle$1(textStyleModel, { - text: content, - x: textX, - y: itemHeight / 2, - fill: textColor, - align: textAlign, - verticalAlign: 'middle' - }, { - inheritColor: textColor - }) - })); // Add a invisible rect to increase the area of mouse hover - - var hitRect = new Rect({ - shape: itemGroup.getBoundingRect(), - style: { - // Cannot use 'invisible' because SVG SSR will miss the node - fill: 'transparent' - } - }); - var tooltipModel = legendItemModel.getModel('tooltip'); - - if (tooltipModel.get('show')) { - setTooltipConfig({ - el: hitRect, - componentModel: legendModel, - itemName: name, - itemTooltipOption: tooltipModel.option - }); - } - - itemGroup.add(hitRect); - itemGroup.eachChild(function (child) { - child.silent = true; - }); - hitRect.silent = !selectMode; - this.getContentGroup().add(itemGroup); - enableHoverEmphasis(itemGroup); // @ts-ignore - - itemGroup.__legendDataIndex = dataIndex; - return itemGroup; - }; - - LegendView.prototype.layoutInner = function (legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition) { - var contentGroup = this.getContentGroup(); - var selectorGroup = this.getSelectorGroup(); // Place items in contentGroup. - - box(legendModel.get('orient'), contentGroup, legendModel.get('itemGap'), maxSize.width, maxSize.height); - var contentRect = contentGroup.getBoundingRect(); - var contentPos = [-contentRect.x, -contentRect.y]; - selectorGroup.markRedraw(); - contentGroup.markRedraw(); - - if (selector) { - // Place buttons in selectorGroup - box( // Buttons in selectorGroup always layout horizontally - 'horizontal', selectorGroup, legendModel.get('selectorItemGap', true)); - var selectorRect = selectorGroup.getBoundingRect(); - var selectorPos = [-selectorRect.x, -selectorRect.y]; - var selectorButtonGap = legendModel.get('selectorButtonGap', true); - var orientIdx = legendModel.getOrient().index; - var wh = orientIdx === 0 ? 'width' : 'height'; - var hw = orientIdx === 0 ? 'height' : 'width'; - var yx = orientIdx === 0 ? 'y' : 'x'; - - if (selectorPosition === 'end') { - selectorPos[orientIdx] += contentRect[wh] + selectorButtonGap; - } else { - contentPos[orientIdx] += selectorRect[wh] + selectorButtonGap; - } // Always align selector to content as 'middle' - - - selectorPos[1 - orientIdx] += contentRect[hw] / 2 - selectorRect[hw] / 2; - selectorGroup.x = selectorPos[0]; - selectorGroup.y = selectorPos[1]; - contentGroup.x = contentPos[0]; - contentGroup.y = contentPos[1]; - var mainRect = { - x: 0, - y: 0 - }; - mainRect[wh] = contentRect[wh] + selectorButtonGap + selectorRect[wh]; - mainRect[hw] = Math.max(contentRect[hw], selectorRect[hw]); - mainRect[yx] = Math.min(0, selectorRect[yx] + selectorPos[1 - orientIdx]); - return mainRect; - } else { - contentGroup.x = contentPos[0]; - contentGroup.y = contentPos[1]; - return this.group.getBoundingRect(); - } - }; - /** - * @protected - */ - - - LegendView.prototype.remove = function () { - this.getContentGroup().removeAll(); - this._isFirstRender = true; - }; - - LegendView.type = 'legend.plain'; - return LegendView; - }(ComponentView); - - function getLegendStyle(iconType, legendItemModel, lineVisualStyle, itemVisualStyle, drawType, isSelected, api) { - /** - * Use series style if is inherit; - * elsewise, use legend style - */ - function handleCommonProps(style, visualStyle) { - // If lineStyle.width is 'auto', it is set to be 2 if series has border - if (style.lineWidth === 'auto') { - style.lineWidth = visualStyle.lineWidth > 0 ? 2 : 0; - } - - each$1(style, function (propVal, propName) { - style[propName] === 'inherit' && (style[propName] = visualStyle[propName]); - }); - } // itemStyle - - - var itemStyleModel = legendItemModel.getModel('itemStyle'); - var itemStyle = itemStyleModel.getItemStyle(); - var iconBrushType = iconType.lastIndexOf('empty', 0) === 0 ? 'fill' : 'stroke'; - var decalStyle = itemStyleModel.getShallow('decal'); - itemStyle.decal = !decalStyle || decalStyle === 'inherit' ? itemVisualStyle.decal : createOrUpdatePatternFromDecal(decalStyle, api); - - if (itemStyle.fill === 'inherit') { - /** - * Series with visualDrawType as 'stroke' should have - * series stroke as legend fill - */ - itemStyle.fill = itemVisualStyle[drawType]; - } - - if (itemStyle.stroke === 'inherit') { - /** - * icon type with "emptyXXX" should use fill color - * in visual style - */ - itemStyle.stroke = itemVisualStyle[iconBrushType]; - } - - if (itemStyle.opacity === 'inherit') { - /** - * Use lineStyle.opacity if drawType is stroke - */ - itemStyle.opacity = (drawType === 'fill' ? itemVisualStyle : lineVisualStyle).opacity; - } - - handleCommonProps(itemStyle, itemVisualStyle); // lineStyle - - var legendLineModel = legendItemModel.getModel('lineStyle'); - var lineStyle = legendLineModel.getLineStyle(); - handleCommonProps(lineStyle, lineVisualStyle); // Fix auto color to real color - - itemStyle.fill === 'auto' && (itemStyle.fill = itemVisualStyle.fill); - itemStyle.stroke === 'auto' && (itemStyle.stroke = itemVisualStyle.fill); - lineStyle.stroke === 'auto' && (lineStyle.stroke = itemVisualStyle.fill); - - if (!isSelected) { - var borderWidth = legendItemModel.get('inactiveBorderWidth'); - /** - * Since stroke is set to be inactiveBorderColor, it may occur that - * there is no border in series but border in legend, so we need to - * use border only when series has border if is set to be auto - */ - - var visualHasBorder = itemStyle[iconBrushType]; - itemStyle.lineWidth = borderWidth === 'auto' ? itemVisualStyle.lineWidth > 0 && visualHasBorder ? 2 : 0 : itemStyle.lineWidth; - itemStyle.fill = legendItemModel.get('inactiveColor'); - itemStyle.stroke = legendItemModel.get('inactiveBorderColor'); - lineStyle.stroke = legendLineModel.get('inactiveColor'); - lineStyle.lineWidth = legendLineModel.get('inactiveWidth'); - } - - return { - itemStyle: itemStyle, - lineStyle: lineStyle - }; - } - - function getDefaultLegendIcon(opt) { - var symboType = opt.icon || 'roundRect'; - var icon = createSymbol(symboType, 0, 0, opt.itemWidth, opt.itemHeight, opt.itemStyle.fill, opt.symbolKeepAspect); - icon.setStyle(opt.itemStyle); - icon.rotation = (opt.iconRotate || 0) * Math.PI / 180; - icon.setOrigin([opt.itemWidth / 2, opt.itemHeight / 2]); - - if (symboType.indexOf('empty') > -1) { - icon.style.stroke = icon.style.fill; - icon.style.fill = tokens.color.neutral00; - icon.style.lineWidth = 2; - } - - return icon; - } - - function dispatchSelectAction(seriesName, dataName, api, excludeSeriesId) { - // downplay before unselect - dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId); - api.dispatchAction({ - type: 'legendToggleSelect', - name: seriesName != null ? seriesName : dataName - }); // highlight after select - // TODO highlight immediately may cause animation loss. - - dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId); - } - - function isUseHoverLayer(api) { - var list = api.getZr().storage.getDisplayList(); - var emphasisState; - var i = 0; - var len = list.length; - - while (i < len && !(emphasisState = list[i].states.emphasis)) { - i++; - } - - return emphasisState && emphasisState.hoverLayer; - } - - function dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId) { - // If element hover will move to a hoverLayer. - if (!isUseHoverLayer(api)) { - api.dispatchAction({ - type: 'highlight', - seriesName: seriesName, - name: dataName, - excludeSeriesId: excludeSeriesId - }); - } - } - - function dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId) { - // If element hover will move to a hoverLayer. - if (!isUseHoverLayer(api)) { - api.dispatchAction({ - type: 'downplay', - seriesName: seriesName, - name: dataName, - excludeSeriesId: excludeSeriesId - }); - } - } - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * AUTO-GENERATED FILE. DO NOT MODIFY. - */ - - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - - function legendFilter(ecModel) { - var legendModels = ecModel.findComponents({ - mainType: 'legend' - }); - - if (legendModels && legendModels.length) { - ecModel.filterSeries(function (series) { - // If in any legend component the status is not selected. - // Because in legend series is assumed selected when it is not in the legend data. - for (var i = 0; i < legendModels.length; i++) { - if (!legendModels[i].isSelected(series.name)) { - return false; - } - } - - return true; - }); - } - } - - function legendSelectActionHandler(methodName, payload, ecModel) { - var isAllSelect = methodName === 'allSelect' || methodName === 'inverseSelect'; - var selectedMap = {}; - var actionLegendIndices = []; - ecModel.eachComponent({ - mainType: 'legend', - query: payload - }, function (legendModel) { - if (isAllSelect) { - legendModel[methodName](); - } else { - legendModel[methodName](payload.name); - } - - makeSelectedMap(legendModel, selectedMap); - actionLegendIndices.push(legendModel.componentIndex); - }); - var allSelectedMap = {}; // make selectedMap from all legend components - - ecModel.eachComponent('legend', function (legendModel) { - each$4(selectedMap, function (isSelected, name) { - // Force other legend has same selected status - // Or the first is toggled to true and other are toggled to false - // In the case one legend has some item unSelected in option. And if other legend - // doesn't has the item, they will assume it is selected. - legendModel[isSelected ? 'select' : 'unSelect'](name); - }); - makeSelectedMap(legendModel, allSelectedMap); - }); // Return the event explicitly - - return isAllSelect ? { - selected: allSelectedMap, - // return legendIndex array to tell the developers which legends are allSelect / inverseSelect - legendIndex: actionLegendIndices - } : { - name: payload.name, - selected: allSelectedMap - }; - } - - function makeSelectedMap(legendModel, out) { - var selectedMap = out || {}; - each$4(legendModel.getData(), function (model) { - var name = model.get('name'); // Wrap element - - if (name === '\n' || name === '') { - return; - } - - var isItemSelected = legendModel.isSelected(name); - - if (hasOwn(selectedMap, name)) { - // Unselected if any legend is unselected - selectedMap[name] = selectedMap[name] && isItemSelected; - } else { - selectedMap[name] = isItemSelected; - } - }); - return selectedMap; - } - - function installLegendAction(registers) { - /** - * @event legendToggleSelect - * @type {Object} - * @property {string} type 'legendToggleSelect' - * @property {string} [from] - * @property {string} name Series name or data item name - */ - registers.registerAction('legendToggleSelect', 'legendselectchanged', curry$1(legendSelectActionHandler, 'toggleSelected')); - registers.registerAction('legendAllSelect', 'legendselectall', curry$1(legendSelectActionHandler, 'allSelect')); - registers.registerAction('legendInverseSelect', 'legendinverseselect', curry$1(legendSelectActionHandler, 'inverseSelect')); - /** - * @event legendSelect - * @type {Object} - * @property {string} type 'legendSelect' - * @property {string} name Series name or data item name - */ - - registers.registerAction('legendSelect', 'legendselected', curry$1(legendSelectActionHandler, 'select')); - /** - * @event legendUnSelect - * @type {Object} - * @property {string} type 'legendUnSelect' - * @property {string} name Series name or data item name - */ - - registers.registerAction('legendUnSelect', 'legendunselected', curry$1(legendSelectActionHandler, 'unSelect')); - } - - function install$5(registers) { - registers.registerComponentModel(LegendModel); - registers.registerComponentView(LegendView); - registers.registerProcessor(registers.PRIORITY.PROCESSOR.SERIES_FILTER, legendFilter); - registers.registerSubTypeDefaulter('legend', function () { - return 'plain'; - }); - installLegendAction(registers); - } - - var ScrollableLegendModel = - /** @class */ - function (_super) { - __extends(ScrollableLegendModel, _super); - - function ScrollableLegendModel() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = ScrollableLegendModel.type; - return _this; - } - /** - * @param {number} scrollDataIndex - */ - - - ScrollableLegendModel.prototype.setScrollDataIndex = function (scrollDataIndex) { - this.option.scrollDataIndex = scrollDataIndex; - }; - - ScrollableLegendModel.prototype.init = function (option, parentModel, ecModel) { - var inputPositionParams = getLayoutParams(option); - - _super.prototype.init.call(this, option, parentModel, ecModel); - - mergeAndNormalizeLayoutParams(this, option, inputPositionParams); - }; - /** - * @override - */ - - - ScrollableLegendModel.prototype.mergeOption = function (option, ecModel) { - _super.prototype.mergeOption.call(this, option, ecModel); - - mergeAndNormalizeLayoutParams(this, this.option, option); - }; - - ScrollableLegendModel.type = 'legend.scroll'; - ScrollableLegendModel.defaultOption = inheritDefaultOption(LegendModel.defaultOption, { - scrollDataIndex: 0, - pageButtonItemGap: 5, - pageButtonGap: null, - pageButtonPosition: 'end', - pageFormatter: '{current}/{total}', - pageIcons: { - horizontal: ['M0,0L12,-10L12,10z', 'M0,0L-12,-10L-12,10z'], - vertical: ['M0,0L20,0L10,-20z', 'M0,0L20,0L10,20z'] - }, - pageIconColor: tokens.color.accent50, - pageIconInactiveColor: tokens.color.accent10, - pageIconSize: 15, - pageTextStyle: { - color: tokens.color.tertiary - }, - animationDurationUpdate: 800 - }); - return ScrollableLegendModel; - }(LegendModel); // Do not `ignoreSize` to enable setting {left: 10, right: 10}. - - - function mergeAndNormalizeLayoutParams(legendModel, target, raw) { - var orient = legendModel.getOrient(); - var ignoreSize = [1, 1]; - ignoreSize[orient.index] = 0; - mergeLayoutParam(target, raw, { - type: 'box', - ignoreSize: !!ignoreSize - }); - } - - var Group = Group$2; - var WH = ['width', 'height']; - var XY = ['x', 'y']; - - var ScrollableLegendView = - /** @class */ - function (_super) { - __extends(ScrollableLegendView, _super); - - function ScrollableLegendView() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = ScrollableLegendView.type; - _this.newlineDisabled = true; - _this._currentIndex = 0; - return _this; - } - - ScrollableLegendView.prototype.init = function () { - _super.prototype.init.call(this); - - this.group.add(this._containerGroup = new Group()); - - this._containerGroup.add(this.getContentGroup()); - - this.group.add(this._controllerGroup = new Group()); - }; - /** - * @override - */ - - - ScrollableLegendView.prototype.resetInner = function () { - _super.prototype.resetInner.call(this); - - this._controllerGroup.removeAll(); - - this._containerGroup.removeClipPath(); - - this._containerGroup.__rectSize = null; - }; - /** - * @override - */ - - - ScrollableLegendView.prototype.renderInner = function (itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition) { - var self = this; // Render content items. - - _super.prototype.renderInner.call(this, itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition); - - var controllerGroup = this._controllerGroup; // FIXME: support be 'auto' adapt to size number text length, - // e.g., '3/12345' should not overlap with the control arrow button. - - var pageIconSize = legendModel.get('pageIconSize', true); - var pageIconSizeArr = isArray(pageIconSize) ? pageIconSize : [pageIconSize, pageIconSize]; - createPageButton('pagePrev', 0); - var pageTextStyleModel = legendModel.getModel('pageTextStyle'); - controllerGroup.add(new ZRText({ - name: 'pageText', - style: { - // Placeholder to calculate a proper layout. - text: 'xx/xx', - fill: pageTextStyleModel.getTextColor(), - font: pageTextStyleModel.getFont(), - verticalAlign: 'middle', - align: 'center' - }, - silent: true - })); - createPageButton('pageNext', 1); - - function createPageButton(name, iconIdx) { - var pageDataIndexName = name + 'DataIndex'; - var icon = createIcon(legendModel.get('pageIcons', true)[legendModel.getOrient().name][iconIdx], { - // Buttons will be created in each render, so we do not need - // to worry about avoiding using legendModel kept in scope. - onclick: bind$1(self._pageGo, self, pageDataIndexName, legendModel, api) - }, { - x: -pageIconSizeArr[0] / 2, - y: -pageIconSizeArr[1] / 2, - width: pageIconSizeArr[0], - height: pageIconSizeArr[1] - }); - icon.name = name; - controllerGroup.add(icon); - } - }; - /** - * @override - */ - - - ScrollableLegendView.prototype.layoutInner = function (legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition) { - var selectorGroup = this.getSelectorGroup(); - var orientIdx = legendModel.getOrient().index; - var wh = WH[orientIdx]; - var xy = XY[orientIdx]; - var hw = WH[1 - orientIdx]; - var yx = XY[1 - orientIdx]; - selector && box( // Buttons in selectorGroup always layout horizontally - 'horizontal', selectorGroup, legendModel.get('selectorItemGap', true)); - var selectorButtonGap = legendModel.get('selectorButtonGap', true); - var selectorRect = selectorGroup.getBoundingRect(); - var selectorPos = [-selectorRect.x, -selectorRect.y]; - var processMaxSize = clone$3(maxSize); - selector && (processMaxSize[wh] = maxSize[wh] - selectorRect[wh] - selectorButtonGap); - - var mainRect = this._layoutContentAndController(legendModel, isFirstRender, processMaxSize, orientIdx, wh, hw, yx, xy); - - if (selector) { - if (selectorPosition === 'end') { - selectorPos[orientIdx] += mainRect[wh] + selectorButtonGap; - } else { - var offset = selectorRect[wh] + selectorButtonGap; - selectorPos[orientIdx] -= offset; - mainRect[xy] -= offset; - } - - mainRect[wh] += selectorRect[wh] + selectorButtonGap; - selectorPos[1 - orientIdx] += mainRect[yx] + mainRect[hw] / 2 - selectorRect[hw] / 2; - mainRect[hw] = Math.max(mainRect[hw], selectorRect[hw]); - mainRect[yx] = Math.min(mainRect[yx], selectorRect[yx] + selectorPos[1 - orientIdx]); - selectorGroup.x = selectorPos[0]; - selectorGroup.y = selectorPos[1]; - selectorGroup.markRedraw(); - } - - return mainRect; - }; - - ScrollableLegendView.prototype._layoutContentAndController = function (legendModel, isFirstRender, maxSize, orientIdx, wh, hw, yx, xy) { - var contentGroup = this.getContentGroup(); - var containerGroup = this._containerGroup; - var controllerGroup = this._controllerGroup; // Place items in contentGroup. - - box(legendModel.get('orient'), contentGroup, legendModel.get('itemGap'), !orientIdx ? null : maxSize.width, orientIdx ? null : maxSize.height); - box( // Buttons in controller are layout always horizontally. - 'horizontal', controllerGroup, legendModel.get('pageButtonItemGap', true)); - var contentRect = contentGroup.getBoundingRect(); - var controllerRect = controllerGroup.getBoundingRect(); - var showController = this._showController = contentRect[wh] > maxSize[wh]; // In case that the inner elements of contentGroup layout do not based on [0, 0] - - var contentPos = [-contentRect.x, -contentRect.y]; // Remain contentPos when scroll animation perfroming. - // If first rendering, `contentGroup.position` is [0, 0], which - // does not make sense and may cause unexepcted animation if adopted. - - if (!isFirstRender) { - contentPos[orientIdx] = contentGroup[xy]; - } // Layout container group based on 0. - - - var containerPos = [0, 0]; - var controllerPos = [-controllerRect.x, -controllerRect.y]; - var pageButtonGap = retrieve2(legendModel.get('pageButtonGap', true), legendModel.get('itemGap', true)); // Place containerGroup and controllerGroup and contentGroup. - - if (showController) { - var pageButtonPosition = legendModel.get('pageButtonPosition', true); // controller is on the right / bottom. - - if (pageButtonPosition === 'end') { - controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh]; - } // controller is on the left / top. - else { - containerPos[orientIdx] += controllerRect[wh] + pageButtonGap; - } - } // Always align controller to content as 'middle'. - - - controllerPos[1 - orientIdx] += contentRect[hw] / 2 - controllerRect[hw] / 2; - contentGroup.setPosition(contentPos); - containerGroup.setPosition(containerPos); - controllerGroup.setPosition(controllerPos); // Calculate `mainRect` and set `clipPath`. - // mainRect should not be calculated by `this.group.getBoundingRect()` - // for sake of the overflow. - - var mainRect = { - x: 0, - y: 0 - }; // Consider content may be overflow (should be clipped). - - mainRect[wh] = showController ? maxSize[wh] : contentRect[wh]; - mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw]); // `containerRect[yx] + containerPos[1 - orientIdx]` is 0. - - mainRect[yx] = Math.min(0, controllerRect[yx] + controllerPos[1 - orientIdx]); - containerGroup.__rectSize = maxSize[wh]; - - if (showController) { - var clipShape = { - x: 0, - y: 0 - }; - clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap, 0); - clipShape[hw] = mainRect[hw]; - containerGroup.setClipPath(new Rect({ - shape: clipShape - })); // Consider content may be larger than container, container rect - // can not be obtained from `containerGroup.getBoundingRect()`. - - containerGroup.__rectSize = clipShape[wh]; - } else { - // Do not remove or ignore controller. Keep them set as placeholders. - controllerGroup.eachChild(function (child) { - child.attr({ - invisible: true, - silent: true - }); - }); - } // Content translate animation. - - - var pageInfo = this._getPageInfo(legendModel); - - pageInfo.pageIndex != null && updateProps$1(contentGroup, { - x: pageInfo.contentPosition[0], - y: pageInfo.contentPosition[1] - }, // When switch from "show controller" to "not show controller", view should be - // updated immediately without animation, otherwise causes weird effect. - showController ? legendModel : null); - - this._updatePageInfoView(legendModel, pageInfo); - - return mainRect; - }; - - ScrollableLegendView.prototype._pageGo = function (to, legendModel, api) { - var scrollDataIndex = this._getPageInfo(legendModel)[to]; - - scrollDataIndex != null && api.dispatchAction({ - type: 'legendScroll', - scrollDataIndex: scrollDataIndex, - legendId: legendModel.id - }); - }; - - ScrollableLegendView.prototype._updatePageInfoView = function (legendModel, pageInfo) { - var controllerGroup = this._controllerGroup; - each$4(['pagePrev', 'pageNext'], function (name) { - var key = name + 'DataIndex'; - var canJump = pageInfo[key] != null; - var icon = controllerGroup.childOfName(name); - - if (icon) { - icon.setStyle('fill', canJump ? legendModel.get('pageIconColor', true) : legendModel.get('pageIconInactiveColor', true)); - icon.cursor = canJump ? 'pointer' : 'default'; - } - }); - var pageText = controllerGroup.childOfName('pageText'); - var pageFormatter = legendModel.get('pageFormatter'); - var pageIndex = pageInfo.pageIndex; - var current = pageIndex != null ? pageIndex + 1 : 0; - var total = pageInfo.pageCount; - pageText && pageFormatter && pageText.setStyle('text', isString(pageFormatter) ? pageFormatter.replace('{current}', current == null ? '' : current + '').replace('{total}', total == null ? '' : total + '') : pageFormatter({ - current: current, - total: total - })); - }; - /** - * contentPosition: Array., null when data item not found. - * pageIndex: number, null when data item not found. - * pageCount: number, always be a number, can be 0. - * pagePrevDataIndex: number, null when no previous page. - * pageNextDataIndex: number, null when no next page. - * } - */ - - - ScrollableLegendView.prototype._getPageInfo = function (legendModel) { - var scrollDataIndex = legendModel.get('scrollDataIndex', true); - var contentGroup = this.getContentGroup(); - var containerRectSize = this._containerGroup.__rectSize; - var orientIdx = legendModel.getOrient().index; - var wh = WH[orientIdx]; - var xy = XY[orientIdx]; - - var targetItemIndex = this._findTargetItemIndex(scrollDataIndex); - - var children = contentGroup.children(); - var targetItem = children[targetItemIndex]; - var itemCount = children.length; - var pCount = !itemCount ? 0 : 1; - var result = { - contentPosition: [contentGroup.x, contentGroup.y], - pageCount: pCount, - pageIndex: pCount - 1, - pagePrevDataIndex: null, - pageNextDataIndex: null - }; - - if (!targetItem) { - return result; - } - - var targetItemInfo = getItemInfo(targetItem); - result.contentPosition[orientIdx] = -targetItemInfo.s; // Strategy: - // (1) Always align based on the left/top most item. - // (2) It is user-friendly that the last item shown in the - // current window is shown at the begining of next window. - // Otherwise if half of the last item is cut by the window, - // it will have no chance to display entirely. - // (3) Consider that item size probably be different, we - // have calculate pageIndex by size rather than item index, - // and we can not get page index directly by division. - // (4) The window is to narrow to contain more than - // one item, we should make sure that the page can be fliped. - - for (var i = targetItemIndex + 1, winStartItemInfo = targetItemInfo, winEndItemInfo = targetItemInfo, currItemInfo = null; i <= itemCount; ++i) { - currItemInfo = getItemInfo(children[i]); - - if ( // Half of the last item is out of the window. - !currItemInfo && winEndItemInfo.e > winStartItemInfo.s + containerRectSize // If the current item does not intersect with the window, the new page - // can be started at the current item or the last item. - || currItemInfo && !intersect(currItemInfo, winStartItemInfo.s)) { - if (winEndItemInfo.i > winStartItemInfo.i) { - winStartItemInfo = winEndItemInfo; - } else { - // e.g., when page size is smaller than item size. - winStartItemInfo = currItemInfo; - } - - if (winStartItemInfo) { - if (result.pageNextDataIndex == null) { - result.pageNextDataIndex = winStartItemInfo.i; - } - - ++result.pageCount; - } - } - - winEndItemInfo = currItemInfo; - } - - for (var i = targetItemIndex - 1, winStartItemInfo = targetItemInfo, winEndItemInfo = targetItemInfo, currItemInfo = null; i >= -1; --i) { - currItemInfo = getItemInfo(children[i]); - - if ( // If the the end item does not intersect with the window started - // from the current item, a page can be settled. - (!currItemInfo || !intersect(winEndItemInfo, currItemInfo.s) // e.g., when page size is smaller than item size. - ) && winStartItemInfo.i < winEndItemInfo.i) { - winEndItemInfo = winStartItemInfo; - - if (result.pagePrevDataIndex == null) { - result.pagePrevDataIndex = winStartItemInfo.i; - } - - ++result.pageCount; - ++result.pageIndex; - } - - winStartItemInfo = currItemInfo; - } - - return result; - - function getItemInfo(el) { - if (el) { - var itemRect = el.getBoundingRect(); - var start = itemRect[xy] + el[xy]; - return { - s: start, - e: start + itemRect[wh], - i: el.__legendDataIndex - }; - } - } - - function intersect(itemInfo, winStart) { - return itemInfo.e >= winStart && itemInfo.s <= winStart + containerRectSize; - } - }; - - ScrollableLegendView.prototype._findTargetItemIndex = function (targetDataIndex) { - if (!this._showController) { - return 0; - } - - var index; - var contentGroup = this.getContentGroup(); - var defaultIndex; - contentGroup.eachChild(function (child, idx) { - var legendDataIdx = child.__legendDataIndex; // FIXME - // If the given targetDataIndex (from model) is illegal, - // we use defaultIndex. But the index on the legend model and - // action payload is still illegal. That case will not be - // changed until some scenario requires. - - if (defaultIndex == null && legendDataIdx != null) { - defaultIndex = idx; - } - - if (legendDataIdx === targetDataIndex) { - index = idx; - } - }); - return index != null ? index : defaultIndex; - }; - - ScrollableLegendView.type = 'legend.scroll'; - return ScrollableLegendView; - }(LegendView); - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - /** - * AUTO-GENERATED FILE. DO NOT MODIFY. - */ - - /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - - - function installScrollableLegendAction(registers) { - /** - * @event legendScroll - * @type {Object} - * @property {string} type 'legendScroll' - * @property {string} scrollDataIndex - */ - registers.registerAction('legendScroll', 'legendscroll', function (payload, ecModel) { - var scrollDataIndex = payload.scrollDataIndex; - scrollDataIndex != null && ecModel.eachComponent({ - mainType: 'legend', - subType: 'scroll', - query: payload - }, function (legendModel) { - legendModel.setScrollDataIndex(scrollDataIndex); - }); - }); - } - - function install$4(registers) { - use(install$5); - registers.registerComponentModel(ScrollableLegendModel); - registers.registerComponentView(ScrollableLegendView); - installScrollableLegendAction(registers); - } - - use(install$4); - var inner$5 = makeInner(); - var clone = clone$3; - var bind = bind$1; - /** - * Base axis pointer class in 2D. - */ - - var BaseAxisPointer = - /** @class */ - function () { - function BaseAxisPointer() { - this._dragging = false; - /** - * In px, arbitrary value. Do not set too small, - * no animation is ok for most cases. - */ - - this.animationThreshold = 15; - } - /** - * @implement - */ - - - BaseAxisPointer.prototype.render = function (axisModel, axisPointerModel, api, forceRender) { - var value = axisPointerModel.get('value'); - var status = axisPointerModel.get('status'); // Bind them to `this`, not in closure, otherwise they will not - // be replaced when user calling setOption in not merge mode. - - this._axisModel = axisModel; - this._axisPointerModel = axisPointerModel; - this._api = api; // Optimize: `render` will be called repeatedly during mouse move. - // So it is power consuming if performing `render` each time, - // especially on mobile device. - - if (!forceRender && this._lastValue === value && this._lastStatus === status) { - return; - } - - this._lastValue = value; - this._lastStatus = status; - var group = this._group; - var handle = this._handle; - - if (!status || status === 'hide') { - // Do not clear here, for animation better. - group && group.hide(); - handle && handle.hide(); - return; - } - - group && group.show(); - handle && handle.show(); // Otherwise status is 'show' - - var elOption = {}; - this.makeElOption(elOption, value, axisModel, axisPointerModel, api); // Enable change axis pointer type. - - var graphicKey = elOption.graphicKey; - - if (graphicKey !== this._lastGraphicKey) { - this.clear(api); - } - - this._lastGraphicKey = graphicKey; - var moveAnimation = this._moveAnimation = this.determineAnimation(axisModel, axisPointerModel); - - if (!group) { - group = this._group = new Group$2(); - this.createPointerEl(group, elOption, axisModel, axisPointerModel); - this.createLabelEl(group, elOption, axisModel, axisPointerModel); - api.getZr().add(group); - } else { - var doUpdateProps = curry$1(updateProps, axisPointerModel, moveAnimation); - this.updatePointerEl(group, elOption, doUpdateProps); - this.updateLabelEl(group, elOption, doUpdateProps, axisPointerModel); - } - - updateMandatoryProps(group, axisPointerModel, true); - - this._renderHandle(value); - }; - /** - * @implement - */ - - - BaseAxisPointer.prototype.remove = function (api) { - this.clear(api); - }; - /** - * @implement - */ - - - BaseAxisPointer.prototype.dispose = function (api) { - this.clear(api); - }; - /** - * @protected - */ - - - BaseAxisPointer.prototype.determineAnimation = function (axisModel, axisPointerModel) { - var animation = axisPointerModel.get('animation'); - var axis = axisModel.axis; - var isCategoryAxis = axis.type === 'category'; - var useSnap = axisPointerModel.get('snap'); // Value axis without snap always do not snap. - - if (!useSnap && !isCategoryAxis) { - return false; - } - - if (animation === 'auto' || animation == null) { - var animationThreshold = this.animationThreshold; - - if (isCategoryAxis && axis.getBandWidth() > animationThreshold) { - return true; - } // It is important to auto animation when snap used. Consider if there is - // a dataZoom, animation will be disabled when too many points exist, while - // it will be enabled for better visual effect when little points exist. - - - if (useSnap) { - var seriesDataCount = getAxisInfo$1(axisModel).seriesDataCount; - var axisExtent = axis.getExtent(); // Approximate band width - - return Math.abs(axisExtent[0] - axisExtent[1]) / seriesDataCount > animationThreshold; - } - - return false; - } - - return animation === true; - }; - /** - * add {pointer, label, graphicKey} to elOption - * @protected - */ - - - BaseAxisPointer.prototype.makeElOption = function (elOption, value, axisModel, axisPointerModel, api) {// Should be implemenented by sub-class. - }; - /** - * @protected - */ - - - BaseAxisPointer.prototype.createPointerEl = function (group, elOption, axisModel, axisPointerModel) { - var pointerOption = elOption.pointer; - - if (pointerOption) { - var pointerEl = inner$5(group).pointerEl = new graphic$1[pointerOption.type](clone(elOption.pointer)); - group.add(pointerEl); - } - }; - /** - * @protected - */ - - - BaseAxisPointer.prototype.createLabelEl = function (group, elOption, axisModel, axisPointerModel) { - if (elOption.label) { - var labelEl = inner$5(group).labelEl = new ZRText(clone(elOption.label)); - group.add(labelEl); - updateLabelShowHide(labelEl, axisPointerModel); - } - }; - /** - * @protected - */ - - - BaseAxisPointer.prototype.updatePointerEl = function (group, elOption, updateProps) { - var pointerEl = inner$5(group).pointerEl; - - if (pointerEl && elOption.pointer) { - pointerEl.setStyle(elOption.pointer.style); - updateProps(pointerEl, { - shape: elOption.pointer.shape - }); - } - }; - /** - * @protected - */ - - - BaseAxisPointer.prototype.updateLabelEl = function (group, elOption, updateProps, axisPointerModel) { - var labelEl = inner$5(group).labelEl; - - if (labelEl) { - labelEl.setStyle(elOption.label.style); - updateProps(labelEl, { - // Consider text length change in vertical axis, animation should - // be used on shape, otherwise the effect will be weird. - // TODOTODO - // shape: elOption.label.shape, - x: elOption.label.x, - y: elOption.label.y - }); - updateLabelShowHide(labelEl, axisPointerModel); - } - }; - /** - * @private - */ - - - BaseAxisPointer.prototype._renderHandle = function (value) { - if (this._dragging || !this.updateHandleTransform) { - return; - } - - var axisPointerModel = this._axisPointerModel; - - var zr = this._api.getZr(); - - var handle = this._handle; - var handleModel = axisPointerModel.getModel('handle'); - var status = axisPointerModel.get('status'); - - if (!handleModel.get('show') || !status || status === 'hide') { - handle && zr.remove(handle); - this._handle = null; - return; - } - - var isInit; - - if (!this._handle) { - isInit = true; - handle = this._handle = createIcon(handleModel.get('icon'), { - cursor: 'move', - draggable: true, - onmousemove: function (e) { - // For mobile device, prevent screen slider on the button. - stop(e.event); - }, - onmousedown: bind(this._onHandleDragMove, this, 0, 0), - drift: bind(this._onHandleDragMove, this), - ondragend: bind(this._onHandleDragEnd, this) - }); - zr.add(handle); - } - - updateMandatoryProps(handle, axisPointerModel, false); // update style - - handle.setStyle(handleModel.getItemStyle(null, ['color', 'borderColor', 'borderWidth', 'opacity', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'])); // update position - - var handleSize = handleModel.get('size'); - - if (!isArray(handleSize)) { - handleSize = [handleSize, handleSize]; - } - - handle.scaleX = handleSize[0] / 2; - handle.scaleY = handleSize[1] / 2; - createOrUpdate(this, '_doDispatchAxisPointer', handleModel.get('throttle') || 0, 'fixRate'); - - this._moveHandleToValue(value, isInit); - }; - - BaseAxisPointer.prototype._moveHandleToValue = function (value, isInit) { - updateProps(this._axisPointerModel, !isInit && this._moveAnimation, this._handle, getHandleTransProps(this.getHandleTransform(value, this._axisModel, this._axisPointerModel))); - }; - - BaseAxisPointer.prototype._onHandleDragMove = function (dx, dy) { - var handle = this._handle; - - if (!handle) { - return; - } - - this._dragging = true; // Persistent for throttle. - - var trans = this.updateHandleTransform(getHandleTransProps(handle), [dx, dy], this._axisModel, this._axisPointerModel); - this._payloadInfo = trans; - handle.stopAnimation(); - handle.attr(getHandleTransProps(trans)); - inner$5(handle).lastProp = null; - - this._doDispatchAxisPointer(); - }; - /** - * Throttled method. - */ - - - BaseAxisPointer.prototype._doDispatchAxisPointer = function () { - var handle = this._handle; - - if (!handle) { - return; - } - - var payloadInfo = this._payloadInfo; - var axisModel = this._axisModel; - - this._api.dispatchAction({ - type: 'updateAxisPointer', - x: payloadInfo.cursorPoint[0], - y: payloadInfo.cursorPoint[1], - tooltipOption: payloadInfo.tooltipOption, - axesInfo: [{ - axisDim: axisModel.axis.dim, - axisIndex: axisModel.componentIndex - }] - }); - }; - - BaseAxisPointer.prototype._onHandleDragEnd = function () { - this._dragging = false; - var handle = this._handle; - - if (!handle) { - return; - } - - var value = this._axisPointerModel.get('value'); // Consider snap or categroy axis, handle may be not consistent with - // axisPointer. So move handle to align the exact value position when - // drag ended. - - - this._moveHandleToValue(value); // For the effect: tooltip will be shown when finger holding on handle - // button, and will be hidden after finger left handle button. - - - this._api.dispatchAction({ - type: 'hideTip' - }); - }; - /** - * @private - */ - - - BaseAxisPointer.prototype.clear = function (api) { - this._lastValue = null; - this._lastStatus = null; - var zr = api.getZr(); - var group = this._group; - var handle = this._handle; - - if (zr && group) { - this._lastGraphicKey = null; - group && zr.remove(group); - handle && zr.remove(handle); - this._group = null; - this._handle = null; - this._payloadInfo = null; - } - - clear(this, '_doDispatchAxisPointer'); - }; - /** - * @protected - */ - - - BaseAxisPointer.prototype.doClear = function () {// Implemented by sub-class if necessary. - }; - - BaseAxisPointer.prototype.buildLabel = function (xy, wh, xDimIndex) { - xDimIndex = xDimIndex || 0; - return { - x: xy[xDimIndex], - y: xy[1 - xDimIndex], - width: wh[xDimIndex], - height: wh[1 - xDimIndex] - }; - }; - - return BaseAxisPointer; - }(); - - function updateProps(animationModel, moveAnimation, el, props) { - // Animation optimize. - if (!propsEqual(inner$5(el).lastProp, props)) { - inner$5(el).lastProp = props; - moveAnimation ? updateProps$1(el, props, animationModel) : (el.stopAnimation(), el.attr(props)); - } - } - - function propsEqual(lastProps, newProps) { - if (isObject$2(lastProps) && isObject$2(newProps)) { - var equals_1 = true; - each$4(newProps, function (item, key) { - equals_1 = equals_1 && propsEqual(lastProps[key], item); - }); - return !!equals_1; - } else { - return lastProps === newProps; - } - } - - function updateLabelShowHide(labelEl, axisPointerModel) { - labelEl[axisPointerModel.get(['label', 'show']) ? 'show' : 'hide'](); - } - - function getHandleTransProps(trans) { - return { - x: trans.x || 0, - y: trans.y || 0, - rotation: trans.rotation || 0 - }; - } - - function updateMandatoryProps(group, axisPointerModel, silent) { - var z = axisPointerModel.get('z'); - var zlevel = axisPointerModel.get('zlevel'); - group && group.traverse(function (el) { - if (el.type !== 'group') { - z != null && (el.z = z); - zlevel != null && (el.zlevel = zlevel); - el.silent = silent; - } - }); - } - - function buildElStyle(axisPointerModel) { - var axisPointerType = axisPointerModel.get('type'); - var styleModel = axisPointerModel.getModel(axisPointerType + 'Style'); - var style; - - if (axisPointerType === 'line') { - style = styleModel.getLineStyle(); - style.fill = null; - } else if (axisPointerType === 'shadow') { - style = styleModel.getAreaStyle(); - style.stroke = null; - } - - return style; - } - /** - * @param {Function} labelPos {align, verticalAlign, position} - */ - - - function buildLabelElOption(elOption, axisModel, axisPointerModel, api, labelPos) { - var value = axisPointerModel.get('value'); - var text = getValueLabel(value, axisModel.axis, axisModel.ecModel, axisPointerModel.get('seriesDataIndices'), { - precision: axisPointerModel.get(['label', 'precision']), - formatter: axisPointerModel.get(['label', 'formatter']) - }); - var labelModel = axisPointerModel.getModel('label'); - var paddings = normalizeCssArray(labelModel.get('padding') || 0); - var font = labelModel.getFont(); - var textRect = getBoundingRect(text, font); - var position = labelPos.position; - var width = textRect.width + paddings[1] + paddings[3]; - var height = textRect.height + paddings[0] + paddings[2]; // Adjust by align. - - var align = labelPos.align; - align === 'right' && (position[0] -= width); - align === 'center' && (position[0] -= width / 2); - var verticalAlign = labelPos.verticalAlign; - verticalAlign === 'bottom' && (position[1] -= height); - verticalAlign === 'middle' && (position[1] -= height / 2); // Not overflow ec container - - confineInContainer(position, width, height, api); - var bgColor = labelModel.get('backgroundColor'); - - if (!bgColor || bgColor === 'auto') { - bgColor = axisModel.get(['axisLine', 'lineStyle', 'color']); - } - - elOption.label = { - // shape: {x: 0, y: 0, width: width, height: height, r: labelModel.get('borderRadius')}, - x: position[0], - y: position[1], - style: createTextStyle$1(labelModel, { - text: text, - font: font, - fill: labelModel.getTextColor(), - padding: paddings, - backgroundColor: bgColor - }), - // Label should be over axisPointer. - z2: 10 - }; - } // Do not overflow ec container - - - function confineInContainer(position, width, height, api) { - var viewWidth = api.getWidth(); - var viewHeight = api.getHeight(); - position[0] = Math.min(position[0] + width, viewWidth) - width; - position[1] = Math.min(position[1] + height, viewHeight) - height; - position[0] = Math.max(position[0], 0); - position[1] = Math.max(position[1], 0); - } - - function getValueLabel(value, axis, ecModel, seriesDataIndices, opt) { - value = axis.scale.parse(value); - var text = axis.scale.getLabel({ - value: value - }, { - // If `precision` is set, width can be fixed (like '12.00500'), which - // helps to debounce when when moving label. - precision: opt.precision - }); - var formatter = opt.formatter; - - if (formatter) { - var params_1 = { - value: getAxisRawValue(axis, { - value: value - }), - axisDimension: axis.dim, - axisIndex: axis.index, - seriesData: [] - }; - each$4(seriesDataIndices, function (idxItem) { - var series = ecModel.getSeriesByIndex(idxItem.seriesIndex); - var dataIndex = idxItem.dataIndexInside; - var dataParams = series && series.getDataParams(dataIndex); - dataParams && params_1.seriesData.push(dataParams); - }); - - if (isString(formatter)) { - text = formatter.replace('{value}', text); - } else if (isFunction(formatter)) { - text = formatter(params_1); - } - } - - return text; - } - - function getTransformedPosition(axis, value, layoutInfo) { - var transform = create(); - rotate(transform, transform, layoutInfo.rotation); - translate(transform, transform, layoutInfo.position); - return applyTransform([axis.dataToCoord(value), (layoutInfo.labelOffset || 0) + (layoutInfo.labelDirection || 1) * (layoutInfo.labelMargin || 0)], transform); - } - - function buildCartesianSingleLabelElOption(value, elOption, layoutInfo, axisModel, axisPointerModel, api) { - var textLayout = AxisBuilder.innerTextLayout(layoutInfo.rotation, 0, layoutInfo.labelDirection); - layoutInfo.labelMargin = axisPointerModel.get(['label', 'margin']); - buildLabelElOption(elOption, axisModel, axisPointerModel, api, { - position: getTransformedPosition(axisModel.axis, value, layoutInfo), - align: textLayout.textAlign, - verticalAlign: textLayout.textVerticalAlign - }); - } - - function makeLineShape(p1, p2, xDimIndex) { - xDimIndex = xDimIndex || 0; - return { - x1: p1[xDimIndex], - y1: p1[1 - xDimIndex], - x2: p2[xDimIndex], - y2: p2[1 - xDimIndex] - }; - } - - function makeRectShape(xy, wh, xDimIndex) { - xDimIndex = xDimIndex || 0; - return { - x: xy[xDimIndex], - y: xy[1 - xDimIndex], - width: wh[xDimIndex], - height: wh[1 - xDimIndex] - }; - } - - var CartesianAxisPointer = - /** @class */ - function (_super) { - __extends(CartesianAxisPointer, _super); - - function CartesianAxisPointer() { - return _super !== null && _super.apply(this, arguments) || this; - } - /** - * @override - */ - - - CartesianAxisPointer.prototype.makeElOption = function (elOption, value, axisModel, axisPointerModel, api) { - var axis = axisModel.axis; - var grid = axis.grid; - var axisPointerType = axisPointerModel.get('type'); - var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent(); - var pixelValue = axis.toGlobalCoord(axis.dataToCoord(value, true)); - - if (axisPointerType && axisPointerType !== 'none') { - var elStyle = buildElStyle(axisPointerModel); - var pointerOption = pointerShapeBuilder[axisPointerType](axis, pixelValue, otherExtent); - pointerOption.style = elStyle; - elOption.graphicKey = pointerOption.type; - elOption.pointer = pointerOption; - } - - var layoutInfo = layout(grid.getRect(), axisModel); - buildCartesianSingleLabelElOption(value, elOption, layoutInfo, axisModel, axisPointerModel, api); - }; - /** - * @override - */ - - - CartesianAxisPointer.prototype.getHandleTransform = function (value, axisModel, axisPointerModel) { - var layoutInfo = layout(axisModel.axis.grid.getRect(), axisModel, { - labelInside: false - }); - layoutInfo.labelMargin = axisPointerModel.get(['handle', 'margin']); - var pos = getTransformedPosition(axisModel.axis, value, layoutInfo); - return { - x: pos[0], - y: pos[1], - rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0) - }; - }; - /** - * @override - */ - - - CartesianAxisPointer.prototype.updateHandleTransform = function (transform, delta, axisModel, axisPointerModel) { - var axis = axisModel.axis; - var grid = axis.grid; - var axisExtent = axis.getGlobalExtent(true); - var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent(); - var dimIndex = axis.dim === 'x' ? 0 : 1; - var currPosition = [transform.x, transform.y]; - currPosition[dimIndex] += delta[dimIndex]; - currPosition[dimIndex] = Math.min(axisExtent[1], currPosition[dimIndex]); - currPosition[dimIndex] = Math.max(axisExtent[0], currPosition[dimIndex]); - var cursorOtherValue = (otherExtent[1] + otherExtent[0]) / 2; - var cursorPoint = [cursorOtherValue, cursorOtherValue]; - cursorPoint[dimIndex] = currPosition[dimIndex]; // Make tooltip do not overlap axisPointer and in the middle of the grid. - - var tooltipOptions = [{ - verticalAlign: 'middle' - }, { - align: 'center' - }]; - return { - x: currPosition[0], - y: currPosition[1], - rotation: transform.rotation, - cursorPoint: cursorPoint, - tooltipOption: tooltipOptions[dimIndex] - }; - }; - - return CartesianAxisPointer; - }(BaseAxisPointer); - - function getCartesian(grid, axis) { - var opt = {}; - opt[axis.dim + 'AxisIndex'] = axis.index; - return grid.getCartesian(opt); - } - - var pointerShapeBuilder = { - line: function (axis, pixelValue, otherExtent) { - var targetShape = makeLineShape([pixelValue, otherExtent[0]], [pixelValue, otherExtent[1]], getAxisDimIndex(axis)); - return { - type: 'Line', - subPixelOptimize: true, - shape: targetShape - }; - }, - shadow: function (axis, pixelValue, otherExtent) { - var bandWidth = Math.max(1, axis.getBandWidth()); - var span = otherExtent[1] - otherExtent[0]; - return { - type: 'Rect', - shape: makeRectShape([pixelValue - bandWidth / 2, otherExtent[0]], [bandWidth, span], getAxisDimIndex(axis)) - }; - } - }; - - function getAxisDimIndex(axis) { - return axis.dim === 'x' ? 0 : 1; - } - - var AxisPointerModel = - /** @class */ - function (_super) { - __extends(AxisPointerModel, _super); - - function AxisPointerModel() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = AxisPointerModel.type; - return _this; - } - - AxisPointerModel.type = 'axisPointer'; - AxisPointerModel.defaultOption = { - // 'auto' means that show when triggered by tooltip or handle. - show: 'auto', - // zlevel: 0, - z: 50, - type: 'line', - // axispointer triggered by tootip determine snap automatically, - // see `modelHelper`. - snap: false, - triggerTooltip: true, - triggerEmphasis: true, - value: null, - status: null, - link: [], - // Do not set 'auto' here, otherwise global animation: false - // will not effect at this axispointer. - animation: null, - animationDurationUpdate: 200, - lineStyle: { - color: tokens.color.border, - width: 1, - type: 'dashed' - }, - shadowStyle: { - color: tokens.color.shadowTint - }, - label: { - show: true, - formatter: null, - precision: 'auto', - margin: 3, - color: tokens.color.neutral00, - padding: [5, 7, 5, 7], - backgroundColor: tokens.color.accent60, - borderColor: null, - borderWidth: 0, - borderRadius: 3 - }, - handle: { - show: false, - // eslint-disable-next-line - icon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z', - size: 45, - // handle margin is from symbol center to axis, which is stable when circular move. - margin: 50, - // color: '#1b8bbd' - // color: '#2f4554' - color: tokens.color.accent40, - // For mobile performance - throttle: 40 - } - }; - return AxisPointerModel; - }(ComponentModel); - - var inner$4 = makeInner(); - var each = each$4; - /** - * @param {string} key - * @param {module:echarts/ExtensionAPI} api - * @param {Function} handler - * param: {string} currTrigger - * param: {Array.} point - */ - - function register(key, api, handler) { - if (env.node) { - return; - } - - var zr = api.getZr(); - inner$4(zr).records || (inner$4(zr).records = {}); - initGlobalListeners(zr, api); - var record = inner$4(zr).records[key] || (inner$4(zr).records[key] = {}); - record.handler = handler; - } - - function initGlobalListeners(zr, api) { - if (inner$4(zr).initialized) { - return; - } - - inner$4(zr).initialized = true; - useHandler('click', curry$1(doEnter, 'click')); - useHandler('mousemove', curry$1(doEnter, 'mousemove')); // useHandler('mouseout', onLeave); - - useHandler('globalout', onLeave); - - function useHandler(eventType, cb) { - zr.on(eventType, function (e) { - var dis = makeDispatchAction$1(api); - each(inner$4(zr).records, function (record) { - record && cb(record, e, dis.dispatchAction); - }); - dispatchTooltipFinally(dis.pendings, api); - }); - } - } - - function dispatchTooltipFinally(pendings, api) { - var showLen = pendings.showTip.length; - var hideLen = pendings.hideTip.length; - var actuallyPayload; - - if (showLen) { - actuallyPayload = pendings.showTip[showLen - 1]; - } else if (hideLen) { - actuallyPayload = pendings.hideTip[hideLen - 1]; - } - - if (actuallyPayload) { - actuallyPayload.dispatchAction = null; - api.dispatchAction(actuallyPayload); - } - } - - function onLeave(record, e, dispatchAction) { - record.handler('leave', null, dispatchAction); - } - - function doEnter(currTrigger, record, e, dispatchAction) { - record.handler(currTrigger, e, dispatchAction); - } - - function makeDispatchAction$1(api) { - var pendings = { - showTip: [], - hideTip: [] - }; // FIXME - // better approach? - // 'showTip' and 'hideTip' can be triggered by axisPointer and tooltip, - // which may be conflict, (axisPointer call showTip but tooltip call hideTip); - // So we have to add "final stage" to merge those dispatched actions. - - var dispatchAction = function (payload) { - var pendingList = pendings[payload.type]; - - if (pendingList) { - pendingList.push(payload); - } else { - payload.dispatchAction = dispatchAction; - api.dispatchAction(payload); - } - }; - - return { - dispatchAction: dispatchAction, - pendings: pendings - }; - } - - function unregister(key, api) { - if (env.node) { - return; - } - - var zr = api.getZr(); - var record = (inner$4(zr).records || {})[key]; - - if (record) { - inner$4(zr).records[key] = null; - } - } - - var AxisPointerView = - /** @class */ - function (_super) { - __extends(AxisPointerView, _super); - - function AxisPointerView() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = AxisPointerView.type; - return _this; - } - - AxisPointerView.prototype.render = function (globalAxisPointerModel, ecModel, api) { - var globalTooltipModel = ecModel.getComponent('tooltip'); - var triggerOn = globalAxisPointerModel.get('triggerOn') || globalTooltipModel && globalTooltipModel.get('triggerOn') || 'mousemove|click'; // Register global listener in AxisPointerView to enable - // AxisPointerView to be independent to Tooltip. - - register('axisPointer', api, function (currTrigger, e, dispatchAction) { - // If 'none', it is not controlled by mouse totally. - if (triggerOn !== 'none' && (currTrigger === 'leave' || triggerOn.indexOf(currTrigger) >= 0)) { - dispatchAction({ - type: 'updateAxisPointer', - currTrigger: currTrigger, - x: e && e.offsetX, - y: e && e.offsetY - }); - } - }); - }; - - AxisPointerView.prototype.remove = function (ecModel, api) { - unregister('axisPointer', api); - }; - - AxisPointerView.prototype.dispose = function (ecModel, api) { - unregister('axisPointer', api); - }; - - AxisPointerView.type = 'axisPointer'; - return AxisPointerView; - }(ComponentView); - /** - * @param finder contains {seriesIndex, dataIndex, dataIndexInside} - * @param ecModel - * @return {point: [x, y], el: ...} point Will not be null. - */ - - - function findPointFromSeries(finder, ecModel) { - var point = []; - var seriesIndex = finder.seriesIndex; - var seriesModel; - - if (seriesIndex == null || !(seriesModel = ecModel.getSeriesByIndex(seriesIndex))) { - return { - point: [] - }; - } - - var data = seriesModel.getData(); - var dataIndex = queryDataIndex(data, finder); - - if (dataIndex == null || dataIndex < 0 || isArray(dataIndex)) { - return { - point: [] - }; - } - - var el = data.getItemGraphicEl(dataIndex); - var coordSys = seriesModel.coordinateSystem; - - if (seriesModel.getTooltipPosition) { - point = seriesModel.getTooltipPosition(dataIndex) || []; - } else if (coordSys && coordSys.dataToPoint) { - if (finder.isStacked) { - var baseAxis = coordSys.getBaseAxis(); - var valueAxis = coordSys.getOtherAxis(baseAxis); - var valueAxisDim = valueAxis.dim; - var baseAxisDim = baseAxis.dim; - var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0; - var baseDim = data.mapDimension(baseAxisDim); - var stackedData = []; - stackedData[baseDataOffset] = data.get(baseDim, dataIndex); - stackedData[1 - baseDataOffset] = data.get(data.getCalculationInfo('stackResultDimension'), dataIndex); - point = coordSys.dataToPoint(stackedData) || []; - } else { - point = coordSys.dataToPoint(data.getValues(map$1(coordSys.dimensions, function (dim) { - return data.mapDimension(dim); - }), dataIndex)) || []; - } - } else if (el) { - // Use graphic bounding rect - var rect = el.getBoundingRect().clone(); - rect.applyTransform(el.transform); - point = [rect.x + rect.width / 2, rect.y + rect.height / 2]; - } - - return { - point: point, - el: el - }; - } - - var inner$3 = makeInner(); - /** - * Basic logic: check all axis, if they do not demand show/highlight, - * then hide/downplay them. - * - * @return content of event obj for echarts.connect. - */ - - function axisTrigger(payload, ecModel, api) { - var currTrigger = payload.currTrigger; - var point = [payload.x, payload.y]; - var finder = payload; - var dispatchAction = payload.dispatchAction || bind$1(api.dispatchAction, api); - var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo; // Pending - // See #6121. But we are not able to reproduce it yet. - - if (!coordSysAxesInfo) { - return; - } - - if (illegalPoint(point)) { - // Used in the default behavior of `connection`: use the sample seriesIndex - // and dataIndex. And also used in the tooltipView trigger. - point = findPointFromSeries({ - seriesIndex: finder.seriesIndex, - // Do not use dataIndexInside from other ec instance. - // FIXME: auto detect it? - dataIndex: finder.dataIndex - }, ecModel).point; - } - - var isIllegalPoint = illegalPoint(point); // Axis and value can be specified when calling dispatchAction({type: 'updateAxisPointer'}). - // Notice: In this case, it is difficult to get the `point` (which is necessary to show - // tooltip, so if point is not given, we just use the point found by sample seriesIndex - // and dataIndex. - - var inputAxesInfo = finder.axesInfo; - var axesInfo = coordSysAxesInfo.axesInfo; - var shouldHide = currTrigger === 'leave' || illegalPoint(point); - var outputPayload = {}; - var showValueMap = {}; - var dataByCoordSys = { - list: [], - map: {} - }; - var updaters = { - showPointer: curry$1(showPointer, showValueMap), - showTooltip: curry$1(showTooltip, dataByCoordSys) - }; // Process for triggered axes. - - each$4(coordSysAxesInfo.coordSysMap, function (coordSys, coordSysKey) { - // If a point given, it must be contained by the coordinate system. - var coordSysContainsPoint = isIllegalPoint || coordSys.containPoint(point); - each$4(coordSysAxesInfo.coordSysAxesInfo[coordSysKey], function (axisInfo, key) { - var axis = axisInfo.axis; - var inputAxisInfo = findInputAxisInfo(inputAxesInfo, axisInfo); // If no inputAxesInfo, no axis is restricted. - - if (!shouldHide && coordSysContainsPoint && (!inputAxesInfo || inputAxisInfo)) { - var val = inputAxisInfo && inputAxisInfo.value; - - if (val == null && !isIllegalPoint) { - val = axis.pointToData(point); - } - - val != null && processOnAxis(axisInfo, val, updaters, false, outputPayload); - } - }); - }); // Process for linked axes. - - var linkTriggers = {}; - each$4(axesInfo, function (tarAxisInfo, tarKey) { - var linkGroup = tarAxisInfo.linkGroup; // If axis has been triggered in the previous stage, it should not be triggered by link. - - if (linkGroup && !showValueMap[tarKey]) { - each$4(linkGroup.axesInfo, function (srcAxisInfo, srcKey) { - var srcValItem = showValueMap[srcKey]; // If srcValItem exist, source axis is triggered, so link to target axis. - - if (srcAxisInfo !== tarAxisInfo && srcValItem) { - var val = srcValItem.value; - linkGroup.mapper && (val = tarAxisInfo.axis.scale.parse(linkGroup.mapper(val, makeMapperParam(srcAxisInfo), makeMapperParam(tarAxisInfo)))); - linkTriggers[tarAxisInfo.key] = val; - } - }); - } - }); - each$4(linkTriggers, function (val, tarKey) { - processOnAxis(axesInfo[tarKey], val, updaters, true, outputPayload); - }); - updateModelActually(showValueMap, axesInfo, outputPayload); - dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction); - dispatchHighDownActually(axesInfo, dispatchAction, api); - return outputPayload; - } - - function processOnAxis(axisInfo, newValue, updaters, noSnap, outputFinder) { - var axis = axisInfo.axis; - - if (axis.scale.isBlank() || !axis.containData(newValue)) { - return; - } - - if (!axisInfo.involveSeries) { - updaters.showPointer(axisInfo, newValue); - return; - } // Heavy calculation. So put it after axis.containData checking. - - - var payloadInfo = buildPayloadsBySeries(newValue, axisInfo); - var payloadBatch = payloadInfo.payloadBatch; - var snapToValue = payloadInfo.snapToValue; // Fill content of event obj for echarts.connect. - // By default use the first involved series data as a sample to connect. - - if (payloadBatch[0] && outputFinder.seriesIndex == null) { - extend(outputFinder, payloadBatch[0]); - } // If no linkSource input, this process is for collecting link - // target, where snap should not be accepted. - - - if (!noSnap && axisInfo.snap) { - if (axis.containData(snapToValue) && snapToValue != null) { - newValue = snapToValue; - } - } - - updaters.showPointer(axisInfo, newValue, payloadBatch); // Tooltip should always be snapToValue, otherwise there will be - // incorrect "axis value ~ series value" mapping displayed in tooltip. - - updaters.showTooltip(axisInfo, payloadInfo, snapToValue); - } - - function buildPayloadsBySeries(value, axisInfo) { - var axis = axisInfo.axis; - var dim = axis.dim; - var snapToValue = value; - var payloadBatch = []; - var minDist = Number.MAX_VALUE; - var minDiff = -1; - each$4(axisInfo.seriesModels, function (series, idx) { - var dataDim = series.getData().mapDimensionsAll(dim); - var seriesNestestValue; - var dataIndices; - - if (series.getAxisTooltipData) { - var result = series.getAxisTooltipData(dataDim, value, axis); - dataIndices = result.dataIndices; - seriesNestestValue = result.nestestValue; - } else { - dataIndices = series.indicesOfNearest(dim, dataDim[0], value, // Add a threshold to avoid find the wrong dataIndex - // when data length is not same. - // false, - axis.type === 'category' ? 0.5 : null); - - if (!dataIndices.length) { - return; - } - - seriesNestestValue = series.getData().get(dataDim[0], dataIndices[0]); - } - - if (seriesNestestValue == null || !isFinite(seriesNestestValue)) { - return; - } - - var diff = value - seriesNestestValue; - var dist = Math.abs(diff); // Consider category case - - if (dist <= minDist) { - if (dist < minDist || diff >= 0 && minDiff < 0) { - minDist = dist; - minDiff = diff; - snapToValue = seriesNestestValue; - payloadBatch.length = 0; - } - - each$4(dataIndices, function (dataIndex) { - payloadBatch.push({ - seriesIndex: series.seriesIndex, - dataIndexInside: dataIndex, - dataIndex: series.getData().getRawIndex(dataIndex) - }); - }); - } - }); - return { - payloadBatch: payloadBatch, - snapToValue: snapToValue - }; - } - - function showPointer(showValueMap, axisInfo, value, payloadBatch) { - showValueMap[axisInfo.key] = { - value: value, - payloadBatch: payloadBatch - }; - } - - function showTooltip(dataByCoordSys, axisInfo, payloadInfo, value) { - var payloadBatch = payloadInfo.payloadBatch; - var axis = axisInfo.axis; - var axisModel = axis.model; - var axisPointerModel = axisInfo.axisPointerModel; // If no data, do not create anything in dataByCoordSys, - // whose length will be used to judge whether dispatch action. - - if (!axisInfo.triggerTooltip || !payloadBatch.length) { - return; - } - - var coordSysModel = axisInfo.coordSys.model; - var coordSysKey = makeKey(coordSysModel); - var coordSysItem = dataByCoordSys.map[coordSysKey]; - - if (!coordSysItem) { - coordSysItem = dataByCoordSys.map[coordSysKey] = { - coordSysId: coordSysModel.id, - coordSysIndex: coordSysModel.componentIndex, - coordSysType: coordSysModel.type, - coordSysMainType: coordSysModel.mainType, - dataByAxis: [] - }; - dataByCoordSys.list.push(coordSysItem); - } - - coordSysItem.dataByAxis.push({ - axisDim: axis.dim, - axisIndex: axisModel.componentIndex, - axisType: axisModel.type, - axisId: axisModel.id, - value: value, - // Caustion: viewHelper.getValueLabel is actually on "view stage", which - // depends that all models have been updated. So it should not be performed - // here. Considering axisPointerModel used here is volatile, which is hard - // to be retrieve in TooltipView, we prepare parameters here. - valueLabelOpt: { - precision: axisPointerModel.get(['label', 'precision']), - formatter: axisPointerModel.get(['label', 'formatter']) - }, - seriesDataIndices: payloadBatch.slice() - }); - } - - function updateModelActually(showValueMap, axesInfo, outputPayload) { - var outputAxesInfo = outputPayload.axesInfo = []; // Basic logic: If no 'show' required, 'hide' this axisPointer. - - each$4(axesInfo, function (axisInfo, key) { - var option = axisInfo.axisPointerModel.option; - var valItem = showValueMap[key]; - - if (valItem) { - !axisInfo.useHandle && (option.status = 'show'); - option.value = valItem.value; // For label formatter param and highlight. - - option.seriesDataIndices = (valItem.payloadBatch || []).slice(); - } // When always show (e.g., handle used), remain - // original value and status. - else { - // If hide, value still need to be set, consider - // click legend to toggle axis blank. - !axisInfo.useHandle && (option.status = 'hide'); - } // If status is 'hide', should be no info in payload. - - - option.status === 'show' && outputAxesInfo.push({ - axisDim: axisInfo.axis.dim, - axisIndex: axisInfo.axis.model.componentIndex, - value: option.value - }); - }); - } - - function dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction) { - // Basic logic: If no showTip required, hideTip will be dispatched. - if (illegalPoint(point) || !dataByCoordSys.list.length) { - dispatchAction({ - type: 'hideTip' - }); - return; - } // In most case only one axis (or event one series is used). It is - // convenient to fetch payload.seriesIndex and payload.dataIndex - // directly. So put the first seriesIndex and dataIndex of the first - // axis on the payload. - - - var sampleItem = ((dataByCoordSys.list[0].dataByAxis[0] || {}).seriesDataIndices || [])[0] || {}; - dispatchAction({ - type: 'showTip', - escapeConnect: true, - x: point[0], - y: point[1], - tooltipOption: payload.tooltipOption, - position: payload.position, - dataIndexInside: sampleItem.dataIndexInside, - dataIndex: sampleItem.dataIndex, - seriesIndex: sampleItem.seriesIndex, - dataByCoordSys: dataByCoordSys.list - }); - } - - function dispatchHighDownActually(axesInfo, dispatchAction, api) { - // FIXME - // highlight status modification should be a stage of main process? - // (Consider confilct (e.g., legend and axisPointer) and setOption) - var zr = api.getZr(); - var highDownKey = 'axisPointerLastHighlights'; - var lastHighlights = inner$3(zr)[highDownKey] || {}; - var newHighlights = inner$3(zr)[highDownKey] = {}; // Update highlight/downplay status according to axisPointer model. - // Build hash map and remove duplicate incidentally. - - each$4(axesInfo, function (axisInfo, key) { - var option = axisInfo.axisPointerModel.option; - option.status === 'show' && axisInfo.triggerEmphasis && each$4(option.seriesDataIndices, function (batchItem) { - var key = batchItem.seriesIndex + ' | ' + batchItem.dataIndex; - newHighlights[key] = batchItem; - }); - }); // Diff. - - var toHighlight = []; - var toDownplay = []; - each$4(lastHighlights, function (batchItem, key) { - !newHighlights[key] && toDownplay.push(batchItem); - }); - each$4(newHighlights, function (batchItem, key) { - !lastHighlights[key] && toHighlight.push(batchItem); - }); - toDownplay.length && api.dispatchAction({ - type: 'downplay', - escapeConnect: true, - // Not blur others when highlight in axisPointer. - notBlur: true, - batch: toDownplay - }); - toHighlight.length && api.dispatchAction({ - type: 'highlight', - escapeConnect: true, - // Not blur others when highlight in axisPointer. - notBlur: true, - batch: toHighlight - }); - } - - function findInputAxisInfo(inputAxesInfo, axisInfo) { - for (var i = 0; i < (inputAxesInfo || []).length; i++) { - var inputAxisInfo = inputAxesInfo[i]; - - if (axisInfo.axis.dim === inputAxisInfo.axisDim && axisInfo.axis.model.componentIndex === inputAxisInfo.axisIndex) { - return inputAxisInfo; - } - } - } - - function makeMapperParam(axisInfo) { - var axisModel = axisInfo.axis.model; - var item = {}; - var dim = item.axisDim = axisInfo.axis.dim; - item.axisIndex = item[dim + 'AxisIndex'] = axisModel.componentIndex; - item.axisName = item[dim + 'AxisName'] = axisModel.name; - item.axisId = item[dim + 'AxisId'] = axisModel.id; - return item; - } - - function illegalPoint(point) { - return !point || point[0] == null || isNaN(point[0]) || point[1] == null || isNaN(point[1]); - } - - function install$3(registers) { - // CartesianAxisPointer is not supposed to be required here. But consider - // echarts.simple.js and online build tooltip, which only require gridSimple, - // CartesianAxisPointer should be able to required somewhere. - AxisView.registerAxisPointerClass('CartesianAxisPointer', CartesianAxisPointer); - registers.registerComponentModel(AxisPointerModel); - registers.registerComponentView(AxisPointerView); - registers.registerPreprocessor(function (option) { - // Always has a global axisPointerModel for default setting. - if (option) { - (!option.axisPointer || option.axisPointer.length === 0) && (option.axisPointer = {}); - var link = option.axisPointer.link; // Normalize to array to avoid object mergin. But if link - // is not set, remain null/undefined, otherwise it will - // override existent link setting. - - if (link && !isArray(link)) { - option.axisPointer.link = [link]; - } - } - }); // This process should proformed after coordinate systems created - // and series data processed. So put it on statistic processing stage. - - registers.registerProcessor(registers.PRIORITY.PROCESSOR.STATISTIC, function (ecModel, api) { - // Build axisPointerModel, mergin tooltip.axisPointer model for each axis. - // allAxesInfo should be updated when setOption performed. - ecModel.getComponent('axisPointer').coordSysAxesInfo = collect(ecModel, api); - }); // Broadcast to all views. - - registers.registerAction({ - type: 'updateAxisPointer', - event: 'updateAxisPointer', - update: ':updateAxisPointer' - }, axisTrigger); - } - - var TooltipModel = - /** @class */ - function (_super) { - __extends(TooltipModel, _super); - - function TooltipModel() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = TooltipModel.type; - return _this; - } - - TooltipModel.type = 'tooltip'; - TooltipModel.dependencies = ['axisPointer']; - TooltipModel.defaultOption = { - // zlevel: 0, - z: 60, - show: true, - // tooltip main content - showContent: true, - // 'trigger' only works on coordinate system. - // 'item' | 'axis' | 'none' - trigger: 'item', - // 'click' | 'mousemove' | 'none' - triggerOn: 'mousemove|click', - alwaysShowContent: false, - renderMode: 'auto', - // whether restraint content inside viewRect. - // If renderMode: 'richText', default true. - // If renderMode: 'html', defaults to `false` (for backward compat). - confine: null, - showDelay: 0, - hideDelay: 100, - // Animation transition time, unit is second - transitionDuration: 0.4, - displayTransition: true, - enterable: false, - backgroundColor: tokens.color.neutral00, - // box shadow - shadowBlur: 10, - shadowColor: 'rgba(0, 0, 0, .2)', - shadowOffsetX: 1, - shadowOffsetY: 2, - // tooltip border radius, unit is px, default is 4 - borderRadius: 4, - // tooltip border width, unit is px, default is 0 (no border) - borderWidth: 1, - defaultBorderColor: tokens.color.border, - // Tooltip inside padding, default is 5 for all direction - // Array is allowed to set up, right, bottom, left, same with css - // The default value: See `tooltip/tooltipMarkup.ts#getPaddingFromTooltipModel`. - padding: null, - // Extra css text - extraCssText: '', - // axis indicator, trigger by axis - axisPointer: { - // default is line - // legal values: 'line' | 'shadow' | 'cross' - type: 'line', - // Valid when type is line, appoint tooltip line locate on which line. Optional - // legal values: 'x' | 'y' | 'angle' | 'radius' | 'auto' - // default is 'auto', chose the axis which type is category. - // for multiply y axis, cartesian coord chose x axis, polar chose angle axis - axis: 'auto', - animation: 'auto', - animationDurationUpdate: 200, - animationEasingUpdate: 'exponentialOut', - crossStyle: { - color: tokens.color.borderShade, - width: 1, - type: 'dashed', - // TODO formatter - textStyle: {} - } // lineStyle and shadowStyle should not be specified here, - // otherwise it will always override those styles on option.axisPointer. - - }, - textStyle: { - color: tokens.color.tertiary, - fontSize: 14 - } - }; - return TooltipModel; - }(ComponentModel); - /* global document */ - - - function shouldTooltipConfine(tooltipModel) { - var confineOption = tooltipModel.get('confine'); - return confineOption != null ? !!confineOption // In richText mode, the outside part can not be visible. - : tooltipModel.get('renderMode') === 'richText'; - } - - function testStyle(styleProps) { - if (!env.domSupported) { - return; - } - - var style = document.documentElement.style; - - for (var i = 0, len = styleProps.length; i < len; i++) { - if (styleProps[i] in style) { - return styleProps[i]; - } - } - } - - var TRANSFORM_VENDOR = testStyle(['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']); - var TRANSITION_VENDOR = testStyle(['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']); - - function toCSSVendorPrefix(styleVendor, styleProp) { - if (!styleVendor) { - return styleProp; - } - - styleProp = toCamelCase(styleProp, true); - var idx = styleVendor.indexOf(styleProp); - styleVendor = idx === -1 ? styleProp : "-" + styleVendor.slice(0, idx) + "-" + styleProp; - return styleVendor.toLowerCase(); - } - - function getComputedStyle(el, style) { - var stl = el.currentStyle || document.defaultView && document.defaultView.getComputedStyle(el); - return stl ? style ? stl[style] : stl : null; - } - /* global document, window */ - - - var CSS_TRANSITION_VENDOR = toCSSVendorPrefix(TRANSITION_VENDOR, 'transition'); - var CSS_TRANSFORM_VENDOR = toCSSVendorPrefix(TRANSFORM_VENDOR, 'transform'); // eslint-disable-next-line - - var gCssText = "position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;" + (env.transform3dSupported ? 'will-change:transform;' : ''); - - function mirrorPos(pos) { - pos = pos === 'left' ? 'right' : pos === 'right' ? 'left' : pos === 'top' ? 'bottom' : 'top'; - return pos; - } - - function assembleArrow(tooltipModel, borderColor, arrowPosition) { - if (!isString(arrowPosition) || arrowPosition === 'inside') { - return ''; - } - - var backgroundColor = tooltipModel.get('backgroundColor'); - var borderWidth = tooltipModel.get('borderWidth'); - borderColor = convertToColorString(borderColor); - var arrowPos = mirrorPos(arrowPosition); - var arrowSize = Math.max(Math.round(borderWidth) * 1.5, 6); - var positionStyle = ''; - var transformStyle = CSS_TRANSFORM_VENDOR + ':'; - var rotateDeg; - - if (indexOf(['left', 'right'], arrowPos) > -1) { - positionStyle += 'top:50%'; - transformStyle += "translateY(-50%) rotate(" + (rotateDeg = arrowPos === 'left' ? -225 : -45) + "deg)"; - } else { - positionStyle += 'left:50%'; - transformStyle += "translateX(-50%) rotate(" + (rotateDeg = arrowPos === 'top' ? 225 : 45) + "deg)"; - } - - var rotateRadian = rotateDeg * Math.PI / 180; - var arrowWH = arrowSize + borderWidth; - var rotatedWH = arrowWH * Math.abs(Math.cos(rotateRadian)) + arrowWH * Math.abs(Math.sin(rotateRadian)); - var arrowOffset = Math.round(((rotatedWH - Math.SQRT2 * borderWidth) / 2 + Math.SQRT2 * borderWidth - (rotatedWH - arrowWH) / 2) * 100) / 100; - positionStyle += ";" + arrowPos + ":-" + arrowOffset + "px"; - var borderStyle = borderColor + " solid " + borderWidth + "px;"; - var styleCss = ["position:absolute;width:" + arrowSize + "px;height:" + arrowSize + "px;z-index:-1;", positionStyle + ";" + transformStyle + ";", "border-bottom:" + borderStyle, "border-right:" + borderStyle, "background-color:" + backgroundColor + ";"]; - return "
"; - } - - function assembleTransition(duration, onlyFadeTransition, enableDisplayTransition) { - var transitionCurve = 'cubic-bezier(0.23,1,0.32,1)'; - var transitionOption = ''; - var transitionText = ''; - - if (enableDisplayTransition) { - transitionOption = " " + duration / 2 + "s " + transitionCurve; - transitionText = "opacity" + transitionOption + ",visibility" + transitionOption; - } - - if (!onlyFadeTransition) { - transitionOption = " " + duration + "s " + transitionCurve; - transitionText += (transitionText.length ? ',' : '') + (env.transformSupported ? "" + CSS_TRANSFORM_VENDOR + transitionOption : ",left" + transitionOption + ",top" + transitionOption); - } - - return CSS_TRANSITION_VENDOR + ':' + transitionText; - } - - function assembleTransform(x, y, toString) { - // If using float on style, the final width of the dom might - // keep changing slightly while mouse move. So `toFixed(0)` them. - var x0 = x.toFixed(0) + 'px'; - var y0 = y.toFixed(0) + 'px'; // not support transform, use `left` and `top` instead. - - if (!env.transformSupported) { - return toString ? "top:" + y0 + ";left:" + x0 + ";" : [['top', y0], ['left', x0]]; - } // support transform - - - var is3d = env.transform3dSupported; - var translate = "translate" + (is3d ? '3d' : '') + "(" + x0 + "," + y0 + (is3d ? ',0' : '') + ")"; - return toString ? 'top:0;left:0;' + CSS_TRANSFORM_VENDOR + ':' + translate + ';' : [['top', 0], ['left', 0], [TRANSFORM_VENDOR, translate]]; - } - /** - * @param {Object} textStyle - * @return {string} - * @inner - */ - - - function assembleFont(textStyleModel) { - var cssText = []; - var fontSize = textStyleModel.get('fontSize'); - var color = textStyleModel.getTextColor(); - color && cssText.push('color:' + color); - cssText.push('font:' + textStyleModel.getFont()); // @ts-ignore, leave it to the tooltip refactor. - - var lineHeight = retrieve2(textStyleModel.get('lineHeight'), Math.round(fontSize * 3 / 2)); - fontSize && cssText.push('line-height:' + lineHeight + 'px'); - var shadowColor = textStyleModel.get('textShadowColor'); - var shadowBlur = textStyleModel.get('textShadowBlur') || 0; - var shadowOffsetX = textStyleModel.get('textShadowOffsetX') || 0; - var shadowOffsetY = textStyleModel.get('textShadowOffsetY') || 0; - shadowColor && shadowBlur && cssText.push('text-shadow:' + shadowOffsetX + 'px ' + shadowOffsetY + 'px ' + shadowBlur + 'px ' + shadowColor); - each$4(['decoration', 'align'], function (name) { - var val = textStyleModel.get(name); - val && cssText.push('text-' + name + ':' + val); - }); - return cssText.join(';'); - } - - function assembleCssText(tooltipModel, enableTransition, onlyFadeTransition, enableDisplayTransition) { - var cssText = []; - var transitionDuration = tooltipModel.get('transitionDuration'); - var backgroundColor = tooltipModel.get('backgroundColor'); - var shadowBlur = tooltipModel.get('shadowBlur'); - var shadowColor = tooltipModel.get('shadowColor'); - var shadowOffsetX = tooltipModel.get('shadowOffsetX'); - var shadowOffsetY = tooltipModel.get('shadowOffsetY'); - var textStyleModel = tooltipModel.getModel('textStyle'); - var padding = getPaddingFromTooltipModel(tooltipModel, 'html'); - var boxShadow = shadowOffsetX + "px " + shadowOffsetY + "px " + shadowBlur + "px " + shadowColor; - cssText.push('box-shadow:' + boxShadow); // Animation transition. Do not animate when transitionDuration <= 0. - - enableTransition && transitionDuration > 0 && cssText.push(assembleTransition(transitionDuration, onlyFadeTransition, enableDisplayTransition)); - - if (backgroundColor) { - cssText.push('background-color:' + backgroundColor); - } // Border style - - - each$4(['width', 'color', 'radius'], function (name) { - var borderName = 'border-' + name; - var camelCase = toCamelCase(borderName); - var val = tooltipModel.get(camelCase); - val != null && cssText.push(borderName + ':' + val + (name === 'color' ? '' : 'px')); - }); // Text style - - cssText.push(assembleFont(textStyleModel)); // Padding - - if (padding != null) { - cssText.push('padding:' + normalizeCssArray(padding).join('px ') + 'px'); - } - - return cssText.join(';') + ';'; - } // If not able to make, do not modify the input `out`. - - - function makeStyleCoord$1(out, zr, container, zrX, zrY) { - var zrPainter = zr && zr.painter; - - if (container) { - var zrViewportRoot = zrPainter && zrPainter.getViewportRoot(); - - if (zrViewportRoot) { - // Some APPs might use scale on body, so we support CSS transform here. - transformLocalCoord(out, zrViewportRoot, container, zrX, zrY); - } - } else { - out[0] = zrX; - out[1] = zrY; // xy should be based on canvas root. But tooltipContent is - // the sibling of canvas root. So padding of ec container - // should be considered here. - - var viewportRootOffset = zrPainter && zrPainter.getViewportRootOffset(); - - if (viewportRootOffset) { - out[0] += viewportRootOffset.offsetLeft; - out[1] += viewportRootOffset.offsetTop; - } - } - - out[2] = out[0] / zr.getWidth(); - out[3] = out[1] / zr.getHeight(); - } - - var TooltipHTMLContent = - /** @class */ - function () { - function TooltipHTMLContent(api, opt) { - this._show = false; - this._styleCoord = [0, 0, 0, 0]; - this._enterable = true; - this._alwaysShowContent = false; - this._firstShow = true; - this._longHide = true; - - if (env.wxa) { - return null; - } - - var el = document.createElement('div'); // TODO: TYPE - - el.domBelongToZr = true; - this.el = el; - var zr = this._zr = api.getZr(); - var appendTo = opt.appendTo; - var container = appendTo && (isString(appendTo) ? document.querySelector(appendTo) : isDom(appendTo) ? appendTo : isFunction(appendTo) && appendTo(api.getDom())); - makeStyleCoord$1(this._styleCoord, zr, container, api.getWidth() / 2, api.getHeight() / 2); - (container || api.getDom()).appendChild(el); - this._api = api; - this._container = container; // FIXME - // Is it needed to trigger zr event manually if - // the browser do not support `pointer-events: none`. - - var self = this; - - el.onmouseenter = function () { - // clear the timeout in hideLater and keep showing tooltip - if (self._enterable) { - clearTimeout(self._hideTimeout); - self._show = true; - } - - self._inContent = true; - }; - - el.onmousemove = function (e) { - e = e || window.event; - - if (!self._enterable) { - // `pointer-events: none` is set to tooltip content div - // if `enterable` is set as `false`, and `el.onmousemove` - // can not be triggered. But in browser that do not - // support `pointer-events`, we need to do this: - // Try trigger zrender event to avoid mouse - // in and out shape too frequently - var handler = zr.handler; - var zrViewportRoot = zr.painter.getViewportRoot(); - normalizeEvent(zrViewportRoot, e, true); - handler.dispatch('mousemove', e); - } - }; - - el.onmouseleave = function () { - // set `_inContent` to `false` before `hideLater` - self._inContent = false; - - if (self._enterable) { - if (self._show) { - self.hideLater(self._hideDelay); - } - } - }; - } - /** - * Update when tooltip is rendered - */ - - - TooltipHTMLContent.prototype.update = function (tooltipModel) { - // FIXME - // Move this logic to ec main? - if (!this._container) { - var container = this._api.getDom(); - - var position = getComputedStyle(container, 'position'); - var domStyle = container.style; - - if (domStyle.position !== 'absolute' && position !== 'absolute') { - domStyle.position = 'relative'; - } - } // move tooltip if chart resized - - - var alwaysShowContent = tooltipModel.get('alwaysShowContent'); - alwaysShowContent && this._moveIfResized(); // update alwaysShowContent - - this._alwaysShowContent = alwaysShowContent; - this._enableDisplayTransition = tooltipModel.get('displayTransition') && tooltipModel.get('transitionDuration') > 0; // update className - - this.el.className = tooltipModel.get('className') || ''; // Hide the tooltip - // PENDING - // this.hide(); - }; - - TooltipHTMLContent.prototype.show = function (tooltipModel, nearPointColor) { - clearTimeout(this._hideTimeout); - clearTimeout(this._longHideTimeout); - var el = this.el; - var style = el.style; - var styleCoord = this._styleCoord; - - if (!el.innerHTML) { - style.display = 'none'; - } else { - style.cssText = gCssText + assembleCssText(tooltipModel, !this._firstShow, this._longHide, this._enableDisplayTransition) // initial transform - + assembleTransform(styleCoord[0], styleCoord[1], true) + ("border-color:" + convertToColorString(nearPointColor) + ";") + (tooltipModel.get('extraCssText') || '') // If mouse occasionally move over the tooltip, a mouseout event will be - // triggered by canvas, and cause some unexpectable result like dragging - // stop, "unfocusAdjacency". Here `pointer-events: none` is used to solve - // it. Although it is not supported by IE8~IE10, fortunately it is a rare - // scenario. - + (";pointer-events:" + (this._enterable ? 'auto' : 'none')); - } - - this._show = true; - this._firstShow = false; - this._longHide = false; - }; - - TooltipHTMLContent.prototype.setContent = function (content, markers, tooltipModel, borderColor, arrowPosition) { - var el = this.el; - - if (content == null) { - el.innerHTML = ''; - return; - } - - var arrow = ''; - - if (isString(arrowPosition) && tooltipModel.get('trigger') === 'item' && !shouldTooltipConfine(tooltipModel)) { - arrow = assembleArrow(tooltipModel, borderColor, arrowPosition); - } - - if (isString(content)) { - el.innerHTML = content + arrow; - } else if (content) { - // Clear previous - el.innerHTML = ''; - - if (!isArray(content)) { - content = [content]; - } - - for (var i = 0; i < content.length; i++) { - if (isDom(content[i]) && content[i].parentNode !== el) { - el.appendChild(content[i]); - } - } // no arrow if empty - - - if (arrow && el.childNodes.length) { - // no need to create a new parent element, but it's not supported by IE 10 and older. - // const arrowEl = document.createRange().createContextualFragment(arrow); - var arrowEl = document.createElement('div'); - arrowEl.innerHTML = arrow; - el.appendChild(arrowEl); - } - } - }; - - TooltipHTMLContent.prototype.setEnterable = function (enterable) { - this._enterable = enterable; - }; - - TooltipHTMLContent.prototype.getSize = function () { - var el = this.el; - return el ? [el.offsetWidth, el.offsetHeight] : [0, 0]; - }; - - TooltipHTMLContent.prototype.moveTo = function (zrX, zrY) { - if (!this.el) { - return; - } - - var styleCoord = this._styleCoord; - makeStyleCoord$1(styleCoord, this._zr, this._container, zrX, zrY); - - if (styleCoord[0] != null && styleCoord[1] != null) { - var style_1 = this.el.style; - var transforms = assembleTransform(styleCoord[0], styleCoord[1]); - each$4(transforms, function (transform) { - style_1[transform[0]] = transform[1]; - }); - } - }; - /** - * when `alwaysShowContent` is true, - * move the tooltip after chart resized - */ - - - TooltipHTMLContent.prototype._moveIfResized = function () { - // The ratio of left to width - var ratioX = this._styleCoord[2]; // The ratio of top to height - - var ratioY = this._styleCoord[3]; - this.moveTo(ratioX * this._zr.getWidth(), ratioY * this._zr.getHeight()); - }; - - TooltipHTMLContent.prototype.hide = function () { - var _this = this; - - var style = this.el.style; - - if (this._enableDisplayTransition) { - style.visibility = 'hidden'; - style.opacity = '0'; - } else { - style.display = 'none'; - } - - env.transform3dSupported && (style.willChange = ''); - this._show = false; - this._longHideTimeout = setTimeout(function () { - return _this._longHide = true; - }, 500); - }; - - TooltipHTMLContent.prototype.hideLater = function (time) { - if (this._show && !(this._inContent && this._enterable) && !this._alwaysShowContent) { - if (time) { - this._hideDelay = time; // Set show false to avoid invoke hideLater multiple times - - this._show = false; - this._hideTimeout = setTimeout(bind$1(this.hide, this), time); - } else { - this.hide(); - } - } - }; - - TooltipHTMLContent.prototype.isShow = function () { - return this._show; - }; - - TooltipHTMLContent.prototype.dispose = function () { - clearTimeout(this._hideTimeout); - clearTimeout(this._longHideTimeout); - var zr = this._zr; - transformLocalCoordClear(zr && zr.painter && zr.painter.getViewportRoot(), this._container); - var el = this.el; - - if (el) { - el.onmouseenter = el.onmousemove = el.onmouseleave = null; - var parentNode = el.parentNode; - parentNode && parentNode.removeChild(el); - } - - this.el = this._container = null; - }; - - return TooltipHTMLContent; - }(); - - var TooltipRichContent = - /** @class */ - function () { - function TooltipRichContent(api) { - this._show = false; - this._styleCoord = [0, 0, 0, 0]; - this._alwaysShowContent = false; - this._enterable = true; - this._zr = api.getZr(); - makeStyleCoord(this._styleCoord, this._zr, api.getWidth() / 2, api.getHeight() / 2); - } - /** - * Update when tooltip is rendered - */ - - - TooltipRichContent.prototype.update = function (tooltipModel) { - var alwaysShowContent = tooltipModel.get('alwaysShowContent'); - alwaysShowContent && this._moveIfResized(); // update alwaysShowContent - - this._alwaysShowContent = alwaysShowContent; - }; - - TooltipRichContent.prototype.show = function () { - if (this._hideTimeout) { - clearTimeout(this._hideTimeout); - } - - this.el.show(); - this._show = true; - }; - /** - * Set tooltip content - */ - - - TooltipRichContent.prototype.setContent = function (content, markupStyleCreator, tooltipModel, borderColor, arrowPosition) { - var _this = this; - - if (isObject$2(content)) { - throwError('Passing DOM nodes as content is not supported in richText tooltip!'); - } - - if (this.el) { - this._zr.remove(this.el); - } - - var textStyleModel = tooltipModel.getModel('textStyle'); - this.el = new ZRText({ - style: { - rich: markupStyleCreator.richTextStyles, - text: content, - lineHeight: 22, - borderWidth: 1, - borderColor: borderColor, - textShadowColor: textStyleModel.get('textShadowColor'), - fill: tooltipModel.get(['textStyle', 'color']), - padding: getPaddingFromTooltipModel(tooltipModel, 'richText'), - verticalAlign: 'top', - align: 'left' - }, - z: tooltipModel.get('z') - }); - each$4(['backgroundColor', 'borderRadius', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'], function (propName) { - _this.el.style[propName] = tooltipModel.get(propName); - }); - each$4(['textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY'], function (propName) { - _this.el.style[propName] = textStyleModel.get(propName) || 0; - }); - - this._zr.add(this.el); - - var self = this; - this.el.on('mouseover', function () { - // clear the timeout in hideLater and keep showing tooltip - if (self._enterable) { - clearTimeout(self._hideTimeout); - self._show = true; - } - - self._inContent = true; - }); - this.el.on('mouseout', function () { - if (self._enterable) { - if (self._show) { - self.hideLater(self._hideDelay); - } - } - - self._inContent = false; - }); - }; - - TooltipRichContent.prototype.setEnterable = function (enterable) { - this._enterable = enterable; - }; - - TooltipRichContent.prototype.getSize = function () { - var el = this.el; - var bounding = this.el.getBoundingRect(); // bounding rect does not include shadow. For renderMode richText, - // if overflow, it will be cut. So calculate them accurately. - - var shadowOuterSize = calcShadowOuterSize(el.style); - return [bounding.width + shadowOuterSize.left + shadowOuterSize.right, bounding.height + shadowOuterSize.top + shadowOuterSize.bottom]; - }; - - TooltipRichContent.prototype.moveTo = function (x, y) { - var el = this.el; - - if (el) { - var styleCoord = this._styleCoord; - makeStyleCoord(styleCoord, this._zr, x, y); - x = styleCoord[0]; - y = styleCoord[1]; - var style = el.style; - var borderWidth = mathMaxWith0(style.borderWidth || 0); - var shadowOuterSize = calcShadowOuterSize(style); // rich text x, y do not include border. - - el.x = x + borderWidth + shadowOuterSize.left; - el.y = y + borderWidth + shadowOuterSize.top; - el.markRedraw(); - } - }; - /** - * when `alwaysShowContent` is true, - * move the tooltip after chart resized - */ - - - TooltipRichContent.prototype._moveIfResized = function () { - // The ratio of left to width - var ratioX = this._styleCoord[2]; // The ratio of top to height - - var ratioY = this._styleCoord[3]; - this.moveTo(ratioX * this._zr.getWidth(), ratioY * this._zr.getHeight()); - }; - - TooltipRichContent.prototype.hide = function () { - if (this.el) { - this.el.hide(); - } - - this._show = false; - }; - - TooltipRichContent.prototype.hideLater = function (time) { - if (this._show && !(this._inContent && this._enterable) && !this._alwaysShowContent) { - if (time) { - this._hideDelay = time; // Set show false to avoid invoke hideLater multiple times - - this._show = false; - this._hideTimeout = setTimeout(bind$1(this.hide, this), time); - } else { - this.hide(); - } - } - }; - - TooltipRichContent.prototype.isShow = function () { - return this._show; - }; - - TooltipRichContent.prototype.dispose = function () { - this._zr.remove(this.el); - }; - - return TooltipRichContent; - }(); - - function mathMaxWith0(val) { - return Math.max(0, val); - } - - function calcShadowOuterSize(style) { - var shadowBlur = mathMaxWith0(style.shadowBlur || 0); - var shadowOffsetX = mathMaxWith0(style.shadowOffsetX || 0); - var shadowOffsetY = mathMaxWith0(style.shadowOffsetY || 0); - return { - left: mathMaxWith0(shadowBlur - shadowOffsetX), - right: mathMaxWith0(shadowBlur + shadowOffsetX), - top: mathMaxWith0(shadowBlur - shadowOffsetY), - bottom: mathMaxWith0(shadowBlur + shadowOffsetY) - }; - } - - function makeStyleCoord(out, zr, zrX, zrY) { - out[0] = zrX; - out[1] = zrY; - out[2] = out[0] / zr.getWidth(); - out[3] = out[1] / zr.getHeight(); - } - - var proxyRect = new Rect({ - shape: { - x: -1, - y: -1, - width: 2, - height: 2 - } - }); - - var TooltipView = - /** @class */ - function (_super) { - __extends(TooltipView, _super); - - function TooltipView() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = TooltipView.type; - return _this; - } - - TooltipView.prototype.init = function (ecModel, api) { - if (env.node || !api.getDom()) { - return; - } - - var tooltipModel = ecModel.getComponent('tooltip'); - var renderMode = this._renderMode = getTooltipRenderMode(tooltipModel.get('renderMode')); - this._tooltipContent = renderMode === 'richText' ? new TooltipRichContent(api) : new TooltipHTMLContent(api, { - appendTo: tooltipModel.get('appendToBody', true) ? 'body' : tooltipModel.get('appendTo', true) - }); - }; - - TooltipView.prototype.render = function (tooltipModel, ecModel, api) { - if (env.node || !api.getDom()) { - return; - } // Reset - - - this.group.removeAll(); - this._tooltipModel = tooltipModel; - this._ecModel = ecModel; - this._api = api; - var tooltipContent = this._tooltipContent; - tooltipContent.update(tooltipModel); - tooltipContent.setEnterable(tooltipModel.get('enterable')); - - this._initGlobalListener(); - - this._keepShow(); // PENDING - // `mousemove` event will be triggered very frequently when the mouse moves fast, - // which causes that the `updatePosition` function was also called frequently. - // In Chrome with devtools open and Firefox, tooltip looks laggy and shakes. See #14695 #16101 - // To avoid frequent triggering, - // consider throttling it in 50ms when transition is enabled - - - if (this._renderMode !== 'richText' && tooltipModel.get('transitionDuration')) { - createOrUpdate(this, '_updatePosition', 50, 'fixRate'); - } else { - clear(this, '_updatePosition'); - } - }; - - TooltipView.prototype._initGlobalListener = function () { - var tooltipModel = this._tooltipModel; - var triggerOn = tooltipModel.get('triggerOn'); - register('itemTooltip', this._api, bind$1(function (currTrigger, e, dispatchAction) { - // If 'none', it is not controlled by mouse totally. - if (triggerOn !== 'none') { - if (triggerOn.indexOf(currTrigger) >= 0) { - this._tryShow(e, dispatchAction); - } else if (currTrigger === 'leave') { - this._hide(dispatchAction); - } - } - }, this)); - }; - - TooltipView.prototype._keepShow = function () { - var tooltipModel = this._tooltipModel; - var ecModel = this._ecModel; - var api = this._api; - var triggerOn = tooltipModel.get('triggerOn'); // Try to keep the tooltip show when refreshing - - if (this._lastX != null && this._lastY != null // When user is willing to control tooltip totally using API, - // self.manuallyShowTip({x, y}) might cause tooltip hide, - // which is not expected. - && triggerOn !== 'none' && triggerOn !== 'click') { - var self_1 = this; - clearTimeout(this._refreshUpdateTimeout); - this._refreshUpdateTimeout = setTimeout(function () { - // Show tip next tick after other charts are rendered - // In case highlight action has wrong result - // FIXME - !api.isDisposed() && self_1.manuallyShowTip(tooltipModel, ecModel, api, { - x: self_1._lastX, - y: self_1._lastY, - dataByCoordSys: self_1._lastDataByCoordSys - }); - }); - } - }; - /** - * Show tip manually by - * dispatchAction({ - * type: 'showTip', - * x: 10, - * y: 10 - * }); - * Or - * dispatchAction({ - * type: 'showTip', - * seriesIndex: 0, - * dataIndex or dataIndexInside or name - * }); - * - * TODO Batch - */ - - - TooltipView.prototype.manuallyShowTip = function (tooltipModel, ecModel, api, payload) { - if (payload.from === this.uid || env.node || !api.getDom()) { - return; - } - - var dispatchAction = makeDispatchAction(payload, api); // Reset ticket - - this._ticket = ''; // When triggered from axisPointer. - - var dataByCoordSys = payload.dataByCoordSys; - var cmptRef = findComponentReference(payload, ecModel, api); - - if (cmptRef) { - var rect = cmptRef.el.getBoundingRect().clone(); - rect.applyTransform(cmptRef.el.transform); - - this._tryShow({ - offsetX: rect.x + rect.width / 2, - offsetY: rect.y + rect.height / 2, - target: cmptRef.el, - position: payload.position, - // When manully trigger, the mouse is not on the el, so we'd better to - // position tooltip on the bottom of the el and display arrow is possible. - positionDefault: 'bottom' - }, dispatchAction); - } else if (payload.tooltip && payload.x != null && payload.y != null) { - var el = proxyRect; - el.x = payload.x; - el.y = payload.y; - el.update(); - getECData(el).tooltipConfig = { - name: null, - option: payload.tooltip - }; // Manually show tooltip while view is not using zrender elements. - - this._tryShow({ - offsetX: payload.x, - offsetY: payload.y, - target: el - }, dispatchAction); - } else if (dataByCoordSys) { - this._tryShow({ - offsetX: payload.x, - offsetY: payload.y, - position: payload.position, - dataByCoordSys: dataByCoordSys, - tooltipOption: payload.tooltipOption - }, dispatchAction); - } else if (payload.seriesIndex != null) { - if (this._manuallyAxisShowTip(tooltipModel, ecModel, api, payload)) { - return; - } - - var pointInfo = findPointFromSeries(payload, ecModel); - var cx = pointInfo.point[0]; - var cy = pointInfo.point[1]; - - if (cx != null && cy != null) { - this._tryShow({ - offsetX: cx, - offsetY: cy, - target: pointInfo.el, - position: payload.position, - // When manully trigger, the mouse is not on the el, so we'd better to - // position tooltip on the bottom of the el and display arrow is possible. - positionDefault: 'bottom' - }, dispatchAction); - } - } else if (payload.x != null && payload.y != null) { - // FIXME - // should wrap dispatchAction like `axisPointer/globalListener` ? - api.dispatchAction({ - type: 'updateAxisPointer', - x: payload.x, - y: payload.y - }); - - this._tryShow({ - offsetX: payload.x, - offsetY: payload.y, - position: payload.position, - target: api.getZr().findHover(payload.x, payload.y).target - }, dispatchAction); - } - }; - - TooltipView.prototype.manuallyHideTip = function (tooltipModel, ecModel, api, payload) { - var tooltipContent = this._tooltipContent; - - if (this._tooltipModel) { - tooltipContent.hideLater(this._tooltipModel.get('hideDelay')); - } - - this._lastX = this._lastY = this._lastDataByCoordSys = null; - - if (payload.from !== this.uid) { - this._hide(makeDispatchAction(payload, api)); - } - }; // Be compatible with previous design, that is, when tooltip.type is 'axis' and - // dispatchAction 'showTip' with seriesIndex and dataIndex will trigger axis pointer - // and tooltip. - - - TooltipView.prototype._manuallyAxisShowTip = function (tooltipModel, ecModel, api, payload) { - var seriesIndex = payload.seriesIndex; - var dataIndex = payload.dataIndex; // @ts-ignore - - var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo; - - if (seriesIndex == null || dataIndex == null || coordSysAxesInfo == null) { - return; - } - - var seriesModel = ecModel.getSeriesByIndex(seriesIndex); - - if (!seriesModel) { - return; - } - - var data = seriesModel.getData(); - var tooltipCascadedModel = buildTooltipModel([data.getItemModel(dataIndex), seriesModel, (seriesModel.coordinateSystem || {}).model], this._tooltipModel); - - if (tooltipCascadedModel.get('trigger') !== 'axis') { - return; - } - - api.dispatchAction({ - type: 'updateAxisPointer', - seriesIndex: seriesIndex, - dataIndex: dataIndex, - position: payload.position - }); - return true; - }; - - TooltipView.prototype._tryShow = function (e, dispatchAction) { - var el = e.target; - var tooltipModel = this._tooltipModel; - - if (!tooltipModel) { - return; - } // Save mouse x, mouse y. So we can try to keep showing the tip if chart is refreshed - - - this._lastX = e.offsetX; - this._lastY = e.offsetY; - var dataByCoordSys = e.dataByCoordSys; - - if (dataByCoordSys && dataByCoordSys.length) { - this._showAxisTooltip(dataByCoordSys, e); - } else if (el) { - var ecData = getECData(el); - - if (ecData.ssrType === 'legend') { - // Don't trigger tooltip for legend tooltip item - return; - } - - this._lastDataByCoordSys = null; - var seriesDispatcher_1; - var cmptDispatcher_1; - findEventDispatcher(el, function (target) { - if (target.tooltipDisabled) { - seriesDispatcher_1 = cmptDispatcher_1 = null; - return true; - } - - if (seriesDispatcher_1 || cmptDispatcher_1) { - return; - } // Always show item tooltip if mouse is on the element with dataIndex - - - if (getECData(target).dataIndex != null) { - seriesDispatcher_1 = target; - } // Tooltip provided directly. Like legend. - else if (getECData(target).tooltipConfig != null) { - cmptDispatcher_1 = target; - } - }, true); - - if (seriesDispatcher_1) { - this._showSeriesItemTooltip(e, seriesDispatcher_1, dispatchAction); - } else if (cmptDispatcher_1) { - this._showComponentItemTooltip(e, cmptDispatcher_1, dispatchAction); - } else { - this._hide(dispatchAction); - } - } else { - this._lastDataByCoordSys = null; - - this._hide(dispatchAction); - } - }; - - TooltipView.prototype._showOrMove = function (tooltipModel, cb) { - // showDelay is used in this case: tooltip.enterable is set - // as true. User intent to move mouse into tooltip and click - // something. `showDelay` makes it easier to enter the content - // but tooltip do not move immediately. - var delay = tooltipModel.get('showDelay'); - cb = bind$1(cb, this); - clearTimeout(this._showTimout); - delay > 0 ? this._showTimout = setTimeout(cb, delay) : cb(); - }; - - TooltipView.prototype._showAxisTooltip = function (dataByCoordSys, e) { - var ecModel = this._ecModel; - var globalTooltipModel = this._tooltipModel; - var point = [e.offsetX, e.offsetY]; - var singleTooltipModel = buildTooltipModel([e.tooltipOption], globalTooltipModel); - var renderMode = this._renderMode; - var cbParamsList = []; - var articleMarkup = createTooltipMarkup('section', { - blocks: [], - noHeader: true - }); // Only for legacy: `Serise['formatTooltip']` returns a string. - - var markupTextArrLegacy = []; - var markupStyleCreator = new TooltipMarkupStyleCreator(); - each$4(dataByCoordSys, function (itemCoordSys) { - each$4(itemCoordSys.dataByAxis, function (axisItem) { - var axisModel = ecModel.getComponent(axisItem.axisDim + 'Axis', axisItem.axisIndex); - var axisValue = axisItem.value; - - if (!axisModel || axisValue == null) { - return; - } // FIXME: when using `tooltip.trigger: 'axis'`, the precision of the axis value displayed in tooltip - // should match the original series values rather than using the default stretegy in Interval.ts - // (getPrecision(interval) + 2); otherwise it may cuase confusion. - - - var axisValueLabel = getValueLabel(axisValue, axisModel.axis, ecModel, axisItem.seriesDataIndices, axisItem.valueLabelOpt); - var axisSectionMarkup = createTooltipMarkup('section', { - header: axisValueLabel, - noHeader: !trim(axisValueLabel), - sortBlocks: true, - blocks: [] - }); - articleMarkup.blocks.push(axisSectionMarkup); - each$4(axisItem.seriesDataIndices, function (idxItem) { - var series = ecModel.getSeriesByIndex(idxItem.seriesIndex); - var dataIndex = idxItem.dataIndexInside; - var cbParams = series.getDataParams(dataIndex); // Can't find data. - - if (cbParams.dataIndex < 0) { - return; - } - - cbParams.axisDim = axisItem.axisDim; - cbParams.axisIndex = axisItem.axisIndex; - cbParams.axisType = axisItem.axisType; - cbParams.axisId = axisItem.axisId; - cbParams.axisValue = getAxisRawValue(axisModel.axis, { - value: axisValue - }); - cbParams.axisValueLabel = axisValueLabel; // Pre-create marker style for makers. Users can assemble richText - // text in `formatter` callback and use those markers style. - - cbParams.marker = markupStyleCreator.makeTooltipMarker('item', convertToColorString(cbParams.color), renderMode); - var seriesTooltipResult = normalizeTooltipFormatResult(series.formatTooltip(dataIndex, true, null)); - var frag = seriesTooltipResult.frag; - - if (frag) { - var valueFormatter = buildTooltipModel([series], globalTooltipModel).get('valueFormatter'); - axisSectionMarkup.blocks.push(valueFormatter ? extend({ - valueFormatter: valueFormatter - }, frag) : frag); - } - - if (seriesTooltipResult.text) { - markupTextArrLegacy.push(seriesTooltipResult.text); - } - - cbParamsList.push(cbParams); - }); - }); - }); // In most cases, the second axis is displays upper on the first one. - // So we reverse it to look better. - - articleMarkup.blocks.reverse(); - markupTextArrLegacy.reverse(); - var positionExpr = e.position; - var orderMode = singleTooltipModel.get('order'); - var builtMarkupText = buildTooltipMarkup(articleMarkup, markupStyleCreator, renderMode, orderMode, ecModel.get('useUTC'), singleTooltipModel.get('textStyle')); - builtMarkupText && markupTextArrLegacy.unshift(builtMarkupText); - var blockBreak = renderMode === 'richText' ? '\n\n' : '
'; - var allMarkupText = markupTextArrLegacy.join(blockBreak); - - this._showOrMove(singleTooltipModel, function () { - if (this._updateContentNotChangedOnAxis(dataByCoordSys, cbParamsList)) { - this._updatePosition(singleTooltipModel, positionExpr, point[0], point[1], this._tooltipContent, cbParamsList); - } else { - this._showTooltipContent(singleTooltipModel, allMarkupText, cbParamsList, Math.random() + '', point[0], point[1], positionExpr, null, markupStyleCreator); - } - }); // Do not trigger events here, because this branch only be entered - // from dispatchAction. - - }; - - TooltipView.prototype._showSeriesItemTooltip = function (e, dispatcher, dispatchAction) { - var ecModel = this._ecModel; - var ecData = getECData(dispatcher); // Use dataModel in element if possible - // Used when mouseover on a element like markPoint or edge - // In which case, the data is not main data in series. - - var seriesIndex = ecData.seriesIndex; - var seriesModel = ecModel.getSeriesByIndex(seriesIndex); // For example, graph link. - - var dataModel = ecData.dataModel || seriesModel; - var dataIndex = ecData.dataIndex; - var dataType = ecData.dataType; - var data = dataModel.getData(dataType); - var renderMode = this._renderMode; - var positionDefault = e.positionDefault; - var tooltipModel = buildTooltipModel([data.getItemModel(dataIndex), dataModel, seriesModel && (seriesModel.coordinateSystem || {}).model], this._tooltipModel, positionDefault ? { - position: positionDefault - } : null); - var tooltipTrigger = tooltipModel.get('trigger'); - - if (tooltipTrigger != null && tooltipTrigger !== 'item') { - return; - } - - var params = dataModel.getDataParams(dataIndex, dataType); - var markupStyleCreator = new TooltipMarkupStyleCreator(); // Pre-create marker style for makers. Users can assemble richText - // text in `formatter` callback and use those markers style. - - params.marker = markupStyleCreator.makeTooltipMarker('item', convertToColorString(params.color), renderMode); - var seriesTooltipResult = normalizeTooltipFormatResult(dataModel.formatTooltip(dataIndex, false, dataType)); - var orderMode = tooltipModel.get('order'); - var valueFormatter = tooltipModel.get('valueFormatter'); - var frag = seriesTooltipResult.frag; - var markupText = frag ? buildTooltipMarkup(valueFormatter ? extend({ - valueFormatter: valueFormatter - }, frag) : frag, markupStyleCreator, renderMode, orderMode, ecModel.get('useUTC'), tooltipModel.get('textStyle')) : seriesTooltipResult.text; - var asyncTicket = 'item_' + dataModel.name + '_' + dataIndex; - - this._showOrMove(tooltipModel, function () { - this._showTooltipContent(tooltipModel, markupText, params, asyncTicket, e.offsetX, e.offsetY, e.position, e.target, markupStyleCreator); - }); // FIXME - // duplicated showtip if manuallyShowTip is called from dispatchAction. - - - dispatchAction({ - type: 'showTip', - dataIndexInside: dataIndex, - dataIndex: data.getRawIndex(dataIndex), - seriesIndex: seriesIndex, - from: this.uid - }); - }; - - TooltipView.prototype._showComponentItemTooltip = function (e, el, dispatchAction) { - var isHTMLRenderMode = this._renderMode === 'html'; - var ecData = getECData(el); - var tooltipConfig = ecData.tooltipConfig; - var tooltipOpt = tooltipConfig.option || {}; - var encodeHTMLContent = tooltipOpt.encodeHTMLContent; - - if (isString(tooltipOpt)) { - var content = tooltipOpt; - tooltipOpt = { - content: content, - // Fixed formatter - formatter: content - }; // when `tooltipConfig.option` is a string rather than an object, - // we can't know if the content needs to be encoded - // for the sake of security, encode it by default. - - encodeHTMLContent = true; - } - - if (encodeHTMLContent && isHTMLRenderMode && tooltipOpt.content) { - // clone might be unnecessary? - tooltipOpt = clone$3(tooltipOpt); - tooltipOpt.content = encodeHTML(tooltipOpt.content); - } - - var tooltipModelCascade = [tooltipOpt]; - - var cmpt = this._ecModel.getComponent(ecData.componentMainType, ecData.componentIndex); - - if (cmpt) { - tooltipModelCascade.push(cmpt); - } // In most cases, component tooltip formatter has different params with series tooltip formatter, - // so that they cannot share the same formatter. Since the global tooltip formatter is used for series - // by convention, we do not use it as the default formatter for component. - - - tooltipModelCascade.push({ - formatter: tooltipOpt.content - }); - var positionDefault = e.positionDefault; - var subTooltipModel = buildTooltipModel(tooltipModelCascade, this._tooltipModel, positionDefault ? { - position: positionDefault - } : null); - var defaultHtml = subTooltipModel.get('content'); - var asyncTicket = Math.random() + ''; // PENDING: this case do not support richText style yet. - - var markupStyleCreator = new TooltipMarkupStyleCreator(); // Do not check whether `trigger` is 'none' here, because `trigger` - // only works on coordinate system. In fact, we have not found case - // that requires setting `trigger` nothing on component yet. - - this._showOrMove(subTooltipModel, function () { - // Use formatterParams from element defined in component - // Avoid users modify it. - var formatterParams = clone$3(subTooltipModel.get('formatterParams') || {}); - - this._showTooltipContent(subTooltipModel, defaultHtml, formatterParams, asyncTicket, e.offsetX, e.offsetY, e.position, el, markupStyleCreator); - }); // If not dispatch showTip, tip may be hide triggered by axis. - - - dispatchAction({ - type: 'showTip', - from: this.uid - }); - }; - - TooltipView.prototype._showTooltipContent = function ( // Use Model insteadof TooltipModel because this model may be from series or other options. - // Instead of top level tooltip. - tooltipModel, defaultHtml, params, asyncTicket, x, y, positionExpr, el, markupStyleCreator) { - // Reset ticket - this._ticket = ''; - - if (!tooltipModel.get('showContent') || !tooltipModel.get('show')) { - return; - } - - var tooltipContent = this._tooltipContent; - tooltipContent.setEnterable(tooltipModel.get('enterable')); - var formatter = tooltipModel.get('formatter'); - positionExpr = positionExpr || tooltipModel.get('position'); - var html = defaultHtml; - - var nearPoint = this._getNearestPoint([x, y], params, tooltipModel.get('trigger'), tooltipModel.get('borderColor'), tooltipModel.get('defaultBorderColor', true)); - - var nearPointColor = nearPoint.color; - - if (formatter) { - if (isString(formatter)) { - var useUTC = tooltipModel.ecModel.get('useUTC'); - var params0 = isArray(params) ? params[0] : params; - var isTimeAxis = params0 && params0.axisType && params0.axisType.indexOf('time') >= 0; - html = formatter; - - if (isTimeAxis) { - html = format$1(params0.axisValue, html, useUTC); - } - - html = formatTpl(html, params, true); - } else if (isFunction(formatter)) { - var callback = bind$1(function (cbTicket, html) { - if (cbTicket === this._ticket) { - tooltipContent.setContent(html, markupStyleCreator, tooltipModel, nearPointColor, positionExpr); - - this._updatePosition(tooltipModel, positionExpr, x, y, tooltipContent, params, el); - } - }, this); - this._ticket = asyncTicket; - html = formatter(params, asyncTicket, callback); - } else { - html = formatter; - } - } - - tooltipContent.setContent(html, markupStyleCreator, tooltipModel, nearPointColor, positionExpr); - tooltipContent.show(tooltipModel, nearPointColor); - - this._updatePosition(tooltipModel, positionExpr, x, y, tooltipContent, params, el); - }; - - TooltipView.prototype._getNearestPoint = function (point, tooltipDataParams, trigger, borderColor, defaultBorderColor) { - if (trigger === 'axis' || isArray(tooltipDataParams)) { - return { - color: borderColor || defaultBorderColor - }; - } - - if (!isArray(tooltipDataParams)) { - return { - color: borderColor || tooltipDataParams.color || tooltipDataParams.borderColor - }; - } - }; - - TooltipView.prototype._updatePosition = function (tooltipModel, positionExpr, x, // Mouse x - y, // Mouse y - content, params, el) { - var viewWidth = this._api.getWidth(); - - var viewHeight = this._api.getHeight(); - - positionExpr = positionExpr || tooltipModel.get('position'); - var contentSize = content.getSize(); - var align = tooltipModel.get('align'); - var vAlign = tooltipModel.get('verticalAlign'); - var rect = el && el.getBoundingRect().clone(); - el && rect.applyTransform(el.transform); - - if (isFunction(positionExpr)) { - // Callback of position can be an array or a string specify the position - positionExpr = positionExpr([x, y], params, content.el, rect, { - viewSize: [viewWidth, viewHeight], - contentSize: contentSize.slice() - }); - } - - if (isArray(positionExpr)) { - x = parsePercent(positionExpr[0], viewWidth); - y = parsePercent(positionExpr[1], viewHeight); - } else if (isObject$2(positionExpr)) { - var boxLayoutPosition = positionExpr; - boxLayoutPosition.width = contentSize[0]; - boxLayoutPosition.height = contentSize[1]; - var layoutRect = getLayoutRect(boxLayoutPosition, { - width: viewWidth, - height: viewHeight - }); - x = layoutRect.x; - y = layoutRect.y; - align = null; // When positionExpr is left/top/right/bottom, - // align and verticalAlign will not work. - - vAlign = null; - } // Specify tooltip position by string 'top' 'bottom' 'left' 'right' around graphic element - else if (isString(positionExpr) && el) { - var pos = calcTooltipPosition(positionExpr, rect, contentSize, tooltipModel.get('borderWidth')); - x = pos[0]; - y = pos[1]; - } else { - var pos = refixTooltipPosition(x, y, content, viewWidth, viewHeight, align ? null : 20, vAlign ? null : 20); - x = pos[0]; - y = pos[1]; - } - - align && (x -= isCenterAlign(align) ? contentSize[0] / 2 : align === 'right' ? contentSize[0] : 0); - vAlign && (y -= isCenterAlign(vAlign) ? contentSize[1] / 2 : vAlign === 'bottom' ? contentSize[1] : 0); - - if (shouldTooltipConfine(tooltipModel)) { - var pos = confineTooltipPosition(x, y, content, viewWidth, viewHeight); - x = pos[0]; - y = pos[1]; - } - - content.moveTo(x, y); - }; // FIXME - // Should we remove this but leave this to user? - - - TooltipView.prototype._updateContentNotChangedOnAxis = function (dataByCoordSys, cbParamsList) { - var lastCoordSys = this._lastDataByCoordSys; - var lastCbParamsList = this._cbParamsList; - var contentNotChanged = !!lastCoordSys && lastCoordSys.length === dataByCoordSys.length; - contentNotChanged && each$4(lastCoordSys, function (lastItemCoordSys, indexCoordSys) { - var lastDataByAxis = lastItemCoordSys.dataByAxis || []; - var thisItemCoordSys = dataByCoordSys[indexCoordSys] || {}; - var thisDataByAxis = thisItemCoordSys.dataByAxis || []; - contentNotChanged = contentNotChanged && lastDataByAxis.length === thisDataByAxis.length; - contentNotChanged && each$4(lastDataByAxis, function (lastItem, indexAxis) { - var thisItem = thisDataByAxis[indexAxis] || {}; - var lastIndices = lastItem.seriesDataIndices || []; - var newIndices = thisItem.seriesDataIndices || []; - contentNotChanged = contentNotChanged && lastItem.value === thisItem.value && lastItem.axisType === thisItem.axisType && lastItem.axisId === thisItem.axisId && lastIndices.length === newIndices.length; - contentNotChanged && each$4(lastIndices, function (lastIdxItem, j) { - var newIdxItem = newIndices[j]; - contentNotChanged = contentNotChanged && lastIdxItem.seriesIndex === newIdxItem.seriesIndex && lastIdxItem.dataIndex === newIdxItem.dataIndex; - }); // check is cbParams data value changed - - lastCbParamsList && each$4(lastItem.seriesDataIndices, function (idxItem) { - var seriesIdx = idxItem.seriesIndex; - var cbParams = cbParamsList[seriesIdx]; - var lastCbParams = lastCbParamsList[seriesIdx]; - - if (cbParams && lastCbParams && lastCbParams.data !== cbParams.data) { - contentNotChanged = false; - } - }); - }); - }); - this._lastDataByCoordSys = dataByCoordSys; - this._cbParamsList = cbParamsList; - return !!contentNotChanged; - }; - - TooltipView.prototype._hide = function (dispatchAction) { - // Do not directly hideLater here, because this behavior may be prevented - // in dispatchAction when showTip is dispatched. - // FIXME - // duplicated hideTip if manuallyHideTip is called from dispatchAction. - this._lastDataByCoordSys = null; - dispatchAction({ - type: 'hideTip', - from: this.uid - }); - }; - - TooltipView.prototype.dispose = function (ecModel, api) { - if (env.node || !api.getDom()) { - return; - } - - clear(this, '_updatePosition'); - - this._tooltipContent.dispose(); - - unregister('itemTooltip', api); - }; - - TooltipView.type = 'tooltip'; - return TooltipView; - }(ComponentView); - /** - * From top to bottom. (the last one should be globalTooltipModel); - */ - - - function buildTooltipModel(modelCascade, globalTooltipModel, defaultTooltipOption) { - // Last is always tooltip model. - var ecModel = globalTooltipModel.ecModel; - var resultModel; - - if (defaultTooltipOption) { - resultModel = new Model(defaultTooltipOption, ecModel, ecModel); - resultModel = new Model(globalTooltipModel.option, resultModel, ecModel); - } else { - resultModel = globalTooltipModel; - } - - for (var i = modelCascade.length - 1; i >= 0; i--) { - var tooltipOpt = modelCascade[i]; - - if (tooltipOpt) { - if (tooltipOpt instanceof Model) { - tooltipOpt = tooltipOpt.get('tooltip', true); - } // In each data item tooltip can be simply write: - // { - // value: 10, - // tooltip: 'Something you need to know' - // } - - - if (isString(tooltipOpt)) { - tooltipOpt = { - formatter: tooltipOpt - }; - } - - if (tooltipOpt) { - resultModel = new Model(tooltipOpt, resultModel, ecModel); - } - } - } - - return resultModel; - } - - function makeDispatchAction(payload, api) { - return payload.dispatchAction || bind$1(api.dispatchAction, api); - } - - function refixTooltipPosition(x, y, content, viewWidth, viewHeight, gapH, gapV) { - var size = content.getSize(); - var width = size[0]; - var height = size[1]; - - if (gapH != null) { - // Add extra 2 pixels for this case: - // At present the "values" in default tooltip are using CSS `float: right`. - // When the right edge of the tooltip box is on the right side of the - // viewport, the `float` layout might push the "values" to the second line. - if (x + width + gapH + 2 > viewWidth) { - x -= width + gapH; - } else { - x += gapH; - } - } - - if (gapV != null) { - if (y + height + gapV > viewHeight) { - y -= height + gapV; - } else { - y += gapV; - } - } - - return [x, y]; - } - - function confineTooltipPosition(x, y, content, viewWidth, viewHeight) { - var size = content.getSize(); - var width = size[0]; - var height = size[1]; - x = Math.min(x + width, viewWidth) - width; - y = Math.min(y + height, viewHeight) - height; - x = Math.max(x, 0); - y = Math.max(y, 0); - return [x, y]; - } - - function calcTooltipPosition(position, rect, contentSize, borderWidth) { - var domWidth = contentSize[0]; - var domHeight = contentSize[1]; - var offset = Math.ceil(Math.SQRT2 * borderWidth) + 8; - var x = 0; - var y = 0; - var rectWidth = rect.width; - var rectHeight = rect.height; - - switch (position) { - case 'inside': - x = rect.x + rectWidth / 2 - domWidth / 2; - y = rect.y + rectHeight / 2 - domHeight / 2; - break; - - case 'top': - x = rect.x + rectWidth / 2 - domWidth / 2; - y = rect.y - domHeight - offset; - break; - - case 'bottom': - x = rect.x + rectWidth / 2 - domWidth / 2; - y = rect.y + rectHeight + offset; - break; - - case 'left': - x = rect.x - domWidth - offset; - y = rect.y + rectHeight / 2 - domHeight / 2; - break; - - case 'right': - x = rect.x + rectWidth + offset; - y = rect.y + rectHeight / 2 - domHeight / 2; - } - - return [x, y]; - } - - function isCenterAlign(align) { - return align === 'center' || align === 'middle'; - } - /** - * Find target component by payload like: - * ```js - * { legendId: 'some_id', name: 'xxx' } - * { toolboxIndex: 1, name: 'xxx' } - * { geoName: 'some_name', name: 'xxx' } - * ``` - * PENDING: at present only - * - * If not found, return null/undefined. - */ - - - function findComponentReference(payload, ecModel, api) { - var queryOptionMap = preParseFinder(payload).queryOptionMap; - var componentMainType = queryOptionMap.keys()[0]; - - if (!componentMainType || componentMainType === 'series') { - return; - } - - var queryResult = queryReferringComponents(ecModel, componentMainType, queryOptionMap.get(componentMainType), { - useDefault: false, - enableAll: false, - enableNone: false - }); - var model = queryResult.models[0]; - - if (!model) { - return; - } - - var view = api.getViewOfComponentModel(model); - var el; - view.group.traverse(function (subEl) { - var tooltipConfig = getECData(subEl).tooltipConfig; - - if (tooltipConfig && tooltipConfig.name === payload.name) { - el = subEl; - return true; // stop - } - }); - - if (el) { - return { - componentMainType: componentMainType, - componentIndex: model.componentIndex, - el: el - }; - } - } - - function install$2(registers) { - use(install$3); - registers.registerComponentModel(TooltipModel); - registers.registerComponentView(TooltipView); - /** - * @action - * @property {string} type - * @property {number} seriesIndex - * @property {number} dataIndex - * @property {number} [x] - * @property {number} [y] - */ - - registers.registerAction({ - type: 'showTip', - event: 'showTip', - update: 'tooltip:manuallyShowTip' - }, noop); - registers.registerAction({ - type: 'hideTip', - event: 'hideTip', - update: 'tooltip:manuallyHideTip' - }, noop); - } - - use(install$2); - - function checkMarkerInSeries(seriesOpts, markerType) { - if (!seriesOpts) { - return false; - } - - var seriesOptArr = isArray(seriesOpts) ? seriesOpts : [seriesOpts]; - - for (var idx = 0; idx < seriesOptArr.length; idx++) { - if (seriesOptArr[idx] && seriesOptArr[idx][markerType]) { - return true; - } - } - - return false; - } - - function fillLabel(opt) { - defaultEmphasis(opt, 'label', ['show']); - } // { [componentType]: MarkerModel } - - - var inner$2 = makeInner(); - - var MarkerModel = - /** @class */ - function (_super) { - __extends(MarkerModel, _super); - - function MarkerModel() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = MarkerModel.type; - /** - * If marker model is created by self from series - */ - - _this.createdBySelf = false; - _this.preventAutoZ = true; - return _this; - } - /** - * @overrite - */ - - - MarkerModel.prototype.init = function (option, parentModel, ecModel) { - { - if (this.type === 'marker') { - throw new Error('Marker component is abstract component. Use markLine, markPoint, markArea instead.'); - } - } - this.mergeDefaultAndTheme(option, ecModel); - - this._mergeOption(option, ecModel, false, true); - }; - - MarkerModel.prototype.isAnimationEnabled = function () { - if (env.node) { - return false; - } - - var hostSeries = this.__hostSeries; - return this.getShallow('animation') && hostSeries && hostSeries.isAnimationEnabled(); - }; - /** - * @overrite - */ - - - MarkerModel.prototype.mergeOption = function (newOpt, ecModel) { - this._mergeOption(newOpt, ecModel, false, false); - }; - - MarkerModel.prototype._mergeOption = function (newOpt, ecModel, createdBySelf, isInit) { - var componentType = this.mainType; - - if (!createdBySelf) { - ecModel.eachSeries(function (seriesModel) { - // mainType can be markPoint, markLine, markArea - var markerOpt = seriesModel.get(this.mainType, true); - var markerModel = inner$2(seriesModel)[componentType]; - - if (!markerOpt || !markerOpt.data) { - inner$2(seriesModel)[componentType] = null; - return; - } - - if (!markerModel) { - if (isInit) { - // Default label emphasis `position` and `show` - fillLabel(markerOpt); - } - - each$4(markerOpt.data, function (item) { - // FIXME Overwrite fillLabel method ? - if (item instanceof Array) { - fillLabel(item[0]); - fillLabel(item[1]); - } else { - fillLabel(item); - } - }); - markerModel = this.createMarkerModelFromSeries(markerOpt, this, ecModel); // markerModel = new ImplementedMarkerModel( - // markerOpt, this, ecModel - // ); - - extend(markerModel, { - mainType: this.mainType, - // Use the same series index and name - seriesIndex: seriesModel.seriesIndex, - name: seriesModel.name, - createdBySelf: true - }); - markerModel.__hostSeries = seriesModel; - } else { - markerModel._mergeOption(markerOpt, ecModel, true); - } - - inner$2(seriesModel)[componentType] = markerModel; - }, this); - } - }; - - MarkerModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) { - var data = this.getData(); - var value = this.getRawValue(dataIndex); - var itemName = data.getName(dataIndex); - return createTooltipMarkup('section', { - header: this.name, - blocks: [createTooltipMarkup('nameValue', { - name: itemName, - value: value, - noName: !itemName, - noValue: value == null - })] - }); - }; - - MarkerModel.prototype.getData = function () { - return this._data; - }; - - MarkerModel.prototype.setData = function (data) { - this._data = data; - }; - - MarkerModel.prototype.getDataParams = function (dataIndex, dataType) { - var params = DataFormatMixin.prototype.getDataParams.call(this, dataIndex, dataType); - var hostSeries = this.__hostSeries; - - if (hostSeries) { - params.seriesId = hostSeries.id; - params.seriesName = hostSeries.name; - params.seriesType = hostSeries.subType; - } - - return params; - }; - - MarkerModel.getMarkerModelFromSeries = function (seriesModel, // Support three types of markers. Strict check. - componentType) { - return inner$2(seriesModel)[componentType]; - }; - - MarkerModel.type = 'marker'; - MarkerModel.dependencies = ['series', 'grid', 'polar', 'geo']; - return MarkerModel; - }(ComponentModel); - - mixin(MarkerModel, DataFormatMixin.prototype); - - var MarkAreaModel = - /** @class */ - function (_super) { - __extends(MarkAreaModel, _super); - - function MarkAreaModel() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = MarkAreaModel.type; - return _this; - } - - MarkAreaModel.prototype.createMarkerModelFromSeries = function (markerOpt, masterMarkerModel, ecModel) { - return new MarkAreaModel(markerOpt, masterMarkerModel, ecModel); - }; - - MarkAreaModel.type = 'markArea'; - MarkAreaModel.defaultOption = { - // zlevel: 0, - // PENDING - z: 1, - tooltip: { - trigger: 'item' - }, - // markArea should fixed on the coordinate system - animation: false, - label: { - show: true, - position: 'top' - }, - itemStyle: { - // color and borderColor default to use color from series - // color: 'auto' - // borderColor: 'auto' - borderWidth: 0 - }, - emphasis: { - label: { - show: true, - position: 'top' - } - } - }; - return MarkAreaModel; - }(MarkerModel); - - function hasXOrY(item) { - return !(isNaN(parseFloat(item.x)) && isNaN(parseFloat(item.y))); - } - - function hasXAndY(item) { - return !isNaN(parseFloat(item.x)) && !isNaN(parseFloat(item.y)); - } - - function markerTypeCalculatorWithExtent(markerType, data, axisDim, otherDataDim, targetDataDim, otherCoordIndex, targetCoordIndex) { - var coordArr = []; - var stacked = isDimensionStacked(data, targetDataDim - /* , otherDataDim */ - ); - var calcDataDim = stacked ? data.getCalculationInfo('stackResultDimension') : targetDataDim; - var value = numCalculate(data, calcDataDim, markerType); - var seriesModel = data.hostModel; - var dataIndex = seriesModel.indicesOfNearest(axisDim, calcDataDim, value)[0]; - coordArr[otherCoordIndex] = data.get(otherDataDim, dataIndex); - coordArr[targetCoordIndex] = data.get(calcDataDim, dataIndex); - var coordArrValue = data.get(targetDataDim, dataIndex); // Make it simple, do not visit all stacked value to count precision. - - var precision = getPrecision(data.get(targetDataDim, dataIndex)); - precision = Math.min(precision, 20); - - if (precision >= 0) { - coordArr[targetCoordIndex] = +coordArr[targetCoordIndex].toFixed(precision); - } - - return [coordArr, coordArrValue]; - } // TODO Specified percent - - - var markerTypeCalculator = { - min: curry$1(markerTypeCalculatorWithExtent, 'min'), - max: curry$1(markerTypeCalculatorWithExtent, 'max'), - average: curry$1(markerTypeCalculatorWithExtent, 'average'), - median: curry$1(markerTypeCalculatorWithExtent, 'median') - }; - /** - * Transform markPoint data item to format used in List by do the following - * 1. Calculate statistic like `max`, `min`, `average` - * 2. Convert `item.xAxis`, `item.yAxis` to `item.coord` array - */ - - function dataTransform(seriesModel, item) { - if (!item) { - return; - } - - var data = seriesModel.getData(); - var coordSys = seriesModel.coordinateSystem; - var dims = coordSys && coordSys.dimensions; // 1. If not specify the position with pixel directly - // 2. If `coord` is not a data array. Which uses `xAxis`, - // `yAxis` to specify the coord on each dimension - // parseFloat first because item.x and item.y can be percent string like '20%' - - if (!hasXAndY(item) && !isArray(item.coord) && isArray(dims)) { - var axisInfo = getAxisInfo(item, data, coordSys, seriesModel); // Clone the option - // Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value - - item = clone$3(item); - - if (item.type && markerTypeCalculator[item.type] && axisInfo.baseAxis && axisInfo.valueAxis) { - var otherCoordIndex = indexOf(dims, axisInfo.baseAxis.dim); - var targetCoordIndex = indexOf(dims, axisInfo.valueAxis.dim); - var coordInfo = markerTypeCalculator[item.type](data, axisInfo.valueAxis.dim, axisInfo.baseDataDim, axisInfo.valueDataDim, otherCoordIndex, targetCoordIndex); - item.coord = coordInfo[0]; // Force to use the value of calculated value. - // let item use the value without stack. - - item.value = coordInfo[1]; - } else { - // FIXME Only has one of xAxis and yAxis. - item.coord = [item.xAxis != null ? item.xAxis : item.radiusAxis, item.yAxis != null ? item.yAxis : item.angleAxis]; - } - } // x y is provided - - - if (item.coord == null || !isArray(dims)) { - item.coord = []; - var baseAxis = seriesModel.getBaseAxis(); - - if (baseAxis && item.type && markerTypeCalculator[item.type]) { - var otherAxis = coordSys.getOtherAxis(baseAxis); - - if (otherAxis) { - item.value = numCalculate(data, data.mapDimension(otherAxis.dim), item.type); - } - } - } else { - // Each coord support max, min, average - var coord = item.coord; - - for (var i = 0; i < 2; i++) { - if (markerTypeCalculator[coord[i]]) { - coord[i] = numCalculate(data, data.mapDimension(dims[i]), coord[i]); - } - } - } - - return item; - } - - function getAxisInfo(item, data, coordSys, seriesModel) { - var ret = {}; - - if (item.valueIndex != null || item.valueDim != null) { - ret.valueDataDim = item.valueIndex != null ? data.getDimension(item.valueIndex) : item.valueDim; - ret.valueAxis = coordSys.getAxis(dataDimToCoordDim(seriesModel, ret.valueDataDim)); - ret.baseAxis = coordSys.getOtherAxis(ret.valueAxis); - ret.baseDataDim = data.mapDimension(ret.baseAxis.dim); - } else { - ret.baseAxis = seriesModel.getBaseAxis(); - ret.valueAxis = coordSys.getOtherAxis(ret.baseAxis); - ret.baseDataDim = data.mapDimension(ret.baseAxis.dim); - ret.valueDataDim = data.mapDimension(ret.valueAxis.dim); - } - - return ret; - } - - function dataDimToCoordDim(seriesModel, dataDim) { - var dimItem = seriesModel.getData().getDimensionInfo(dataDim); - return dimItem && dimItem.coordDim; - } - /** - * Filter data which is out of coordinateSystem range - * [dataFilter description] - */ - - - function dataFilter( // Currently only polar and cartesian has containData. - coordSys, item) { - // Always return true if there is no coordSys - return coordSys && coordSys.containData && item.coord && !hasXOrY(item) ? coordSys.containData(item.coord) : true; - } - - function zoneFilter( // Currently only polar and cartesian has containData. - coordSys, item1, item2) { - // Always return true if there is no coordSys - return coordSys && coordSys.containZone && item1.coord && item2.coord && !hasXOrY(item1) && !hasXOrY(item2) ? coordSys.containZone(item1.coord, item2.coord) : true; - } - - function numCalculate(data, valueDataDim, type) { - if (type === 'average') { - var sum_1 = 0; - var count_1 = 0; - data.each(valueDataDim, function (val, idx) { - if (!isNaN(val)) { - sum_1 += val; - count_1++; - } - }); - return sum_1 / count_1; - } else if (type === 'median') { - return data.getMedian(valueDataDim); - } else { - // max & min - return data.getDataExtent(valueDataDim)[type === 'max' ? 1 : 0]; - } - } - - var inner$1 = makeInner(); - - var MarkerView = - /** @class */ - function (_super) { - __extends(MarkerView, _super); - - function MarkerView() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = MarkerView.type; - return _this; - } - - MarkerView.prototype.init = function () { - this.markerGroupMap = createHashMap(); - }; - - MarkerView.prototype.render = function (markerModel, ecModel, api) { - var _this = this; - - var markerGroupMap = this.markerGroupMap; - markerGroupMap.each(function (item) { - inner$1(item).keep = false; - }); - ecModel.eachSeries(function (seriesModel) { - var markerModel = MarkerModel.getMarkerModelFromSeries(seriesModel, _this.type); - markerModel && _this.renderSeries(seriesModel, markerModel, ecModel, api); - }); - markerGroupMap.each(function (item) { - !inner$1(item).keep && _this.group.remove(item.group); - }); - updateZ(ecModel, markerGroupMap, this.type); - }; - - MarkerView.prototype.markKeep = function (drawGroup) { - inner$1(drawGroup).keep = true; - }; - - MarkerView.prototype.toggleBlurSeries = function (seriesModelList, isBlur) { - var _this = this; - - each$4(seriesModelList, function (seriesModel) { - var markerModel = MarkerModel.getMarkerModelFromSeries(seriesModel, _this.type); - - if (markerModel) { - var data = markerModel.getData(); - data.eachItemGraphicEl(function (el) { - if (el) { - isBlur ? enterBlur(el) : leaveBlur(el); - } - }); - } - }); - }; - - MarkerView.type = 'marker'; - return MarkerView; - }(ComponentView); - - function updateZ(ecModel, markerGroupMap, type) { - ecModel.eachSeries(function (seriesModel) { - var markerModel = MarkerModel.getMarkerModelFromSeries(seriesModel, type); - var markerDraw = markerGroupMap.get(seriesModel.id); - - if (markerModel && markerDraw && markerDraw.group) { - var _a = retrieveZInfo(markerModel), - z = _a.z, - zlevel = _a.zlevel; - - traverseUpdateZ(markerDraw.group, z, zlevel); - } - }); - } - - var inner = makeInner(); - - var markAreaTransform = function (seriesModel, coordSys, maModel, item) { - // item may be null - var item0 = item[0]; - var item1 = item[1]; - - if (!item0 || !item1) { - return; - } - - var lt = dataTransform(seriesModel, item0); - var rb = dataTransform(seriesModel, item1); // FIXME make sure lt is less than rb - - var ltCoord = lt.coord; - var rbCoord = rb.coord; - ltCoord[0] = retrieve(ltCoord[0], -Infinity); - ltCoord[1] = retrieve(ltCoord[1], -Infinity); - rbCoord[0] = retrieve(rbCoord[0], Infinity); - rbCoord[1] = retrieve(rbCoord[1], Infinity); // Merge option into one - - var result = mergeAll([{}, lt, rb]); - result.coord = [lt.coord, rb.coord]; - result.x0 = lt.x; - result.y0 = lt.y; - result.x1 = rb.x; - result.y1 = rb.y; - return result; - }; - - function isInfinity(val) { - return !isNaN(val) && !isFinite(val); - } // If a markArea has one dim - - - function ifMarkAreaHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) { - var otherDimIndex = 1 - dimIndex; - return isInfinity(fromCoord[otherDimIndex]) && isInfinity(toCoord[otherDimIndex]); - } - - function markAreaFilter(coordSys, item) { - var fromCoord = item.coord[0]; - var toCoord = item.coord[1]; - var item0 = { - coord: fromCoord, - x: item.x0, - y: item.y0 - }; - var item1 = { - coord: toCoord, - x: item.x1, - y: item.y1 - }; - - if (isCoordinateSystemType(coordSys, 'cartesian2d')) { - // In case - // { - // markArea: { - // data: [{ yAxis: 2 }] - // } - // } - if (fromCoord && toCoord && (ifMarkAreaHasOnlyDim(1, fromCoord, toCoord) || ifMarkAreaHasOnlyDim(0, fromCoord, toCoord))) { - return true; - } // Directly returning true may also do the work, - // because markArea will not be shown automatically - // when it's not included in coordinate system. - // But filtering ahead can avoid keeping rendering markArea - // when there are too many of them. - - - return zoneFilter(coordSys, item0, item1); - } - - return dataFilter(coordSys, item0) || dataFilter(coordSys, item1); - } // dims can be ['x0', 'y0'], ['x1', 'y1'], ['x0', 'y1'], ['x1', 'y0'] - - - function getSingleMarkerEndPoint(data, idx, dims, seriesModel, api) { - var coordSys = seriesModel.coordinateSystem; - var itemModel = data.getItemModel(idx); - var point; - var xPx = parsePercent(itemModel.get(dims[0]), api.getWidth()); - var yPx = parsePercent(itemModel.get(dims[1]), api.getHeight()); - - if (!isNaN(xPx) && !isNaN(yPx)) { - point = [xPx, yPx]; - } else { - // Chart like bar may have there own marker positioning logic - if (seriesModel.getMarkerPosition) { - // Consider the case that user input the right-bottom point first - // Pick the larger x and y as 'x1' and 'y1' - var pointValue0 = data.getValues(['x0', 'y0'], idx); - var pointValue1 = data.getValues(['x1', 'y1'], idx); - var clampPointValue0 = coordSys.clampData(pointValue0); - var clampPointValue1 = coordSys.clampData(pointValue1); - var pointValue = []; - - if (dims[0] === 'x0') { - pointValue[0] = clampPointValue0[0] > clampPointValue1[0] ? pointValue1[0] : pointValue0[0]; - } else { - pointValue[0] = clampPointValue0[0] > clampPointValue1[0] ? pointValue0[0] : pointValue1[0]; - } - - if (dims[1] === 'y0') { - pointValue[1] = clampPointValue0[1] > clampPointValue1[1] ? pointValue1[1] : pointValue0[1]; - } else { - pointValue[1] = clampPointValue0[1] > clampPointValue1[1] ? pointValue0[1] : pointValue1[1]; - } // Use the getMarkerPosition - - - point = seriesModel.getMarkerPosition(pointValue, dims, true); - } else { - var x = data.get(dims[0], idx); - var y = data.get(dims[1], idx); - var pt = [x, y]; - coordSys.clampData && coordSys.clampData(pt, pt); - point = coordSys.dataToPoint(pt, true); - } - - if (isCoordinateSystemType(coordSys, 'cartesian2d')) { - // TODO: TYPE ts@4.1 may still infer it as Axis instead of Axis2D. Not sure if it's a bug - var xAxis = coordSys.getAxis('x'); - var yAxis = coordSys.getAxis('y'); - var x = data.get(dims[0], idx); - var y = data.get(dims[1], idx); - - if (isInfinity(x)) { - point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[dims[0] === 'x0' ? 0 : 1]); - } else if (isInfinity(y)) { - point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[dims[1] === 'y0' ? 0 : 1]); - } - } // Use x, y if has any - - - if (!isNaN(xPx)) { - point[0] = xPx; - } - - if (!isNaN(yPx)) { - point[1] = yPx; - } - } - - return point; - } - - var dimPermutations = [['x0', 'y0'], ['x1', 'y0'], ['x1', 'y1'], ['x0', 'y1']]; - - var MarkAreaView = - /** @class */ - function (_super) { - __extends(MarkAreaView, _super); - - function MarkAreaView() { - var _this = _super !== null && _super.apply(this, arguments) || this; - - _this.type = MarkAreaView.type; - return _this; - } - - MarkAreaView.prototype.updateTransform = function (markAreaModel, ecModel, api) { - ecModel.eachSeries(function (seriesModel) { - var maModel = MarkerModel.getMarkerModelFromSeries(seriesModel, 'markArea'); - - if (maModel) { - var areaData_1 = maModel.getData(); - areaData_1.each(function (idx) { - var points = map$1(dimPermutations, function (dim) { - return getSingleMarkerEndPoint(areaData_1, idx, dim, seriesModel, api); - }); // Layout - - areaData_1.setItemLayout(idx, points); - var el = areaData_1.getItemGraphicEl(idx); - el.setShape('points', points); - }); - } - }, this); - }; - - MarkAreaView.prototype.renderSeries = function (seriesModel, maModel, ecModel, api) { - var coordSys = seriesModel.coordinateSystem; - var seriesId = seriesModel.id; - var seriesData = seriesModel.getData(); - var areaGroupMap = this.markerGroupMap; - var polygonGroup = areaGroupMap.get(seriesId) || areaGroupMap.set(seriesId, { - group: new Group$2() - }); - this.group.add(polygonGroup.group); - this.markKeep(polygonGroup); - var areaData = createList(coordSys, seriesModel, maModel); // Line data for tooltip and formatter - - maModel.setData(areaData); // Update visual and layout of line - - areaData.each(function (idx) { - // Layout - var points = map$1(dimPermutations, function (dim) { - return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api); - }); - var xAxisScale = coordSys.getAxis('x').scale; - var yAxisScale = coordSys.getAxis('y').scale; - var xAxisExtent = xAxisScale.getExtent(); - var yAxisExtent = yAxisScale.getExtent(); - var xPointExtent = [xAxisScale.parse(areaData.get('x0', idx)), xAxisScale.parse(areaData.get('x1', idx))]; - var yPointExtent = [yAxisScale.parse(areaData.get('y0', idx)), yAxisScale.parse(areaData.get('y1', idx))]; - asc(xPointExtent); - asc(yPointExtent); - var overlapped = !(xAxisExtent[0] > xPointExtent[1] || xAxisExtent[1] < xPointExtent[0] || yAxisExtent[0] > yPointExtent[1] || yAxisExtent[1] < yPointExtent[0]); // If none of the area is inside coordSys, allClipped is set to be true - // in layout so that label will not be displayed. See #12591 - - var allClipped = !overlapped; - areaData.setItemLayout(idx, { - points: points, - allClipped: allClipped - }); - var itemModel = areaData.getItemModel(idx); - var style = itemModel.getModel('itemStyle').getItemStyle(); - var z2 = itemModel.get('z2'); - var color = getVisualFromData(seriesData, 'color'); - - if (!style.fill) { - style.fill = color; - - if (isString(style.fill)) { - style.fill = modifyAlpha(style.fill, 0.4); - } - } - - if (!style.stroke) { - style.stroke = color; - } // Visual - - - areaData.setItemVisual(idx, 'style', style); - areaData.setItemVisual(idx, 'z2', retrieve2(z2, 0)); - }); - areaData.diff(inner(polygonGroup).data).add(function (idx) { - var layout = areaData.getItemLayout(idx); - var z2 = areaData.getItemVisual(idx, 'z2'); - - if (!layout.allClipped) { - var polygon = new Polygon({ - z2: retrieve2(z2, 0), - shape: { - points: layout.points - } - }); - areaData.setItemGraphicEl(idx, polygon); - polygonGroup.group.add(polygon); - } - }).update(function (newIdx, oldIdx) { - var polygon = inner(polygonGroup).data.getItemGraphicEl(oldIdx); - var layout = areaData.getItemLayout(newIdx); - var z2 = areaData.getItemVisual(newIdx, 'z2'); - - if (!layout.allClipped) { - if (polygon) { - updateProps$1(polygon, { - z2: retrieve2(z2, 0), - shape: { - points: layout.points - } - }, maModel, newIdx); - } else { - polygon = new Polygon({ - shape: { - points: layout.points - } - }); - } - - areaData.setItemGraphicEl(newIdx, polygon); - polygonGroup.group.add(polygon); - } else if (polygon) { - polygonGroup.group.remove(polygon); - } - }).remove(function (idx) { - var polygon = inner(polygonGroup).data.getItemGraphicEl(idx); - polygonGroup.group.remove(polygon); - }).execute(); - areaData.eachItemGraphicEl(function (polygon, idx) { - var itemModel = areaData.getItemModel(idx); - var style = areaData.getItemVisual(idx, 'style'); - polygon.useStyle(areaData.getItemVisual(idx, 'style')); - setLabelStyle(polygon, getLabelStatesModels(itemModel), { - labelFetcher: maModel, - labelDataIndex: idx, - defaultText: areaData.getName(idx) || '', - inheritColor: isString(style.fill) ? modifyAlpha(style.fill, 1) : tokens.color.neutral99 - }); - setStatesStylesFromModel(polygon, itemModel); - toggleHoverEmphasis(polygon, null, null, itemModel.get(['emphasis', 'disabled'])); - getECData(polygon).dataModel = maModel; - }); - inner(polygonGroup).data = areaData; - polygonGroup.group.silent = maModel.get('silent') || seriesModel.get('silent'); - }; - - MarkAreaView.type = 'markArea'; - return MarkAreaView; - }(MarkerView); - - function createList(coordSys, seriesModel, maModel) { - var areaData; - var dataDims; - var dims = ['x0', 'y0', 'x1', 'y1']; - - if (coordSys) { - var coordDimsInfos_1 = map$1(coordSys && coordSys.dimensions, function (coordDim) { - var data = seriesModel.getData(); - var info = data.getDimensionInfo(data.mapDimension(coordDim)) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys - - return extend(extend({}, info), { - name: coordDim, - // DON'T use ordinalMeta to parse and collect ordinal. - ordinalMeta: null - }); - }); - dataDims = map$1(dims, function (dim, idx) { - return { - name: dim, - type: coordDimsInfos_1[idx % 2].type - }; - }); - areaData = new SeriesData(dataDims, maModel); - } else { - dataDims = [{ - name: 'value', - type: 'float' - }]; - areaData = new SeriesData(dataDims, maModel); - } - - var optData = map$1(maModel.get('data'), curry$1(markAreaTransform, seriesModel, coordSys, maModel)); - - if (coordSys) { - optData = filter(optData, curry$1(markAreaFilter, coordSys)); - } - - var dimValueGetter = coordSys ? function (item, dimName, dataIndex, dimIndex) { - // TODO should convert to ParsedValue? - var rawVal = item.coord[Math.floor(dimIndex / 2)][dimIndex % 2]; - return parseDataValue(rawVal, dataDims[dimIndex]); - } : function (item, dimName, dataIndex, dimIndex) { - return parseDataValue(item.value, dataDims[dimIndex]); - }; - areaData.initData(optData, null, dimValueGetter); - areaData.hasItemOption = true; - return areaData; - } - - function install$1(registers) { - registers.registerComponentModel(MarkAreaModel); - registers.registerComponentView(MarkAreaView); - registers.registerPreprocessor(function (opt) { - if (checkMarkerInSeries(opt.series, 'markArea')) { - // Make sure markArea component is enabled - opt.markArea = opt.markArea || {}; - } - }); - } - - use(install$1); - use(install$a); - var RELATIONAL_EXPRESSION_OP_ALIAS_MAP = { - value: 'eq', - // PENDING: not good for literal semantic? - '<': 'lt', - '<=': 'lte', - '>': 'gt', - '>=': 'gte', - '=': 'eq', - '!=': 'ne', - '<>': 'ne' // Might be misleading for sake of the difference between '==' and '===', - // so don't support them. - // '==': 'eq', - // '===': 'seq', - // '!==': 'sne' - // PENDING: Whether support some common alias "ge", "le", "neq"? - // ge: 'gte', - // le: 'lte', - // neq: 'ne', - - }; // type RelationalExpressionOpEvaluate = (tarVal: unknown, condVal: unknown) => boolean; - - var RegExpEvaluator = - /** @class */ - function () { - function RegExpEvaluator(rVal) { - // Support condVal: RegExp | string - var condValue = this._condVal = isString(rVal) ? new RegExp(rVal) : isRegExp(rVal) ? rVal : null; - - if (condValue == null) { - var errMsg = ''; - { - errMsg = makePrintable('Illegal regexp', rVal, 'in'); - } - throwError(errMsg); - } - } - - RegExpEvaluator.prototype.evaluate = function (lVal) { - var type = typeof lVal; - return isString(type) ? this._condVal.test(lVal) : isNumber(type) ? this._condVal.test(lVal + '') : false; - }; - - return RegExpEvaluator; - }(); - - var ConstConditionInternal = - /** @class */ - function () { - function ConstConditionInternal() {} - - ConstConditionInternal.prototype.evaluate = function () { - return this.value; - }; - - return ConstConditionInternal; - }(); - - var AndConditionInternal = - /** @class */ - function () { - function AndConditionInternal() {} - - AndConditionInternal.prototype.evaluate = function () { - var children = this.children; - - for (var i = 0; i < children.length; i++) { - if (!children[i].evaluate()) { - return false; - } - } - - return true; - }; - - return AndConditionInternal; - }(); - - var OrConditionInternal = - /** @class */ - function () { - function OrConditionInternal() {} - - OrConditionInternal.prototype.evaluate = function () { - var children = this.children; - - for (var i = 0; i < children.length; i++) { - if (children[i].evaluate()) { - return true; - } - } - - return false; - }; - - return OrConditionInternal; - }(); - - var NotConditionInternal = - /** @class */ - function () { - function NotConditionInternal() {} - - NotConditionInternal.prototype.evaluate = function () { - return !this.child.evaluate(); - }; - - return NotConditionInternal; - }(); - - var RelationalConditionInternal = - /** @class */ - function () { - function RelationalConditionInternal() {} - - RelationalConditionInternal.prototype.evaluate = function () { - var needParse = !!this.valueParser; // Call getValue with no `this`. - - var getValue = this.getValue; - var tarValRaw = getValue(this.valueGetterParam); - var tarValParsed = needParse ? this.valueParser(tarValRaw) : null; // Relational cond follow "and" logic internally. - - for (var i = 0; i < this.subCondList.length; i++) { - if (!this.subCondList[i].evaluate(needParse ? tarValParsed : tarValRaw)) { - return false; - } - } - - return true; - }; - - return RelationalConditionInternal; - }(); - - function parseOption(exprOption, getters) { - if (exprOption === true || exprOption === false) { - var cond = new ConstConditionInternal(); - cond.value = exprOption; - return cond; - } - - var errMsg = ''; - - if (!isObjectNotArray(exprOption)) { - { - errMsg = makePrintable('Illegal config. Expect a plain object but actually', exprOption); - } - throwError(errMsg); - } - - if (exprOption.and) { - return parseAndOrOption('and', exprOption, getters); - } else if (exprOption.or) { - return parseAndOrOption('or', exprOption, getters); - } else if (exprOption.not) { - return parseNotOption(exprOption, getters); - } - - return parseRelationalOption(exprOption, getters); - } - - function parseAndOrOption(op, exprOption, getters) { - var subOptionArr = exprOption[op]; - var errMsg = ''; - { - errMsg = makePrintable('"and"/"or" condition should only be `' + op + ': [...]` and must not be empty array.', 'Illegal condition:', exprOption); - } - - if (!isArray(subOptionArr)) { - throwError(errMsg); - } - - if (!subOptionArr.length) { - throwError(errMsg); - } - - var cond = op === 'and' ? new AndConditionInternal() : new OrConditionInternal(); - cond.children = map$1(subOptionArr, function (subOption) { - return parseOption(subOption, getters); - }); - - if (!cond.children.length) { - throwError(errMsg); - } - - return cond; - } - - function parseNotOption(exprOption, getters) { - var subOption = exprOption.not; - var errMsg = ''; - { - errMsg = makePrintable('"not" condition should only be `not: {}`.', 'Illegal condition:', exprOption); - } - - if (!isObjectNotArray(subOption)) { - throwError(errMsg); - } - - var cond = new NotConditionInternal(); - cond.child = parseOption(subOption, getters); - - if (!cond.child) { - throwError(errMsg); - } - - return cond; - } - - function parseRelationalOption(exprOption, getters) { - var errMsg = ''; - var valueGetterParam = getters.prepareGetValue(exprOption); - var subCondList = []; - var exprKeys = keys(exprOption); - var parserName = exprOption.parser; - var valueParser = parserName ? getRawValueParser(parserName) : null; - - for (var i = 0; i < exprKeys.length; i++) { - var keyRaw = exprKeys[i]; - - if (keyRaw === 'parser' || getters.valueGetterAttrMap.get(keyRaw)) { - continue; - } - - var op = hasOwn(RELATIONAL_EXPRESSION_OP_ALIAS_MAP, keyRaw) ? RELATIONAL_EXPRESSION_OP_ALIAS_MAP[keyRaw] : keyRaw; - var condValueRaw = exprOption[keyRaw]; - var condValueParsed = valueParser ? valueParser(condValueRaw) : condValueRaw; - var evaluator = createFilterComparator(op, condValueParsed) || op === 'reg' && new RegExpEvaluator(condValueParsed); - - if (!evaluator) { - { - errMsg = makePrintable('Illegal relational operation: "' + keyRaw + '" in condition:', exprOption); - } - throwError(errMsg); - } - - subCondList.push(evaluator); - } - - if (!subCondList.length) { - { - errMsg = makePrintable('Relational condition must have at least one operator.', 'Illegal condition:', exprOption); - } // No relational operator always disabled in case of dangers result. - - throwError(errMsg); - } - - var cond = new RelationalConditionInternal(); - cond.valueGetterParam = valueGetterParam; - cond.valueParser = valueParser; - cond.getValue = getters.getValue; - cond.subCondList = subCondList; - return cond; - } - - function isObjectNotArray(val) { - return isObject$2(val) && !isArrayLike(val); - } - - var ConditionalExpressionParsed = - /** @class */ - function () { - function ConditionalExpressionParsed(exprOption, getters) { - this._cond = parseOption(exprOption, getters); - } - - ConditionalExpressionParsed.prototype.evaluate = function () { - return this._cond.evaluate(); - }; - - return ConditionalExpressionParsed; - }(); - - function parseConditionalExpression(exprOption, getters) { - return new ConditionalExpressionParsed(exprOption, getters); - } - - var filterTransform = { - type: 'echarts:filter', - // PENDING: enhance to filter by index rather than create new data - transform: function (params) { - // [Caveat] Fail-Fast: - // Do not return the whole dataset unless user config indicates it explicitly. - // For example, if no condition is specified by mistake, returning an empty result - // is better than returning the entire raw source for the user to find the mistake. - var upstream = params.upstream; - var rawItem; - var condition = parseConditionalExpression(params.config, { - valueGetterAttrMap: createHashMap({ - dimension: true - }), - prepareGetValue: function (exprOption) { - var errMsg = ''; - var dimLoose = exprOption.dimension; - - if (!hasOwn(exprOption, 'dimension')) { - { - errMsg = makePrintable('Relation condition must has prop "dimension" specified.', 'Illegal condition:', exprOption); - } - throwError(errMsg); - } - - var dimInfo = upstream.getDimensionInfo(dimLoose); - - if (!dimInfo) { - { - errMsg = makePrintable('Can not find dimension info via: ' + dimLoose + '.\n', 'Existing dimensions: ', upstream.cloneAllDimensionInfo(), '.\n', 'Illegal condition:', exprOption, '.\n'); - } - throwError(errMsg); - } - - return { - dimIdx: dimInfo.index - }; - }, - getValue: function (param) { - return upstream.retrieveValueFromItem(rawItem, param.dimIdx); - } - }); - var resultData = []; - - for (var i = 0, len = upstream.count(); i < len; i++) { - rawItem = upstream.getRawDataItem(i); - - if (condition.evaluate()) { - resultData.push(rawItem); - } - } - - return { - data: resultData - }; - } - }; - var sampleLog = ''; - { - sampleLog = ['Valid config is like:', '{ dimension: "age", order: "asc" }', 'or [{ dimension: "age", order: "asc"], { dimension: "date", order: "desc" }]'].join(' '); - } - var sortTransform = { - type: 'echarts:sort', - transform: function (params) { - var upstream = params.upstream; - var config = params.config; - var errMsg = ''; // Normalize - // const orderExprList: OrderExpression[] = isArray(config[0]) - // ? config as OrderExpression[] - // : [config as OrderExpression]; - - var orderExprList = normalizeToArray(config); - - if (!orderExprList.length) { - { - errMsg = 'Empty `config` in sort transform.'; - } - throwError(errMsg); - } - - var orderDefList = []; - each$4(orderExprList, function (orderExpr) { - var dimLoose = orderExpr.dimension; - var order = orderExpr.order; - var parserName = orderExpr.parser; - var incomparable = orderExpr.incomparable; - - if (dimLoose == null) { - { - errMsg = 'Sort transform config must has "dimension" specified.' + sampleLog; - } - throwError(errMsg); - } - - if (order !== 'asc' && order !== 'desc') { - { - errMsg = 'Sort transform config must has "order" specified.' + sampleLog; - } - throwError(errMsg); - } - - if (incomparable && incomparable !== 'min' && incomparable !== 'max') { - var errMsg_1 = ''; - { - errMsg_1 = 'incomparable must be "min" or "max" rather than "' + incomparable + '".'; - } - throwError(errMsg_1); - } - - if (order !== 'asc' && order !== 'desc') { - var errMsg_2 = ''; - { - errMsg_2 = 'order must be "asc" or "desc" rather than "' + order + '".'; - } - throwError(errMsg_2); - } - - var dimInfo = upstream.getDimensionInfo(dimLoose); - - if (!dimInfo) { - { - errMsg = makePrintable('Can not find dimension info via: ' + dimLoose + '.\n', 'Existing dimensions: ', upstream.cloneAllDimensionInfo(), '.\n', 'Illegal config:', orderExpr, '.\n'); - } - throwError(errMsg); - } - - var parser = parserName ? getRawValueParser(parserName) : null; - - if (parserName && !parser) { - { - errMsg = makePrintable('Invalid parser name ' + parserName + '.\n', 'Illegal config:', orderExpr, '.\n'); - } - throwError(errMsg); - } - - orderDefList.push({ - dimIdx: dimInfo.index, - parser: parser, - comparator: new SortOrderComparator(order, incomparable) - }); - }); // TODO: support it? - - var sourceFormat = upstream.sourceFormat; - - if (sourceFormat !== SOURCE_FORMAT_ARRAY_ROWS && sourceFormat !== SOURCE_FORMAT_OBJECT_ROWS) { - { - errMsg = 'sourceFormat "' + sourceFormat + '" is not supported yet'; - } - throwError(errMsg); - } // Other upstream format are all array. - - - var resultData = []; - - for (var i = 0, len = upstream.count(); i < len; i++) { - resultData.push(upstream.getRawDataItem(i)); - } - - resultData.sort(function (item0, item1) { - for (var i = 0; i < orderDefList.length; i++) { - var orderDef = orderDefList[i]; - var val0 = upstream.retrieveValueFromItem(item0, orderDef.dimIdx); - var val1 = upstream.retrieveValueFromItem(item1, orderDef.dimIdx); - - if (orderDef.parser) { - val0 = orderDef.parser(val0); - val1 = orderDef.parser(val1); - } - - var result = orderDef.comparator.evaluate(val0, val1); - - if (result !== 0) { - return result; - } - } - - return 0; - }); - return { - data: resultData - }; - } - }; - - function install(registers) { - registers.registerTransform(filterTransform); - registers.registerTransform(sortTransform); - } - - use(install); - exports.Axis = Axis; - exports.ChartView = ChartView; - exports.ComponentModel = ComponentModel; - exports.ComponentView = ComponentView; - exports.List = SeriesData; - exports.Model = Model; - exports.PRIORITY = PRIORITY; - exports.SeriesModel = SeriesModel; - exports.color = color$2; - exports.connect = connect; - exports.dataTool = dataTool; - exports.dependencies = dependencies; - exports.disConnect = disConnect; - exports.disconnect = disconnect; - exports.dispose = dispose; - exports.env = env; - exports.extendChartView = extendChartView; - exports.extendComponentModel = extendComponentModel; - exports.extendComponentView = extendComponentView; - exports.extendSeriesModel = extendSeriesModel; - exports.format = format; - exports.getCoordinateSystemDimensions = getCoordinateSystemDimensions; - exports.getInstanceByDom = getInstanceByDom; - exports.getInstanceById = getInstanceById; - exports.getMap = getMap; - exports.graphic = graphic; - exports.helper = helper; - exports.init = init; - exports.innerDrawElementOnCanvas = brushSingle; - exports.matrix = matrix; - exports.number = number; - exports.parseGeoJSON = parseGeoJSON; - exports.parseGeoJson = parseGeoJSON; - exports.registerAction = registerAction; - exports.registerCoordinateSystem = registerCoordinateSystem; - exports.registerCustomSeries = registerCustomSeries; - exports.registerLayout = registerLayout; - exports.registerLoading = registerLoading; - exports.registerLocale = registerLocale; - exports.registerMap = registerMap; - exports.registerPostInit = registerPostInit; - exports.registerPostUpdate = registerPostUpdate; - exports.registerPreprocessor = registerPreprocessor; - exports.registerProcessor = registerProcessor; - exports.registerTheme = registerTheme; - exports.registerTransform = registerTransform; - exports.registerUpdateLifecycle = registerUpdateLifecycle; - exports.registerVisual = registerVisual; - exports.setCanvasCreator = setCanvasCreator; - exports.setPlatformAPI = setPlatformAPI; - exports.throttle = throttle; - exports.time = time; - exports.use = use; - exports.util = util; - exports.vector = vector; - exports.version = version; - exports.zrUtil = util$1; - exports.zrender = zrender; -}); \ No newline at end of file diff --git a/src/site/echarts.min.js b/src/site/echarts.min.js new file mode 100644 index 000000000..43e4952d7 --- /dev/null +++ b/src/site/echarts.min.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).echarts={})}(this,function(t){"use strict";var _=function(t,e){return(_=Object.setPrototypeOf||({__proto__:[]}instanceof Array?function(t,e){t.__proto__=e}:function(t,e){for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])}))(t,e)};function u(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function n(){this.constructor=t}_(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}var x=function(){this.firefox=!1,this.ie=!1,this.edge=!1,this.newEdge=!1,this.weChat=!1},w=new function(){this.browser=new x,this.node=!1,this.wxa=!1,this.worker=!1,this.svgSupported=!1,this.touchEventsSupported=!1,this.pointerEventsSupported=!1,this.domSupported=!1,this.transformSupported=!1,this.transform3dSupported=!1,this.hasGlobalWindow="undefined"!=typeof window};"object"==typeof wx&&"function"==typeof wx.getSystemInfoSync?(w.wxa=!0,w.touchEventsSupported=!0):"undefined"==typeof document&&"undefined"!=typeof self?w.worker=!0:!w.hasGlobalWindow||"Deno"in window||"undefined"!=typeof navigator&&"string"==typeof navigator.userAgent&&-1>1)%2;s.cssText=["position: absolute","visibility: hidden","padding: 0","margin: 0","border-width: 0","user-select: none","width:0","height:0",i[l]+":0",r[u]+":0",i[1-l]+":auto",r[1-u]+":auto",""].join("!important;"),t.appendChild(a),n.push(a)}e.clearMarkers=function(){z(n,function(t){t.parentNode&&t.parentNode.removeChild(t)})}}return n}(e,o),o,r);if(e)return e(t,n,i),!0}return!1}function me(t){return"CANVAS"===t.nodeName.toUpperCase()}var ve=/([&<>"'])/g,_e={"&":"&","<":"<",">":">",'"':""","'":"'"};function xe(t){return null==t?"":(t+"").replace(ve,function(t,e){return _e[e]})}var be=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,we=[],Se=w.browser.firefox&&+w.browser.version.split(".")[0]<39;function Me(t,e,n,i){return n=n||{},i?Te(t,e,n):Se&&null!=e.layerX&&e.layerX!==e.offsetX?(n.zrX=e.layerX,n.zrY=e.layerY):null!=e.offsetX?(n.zrX=e.offsetX,n.zrY=e.offsetY):Te(t,e,n),n}function Te(t,e,n){if(w.domSupported&&t.getBoundingClientRect){var i,r=e.clientX,e=e.clientY;if(me(t))return i=t.getBoundingClientRect(),n.zrX=r-i.left,void(n.zrY=e-i.top);if(ye(we,t,r,e))return n.zrX=we[0],void(n.zrY=we[1])}n.zrX=n.zrY=0}function Ce(t){return t||window.event}function Ie(t,e,n){var i;return null==(e=Ce(e)).zrX&&((i=e.type)&&0<=i.indexOf("touch")?(i=("touchend"!==i?e.targetTouches:e.changedTouches)[0])&&Me(t,i,e,n):(Me(t,e,e,n),i=function(t){var e=t.wheelDelta;if(e)return e;var n=t.deltaX,t=t.deltaY;return null!=n&&null!=t?3*(0!==t?Math.abs(t):Math.abs(n))*(0=t.x&&e<=t.x+t.width&&n>=t.y&&n<=t.y+t.height},nn.prototype.contain=function(t,e){return nn.contain(this,t,e)},nn.prototype.clone=function(){return new nn(this.x,this.y,this.width,this.height)},nn.prototype.copy=function(t){nn.copy(this,t)},nn.prototype.plain=function(){return{x:this.x,y:this.y,width:this.width,height:this.height}},nn.prototype.isFinite=function(){return isFinite(this.x)&&isFinite(this.y)&&isFinite(this.width)&&isFinite(this.height)},nn.prototype.isZero=function(){return 0===this.width||0===this.height},nn.create=function(t){return new nn(t.x,t.y,t.width,t.height)},nn.copy=function(t,e){return t.x=e.x,t.y=e.y,t.width=e.width,t.height=e.height,t},nn.applyTransform=function(t,e,n){var i,r,o,a;n?n[1]<1e-5&&-1e-5t.getWidth()||n<0||n>t.getHeight()}z(["click","mousedown","mouseup","mousewheel","dblclick","contextmenu"],function(a){mn.prototype[a]=function(t){var e,n,i=t.zrX,r=t.zrY,o=xn(this,i,r);if("mouseup"===a&&o||(n=(e=this.findHover(i,r)).target),"mousedown"===a)this._downEl=n,this._downPoint=[t.zrX,t.zrY],this._upEl=n;else if("mouseup"===a)this._upEl=n;else if("click"===a){if(this._downEl!==this._upEl||!this._downPoint||4>>1])<0?l=o:s=1+o;var u=i-s;switch(u){case 3:t[s+3]=t[s+2];case 2:t[s+2]=t[s+1];case 1:t[s+1]=t[s];break;default:for(;0>>1);0>>1);o(t,e[n+h])<0?l=h:a=h+1}return l}function In(A,L){var P,O,R=wn,N=0,B=[];function e(t){var e=P[t],n=O[t],i=P[t+1],r=O[t+1],t=(O[t]=n+r,t===N-3&&(P[t+1]=P[t+2],O[t+1]=O[t+2]),N--,Cn(A[i],A,e,n,0,L));if(e+=t,0!=(n-=t)&&0!==(r=Tn(A[e+n-1],A,i,r,r-1,L)))if(n<=r){var o=e,a=n,t=i,s=r,l=0;for(l=0;lO[t+1])break;e(t)}},forceMergeRuns:function(){for(;1>=1;return t+e}(r);do{}while((o=Sn(t,n,i,e))=this._maxSize&&0>4|(3840&r)>>8,240&r|(240&r)>>4,15&r|(15&r)<<4,5===i?parseInt(n.slice(4),16)/15:1),Ti(t,e),e):void bi(e,0,0,0,1):7===i||9===i?0<=(r=parseInt(n.slice(1,7),16))&&r<=16777215?(bi(e,(16711680&r)>>16,(65280&r)>>8,255&r,9===i?parseInt(n.slice(7),16)/255:1),Ti(t,e),e):void bi(e,0,0,0,1):void 0;var r=n.indexOf("("),o=n.indexOf(")");if(-1!==r&&o+1===i){var i=n.substr(0,r),a=n.substr(r+1,o-(r+1)).split(","),s=1;switch(i){case"rgba":if(4!==a.length)return 3===a.length?bi(e,+a[0],+a[1],+a[2],1):bi(e,0,0,0,1);s=vi(a.pop());case"rgb":return 3<=a.length?(bi(e,mi(a[0]),mi(a[1]),mi(a[2]),3===a.length?s:vi(a[3])),Ti(t,e),e):void bi(e,0,0,0,1);case"hsla":return 4!==a.length?void bi(e,0,0,0,1):(a[3]=vi(a[3]),Ii(a,e),Ti(t,e),e);case"hsl":return 3!==a.length?void bi(e,0,0,0,1):(Ii(a,e),Ti(t,e),e);default:return}}bi(e,0,0,0,1)}}function Ii(t,e){var n=(parseFloat(t[0])%360+360)%360/360,i=vi(t[1]),r=vi(t[2]),i=r<=.5?r*(i+1):r+i-r*i,r=2*r-i;return bi(e=e||[],gi(255*_i(r,i,n+1/3)),gi(255*_i(r,i,n)),gi(255*_i(r,i,n-1/3)),1),4===t.length&&(e[3]=t[3]),e}function ki(t,e){var n=Ci(t);if(n){for(var i=0;i<3;i++)n[i]=e<0?n[i]*(1-e)|0:(255-n[i])*e+n[i]|0,255e);g++);g=f(g-1,h-2)}i=u[g+1],n=u[g]}n&&i&&(this._lastFr=g,this._lastFrP=e,d=i.percent-n.percent,r=0==d?1:f((e-n.percent)/d,1),i.easingFunc&&(r=i.easingFunc(r)),f=a?this._additiveValue:p?Yi:t[c],(Xi(l)||p)&&(f=f||(this._additiveValue=[])),this.discrete?t[c]=(r<1?n:i).rawValue:Xi(l)?(1===l?Fi:function(t,e,n,i){for(var r=e.length,o=r&&e[0].length,a=0;athis._sleepAfterStill)&&this.animation.stop()},co.prototype.setSleepAfterStill=function(t){this._sleepAfterStill=t},co.prototype.wakeUp=function(){this._disposed||(this.animation.start(),this._stillFrameAccum=0)},co.prototype.refreshHover=function(){this._needsRefreshHover=!0},co.prototype.refreshHoverImmediately=function(){this._disposed||(this._needsRefreshHover=!1,this.painter.refreshHover&&"canvas"===this.painter.getType()&&this.painter.refreshHover())},co.prototype.resize=function(t){this._disposed||(this.painter.resize((t=t||{}).width,t.height),this.handler.resize())},co.prototype.clearAnimation=function(){this._disposed||this.animation.clear()},co.prototype.getWidth=function(){if(!this._disposed)return this.painter.getWidth()},co.prototype.getHeight=function(){if(!this._disposed)return this.painter.getHeight()},co.prototype.setCursorStyle=function(t){this._disposed||this.handler.setCursorStyle(t)},co.prototype.findHover=function(t,e){if(!this._disposed)return this.handler.findHover(t,e)},co.prototype.on=function(t,e,n){return this._disposed||this.handler.on(t,e,n),this},co.prototype.off=function(t,e){this._disposed||this.handler.off(t,e)},co.prototype.trigger=function(t,e){this._disposed||this.handler.trigger(t,e)},co.prototype.clear=function(){if(!this._disposed){for(var t=this.storage.getRoots(),e=0;el&&(l=s[h],u=h);++o[u],s[u]=0,++a}return F(o,function(t){return t/i})}function Do(t){var e=2*Math.PI;return(t%e+e)%e}function Ao(t){return-1e-4=n.maxIterations){e+=n.ellipsis;break}var s=0===a?function(t,e,n){for(var i=0,r=0,o=t.length;rh){I=o.lines.length;0i.width&&(o=e.split("\n"),c=!0),i.accumWidth=s):(s=Ba(e,t,i.width,i.breakAll,i.accumWidth),i.accumWidth=s.accumWidth+n,a=s.linesWidths,o=s.lines)),o=o||e.split("\n"),Nr(t)),d=0;dthis._ux||i>this._uy;return this.addData(ls.L,t,e),this._ctx&&r&&this._ctx.lineTo(t,e),r?(this._xi=t,this._yi=e,this._pendingPtDist=0):(r=n*n+i*i)>this._pendingPtDist&&(this._pendingPtX=t,this._pendingPtY=e,this._pendingPtDist=r),this},r.prototype.bezierCurveTo=function(t,e,n,i,r,o){return this._drawPendingPt(),this.addData(ls.C,t,e,n,i,r,o),this._ctx&&this._ctx.bezierCurveTo(t,e,n,i,r,o),this._xi=r,this._yi=o,this},r.prototype.quadraticCurveTo=function(t,e,n,i){return this._drawPendingPt(),this.addData(ls.Q,t,e,n,i),this._ctx&&this._ctx.quadraticCurveTo(t,e,n,i),this._xi=n,this._yi=i,this},r.prototype.arc=function(t,e,n,i,r,o){return this._drawPendingPt(),Ss[0]=i,Ss[1]=r,Ts(Ss,o),this.addData(ls.A,t,e,n,n,i=Ss[0],(r=Ss[1])-i,0,o?0:1),this._ctx&&this._ctx.arc(t,e,n,i,r,o),this._xi=ms(r)*n+t,this._yi=vs(r)*n+e,this},r.prototype.arcTo=function(t,e,n,i,r){return this._drawPendingPt(),this._ctx&&this._ctx.arcTo(t,e,n,i,r),this},r.prototype.rect=function(t,e,n,i){return this._drawPendingPt(),this._ctx&&this._ctx.rect(t,e,n,i),this.addData(ls.R,t,e,n,i),this},r.prototype.closePath=function(){this._drawPendingPt(),this.addData(ls.Z);var t=this._ctx,e=this._x0,n=this._y0;return t&&t.closePath(),this._xi=e,this._yi=n,this},r.prototype.fill=function(t){t&&t.fill(),this.toStatic()},r.prototype.stroke=function(t){t&&t.stroke(),this.toStatic()},r.prototype.len=function(){return this._len},r.prototype.setData=function(t){if(this._saveData){var e=t.length;this.data&&this.data.length===e||!ws||(this.data=new Float32Array(e));for(var n=0;nu.length&&(this._expandData(),u=this.data);for(var h=0;hn||_s(y)>i||c===e-1)&&(f=Math.sqrt(I*I+y*y),r=g,o=_);break;case ls.C:var m=t[c++],v=t[c++],g=t[c++],_=t[c++],x=t[c++],b=t[c++],f=function(t,e,n,i,r,o,a,s,l){for(var u=t,h=e,c=0,p=1/l,d=1;d<=l;d++){var f=d*p,g=Zn(t,n,r,a,f),f=Zn(e,i,o,s,f),y=g-u,m=f-h;c+=Math.sqrt(y*y+m*m),u=g,h=f}return c}(r,o,m,v,g,_,x,b,10),r=x,o=b;break;case ls.Q:f=function(t,e,n,i,r,o,a){for(var s=t,l=e,u=0,h=1/a,c=1;c<=a;c++){var p=c*h,d=ti(t,n,r,p),p=ti(e,i,o,p),f=d-s,g=p-l;u+=Math.sqrt(f*f+g*g),s=d,l=p}return u}(r,o,m=t[c++],v=t[c++],g=t[c++],_=t[c++],10),r=g,o=_;break;case ls.A:var x=t[c++],b=t[c++],w=t[c++],S=t[c++],M=t[c++],T=t[c++],C=T+M;c+=1,d&&(a=ms(M)*w+x,s=vs(M)*S+b),f=ys(w,S)*gs(bs,Math.abs(T)),r=ms(C)*w+x,o=vs(C)*S+b;break;case ls.R:a=r=t[c++],s=o=t[c++];f=2*t[c++]+2*t[c++];break;case ls.Z:var I=a-r,y=s-o;f=Math.sqrt(I*I+y*y),r=a,o=s}0<=f&&(u+=l[h++]=f)}return this._pathLen=u},r.prototype.rebuildPath=function(t,e){var n,i,r,o,a,s,l,u,h=this.data,B=this._ux,E=this._uy,z=this._len,c=e<1,p=0,d=0,f=0;if(!c||(this._pathSegLen||this._calculateLength(),a=this._pathSegLen,s=e*this._pathLen))t:for(var g=0;g=Ns[i=0]+t&&a<=Ns[1]+t?h:0;rMath.PI/2&&c<1.5*Math.PI?-h:h)}return l}(y,m,_,x,x+b,w,T,r);u=Math.cos(x+b)*v+y,h=Math.sin(x+b)*_+m;break;case Ps.R:c=u=a[d++],p=h=a[d++];if(S=c+a[d++],M=p+a[d++],n){if(Is(c,p,S,p,e,i,r)||Is(S,p,S,M,e,i,r)||Is(S,M,c,M,e,i,r)||Is(c,M,c,p,e,i,r))return!0}else l=(l+=Ls(S,p,S,M,i,r))+Ls(c,M,c,p,i,r);break;case Ps.Z:if(n){if(Is(u,h,c,p,e,i,r))return!0}else l+=Ls(u,h,c,p,i,r);u=c,h=p}}return n||(t=h,o=p,Math.abs(t-o)n,i=(r=r.slice(0,n)).length*c),t&&u&&null!=f)for(var y=ka(f,l,e.ellipsis,{minChar:e.truncateMinChar,placeholder:e.placeholder}),m={},v=0;vic.len()&&(sxo(i[1])?0':'':{renderMode:r,content:"{"+(t.markerId||"markerX")+"|} ",style:"subItem"===i?{width:4,height:4,borderRadius:2,backgroundColor:n}:{width:10,height:10,borderRadius:5,backgroundColor:n}}:""}function wd(t,e){return e=e||"transparent",H(t)?t:B(t)&&t.colorStops&&(t.colorStops[0]||{}).color||e}function Sd(t,e){var n;"_blank"===e||"blank"===e?((n=window.open()).opener=null,n.location.href=t):window.open(t,e)}var Md={},Td={},Cd=(Id.prototype.create=function(i,r){function t(t){var n=[];return z(t,function(t,e){t=t.create(i,r);n=n.concat(t||[])}),n}this._nonSeriesBoxMasterList=t(Md),this._normalMasterList=t(Td)},Id.prototype.update=function(e,n){z(this._normalMasterList,function(t){t.update&&t.update(e,n)})},Id.prototype.getCoordinateSystems=function(){return this._normalMasterList.concat(this._nonSeriesBoxMasterList)},Id.register=function(t,e){"matrix"===t||"calendar"===t?Md[t]=e:Td[t]=e},Id.get=function(t){return Td[t]||Md[t]},Id);function Id(){this._normalMasterList=[],this._nonSeriesBoxMasterList=[]}var kd={coord:1,coord2:2};var Dd=O();var Ad={none:0,dataCoordSys:1,boxCoordSys:2};function Ld(t){var e=t.getShallow("coordinateSystem"),n=t.getShallow("coordinateSystemUsage",!0),i=Ad.none;return e&&(t="series"===t.mainType,"data"===(n=null==n?t?"data":"box":n)?(i=Ad.dataCoordSys,t||(i=Ad.none)):"box"===n&&(i=Ad.boxCoordSys,t||Md[e]||(i=Ad.none))),{coordSysType:e,kind:i}}var Pd=z,Od=["left","right","top","bottom","width","height"],Rd=[["width","left","right"],["height","top","bottom"]];function Nd(a,s,l,u,h){var c=0,p=0,d=(null==u&&(u=1/0),null==h&&(h=1/0),0);s.eachChild(function(t,e){var n,i,r,o=t.getBoundingRect(),e=s.childAt(e+1),e=e&&e.getBoundingRect();d="horizontal"===a?(i=o.width+(e?-e.x+o.x:0),u<(n=c+i)||t.newline?(c=0,n=i,p+=d+l,o.height):Math.max(d,o.height)):(i=o.height+(e?-e.y+o.y:0),h<(r=p+i)||t.newline?(c+=d+l,p=0,r=i,o.width):Math.max(d,o.width)),t.newline||(t.x=c,t.y=p,t.markRedraw(),"horizontal"===a?c=n+l:p=r+l)})}var Bd=Nd;function Ed(t,e){r=Hd(o=t,n=e,{enableLayoutOnlyByCenter:!0}),i=o.getBoxLayoutParams(),r.type===Vd?(s=r.refPoint,a=zd(i,{width:n.getWidth(),height:n.getHeight()})):(o=V(n=o.get("center"))?n:[n,n],a=zd(i,r.refContainer),s=r.boxCoordFrom===kd.coord2?r.refPoint:[wo(o[0],a.width)+a.x,wo(o[1],a.height)+a.y]);var n={viewRect:a,center:s},i=n.viewRect,r=n.center,o=t.get("radius"),a=(V(o)||(o=[0,o]),wo(i.width,e.getWidth())),s=wo(i.height,e.getHeight()),n=Math.min(a,s),t=wo(o[0],n/2),e=wo(o[1],n/2);return{cx:r[0],cy:r[1],r0:t,r:e,viewRect:i}}function zd(t,e,n){n=yd(n||0);var i=e.width,r=e.height,o=wo(t.left,i),a=wo(t.top,r),s=wo(t.right,i),l=wo(t.bottom,r),u=wo(t.width,i),h=wo(t.height,r),c=n[2]+n[0],p=n[1]+n[3],d=t.aspect;switch(isNaN(u)&&(u=i-s-p-o),isNaN(h)&&(h=r-l-c-a),null!=d&&(isNaN(u)&&isNaN(h)&&(i/re)return t[i];return t[n-1]}var If,kf="\0_ec_inner",Df=(u(o,If=Cp),o.prototype.init=function(t,e,n,i,r,o){i=i||{},this.option=null,this._theme=new Cp(i),this._locale=new Cp(r),this._optionManager=o},o.prototype.setOption=function(t,e,n){e=Pf(e);this._optionManager.setOption(t,n,e),this._resetOption(null,e)},o.prototype.resetOption=function(t,e){return this._resetOption(t,Pf(e))},o.prototype._resetOption=function(t,e){var n,i=!1,r=this._optionManager;return t&&"recreate"!==t||(n=r.mountOption("recreate"===t),this.option&&"recreate"!==t?(this.restoreData(),this._mergeOption(n,e)):wf(this,n),i=!0),"timeline"!==t&&"media"!==t||this.restoreData(),t&&"recreate"!==t&&"timeline"!==t||(n=r.getTimelineOption(this))&&(i=!0,this._mergeOption(n,e)),t&&"recreate"!==t&&"media"!==t||(n=r.getMediaOption(this)).length&&z(n,function(t){i=!0,this._mergeOption(t,e)},this),i},o.prototype.mergeOption=function(t){this._mergeOption(t,null)},o.prototype._mergeOption=function(i,t){var r=this.option,h=this._componentsMap,c=this._componentsCount,n=[],o=O(),p=t&&t.replaceMergeMainTypeMap;df(this).datasetMap=O(),z(i,function(t,e){null!=t&&(g.hasClass(e)?e&&(n.push(e),o.set(e,!0)):r[e]=null==r[e]?y(t):d(r[e],t,!0))}),p&&p.each(function(t,e){g.hasClass(e)&&!o.get(e)&&(n.push(e),o.set(e,!0))}),g.topologicalTravel(n,g.getAllClassMainTypes(),function(o){var a,t=function(t,e,n){return(e=(e=_f.get(e))&&e(t))?n.concat(e):n}(this,o,Wo(i[o])),e=h.get(o),n=e?p&&p.get(o)?"replaceMerge":"normalMerge":"replaceAll",e=Yo(e,t,n),s=(Qo(e,o,g),r[o]=null,h.set(o,null),c.set(o,0),[]),l=[],u=0;z(e,function(t,e){var n=t.existing,i=t.newOption;if(i){var r=g.getClass(o,t.keyInfo.subType,!("series"===o));if(!r)return;if("tooltip"===o){if(a)return;a=!0}n&&n.constructor===r?(n.name=t.keyInfo.name,n.mergeOption(i,this),n.optionUpdated(i,!1)):(e=P({componentIndex:e},t.keyInfo),P(n=new r(i,this,this,e),e),t.brandNew&&(n.__requireNewView=!0),n.init(i,this,this),n.optionUpdated(null,!0))}else n&&(n.mergeOption({},this),n.optionUpdated({},!1));n?(s.push(n.option),l.push(n),u++):(s.push(void 0),l.push(void 0))},this),r[o]=s,h.set(o,l),c.set(o,u),"series"===o&&xf(this)},this),this._seriesIndices||xf(this)},o.prototype.getOption=function(){var a=y(this.option);return z(a,function(t,e){if(g.hasClass(e)){for(var n=Wo(t),i=n.length,r=!1,o=i-1;0<=o;o--)n[o]&&!$o(n[o])?r=!0:(n[o]=null,r||i--);n.length=i,a[e]=n}}),delete a[kf],a},o.prototype.setTheme=function(t){this._theme=new Cp(t),this._resetOption("recreate",null)},o.prototype.getTheme=function(){return this._theme},o.prototype.getLocaleModel=function(){return this._locale},o.prototype.setUpdatePayload=function(t){this._payload=t},o.prototype.getUpdatePayload=function(){return this._payload},o.prototype.getComponent=function(t,e){var n=this._componentsMap.get(t);if(n){t=n[e||0];if(t)return t;if(null==e)for(var i=0;ig[1]&&(g[1]=f)}return{start:a,end:this._rawCount=this._count=s}},l.prototype._initDataFromProvider=function(t,e,n){for(var i=this._provider,r=this._chunks,o=this._dimensions,a=o.length,s=this._rawExtent,l=F(o,function(t){return t.property}),u=0;uf[1]&&(f[1]=g)}!i.persistent&&i.clean&&i.clean(),this._rawCount=this._count=e,this._extent=[]},l.prototype.count=function(){return this._count},l.prototype.get=function(t,e){return 0<=e&&e=this._rawCount||t<0)){if(!this._indices)return t;var e=this._indices,n=e[t];if(null!=n&&nt))return o;r=o-1}}}return-1},l.prototype.getIndices=function(){var t=this._indices;if(t){var e=t.constructor,n=this._count;if(e===Array)for(var i=new e(n),r=0;rt[S][1])&&(b=!1)}b&&(a[s++]=e.getRawIndex(f))}return sy[1]&&(y[1]=g)}}}},l.prototype.lttbDownSample=function(t,e){var n,i=this.clone([t],!0),r=i._chunks[t],o=this.count(),a=0,s=Math.floor(1/e),l=this.getRawIndex(0),u=new(gy(this._rawCount))(Math.min(2*(Math.ceil(o/s)+2),o));u[a++]=l;for(var h=1;hh[1]&&(h[1]=y),c[p++]=m}return r._count=p,r._indices=c,r._updateGetRawIdx(),r},l.prototype.each=function(t,e){if(this._count)for(var n=t.length,i=this._chunks,r=0,o=this.count();r'+xe(u)+""+h,t))}function Ry(t,e,n,i){var r,o,a,s,l,u=t.renderMode,h=e.noName,c=e.noValue,p=!e.markerType,d=e.name,f=t.useUTC,g=e.valueFormatter||t.valueFormatter||function(t){return F(t=V(t)?t:[t],function(t,e){return md(t,V(o)?o[e]:o,f)})};if(!h||!c)return r=p?"":t.markupStyleCreator.makeTooltipMarker(e.markerType,e.markerColor||v.color.secondary,u),d=h?"":md(d,"ordinal",f),o=e.valueType,g=c?[]:g(e.value,e.dataIndex),e=!p||!h,a=!p&&h,l=Iy(i,u),s=l.nameStyle,l=l.valueStyle,"richText"===u?(p?"":r)+(h?"":Ey(t,d,s))+(c?"":function(t,e,n,i,r){r=[r],i=i?10:20;return n&&r.push({padding:[0,0,0,i],align:"right"}),t.markupStyleCreator.wrapRichTextStyle(V(e)?e.join(" "):e,r)}(t,g,e,a,l)):By(i,(p?"":r)+(h?"":''+xe(d)+"")+(c?"":function(t,e,n,i){n=n?"10px":"20px",e=e?"float:right;margin-left:"+n:"";return t=V(t)?t:[t],''+F(t,xe).join("  ")+""}(g,e,a,l)),n)}function Ny(t,e,n,i,r,o){if(t)return Py(t)({useUTC:r,renderMode:n,orderMode:i,markupStyleCreator:e,valueFormatter:t.valueFormatter},t,0,o)}function By(t,e,n){return'
'+e+'
'}function Ey(t,e,n){return t.markupStyleCreator.wrapRichTextStyle(e,n)}function zy(t,e){t=t.get("padding");return null!=t?t:"richText"===e?[8,10]:10}Vy.prototype._generateStyleName=function(){return"__EC_aUTo_"+this._nextStyleNameId++},Vy.prototype.makeTooltipMarker=function(t,e,n){var i="richText"===n?this._generateStyleName():null,e=bd({color:e,type:t,renderMode:n,markerId:i});return H(e)?e:(this.richTextStyles[i]=e.style,e.content)},Vy.prototype.wrapRichTextStyle=function(t,e){var n={},e=(V(e)?z(e,function(t){return P(n,t)}):P(n,e),this._generateStyleName());return this.richTextStyles[e]=n,"{"+e+"|"+t+"}"};var Fy=Vy;function Vy(){this.richTextStyles={},this._nextStyleNameId=zo()}function Hy(t){var e,n,i,r,o,a,s,l,u,h,c,p=t.series,d=t.dataIndex,t=t.multipleSeries,f=p.getData(),g=f.mapDimensionsAll("defaultedTooltip"),y=g.length,m=p.getRawValue(d),v=V(m),_=(_=d,wd((b=p).getData().getItemVisual(_,"style")[b.visualDrawType]));function x(t,e){e=s.getDimensionInfo(e);e&&!1!==e.otherDims.tooltip&&(l?c.push(Ay("nameValue",{markerType:"subItem",markerColor:a,name:e.displayName,value:t,valueType:e.type})):(u.push(t),h.push(e.type)))}1this.getShallow("animationThreshold")?!1:t)},s.prototype.restoreData=function(){this.dataTask.dirty()},s.prototype.getColorFromPalette=function(t,e,n){var i=this.ecModel;return Mf.prototype.getColorFromPalette.call(this,t,e,n)||i.getColorFromPalette(t,e,n)},s.prototype.coordDimToDataDim=function(t){return this.getRawData().mapDimensionsAll(t)},s.prototype.getProgressive=function(){return this.get("progressive")},s.prototype.getProgressiveThreshold=function(){return this.get("progressiveThreshold")},s.prototype.select=function(t,e){this._innerSelect(this.getData(e),t)},s.prototype.unselect=function(t,e){var n=this.option.selectedMap;if(n){var i=this.option.selectedMode,r=this.getData(e);if("series"===i||"all"===n)this.option.selectedMap={},this._selectedDataIndicesMap={};else for(var o=0;oe.outputData.count()&&e.model.getRawData().cloneShallow(e.outputData)}function Ky(e,n){z(Nt(e.CHANGABLE_METHODS,e.DOWNSAMPLE_METHODS),function(t){e.wrapMethod(t,pt($y,n))})}function $y(t,e){t=Qy(t);return t&&t.setOutputEnd((e||this).count()),e}function Qy(t){var e,n=(t.ecModel||{}).scheduler,n=n&&n.getPipeline(t.uid);if(n)return(n=n.currentTask)&&(e=n.agentStubMap)?e.get(t.uid):n}at(Xy,Sp),at(Xy,Mf),da(Xy,g);tm.prototype.init=function(t,e){},tm.prototype.render=function(t,e,n,i){},tm.prototype.dispose=function(t,e){},tm.prototype.updateView=function(t,e,n,i){},tm.prototype.updateLayout=function(t,e,n,i){},tm.prototype.updateVisual=function(t,e,n,i){},tm.prototype.toggleBlurSeries=function(t,e,n){},tm.prototype.eachRendered=function(t){var e=this.group;e&&e.traverse(t)};var Jy=tm;function tm(){this.group=new oo,this.uid=Dp("viewComponent")}function em(){var o=ta();return function(t){var e=o(t),t=t.pipelineContext,n=!!e.large,i=!!e.progressiveRender,r=e.large=!(!t||!t.large),e=e.progressiveRender=!(!t||!t.progressiveRender);return!(n==r&&i==e)&&"reset"}}pa(Jy),ma(Jy);var nm=ta(),im=em(),rm=(om.prototype.init=function(t,e){},om.prototype.render=function(t,e,n,i){},om.prototype.highlight=function(t,e,n,i){t=t.getData(i&&i.dataType);t&&sm(t,i,"emphasis")},om.prototype.downplay=function(t,e,n,i){t=t.getData(i&&i.dataType);t&&sm(t,i,"normal")},om.prototype.remove=function(t,e){this.group.removeAll()},om.prototype.dispose=function(t,e){},om.prototype.updateView=function(t,e,n,i){this.render(t,e,n,i)},om.prototype.updateLayout=function(t,e,n,i){this.render(t,e,n,i)},om.prototype.updateVisual=function(t,e,n,i){this.render(t,e,n,i)},om.prototype.eachRendered=function(t){Yc(this.group,t)},om.markUpdateMethod=function(t,e){nm(t).updateMethod=e},om.protoInitialize=void(om.prototype.type="chart"),om);function om(){this.group=new oo,this.uid=Dp("viewChart"),this.renderTask=Og({plan:lm,reset:um}),this.renderTask.context={view:this}}function am(t,e,n){t&&_u(t)&&("emphasis"===e?nu:iu)(t,n)}function sm(e,t,n){var i,r=Jo(e,t),o=t&&null!=t.highlightKey?(t=t.highlightKey,i=null==(i=Cl[t])&&Tl<=32?Cl[t]=Tl++:i):null;null!=r?z(Wo(r),function(t){am(e.getItemGraphicEl(t),n,o)}):e.eachItemGraphicEl(function(t){am(t,n,o)})}function lm(t){return im(t.model)}function um(t){var e=t.model,n=t.ecModel,i=t.api,r=t.payload,o=e.pipelineContext.progressiveRender,t=t.view,a=r&&nm(r).updateMethod,o=o?"incrementalPrepareRender":a&&t[a]?a:"render";return"render"!==o&&t[o](e,n,i,r),hm[o]}pa(rm),ma(rm);var hm={incrementalPrepareRender:{progress:function(t,e){e.view.incrementalRender(t,e.model,e.ecModel,e.api,e.payload)}},render:{forceFirstProgress:!0,progress:function(t,e){e.view.render(e.model,e.ecModel,e.api,e.payload)}}},cm="\0__throttleOriginMethod",pm="\0__throttleRate",dm="\0__throttleType";function fm(t,r,o){var a,s,l,u,h,c=0,p=0,d=null;function f(){p=(new Date).getTime(),d=null,t.apply(l,u||[])}r=r||0;function e(){for(var t=[],e=0;en.blockIndex?n.step:null,modBy:null!=(t=i&&i.modDataCount)?Math.ceil(t/e):null,modDataCount:t}},Tm.prototype.getPipeline=function(t){return this._pipelineMap.get(t)},Tm.prototype.updateStreamModes=function(t,e){var n=this._pipelineMap.get(t.uid),i=t.getData().count(),e=n.progressiveEnabled&&e.incrementalPrepareRender&&i>=n.threshold,r=t.get("large")&&i>=t.get("largeThreshold"),i="mod"===t.get("progressiveChunkMode")?i:null;t.pipelineContext=n.context={progressiveRender:e,modDataCount:i,large:r}},Tm.prototype.restorePipelines=function(t){var i=this,r=i._pipelineMap=O();t.eachSeries(function(t){var e=t.getProgressive(),n=t.uid;r.set(n,{id:n,head:null,tail:null,threshold:t.getProgressiveThreshold(),progressiveEnabled:e&&!(t.preventIncremental&&t.preventIncremental()),blockIndex:-1,step:Math.round(e||700),count:0}),i._pipe(t,t.dataTask)})},Tm.prototype.prepareStageTasks=function(){var n=this._stageTaskMap,i=this.api.getModel(),r=this.api;z(this._allHandlers,function(t){var e=n.get(t.uid)||n.set(t.uid,{});Tt(!(t.reset&&t.overallReset),""),t.reset&&this._createSeriesStageTask(t,e,i,r),t.overallReset&&this._createOverallStageTask(t,e,i,r)},this)},Tm.prototype.prepareView=function(t,e,n,i){var r=t.renderTask,o=r.context;o.model=e,o.ecModel=n,o.api=i,r.__block=!t.incrementalPrepareRender,this._pipe(e,r)},Tm.prototype.performDataProcessorTasks=function(t,e){this._performStageTasks(this._dataProcessorHandlers,t,e,{block:!0})},Tm.prototype.performVisualTasks=function(t,e,n){this._performStageTasks(this._visualHandlers,t,e,n)},Tm.prototype._performStageTasks=function(t,s,l,u){u=u||{};var h=!1,c=this;function p(t,e){return t.setDirty&&(!t.dirtyMap||t.dirtyMap.get(e.__pipeline.id))}z(t,function(i,t){var e,n,r,o,a;u.visualType&&u.visualType!==i.visualType||(e=(n=c._stageTaskMap.get(i.uid)).seriesTaskMap,(n=n.overallTask)?((o=n.agentStubMap).each(function(t){p(u,t)&&(t.dirty(),r=!0)}),r&&n.dirty(),c.updatePayload(n,l),a=c.getPerformArgs(n,u.block),o.each(function(t){t.perform(a)}),n.perform(a)&&(h=!0)):e&&e.each(function(t,e){p(u,t)&&t.dirty();var n=c.getPerformArgs(t,u.block);n.skip=!i.performRawSeries&&s.isSeriesFiltered(t.context.model),c.updatePayload(t,l),t.perform(n)&&(h=!0)}))}),this.unfinished=h||this.unfinished},Tm.prototype.performSeriesTasks=function(t){var e;t.eachSeries(function(t){e=t.dataTask.perform()||e}),this.unfinished=e||this.unfinished},Tm.prototype.plan=function(){this._pipelineMap.each(function(t){var e=t.tail;do{if(e.__block){t.blockIndex=e.__idxInPipeline;break}}while(e=e.getUpstream())})},Tm.prototype.updatePayload=function(t,e){"remain"!==e&&(t.context.payload=e)},Tm.prototype._createSeriesStageTask=function(n,t,i,r){var o=this,a=t.seriesTaskMap,s=t.seriesTaskMap=O(),t=n.seriesType,e=n.getTargetSeries;function l(t){var e=t.uid,e=s.set(e,a&&a.get(e)||Og({plan:Am,reset:Lm,count:Rm}));e.context={model:t,ecModel:i,api:r,useClearVisual:n.isVisual&&!n.isLayout,plan:n.plan,reset:n.reset,scheduler:o},o._pipe(t,e)}n.createOnAllSeries?i.eachRawSeries(l):t?i.eachRawSeriesByType(t,l):e&&e(i,r).each(l)},Tm.prototype._createOverallStageTask=function(t,e,n,i){var r=this,o=e.overallTask=e.overallTask||Og({reset:Cm}),a=(o.context={ecModel:n,api:i,overallReset:t.overallReset,scheduler:r},o.agentStubMap),s=o.agentStubMap=O(),e=t.seriesType,l=t.getTargetSeries,u=!0,h=!1;function c(t){var e=t.uid,e=s.set(e,a&&a.get(e)||(h=!0,Og({reset:Im,onDirty:Dm})));e.context={model:t,overallProgress:u},e.agent=o,e.__block=u,r._pipe(t,e)}Tt(!t.createOnAllSeries,""),e?n.eachRawSeriesByType(e,c):l?l(n,i).each(c):(u=!1,z(n.getSeries(),c)),h&&o.dirty()},Tm.prototype._pipe=function(t,e){t=t.uid,t=this._pipelineMap.get(t);t.head||(t.head=e),t.tail&&t.tail.pipe(e),(t.tail=e).__idxInPipeline=t.count++,e.__pipeline=t},Tm.wrapStageHandler=function(t,e){return(t=N(t)?{overallReset:t,seriesType:function(t){Nm=null;try{t(Bm,Em)}catch(t){}return Nm}(t)}:t).uid=Dp("stageHandler"),e&&(t.visualType=e),t};var Mm=Tm;function Tm(t,e,n,i){this._stageTaskMap=O(),this.ecInstance=t,this.api=e,n=this._dataProcessorHandlers=n.slice(),i=this._visualHandlers=i.slice(),this._allHandlers=n.concat(i)}function Cm(t){t.overallReset(t.ecModel,t.api,t.payload)}function Im(t){return t.overallProgress&&km}function km(){this.agent.dirty(),this.getDownstream().dirty()}function Dm(){this.agent&&this.agent.dirty()}function Am(t){return t.plan?t.plan(t.model,t.ecModel,t.api,t.payload):null}function Lm(t){t.useClearVisual&&t.data.clearAllVisual();t=t.resetDefines=Wo(t.reset(t.model,t.ecModel,t.api,t.payload));return 1'+t.dom+""}),f.painter.getSvgRoot().innerHTML=g,i.connectedBackgroundColor&&f.painter.setBackgroundColor(i.connectedBackgroundColor),f.refreshImmediately(),f.painter.toDataURL()):(i.connectedBackgroundColor&&f.add(new sl({shape:{x:0,y:0,width:t,height:n},style:{fill:i.connectedBackgroundColor}})),z(p,function(t){t=new Qs({style:{x:t.left*e-l,y:t.top*e-u,image:t.dom}});f.add(t)}),f.refreshImmediately(),d.toDataURL("image/"+(i&&i.type||"png")))):this.getDataURL(i);this.id},c.prototype.convertToPixel=function(t,e,n){return tv(this,"convertToPixel",t,e,n)},c.prototype.convertToLayout=function(t,e,n){return tv(this,"convertToLayout",t,e,n)},c.prototype.convertFromPixel=function(t,e,n){return tv(this,"convertFromPixel",t,e,n)},c.prototype.containPixel=function(t,i){var r;if(!this._disposed)return z(na(this._model,t),function(t,n){0<=n.indexOf("Models")&&z(t,function(t){var e=t.coordinateSystem;e&&e.containPoint?r=r||!!e.containPoint(i):"seriesModels"===n&&(e=this._chartsMap[t.__viewId])&&e.containPoint&&(r=r||e.containPoint(i,t))},this)},this),!!r;this.id},c.prototype.getVisual=function(t,e){var t=na(this._model,t,{defaultMainType:"series"}),n=t.seriesModel.getData(),t=t.hasOwnProperty("dataIndexInside")?t.dataIndexInside:t.hasOwnProperty("dataIndex")?n.indexOfRawIndex(t.dataIndex):null;if(null!=t){var i=n,r=t,o=e;switch(o){case"color":return i.getItemVisual(r,"style")[i.getVisual("drawType")];case"opacity":return i.getItemVisual(r,"style").opacity;case"symbol":case"symbolSize":case"liftZ":return i.getItemVisual(r,o)}}else{var a=n,s=e;switch(s){case"color":return a.getVisual("style")[a.getVisual("drawType")];case"opacity":return a.getVisual("style").opacity;case"symbol":case"symbolSize":case"liftZ":return a.getVisual(s)}}},c.prototype.getViewOfComponentModel=function(t){return this._componentsMap[t.__viewId]},c.prototype.getViewOfSeriesModel=function(t){return this._chartsMap[t.__viewId]},c.prototype._initEvents=function(){var n,i,s=this,r=(z(wv,function(a){function t(t){var n,e,i,r=s.getModel(),o=t.target;"globalout"===a?n={}:o&&Ym(o,function(t){var e,t=Y(t);return t&&null!=t.dataIndex?(e=t.dataModel||r.getSeriesByIndex(t.seriesIndex),n=e&&e.getDataParams(t.dataIndex,t.dataType,o)||{},1):t.eventData&&(n=P({},t.eventData),1)},!0),n&&(e=n.componentType,i=n.componentIndex,"markLine"!==e&&"markPoint"!==e&&"markArea"!==e||(e="series",i=n.seriesIndex),i=(e=e&&null!=i&&r.getComponent(e,i))&&s["series"===e.mainType?"_chartsMap":"_componentsMap"][e.__viewId],n.event=t,n.type=a,s._$eventProcessor.eventInfo={targetEl:o,packedEvent:n,model:e,view:i},s.trigger(a,n))}t.zrEventfulCallAtLast=!0,s._zr.on(a,t,s)}),this._messageCenter);z(Tv,function(t,e){r.on(e,function(t){s.trigger(e,t)})}),i=(n=this)._api,r.on("selectchanged",function(t){var e=i.getModel();t.isFromClick?(Xm("map","selectchanged",n,e,t),Xm("pie","selectchanged",n,e,t)):"select"===t.fromAction?(Xm("map","selected",n,e,t),Xm("pie","selected",n,e,t)):"unselect"===t.fromAction&&(Xm("map","unselected",n,e,t),Xm("pie","unselected",n,e,t))})},c.prototype.isDisposed=function(){return this._disposed},c.prototype.clear=function(){this._disposed?this.id:this.setOption({series:[]},!0)},c.prototype.dispose=function(){var t,e,n;this._disposed?this.id:(this._disposed=!0,this.getDom()&&aa(this.getDom(),Nv,""),e=(t=this)._api,n=t._model,z(t._componentsViews,function(t){t.dispose(n,e)}),z(t._chartsViews,function(t){t.dispose(n,e)}),t._zr.dispose(),t._dom=t._model=t._chartsMap=t._componentsMap=t._chartsViews=t._componentsViews=t._scheduler=t._api=t._zr=t._throttledZrFlush=t._theme=t._coordSysMgr=t._messageCenter=null,delete Lv[t.id])},c.prototype.resize=function(t){if(!this[z0])if(this._disposed)this.id;else{this._zr.resize(t);var e=this._model;if(this._loadingFX&&this._loadingFX.resize(),e){var e=e.resetOption("media"),n=t&&t.silent;this[V0]&&(null==n&&(n=this[V0].silent),e=!0,this[V0]=null),this[z0]=!0,fv(this);try{e&&K0(this),J0.update.call(this,{type:"resize",animation:P({duration:0},t&&t.animation)})}catch(t){throw this[z0]=!1,t}this[z0]=!1,iv.call(this,n),rv.call(this,n)}}},c.prototype.showLoading=function(t,e){this._disposed?this.id:(B(t)&&(e=t,t=""),t=t||"default",this.hideLoading(),Av[t]&&(t=Av[t](this._api,e),e=this._zr,this._loadingFX=t,e.add(t)))},c.prototype.hideLoading=function(){this._disposed?this.id:(this._loadingFX&&this._zr.remove(this._loadingFX),this._loadingFX=null)},c.prototype.makeActionFromEvent=function(t){var e=P({},t);return e.type=Mv[t.type],e},c.prototype.dispatchAction=function(t,e){var n;this._disposed?this.id:(B(e)||(e={silent:!!e}),Sv[t.type]&&this._model&&(this[z0]?this._pendingActions.push(t):(n=e.silent,nv.call(this,t,n),(t=e.flush)?this._zr.flush():!1!==t&&w.browser.weChat&&this._throttledZrFlush(),iv.call(this,n),rv.call(this,n))))},c.prototype.updateLabelLayout=function(){B0.trigger("series:layoutlabels",this._model,this._api,{updatedSeries:[]})},c.prototype.appendData=function(t){var e;this._disposed?this.id:(e=t.seriesIndex,this.getModel().getSeriesByIndex(e).appendData(t),this._scheduler.unfinished=!0,this.getZr().wakeUp())},c.internalField=(K0=function(t){var e=t._scheduler;e.restorePipelines(t._model),e.prepareStageTasks(),$0(t,!0),$0(t,!1),e.plan()},$0=function(t,r){for(var o=t._model,a=t._scheduler,s=r?t._componentsViews:t._chartsViews,l=r?t._componentsMap:t._chartsMap,u=t._zr,h=t._api,e=0;es.get("hoverLayerThreshold")&&!w.node&&!w.worker&&s.eachSeries(function(t){t.preventUsingHoverLayer||(t=i._chartsMap[t.__viewId]).__alive&&t.eachRendered(function(t){t.states.emphasis&&(t.states.emphasis.hoverLayer=!0)})}),B0.trigger("series:afterupdate",t,e,n)},pv=function(t){t[H0]=!0,t.getZr().wakeUp()},fv=function(t){t[F0]=(t[F0]+1)%1e3},dv=function(t){t[H0]&&(t.getZr().storage.traverse(function(t){dc(t)||vv(t)}),t[H0]=!1)},hv=function(n){return u(t,e=Of),t.prototype.getCoordinateSystems=function(){return n._coordSysMgr.getCoordinateSystems()},t.prototype.getComponentByElement=function(t){for(;t;){var e=t.__ecComponentInfo;if(null!=e)return n._model.getComponent(e.mainType,e.index);t=t.parent}},t.prototype.enterEmphasis=function(t,e){nu(t,e),pv(n)},t.prototype.leaveEmphasis=function(t,e){iu(t,e),pv(n)},t.prototype.enterBlur=function(t){jl(t,Ul),pv(n)},t.prototype.leaveBlur=function(t){ru(t),pv(n)},t.prototype.enterSelect=function(t){ou(t),pv(n)},t.prototype.leaveSelect=function(t){au(t),pv(n)},t.prototype.getModel=function(){return n.getModel()},t.prototype.getViewOfComponentModel=function(t){return n.getViewOfComponentModel(t)},t.prototype.getViewOfSeriesModel=function(t){return n.getViewOfSeriesModel(t)},t.prototype.getMainProcessVersion=function(){return n[F0]},new t(n);function t(){return null!==e&&e.apply(this,arguments)||this}var e},void(cv=function(i){function r(t,e){for(var n=0;nr[1]&&(r[0]=r[1]),o}function F_(t){var e=Math.pow(10,Ro(t)),t=t/e;return t?2===t?t=3:3===t?t=5:t*=2:t=1,Mo(t*e)}function V_(t){return To(t)+2}function H_(t,e,n){t[e]=Math.max(Math.min(t[e],n[1]),n[0])}function W_(t,e){return t>=e[0]&&t<=e[1]}U_.prototype.updateMethods=function(t){t.hasBreaks()?(this.normalize=S(t.normalize,t),this.scale=S(t.scale,t)):(this.normalize=X_,this.scale=Y_)};var G_=U_;function U_(){this.normalize=X_,this.scale=Y_}function X_(t,e){return e[1]===e[0]?.5:(t-e[0])/(e[1]-e[0])}function Y_(t,e){return t*(e[1]-e[0])+e[0]}function q_(t,e,n){t=Math.log(t);return[Math.log(n?e[0]:Math.max(0,e[0]))/t,Math.log(n?e[1]:Math.max(0,e[1]))/t]}j_.prototype.getSetting=function(t){return this._setting[t]},j_.prototype._innerUnionExtent=function(t){var e=this._extent;this._innerSetExtent((t[0]e[1]?t:e)[1])},j_.prototype.unionExtentFromData=function(t,e){this._innerUnionExtent(t.getApproximateExtent(e))},j_.prototype.getExtent=function(){return this._extent.slice()},j_.prototype.setExtent=function(t,e){this._innerSetExtent(t,e)},j_.prototype._innerSetExtent=function(t,e){var n=this._extent;isNaN(t)||(n[0]=t),isNaN(e)||(n[1]=e),this._brkCtx&&this._brkCtx.update(n)},j_.prototype.setBreaksFromOption=function(t){},j_.prototype._innerSetBreak=function(t){this._brkCtx&&(this._brkCtx.setBreaks(t),this._calculator.updateMethods(this._brkCtx),this._brkCtx.update(this._extent))},j_.prototype._innerGetBreaks=function(){return this._brkCtx?this._brkCtx.breaks:[]},j_.prototype.hasBreaks=function(){return!!this._brkCtx&&this._brkCtx.hasBreaks()},j_.prototype._getExtentSpanWithBreaks=function(){return this._brkCtx&&this._brkCtx.hasBreaks()?this._brkCtx.getExtentSpan():this._extent[1]-this._extent[0]},j_.prototype.isInExtentRange=function(t){return this._extent[0]<=t&&this._extent[1]>=t},j_.prototype.isBlank=function(){return this._isBlank},j_.prototype.setBlank=function(t){this._isBlank=t};var Z_=j_;function j_(t){this._calculator=new G_,this._setting=t||{},this._extent=[1/0,-1/0]}ma(Z_);var K_=0,$_=(Q_.createByAxisModel=function(t){var t=t.option,e=t.data,e=e&&F(e,J_);return new Q_({categories:e,needCollect:!e,deduplication:!1!==t.dedplication})},Q_.prototype.getOrdinal=function(t){return this._getOrCreateMap().get(t)},Q_.prototype.parseAndCollect=function(t){var e,n,i=this._needCollect;return H(t)||i?(i&&!this._deduplication?(n=this.categories.length,this.categories[n]=t,this._onCollect&&this._onCollect(t,n)):null==(n=(e=this._getOrCreateMap()).get(t))&&(i?(n=this.categories.length,this.categories[n]=t,e.set(t,n),this._onCollect&&this._onCollect(t,n)):n=NaN),n):t},Q_.prototype._getOrCreateMap=function(){return this._map||(this._map=O(this.categories))},Q_);function Q_(t){this.categories=t.categories||[],this._needCollect=t.needCollect,this._deduplication=t.deduplication,this.uid=++K_,this._onCollect=t.onCollect}function J_(t){return B(t)&&null!=t.value?t.value:t+""}u(nx,tx=Z_),nx.prototype.parse=function(t){return null==t?NaN:H(t)?this._ordinalMeta.getOrdinal(t):Math.round(t)},nx.prototype.contain=function(t){return W_(t,this._extent)&&0<=t&&t=t},nx.prototype.getOrdinalMeta=function(){return this._ordinalMeta},nx.prototype.calcNiceTicks=function(){},nx.prototype.calcNiceExtent=function(){},nx.type="ordinal";var tx,ex=nx;function nx(t){var t=tx.call(this,t)||this,e=(t.type="ordinal",t.getSetting("ordinalMeta"));return V(e=e||new $_({}))&&(e=new $_({categories:F(e,function(t){return B(t)?t.value:t})})),t._ordinalMeta=e,t._extent=t.getSetting("extent")||[0,e.categories.length-1],t}Z_.registerClass(ex);var ix,rx=Mo,ox=(u(ax,ix=Z_),ax.prototype.parse=function(t){return null==t||""===t?NaN:Number(t)},ax.prototype.contain=function(t){return W_(t,this._extent)},ax.prototype.normalize=function(t){return this._calculator.normalize(t,this._extent)},ax.prototype.scale=function(t){return this._calculator.scale(t,this._extent)},ax.prototype.getInterval=function(){return this._interval},ax.prototype.setInterval=function(t){this._interval=t,this._niceExtent=this._extent.slice(),this._intervalPrecision=V_(t)},ax.prototype.getTicks=function(t){t=t||{};var n=this._interval,e=this._extent,i=this._niceExtent,r=this._intervalPrecision,o=zp,a=[];if(n)if("only_break"===t.breakTicks&&o)o.addBreaksToTicks(a,this._brkCtx.breaks,this._extent);else{e[0]h&&(t.expandToNicedExtent?a.push({value:rx(h+n,r)}):a.push({value:e[1]})),"none"!==t.breakTicks&&o&&o.addBreaksToTicks(a,this._brkCtx.breaks,this._extent)}return a},ax.prototype.getMinorTicks=function(t){for(var e=this.getTicks({expandToNicedExtent:!0}),n=[],i=this.getExtent(),r=1;ri[0]&&cx));)g[r](g[i]()+t),f=g.getTime(),y&&0<(p=y.calcNiceTickMultiple(f,d))&&(g[r](g[i]()+p*t),f=g.getTime());a.push({value:f,notAdd:!0})}function i(t,e,n){var i,r,o,a,s=[],l=!e.length;if(i=$p(t),r=_[0],o=_[1],a=v,td(new Date(r),i,a).getTime()!==td(new Date(o),i,a).getTime()){l&&(e=[{value:function(t,e,n){e=Math.max(0,k(qp,e)-1);return td(new Date(t),qp[e],n).getTime()}(_[0],t,v)},{value:_[1]}]);for(var u,h,c=0;c=_[0]&&p<=_[1]&&w(f,p,d,g,y,0,s),"year"===t&&1=_[0]&&d<=_[1]&&a++)}u=e/m;if(1.5*u=_[0]&&t.value<=_[1]&&!t.notAdd})}),function(t){return 0n&&(this._approxInterval=n),Sx.length),t=Math.min(function(t,e,n,i){for(;n>>1;t[r][1]>1^-(1&s),l=(l=t.charCodeAt(a+1)-64)>>1^-(1&l);i.push([(r=s+=r)/n,(o=l+=o)/n])}return i}function y1(t,o){var e,n,r;return F(ut((t=(e=t).UTF8Encoding?(null==(r=(n=e).UTF8Scale)&&(r=1024),z(n.features,function(t){var e=t.geometry,n=e.encodeOffsets,i=e.coordinates;if(n)switch(e.type){case"LineString":e.coordinates=g1(i,n,r);break;case"Polygon":case"MultiLineString":f1(i,n,r);break;case"MultiPolygon":z(i,function(t,e){return f1(t,n[e],r)})}}),n.UTF8Encoding=!1,n):e).features,function(t){return t.geometry&&t.properties&&0=e[0]&&t<=e[1]}),function(t){var e={value:t};return{formattedLabel:i(e),rawLabel:n.scale.getLabel(e),tickValue:t,time:void 0,break:void 0}})}):"category"===n.type?(s=t,a=(t=n).getLabelModel(),s=M1(t,a,s),!a.get("show")||t.scale.isBlank()?{labels:[]}:s):(a=(r=n).scale.getTicks(),o=Wx(r),{labels:F(a,function(t,e){return{formattedLabel:o(t,e),rawLabel:r.scale.getLabel(t),tickValue:t.value,time:t.time,break:t.break}})})}function S1(t,e,n){var i,r,o,a,s,l,u=t.getTickModel().get("customValues");return u?(i=t.scale.getExtent(),{ticks:ut(b1(t,u),function(t){return t>=i[0]&&t<=i[1]})}):"category"===t.type?(u=e,a=T1(e=t),s=Ux(u),(l=k1(a,s))||(u.get("show")&&!e.scale.isBlank()||(r=[]),r=N(s)?O1(e,s,!0):"auto"===s?(l=M1(e,e.getLabelModel(),x1(_1.determine)),o=l.labelCategoryInterval,F(l.labels,function(t){return t.tickValue})):P1(e,o=s,!0),D1(a,s,{ticks:r,tickCategoryInterval:o}))):{ticks:F(t.scale.getTicks(n),function(t){return t.value})}}function M1(t,e,n){var i,r=C1(t),o=Ux(e),e=n.kind===_1.estimate;if(!e){var a=k1(r,o);if(a)return a}var s={labels:N(o)?O1(t,o):P1(t,i="auto"===o?function(t,e){{var n;if(e.kind===_1.estimate)return n=t.calculateCategoryInterval(e),e.out.noPxChangeTryDetermine.push(function(){return v1(t).autoInterval=n,!0}),n}var i=v1(t).autoInterval;return null!=i?i:v1(t).autoInterval=t.calculateCategoryInterval(e)}(t,n):o),labelCategoryInterval:i};return e?n.out.noPxChangeTryDetermine.push(function(){return D1(r,o,s),!0}):D1(r,o,s),s}var T1=I1("axisTick"),C1=I1("axisLabel");function I1(e){return function(t){return v1(t)[e]||(v1(t)[e]={list:[]})}}function k1(t,e){for(var n=0;nl[1],h(n[0].coord,l[0])&&(t?n[0].coord=l[0]:n.shift()),t&&h(l[0],n[0].coord)&&n.unshift({coord:l[0],onBand:!0}),h(l[1],i.coord)&&(t?i.coord=l[1]:n.pop()),t)&&h(i.coord,l[1])&&n.push({coord:l[1],onBand:!0}),u},N1.prototype.getMinorTicksCoords=function(){var t;return"ordinal"===this.scale.type?[]:(t=this.model.getModel("minorTick").get("splitNumber"),F(this.scale.getMinorTicks(t=0=u}}for(var o,a=this.__startIndex;ar[0]){for(l=0;lt);l++);s=i[r[l]]}r.splice(l+1,0,t),(i[t]=e).virtual||(s?(n=s.dom).nextSibling?a.insertBefore(e.dom,n.nextSibling):a.appendChild(e.dom):a.firstChild?a.insertBefore(e.dom,a.firstChild):a.appendChild(e.dom)),e.painter||(e.painter=this)}},m.prototype.eachLayer=function(t,e){for(var n=this._zlevelList,i=0;ie&&(e=t[n]);return isFinite(e)?e:NaN},min:function(t){for(var e=1/0,n=0;n=r.r0?"endArc":"startArc":r.endAngle>=r.startAngle?"endAngle":"startAngle":a?0<=r.height?"bottom":"top":0<=r.width?"right":"left"),h=ip(i),l=(np(t,h,{labelFetcher:o,labelDataIndex:n,defaultText:ew(o.getData(),n),inheritColor:l.fill,defaultOpacity:l.opacity,defaultOutsidePosition:u}),t.getTextContent()),h=(s&&l&&(s=i.get(["label","position"]),t.textConfig.inside="middle"===s||null,function(t,e,n,i){if(W(i))t.setTextConfig({rotation:i});else if(V(e))t.setTextConfig({rotation:0});else{var r,i=t.shape,o=i.clockwise?i.startAngle:i.endAngle,a=i.clockwise?i.endAngle:i.startAngle,s=(o+a)/2,i=n(e);switch(i){case"startArc":case"insideStartArc":case"middle":case"insideEndArc":case"endArc":r=s;break;case"startAngle":case"insideStartAngle":r=o;break;case"endAngle":case"insideEndAngle":r=a;break;default:return t.setTextConfig({rotation:0})}n=1.5*Math.PI-r;"middle"===i&&n>Math.PI/2&&n<1.5*Math.PI&&(n-=Math.PI),t.setTextConfig({rotation:n})}}(t,"outside"===s?u:s,_w(a),i.get(["label","rotate"]))),u=l,s=h,a=o.getRawValue(n),l=function(t){return nw(e,t)},u&&((u=hp(u)).prevValue=u.value,u.value=a,a=s.normal,u.valueAnimation=a.get("valueAnimation"),u.valueAnimation)&&(u.precision=a.get("precision"),u.defaultInterpolatedText=l,u.statesModels=s),i.getModel(["emphasis"]));fu(t,h.get("focus"),h.get("blurScope"),h.get("disabled")),mu(t,i),null!=(o=r).startAngle&&null!=o.endAngle&&o.startAngle===o.endAngle&&(t.style.fill="none",t.style.stroke="none",z(t.states,function(t){t.style&&(t.style.fill=t.style.stroke="none")}))}var bw,ww=function(){},Sw=(u(Mw,bw=Us),Mw.prototype.getDefaultShape=function(){return new ww},Mw.prototype.buildPath=function(t,e){for(var n=e.points,i=this.baseDimIdx,r=1-this.baseDimIdx,o=[],a=[],s=this.barWidth,l=0;le[u-1].coord&&(e.reverse(),h.reverse()),function(t,e){var n,i,r=[],o=t.length;function a(t,e,n){var i=t.coord;return{coord:n,color:Li((n-i)/(e.coord-i),[t.color,e.color])}}for(var s=0;si)return;return 1}(a,e))return r=e.mapDimension(a.dim),o={},z(a.getViewLabels(),function(t){t=a.scale.getRawOrdinalNumber(t.tickValue);o[t]=1}),function(t){return!o.hasOwnProperty(e.get(r,t))}}}function uS(t){for(var e,n,i=t.length/2;0l?x:_,(g=Math.abs(d.label.y-l))>=f.maxY&&(m=d.label.x-s-d.len2*h,y=u+d.len,m=Math.abs(m)t.unconstrainedWidth)?null:s,i.setStyle("width",l)),SS(r,i))}function SS(t,e){TS.rect=t,ub(TS,e,MS)}var MS={minMarginForce:[null,0,null,0],marginDefault:[1,0,1,0]},TS={};function CS(t){return"center"===t.position}function IS(t){var S,M,T=t.getData(),C=[],I=!1,B=(t.get("minShowLabelAngle")||0)*xS,e=T.getLayout("viewRect"),k=T.getLayout("r"),D=e.width,A=e.x,n=e.y,L=e.height;function P(t){t.ignore=!0}if(T.each(function(t){var e,n,i,r,o,a,s,l,u,h,c=T.getItemGraphicEl(t),p=c.shape,d=c.getTextContent(),f=c.getTextGuideLine(),t=T.getItemModel(t),g=t.getModel("label"),y=g.get("position")||t.get(["emphasis","label","position"]),m=g.get("distanceToLabelLine"),v=g.get("alignTo"),_=wo(g.get("edgeDistance"),D),x=g.get("bleedMargin"),t=(null==x&&(x=200=e.r0},OS.type="pie";var LS,PS=OS;function OS(){var t=null!==LS&&LS.apply(this,arguments)||this;return t.ignoreLabelLineUpdate=!0,t}NS.prototype.getAllNames=function(){var t=this._getRawData();return t.mapArray(t.getName)},NS.prototype.containName=function(t){return 0<=this._getRawData().indexOfName(t)},NS.prototype.indexOfName=function(t){return this._getDataWithEncodedVisual().indexOfName(t)},NS.prototype.getItemVisual=function(t,e){return this._getDataWithEncodedVisual().getItemVisual(t,e)};var RS=NS;function NS(t,e){this._getDataWithEncodedVisual=t,this._getRawData=e}var BS,ES=ta(),zS=(u(FS,BS=Xy),FS.prototype.init=function(t){BS.prototype.init.apply(this,arguments),this.legendVisualProvider=new RS(S(this.getData,this),S(this.getRawData,this)),this._defaultLabelLine(t)},FS.prototype.mergeOption=function(){BS.prototype.mergeOption.apply(this,arguments)},FS.prototype.getInitialData=function(){return e=V(e={coordDimensions:["value"],encodeDefaulter:pt(gf,t=this)})?{coordDimensions:e}:P({encodeDefine:t.getEncode()},e),i=t.getSource(),e=D_(i,e).dimensions,(e=new k_(e,t)).initData(i,n),e;var t,e,n,i},FS.prototype.getDataParams=function(t){var e,n=this.getData(),i=ES(n),r=i.seats,i=(r||(e=[],n.each(n.mapDimension("value"),function(t){e.push(t)}),r=i.seats=ko(e,n.hostModel.get("percentPrecision"))),BS.prototype.getDataParams.call(this,t));return i.percent=r[t]||0,i.$vars.push("percent"),i},FS.prototype._defaultLabelLine=function(t){Go(t,"labelLine",["show"]);var e=t.labelLine,n=t.emphasis.labelLine;e.show=e.show&&t.label.show,n.show=n.show&&t.emphasis.label.show},FS.type="series.pie",FS.defaultOption={z:2,legendHoverLink:!0,colorBy:"data",center:["50%","50%"],radius:[0,"50%"],clockwise:!0,startAngle:90,endAngle:"auto",padAngle:0,minAngle:0,minShowLabelAngle:0,selectedOffset:10,percentPrecision:2,stillShowZeroSum:!0,coordinateSystemUsage:"box",left:0,top:0,right:0,bottom:0,width:null,height:null,label:{rotate:0,show:!0,overflow:"truncate",position:"outer",alignTo:"none",edgeDistance:"25%",distanceToLabelLine:5},labelLine:{show:!0,length:15,length2:30,smooth:!1,minTurnAngle:90,maxSurfaceAngle:90,lineStyle:{width:1,type:"solid"}},itemStyle:{borderWidth:1,borderJoin:"round"},showEmptyCircle:!0,emptyCircleStyle:{color:"lightgray",opacity:1},labelLayout:{hideOverlap:!0},emphasis:{scale:!0,scaleSize:5},avoidLabelOverlap:!0,animationType:"expansion",animationDuration:1e3,animationTypeUpdate:"transition",animationEasingUpdate:"cubicInOut",animationDurationUpdate:500,animationEasing:"cubicInOut"},FS);function FS(){return null!==BS&&BS.apply(this,arguments)||this}mp={fullType:zS.type,getCoord2:function(t){return t.getShallow("center")}},Dd.set(mp.fullType,{getCoord2:void 0}).getCoord2=mp.getCoord2,Jx(function(t){t.registerChartView(PS),t.registerSeriesModel(zS),Um("pie",t.registerAction),t.registerLayout(pt(vS,"pie")),t.registerProcessor({seriesType:"pie",reset:function(t,e){var i,r=e.findComponents({mainType:"legend"});r&&r.length&&(i=t.getData()).filterSelf(function(t){for(var e=i.getName(t),n=0;ne[1]&&e.reverse(),e},sM.prototype.pointToData=function(t,e){return this.coordToData(this.toLocalCoord(t["x"===this.dim?0:1]),e)},sM.prototype.setCategorySortInfo=function(t){if("category"!==this.type)return!1;this.model.option.categorySortInfo=t,this.scale.setSortInfo(t)};var oM,aM=sM;function sM(t,e,n,i,r){t=oM.call(this,t,e,n)||this;return t.index=0,t.type=i||"value",t.position=r||"bottom",t}var lM="expandAxisBreak",uM=Math.PI,hM=[[1,2,1,2],[5,3,5,3],[8,3,8,3]],cM=[[0,1,0,1],[0,3,0,3],[0,3,0,3]],pM=ta(),dM=ta(),fM=(gM.prototype.ensureRecord=function(t){var e=t.axis.dim,t=t.componentIndex,n=this.recordMap,n=n[e]||(n[e]=[]);return n[t]||(n[t]={ready:{}})},gM);function gM(t){this.recordMap={},this.resolveAxisNameOverlap=t}function yM(t,e,n,i,r,o){var a,s;Yx(t.nameLocation)?(t=o.stOccupiedRect)&&_M((a={},t=t,s=o.transGroup.transform,a.transform=jc(a.transform,s),a.localRect=Zc(a.localRect,t),a.rect=Zc(a.rect,t),s&&a.rect.applyTransform(s),a.axisAligned=qc(s),a.obb=void 0,(a.label=a.label||{}).ignore=!1,a),i,r):xM(o.labelInfoList,o.dirVec,i,r)}var mM=Oe(),vM=new X(0,0,0,0);function _M(t,e,n){var i=new U;gb(t,e,i,{direction:Math.atan2(n.y,n.x),bidirectional:!1,touchThreshold:.05})&&(t=i,n=e)&&(n.label.x+=t.x,n.label.y+=t.y,n.label.markRedraw(),(i=n.transform)&&(i[4]+=t.x,i[5]+=t.y),(e=n.rect)&&(e.x+=t.x,e.y+=t.y),e=n.obb)&&e.fromBoundingRect(n.localRect,i)}function xM(t,e,n,i){for(var r=0<=U.dot(i,e),o=0,a=t.length;oi[1],i="start"===e&&!t||"start"!==e&&t;e=Ao(n-uM/2)?(r=i?"bottom":"top","center"):Ao(n-1.5*uM)?(r=i?"top":"bottom","center"):(r="middle",n<1.5*uM&&uM/2s[0]&&isFinite(c)&&isFinite(s[0]);)h=F_(h),c=s[1]-h*a;else{t=(h=au[1]&&u.reverse(),(s=null==s||s>u[1]?u[1]:s)n[r],f=[-c.x,-c.y],e=(e||(f[i]=l[s]),[0,0]),s=[-p.x,-p.y],g=G(t.get("pageButtonGap",!0),t.get("itemGap",!0)),f=(d&&("end"===t.get("pageButtonPosition",!0)?s[i]+=n[r]-p[r]:e[i]+=p[r]+g),s[1-i]+=c[o]/2-p[o]/2,l.setPosition(f),u.setPosition(e),h.setPosition(s),{x:0,y:0}),c=(f[r]=(d?n:c)[r],f[o]=Math.max(c[o],p[o]),f[a]=Math.min(0,p[a]+s[1-i]),u.__rectSize=n[r],d?((e={x:0,y:0})[r]=Math.max(n[r]-p[r]-g,0),e[o]=f[o],u.setClipPath(new sl({shape:e})),u.__rectSize=e[r]):h.eachChild(function(t){t.attr({invisible:!0,silent:!0})}),this._getPageInfo(t));return null!=c.pageIndex&&cc(l,{x:c.contentPosition[0],y:c.contentPosition[1]},d?t:null),this._updatePageInfoView(t,c),f},ZT.prototype._pageGo=function(t,e,n){t=this._getPageInfo(e)[t];null!=t&&n.dispatchAction({type:"legendScroll",scrollDataIndex:t,legendId:e.id})},ZT.prototype._updatePageInfoView=function(n,i){var r=this._controllerGroup,t=(z(["pagePrev","pageNext"],function(t){var e=null!=i[t+"DataIndex"],t=r.childOfName(t);t&&(t.setStyle("fill",e?n.get("pageIconColor",!0):n.get("pageIconInactiveColor",!0)),t.cursor=e?"pointer":"default")}),r.childOfName("pageText")),e=n.get("pageFormatter"),o=i.pageIndex,o=null!=o?o+1:0,a=i.pageCount;t&&e&&t.setStyle("text",H(e)?e.replace("{current}",null==o?"":o+"").replace("{total}",null==a?"":a+""):e({current:o,total:a}))},ZT.prototype._getPageInfo=function(t){var e=t.get("scrollDataIndex",!0),n=this.getContentGroup(),i=this._containerGroup.__rectSize,t=t.getOrient().index,r=XT[t],o=YT[t],e=this._findTargetItemIndex(e),a=n.children(),s=a[e],l=a.length,u=l?1:0,h={contentPosition:[n.x,n.y],pageCount:u,pageIndex:u-1,pagePrevDataIndex:null,pageNextDataIndex:null};if(s){n=g(s);h.contentPosition[t]=-n.s;for(var c=e+1,p=n,d=n,f=null;c<=l;++c)(!(f=g(a[c]))&&d.e>p.s+i||f&&!y(f,p.s))&&(p=d.i>p.i?d:f)&&(null==h.pageNextDataIndex&&(h.pageNextDataIndex=p.i),++h.pageCount),d=f;for(c=e-1,p=n,d=n,f=null;-1<=c;--c)(f=g(a[c]))&&y(d,f.s)||!(p.i=e&&t.s<=e+i}},ZT.prototype._findTargetItemIndex=function(n){var i,r;return this._showController?(this.getContentGroup().eachChild(function(t,e){t=t.__legendDataIndex;null==r&&null!=t&&(r=e),t===n&&(i=e)}),null!=i?i:r):0},ZT.type="legend.scroll",ZT);function ZT(){var t=null!==GT&>.apply(this,arguments)||this;return t.type=ZT.type,t.newlineDisabled=!0,t._currentIndex=0,t}Jx(function(t){Jx(zT),t.registerComponentModel(VT),t.registerComponentView(qT),t.registerAction("legendScroll","legendscroll",function(t,e){var n=t.scrollDataIndex;null!=n&&e.eachComponent({mainType:"legend",subType:"scroll",query:t},function(t){t.setScrollDataIndex(n)})})});var jT=ta(),KT=y,$T=S;function QT(){this._dragging=!1,this.animationThreshold=15}function JT(t,e,n,i){!function n(i,t){{var r;return B(i)&&B(t)?(r=!0,z(t,function(t,e){r=r&&n(i[e],t)}),!!r):i===t}}(jT(n).lastProp,i)&&(jT(n).lastProp=i,e?cc(n,i,t):(n.stopAnimation(),n.attr(i)))}function tC(t,e){t[e.get(["label","show"])?"show":"hide"]()}function eC(t){return{x:t.x||0,y:t.y||0,rotation:t.rotation||0}}function nC(t,e,n){var i=e.get("z"),r=e.get("zlevel");t&&t.traverse(function(t){"group"!==t.type&&(null!=i&&(t.z=i),null!=r&&(t.zlevel=r),t.silent=n)})}function iC(t,e,n,i,r){var o=rC(n.get("value"),e.axis,e.ecModel,n.get("seriesDataIndices"),{precision:n.get(["label","precision"]),formatter:n.get(["label","formatter"])}),n=n.getModel("label"),a=yd(n.get("padding")||0),s=n.getFont(),l=Vr(o,s),u=r.position,h=l.width+a[1]+a[3],l=l.height+a[0]+a[2],c=r.align,c=("right"===c&&(u[0]-=h),"center"===c&&(u[0]-=h/2),r.verticalAlign),i=("bottom"===c&&(u[1]-=l),"middle"===c&&(u[1]-=l/2),r=u,c=h,h=l,i=(l=i).getWidth(),l=l.getHeight(),r[0]=Math.min(r[0]+c,i)-c,r[1]=Math.min(r[1]+h,l)-h,r[0]=Math.max(r[0],0),r[1]=Math.max(r[1],0),n.get("backgroundColor"));i&&"auto"!==i||(i=e.get(["axisLine","lineStyle","color"])),t.label={x:u[0],y:u[1],style:rp(n,{text:o,font:s,fill:n.getTextColor(),padding:a,backgroundColor:i}),z2:10}}function rC(t,e,n,i,r){t=e.scale.parse(t);var o,a=e.scale.getLabel({value:t},{precision:r.precision}),r=r.formatter;return r&&(o={value:Gx(e,{value:t}),axisDimension:e.dim,axisIndex:e.index,seriesData:[]},z(i,function(t){var e=n.getSeriesByIndex(t.seriesIndex),t=t.dataIndexInside,e=e&&e.getDataParams(t);e&&o.seriesData.push(e)}),H(r)?a=r.replace("{value}",a):N(r)&&(a=r(o))),a}function oC(t,e,n){var i=Oe();return ze(i,i,n.rotation),Ee(i,i,n.position),Rc([t.dataToCoord(e),(n.labelOffset||0)+(n.labelDirection||1)*(n.labelMargin||0)],i)}QT.prototype.render=function(t,e,n,i){var r,o,a=e.get("value"),s=e.get("status");this._axisModel=t,this._axisPointerModel=e,this._api=n,!i&&this._lastValue===a&&this._lastStatus===s||(this._lastValue=a,this._lastStatus=s,i=this._group,r=this._handle,s&&"hide"!==s?(i&&i.show(),r&&r.show(),this.makeElOption(s={},a,t,e,n),(o=s.graphicKey)!==this._lastGraphicKey&&this.clear(n),this._lastGraphicKey=o,o=this._moveAnimation=this.determineAnimation(t,e),i?(o=pt(JT,e,o),this.updatePointerEl(i,s,o),this.updateLabelEl(i,s,o,e)):(i=this._group=new oo,this.createPointerEl(i,s,t,e),this.createLabelEl(i,s,t,e),n.getZr().add(i)),nC(i,e,!0),this._renderHandle(a)):(i&&i.hide(),r&&r.hide()))},QT.prototype.remove=function(t){this.clear(t)},QT.prototype.dispose=function(t){this.clear(t)},QT.prototype.determineAnimation=function(t,e){var n,i=e.get("animation"),r=t.axis,o="category"===r.type,e=e.get("snap");return!(!e&&!o)&&("auto"===i||null==i?(n=this.animationThreshold,o&&r.getBandWidth()>n||!!e&&(o=ZM(t).seriesDataCount,e=r.getExtent(),Math.abs(e[0]-e[1])/o>n)):!0===i)},QT.prototype.makeElOption=function(t,e,n,i,r){},QT.prototype.createPointerEl=function(t,e,n,i){var r=e.pointer;r&&(r=jT(t).pointerEl=new Qc[r.type](KT(e.pointer)),t.add(r))},QT.prototype.createLabelEl=function(t,e,n,i){e.label&&(e=jT(t).labelEl=new dl(KT(e.label)),t.add(e),tC(e,i))},QT.prototype.updatePointerEl=function(t,e,n){t=jT(t).pointerEl;t&&e.pointer&&(t.setStyle(e.pointer.style),n(t,{shape:e.pointer.shape}))},QT.prototype.updateLabelEl=function(t,e,n,i){t=jT(t).labelEl;t&&(t.setStyle(e.label.style),n(t,{x:e.label.x,y:e.label.y}),tC(t,i))},QT.prototype._renderHandle=function(t){var e,n,i,r,o,a;!this._dragging&&this.updateHandleTransform&&(e=this._axisPointerModel,n=this._api.getZr(),i=this._handle,r=e.getModel("handle"),a=e.get("status"),r.get("show")&&a&&"hide"!==a?(this._handle||(o=!0,i=this._handle=Fc(r.get("icon"),{cursor:"move",draggable:!0,onmousemove:function(t){ke(t.event)},onmousedown:$T(this._onHandleDragMove,this,0,0),drift:$T(this._onHandleDragMove,this),ondragend:$T(this._onHandleDragEnd,this)}),n.add(i)),nC(i,e,!1),i.setStyle(r.getItemStyle(null,["color","borderColor","borderWidth","opacity","shadowColor","shadowBlur","shadowOffsetX","shadowOffsetY"])),V(a=r.get("size"))||(a=[a,a]),i.scaleX=a[0]/2,i.scaleY=a[1]/2,gm(this,"_doDispatchAxisPointer",r.get("throttle")||0,"fixRate"),this._moveHandleToValue(t,o)):(i&&n.remove(i),this._handle=null))},QT.prototype._moveHandleToValue=function(t,e){JT(this._axisPointerModel,!e&&this._moveAnimation,this._handle,eC(this.getHandleTransform(t,this._axisModel,this._axisPointerModel)))},QT.prototype._onHandleDragMove=function(t,e){var n=this._handle;n&&(this._dragging=!0,t=this.updateHandleTransform(eC(n),[t,e],this._axisModel,this._axisPointerModel),this._payloadInfo=t,n.stopAnimation(),n.attr(eC(t)),jT(n).lastProp=null,this._doDispatchAxisPointer())},QT.prototype._doDispatchAxisPointer=function(){var t,e;this._handle&&(t=this._payloadInfo,e=this._axisModel,this._api.dispatchAction({type:"updateAxisPointer",x:t.cursorPoint[0],y:t.cursorPoint[1],tooltipOption:t.tooltipOption,axesInfo:[{axisDim:e.axis.dim,axisIndex:e.componentIndex}]}))},QT.prototype._onHandleDragEnd=function(){var t;this._dragging=!1,this._handle&&(t=this._axisPointerModel.get("value"),this._moveHandleToValue(t),this._api.dispatchAction({type:"hideTip"}))},QT.prototype.clear=function(t){this._lastValue=null,this._lastStatus=null;var t=t.getZr(),e=this._group,n=this._handle;t&&e&&(this._lastGraphicKey=null,e&&t.remove(e),n&&t.remove(n),this._group=null,this._handle=null,this._payloadInfo=null),ym(this,"_doDispatchAxisPointer")},QT.prototype.doClear=function(){},QT.prototype.buildLabel=function(t,e,n){return{x:t[n=n||0],y:t[1-n],width:e[n],height:e[1-n]}};u(lC,aC=QT),lC.prototype.makeElOption=function(t,e,n,i,r){var o,a,s=n.axis,l=s.grid,u=i.get("type"),h=uC(l,s).getOtherAxis(s).getGlobalExtent(),c=s.toGlobalCoord(s.dataToCoord(e,!0)),p=(u&&"none"!==u&&(o=(a=i).get("type"),a=a.getModel(o+"Style"),"line"===o?(p=a.getLineStyle()).fill=null:"shadow"===o&&((p=a.getAreaStyle()).stroke=null),o=p,(a=hC[u](s,c,h)).style=o,t.graphicKey=a.type,t.pointer=a),OM(l.getRect(),n));u=e,s=t,c=p,h=n,o=i,a=r,l=bM.innerTextLayout(c.rotation,0,c.labelDirection),c.labelMargin=o.get(["label","margin"]),iC(s,h,o,a,{position:oC(h.axis,u,c),align:l.textAlign,verticalAlign:l.textVerticalAlign})},lC.prototype.getHandleTransform=function(t,e,n){var i=OM(e.axis.grid.getRect(),e,{labelInside:!1}),n=(i.labelMargin=n.get(["handle","margin"]),oC(e.axis,t,i));return{x:n[0],y:n[1],rotation:i.rotation+(i.labelDirection<0?Math.PI:0)}},lC.prototype.updateHandleTransform=function(t,e,n,i){var n=n.axis,r=n.grid,o=n.getGlobalExtent(!0),r=uC(r,n).getOtherAxis(n).getGlobalExtent(),n="x"===n.dim?0:1,a=[t.x,t.y],e=(a[n]+=e[n],a[n]=Math.min(o[1],a[n]),a[n]=Math.max(o[0],a[n]),(r[1]+r[0])/2),o=[e,e];o[n]=a[n];return{x:a[0],y:a[1],rotation:t.rotation,cursorPoint:o,tooltipOption:[{verticalAlign:"middle"},{align:"center"}][n]}};var aC,sC=lC;function lC(){return null!==aC&&aC.apply(this,arguments)||this}function uC(t,e){var n={};return n[e.dim+"AxisIndex"]=e.index,t.getCartesian(n)}var hC={line:function(t,e,n){var i;return i=[e,n[0]],e=[e,n[1]],n=cC(t),{type:"Line",subPixelOptimize:!0,shape:{x1:i[n=n||0],y1:i[1-n],x2:e[n],y2:e[1-n]}}},shadow:function(t,e,n){var i=Math.max(1,t.getBandWidth()),r=n[1]-n[0];return{type:"Rect",shape:(e=[e-i/2,n[0]],n=[i,r],i=cC(t),{x:e[i=i||0],y:e[1-i],width:n[i],height:n[1-i]})}}};function cC(t){return"x"===t.dim?0:1}u(fC,pC=g),fC.type="axisPointer",fC.defaultOption={show:"auto",z:50,type:"line",snap:!1,triggerTooltip:!0,triggerEmphasis:!0,value:null,status:null,link:[],animation:null,animationDurationUpdate:200,lineStyle:{color:v.color.border,width:1,type:"dashed"},shadowStyle:{color:v.color.shadowTint},label:{show:!0,formatter:null,precision:"auto",margin:3,color:v.color.neutral00,padding:[5,7,5,7],backgroundColor:v.color.accent60,borderColor:null,borderWidth:0,borderRadius:3},handle:{show:!1,icon:"M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z",size:45,margin:50,color:v.color.accent40,throttle:40}};var pC,dC=fC;function fC(){var t=null!==pC&&pC.apply(this,arguments)||this;return t.type=fC.type,t}var gC=ta(),yC=z;function mC(t,e,n){var i,c,p;function r(t,h){c.on(t,function(e){n=p;var n,i,r={dispatchAction:o,pendings:i={showTip:[],hideTip:[]}};function o(t){var e=i[t.type];e?e.push(t):(t.dispatchAction=o,n.dispatchAction(t))}yC(gC(c).records,function(t){t&&h(t,e,r.dispatchAction)});var t,a=r.pendings,s=p,l=a.showTip.length,u=a.hideTip.length;l?t=a.showTip[l-1]:u&&(t=a.hideTip[u-1]),t&&(t.dispatchAction=null,s.dispatchAction(t))})}w.node||(i=e.getZr(),gC(i).records||(gC(i).records={}),p=e,gC(c=i).initialized||(gC(c).initialized=!0,r("click",pt(_C,"click")),r("mousemove",pt(_C,"mousemove")),r("globalout",vC)),(gC(i).records[t]||(gC(i).records[t]={})).handler=n)}function vC(t,e,n){t.handler("leave",null,n)}function _C(t,e,n,i){e.handler(t,n,i)}function xC(t,e){w.node||(e=e.getZr(),(gC(e).records||{})[t]&&(gC(e).records[t]=null))}u(SC,bC=Jy),SC.prototype.render=function(t,e,n){var e=e.getComponent("tooltip"),i=t.get("triggerOn")||e&&e.get("triggerOn")||"mousemove|click";mC("axisPointer",n,function(t,e,n){"none"!==i&&("leave"===t||0<=i.indexOf(t))&&n({type:"updateAxisPointer",currTrigger:t,x:e&&e.offsetX,y:e&&e.offsetY})})},SC.prototype.remove=function(t,e){xC("axisPointer",e)},SC.prototype.dispose=function(t,e){xC("axisPointer",e)},SC.type="axisPointer";var bC,wC=SC;function SC(){var t=null!==bC&&bC.apply(this,arguments)||this;return t.type=SC.type,t}function MC(t,e){var n,i,r,o,a=[],s=t.seriesIndex;return null==s||!(e=e.getSeriesByIndex(s))||null==(s=Jo(n=e.getData(),t))||s<0||V(s)?{point:[]}:(i=n.getItemGraphicEl(s),r=e.coordinateSystem,e.getTooltipPosition?a=e.getTooltipPosition(s)||[]:r&&r.dataToPoint?a=t.isStacked?(e=r.getBaseAxis(),t=r.getOtherAxis(e).dim,e=e.dim,t="x"===t||"radius"===t?1:0,e=n.mapDimension(e),(o=[])[t]=n.get(e,s),o[1-t]=n.get(n.getCalculationInfo("stackResultDimension"),s),r.dataToPoint(o)||[]):r.dataToPoint(n.getValues(F(r.dimensions,function(t){return n.mapDimension(t)}),s))||[]:i&&((e=i.getBoundingRect().clone()).applyTransform(i.transform),a=[e.x+e.width/2,e.y+e.height/2]),{point:a,el:i})}var TC=ta();function CC(t,e,n){var o,a,i,s,l,r,u,h,c,p,d,f,g,y,m=t.currTrigger,v=[t.x,t.y],_=t,x=t.dispatchAction||S(n.dispatchAction,n),b=e.getComponent("axisPointer").coordSysAxesInfo;if(b)return LC(v)&&(v=MC({seriesIndex:_.seriesIndex,dataIndex:_.dataIndex},e).point),o=LC(v),a=_.axesInfo,i=b.axesInfo,s="leave"===m||LC(v),l={},e={list:[],map:{}},u={showPointer:pt(kC,r={}),showTooltip:pt(DC,e)},z(b.coordSysMap,function(t,e){var r=o||t.containPoint(v);z(b.coordSysAxesInfo[e],function(t,e){var n=t.axis,i=function(t,e){for(var n=0;n<(t||[]).length;n++){var i=t[n];if(e.axis.dim===i.axisDim&&e.axis.model.componentIndex===i.axisIndex)return i}}(a,t);s||!r||a&&!i||null!=(i=null!=(i=i&&i.value)||o?i:n.pointToData(v))&&IC(t,i,u,!1,l)})}),h={},z(i,function(n,t){var i=n.linkGroup;i&&!r[t]&&z(i.axesInfo,function(t,e){var e=r[e];t!==n&&e&&(e=e.value,i.mapper&&(e=n.axis.scale.parse(i.mapper(e,AC(t),AC(n)))),h[n.key]=e)})}),z(h,function(t,e){IC(i[e],t,u,!0,l)}),c=r,_=i,p=l.axesInfo=[],z(_,function(t,e){var n=t.axisPointerModel.option,e=c[e];e?(t.useHandle||(n.status="show"),n.value=e.value,n.seriesDataIndices=(e.payloadBatch||[]).slice()):t.useHandle||(n.status="hide"),"show"===n.status&&p.push({axisDim:t.axis.dim,axisIndex:t.axis.model.componentIndex,value:n.value})}),m=e,_=t,e=x,LC(t=v)||!m.list.length?e({type:"hideTip"}):(x=((m.list[0].dataByAxis[0]||{}).seriesDataIndices||[])[0]||{},e({type:"showTip",escapeConnect:!0,x:t[0],y:t[1],tooltipOption:_.tooltipOption,position:_.position,dataIndexInside:x.dataIndexInside,dataIndex:x.dataIndex,seriesIndex:x.seriesIndex,dataByCoordSys:m.list})),e=i,_=(t=n).getZr(),x="axisPointerLastHighlights",d=TC(_)[x]||{},f=TC(_)[x]={},z(e,function(t,e){var n=t.axisPointerModel.option;"show"===n.status&&t.triggerEmphasis&&z(n.seriesDataIndices,function(t){var e=t.seriesIndex+" | "+t.dataIndex;f[e]=t})}),g=[],y=[],z(d,function(t,e){f[e]||y.push(t)}),z(f,function(t,e){d[e]||g.push(t)}),y.length&&t.dispatchAction({type:"downplay",escapeConnect:!0,notBlur:!0,batch:y}),g.length&&t.dispatchAction({type:"highlight",escapeConnect:!0,notBlur:!0,batch:g}),l}function IC(t,e,n,i,r){var o,a,s,l,u,h,c,p,d,f,g=t.axis;!g.scale.isBlank()&&g.containData(e)&&(t.involveSeries?(a=e,s=t.axis,l=s.dim,u=a,h=[],c=Number.MAX_VALUE,p=-1,z(t.seriesModels,function(e,t){var n,i=e.getData().mapDimensionsAll(l);if(e.getAxisTooltipData)var r=e.getAxisTooltipData(i,a,s),o=r.dataIndices,r=r.nestestValue;else{if(!(o=e.indicesOfNearest(l,i[0],a,"category"===s.type?.5:null)).length)return;r=e.getData().get(i[0],o[0])}null!=r&&isFinite(r)&&(i=a-r,(n=Math.abs(i))<=c)&&((n'):""),H(t))o.innerHTML=t+c;else if(t){o.innerHTML="",V(t)||(t=[t]);for(var p,d=0;d"),o=f.join(e);this._showOrMove(i,function(){this._updateContentNotChangedOnAxis(t,p)?this._updatePosition(i,r,n[0],n[1],this._tooltipContent,p):this._showTooltipContent(i,o,p,Math.random()+"",n[0],n[1],r,null,g)})},n2.prototype._showSeriesItemTooltip=function(t,e,n){var i,r,o,a,s,l=this._ecModel,e=Y(e),u=e.seriesIndex,h=l.getSeriesByIndex(u),c=e.dataModel||h,p=e.dataIndex,e=e.dataType,d=c.getData(e),f=this._renderMode,g=t.positionDefault,y=i2([d.getItemModel(p),c,h&&(h.coordinateSystem||{}).model],this._tooltipModel,g?{position:g}:null),h=y.get("trigger");null!=h&&"item"!==h||(i=c.getDataParams(p,e),r=new Fy,i.marker=r.makeTooltipMarker("item",wd(i.color),f),g=Pg(c.formatTooltip(p,!1,e)),h=y.get("order"),e=y.get("valueFormatter"),o=g.frag,a=o?Ny(e?P({valueFormatter:e},o):o,r,f,h,l.get("useUTC"),y.get("textStyle")):g.text,s="item_"+c.name+"_"+p,this._showOrMove(y,function(){this._showTooltipContent(y,a,i,s,t.offsetX,t.offsetY,t.position,t.target,r)}),n({type:"showTip",dataIndexInside:p,dataIndex:d.getRawIndex(p),seriesIndex:u,from:this.uid}))},n2.prototype._showComponentItemTooltip=function(e,n,t){var i="html"===this._renderMode,r=Y(n),o=r.tooltipConfig.option||{},a=o.encodeHTMLContent,a=(H(o)&&(o={content:o,formatter:o},a=!0),a&&i&&o.content&&((o=y(o)).content=xe(o.content)),[o]),i=this._ecModel.getComponent(r.componentMainType,r.componentIndex),r=(i&&a.push(i),a.push({formatter:o.content}),e.positionDefault),s=i2(a,this._tooltipModel,r?{position:r}:null),l=s.get("content"),u=Math.random()+"",h=new Fy;this._showOrMove(s,function(){var t=y(s.get("formatterParams")||{});this._showTooltipContent(s,l,t,u,e.offsetX,e.offsetY,e.position,n,h)}),t({type:"showTip",from:this.uid})},n2.prototype._showTooltipContent=function(n,t,i,e,r,o,a,s,l){var u,h,c,p,d;this._ticket="",n.get("showContent")&&n.get("show")&&((u=this._tooltipContent).setEnterable(n.get("enterable")),h=n.get("formatter"),a=a||n.get("position"),t=t,c=this._getNearestPoint([r,o],i,n.get("trigger"),n.get("borderColor"),n.get("defaultBorderColor",!0)).color,h&&(t=H(h)?(p=n.ecModel.get("useUTC"),t=h,xd(t=(d=V(i)?i[0]:i)&&d.axisType&&0<=d.axisType.indexOf("time")?Qp(d.axisValue,t,p):t,i,!0)):N(h)?(d=S(function(t,e){t===this._ticket&&(u.setContent(e,l,n,c,a),this._updatePosition(n,a,r,o,u,i,s))},this),this._ticket=e,h(i,e,d)):h),u.setContent(t,l,n,c,a),u.show(n,c),this._updatePosition(n,a,r,o,u,i,s))},n2.prototype._getNearestPoint=function(t,e,n,i,r){return"axis"===n||V(e)?{color:i||r}:V(e)?void 0:{color:i||e.color||e.borderColor}},n2.prototype._updatePosition=function(t,e,n,i,r,o,a){var s,l=this._api.getWidth(),u=this._api.getHeight(),h=(e=e||t.get("position"),r.getSize()),c=t.get("align"),p=t.get("verticalAlign"),d=a&&a.getBoundingRect().clone();a&&d.applyTransform(a.transform),V(e=N(e)?e([n,i],o,r.el,d,{viewSize:[l,u],contentSize:h.slice()}):e)?(n=wo(e[0],l),i=wo(e[1],u)):B(e)?((o=e).width=h[0],o.height=h[1],n=(o=zd(o,{width:l,height:u})).x,i=o.y,p=c=null):i=(n=(s=H(e)&&a?function(t,e,n,i){var r=n[0],o=n[1],a=Math.ceil(Math.SQRT2*i)+8,s=0,l=0,u=e.width,h=e.height;switch(t){case"inside":s=e.x+u/2-r/2,l=e.y+h/2-o/2;break;case"top":s=e.x+u/2-r/2,l=e.y-o-a;break;case"bottom":s=e.x+u/2-r/2,l=e.y+h+a;break;case"left":s=e.x-r-a,l=e.y+h/2-o/2;break;case"right":s=e.x+u+a,l=e.y+h/2-o/2}return[s,l]}(e,d,h,t.get("borderWidth")):function(t,e,n,i,r,o,a){var n=n.getSize(),s=n[0],n=n[1];null!=o&&(i":"gt",">=":"gte","=":"eq","!=":"ne","<>":"ne"},s2=(l2.prototype.evaluate=function(t){var e=typeof t;return H(e)?this._condVal.test(t):!!W(e)&&this._condVal.test(t+"")},l2);function l2(t){null==(this._condVal=H(t)?new RegExp(t):_t(t)?t:null)&&f("")}h2.prototype.evaluate=function(){return this.value};var u2=h2;function h2(){}p2.prototype.evaluate=function(){for(var t=this.children,e=0;e - + @endhtmlonly From dc515f8c71b1eb4e98b246719bc8cd96b957554c Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Mon, 1 Dec 2025 13:08:14 +1100 Subject: [PATCH 6/6] Reduce load time of the web-site performance page --- src/site/test_echarts.html | 6 +++--- src/site/test_echarts.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/site/test_echarts.html b/src/site/test_echarts.html index 18557844c..2c5568047 100644 --- a/src/site/test_echarts.html +++ b/src/site/test_echarts.html @@ -4,9 +4,9 @@ -

Hello World!

-
- +

Test page for iterating through echarts format options

+
+