diff --git a/src/component/toolbox/feature/DataView.ts b/src/component/toolbox/feature/DataView.ts index 300417a7b3..b378236b54 100644 --- a/src/component/toolbox/feature/DataView.ts +++ b/src/component/toolbox/feature/DataView.ts @@ -61,6 +61,27 @@ interface SeriesGroup { valueAxis: Axis } +function addCategory(categories: string[], category: unknown): void { + if (category == null) { + return; + } + const categoryName = category + ''; + zrUtil.indexOf(categories, categoryName) < 0 && categories.push(categoryName); +} + +function getCategoryNameByValue(categories: string[], categoryValue: unknown): string { + if (categoryValue == null) { + return; + } + if (typeof categoryValue === 'number') { + const category = categories[categoryValue]; + if (category != null) { + return category; + } + } + return categoryValue + ''; +} + /** * Group series into two types * 1. on category axis, like line, bar @@ -116,17 +137,47 @@ function assembleSeriesWithCategoryAxis(groups: Dictionary): string zrUtil.each(groups, function (group, key) { const categoryAxis = group.categoryAxis; const valueAxis = group.valueAxis; + const categoryAxisDim = categoryAxis.dim; const valueAxisDim = valueAxis.dim; + const categories: string[] = []; const headers = [' '].concat(zrUtil.map(group.series, function (series) { return series.name; })); + // @ts-ignore TODO Polar - const columns = [categoryAxis.model.getCategories()]; + zrUtil.each(categoryAxis.model.getCategories(), function (category) { + addCategory(categories, category); + }); + zrUtil.each(group.series, function (series) { const rawData = series.getRawData(); - columns.push(series.getRawData().mapArray(rawData.mapDimension(valueAxisDim), function (val) { - return val; + for (let i = 0, len = rawData.count(); i < len; i++) { + addCategory(categories, rawData.getName(i)); + } + }); + + const columns: unknown[][] = [categories]; + zrUtil.each(group.series, function (series) { + const rawData = series.getRawData(); + const valueDim = rawData.mapDimension(valueAxisDim); + const categoryDim = rawData.mapDimension(categoryAxisDim); + const valueByCategory: Dictionary = {}; + for (let i = 0, len = rawData.count(); i < len; i++) { + const name = rawData.getName(i); + if (name) { + valueByCategory[name] = rawData.get(valueDim, i); + } + else { + const categoryName = getCategoryNameByValue(categories, rawData.get(categoryDim, i)); + if (categoryName != null && valueByCategory[categoryName] == null) { + valueByCategory[categoryName] = rawData.get(valueDim, i); + } + } + } + columns.push(zrUtil.map(categories, function (category) { + const value = valueByCategory[category]; + return value == null || isNaN(value as number) ? '' : value; })); }); // Assemble table content @@ -164,7 +215,7 @@ function assembleOtherSeries(series: SeriesModel[]) { }).join('\n\n' + BLOCK_SPLITER + '\n\n'); } -function getContentFromModel(ecModel: GlobalModel) { +export function getContentFromModel(ecModel: GlobalModel) { const result = groupSeries(ecModel); @@ -202,7 +253,7 @@ const itemSplitRegex = new RegExp('[' + ITEM_SPLITER + ']+', 'g'); */ function parseTSVContents(tsv: string) { const tsvLines = tsv.split(/\n+/g); - const headers = trim(tsvLines.shift()).split(itemSplitRegex); + const headers = trim(tsvLines.shift()).split(ITEM_SPLITER); const categories: string[] = []; const series: {name: string, data: string[]}[] = zrUtil.map(headers, function (header) { @@ -212,10 +263,12 @@ function parseTSVContents(tsv: string) { }; }); for (let i = 0; i < tsvLines.length; i++) { - const items = trim(tsvLines[i]).split(itemSplitRegex); + const items = trim(tsvLines[i]).split(ITEM_SPLITER); categories.push(items.shift()); for (let j = 0; j < items.length; j++) { - series[j] && (series[j].data[i] = items[j]); + if (series[j] && items[j] !== '') { + series[j].data[i] = items[j]; + } } } return { diff --git a/test/ut/spec/component/toolbox/DataView.test.ts b/test/ut/spec/component/toolbox/DataView.test.ts new file mode 100644 index 0000000000..55a325a72a --- /dev/null +++ b/test/ut/spec/component/toolbox/DataView.test.ts @@ -0,0 +1,77 @@ +/* +* 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 { getContentFromModel } from '../../../../../src/component/toolbox/feature/DataView'; +import { createChart, getECModel } from '../../../core/utHelper'; +import { EChartsType } from '../../../../../src/echarts'; + + +describe('toolbox/DataView', function () { + + let chart: EChartsType; + + beforeEach(function () { + chart = createChart(); + }); + + afterEach(function () { + chart.dispose(); + }); + + it('aligns category-axis series values by data item name', function () { + chart.setOption({ + xAxis: { + type: 'category', + data: ['cat-1', 'cat-2', 'col-1', 'col-2', 'col-3', 'col-4'] + }, + yAxis: {}, + series: [ + { + type: 'line', + name: 'cats', + data: [ + { name: 'cat-1', value: 1 }, + { name: 'cat-2', value: 2 } + ] + }, + { + type: 'line', + name: 'cols', + data: [ + { name: 'col-1', value: 3 }, + { name: 'col-2', value: 4 }, + { name: 'col-3', value: 5 }, + { name: 'col-4', value: 6 } + ] + } + ] + }); + + expect(getContentFromModel(getECModel(chart)).value).toEqual([ + ' \tcats\tcols', + 'cat-1\t1\t', + 'cat-2\t2\t', + 'col-1\t\t3', + 'col-2\t\t4', + 'col-3\t\t5', + 'col-4\t\t6' + ].join('\n')); + }); + +});