renderings
Main idea
Prepare three cylinders (original plan, actual progress, difference)
The original plan and actual progress are set to overlap
{<!-- --> barWidth: 20, // yAxisIndex: 1, z: 1, name: 'original plan', type: 'bar', stack: 'ab', emphasis: {<!-- --> // Click on the cylinder and the color of other cylinders will become lighter. disabled: true }, label: {<!-- --> show: true }, itemStyle: {<!-- --> emphasis: {<!-- --> barBorderRadius: 10 }, normal: {<!-- --> barBorderRadius: 10 } }, data: this.planProcessData.map((item) => {<!-- --> return {<!-- --> value: item, label: {<!-- --> show: !(item < 10), formatter: item + '%', position: 'insideRight', textStyle: {<!-- --> color: '#262626', fontSize: 12 } } } }) },
{<!-- --> barGap: '-100%', /* can overlap*/ barWidth: 20, yAxisIndex: 0, z: 2, itemStyle: {<!-- --> emphasis: {<!-- --> barBorderRadius: 10 }, normal: {<!-- --> barBorderRadius: 10 } }, data: this.realityProcessData.map((item) => {<!-- --> return {<!-- --> value: item, label: {<!-- --> show: true, formatter: item + '%', position: item < 10 ? 'right' : 'insideRight', textStyle: {<!-- --> color: '#262626', fontSize: 12 } } } }), type: 'bar', label: {<!-- --> show: true }, emphasis: {<!-- --> // Click on the cylinder and the color of other cylinders will become lighter. disabled: true }, name: 'Actual progress' }
Set the actual progress barGap: -100%’, and you can overlap it.
Then set the difference cylinder
{<!-- --> barWidth: 20, // yAxisIndex: 1, z: 1, stack: 'ab', // This can be stacked by keeping it the same data: this.differenceData.map((item) => {<!-- --> return {<!-- --> value: item, label: {<!-- --> show: true, formatter: (params) => {<!-- --> // The core part formatter can be a string or a callback // var that = this // console.log('0904', this.differenceData) if (params.value) {<!-- --> // Splice if the current value exists return '↓' + ' ' + '-' + params.value + '%' } else {<!-- --> // Otherwise return empty return '' } }, position: 'insideLeft', textStyle: {<!-- --> color: '#E20000', fontSize: 12 } } } }), type: 'bar', emphasis: {<!-- --> // Click on the cylinder and the color of other cylinders will become lighter. disabled: true }, label: {<!-- --> show: true }, name: 'difference' },
To stack the differences with the original plan, they set stack: ab’, which can be stacked as they are, and then change the background color of the difference column to white
Then change the position of the displayed value to insideLeft
You can achieve the above effect
3. If the two overlapping cylinders do not completely overlap
Effect
To set the width in the original plan
In actual progress, the width should be set smaller and the overlap should be 80%.
4. Set the maximum width to 100%, but the content can exceed
This way it can be displayed
5. In series, in formatter, customize pictures
renderings
Then define it in rich
Finally used in formatter
First, import pictures
Supplement
1. If you want to use this here, be sure to use an arrow function
2. If you want to move the mouse to a cylinder, some other cylinders will not be transparent
To be set in each cylinder
3. Add a click event to the bar chart
This cannot be obtained directly in the click event function, you need to let that = this
Complete code
initData() {<!-- --> const PieEchartBox = this.$refs.projectChart const myPieEchart = this.$echarts.init(PieEchartBox) myPieEchart.setOption({<!-- --> color: ['#E3F1FF', '#fff', '#1CCBD3'], legend: {<!-- --> data: ['Original plan', 'Difference', 'Actual progress'], show: false }, tooltip: {<!-- --> trigger: 'axis', extraCssText: 'width:200px', valueFormatter: function(value) {<!-- --> // Add content to the value inside return value + '%' }, axisPointer: {<!-- --> type: 'shadow' }, formatter: "<div style='display:block;word-break: break-all;word-wrap: break-word;white-space:pre-wrap;margin-bottom: 10px'>" + \ '{b}' + '</div>' + "<div style='display: flex;justify-content: space-between;'><div style='display: flex;align-items: center;'><div style='border- radius: 50%;width: 8px;height: 8px;background: #7ECAD3;margin-right: 10px'></div>" + '<span>' + '{a0}' + \ '</span></div><div>{c0}%</div></div>' + "<div style='display: flex;justify-content: space-between;'><div style='display: flex;align-items: center;'><div style='border- radius: 50%;width: 8px;height: 8px;background: #5682cc;margin-right: 10px'></div>" + '<span>' + '{a2}' + \ '</span></div><div>{c2}%</div></div>' }, grid: {<!-- --> left: '10', right: '6%', bottom: '3%', top: '2%', containLabel: true }, yAxis: [{<!-- --> type: 'category', axisTick: {<!-- --> length: 10 }, axisLine: 'none', data: this.topicNameData, axisLabel: {<!-- --> margin: 10, interval: 0, lineHeight: 14, textStyle: {<!-- --> fontSize: 12, color: '#666666' }, formatter: function(value) {<!-- --> var ret = ''// Concatenate and add \\ returned category items var valLength = value.length//The number of texts in the X-axis category items var maxLength = 10 //Number of displayed text for each item var rowN = Math.ceil(valLength / maxLength) //The number of rows that the category item needs to wrap if (rowN > 1) {<!-- --> // / If the text of the category item is greater than 3, for (var i = 0; i < rowN & amp; & amp; i < 2; i + + ) {<!-- --> var temp = ''// The string intercepted each time var end = '' var start = i * maxLength//Start interception position if (i === 1 & amp; & amp; valLength > 20) {<!-- --> end = start + 9//End interception position } else {<!-- --> end = start + maxLength//End interception position } // You can also add a judgment here to determine whether it is the last line, but it will have no effect if you don't add it, so don't add it. if (i === 1 & amp; & amp; valLength > 20) {<!-- --> temp = value.substring(start, end) + '...'//End interception position } else {<!-- --> temp = value.substring(start, end) + '\\ '// End interception position } ret + = temp // with the final string } return ret } else {<!-- --> return value } } } }, {<!-- --> show: false, type: 'category', axisTick: 'none', data: [], axisLine: 'none' }], xAxis: {<!-- --> type: 'value', interval: 10, max: 100.001, // in order to display the difference axisLabel: {<!-- --> show: true, textStyle: {<!-- --> fontSize: 10 }, itemWidth: 123, formatter: '{value}%' // Add a percent sign to the Y-axis value }, position: 'top' }, series: [ {<!-- --> barWidth: 24, barCategoryGap: '60%', // yAxisIndex: 1, z: 1, name: 'original plan', type: 'bar', stack: 'ab', emphasis: {<!-- --> // Click on the cylinder and the color of other cylinders will become lighter. disabled: true }, label: {<!-- --> show: true }, itemStyle: {<!-- --> emphasis: {<!-- --> barBorderRadius: 10 }, normal: {<!-- --> barBorderRadius: 10 } }, data: this.planProcessData.map((item) => {<!-- --> return {<!-- --> value: item, label: {<!-- --> show: !(item < 10), formatter: item + '%', position: 'insideRight', textStyle: {<!-- --> color: '#262626', fontSize: 12 } } } }) }, {<!-- --> barWidth: 20, barCategoryGap: '60%', // yAxisIndex: 1, z: 1, stack: 'ab', // This can be stacked by keeping it the same data: this.differenceData.map((item) => {<!-- --> return {<!-- --> value: item, label: {<!-- --> normal: {<!-- --> show: true, formatter: (params) => {<!-- --> // The core part formatter can be a string or a callback if (params.value) {<!-- --> // Splice if the current value exists return '{imgDown|}' + ' ' + '-' + params.value.toFixed(2) + '%' } else {<!-- --> // Otherwise return empty return '' } }, rich: {<!-- --> imgDown: {<!-- --> paddingLeft: 10, backgroundColor: {<!-- --> image: downIcon }, width: 8, height: 12 } }, position: 'insideLeft', textStyle: {<!-- --> color: '#E20000', fontSize: 12 } } } } }), type: 'bar', emphasis: {<!-- --> // Click on the cylinder and the color of other cylinders will become lighter. disabled: true }, label: {<!-- --> show: true }, name: 'Difference' }, {<!-- --> barGap: '-80%', /* can overlap*/ barWidth: 14, barCategoryGap: '60%', yAxisIndex: 0, z: 2, itemStyle: {<!-- --> emphasis: {<!-- --> barBorderRadius: 10 }, normal: {<!-- --> barBorderRadius: 10 } }, data: this.realityProcessData.map((item) => {<!-- --> return {<!-- --> value: item, label: {<!-- --> show: true, formatter: item + '%', position: item < 10 ? 'right' : 'insideRight', textStyle: {<!-- --> color: '#262626', fontSize: 12 } } } }), type: 'bar', label: {<!-- --> show: true }, emphasis: {<!-- --> // Click on the cylinder and the color of other cylinders will become lighter. disabled: true }, name: 'Actual progress' } ] }) const that = this myPieEchart.on('click', function(param) {<!-- --> console.log('1019', that.dictTypeTopicList, param) let topicType = '' that.dictTypeTopicList.forEach((res) => {<!-- --> if (param.name === res.label) {<!-- --> topicType = res.value return } }) that.$router.push({<!-- --> path: '/projectDetails', query: {<!-- --> topicName: param.name, topicType: topicType } }) }) }