柱状图用百分比实现非线性结构

This commit is contained in:
hongchao 2025-12-31 16:48:51 +08:00
parent 94c6812662
commit 8de15e50dd
1 changed files with 130 additions and 223 deletions

View File

@ -137,7 +137,7 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 柱状图 --> <!-- 柱状图 -->
<div v-else ref="barRef" style="width: 100%; height: calc(100vh - 580px); margin-top: 20px"></div> <div v-else ref="barRef" style="width: 100%; height: calc(100vh - 480px); margin-top: 20px"></div>
</el-card> </el-card>
</div> </div>
</div> </div>
@ -331,261 +331,168 @@ export default {
chart.setOption(option) chart.setOption(option)
}, },
initBarChart() { initBarChart() {
const barDom = this.$refs.barRef const barDom = this.$refs.barRef;
const barChart = echarts.init(barDom) const barChart = echarts.init(barDom);
const companyNames = this.tableList.map((item) => item.companyName) const companyNames = this.tableList.map((item) => item.companyName);
const equipTotals = this.tableList.map((item) => item.maNum) const equipTotals = this.tableList.map((item) => item.maNum);
const toolTotals = this.tableList.map((item) => item.toolNum) const toolTotals = this.tableList.map((item) => item.toolNum);
// y // -
const yAxisTicks = ['0', '200', '500', '1000', '10000', '100000', '200000+'] const yAxisTicks = ['0', '200', '500', '1000', '10000', '100000', '200000+'];
const yAxisValues = [0, 200, 500, 1000, 10000, 100000, 200000];
// //
const yAxisValues = [0, 200, 500, 1000, 10000, 100000, 200000] const mapToStepHeight = (value) => {
let i = 0;
while (i < yAxisValues.length - 1 && value > yAxisValues[i + 1]) i++;
const rangeStart = yAxisValues[i];
const rangeEnd = yAxisValues[i + 1] || yAxisValues[i];
const ratio = (value - rangeStart) / (rangeEnd - rangeStart || 1);
return i + ratio;
};
const mappedEquipTotals = equipTotals.map(mapToStepHeight);
const mappedToolTotals = toolTotals.map(mapToStepHeight);
// y // ---------------------- ----------------------
const mapDataToYAxis = (value) => { const initShowEquip = equipTotals.some(v => v > 0);
for (let i = 0; i < yAxisValues.length; i++) { const initShowTool = toolTotals.some(v => v > 0);
if (value <= yAxisValues[i]) { const initShowBoth = initShowEquip && initShowTool;
return i
}
}
return yAxisValues.length - 1 //
}
// barChart.setOption({
const mappedEquipTotals = equipTotals.map(mapDataToYAxis)
const mappedToolTotals = toolTotals.map(mapDataToYAxis)
//
const showBothSeries = equipTotals.some(val => val > 0) && toolTotals.some(val => val > 0)
// y
let yAxisConfig
if (showBothSeries) {
// 使categoryy
yAxisConfig = {
type: 'category',
data: yAxisTicks,
name: '数量(个)',
nameTextStyle: { fontSize: 14 },
axisTick: {
show: true,
alignWithLabel: true,
length: 4
},
axisLabel: {
fontSize: 12,
margin: 8 //
},
//
offset: 0,
//
boundaryGap: false,
// 线
splitLine: {
show: true,
lineStyle: {
type: 'dashed',
color: '#e0e0e0'
}
}
}
} else {
// 使valuey
yAxisConfig = {
type: 'value',
name: '数量(个)',
nameTextStyle: { fontSize: 14 }
}
}
// series
const series = []
//
if (equipTotals.some(val => val > 0)) {
series.push({
name: '装备总数',
type: 'bar',
barWidth: 35,
barGap: '0%', //
barCategoryGap: '0%', //
itemStyle: {
color: '#5470C6',
borderRadius: [4, 4, 0, 0],
},
data: showBothSeries ? mappedEquipTotals : equipTotals,
coordinateSystem: 'cartesian2d',
xAxisIndex: 0,
yAxisIndex: 0,
})
}
//
if (toolTotals.some(val => val > 0)) {
series.push({
name: '工具总数',
type: 'bar',
barWidth: 35,
barGap: '0%',
barCategoryGap: '0%',
itemStyle: {
color: '#91CC75',
borderRadius: [4, 4, 0, 0],
},
data: showBothSeries ? mappedToolTotals : toolTotals,
coordinateSystem: 'cartesian2d',
xAxisIndex: 0,
yAxisIndex: 0,
})
}
const option = {
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
formatter: function (params) { formatter: (params) => {
// tooltip let res = `${params[0].name}<br/>`;
let result = params[0].name + '<br/>' params.forEach(p => {
params.forEach(param => { const val = p.seriesName === '装备总数'
// ? equipTotals[p.dataIndex]
const originalValue = param.seriesName === '装备总数' : toolTotals[p.dataIndex];
? equipTotals[param.dataIndex] res += `${p.seriesName}: ${val}个<br/>`;
: toolTotals[param.dataIndex] });
result += `${param.seriesName}: ${originalValue}个<br/>` return res;
})
return result
} }
}, },
//
legend: { legend: {
top: 0, top: 0,
right: 20, right: 20,
data: series.map(s => s.name), // data: ['装备总数', '工具总数'],
selected: {
'装备总数': initShowEquip,
'工具总数': initShowTool
}
}, },
grid: { left: '3%', right: '3%', bottom: '3%', top: '15%', containLabel: true },
grid: {
left: '3%',
right: '3%',
bottom: '3%',
top: '15%',
containLabel: true,
},
xAxis: { xAxis: {
type: 'category', type: 'category',
data: companyNames, data: companyNames,
axisLabel: { axisLabel: {
fontSize: 13, fontSize: 13, interval: 0, lineHeight: 16,
interval: 0, // formatter: (name) => {
lineHeight: 16, if (name.length <= 4) return name;
formatter: function (name) { let res = '';
const maxLen = 3 // 6 for (let i = 0; i < Math.ceil(name.length / 4); i++) {
if (name.length <= maxLen) return name res += name.substring(i * 4, (i + 1) * 4) + '\n';
const rows = Math.ceil(name.length / maxLen)
let res = ''
for (let i = 0; i < rows; i++) {
res += name.substring(i * maxLen, (i + 1) * maxLen) + '\n'
} }
return res return res;
},
},
},
yAxis: yAxisConfig, // 使y
series: series, // 使
} }
}
barChart.setOption(option) },
yAxis: initShowBoth
// ? { // -
barChart.on('legendselectchanged', (params) => { type: 'value',
//
const selectedSeries = Object.keys(params.selected).filter(key => params.selected[key]);
//
const showBothSeries = selectedSeries.length > 1;
// y
let newYAxisConfig;
if (showBothSeries) {
// 使categoryy
newYAxisConfig = {
type: 'category',
data: yAxisTicks,
name: '数量(个)', name: '数量(个)',
nameTextStyle: { fontSize: 14 }, nameTextStyle: { fontSize: 14 },
min: 0, max: 6, interval: 1,
axisTick: { axisLabel: { fontSize:12, margin:8, formatter: idx => yAxisTicks[Math.floor(idx)] },
show: true, splitLine: { lineStyle: { type: 'dashed', color: '#e0e0e0' } }
alignWithLabel: true,
length: 4
},
axisLabel: {
fontSize: 12,
margin: 8 //
},
//
offset: 0,
//
boundaryGap: false,
// 线
splitLine: {
show: true,
lineStyle: {
type: 'dashed',
color: '#e0e0e0'
} }
} : { // -线
};
} else {
// 使valuey
newYAxisConfig = {
type: 'value', type: 'value',
name: '数量(个)', name: '数量(个)',
nameTextStyle: { fontSize: 14 } nameTextStyle: { fontSize: 14 }
},
series: [
...(initShowEquip ? [{
name: '装备总数', type: 'bar', barWidth:35,
barGap:'0%', barCategoryGap:'0%',
itemStyle: { color:'#5470C6', borderRadius:[4,4,0,0] },
data: initShowBoth ? mappedEquipTotals : equipTotals
}] : []),
...(initShowTool ? [{
name: '工具总数', type: 'bar', barWidth:35,
barGap:'0%', barCategoryGap:'0%',
itemStyle: { color:'#91CC75', borderRadius:[4,4,0,0] },
data: initShowBoth ? mappedToolTotals : toolTotals
}] : [])
]
}, true);
// ---------------------- Y ----------------------
barChart.on('legendselectchanged', (params) => {
//
const selectedSeries = Object.keys(params.selected).filter(key => params.selected[key]);
//
const showBothSeries = selectedSeries.length > 1;
// 线
let newYAxisConfig;
if (showBothSeries) {
//
newYAxisConfig = {
type: 'value',
name: '数量(个)',
nameTextStyle: { fontSize: 14 },
min: 0, //
max: 6, //
interval: 1, //
axisTick: { show: true, alignWithLabel: true, length: 4 },
axisLabel: { fontSize: 12, margin:8, formatter: idx => yAxisTicks[Math.floor(idx)] },
splitLine: { lineStyle: { type: 'dashed', color: '#e0e0e0' } }
};
} else {
// 线
newYAxisConfig = {
type: 'value',
name: '数量(个)',
nameTextStyle: { fontSize: 14 },
min: undefined, //
max: undefined, //
interval: undefined, //
axisLabel: { //
fontSize: 12,
margin: 8,
formatter: undefined
},
splitLine: { lineStyle: { type: 'solid', color: '#e0e0e0' } }
}; };
} }
// y // Y replaceMerge: true
barChart.setOption({ barChart.setOption({ yAxis: newYAxisConfig }, { replaceMerge: ['yAxis'], silent: true });
yAxis: newYAxisConfig
});
// //
const newSeries = []; const newSeries = [];
//
if (params.selected['装备总数']) { if (params.selected['装备总数']) {
newSeries.push({ newSeries.push({
name: '装备总数', name: '装备总数',
type: 'bar', barWidth:35,
barGap:'0%', barCategoryGap:'0%',
itemStyle: { color:'#5470C6', borderRadius:[4,4,0,0] },
data: showBothSeries ? mappedEquipTotals : equipTotals data: showBothSeries ? mappedEquipTotals : equipTotals
}); });
} }
//
if (params.selected['工具总数']) { if (params.selected['工具总数']) {
newSeries.push({ newSeries.push({
name: '工具总数', name: '工具总数',
type: 'bar', barWidth:35,
barGap:'0%', barCategoryGap:'0%',
itemStyle: { color:'#91CC75', borderRadius:[4,4,0,0] },
data: showBothSeries ? mappedToolTotals : toolTotals data: showBothSeries ? mappedToolTotals : toolTotals
}); });
} }
barChart.setOption({ series: newSeries });
barChart.setOption({
series: newSeries
});
}); });
} }
}, },