基于vue3+leaflet+postgresql+postgis的南京市充电站可视化平台案例,覆盖功能点包括底图切换、地图工具栏、充电站点查询(属性和框选查询)、充电站点聚合+热力图以及充电站数量的柱状图/各区县充电站柱状图饼图等,适合学习leaflet与前端框架结合开发webgis开发可视化项目。
demo源码运行环境以及配置
运行环境:依赖Node安装环境,demo本地Node版本:推荐v18+。
运行工具:vscode或者其他工具。
前端项目配置方式:下载demo源码,vscode打开,然后顺序执行以下命令:
(1)下载demo环境依赖包命令:npm install
(2)启动demo命令:npm run dev
(3)打包demo命令: npm run build后端项目配置方式:下载demo源码,vscode打开,然后顺序执行以下命令:
(1)下载demo环境依赖包命令:npm install express pg cors
(2)启动demo命令:node src/server.js
技术栈
Vue 3.2.39
Vite 2.5.10
leaflet 1.9.4
cors 2.8.5 express 4.21.2
pg 8.13.3
示例效果
核心源码
<template>
<div class="titleContainer center">
<span>南京市充电站可视化平台</span>
</div>
<div id="map"></div>
<!-- 统计图表 -->
<div class="echartsDIV center">
<div class="echarts" id="echart1"></div>
<div class="echarts" id="echart2"></div>
<div class="echarts" id="echart3"></div>
</div>
<!-- 量算工具 -->
<div class="measureDIV">
<el-tooltip class="box-item" effect="dark" content="测距" placement="left">
<div class="measure-btn center" @click.stop="distanceMeasureFun"><img alt="测距" :src="distanceSrc">
</div>
</el-tooltip>
<el-tooltip class="box-item" effect="dark" content="测面" placement="left">
<div class="measure-btn center" @click.stop="areaMeasureFun"><img alt="测面" :src="areaSrc"></div>
</el-tooltip>
<el-tooltip class="box-item" effect="dark" content="清空" placement="left">
<div class="measure-btn center" @click.stop="clearFun"><img alt="清空" :src="clearSrc"></div>
</el-tooltip>
<el-tooltip class="box-item" effect="dark" content="复位" placement="left">
<div class="measure-btn center" @click.stop="resetFun"><img alt="复位" :src="resetSrc"></div>
</el-tooltip>
</div>
<!-- 查询功能 -->
<div class="queryDIV">
<div style="display: flex;">
<el-input v-model="keyword" @clear="clearQuery" clearable placeholder="输入关键字搜索" class="input-with-select">
<template #append>
<el-tooltip class="box-item" effect="dark" content="搜索" placement="bottom">
<el-button :icon="Search" @click="queryFun" />
</el-tooltip>
</template>
</el-input>
<el-tooltip class="box-item" effect="dark" content="框选查询" placement="bottom">
<el-button class="rectBtn" :icon="Edit" @click="rectQueryFun" />
</el-tooltip>
</div>
<el-card v-if="isShowResult" class="elcard">
<template #header>
<div class="card-header">
<span>搜索结果:<span style="color: #eaf908;">{{ queryData.length }}</span>条</span>
<el-tooltip class="box-item" effect="dark" content="关闭" placement="bottom">
<el-icon style="float: right;color: red; cursor: pointer;" @click="clearQueryResult">
<CloseBold />
</el-icon>
</el-tooltip>
</div>
</template>
<el-scrollbar v-if="queryData.length !== 0" max-height="calc(100vh - calc((100vw / 1920) * 200))">
<div v-for="(item, index) in queryData" :key="index" class="textitem" @click="openMapPopup(item)">
{{ '名称: ' + item.name }}
<br>
{{ '地址: ' + item.address }}
<br>
{{ '类型: ' + item.type }}
<br>
{{ '地区: ' + item.adname }}
<br>
{{ '电话: ' + item.tel }}
<br>
{{ '地理位置: ' + item.longitude + ',' + item.latitude }}
<el-divider />
</div>
</el-scrollbar>
<div v-else>
<div class="textitem">
搜索不到相关数据
</div>
</div>
</el-card>
</div>
</template>
<script setup>
import { onMounted, nextTick, ref } from "vue";
import L from "leaflet";
import "leaflet.markercluster/dist/MarkerCluster.css";
import "leaflet.markercluster/dist/MarkerCluster.Default.css";
import "leaflet.markercluster";
import "@geoman-io/leaflet-geoman-free";
import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";
import * as echarts from "echarts";
import config from "../config";
// import { useRouter } from "vue-router";
import distanceSrc from '@/assets/distance.png';
import areaSrc from '@/assets/area.png';
import clearSrc from '@/assets/clear.png';
import resetSrc from '@/assets/reset.png';
import shanchu from "@/assets/shanchu.png";
import { Search, Edit, CloseBold } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
// const router = useRouter();
// 查询搜索定义
const keyword = ref(''); // 关键字输入框
const isShowResult = ref(false); // 是否显示搜索结果
// 查询模拟数据源
const queryData = ref([]); // 查询结果数据源
// 请求所有充电站数据源接口
const getAllListsApi = '/api/charging-stations';
// 模糊查询充电站数据源接口
const searchApi = '/api/charging-stations/search';
// 框选查询充电站数据源接口
const rectSearchApi = '/api/charging-stations/bbox';
// 按照行政区统计电站数据源接口
const statisticsApi = '/api/charging-stations/statistics';
// 按照类型统计电站数据源接口
const typeStatisticsApi = '/api/charging-stations/type-statistics';
// 统计图表数据源
let echartsData1 = {};
// 统计图表数据源
let echartsData2 = [];
// 充电站数据源
let stationData = null;
// 充电站热力图数据源
let heatmapData = {
max: 100,
data: []
};
// 热力图配置
const cfg = {
// radius: 0.0009,
radius: 0.009,
maxOpacity: 0.4,
scaleRadius: true,
useLocalExtrema: true,
latField: "lat",
lngField: "lng",
valueField: "value",
};
let map = null; // 地图对象
let geojsonLayer = null; // 框选绘制图层对象
onMounted(() => {
nextTick(() => {
// 待加载的热力图JS文件数组
const files = [
"./lib/heatmap/heatmap.min.js",
"./lib/heatmap/leaflet-heatmap.js",
"./lib/measure/Leaflet.Editable.js",
"./lib/measure/leaflet-measure-path.js",
];
loadScripts(files, async function () {
// console.log("All scripts loaded");
// 获取充电站数据源
await fetchData();
initMap();
initMeasure();
// 获取充电站统计图表数据源
await fetchStatisticsData();
// 获取类型充电站统计图表数据源
await fetchTypeStatisticsData();
// 统计图表初始化
initCharts();
});
});
});
const loadScripts = (files, callback) => {
if (files.length === 0) {
callback();
return;
}
const file = files.shift();
const script = document.createElement("script");
script.onload = function () {
loadScripts(files, callback);
};
script.src = file;
document.head.appendChild(script);
};
// 请求数据源接口
// 使用 fetch API 获取数据
async function fetchData() {
try {
// 使用 fetch API 发起请求并等待响应
const response = await fetch(getAllListsApi);
// 检查响应状态是否成功
if (!response.ok) {
throw new Error('网络响应异常');
}
// 将响应解析为 JSON 并等待结果
stationData = await response.json();
// 处理 JSON 数据
// console.log(stationData);
heatmapData.data = stationData.features.map((item) => {
const properties = item.properties;
return {
lng: properties.longitude,
lat: properties.latitude,
value: Math.floor(Math.random() * 100) + 1,
};
});
// console.log(heatmapData);
} catch (error) {
// 处理错误
console.error('错误异常:', error);
}
}
// 按照行政区统计电站数据源接口
async function fetchStatisticsData() {
try {
// 使用 fetch API 发起请求并等待响应
const response = await fetch(statisticsApi);
// 检查响应状态是否成功
if (!response.ok) {
throw new Error('网络响应异常');
}
// 将响应解析为 JSON 并等待结果
echartsData1 = await response.json();
console.log(echartsData1);
} catch (error) {
// 处理错误
console.error('错误异常:', error);
}
}
// 按照类型统计电站数据源接口
async function fetchTypeStatisticsData() {
try {
// 使用 fetch API 发起请求并等待响应
const response = await fetch(typeStatisticsApi);
// 检查响应状态是否成功
if (!response.ok) {
throw new Error('网络响应异常');
}
// 将响应解析为 JSON 并等待结果
echartsData2 = await response.json();
// console.log(echartsData2);
} catch (error) {
// 处理错误
console.error('错误异常:', error);
}
}
// 初始化地图
const initMap = () => {
// 创建地图对象
map = L.map("map", {
attributionControl: false,
zoomControl: false,
}).setView(config.mapInitParams.center, config.mapInitParams.zoom);
//创建底图切换数据源
const baseLayer1 = L.tileLayer(config.baseMaps[0].Url); //OSM街道图
const baseLayer2 = L.tileLayer(config.baseMaps[1].Url); //ArcGIS影像图
const baseLayer4 = L.layerGroup([L.tileLayer(config.baseMaps[3].Url, {
subdomains: ["0", "1", "2", "3", "4", "5", "6", "7"],
}), L.tileLayer(config.baseMaps[4].Url, {
subdomains: ["0", "1", "2", "3", "4", "5", "6", "7"],
})]); //天地图街道图
const baseLayer5 = L.layerGroup([L.tileLayer(config.baseMaps[5].Url, {
subdomains: ["0", "1", "2", "3", "4", "5", "6", "7"],
}), L.tileLayer(config.baseMaps[6].Url, {
subdomains: ["0", "1", "2", "3", "4", "5", "6", "7"],
})]); //天地图影像图
const baseLayer8 = L.tileLayer(config.baseMaps[9].Url, {
subdomains: ["1", "2", "3", "4"],
}); //高德街道图
const baseLayer9 = L.tileLayer(config.baseMaps[10].Url, {
subdomains: ["1", "2", "3", "4"],
}); //高德影像图
// 充电站点
const labelPointLayer = L.markerClusterGroup({
showCoverageOnHover: false,
zoomToBoundsOnClick: true,
chunkedLoading: true,
maxClusterRadius: 25, //默认80
});
labelPointLayer.on("click", (e) => {
// console.log('e', e);
e.layer.unbindPopup();
const properties = e.layer.options.properties;
const elements = getPopupContent(properties);
e.layer.bindPopup(elements).openPopup(e.latlng);
});
addLabelClusterLayers(stationData, labelPointLayer);
// 构建图层标题及图例
const getTitle = (text, borderColor, fillColor, isBorderDashed) => {
return `<i style='display:inline-block;border:${isBorderDashed ? "dashed" : "solid"
} 2px ${borderColor};background:${fillColor};width:20px;height:20px;position:relative;top:4px;'></i>
<span style='padding-left:1px;margin-top: 2px;position: relative;top:1px;'>${text}</span>`;
};
// 构建图片形式的标题及图例
const getImageTitle = (text, imgUrl, size) => {
return `<div style='display:inline-block;width:${size}px;height:${size}px;position:relative;top:4px;'><img src='${imgUrl}' style='height:${size}px;'/></div>
<span style='padding-left:1px;margin-top: 2px;position: relative;top:1px;'>${text}</span>`;
};
map.addLayer(baseLayer2); //地图默认加载的底图
map.addLayer(labelPointLayer); //地图默认加载的叠加图层
// 热力图图层创建
const heatmapLayer = new HeatmapOverlay(cfg);
// map.addLayer(heatmapLayer); //地图默认加载的叠加图层
heatmapLayer.setData(heatmapData);
// 地图缩放按钮
// L.control.zoom({
// position: 'topright', // 设置为右下角
// zoomInTitle: '放大',
// zoomOutTitle: '缩小'
// }).addTo(map);
const baseLayers = {
[getImageTitle(`OSM街道图`, `./img/OSMVector.png`, 35)]: baseLayer1,
[getImageTitle(`ArcGIS影像图`, `./img/arcgisImage.png`, 35)]: baseLayer2,
[getImageTitle(`天地图街道图`, `./img/tdtVector.png`, 35)]: baseLayer4,
[getImageTitle(`天地图影像图`, `./img/tdtImage.png`, 35)]: baseLayer5,
[getImageTitle(`高德街道图`, `./img/gaodeVector.png`, 35)]: baseLayer8,
[getImageTitle(`高德街道图`, `./img/gaodeImage.png`, 35)]: baseLayer9,
};
//底图切换控件
// const OHTER_SPOT_COLOR = "#006fff";
// const SPOT_FILL_COLOR = "rgba(0,0,255,0.15)";
// 专题图层
const overlayMaps = {
[getImageTitle(`充电站`, `./img/labelPointMarker.png`, 20)]:
labelPointLayer,
[getImageTitle("热力图", `./img/heatmap.png`, 25)]: heatmapLayer,
};
//底图切换控件
L.control.layers(baseLayers, overlayMaps).addTo(map);
// 框选工具初始化
//绘制工具draw
const customTranslation = {
tooltips: {
finishLine: "单击任何存在的标记或者双击以完成",
finishPoly: "单击第一个标记或者双击完成以完成",
},
};
map.pm.setLang("customName", customTranslation, "zh");
map.pm.addControls({
position: "topleft",
drawMarker: false,
drawCircleMarker: false,
drawCircle: false,
drawPolyline: false,
drawRectangle: false,
drawPolygon: false,
editMode: false,
dragMode: false,
removalMode: false,
cutPolygon: false,
drawText: false,
rotateMode: false,
});
map.on("pm:create", endRectQuery);
};
// 构造地图弹窗内容
const getPopupContent = (properties) => {
return `名称:${properties.name}</br></br>地址:${properties.address}</br></br>类型:${properties.type}</br></br>地区:${properties.adname}</br></br>电话:${properties.tel}</br></br>地理位置:${properties.longitude},${properties.latitude}`;
};
// 搜索结果列表点击定位地图弹窗
const openMapPopup = (properties) => {
const elements = getPopupContent(properties);
const latlng = L.latLng(properties.latitude, properties.longitude);
map.openPopup(elements, latlng);
map.setView(latlng, 15);
}
// 量算工具初始化
let areaMeasure = null;
let distanceMeasure = null;
const initMeasure = () => {
const deleteIcon = L.icon({
iconUrl: shanchu,
iconSize: [16, 16],
});
// 面积测量方法
areaMeasure = {
points: [],
color: "red",
layers: L.layerGroup(),
polygon: null,
marker: null,
init: function () {
areaMeasure.points = [];
areaMeasure.polygon = null;
areaMeasure.marker = null;
map.on("click", areaMeasure.click).on("dblclick", areaMeasure.dblclick);
L.DomUtil.addClass(map._container, 'leaflet-cursor-crosshair');
},
close: function (latlng) {
areaMeasure.marker = L.marker(latlng, { icon: deleteIcon })
.addTo(map)
.on("click", function (e) {
if (areaMeasure.polygon) map.removeLayer(areaMeasure.polygon);
if (areaMeasure.marker) areaMeasure.marker.remove();
});
},
click: function (e) {
map.doubleClickZoom.disable();
// 添加点信息
areaMeasure.points.push(e.latlng);
// 添加面
map.on("mousemove", areaMeasure.mousemove);
},
mousemove: function (e) {
areaMeasure.points.push(e.latlng);
if (areaMeasure.polygon) map.removeLayer(areaMeasure.polygon);
areaMeasure.polygon = L.polygon(areaMeasure.points, {
showMeasurements: true,
color: "red",
});
areaMeasure.polygon.addTo(areaMeasure.layers);
areaMeasure.layers.addTo(map);
areaMeasure.points.pop();
},
dblclick: function (e) {
// 双击结束
// console.log("双击结束", e);
areaMeasure.polygon.addTo(areaMeasure.layers);
areaMeasure.close(e.latlng);
map
.off("click", areaMeasure.click)
.off("mousemove", areaMeasure.mousemove)
.off("dblclick", areaMeasure.dblclick);
L.DomUtil.removeClass(map._container, 'leaflet-cursor-crosshair');
},
destory: function () {
if (areaMeasure.polygon) map.removeLayer(areaMeasure.polygon);
if (areaMeasure.marker) areaMeasure.marker.remove();
L.DomUtil.removeClass(map._container, 'leaflet-cursor-crosshair');
},
};
// 距离测量方法
distanceMeasure = {
points: [],
color: "red",
layers: L.layerGroup(),
polyline: null,
marker: null,
init: function () {
distanceMeasure.points = [];
distanceMeasure.polyline = null;
distanceMeasure.marker = null;
map
.on("click", distanceMeasure.click)
.on("dblclick", distanceMeasure.dblclick);
L.DomUtil.addClass(map._container, 'leaflet-cursor-crosshair');
},
close: function (latlng) {
distanceMeasure.marker = L.marker(latlng, { icon: deleteIcon })
.addTo(map)
.on("click", function (e) {
if (distanceMeasure.polyline)
map.removeLayer(distanceMeasure.polyline);
if (distanceMeasure.marker) distanceMeasure.marker.remove();
});
},
click: function (e) {
map.doubleClickZoom.disable();
// 添加点信息
distanceMeasure.points.push(e.latlng);
// 添加线
map.on("mousemove", distanceMeasure.mousemove);
},
mousemove: function (e) {
distanceMeasure.points.push(e.latlng);
if (distanceMeasure.polyline) map.removeLayer(distanceMeasure.polyline);
distanceMeasure.polyline = L.polyline(distanceMeasure.points, {
showMeasurements: true,
color: "red",
});
distanceMeasure.polyline.addTo(distanceMeasure.layers);
distanceMeasure.layers.addTo(map);
distanceMeasure.points.pop();
},
dblclick: function (e) {
// 双击结束
// console.log("双击结束", e);
distanceMeasure.polyline.addTo(distanceMeasure.layers);
distanceMeasure.close(e.latlng);
map
.off("click", distanceMeasure.click)
.off("mousemove", distanceMeasure.mousemove)
.off("dblclick", distanceMeasure.dblclick);
L.DomUtil.removeClass(map._container, 'leaflet-cursor-crosshair');
},
destory: function () {
if (distanceMeasure.polyline) map.removeLayer(distanceMeasure.polyline);
if (distanceMeasure.marker) distanceMeasure.marker.remove();
L.DomUtil.removeClass(map._container, 'leaflet-cursor-crosshair');
},
};
}
// 测距
const distanceMeasureFun = () => {
distanceMeasure.destory();
distanceMeasure.init();
}
// 测面
const areaMeasureFun = () => {
areaMeasure.destory();
areaMeasure.init();
}
// 清空
const clearFun = () => {
distanceMeasure.destory();
areaMeasure.destory();
if (geojsonLayer) {
map.removeLayer(geojsonLayer);
geojsonLayer = null;
}
}
// 复位
const resetFun = () => {
map.setView(config.mapInitParams.center, config.mapInitParams.zoom);
}
// 查询搜索模块
const clearQuery = () => {
clearQueryResult();
}
const queryFun = async () => {
try {
if (!keyword.value) {
ElMessage({
message: '搜索框中请输入关键字',
type: 'warning',
})
return;
}
// 使用 fetch API 发起请求并等待响应
const response = await fetch(`${searchApi}?name=${keyword.value}`);
// 检查响应状态是否成功
if (!response.ok) {
throw new Error('网络响应异常');
}
// 将响应解析为 JSON 并等待结果
const dataList = await response.json();
// 处理 JSON 数据
queryData.value = dataList.features.map((item) => {
const properties = item.properties;
return {
name: properties.name,
address: properties.address,
type: properties.type,
adname: properties.adname,
tel: properties.tel,
longitude: properties.longitude,
latitude: properties.latitude
};
});
isShowResult.value = true;
// console.log(heatmapData);
} catch (error) {
queryData.value = [];
ElMessage({
message: '搜索查询异常',
type: 'warning',
})
// 处理错误
console.error('错误异常:', error);
}
}
// 框选查询搜索
const rectQueryFun = async () => {
//绘制矩形
map.pm.enableDraw("Rectangle", {
finishOn: "dblclick",
allowSelfIntersection: false,
tooltips: false,
});
}
const endRectQuery = async (e) => {
if (geojsonLayer) {
map.removeLayer(geojsonLayer);
geojsonLayer = null;
}
geojsonLayer = e.layer;
geojsonLayer.addTo(map);
const northEast = e.layer.getBounds()._northEast;
const southWest = e.layer.getBounds()._southWest;
try {
// 使用 fetch API 发起请求并等待响应
const response = await fetch(`${rectSearchApi}?swLng=${southWest.lng}&swLat=${southWest.lat}&neLng=${northEast.lng}&neLat=${northEast.lat}`);
// 检查响应状态是否成功
if (!response.ok) {
throw new Error('网络响应异常');
}
// 将响应解析为 JSON 并等待结果
const dataList = await response.json();
// 处理 JSON 数据
queryData.value = dataList.features.map((item) => {
const properties = item.properties;
return {
name: properties.name,
address: properties.address,
type: properties.type,
adname: properties.adname,
tel: properties.tel,
longitude: properties.longitude,
latitude: properties.latitude
};
});
isShowResult.value = true;
} catch (error) {
queryData.value = [];
ElMessage({
message: '框选查询异常',
type: 'warning',
})
// 处理错误
console.error('错误异常:', error);
}
}
const clearQueryResult = () => {
queryData.value = [];
isShowResult.value = false;
if (geojsonLayer) {
map.removeLayer(geojsonLayer);
geojsonLayer = null;
}
}
// 自定义图标
const customIcon = L.icon({
iconUrl: './public/img/labelPointMarker.png', // 图标图片路径
iconSize: [30, 30], // 图标大小(宽, 高)
});
/*
* 加载标注点聚合图层
*/
const addLabelClusterLayers = async (geojson, clusterlayer) => {
let markerList = [];
if (geojson.features.length > 0) {
for (let i = 0; i < geojson.features.length; i++) {
let marker = L.marker(
new L.LatLng(
geojson.features[i].geometry.coordinates[1],
geojson.features[i].geometry.coordinates[0]
),
{
properties: geojson.features[i].properties,
icon: customIcon // marker点图标
}
);
markerList.push(marker);
}
}
clusterlayer.addLayers(markerList);
};
// 统计图表初始化
const initCharts = () => {
// 各区县充电站数量柱状图
initOneChart();
// 各区县充电站数量折线图
initTwoChart();
// 充电站不同类型饼状图
initThreeChart();
}
// 各区县充电站数量柱状图
const initOneChart = () => {
// 基于准备好的dom,初始化echarts实例
const myChart = echarts.init(document.getElementById('echart1'));
const option = {
// backgroundColor: '#00265f',
title: {
text: '各区县充电站数量柱状图',
left: 'center',
// left: '1%',
top: '3%',
textStyle: {
color: '#fff',
fontSize: '16',
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
backgroundColor: 'rgba(0, 0, 0, 0.35)', // 提示框背景颜色
textStyle: {
color: '#fff', // 提示框文本颜色
fontSize: 14, // 文本字体大小
// fontFamily: 'Arial' // 文本字体
},
// borderColor: '#000', // 设置Tooltip边框颜色为黑色
borderWidth: 0, // 设置Tooltip边框宽度为2像素
},
grid: {
left: '3%',
top: '12%',
right: '3%',
bottom: '3%',
containLabel: true
},
xAxis: [{
type: 'category',
data: echartsData1.xAxis,
axisLine: {
show: true,
lineStyle: {
color: "rgba(255,255,255,.1)",
width: 1,
type: "solid"
},
},
axisTick: {
show: false,
},
axisLabel: {
interval: 0,
// rotate:50,
show: true,
splitNumber: 15,
textStyle: {
color: "rgba(255,255,255,.6)",
fontSize: '12',
},
},
}],
yAxis: [{
type: 'value',
axisLabel: {
//formatter: '{value} %'
show: true,
textStyle: {
color: "rgba(255,255,255,.6)",
fontSize: '12',
},
},
axisTick: {
show: false,
},
axisLine: {
show: true,
lineStyle: {
color: "rgba(255,255,255,.1 )",
width: 1,
type: "solid"
},
},
splitLine: {
lineStyle: {
color: "rgba(255,255,255,.1)",
}
}
}],
series: [
{
type: 'bar',
// name:'阵风速',
data: echartsData1.yAxis,
barWidth: '35%', //柱子宽度
// barGap: 1, //柱子之间间距
itemStyle: {
normal: {
color: '#2f89cf',
opacity: 1,
barBorderRadius: 5,
}
},
tooltip: {
valueFormatter: function (value) {
return value + ' 个';
}
}
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
window.addEventListener("resize", function () {
myChart.resize();
});
}
// 各区县充电站数量折线图
const initTwoChart = () => {
// 基于准备好的dom,初始化echarts实例
const myChart = echarts.init(document.getElementById('echart2'));
const option = {
title: {
text: '各区县充电站数量折线图',
left: 'center',
// left: '1%',
top: '3%',
textStyle: {
color: '#fff',
fontSize: '16',
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: {
color: '#dddc6b'
}
},
backgroundColor: 'rgba(0, 0, 0, 0.35)', // 提示框背景颜色
textStyle: {
color: '#fff', // 提示框文本颜色
fontSize: 14, // 文本字体大小
// fontFamily: 'Arial' // 文本字体
},
// borderColor: '#000', // 设置Tooltip边框颜色为黑色
borderWidth: 0, // 设置Tooltip边框宽度为2像素
},
grid: {
left: '3%',
top: '12%',
right: '3%',
bottom: '3%',
containLabel: true
},
xAxis: [{
type: 'category',
// boundaryGap: false,
data: echartsData1.xAxis,
axisLabel: {
interval: 0,
textStyle: {
color: "rgba(255,255,255,.6)",
fontSize: 12,
},
},
axisLine: {
lineStyle: {
color: 'rgba(255,255,255,.2)'
}
},
}],
yAxis: [{
type: 'value',
axisTick: { show: false },
axisLine: {
lineStyle: {
color: 'rgba(255,255,255,.1)'
}
},
axisLabel: {
textStyle: {
color: "rgba(255,255,255,.6)",
fontSize: 12,
},
},
splitLine: {
lineStyle: {
color: 'rgba(255,255,255,.1)'
}
}
}],
series: [
{
// name: '流速',
type: 'line',
data: echartsData1.yAxis,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
smooth: true,
lineStyle: {
normal: {
color: '#0184d5',
width: 2
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(1, 132, 213, 0.4)'
}, {
offset: 0.8,
color: 'rgba(1, 132, 213, 0.1)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
}
},
itemStyle: {
normal: {
color: '#0184d5',
borderColor: 'rgba(221, 220, 107, .1)',
borderWidth: 12
}
},
tooltip: {
valueFormatter: function (value) {
return value + ' 个';
}
}
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
window.addEventListener("resize", function () {
myChart.resize();
});
}
// 充电站不同类型饼状图
const initThreeChart = () => {
// 基于准备好的dom,初始化echarts实例
const myChart = echarts.init(document.getElementById('echart3'));
const option = {
title: [{
text: '充电站不同类型饼状图',
left: 'center',
top: '3%',
textStyle: {
color: '#fff',
fontSize: '16'
}
}],
tooltip: {
trigger: 'item',
formatter: "{a} <br/>{b}: {c} ({d}%)",
position: function (p) { //其中p为当前鼠标的位置
return [p[0] + 10, p[1] - 10];
},
backgroundColor: 'rgba(0, 0, 0, 0.35)', // 提示框背景颜色
textStyle: {
color: '#fff', // 提示框文本颜色
fontSize: 14, // 文本字体大小
// fontFamily: 'Arial' // 文本字体
},
// borderColor: '#000', // 设置Tooltip边框颜色为黑色
borderWidth: 0, // 设置Tooltip边框宽度为2像素
},
legend: {
bottom: '10%',
itemWidth: 10,
itemHeight: 10,
data: ['充电站', '换电站'],
textStyle: {
color: 'rgba(255,255,255,.5)',
fontSize: '12',
}
},
series: [
{
name: '充电站类型',
type: 'pie',
top: '10%',
center: ['50%', '42%'],
radius: ['40%', '60%'],
color: ['#065aab', '#00d887', '#066eab', '#0682ab', '#0696ab', '#06a0ab', '#06b4ab', '#06c8ab', '#06dcab', '#06f0ab'],
label: { show: false },
labelLine: { show: false },
data: echartsData2
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
window.addEventListener("resize", function () {
myChart.resize();
});
}
</script>