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

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

@ -88,7 +88,7 @@
<ul class="scroll-list" ref="list">
<li v-for="(item, index) in eventList" :key="item.id" :class="{ odd: index % 2 === 1 }">
<div style="display: flex; align-items: center; justify-content: space-between">
<div style="width: 65%">
<div style="width: 65%">
<span>{{ index + 1 }}. </span>
<span>{{ item.deptAbbreviation }} </span>
<span>{{ item.applyUser }} </span>
@ -137,7 +137,7 @@
</el-table-column>
</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>
</div>
</div>
@ -331,261 +331,168 @@ export default {
chart.setOption(option)
},
initBarChart() {
const barDom = this.$refs.barRef
const barChart = echarts.init(barDom)
const companyNames = this.tableList.map((item) => item.companyName)
const equipTotals = this.tableList.map((item) => item.maNum)
const toolTotals = this.tableList.map((item) => item.toolNum)
// y
const yAxisTicks = ['0', '200', '500', '1000', '10000', '100000', '200000+']
const barDom = this.$refs.barRef;
const barChart = echarts.init(barDom);
const companyNames = this.tableList.map((item) => item.companyName);
const equipTotals = this.tableList.map((item) => item.maNum);
const toolTotals = this.tableList.map((item) => item.toolNum);
// -
const yAxisTicks = ['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);
// ---------------------- ----------------------
const initShowEquip = equipTotals.some(v => v > 0);
const initShowTool = toolTotals.some(v => v > 0);
const initShowBoth = initShowEquip && initShowTool;
//
const yAxisValues = [0, 200, 500, 1000, 10000, 100000, 200000]
// y
const mapDataToYAxis = (value) => {
for (let i = 0; i < yAxisValues.length; i++) {
if (value <= yAxisValues[i]) {
return i
}
}
return yAxisValues.length - 1 //
}
//
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: {
trigger: 'axis',
formatter: function (params) {
// tooltip
let result = params[0].name + '<br/>'
params.forEach(param => {
//
const originalValue = param.seriesName === '装备总数'
? equipTotals[param.dataIndex]
: toolTotals[param.dataIndex]
result += `${param.seriesName}: ${originalValue}个<br/>`
})
return result
}
},
barChart.setOption({
tooltip: {
trigger: 'axis',
formatter: (params) => {
let res = `${params[0].name}<br/>`;
params.forEach(p => {
const val = p.seriesName === '装备总数'
? equipTotals[p.dataIndex]
: toolTotals[p.dataIndex];
res += `${p.seriesName}: ${val}个<br/>`;
});
return res;
}
},
//
legend: {
top: 0,
right: 20,
data: series.map(s => s.name), //
},
grid: {
left: '3%',
right: '3%',
bottom: '3%',
top: '15%',
containLabel: true,
},
xAxis: {
data: ['装备总数', '工具总数'],
selected: {
'装备总数': initShowEquip,
'工具总数': initShowTool
}
},
grid: { left: '3%', right: '3%', bottom: '3%', top: '15%', containLabel: true },
xAxis: {
type: 'category',
data: companyNames,
axisLabel: {
fontSize: 13,
interval: 0, //
lineHeight: 16,
formatter: function (name) {
const maxLen = 3 // 6
if (name.length <= maxLen) return name
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
},
},
},
yAxis: yAxisConfig, // 使y
series: series, // 使
}
barChart.setOption(option)
//
data: companyNames,
axisLabel: {
fontSize: 13, interval: 0, lineHeight: 16,
formatter: (name) => {
if (name.length <= 4) return name;
let res = '';
for (let i = 0; i < Math.ceil(name.length / 4); i++) {
res += name.substring(i * 4, (i + 1) * 4) + '\n';
}
return res;
}
}
},
yAxis: initShowBoth
? { // -
type: 'value',
name: '数量(个)',
nameTextStyle: { fontSize: 14 },
min: 0, max: 6, interval: 1,
axisLabel: { fontSize:12, margin:8, formatter: idx => yAxisTicks[Math.floor(idx)] },
splitLine: { lineStyle: { type: 'dashed', color: '#e0e0e0' } }
}
: { // -线
type: 'value',
name: '数量(个)',
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;
// y
// 线
let newYAxisConfig;
if (showBothSeries) {
// 使categoryy
newYAxisConfig = {
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
//
newYAxisConfig = {
type: 'value',
name: '数量(个)',
nameTextStyle: { fontSize: 14 }
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
barChart.setOption({
yAxis: newYAxisConfig
});
// Y replaceMerge: true
barChart.setOption({ yAxis: newYAxisConfig }, { replaceMerge: ['yAxis'], silent: true });
//
const newSeries = [];
//
if (params.selected['装备总数']) {
newSeries.push({
name: '装备总数',
type: 'bar', barWidth:35,
barGap:'0%', barCategoryGap:'0%',
itemStyle: { color:'#5470C6', borderRadius:[4,4,0,0] },
data: showBothSeries ? mappedEquipTotals : equipTotals
});
}
//
if (params.selected['工具总数']) {
newSeries.push({
name: '工具总数',
type: 'bar', barWidth:35,
barGap:'0%', barCategoryGap:'0%',
itemStyle: { color:'#91CC75', borderRadius:[4,4,0,0] },
data: showBothSeries ? mappedToolTotals : toolTotals
});
}
barChart.setOption({
series: newSeries
});
barChart.setOption({ series: newSeries });
});
}
},