Newer
Older
garbageClassificationFront / src / views / overview / overview.vue
<!--
 * @Description: 总览地图
 * @Author: 王晓颖
 * @Date:2021-01-12 09:59:26
 -->
<template>
  <div class="container">
    <!--数量整体显示-->
    <div class="top-board">
      <div class="board-div">
        <div class="board-div-value">
          {{ wastebinCount }}
        </div>
        <div class="board-div-title">
          垃圾桶
        </div>
      </div>
      <el-divider direction="vertical"/>
      <div class="board-div">
        <div class="board-div-value">
          {{ classificationCount }}
        </div>
        <div class="board-div-title">
          分类箱
        </div>
      </div>
      <div v-show="area!==''">
        <el-divider direction="vertical"/>
      </div>
      <div v-show="area" class="board-div">
        <div class="board-div-value">
          {{ area }} km²
        </div>
        <div class="board-div-title">
          面积
        </div>
      </div>
    </div>
    <!--工具箱-->
    <tools-container>
      <!-- 绘制工具-->
      <draw-tool @click="drawBox" @clear="clearDraw"/>
    </tools-container>
    <!--地图-->
    <map-view @ready="mapInit">
      <!--设施显示-->
      <div>
        <div v-if="wastebinShow">
          <l-marker v-for="(wastebin,index) in wastebins" :key="'wastebin'+index" :icon="wastebinIcon" :lat-lng="wastebin.latlng" @click="openPopup($event,'wastebin',wastebin)">
            <l-popup @ready="fetchWastebinDetail">
              <popwindow :data="currentData" type="wastebin"/>
            </l-popup>
          </l-marker>
        </div>
        <div v-if="classificationShow">
          <l-marker v-for="(classification,index) in classifications" :key="'classification'+index" :icon="classificationIcon" :lat-lng="classification.latlng" @click="openPopup($event,'classification',classification)">
            <l-popup @ready="fetchClassificationDetail">
              <popwindow :data="currentData" type="classification"/>
            </l-popup>
          </l-marker>
        </div>
      </div>
    </map-view>
  </div>
</template>

<script>
import MapView from '@/views/mapViews/mapView'
import * as L from 'leaflet'
import { LMarker, LIcon, LPopup } from 'vue2-leaflet'
import Popwindow from './components/popwindow'
import { getWastebinList } from '@/api/biz/wastebin'
import ToolsContainer from './components/toolsContainer'
import DrawTool from './components/drawTool'
import 'leaflet.pm'
import 'leaflet.pm/dist/leaflet.pm.css'
import * as turf from '@turf/turf'
export default {
  name: 'MapOverview',
  components: { DrawTool, ToolsContainer, Popwindow, MapView, LMarker, LIcon, LPopup },
  data() {
    return {
      map: null, // 地图
      drawLayer: null, // 绘制图层
      wastebins: [], // 垃圾桶列表
      classifications: [], // 垃圾中转站列表
      wastebinCount: 0,
      classificationCount: 0,
      wastebinIcon: L.icon({
        iconUrl: require('@/assets/overview/wastebin.png'),
        iconSize: [32, 32],
        iconAnchor: [16, 32]
      }), // 垃圾桶图标
      classificationIcon: L.icon({
        iconUrl: require('@/assets/overview/classification.png'),
        iconSize: [32, 32],
        iconAnchor: [16, 32]
      }), // 分类箱图标
      wastebinShow: true, // 垃圾桶是否显示
      classificationShow: true, // 分类箱是否显示
      currentData: {}, // 当前弹窗数据
      area: '' // 选区面积
    }
  },
  created() {
    this.getWastebins()
  },
  methods: {
    // 地图初始化完毕
    mapInit(map) {
      this.map = map
      this.map.pm.setLang('zh')
    },
    // 获取垃圾桶列表
    getWastebins: function() {
      // this.wastebins = [
      //   { id: '12346', name: '李四', latlng: [27.73252, 116.05321], lng: 27.73252, lat: 116.05321, sex: '0', tel: '13382739123', type: '0', typeName: '普通职工', post: '1', jobs: '0', responseArea: '崇仁县', responseAreaName: '崇仁县' },
      //   { id: '12347', name: '王五', latlng: [27.72852, 116.03721], lng: 27.72852, lat: 116.03721, sex: '0', tel: '13382739123', type: '0', typeName: '普通职工', post: '1', jobs: '1', responseArea: '崇仁县', responseAreaName: '崇仁县' }
      // ]
      const params = {
        offset: 1,
        limit: 200,
        sort: '',
        order: 'desc'
      }
      getWastebinList(params).then(response => {
        if (response.code === 200) {
          this.wastebins = response.data.filter(item => item.isClassification === 0)
          this.wastebins = this.wastebins.map(item => {
            return {
              ...item,
              latlng: [parseFloat(item.lat), parseFloat(item.lng)]
            }
          })
          this.wastebinCount = this.wastebins.length
          this.classifications = response.data.filter(item => item.isClassification === 1)
          this.classifications = this.classifications.map(item => {
            return {
              ...item,
              latlng: [parseFloat(item.lat), parseFloat(item.lng)]
            }
          })
          this.classificationCount = this.classifications.length
        }
      })
    },
    // 获取垃圾桶详情
    fetchWastebinDetail(data) {
      this.currentData = data
    },
    // 获取分类箱详情
    fetchClassificationDetail(data) {
      this.currentData = data
    },
    // 打开弹窗
    async openPopup(event, type, data) {
      switch (type) {
        case 'wastebin':
          await this.fetchWastebinDetail(data)
          break
        case 'classification':
          await this.fetchClassificationDetail(data)
          break
      }
      this.$nextTick(() => {
        event.target.openPopup()
      })
    },
    // 移除绘制图层
    drawDelete() {
      if (this.drawLayer) {
        this.drawLayer.layer.remove()
      }
      if (this.map.graphics) {
        this.map.graphics.forEach(graphic => {
          this.map.removeLayer(graphic.layer)
        })
      }
    },
    // 绘制选框
    drawBox(type) {
      console.log(this.map)
      this.drawDelete()
      this.$nextTick(() => {
        this.map.pm.enableDraw(type, {
          snappable: false
        })
        // 绘制完成
        this.map.on('pm:create', e => {
          this.drawLayer = e
          // debugger
          // 计算面积
          var area
          if (e.shape === 'Circle') {
            // 计算面积
            const radius = e.layer.options.radius
            const latlng = e.layer.getLatLng()
            area = 3.1415926 * radius * radius
            this.area = (area / 1000000).toFixed(2)
            const circle = turf.circle([latlng.lng, latlng.lat], radius / 1000)
            // 依次判断点的存在
            let wastbinCount = 0
            for (const wastbin of this.wastebins) {
              if (this.judgePointInCircle(wastbin, circle)) {
                wastbinCount++
              }
            }
            let classificationCount = 0
            for (const wastbin of this.classifications) {
              if (this.judgePointInCircle(wastbin, circle)) {
                classificationCount++
              }
            }
            this.wastebinCount = wastbinCount
            this.classificationCount = classificationCount
          } else {
            // 获取选区的geojson, 用turf计算面积
            const geojson = e.layer.toGeoJSON()
            area = turf.area(geojson)
            let wastbinCount = 0
            for (const wastbin of this.wastebins) {
              if (this.judgePointInPolygon(wastbin, geojson)) {
                wastbinCount++
              }
            }
            let classificationCount = 0
            for (const wastbin of this.classifications) {
              if (this.judgePointInPolygon(wastbin, geojson)) {
                classificationCount++
              }
            }
            this.wastebinCount = wastbinCount
            this.classificationCount = classificationCount
          }
          this.area = (area / 1000000).toFixed(2)
          console.log('面积' + area.toString())
          // 计算区域内的垃圾桶和分类箱个数
        })
      })
    },
    judgePointInPolygon(p, geojson) {
      // 1. 点
      const point = turf.point([p.latlng[1], p.latlng[0]])
      // 2. 多边形
      const polygon = geojson.geometry
      const result = turf.booleanPointInPolygon(point, polygon)
      if (result) {
        console.log('is in polygon')
      }
      return result
    },
    // 判断点是否在圆里
    judgePointInCircle(p, circle) {
      // 1. 点
      const point = turf.point([p.latlng[1], p.latlng[0]])
      const result = turf.booleanPointInPolygon(point, circle)
      if (result) {
        console.log('is in circle')
      }
      return result
    },
    // 清除绘制
    clearDraw() {
      if (this.drawLayer) {
        this.drawDelete()
      } else {
        this.map.pm.toggleGlobalRemovalMode()
      }
      this.area = ''
      this.wastebinCount = this.wastebins.length
      this.classificationCount = this.classifications.length
    }
  }
}
</script>

<style rel="stylesheet/scss" lang="scss" scoped>
.container{
  width: 100%;
  height: calc(100vh - 150px);
  position: relative;
  .top-board{
    height: 100px;
    min-width:250px;
    background-color: #ffffff;
    position: absolute;
    z-index:1001;
    top:10px;
    left:10px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding:12px;
    .board-div{
      min-width: 80px;
      font-size:19px;
      text-align: center;
      .board-div-value{
        padding-bottom: 10px;
      }
      .board-div-title{
        font-size:17px;
      }
    }
  }
  .legend-group{
    position:absolute;
    z-index:3000;
    bottom: 0px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    justify-content: center;
    background: rgba(82, 82, 82, 0.6);
    width:100%;
    padding:10px 10px;
    .legend-div{
      display:flex;
      align-items: center;
      margin-right: 20px;
      .legend-icon{
        img{
          width:32px;
          height:32px;
          margin-right: 10px;
        }
        .grey-img{
          -webkit-filter: grayscale(100%);
          -moz-filter: grayscale(100%);
          -ms-filter: grayscale(100%);
          -o-filter: grayscale(100%);
          filter: grayscale(100%);
          filter: gray;
        }
      }
      .legend-text{
        line-height: 32px;
        color:white;
        font-weight: bold;
        font-size:0.9rem;

      }
    }
    .legend-div:hover{
      cursor:pointer;
    }
  }
}
</style>