| /* |
| * 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. |
| */ |
| import SeriesModel from '../../model/Series'; |
| import createDimensions from '../../data/helper/createDimensions'; |
| import { getDimensionTypeByAxis } from '../../data/helper/dimensionHelper'; |
| import List from '../../data/List'; |
| import * as zrUtil from 'zrender/src/core/util'; |
| import { groupData } from '../../util/model'; |
| import { encodeHTML } from '../../util/format'; |
| var DATA_NAME_INDEX = 2; |
| var ThemeRiverSeries = SeriesModel.extend({ |
| type: 'series.themeRiver', |
| dependencies: ['singleAxis'], |
| |
| /** |
| * @readOnly |
| * @type {module:zrender/core/util#HashMap} |
| */ |
| nameMap: null, |
| |
| /** |
| * @override |
| */ |
| init: function (option) { |
| // eslint-disable-next-line |
| ThemeRiverSeries.superApply(this, 'init', arguments); // Put this function here is for the sake of consistency of code style. |
| // Enable legend selection for each data item |
| // Use a function instead of direct access because data reference may changed |
| |
| this.legendDataProvider = function () { |
| return this.getRawData(); |
| }; |
| }, |
| |
| /** |
| * If there is no value of a certain point in the time for some event,set it value to 0. |
| * |
| * @param {Array} data initial data in the option |
| * @return {Array} |
| */ |
| fixData: function (data) { |
| var rawDataLength = data.length; // grouped data by name |
| |
| var groupResult = groupData(data, function (item) { |
| return item[2]; |
| }); |
| var layData = []; |
| groupResult.buckets.each(function (items, key) { |
| layData.push({ |
| name: key, |
| dataList: items |
| }); |
| }); |
| var layerNum = layData.length; |
| var largestLayer = -1; |
| var index = -1; |
| |
| for (var i = 0; i < layerNum; ++i) { |
| var len = layData[i].dataList.length; |
| |
| if (len > largestLayer) { |
| largestLayer = len; |
| index = i; |
| } |
| } |
| |
| for (var k = 0; k < layerNum; ++k) { |
| if (k === index) { |
| continue; |
| } |
| |
| var name = layData[k].name; |
| |
| for (var j = 0; j < largestLayer; ++j) { |
| var timeValue = layData[index].dataList[j][0]; |
| var length = layData[k].dataList.length; |
| var keyIndex = -1; |
| |
| for (var l = 0; l < length; ++l) { |
| var value = layData[k].dataList[l][0]; |
| |
| if (value === timeValue) { |
| keyIndex = l; |
| break; |
| } |
| } |
| |
| if (keyIndex === -1) { |
| data[rawDataLength] = []; |
| data[rawDataLength][0] = timeValue; |
| data[rawDataLength][1] = 0; |
| data[rawDataLength][2] = name; |
| rawDataLength++; |
| } |
| } |
| } |
| |
| return data; |
| }, |
| |
| /** |
| * @override |
| * @param {Object} option the initial option that user gived |
| * @param {module:echarts/model/Model} ecModel the model object for themeRiver option |
| * @return {module:echarts/data/List} |
| */ |
| getInitialData: function (option, ecModel) { |
| var singleAxisModel = ecModel.queryComponents({ |
| mainType: 'singleAxis', |
| index: this.get('singleAxisIndex'), |
| id: this.get('singleAxisId') |
| })[0]; |
| var axisType = singleAxisModel.get('type'); // filter the data item with the value of label is undefined |
| |
| var filterData = zrUtil.filter(option.data, function (dataItem) { |
| return dataItem[2] !== undefined; |
| }); // ??? TODO design a stage to transfer data for themeRiver and lines? |
| |
| var data = this.fixData(filterData || []); |
| var nameList = []; |
| var nameMap = this.nameMap = zrUtil.createHashMap(); |
| var count = 0; |
| |
| for (var i = 0; i < data.length; ++i) { |
| nameList.push(data[i][DATA_NAME_INDEX]); |
| |
| if (!nameMap.get(data[i][DATA_NAME_INDEX])) { |
| nameMap.set(data[i][DATA_NAME_INDEX], count); |
| count++; |
| } |
| } |
| |
| var dimensionsInfo = createDimensions(data, { |
| coordDimensions: ['single'], |
| dimensionsDefine: [{ |
| name: 'time', |
| type: getDimensionTypeByAxis(axisType) |
| }, { |
| name: 'value', |
| type: 'float' |
| }, { |
| name: 'name', |
| type: 'ordinal' |
| }], |
| encodeDefine: { |
| single: 0, |
| value: 1, |
| itemName: 2 |
| } |
| }); |
| var list = new List(dimensionsInfo, this); |
| list.initData(data); |
| return list; |
| }, |
| |
| /** |
| * The raw data is divided into multiple layers and each layer |
| * has same name. |
| * |
| * @return {Array.<Array.<number>>} |
| */ |
| getLayerSeries: function () { |
| var data = this.getData(); |
| var lenCount = data.count(); |
| var indexArr = []; |
| |
| for (var i = 0; i < lenCount; ++i) { |
| indexArr[i] = i; |
| } |
| |
| var timeDim = data.mapDimension('single'); // data group by name |
| |
| var groupResult = groupData(indexArr, function (index) { |
| return data.get('name', index); |
| }); |
| var layerSeries = []; |
| groupResult.buckets.each(function (items, key) { |
| items.sort(function (index1, index2) { |
| return data.get(timeDim, index1) - data.get(timeDim, index2); |
| }); |
| layerSeries.push({ |
| name: key, |
| indices: items |
| }); |
| }); |
| return layerSeries; |
| }, |
| |
| /** |
| * Get data indices for show tooltip content |
| * @param {Array.<string>|string} dim single coordinate dimension |
| * @param {number} value axis value |
| * @param {module:echarts/coord/single/SingleAxis} baseAxis single Axis used |
| * the themeRiver. |
| * @return {Object} {dataIndices, nestestValue} |
| */ |
| getAxisTooltipData: function (dim, value, baseAxis) { |
| if (!zrUtil.isArray(dim)) { |
| dim = dim ? [dim] : []; |
| } |
| |
| var data = this.getData(); |
| var layerSeries = this.getLayerSeries(); |
| var indices = []; |
| var layerNum = layerSeries.length; |
| var nestestValue; |
| |
| for (var i = 0; i < layerNum; ++i) { |
| var minDist = Number.MAX_VALUE; |
| var nearestIdx = -1; |
| var pointNum = layerSeries[i].indices.length; |
| |
| for (var j = 0; j < pointNum; ++j) { |
| var theValue = data.get(dim[0], layerSeries[i].indices[j]); |
| var dist = Math.abs(theValue - value); |
| |
| if (dist <= minDist) { |
| nestestValue = theValue; |
| minDist = dist; |
| nearestIdx = layerSeries[i].indices[j]; |
| } |
| } |
| |
| indices.push(nearestIdx); |
| } |
| |
| return { |
| dataIndices: indices, |
| nestestValue: nestestValue |
| }; |
| }, |
| |
| /** |
| * @override |
| * @param {number} dataIndex index of data |
| */ |
| formatTooltip: function (dataIndex) { |
| var data = this.getData(); |
| var htmlName = data.getName(dataIndex); |
| var htmlValue = data.get(data.mapDimension('value'), dataIndex); |
| |
| if (isNaN(htmlValue) || htmlValue == null) { |
| htmlValue = '-'; |
| } |
| |
| return encodeHTML(htmlName + ' : ' + htmlValue); |
| }, |
| defaultOption: { |
| zlevel: 0, |
| z: 2, |
| coordinateSystem: 'singleAxis', |
| // gap in axis's orthogonal orientation |
| boundaryGap: ['10%', '10%'], |
| // legendHoverLink: true, |
| singleAxisIndex: 0, |
| animationEasing: 'linear', |
| label: { |
| margin: 4, |
| show: true, |
| position: 'left', |
| color: '#000', |
| fontSize: 11 |
| }, |
| emphasis: { |
| label: { |
| show: true |
| } |
| } |
| } |
| }); |
| export default ThemeRiverSeries; |