vue3+leaflet案例:南京市充电站可视化平台(附源码下载)

基于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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GIS之家

赠人玫瑰,手有余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值