/* * 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 zrUtil = require("zrender/lib/core/util"); /* * 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. */ /** * Link lists and struct (graph or tree) */ var each = zrUtil.each; var DATAS = '\0__link_datas'; var MAIN_DATA = '\0__link_mainData'; // Caution: // In most case, either list or its shallow clones (see list.cloneShallow) // is active in echarts process. So considering heap memory consumption, // we do not clone tree or graph, but share them among list and its shallow clones. // But in some rare case, we have to keep old list (like do animation in chart). So // please take care that both the old list and the new list share the same tree/graph. /** * @param {Object} opt * @param {module:echarts/data/List} opt.mainData * @param {Object} [opt.struct] For example, instance of Graph or Tree. * @param {string} [opt.structAttr] designation: list[structAttr] = struct; * @param {Object} [opt.datas] {dataType: data}, * like: {node: nodeList, edge: edgeList}. * Should contain mainData. * @param {Object} [opt.datasAttr] {dataType: attr}, * designation: struct[datasAttr[dataType]] = list; */ function linkList(opt) { var mainData = opt.mainData; var datas = opt.datas; if (!datas) { datas = { main: mainData }; opt.datasAttr = { main: 'data' }; } opt.datas = opt.mainData = null; linkAll(mainData, datas, opt); // Porxy data original methods. each(datas, function (data) { each(mainData.TRANSFERABLE_METHODS, function (methodName) { data.wrapMethod(methodName, zrUtil.curry(transferInjection, opt)); }); }); // Beyond transfer, additional features should be added to `cloneShallow`. mainData.wrapMethod('cloneShallow', zrUtil.curry(cloneShallowInjection, opt)); // Only mainData trigger change, because struct.update may trigger // another changable methods, which may bring about dead lock. each(mainData.CHANGABLE_METHODS, function (methodName) { mainData.wrapMethod(methodName, zrUtil.curry(changeInjection, opt)); }); // Make sure datas contains mainData. zrUtil.assert(datas[mainData.dataType] === mainData); } function transferInjection(opt, res) { if (isMainData(this)) { // Transfer datas to new main data. var datas = zrUtil.extend({}, this[DATAS]); datas[this.dataType] = res; linkAll(res, datas, opt); } else { // Modify the reference in main data to point newData. linkSingle(res, this.dataType, this[MAIN_DATA], opt); } return res; } function changeInjection(opt, res) { opt.struct && opt.struct.update(this); return res; } function cloneShallowInjection(opt, res) { // cloneShallow, which brings about some fragilities, may be inappropriate // to be exposed as an API. So for implementation simplicity we can make // the restriction that cloneShallow of not-mainData should not be invoked // outside, but only be invoked here. each(res[DATAS], function (data, dataType) { data !== res && linkSingle(data.cloneShallow(), dataType, res, opt); }); return res; } /** * Supplement method to List. * * @public * @param {string} [dataType] If not specified, return mainData. * @return {module:echarts/data/List} */ function getLinkedData(dataType) { var mainData = this[MAIN_DATA]; return dataType == null || mainData == null ? mainData : mainData[DATAS][dataType]; } function isMainData(data) { return data[MAIN_DATA] === data; } function linkAll(mainData, datas, opt) { mainData[DATAS] = {}; each(datas, function (data, dataType) { linkSingle(data, dataType, mainData, opt); }); } function linkSingle(data, dataType, mainData, opt) { mainData[DATAS][dataType] = data; data[MAIN_DATA] = mainData; data.dataType = dataType; if (opt.struct) { data[opt.structAttr] = opt.struct; opt.struct[opt.datasAttr[dataType]] = data; } // Supplement method. data.getLinkedData = getLinkedData; } var _default = linkList; module.exports = _default;