范围点位过滤

本章介绍地图组件的范围点位的图层过滤

范围图层过滤

🔹海安市政府 🔹
🔹书香园小区 🔹
🔹江苏省海安高级中学 🔹
🔹王府大酒店 🔹
🔹智达教育(海安校区) 🔹
🔹123 🔹
图层
地图
<template>
  <div style="position: relative; width: 100%; height: 500px; overflow: hidden">
    <minemap
      ref="mineMapRef"
      map-dom-id="build-filter"
      :map2D3D="map2D3D"
      :map-edit-data="mapEditDataFilter"
      :point-build-list="pointBuildListFilter"
      :alarm-point-list="alarmPointList"
      :get-message-popupBg="getMessagePopupBg"
      @closeWarningPopup="closeWarningPopup"
    />
    <div class="map-options">
      <div class="options-type">
        <div>
          <i class="iconfont icon-tuceng mr-xs" />
          <span class="inline vt-middle">图层</span>
        </div>
        <div>
          <Dropdown trigger="click" transfer @on-click="switchMap">
            <i class="iconfont icon-ditu mr-xs" />
            <span class="inline vt-middle">地图</span>
            <template #list>
              <DropdownMenu>
                <DropdownItem name="2D">
                  <i class="iconfont icon-wanggekai mr-xs" />
                  <span class="inline vt-middle">二维</span>
                </DropdownItem>
                <DropdownItem name="3D">
                  <i class="iconfont icon-d mr-xs" />
                  <span class="inline vt-middle">三维</span>
                </DropdownItem>
              </DropdownMenu>
            </template>
          </Dropdown>
        </div>
      </div>

      <div class="options-detail">
        <div class="options-content layer" v-show="activeOption === 'layer'">
          <div class="layer-border top-left" />
          <div class="layer-border top-right" />
          <div class="layer-border bottom-left" />
          <div class="layer-border bottom-right" />
          <div class="all-layer">
            <Checkbox
              :indeterminate="indeterminate"
              :model-value="checkAllLayer"
              @on-change="handleCheckAllLayer"
            >
              <span style="color: #fff">全部图层</span>
            </Checkbox>
          </div>
          <Checkbox
            class="option-item"
            v-for="(layer, index) in layerTypeList"
            :key="index"
            v-model="layer.checked"
            @on-change="(val) => checkLayerChange(val, layer)"
          >
            <img class="layer-icon" v-if="layer.icon" :src="layer.icon" />
            <span v-else class="layer-sign" :style="{ backgroundColor: layer.color }" />
            <span style="color: #fff">{{ layer.layerName }}</span>
          </Checkbox>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
  import { ref, reactive } from 'vue';
  import minemap from './components/index.vue';

  import { deepCopy } from '@web-basic-doc/utils';
  import {
    mapEditDataMock,
    pointBuildListMock,
    alarmPointListMock,
    layerTypeListMock,
  } from './example.mock';

  const mineMapRef = ref(null);

  let activeOption = ref('layer');

  // 全选图层状态
  let checkAllLayer = ref(true);
  // 全选图层半选状态
  let indeterminate = ref(false);

  // 地图处于2D还是3D
  let map2D3D = ref('3D');

  const layerTypeList = reactive(layerTypeListMock);

  const mapEditData = mapEditDataMock;

  const pointBuildList = pointBuildListMock;

  const alarmPointList = ref(alarmPointListMock);

  let mapEditDataFilter = ref(deepCopy(mapEditDataMock));

  let pointBuildListFilter = ref(deepCopy(pointBuildListMock));

  // 转换地图2D3D
  const switchMap = (type) => {
    map2D3D.value = type;
  };

  // 全选/取消全选 所有图层分类
  const handleCheckAllLayer = (val) => {
    mineMapRef.value.messagePopupRef.length = 0;
    if (val) {
      checkAllLayer.value = true;
      indeterminate.value = false;
      layerTypeList.forEach((layer) => {
        layer.checked = true;
      });
      // 建筑图层
      if (pointBuildList.length) {
        pointBuildListFilter.value = deepCopy(pointBuildList);
      }
      // 编辑池图层
      if (map2D3D.value === '3D' && mapEditData.length) {
        mapEditDataFilter.value = deepCopy(mapEditData);
        mineMapRef.value.addFence(mapEditDataFilter.value);
      }
    } else {
      checkAllLayer.value = false;
      indeterminate.value = false;
      layerTypeList.forEach((layer) => {
        layer.checked = false;
        removePrimitiveByLayer(layer);
      });
      pointBuildListFilter.value = [];
      mapEditDataFilter.value = [];
    }
    if (alarmPointList.value.length) {
      checkWarningPopup(val);
    }
  };

  // 点选报警弹框图层
  const checkWarningPopup = (val) => {
    if (val) {
      mineMapRef.value.addAlarmMarker(alarmPointList.value);
    } else {
      alarmPointList.value.forEach((row) => {
        mineMapRef.value.closeWarningPopup(row.id, { isRemove: false });
      });
    }
  };

  const closeWarningPopup = (pointId) => {
    const index = alarmPointList.value.findIndex((point) => point.id === pointId);
    if (index !== -1) {
      alarmPointList.value.splice(index, 1);
    }
  };

  const checkLayerChange = (val, layer) => {
    if (layer.layerType === 'warningInfo') {
      checkWarningPopup(val);
      return;
    }
    // 点选其他图层
    mineMapRef.value.messagePopupRef.length = 0;
    const checkedLayer = layerTypeList.filter((row) => row.checked);
    // 全选的情况下
    if (checkedLayer.length === layerTypeList.length) {
      indeterminate.value = false;
      checkAllLayer.value = true;
      pointBuildListFilter.value = deepCopy(pointBuildList);
      mapEditDataFilter.value = deepCopy(mapEditData);
      // 区域范围
      if (map2D3D.value === '3D' && mapEditData.length) {
        const addEditList = mapEditData.filter((edit) => edit.kind === layer.layerType);
        mineMapRef.value.addFence(addEditList);
      }

      // 没有全选的情况下
    } else if (checkedLayer.length > 0) {
      indeterminate.value = true;
      checkAllLayer.value = false;
      if (val) {
        // 建筑点位加载
        if (pointBuildList.length) {
          pointBuildListFilter.value = pointBuildList.filter(
            (point) => checkedLayer.findIndex((row) => row.layerType === point.kind) !== -1,
          );
        }

        // 区域范围
        if (mapEditData.length) {
          mapEditDataFilter.value = mapEditData.filter(
            (edit) => checkedLayer.findIndex((row) => row.layerType === edit.kind) !== -1,
          );
          if (map2D3D.value === '3D') {
            mineMapRef.value.addFence(mapEditDataFilter.value);
          }
        }
      } else {
        // 移除点位
        if (pointBuildList.length) {
          const removePointList = pointBuildListFilter.value.filter(
            (point) => point.kind === layer.layerType,
          );
          removePointList.forEach((removePoint) => {
            const pointIndex = pointBuildListFilter.value.findIndex(
              (point) => point.id === removePoint.id,
            );
            pointIndex !== -1 && pointBuildListFilter.value.splice(pointIndex, 1);
          });
        }

        // 移除围栏
        removePrimitiveByLayer(layer);
        if (mapEditData.length) {
          // 移除框选范围
          const removeEditList = mapEditDataFilter.value.filter(
            (edit) => edit.kind === layer.layerType,
          );
          removeEditList.forEach((removeEdit) => {
            const editIndex = mapEditDataFilter.value.findIndex(
              (edit) => edit.id === removeEdit.id,
            );
            mapEditDataFilter.value.splice(editIndex, 1);
          });
        }
      }
      // 全不选的情况下
    } else {
      indeterminate.value = false;
      checkAllLayer.value = false;
      removePrimitiveByLayer(layer);
      pointBuildListFilter.value = [];
      mapEditDataFilter.value = [];
    }
  };

  // 找到对应的围栏的Primitive并移除
  const removePrimitiveByLayer = (layer) => {
    if (map2D3D.value === '3D' && mapEditData.length) {
      const editData = mapEditData.filter((edit) => edit.kind === layer.layerType);
      editData.forEach((edit) => {
        mineMapRef.value.removePrimitiveById(edit.id);
      });
    }
  };

  const getMessagePopupBg = (point) => {
    return point.kind;
  };
</script>

<style lang="scss" scoped>
  .map-options {
    position: absolute;
    top: 10px;
    right: 20px;
    z-index: 3;

    .options-type {
      display: flex;
      width: 210px;
      height: 30px;
      color: #fff;
      background-color: rgb(8 86 189 / 40%);
      justify-content: space-between;
      align-items: center;

      > div {
        position: relative;
        display: flex;
        width: 33.33%;
        cursor: pointer;
        align-items: center;
        justify-content: center;

        &:hover {
          color: #1acbfe;
        }
      }
    }

    .options-detail {
      position: relative;
      margin-top: 15px;
      color: #fff;
      background-color: transparent;

      .layer-border {
        position: absolute;
        width: 17px;
        height: 17px;

        &.top-left {
          top: -6px;
          left: -6px;
          border-top: 2px solid #14ccff;
          border-left: 2px solid #14ccff;
        }

        &.top-right {
          top: -6px;
          right: -6px;
          border-top: 2px solid #14ccff;
          border-right: 2px solid #14ccff;
        }

        &.bottom-left {
          bottom: -6px;
          left: -6px;
          border-bottom: 2px solid #14ccff;
          border-left: 2px solid #14ccff;
        }

        &.bottom-right {
          right: -6px;
          bottom: -6px;
          border-right: 2px solid #14ccff;
          border-bottom: 2px solid #14ccff;
        }
      }

      .options-content {
        background-color: rgb(2 11 44 / 70%);
        border: 1px solid #083d7d;
        box-shadow: inset 0 0 20px rgb(0 85 255 / 50%);
      }

      .all-layer {
        position: relative;
        display: flex;
        height: 44px;
        padding: 0 15px;
        border-bottom: 1px solid rgb(6 128 251 / 40%);
        align-items: center;

        &::after,
        &::before {
          position: absolute;
          right: 0;
          bottom: 0;
          display: inline-block;
          width: 10px;
          height: 1px;
          background-color: #0680fb;
          content: '';
        }

        &::before {
          left: 0;
        }
      }

      .option-item {
        display: flex;
        height: 40px;
        padding: 0 15px;
        align-items: center;

        :deep(.ivu-checkbox-label-text) {
          display: flex;
          justify-content: center;
          align-items: center;
        }

        .layer-sign {
          display: inline-block;
          width: 26px;
          height: 2px;
          margin-right: 10px;
          margin-left: 5px;
          border-radius: 1px;
        }

        .layer-icon {
          width: 26px;
          height: 30px;
          margin-right: 10px;
          margin-left: 5px;
        }
      }
    }
  }
</style>

example.mock.js

点击查看
import redFence from '/images/map/minemap/red-fence.png';
import greenFence from '/images/map/minemap/green-fence.png';
import blueFence from '/images/map/minemap/blue-fence.png';
import warningPosition from '/images/map/minemap/warning-position.png';

const mapEditDataMock = [
  {
    id: 1,
    type: 'Feature',
    kind: 'red',
    properties: {
      lineColor: '#F61C35',
      fillColor: '#F61C35',
      fillOpacity: 0.2,
      fillOutlineColor: '#F61C35',
      fillOutlineWidth: 2,
      isLock: true,
      custom_style: 'true',
    },
    geometry: {
      type: 'Polygon',
      coordinates: [
        [
          [120.465828, 32.533069],
          [120.468515, 32.534381],
          [120.46998, 32.532282],
          [120.467324, 32.530908],
          [120.465828, 32.533069],
        ],
      ],
    },
    fenceImgUrl: redFence,
  },
  {
    id: 2,
    type: 'Feature',
    kind: 'green',
    properties: {
      lineColor: '#49FBD3',
      fillColor: '#49FBD3',
      fillOpacity: 0.2,
      fillOutlineColor: '#49FBD3',
      fillOutlineWidth: 2,
      isLock: true,
      custom_style: 'true',
    },
    geometry: {
      type: 'Polygon',
      coordinates: [
        [
          [120.466307, 32.537685],
          [120.469146, 32.539252],
          [120.469523, 32.53875],
          [120.469523, 32.53875],
          [120.471136, 32.538194],
          [120.467354, 32.536174],
          [120.466307, 32.537685],
        ],
      ],
    },
    fenceImgUrl: greenFence,
  },
  {
    id: 3,
    type: 'Feature',
    kind: 'blue',
    properties: {
      lineColor: '#37E5FF',
      fillColor: '#37E5FF',
      fillOpacity: 0.2,
      fillOutlineColor: '#37E5FF',
      fillOutlineWidth: 2,
      isLock: true,
      custom_style: 'true',
    },
    geometry: {
      type: 'Polygon',
      coordinates: [
        [
          [120.46706, 32.556076],
          [120.469683, 32.55657],
          [120.4713, 32.55479],
          [120.467761, 32.554341],
          [120.46706, 32.556076],
        ],
      ],
    },
    fenceImgUrl: blueFence,
  },
  {
    id: 4,
    type: 'Feature',
    kind: 'blue',
    properties: {
      lineColor: '#37E5FF',
      fillColor: '#37E5FF',
      fillOpacity: 0.2,
      fillOutlineColor: '#37E5FF',
      fillOutlineWidth: 2,
      isLock: true,
      custom_style: 'true',
    },
    geometry: {
      type: 'Polygon',
      coordinates: [
        [
          [120.490838, 32.538595],
          [120.491557, 32.538888],
          [120.491611, 32.538439],
          [120.491103, 32.538237],
          [120.490838, 32.538595],
        ],
      ],
    },
    fenceImgUrl: blueFence,
  },
  {
    id: 5,
    type: 'Feature',
    kind: 'blue',
    properties: {
      lineColor: '#37E5FF',
      fillColor: '#37E5FF',
      fillOpacity: 0.2,
      fillOutlineColor: '#37E5FF',
      fillOutlineWidth: 2,
      isLock: true,
      custom_style: 'true',
    },
    geometry: {
      type: 'Polygon',
      coordinates: [
        [
          [120.47087, 32.537774],
          [120.471112, 32.537877],
          [120.471413, 32.537302],
          [120.471413, 32.537302],
          [120.47087, 32.537774],
        ],
      ],
    },
    fenceImgUrl: blueFence,
  },
  {
    id: 7,
    type: 'Feature',
    kind: 'red',
    properties: {
      lineColor: '#F61C35',
      fillColor: '#F61C35',
      fillOpacity: 0.2,
      fillOutlineColor: '#F61C35',
      fillOutlineWidth: 2,
      isLock: true,
      custom_style: 'true',
    },
    geometry: {
      coordinates: [
        [
          [120.46610539854002, 32.53577955594519],
          [120.46610539854002, 32.53107386514961],
          [120.47901921613597, 32.53107386514961],
          [120.47901921613597, 32.53577955594519],
          [120.46610539854002, 32.53577955594519],
        ],
      ],
      type: 'Polygon',
    },
    fenceImgUrl: redFence,
  },
];

const pointBuildListMock = [
  {
    id: 1,
    title: '海安市政府',
    kind: 'red',
    lng: 120.467735,
    lat: 32.532712,
    icon: 'redPoint',
  },
  {
    id: 2,
    title: '书香园小区',
    kind: 'green',
    lng: 120.468946,
    lat: 32.537649,
    icon: 'greenPoint',
  },
  {
    id: 3,
    title: '江苏省海安高级中学',
    kind: 'blue',
    lng: 120.468851,
    lat: 32.555493,
    icon: 'bluePoint',
  },
  {
    id: 4,
    title: '王府大酒店',
    kind: 'blue',
    lng: 120.491374,
    lat: 32.538508,
    icon: 'bluePoint',
  },
  {
    id: 5,
    title: '智达教育(海安校区)',
    kind: 'blue',
    lng: 120.471218,
    lat: 32.537631,
    icon: 'bluePoint',
  },
  {
    id: 7,
    title: '123',
    kind: 'red',
    lng: 120.472562307338,
    lat: 32.5334267105474,
    icon: 'redPoint',
  },
];

const alarmPointListMock = [
  {
    lnglat: [120.456101, 32.53736],
    id: '1',
    title: `一级`,
    similarity: 85.5,
    alarmLevel: '一级',
    name: '陶尚华',
    taskLibName: '人脸测试布控库001',
    alarmTime: '2023-11-23 09:24:09',
    deviceName: 'B_QN1077延安路东南(结构化2)_(一期)',
    alarmPicUrl: '/images/map/minemap/default-photo.png',
    taskPicUrl: '/images/map/minemap/default-photo.png',
    messageType: 'faceAlarms',
  },
];

const layerTypeListMock = [
  { layerName: '蓝色图层', layerType: 'blue', color: '#37E5FF', checked: true },
  { layerName: '红色图层', layerType: 'red', color: '#FF7979', checked: true },
  { layerName: '绿色图层', layerType: 'green', color: '#49FBD3', checked: true },
  { layerName: '预警信息', layerType: 'warningInfo', icon: warningPosition, checked: true },
];

export { mapEditDataMock, pointBuildListMock, alarmPointListMock, layerTypeListMock };


上次更新:
贡献者: zml