(相关资料图)
Echarts创建中国3D地图
客户需要做一版3D中国地图,地图要倾斜角度,然后可以支持点击省份,对地图两侧的图表数据进行切换,此外还有一些纹理,顶牌信息面板的效果,不一一赘述,末尾我会放一张成品的图片。
地图数据
Echarts官网迁移后,地图的json数据已经不翼而飞了,所以在开发地图图表时,要先找一份地图的json数据,阿里的网站就有,直接去下载就好了。链接:http://datav.aliyun.com/portal/school/atlas/area_selectorjson下载完成后,要在Echarts对象初始化的时候注册一下,代码如下:
import china from "../../../public/mock/map/china.json" // 导入地图json数据import * as echarts from "echarts"echarts.registerMap("china", china)
组件代码
<script>import china from "../../../public/mock/map/china.json"import * as echarts from "echarts"import tietu1 from "../../assets/imgs/home/123.jpg"import video from "../../assets/imgs/map/map_bg.mp4"import video2 from "../../assets/imgs/map/map_bg2.mp4"import video3 from "../../assets/imgs/map/map_bg3.mp4"import video4 from "../../assets/imgs/map/map_bg4.mp4"import markerImg from "../../assets/imgs/map/3d_marker_bg.png"import axiosAPI from "../../axios"import { useModule } from "../../store/useModule"export default { props: { config: { type: Object, default: () => ({ width: 7600, height: 2160 }), }, }, setup() { const moduleStore = useModule() let dataMaps = [ { name: "北京", value: 457, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "天津", value: 120, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "河北", value: 421, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "山西", value: 413, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "内蒙古", value: 484, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "辽宁", value: 106, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "吉林", value: 18, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "黑龙江", value: 98, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "上海", value: 331, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "江苏", value: 164, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "浙江", value: 4, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "安徽", value: 26, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "福建", value: 492, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "江西", value: 48, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "山东", value: 132, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "河南", value: 309, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "湖北", value: 35, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "湖南", value: 11, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "重庆", value: 16, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "四川", value: 383, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "贵州", value: 209, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "云南", value: 365, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "西藏", value: 421, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "陕西", value: 144, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "甘肃", value: 472, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "青海", value: 182, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "宁夏", value: 282, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "新疆", value: 51, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "广东", value: 110, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "广西", value: 453, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "海南", value: 356, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "台湾", value: 342, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "香港", value: 406, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, { name: "澳门", value: 223, itemStyle: { color: "rgba(167, 204, 255, 1)", opacity: 1, borderWidth: 2, borderColor: "rgba(167, 204, 255, 1)", // 地图边配色 } }, ] const state = reactive({ videos: [video, video2, video3, video4], videoUrl: window.yunyingzhihuizhongxin.videoUrl, infoData: [], }) const getData = async () => { const res = await axiosAPI.get(window.yunyingzhihuizhongxin.URLs.china3D) if (res.code === 200) { state.infoData = res.data.data } } const timer = setInterval(getData, window.yunyingzhihuizhongxin.looping.china3D * 1000) const addcomma = (num) => (num || 0).toString().replace(/(\d)(?=(?:\d{3})+$)/g, "$1,") const convertData = (data) => { const res = [] for (let i = 0; i < data.length; i++) { res.push({ name: data[i].name, value: data[i].lonlat, value1: data[i].value1, value2: data[i].value2, label1: data[i].label1, label2: data[i].label2, label: { show: true, position: "top", distance: 0, backgroundColor: { image: markerImg, }, width: 414, height: 176, formatter(param) { return `{sty1|${param.data.label1}} {sty2|${param.data.label2}} {sty3|${addcomma(param.data.value1)}} {sty4|${addcomma(param.data.value2)}}` }, rich: { sty1: { fontSize: 32, padding: [15, 0, 0, 20], color: "rgba(23, 31, 44, 1)", fontFamily: "SourceHanSansCN-Bold, sans-serif", fontWeight: 500, align: "left", }, sty2: { color: "rgba(23, 31, 44, 1)", padding: [-39, 20, 0, 0], fontSize: 32, fontFamily: "SourceHanSansCN-Bold, sans-serif", fontWeight: 500, align: "right", }, sty3: { fontSize: 58, padding: [15, 0, 0, -95], fontFamily: "DINPro-Medium, sans-serif", fontWeight: 500, color: "#FFFFFF", align: "left", }, sty4: { fontSize: 58, padding: [-70, 20, 0, 0], fontFamily: "DINPro-Medium, sans-serif", fontWeight: 500, color: "#FFFFFF", align: "right", }, }, }, }) } return res } let myChart const init = () => { if (!myChart) { myChart = echarts.init(document.getElementById("echarts")) echarts.registerMap("china", china) myChart.on("click", "series.map3D", params => { let newOption = myChart.getOption() newOption.geo3D[0].regions.forEach(region => { if (params.data.name === region.name) { if (region.itemStyle.borderWidth === 6) { region.itemStyle.color = "rgba(167, 204, 255, 1)" region.itemStyle.borderColor = "rgba(167, 204, 255, 1)" region.itemStyle.borderWidth = 2 } else { region.itemStyle.color = "#76ddff" region.itemStyle.borderColor = "#76ddff" region.itemStyle.borderWidth = 6 } } else { region.itemStyle.color = "rgba(167, 204, 255, 1)" region.itemStyle.borderColor = "rgba(167, 204, 255, 1)" region.itemStyle.borderWidth = 2 } }) moduleStore.currentMapChoose === params.data.name ? moduleStore.changeCurrentMapChoose("china") : moduleStore.changeCurrentMapChoose(params.data.name) myChart.setOption(newOption, true) }) } if (moduleStore.currentMapChoose !== "china") { dataMaps.forEach(region => { if (region.name === moduleStore.currentMapChoose) { region.itemStyle.color = "#76ddff" region.itemStyle.borderColor = "#76ddff" region.itemStyle.borderWidth = 6 } }) } const option = { visualMap: { show: false, symbolSize: [15, 30], pieces: [ // 自定义每一段的范围,以及每一段的文字 { gte: 300, label: "1000-9999人", color: "rgba(82, 104, 134, 0.8)" }, { gte: 200, lte: 299, label: "500-999人", color: "rgba(82, 104, 134, 0.8)" }, { gte: 100, lte: 199, label: "100-499人", color: "rgba(82, 104, 134, 0.8)" }, { gte: 10, lte: 99, label: "10-99人", color: "rgba(82, 104, 134, 0.8)" }, // 不指定 min,表示 min 为无限大(-Infinity)。 { lte: 9, label: "1-9人", color: "rgba(82, 104, 134, 0.8)" }, ], }, geo3D: { show: true, type: "map3D", map: "china", regionHeight: 4, shading: "realistic", height: 2800, top: -500, label: { // 标签的相关设置 show: true, // (地图上的城市名称)是否显示标签 [ default: false ] formatter(param) { const city = (param.name).substr(0, 3) return city === "香港" ? `{sty1|${city}}` : `{sty2|${city}}` }, rich: { sty1: { color: "#ffffff", fontSize: 28, fontFamily: "SourceHanSansCN-Regular, sans-serif", align: "right", backgroundColor: "transparent", width: 120, }, sty2: { color: "#ffffff", fontSize: 28, fontFamily: "SourceHanSansCN-Regular, sans-serif", align: "center", }, }, }, roam: true, zoom: 2, realisticMaterial: { detailTexture: tietu1, // 纹理贴图 textureTiling: 1, // 纹理平铺,1是拉伸,数字表示纹理平铺次数 roughness: 1, // 材质粗糙度,0完全光滑,1完全粗糙 metalness: 1, // 0材质是非金属 ,1金属 roughnessAdjust: 0, }, // 鼠标hover高亮 emphasis: { label: { show: true, // (地图上的城市名称)是否显示标签 [ default: false ] }, itemStyle: { areaColor: "#61A4E4", // color: "#61A4E4", borderColor: "#88BAEA", borderWidth: 2, }, }, light: { // 光照相关的设置。在 shading 为 "color" 的时候无效。 // 光照的设置会影响到组件以及组件所在坐标系上的所有图表。合理的光照设置能够让整个场景的明暗变得更丰富,更有层次。 main: { // 场景主光源的设置,在 globe 组件中就是太阳光。 color: "#fff", // 主光源的颜色。[ default: #fff ] intensity: 4, // 主光源的强度。[ default: 1 ] shadow: false, // 主光源是否投射阴影。默认关闭。 开启阴影可以给场景带来更真实和有层次的光照效果。但是同时也会增加程序的运行开销。 alpha: 150, // 主光源绕 x 轴,即上下旋转的角度。配合 beta 控制光源的方向。[ default: 40 ] beta: 90, // 主光源绕 y 轴,即左右旋转的角度。[ default: 40 ] shadowQuality: "high", }, ambient: { // 全局的环境光设置。 color: "#fff", // 环境光的颜色。[ default: #fff ] intensity: 1, // 环境光的强度。[ default: 0.2 ] }, }, viewControl: { autoRotate: false, // 自动旋转 // autoRotateAfterStill: 10, // 静止时间后自动旋转 animation: true, alpha: 45, // 视角绕 x 轴,即上下旋转的角度 beta: 5, // 视角绕 y 轴,即左右旋转的角度 distance: 90, // 视角距离主体的距离 rotateSensitivity: 0, zoomSensitivity: 0, }, regions: dataMaps, data: [], // silent: true, }, series: [ { show: true, type: "map3D", map: "china", regionHeight: 4, shading: "realistic", itemStyle: { opacity: 0, }, height: 2800, top: -500, label: { // 标签的相关设置 show: true, // (地图上的城市名称)是否显示标签 [ default: false ] formatter(param) { const city = (param.name).substr(0, 3) return city === "香港" ? `{sty1|${city}}` : `{sty2|${city}}` }, rich: { sty1: { color: "#ffffff", fontSize: 28, fontFamily: "SourceHanSansCN-Regular, sans-serif", align: "right", backgroundColor: "transparent", width: 120, }, sty2: { color: "#ffffff", fontSize: 28, fontFamily: "SourceHanSansCN-Regular, sans-serif", align: "right", height: 150, width: 100, backgroundColor: "transparent", verticalAlign: "top", }, }, }, roam: true, zoom: 2, realisticMaterial: { detailTexture: tietu1, // 纹理贴图 textureTiling: 1, // 纹理平铺,1是拉伸,数字表示纹理平铺次数 roughness: 1, // 材质粗糙度,0完全光滑,1完全粗糙 metalness: 1, // 0材质是非金属 ,1金属 roughnessAdjust: 0, }, // 鼠标hover高亮 emphasis: { label: { show: true, // (地图上的城市名称)是否显示标签 [ default: false ] }, itemStyle: { areaColor: "#61A4E4", // color: "#61A4E4", borderColor: "#88BAEA", borderWidth: 2, }, }, light: { // 光照相关的设置。在 shading 为 "color" 的时候无效。 // 光照的设置会影响到组件以及组件所在坐标系上的所有图表。合理的光照设置能够让整个场景的明暗变得更丰富,更有层次。 main: { // 场景主光源的设置,在 globe 组件中就是太阳光。 color: "#fff", // 主光源的颜色。[ default: #fff ] intensity: 4, // 主光源的强度。[ default: 1 ] shadow: false, // 主光源是否投射阴影。默认关闭。 开启阴影可以给场景带来更真实和有层次的光照效果。但是同时也会增加程序的运行开销。 alpha: 150, // 主光源绕 x 轴,即上下旋转的角度。配合 beta 控制光源的方向。[ default: 40 ] beta: 90, // 主光源绕 y 轴,即左右旋转的角度。[ default: 40 ] shadowQuality: "high", }, ambient: { // 全局的环境光设置。 color: "#fff", // 环境光的颜色。[ default: #fff ] intensity: 1, // 环境光的强度。[ default: 0.2 ] }, }, viewControl: { autoRotate: false, // 自动旋转 // autoRotateAfterStill: 10, // 静止时间后自动旋转 animation: true, alpha: 45, // 视角绕 x 轴,即上下旋转的角度 beta: 5, // 视角绕 y 轴,即左右旋转的角度 distance: 90, // 视角距离主体的距离 rotateSensitivity: 0, zoomSensitivity: 0, }, regions: dataMaps, data: [], zlevel: 1, // silent: true, }, // 叠加地图上需要显示的数据,插牌 { type: "scatter3D", name: "scatter3D", coordinateSystem: "geo3D", symbol: "pin", symbolSize: 0, label: {}, data: convertData(state.infoData), }, ], } // 把option设置给myChart实例 myChart.setOption(option, true) } watch(() => state.infoData, () => { init() }) // 加载完就调用的方法 vue3生命周期 onMounted(() => { getData() }) onBeforeUnmount(() => { clearInterval(timer) }) return { ...toRefs(state), } },}</script>
成品图
如下所示:
关键词: