console
const result ={
"chart": {
"id": 127,
"view_id": 88,
"title": "分区柱形表",
"condition": "{\"type\":\"rulesRelation\",\"relation\":\"AND\",\"rules\":[{\"type\":\"sqlCondition\",\"relation\":\"\",\"field\":\"t1.\\\"buyout\\\"\",\"cname\":\"\",\"function\":[\"greater\"],\"params\":[{\"type\":\"float\",\"value\":1}]},{\"type\":\"sqlCondition\",\"relation\":\"\",\"field\":\"t1.\\\"ch_terminal\\\"\",\"cname\":\"\",\"function\":[\"isSet\"],\"params\":[]},{\"type\":\"sqlCondition\",\"relation\":\"\",\"field\":\"t1.\\\"order_create_time\\\"\",\"cname\":\"\",\"function\":[\"isSet\"],\"params\":[]}],\"field\":\"\",\"cname\":\"\",\"function\":null,\"params\":null}",
"chart_type": 3,
"createdAt": 1717147623,
"updatedAt": 1717153567,
"createBy": 0,
"updateBy": 0
},
"col_dimensions": [],
"data": [
{
"f0": "APP",
"f1": "2023-09-16",
"f2": 11124
},
{
"f0": "APP",
"f1": "2023-09-18",
"f2": 55620
},
{
"f0": "APP",
"f1": "2023-09-22",
"f2": 11124
},
{
"f0": "APP",
"f1": "2023-11-10",
"f2": 35284
},
{
"f0": "APP",
"f1": "2023-11-13",
"f2": 15804
},
{
"f0": "APP",
"f1": "2023-11-14",
"f2": 39429
},
{
"f0": "APP",
"f1": "2023-11-15",
"f2": 11488
},
{
"f0": "APP",
"f1": "2023-12-01",
"f2": 6
},
{
"f0": "APP",
"f1": "2023-12-02",
"f2": 1756
},
{
"f0": "APP",
"f1": "2023-12-04",
"f2": 29613.6
},
{
"f0": "APP",
"f1": "2023-12-05",
"f2": 30973
},
{
"f0": "APP",
"f1": "2023-12-06",
"f2": 11941
},
{
"f0": "字节跳动",
"f1": "2023-09-07",
"f2": 5
},
{
"f0": "字节跳动",
"f1": "2023-09-21",
"f2": 66744
},
{
"f0": "字节跳动",
"f1": "2023-09-22",
"f2": 11124
},
{
"f0": "字节跳动",
"f1": "2023-10-17",
"f2": 2
},
{
"f0": "字节跳动",
"f1": "2023-10-18",
"f2": 4
},
{
"f0": "字节跳动",
"f1": "2023-11-16",
"f2": 17560
},
{
"f0": "字节跳动",
"f1": "2023-11-17",
"f2": 61742
},
{
"f0": "字节跳动",
"f1": "2023-11-18",
"f2": 1756
},
{
"f0": "字节跳动",
"f1": "2023-11-20",
"f2": 3512
},
{
"f0": "字节跳动",
"f1": "2023-12-01",
"f2": 1756
},
{
"f0": "字节跳动",
"f1": "2023-12-02",
"f2": 28096
},
{
"f0": "字节跳动",
"f1": "2023-12-08",
"f2": 1756
},
{
"f0": "字节跳动",
"f1": "2023-12-11",
"f2": 3223.71
},
{
"f0": "字节跳动",
"f1": "2023-12-15",
"f2": 1000
},
{
"f0": "字节跳动",
"f1": "2023-12-25",
"f2": 4
},
{
"f0": "字节跳动",
"f1": "2024-01-13",
"f2": 8
},
{
"f0": "微信",
"f1": "2023-12-18",
"f2": 3000
},
{
"f0": "支付宝",
"f1": "2023-09-04",
"f2": 5
},
{
"f0": "支付宝",
"f1": "2023-09-05",
"f2": 3
},
{
"f0": "支付宝",
"f1": "2023-09-07",
"f2": 2
},
{
"f0": "支付宝",
"f1": "2023-09-08",
"f2": 3
},
{
"f0": "支付宝",
"f1": "2023-09-13",
"f2": 48
},
{
"f0": "支付宝",
"f1": "2023-09-15",
"f2": 5400
},
{
"f0": "支付宝",
"f1": "2023-09-18",
"f2": 66746
},
{
"f0": "支付宝",
"f1": "2023-09-19",
"f2": 18
},
{
"f0": "支付宝",
"f1": "2023-09-21",
"f2": 77868
},
{
"f0": "支付宝",
"f1": "2023-09-26",
"f2": 2
},
{
"f0": "支付宝",
"f1": "2023-09-27",
"f2": 17
},
{
"f0": "支付宝",
"f1": "2023-10-08",
"f2": 11
},
{
"f0": "支付宝",
"f1": "2023-10-09",
"f2": 55
},
{
"f0": "支付宝",
"f1": "2023-10-12",
"f2": 3
},
{
"f0": "支付宝",
"f1": "2023-10-17",
"f2": 5.65
},
{
"f0": "支付宝",
"f1": "2023-10-18",
"f2": 12
},
{
"f0": "支付宝",
"f1": "2023-10-19",
"f2": 14904
},
{
"f0": "支付宝",
"f1": "2023-10-20",
"f2": 5
},
{
"f0": "支付宝",
"f1": "2023-10-23",
"f2": 39
},
{
"f0": "支付宝",
"f1": "2023-10-24",
"f2": 3
},
{
"f0": "支付宝",
"f1": "2023-10-25",
"f2": 5256
},
{
"f0": "支付宝",
"f1": "2023-10-26",
"f2": 21
},
{
"f0": "支付宝",
"f1": "2023-10-27",
"f2": 5090.73
},
{
"f0": "支付宝",
"f1": "2023-10-30",
"f2": 15
},
{
"f0": "支付宝",
"f1": "2023-10-31",
"f2": 45
},
{
"f0": "支付宝",
"f1": "2023-11-01",
"f2": 1331
},
{
"f0": "支付宝",
"f1": "2023-11-03",
"f2": 40
},
{
"f0": "支付宝",
"f1": "2023-11-06",
"f2": 5654
},
{
"f0": "支付宝",
"f1": "2023-11-09",
"f2": 28328
},
{
"f0": "支付宝",
"f1": "2023-11-10",
"f2": 22020
},
{
"f0": "支付宝",
"f1": "2023-11-13",
"f2": 14078
},
{
"f0": "支付宝",
"f1": "2023-11-14",
"f2": 10928
},
{
"f0": "支付宝",
"f1": "2023-11-15",
"f2": 40488
},
{
"f0": "支付宝",
"f1": "2023-11-16",
"f2": 17383
},
{
"f0": "支付宝",
"f1": "2023-11-17",
"f2": 3474
},
{
"f0": "支付宝",
"f1": "2023-11-18",
"f2": 22828
},
{
"f0": "支付宝",
"f1": "2023-11-20",
"f2": 29852
},
{
"f0": "支付宝",
"f1": "2023-11-21",
"f2": 27.5
},
{
"f0": "支付宝",
"f1": "2023-11-22",
"f2": 600
},
{
"f0": "支付宝",
"f1": "2023-11-23",
"f2": 1784
},
{
"f0": "支付宝",
"f1": "2023-11-27",
"f2": 3780
},
{
"f0": "支付宝",
"f1": "2023-11-29",
"f2": 3000
},
{
"f0": "支付宝",
"f1": "2023-11-30",
"f2": 14010
},
{
"f0": "支付宝",
"f1": "2023-12-01",
"f2": 41493.6
},
{
"f0": "支付宝",
"f1": "2023-12-02",
"f2": 43264.2
},
{
"f0": "支付宝",
"f1": "2023-12-04",
"f2": 20102
},
{
"f0": "支付宝",
"f1": "2023-12-05",
"f2": 13236
},
{
"f0": "支付宝",
"f1": "2023-12-06",
"f2": 23427
},
{
"f0": "支付宝",
"f1": "2023-12-07",
"f2": 54579.73
},
{
"f0": "支付宝",
"f1": "2023-12-08",
"f2": 6512
},
{
"f0": "支付宝",
"f1": "2023-12-11",
"f2": 20236
},
{
"f0": "支付宝",
"f1": "2023-12-12",
"f2": 15604
},
{
"f0": "支付宝",
"f1": "2023-12-13",
"f2": 2006
},
{
"f0": "支付宝",
"f1": "2023-12-14",
"f2": 29393.97
},
{
"f0": "支付宝",
"f1": "2023-12-15",
"f2": 10013
},
{
"f0": "支付宝",
"f1": "2023-12-16",
"f2": 5009.2
},
{
"f0": "支付宝",
"f1": "2023-12-18",
"f2": 31567
},
{
"f0": "支付宝",
"f1": "2023-12-19",
"f2": 21148
},
{
"f0": "支付宝",
"f1": "2023-12-20",
"f2": 227
},
{
"f0": "支付宝",
"f1": "2023-12-21",
"f2": 4502
},
{
"f0": "支付宝",
"f1": "2023-12-22",
"f2": 2026
},
{
"f0": "支付宝",
"f1": "2023-12-23",
"f2": 35
},
{
"f0": "支付宝",
"f1": "2023-12-25",
"f2": 15
},
{
"f0": "支付宝",
"f1": "2023-12-27",
"f2": 2
},
{
"f0": "支付宝",
"f1": "2023-12-28",
"f2": 11366
},
{
"f0": "支付宝",
"f1": "2024-01-08",
"f2": 2000
},
{
"f0": "支付宝",
"f1": "2024-01-09",
"f2": 36
},
{
"f0": "支付宝",
"f1": "2024-01-10",
"f2": 10
},
{
"f0": "支付宝",
"f1": "2024-01-13",
"f2": 43
},
{
"f0": "支付宝",
"f1": "2024-01-15",
"f2": 1000
},
{
"f0": "支付宝",
"f1": "2024-01-16",
"f2": 15
},
{
"f0": "支付宝",
"f1": "2024-01-17",
"f2": 5
},
{
"f0": "码商",
"f1": "2023-09-20",
"f2": 8
},
{
"f0": "码商",
"f1": "2023-09-21",
"f2": 6
},
{
"f0": "码商",
"f1": "2023-09-22",
"f2": 2
},
{
"f0": "码商",
"f1": "2023-09-26",
"f2": 6
},
{
"f0": "码商",
"f1": "2023-09-27",
"f2": 10
},
{
"f0": "码商",
"f1": "2023-12-04",
"f2": 320
},
{
"f0": "码商",
"f1": "2023-12-07",
"f2": 6200
},
{
"f0": "系统",
"f1": "2023-12-11",
"f2": 1000
},
{
"f0": "系统",
"f1": "2023-12-18",
"f2": 12000
},
{
"f0": "系统",
"f1": "2023-12-19",
"f2": 4000
}
],
"indicators": [
{
"id": 523,
"chart_id": 127,
"calcul_logic": 1,
"field": "t1.\"buyout\"",
"condition": "{\"function\":[\"greater\"],\"params\":[{\"type\":\"float\",\"value\":1}]}",
"createdAt": 1717153566,
"updatedAt": 1717153566,
"createBy": 0,
"updateBy": 0,
"index_key": "f2",
"fieldType": 2,
"fieldTypeName": "float"
}
],
"meta": [
{
"field": "f0",
"name": "一级渠道"
},
{
"field": "f1",
"name": "下单时间"
},
{
"field": "f2",
"name": "买断价"
}
],
"row_dimensions": [
{
"id": 532,
"chart_id": 127,
"dimension_type": 1,
"condition": "{\"function\":[\"isSet\"],\"params\":[]}",
"field": "t1.\"ch_terminal\"",
"createdAt": 1717153566,
"updatedAt": 1717153566,
"createBy": 0,
"updateBy": 0,
"index_key": "f0",
"fieldType": 3,
"fieldTypeName": "string"
},
{
"id": 533,
"chart_id": 127,
"dimension_type": 1,
"condition": "{\"function\":[\"isSet\"],\"params\":[]}",
"field": "t1.\"order_create_time\"",
"createdAt": 1717153566,
"updatedAt": 1717153566,
"createBy": 0,
"updateBy": 0,
"index_key": "f1",
"fieldType": 5,
"fieldTypeName": "time"
}
]
}
console.time('executionTime');
const groupedData = {};
const dimensionKeys = result.row_dimensions.map(item => item.index_key).slice(0, -1);
const rowDimensionLabels = Array.from({ length: result.row_dimensions.length - 1 }, () => []);
console.log('dimensionKeys:', dimensionKeys);
result.data.forEach(item => {
const key = dimensionKeys.map(key => item[key]).join('.');
if (!_.has(groupedData, key)) {
_.set(groupedData, key, []);
}
_.get(groupedData, key).push(item);
});
console.log('groupedData:', groupedData);
function flattenData(data) {
let result = [];
function recursiveFlatten(obj) {
if (Array.isArray(obj)) {
result = result.concat(obj);
} else if (typeof obj === 'object' && obj !== null) {
for (const key in obj) {
recursiveFlatten(obj[key]);
}
}
}
recursiveFlatten(data);
return result;
}
const flattenedData = flattenData(groupedData);
console.log('flattenedData:', flattenedData);
const lastDimensionKey = result.row_dimensions.slice(-1)[0].index_key;
flattenedData.forEach(item => {
dimensionKeys.forEach((key, index) => {
rowDimensionLabels[index].push(item[key]);
});
});
console.log('rowDimensionLabels:', rowDimensionLabels);
console.timeEnd('executionTime');
const chartHeight = (90 / result.indicators.length).toFixed(2);
const gridConfig = result.indicators.map((_, index) => ({
top: 200 * index,
height: 200
}));
console.log('gridConfig:', gridConfig);
const seriesConfig = result.indicators.map(({ index_key }, index) => {
const data = flattenedData.map(item => {
const template = result.meta.map(({ name, field }) => `${name}:${item[field]}`).join('<br>');
return {
value: item[index_key] || 0,
template
};
});
return {
type: 'bar',
xAxisIndex: index,
yAxisIndex: index,
data,
};
});
const yAxisConfig = result.indicators.map(({ index_key }, index) => ({
type: 'value',
gridIndex: index,
name: index_key,
nameLocation: 'middle'
}));
const xAxisData = flattenedData.map(item => item[lastDimensionKey]);
const xAxisConfig = result.indicators.map((_, index) => ({
type: 'category',
gridIndex: index,
axisLabel: {
show: index === result.indicators.length - 1,
rotate: -45,
color: 'unset'
},
axisTick: false,
data: xAxisData,
alignTicks: true,
axisLine: {
lineStyle: {
color: '#DADCE1'
}
}
}));
function getMiddleIndex(value, data) {
const indices = data.reduce((acc, item, idx) => {
if (item === value) acc.push(idx);
return acc;
}, []);
return indices.length > 0 ? indices[Math.floor(indices.length / 2)] : -1;
}
function findSameElementRange(arr, index) {
if (arr.length === 0 || index < 0 || index >= arr.length) {
return null;
}
let target = arr[index];
let left = index;
let right = index;
while (left > 0 && arr[left - 1] === target) {
left--;
}
while (right < arr.length - 1 && arr[right + 1] === target) {
right++;
}
return [left, right];
}
const container = document.getElementById('main');
container.style.height = (xAxisConfig.length + 1) * 200 + 'px';
const extraXAxisConfig = rowDimensionLabels.reverse().map((data, index) => {
const offset = (gridConfig.length - 1 || 1) * 200 + 100 + index * 30;
const axisTickLength = gridConfig.length * 200 + 100 + index * 20;
const labelTextMarginLeft = (container.clientWidth / 45).toFixed(0);
return {
type: 'category',
gridIndex: xAxisConfig.length - 1,
data,
offset: -offset,
axisLabel: {
show: true,
margin: 0,
interval: (index, value) => {
const [start, end] = findSameElementRange(data, index);
const length = end - start
if (length > 1) {
return index === start + Math.ceil(length / 2)
} else {
return true;
}
},
lineStyle: {
color: 'unset'
}
},
axisTick: {
interval: (index, value) => {
const [start, end] = findSameElementRange(data, index);
return index === start;
},
length: axisTickLength,
lineStyle: {
color: '#DADCE1'
}
},
axisLine: {
show: false
},
};
});
console.log('extraXAxisConfig:', extraXAxisConfig);
const chart = echarts.init(container, null, { renderer: 'svg' });
const xAxisIndex = yAxisConfig.reduce((pre, _, index) => [
...pre,
index + 2
], [0, 1])
const option = {
tooltip: {
trigger: 'item',
formatter: ({ data: { template } }) => template
},
grid: gridConfig,
xAxis: [...xAxisConfig, ...extraXAxisConfig],
yAxis: yAxisConfig,
series: seriesConfig,
dataZoom: [{
type: 'inside',
xAxisIndex,
}]
};
chart.setOption(option);
<div id="main" ></div>