一、最终实现效果
二、开发前奏
这种实现效果是第二次改版了,首次实现的效果只是单个柱状图的展示,不像现在需要每个市都需要展示三段的柱状图,单段柱状图很好实现,在一些echarts网站或者社区都可以找到对应的案例,直接进行复制粘贴,然后自己改吧改吧就完成了,但是现在业主方又提要求了,说让每个市展示三段数据,柱状图分为三段进行展示,拿到UI设计稿后,就开始着手进行开发,首先肯定是在对应的echarts网站或者社区进行查找是否有对应的案例,很遗憾,没有~~,哎,针对我这复制粘贴的选手很是头疼,得需要自己研究实现了,echarts网站上实现的柱状图都是单段柱状图,实现的方式还是series中type为lines的类型,没有type为bar的类型,没招了,只能自己研究了,开始翻看echarts的文档和看看有没有通过地图结合柱状图的例子来进行参考。
三、开发中遇到的问题
- 如何在地图上添加柱状图,并对应每个市进行展示。
- 如何展示多段柱状图。
- 如何让柱状图呈现立体的感觉。
- 针对添加的立体圆片没有在对应的柱状图顶部展示
四、代码实现
1.绘制地图
let that = this; this.nxMap && this.nxMap.dispose();//每次加载地图前清空一下 this.nxMap = this.$echarts.init(this.$refs.nxMapRef);//获取地图实例 let option = { //整体echarts容器背景色 backgroundColor: "transparent", //tooltip展示,我这给关闭了,有这需求在打开 tooltip: { trigger: "item", show: false, enterable: true, textStyle: { fontSize: 18, color: "#fff", }, backgroundColor: "rgba(37,108,190, 0.50)", borderColor: "#4ecee6", padding: 8, formatter: "{a}<br />{c}件", }, //这是地图上柱状图对应的图例展示 legend: { data: ["自己的图例名称1", "自己的图例名称2", "自己的图例名称3"], orient: "vertical", icon:'circle', textStyle: { fontSize: 14, color: "#A4CDED" }, itemWidth: 14, itemHeight: 14, itemGap: 15, bottom: 40, right: 260, selectedMode: false, }, //地图的配置项,我这里叠加了多个地图,让整个地图有立体的感觉,按自己需要进行配置就可 geo: [ { map: "ningxia", aspectScale: 0.9, roam: false, // 是否允许缩放 zoom: 0.9, // 默认显示级别 layoutSize: "90%", layoutCenter: ["50%", "50%"], itemStyle: { normal: { areaColor: { type: "linear-gradient", x: 0, y: 400, x2: 0, y2: 0, colorStops: [ { offset: 0, color: "rgba(37,108,190,0.3)", // 0% 处的颜色 // color: "#3674CC", // 0% 处的颜色 }, { offset: 1, color: "rgba(15,169,195,0.3)", // 50% 处的颜色 // color: "#3674CC", // 50% 处的颜色 }, ], global: true, // 缺省为 false }, borderColor: "#4ecee6", borderWidth: 1, }, emphasis: { areaColor: { //tooltip时的背景色设置 type: "linear-gradient", x: 0, y: 300, x2: 0, y2: 0, colorStops: [ { offset: 0, color: "#3671C9", // 0% 处的颜色 }, { offset: 1, color: "#3671C9", // 50% 处的颜色 }, ], global: true, // 缺省为 false }, }, }, emphasis: { itemStyle: { areaColor: "#3671C9", }, label: { show: 0, color: "#fff", }, }, select: { itemStyle: { areaColor: "transparent", }, label: { show: false, }, }, zlevel: 3, }, { map: "ningxia", aspectScale: 0.9, roam: false, // 是否允许缩放 zoom: 0.9, // 默认显示级别 layoutSize: "90%", layoutCenter: ["50%", "50%"], itemStyle: { normal: { borderColor: "rgba(192,245,249,.6)", borderWidth: 2, areaColor: "#3671C9", }, }, zlevel: 2, silent: true, }, { map: "ningxia", aspectScale: 0.9, roam: false, // 是否允许缩放 zoom: 0.9, // 默认显示级别 layoutSize: "90%", layoutCenter: ["50%", "51.5%"], itemStyle: { areaColor: "#03A4EC", borderColor: "#03A4EC", borderWidth: 3, shadowColor: "rgba(29, 111, 165,0.8)", shadowOffsetY: 10, shadowBlur: 5, }, zlevel: 1, silent: true, }, ], xAxis: [], yAxis: [], grid: [], series: [], }; //下面这两行代码,一定要在添加柱状图展示之前写一遍,先渲染一下地图,否则会报错 this.$echarts.registerMap("ningxia", nx); this.nxMap.setOption(option);
复制
至此大体的地图已经可以展示了,下一步开始实现柱状图的展示
2.添加柱状图展示
//这是需要的数据结构形式,其中的value,value1,value2代表的是三段柱状图的数据 let dataList = [ { name: "银川市", value: 540, value1: 556, value2: 550}, { name: "中卫市", value: 1830, value1: 1356, value2: 1350 }, { name: "固原市", value: 1400, value1: 1456, value2: 1250 }, { name: "吴忠市", value: 1750, value1: 1556, value2: 1450 }, { name: "石嘴山市", value: 1130, value1: 1356, value2: 1550}, ]; //下面的代码就是添加柱状图的代码,对数据进行遍历处理 this.$echarts.util.each(dataList, function (dataItem, idx) { //获取对应城市的经纬度 var geoCoord = that.geoCoordMap[dataItem.name]; //把对应城市的经纬度转换成像素值,好让柱状图展示在对应的城市上 var coord = that.nxMap.convertToPixel("geo", geoCoord); idx += ""; //针对每个城市数据添加x轴 option.xAxis.push({ id: idx, gridId: idx, type: "category", name: dataItem.name, //这个级别需要注意一下,看看自己地图的级别,如果设置的比地图级别小,生成的柱状图会被遮挡,导致好像不生效一样,就是不展示,当时我就是这样以为没有生效。 zlevel: 3, nameLocation: "middle", nameGap: 3, nameTextStyle: { color: "#fff", fontSize: 14, }, splitLine: { show: false, }, axisTick: { show: false, }, axisLabel: { color: "#fff", show: false, }, axisLine: { show: false, onZero: false, lineStyle: { color: "#fff", }, }, z: 1000, }); //针对每个城市数据添加y轴 option.yAxis.push({ id: idx, gridId: idx, splitLine: { show: false, }, axisTick: { show: false, }, axisLabel: { show: false, }, axisLine: { show: false, lineStyle: { color: "#fff", }, }, z: 1000, }); //针对每个城市数据添加grid option.grid.push({ id: idx, //下面的宽高最终会体现为柱状图展示的宽高,这个要设置一下,如果不设置,整体的高度会很高而且展示的位置都是错乱的 width: 30, height: 63, //通过转换的像素值,最终展示柱状图的位置,按自己需要进行调整即可 left: coord[0] - 15, top: coord[1] - 55, z: 1000, }); //下面都是添加柱状图展示的数据 option.series.push({ name: "数据名称1", type: "bar", coordinateSystem: "cartesian2d", xAxisIndex: idx, yAxisIndex: idx, stack: idx, zlevel: 3, barWidth: 12, z: 5, barGap: "-100%", itemStyle: { normal: { color: new that.$echarts.graphic.LinearGradient(0, 1, 1, 0, [ { offset: 0, color: "rgba(21,186,255,0)" }, { offset: 1, color: "#24C6FE" }, ]), }, }, data: [dataItem.value], }); //所有添加type为pictorialBar的系列都是让柱状图有立体感,就是每段柱状图上面的小圆片,如果不需要立体感的,只是普通的平面,这个类型的可以不用添加。 option.series.push({ name: "数据名称1", xAxisIndex: idx, yAxisIndex: idx, stack: idx, z: 100, zlevel:3, type: 'pictorialBar', symbolPosition: 'end', symbol: 'circle', symbolOffset: [0, '-40%'],//设置圆片的偏移 symbolSize: [12, 6],//圆片的宽高 data: [dataItem.value],//第一段的柱状图的数据 itemStyle: { color: '#0290D1', borderColor:'#24C6FE', borderType:'solid', borderWidth:1 }, tooltip: { show: false }, }); option.series.push({ name: "数据名称2", type: "bar", xAxisIndex: idx, yAxisIndex: idx, stack: idx, barWidth: 12, zlevel: 3, z: 5, itemStyle: { normal: { color: new that.$echarts.graphic.LinearGradient(0, 1, 1, 0, [ { offset: 0, color: "rgba(0,213,200,0.4)" }, { offset: 1, color: "#00D5C8" }, ]), }, }, data: [dataItem.value1], }); option.series.push({ name: "数据名称2", xAxisIndex: idx, yAxisIndex: idx, stack: idx, z: 100, zlevel:3, type: 'pictorialBar', symbolPosition: 'end', symbol: 'circle', symbolOffset: [0, '-40%'], symbolSize: [12, 6], //第二段柱状图的数据需要第一段和第二段相加,因为这个圆片始终以第一段为基准值,当时研究了好久,就是对不上,最终数据相加就对上了 data: [dataItem.value+dataItem.value1], itemStyle: { color:'#219C94', borderColor:'#00D5C8', borderType:'solid', borderWidth:1 }, tooltip: { show: false }, }); option.series.push({ name: "数据名称3", type: "bar", xAxisIndex: idx, yAxisIndex: idx, stack: idx, barWidth: 12, zlevel: 3, z: 5, itemStyle: { normal: { color: new that.$echarts.graphic.LinearGradient(0, 1, 1, 0, [ { offset: 0, color: "rgba(255,128,0,.4)" }, { offset: 1, color: "#FF8000" }, ]), }, }, //这个label是为了在顶部展示总的数量值,不需要的可以不用 label: { show: true, color: "#fff", position: "top", distance: 5, fontSize: 12, formatter: function (v) { let index = 0; if (v.seriesIndex === 2) { index = 0; } if (v.seriesIndex === 5) { index = 1; } if (v.seriesIndex === 8) { index = 2; } if (v.seriesIndex === 11) { index = 3; } if (v.seriesIndex === 14) { index = 4; } let datas = dataList[index]; let total = datas.total; return `工单总量:${total||0}`; }, }, data: [dataItem.value2], }); option.series.push({ name: "数据名称3", coordinateSystem: "cartesian2d", xAxisIndex: idx, yAxisIndex: idx, stack: idx, z: 103, zlevel:3, type: 'pictorialBar', symbolPosition: 'end', symbol: 'circle', symbolOffset: [0, '-40%'], symbolSize: [12, 6], //这块也是一样,第三段的数据就是三段数据相加 data: [dataItem.value+dataItem.value1+dataItem.value2], itemStyle: { color: '#6D4201', borderColor:'#FF8000', borderWidth:1 }, tooltip: { show: false }, }); }); //添加完柱状图后,在渲染一下地图 this.$echarts.registerMap("ningxia", nx); this.nxMap.setOption(option); //结束
复制
五、完整代码
let that = this; this.nxMap && this.nxMap.dispose();//每次加载地图前清空一下 this.nxMap = this.$echarts.init(this.$refs.nxMapRef);//获取地图实例 let option = { //整体echarts容器背景色 backgroundColor: "transparent", //tooltip展示,我这给关闭了,有这需求在打开 tooltip: { trigger: "item", show: false, enterable: true, textStyle: { fontSize: 18, color: "#fff", }, backgroundColor: "rgba(37,108,190, 0.50)", borderColor: "#4ecee6", padding: 8, formatter: "{a}<br />{c}件", }, //这是地图上柱状图对应的图例展示 legend: { data: ["自己的图例名称1", "自己的图例名称2", "自己的图例名称3"], orient: "vertical", icon:'circle', textStyle: { fontSize: 14, color: "#A4CDED" }, itemWidth: 14, itemHeight: 14, itemGap: 15, bottom: 40, right: 260, selectedMode: false, }, //地图的配置项,我这里叠加了多个地图,让整个地图有立体的感觉,按自己需要进行配置就可 geo: [ { map: "ningxia", aspectScale: 0.9, roam: false, // 是否允许缩放 zoom: 0.9, // 默认显示级别 layoutSize: "90%", layoutCenter: ["50%", "50%"], itemStyle: { normal: { areaColor: { type: "linear-gradient", x: 0, y: 400, x2: 0, y2: 0, colorStops: [ { offset: 0, color: "rgba(37,108,190,0.3)", // 0% 处的颜色 // color: "#3674CC", // 0% 处的颜色 }, { offset: 1, color: "rgba(15,169,195,0.3)", // 50% 处的颜色 // color: "#3674CC", // 50% 处的颜色 }, ], global: true, // 缺省为 false }, borderColor: "#4ecee6", borderWidth: 1, }, emphasis: { areaColor: { //tooltip时的背景色设置 type: "linear-gradient", x: 0, y: 300, x2: 0, y2: 0, colorStops: [ { offset: 0, color: "#3671C9", // 0% 处的颜色 }, { offset: 1, color: "#3671C9", // 50% 处的颜色 }, ], global: true, // 缺省为 false }, }, }, emphasis: { itemStyle: { areaColor: "#3671C9", }, label: { show: 0, color: "#fff", }, }, select: { itemStyle: { areaColor: "transparent", }, label: { show: false, }, }, zlevel: 3, }, { map: "ningxia", aspectScale: 0.9, roam: false, // 是否允许缩放 zoom: 0.9, // 默认显示级别 layoutSize: "90%", layoutCenter: ["50%", "50%"], itemStyle: { normal: { borderColor: "rgba(192,245,249,.6)", borderWidth: 2, areaColor: "#3671C9", }, }, zlevel: 2, silent: true, }, { map: "ningxia", aspectScale: 0.9, roam: false, // 是否允许缩放 zoom: 0.9, // 默认显示级别 layoutSize: "90%", layoutCenter: ["50%", "51.5%"], itemStyle: { areaColor: "#03A4EC", borderColor: "#03A4EC", borderWidth: 3, shadowColor: "rgba(29, 111, 165,0.8)", shadowOffsetY: 10, shadowBlur: 5, }, zlevel: 1, silent: true, }, ], xAxis: [], yAxis: [], grid: [], series: [], }; //下面这两行代码,一定要在添加柱状图展示之前写一遍,先渲染一下地图,否则会报错 this.$echarts.registerMap("ningxia", nx); this.nxMap.setOption(option); //这是需要的数据结构形式,其中的value,value1,value2代表的是三段柱状图的数据 let dataList = [ { name: "银川市", value: 540, value1: 556, value2: 550}, { name: "中卫市", value: 1830, value1: 1356, value2: 1350 }, { name: "固原市", value: 1400, value1: 1456, value2: 1250 }, { name: "吴忠市", value: 1750, value1: 1556, value2: 1450 }, { name: "石嘴山市", value: 1130, value1: 1356, value2: 1550}, ]; //下面的代码就是添加柱状图的代码,对数据进行遍历处理 this.$echarts.util.each(dataList, function (dataItem, idx) { //获取对应城市的经纬度 var geoCoord = that.geoCoordMap[dataItem.name]; //把对应城市的经纬度转换成像素值,好让柱状图展示在对应的城市上 var coord = that.nxMap.convertToPixel("geo", geoCoord); idx += ""; //针对每个城市数据添加x轴 option.xAxis.push({ id: idx, gridId: idx, type: "category", name: dataItem.name, //这个级别需要注意一下,看看自己地图的级别,如果设置的比地图级别小,生成的柱状图会被遮挡,导致好像不生效一样,就是不展示,当时我就是这样以为没有生效。 zlevel: 3, nameLocation: "middle", nameGap: 3, nameTextStyle: { color: "#fff", fontSize: 14, }, splitLine: { show: false, }, axisTick: { show: false, }, axisLabel: { color: "#fff", show: false, }, axisLine: { show: false, onZero: false, lineStyle: { color: "#fff", }, }, z: 1000, }); //针对每个城市数据添加y轴 option.yAxis.push({ id: idx, gridId: idx, splitLine: { show: false, }, axisTick: { show: false, }, axisLabel: { show: false, }, axisLine: { show: false, lineStyle: { color: "#fff", }, }, z: 1000, }); //针对每个城市数据添加grid option.grid.push({ id: idx, //下面的宽高最终会体现为柱状图展示的宽高,这个要设置一下,如果不设置,整体的高度会很高而且展示的位置都是错乱的 width: 30, height: 63, //通过转换的像素值,最终展示柱状图的位置,按自己需要进行调整即可 left: coord[0] - 15, top: coord[1] - 55, z: 1000, }); //下面都是添加柱状图展示的数据 option.series.push({ name: "数据名称1", type: "bar", coordinateSystem: "cartesian2d", xAxisIndex: idx, yAxisIndex: idx, stack: idx, zlevel: 3, barWidth: 12, z: 5, barGap: "-100%", itemStyle: { normal: { color: new that.$echarts.graphic.LinearGradient(0, 1, 1, 0, [ { offset: 0, color: "rgba(21,186,255,0)" }, { offset: 1, color: "#24C6FE" }, ]), }, }, data: [dataItem.value], }); //所有添加type为pictorialBar的系列都是让柱状图有立体感,就是每段柱状图上面的小圆片,如果不需要立体感的,只是普通的平面,这个类型的可以不用添加。 option.series.push({ name: "数据名称1", xAxisIndex: idx, yAxisIndex: idx, stack: idx, z: 100, zlevel:3, type: 'pictorialBar', symbolPosition: 'end', symbol: 'circle', symbolOffset: [0, '-40%'],//设置圆片的偏移 symbolSize: [12, 6],//圆片的宽高 data: [dataItem.value],//第一段的柱状图的数据 itemStyle: { color: '#0290D1', borderColor:'#24C6FE', borderType:'solid', borderWidth:1 }, tooltip: { show: false }, }); option.series.push({ name: "数据名称2", type: "bar", xAxisIndex: idx, yAxisIndex: idx, stack: idx, barWidth: 12, zlevel: 3, z: 5, itemStyle: { normal: { color: new that.$echarts.graphic.LinearGradient(0, 1, 1, 0, [ { offset: 0, color: "rgba(0,213,200,0.4)" }, { offset: 1, color: "#00D5C8" }, ]), }, }, data: [dataItem.value1], }); option.series.push({ name: "数据名称2", xAxisIndex: idx, yAxisIndex: idx, stack: idx, z: 100, zlevel:3, type: 'pictorialBar', symbolPosition: 'end', symbol: 'circle', symbolOffset: [0, '-40%'], symbolSize: [12, 6], //第二段柱状图的数据需要第一段和第二段相加,因为这个圆片始终以第一段为基准值,当时研究了好久,就是对不上,最终数据相加就对上了 data: [dataItem.value+dataItem.value1], itemStyle: { color:'#219C94', borderColor:'#00D5C8', borderType:'solid', borderWidth:1 }, tooltip: { show: false }, }); option.series.push({ name: "数据名称3", type: "bar", xAxisIndex: idx, yAxisIndex: idx, stack: idx, barWidth: 12, zlevel: 3, z: 5, itemStyle: { normal: { color: new that.$echarts.graphic.LinearGradient(0, 1, 1, 0, [ { offset: 0, color: "rgba(255,128,0,.4)" }, { offset: 1, color: "#FF8000" }, ]), }, }, //这个label是为了在顶部展示总的数量值,不需要的可以不用 label: { show: true, color: "#fff", position: "top", distance: 5, fontSize: 12, formatter: function (v) { let index = 0; if (v.seriesIndex === 2) { index = 0; } if (v.seriesIndex === 5) { index = 1; } if (v.seriesIndex === 8) { index = 2; } if (v.seriesIndex === 11) { index = 3; } if (v.seriesIndex === 14) { index = 4; } let datas = dataList[index]; let total = datas.total; return `工单总量:${total||0}`; }, }, data: [dataItem.value2], }); option.series.push({ name: "数据名称3", coordinateSystem: "cartesian2d", xAxisIndex: idx, yAxisIndex: idx, stack: idx, z: 103, zlevel:3, type: 'pictorialBar', symbolPosition: 'end', symbol: 'circle', symbolOffset: [0, '-40%'], symbolSize: [12, 6], //这块也是一样,第三段的数据就是三段数据相加 data: [dataItem.value+dataItem.value1+dataItem.value2], itemStyle: { color: '#6D4201', borderColor:'#FF8000', borderWidth:1 }, tooltip: { show: false }, }); }); //添加完柱状图后,在渲染一下地图 this.$echarts.registerMap("ningxia", nx); this.nxMap.setOption(option); //结束
复制
六、总结
写这篇博客的缘由就是因为网上实现echarts地图结合柱状图的博客找不到或者有一些博客但是需要会员才能访问,这种事情就算了吧,幸好最终我实现了,所以还是总结一下写出来,让后续有类似需求的伙伴们有个参考的地方,针对代码哪里有不懂的地方可以评论留言或者私信,我看到了会回复的。好了。。本篇博客结束了。