Newer
Older
urbanLifeline_YanAn / src / views / oneMap / map / newfiberMapBox.vue
@wudi wudi on 21 Oct 22 KB 1
<template>
  <div class="mapPage">
    <div id="cesiumContainer"></div>
  </div>
</template>
<script>
import { reactive, toRefs, onBeforeMount, onMounted, nextTick, onBeforeUnmount } from 'vue';
import bus from '@/bus';
import axios from 'axios';
import buildingGeojson from '@/assets/yanAnBuilding.json';
import yanAnRoad from '@/assets/yanAnRoad.json';
import yanAnWater from '@/assets/yanAnWater.json';
import building_icon from '@/assets/newImgs/building_icon.png';
export default {
  components: {},
  props: {
    initJson: {
      type: String,
      default: () => '/static/libs/mapbox/style/floodOneMap.json',
    },
    loadCallback: {
      type: Function,
      default: () => function () {},
    },
  },
  setup(props, event) {
    const allData = reactive({
      layerIds: [],
    });
    let geojson = {
      point: { type: 'FeatureCollection', features: [] },
      polygon: { type: 'FeatureCollection', features: [] },
      linestring: { type: 'FeatureCollection', features: [] },
    };
    let map = null;
    let config = null;
    let highlightLayers = {
      highlight_point: 1,
      highlight_polygon: 1,
      highlight_linestring: 1,
    };

    const initeMap = async () => {
      config = (await axios.get(props.initJson)).data;

      const { basemap } = config.params;
      const { style, localStyle } = config.params.init;
      let styleJson = (
        await axios.get(
          localStyle ? localStyle : (style.includes('http') ? '' : location.origin + basemap) + config.params.init.style
        )
      ).data;
      styleJson.glyphs = styleJson.glyphs.includes('http') ? styleJson.glyphs : location.origin + styleJson.glyphs;
      styleJson.sprite = styleJson.sprite.includes('http') ? styleJson.sprite : location.origin + styleJson.sprite;

      window.newfiberMapbox = new mapboxL7.Scene({
        id: 'cesiumContainer',
        map: new mapboxL7.Mapbox({
          style: styleJson,
          // style:  localStyle?localStyle:(style.includes('http')?'':location.origin + config.params.basemap) + config.params.init.style,
          center: config.params.init.center,
          zoom: config.params.init.zoom,
        }),
      });
      map = newfiberMapbox.map;
      map.ogcLayers = [];
      map.setMaxZoom(18);
      newfiberMapbox.unLoadLayers = [];

      map.on('load', async () => {
        const mouseLocation = new mapboxL7.MouseLocation({
          transform: position => {
            return position;
          },
        });
        newfiberMapbox.addControl(mouseLocation);
        let { sprites, l7 } = config.params;
        (sprites || []).forEach(url =>
          map.style._loadSprite(url.includes('http') ? url : window.location.origin.split('#')[0] + url)
        );
        ((l7 || []).images || []).forEach(item =>
          newfiberMapbox.addImage(
            item.name,
            item.url.includes('http') ? item.url : window.location.origin.split('#')[0] + item.url
          )
        );
        addYanAnBuilding();
        addYanAnRiverFlow();
        // addYanAnRoad();
        await getGeoJSON();
        await loadData();
        props.loadCallback && props.loadCallback();
        // getLayerIdByClick();
        newfiberMapbox.getLayers().filter(i => highlightLayers[i.newfiberId] && (highlightLayers[i.newfiberId] = i));

        let timeout = setTimeout(() => {
          let { pitch, center } = config.params.init;
          pitch && newfiberMapbox.map.setPitch(pitch);
          center && newfiberMapbox.map.setCenter(center);
          (config.orders || []).forEach(item => setLayerOrder(...item));
          clearTimeout(timeout);
        }, 1000);
        // three();

        // getLayerIdByClick();
      });

      let layerIds = (config.mapbox || []).map(i => i.id);
      map.on('click', e => {
        Object.values(highlightLayers).forEach(layer => {
          if (layer.setData) layer.setData({ type: 'FeatureCollection', features: [] });
        });
        const feature = (
          map.queryRenderedFeatures([
            [e.point.x - 10 / 2, e.point.y - 10 / 2],
            [e.point.x + 10 / 2, e.point.y + 10 / 2],
          ]) || []
        ).filter(i => layerIds.includes(i.layer.id))[0];
        setHighlight(feature);
        event.emit('map-click', Object.values(e.lngLat), (feature || {}).properties, ((feature || {}).layer || {}).id);
      });

      async function getGeoJSON() {
        config.geojsonMvts = {};
        let url = config.mapbox
          .filter(i => i.mType == 'geojsonMvt')
          .map(item => {
            let { mType, columns, geom_column, id, key } = item;
            let sourceID = geom_column ? key + '_' + (geom_column || '') : key;
            let params = [];
            if (columns) params.push(`columns=${columns}`);
            if (geom_column) params.push(`geom_column=${geom_column}`);
            return config.params.mvt + `/v1/geojson/${key}?` + params.join('&');
          });
        url = Array.from(new Set(url));
        let fetchs = url.map(url => axios.get(url));
        let results = await Promise.all(fetchs);
        url.forEach((url, index) => (config.geojsonMvts[url] = results[index].data));
      }
    };

    const loadData = async () => {
      let { mapbox, l7, ogc } = config;
      if (mapbox) initMapBoxLayer();
      if (l7)
        l7.forEach(item => {
          let { id, columns, filter } = item;
          let params = [];
          if (columns) params.push(`columns=${columns}`);
          if (filter) params.push(`filter=${filter}`);
          id
            ? axios
                .get(config.params.mvt + `/v1/geojson/${id}?` + params.join('&'))
                .then(({ data: geojson }) => initMapBoxL7Class(item, geojson))
            : initMapBoxL7Class(item, geojson[item.key] || turf.featureCollection([]));
        });

      if (ogc)
        ogc.forEach(item => {
          let { id, type, params, methods } = item;
          Object.keys(params).forEach(
            i => (params[i] = typeof params[i] == 'string' ? (params[i].includes('||') ? eval(params[i]) : params[i]) : params[i])
          );
          let layer = new mapboxgl1[type](params);
          layer.newfiberId = id;
          methods.forEach(method => {
            let ms = method.params.map(i => (typeof i == 'string' ? (i.includes('||') ? eval(i) : i) : i));
            layer[method.name](...ms);
          });
          map.ogcLayers.push(layer);
        });

      function initMapBoxL7Class({ type, params, methods, id, show, key }, geojson) {
        let layer = new mapboxL7[type](params).source(geojson);
        methods.forEach(method => {
          let ms = method.params.map(i => (typeof i == 'string' ? (i.includes('||') ? eval(i) : i) : i));
          layer[method.name](...ms);
        });
        layer.newfiberId = key;
        if (!show) return newfiberMapbox.unLoadLayers.push(layer);
        newfiberMapbox.addLayer(layer);
        allData.layerIds.push(key);
      }

      function initMapBoxLayer() {
        mapbox.forEach(item => {
          let { mType, columns, geom_column, id, key } = item;
          let sourceID = geom_column ? key + '_' + (geom_column || '') : key;
          let params = [];
          if (columns) params.push(`columns=${columns}`);
          if (geom_column) params.push(`geom_column=${geom_column}`);
          if (!!!map.getSource(sourceID)) {
            let flag = mType == 'geojson';
            flag
              ? map.addSource(sourceID, { type: mType, data: geojson[key] })
              : map.addSource(sourceID, {
                  ...(mType == 'mvt'
                    ? {
                        type: 'vector',
                        tiles: [config.params.mvt + `/v1/${mType}/${key}/{z}/{x}/{y}?` + params.join('&')],
                        tileSize: 512,
                        scheme: 'xyz',
                        maxzoom: 14,
                        minzoom: 1,
                      }
                    : {
                        type: 'geojson',
                        data: config.geojsonMvts[config.params.mvt + `/v1/geojson/${key}?` + params.join('&')],
                      }),
                });
          }
          map.addLayer({ ...item, source: sourceID });
          map.moveLayer(id, undefined);
          allData.layerIds.push(id);
        });
      }
    };

    const setLayerVisible = ({ layername, isCheck, values = [] }) => {
      if (!!!layername) return;
      if (((config || {}).filter || [])[layername]) {
        config.filter[layername].layerName.forEach((name, index) => {
          let layer = newfiberMapbox.getLayers().filter(i => i.newfiberId == name)[0];
          let fValues = config.filter[layername].filter[index];
          if (layer) {
            let geojson = layer.getSource().originData;
            geojson.features.forEach(i => fValues.includes(i.properties.type) && (i.properties.visible = isCheck));
            layer.setData(geojson);
          }
          if (map.getLayer(name)) {
            fValues = fValues.filter(Boolean);
            let filter = map.getFilter(name);
            if (!fValues.length) fValues = values;
            if (filter[0] == 'in') {
              isCheck ? filter.push(...fValues) : (filter = filter.filter(i => !fValues.includes(i)));
            } else {
              let _filter =
                filter[filter.length - 1][filter[filter.length - 1].length - 1][
                  filter[filter.length - 1][filter[filter.length - 1].length - 1].length - 1
                ];
              isCheck
                ? filter[filter.length - 1][filter[filter.length - 1].length - 1][
                    filter[filter.length - 1][filter[filter.length - 1].length - 1].length - 1
                  ].push(...fValues)
                : (filter[filter.length - 1][filter[filter.length - 1].length - 1][
                    filter[filter.length - 1][filter[filter.length - 1].length - 1].length - 1
                  ] = _filter.filter(i => !fValues.includes(i)));
            }
            map.setFilter(name, filter);
          }
        });
        return config.filter[layername].easeTo && isCheck && map.easeTo(config.filter[layername].easeTo);
      }

      let features = Object.values(geojson)
        .map(i => i.features)
        .flat(Infinity)
        .filter(i => i.properties.type == layername);
      if (features.length) {
        let types = Array.from(new Set(features.map(i => i.geometry.type.toLocaleLowerCase())));
        types.forEach(type1 => {
          let filter = map.getFilter(type1);
          if (filter[0] == 'in') {
            isCheck ? filter.push(layername) : (filter = filter.filter(i => i != layername));
          } else {
            let _filter =
              filter[filter.length - 1][filter[filter.length - 1].length - 1][
                filter[filter.length - 1][filter[filter.length - 1].length - 1].length - 1
              ];
            isCheck
              ? filter[filter.length - 1][filter[filter.length - 1].length - 1][
                  filter[filter.length - 1][filter[filter.length - 1].length - 1].length - 1
                ].push(layername)
              : (filter[filter.length - 1][filter[filter.length - 1].length - 1][
                  filter[filter.length - 1][filter[filter.length - 1].length - 1].length - 1
                ] = _filter.filter(i => i != layername));
          }
          map.setFilter(type1, filter);
        });
      }

      let layer = newfiberMapbox.getLayers().filter(i => i.newfiberId == layername)[0];
      if (!!!layer) {
        layer = newfiberMapbox.unLoadLayers.filter(i => i.newfiberId == layername)[0];
        isCheck && layer && newfiberMapbox.addLayer(layer);
      }
      layer && layer[['hide', 'show'][Number(isCheck)]]();

      layer = map.getLayer(layername);
      layer && map.setLayoutProperty(layername, 'visibility', isCheck ? 'visible' : 'none');

      layer = map.getLayer(layername + '_text');
      layer && map.setLayoutProperty(layername + '_text', 'visibility', isCheck ? 'visible' : 'none');

      layer = map.ogcLayers.filter(i => i.id == layername)[0];
      layer && (layer.map ? layer[isCheck ? 'show' : 'hide']() : layer.addTo(map));
    };

    const getGeojsonByType = ({ type, callback }) => {
      let geojs = turf.featureCollection(
        Object.values(geojson)
          .map(i => i.features)
          .flat(Infinity)
          .filter(i => i.properties.type == type)
      );
      callback && callback(geojs);
    };

    const removeLayers = ids => {
      let { getLayers, removeAllLayer, removeLayer: removeLayerL7 } = newfiberMapbox;
      let { getLayer, removeLayer } = map;

      if (!!!ids) {
        allData.layerIds.forEach(id => getLayer(id) && removeLayer(id));
        return removeAllLayer();
      }

      ids.forEach(id => {
        getLayer(id) && removeLayer(id);
        getLayers().forEach(layer => layer.newfiberId == id && removeLayerL7(layer));
      });
    };

    const removeMapDatas = types => {
      !!!types
        ? Object.keys(geojson).forEach(key => (geojson[key].features.length = 0))
        : Object.keys(geojson).forEach(
            key => (geojson[key].features = geojson[key].features.filter(feature => !types.includes(feature.properties.type)))
          );
      return refreshGeoJSON();
    };

    const setLegendData = list => {
      list.forEach(i => {
        let points = [];
        if (!i.data) return;
        i.data.features.forEach(a => {
          if (!!!a || !!!a.properties) return;
          (a.properties.minzoom = a.properties.minzoom || 0),
            (a.properties.color = a.properties.color || 'rgba(0,0,0,1)'),
            (a.properties.type = a.properties.type || i.layername);
          a.properties.name =
            a.properties.name ||
            a.properties.Name ||
            a.properties.stName ||
            a.properties.pointNumber ||
            a.properties.sewageName ||
            a.properties.sectionName ||
            a.properties.pumpName;
          if (a.properties.name && !turf.getType(a).toLocaleLowerCase().includes('point')) {
            let center = turf.pointOnFeature(a);
            center.properties = { ...a.properties, minzoom: 10 };
            center.properties.geometry = Terraformer.WKT.convert(center.geometry);
            points.push(center);
          }
        });
        i.data.features = i.data.features.concat(points);
      });

      let types = {};
      list
        .map(i => i.data && i.data.features)
        .filter(Boolean)
        .flat(Infinity)
        .forEach(feature => {
          if (!!!feature || !!!feature.properties) return;
          feature.properties.geometry = Terraformer.WKT.convert(feature.geometry);
          let type = feature.geometry.type.toLocaleLowerCase();
          let flag = type.includes('multi');
          type = type.replaceAll('multi', '');
          let features = null;
          if (flag) features = turf.flatten(feature).features;
          !!!types[type] && (types[type] = []);
          types[type].push(...(features ? features : [feature]));
        });

      Object.keys(types).forEach(key => geojson[key].features.push(...types[key]));
      refreshGeoJSON();
    };

    const refreshGeoJSON = () => {
      Object.keys(geojson).forEach(key => map.getSource(key) && map.getSource(key).setData(geojson[key]));
      map.triggerRepaint();
    };

    const setGeoJSON = ({ json, key }) => {
      let layer = newfiberMapbox.getLayers().filter(i => i.newfiberId == key)[0];
      console.log('layer----', layer);
      if (!!!layer) {
        layer = newfiberMapbox.unLoadLayers.filter(i => i.newfiberId == key)[0];
        layer && layer.setData(json);
        layer && newfiberMapbox.addLayer(layer);
      }
      if (layer) return layer.setData(json);
      setLegendData([{ data: json, layername: key, type: 'point' }]);
    };

    const beansToMap = ({ beans, fields = { geometry: 'geometry', lng: 'lng', lat: 'lat', name: 'name' }, type, isConvert }) => {
      let geojson = turf.featureCollection(
        beans
          .filter(i => i[fields.geometry] || (Boolean(Number(i[fields.lng])) && Boolean(Number(i[fields.lat]))))
          .map(i => {
            let feature = null;
            if (i[fields.geometry])
              feature = turf.feature(Terraformer.WKT.parse(i[fields.geometry]), {
                ...i,
                name: i[fields.name],
              });
            if (i[fields.lng])
              feature = turf.point([i[fields.lng], i[fields.lat]].map(Number), {
                ...i,
                name: i[fields.name],
              });
            return feature;
          })
          .filter(Boolean)
      );
      isConvert && (geojson = gcoord.transform(geojson, gcoord.AMap, gcoord.WGS84));
      setGeoJSON({ json: geojson, key: type });
    };

    const setHighlight = (features = {}) => {
      let array = {};
      features = features.forEach ? features : [features];
      Object.values(highlightLayers).forEach(
        layer => layer.setData && layer.setData({ type: 'FeatureCollection', features: [] })
      );
      features.forEach(feature => {
        if (!!!feature || !Boolean(Object.keys(feature).length) || !feature.properties.geometry) return;
        let geometry = Terraformer.WKT.parse(feature.properties.geometry);
        let geoFeature = turf.feature(geometry, feature.properties);
        let type = geometry.type.toLocaleLowerCase().replaceAll('multi', '');
        let key = Object.keys(highlightLayers).filter(key => key.lastIndexOf(type) > -1)[0];
        if (!array[key]) array[key] = [];
        array[key].push(geoFeature);
      });
      Object.keys(array).forEach(
        key =>
          highlightLayers[key] &&
          highlightLayers[key].setData({
            type: 'FeatureCollection',
            features: array[key],
          })
      );
    };

    const setLayerOrder = (sourceLayer, targetLayer) => {
      map.moveLayer(sourceLayer, targetLayer);
    };

    const getLayerIdByClick = () => {
      map.getStyle().layers.forEach(i =>
        map.on('click', i.id, (a, b, c, d) => {
          console.log('layer-id', a.features[0].layer.id);
        })
      );
    };

    const updateStyle = styleJson => {
      styleJson.glyphs = styleJson.glyphs.includes('http') ? styleJson.glyphs : location.origin + styleJson.glyphs;
      styleJson.sprite = styleJson.sprite.includes('http') ? styleJson.sprite : location.origin + styleJson.sprite;

      const currentStyle = map.getStyle();
      styleJson.sources = Object.assign({}, currentStyle.sources, styleJson.sources);
      let labelIndex = styleJson.layers.findIndex(el => {
        return el.id == 'waterway-label';
      });
      if (labelIndex === -1) {
        labelIndex = styleJson.layers.length;
      }
      const appLayers = currentStyle.layers.filter(el => {
        return el.source && el.source != 'mapbox://mapbox.satellite' && el.source != 'mapbox' && el.source != 'composite';
      });
      styleJson.layers = [...styleJson.layers.slice(0, labelIndex), ...appLayers, ...styleJson.layers.slice(labelIndex, -1)];
      map.setStyle(styleJson);
    };
    //添加延安建筑白膜
    const addYanAnBuilding = () => {
      map.loadImage(building_icon, (error, image) => {
        if (error) throw error;
        // Add the image to the map style.
        map.addImage('buildingLayer', image);
        map.addSource("buildingSource", {
          type: 'geojson',
          data: buildingGeojson,
        })

        map.addLayer({
          id: 'buildingLayer-top',
          type: 'fill-extrusion',
          source: "buildingSource",
          // //绘画功能
          paint: {
            'fill-extrusion-color': 'rgba(0,63,95,1)',
            'fill-extrusion-height': ['+',['get', 'height_3'],0.1],
            'fill-extrusion-base': ['get', 'height_3'],
            'fill-extrusion-opacity': 1,
          },
        });
        map.addLayer({
          id: 'buildingLayer',
          type: 'fill-extrusion',
          source: "buildingSource",
          // //绘画功能
          paint: {
            'fill-extrusion-pattern': 'buildingLayer',
            'fill-extrusion-color': '#ffffff',
            'fill-extrusion-height': ['get', 'height_3'],
            'fill-extrusion-base': 0,
            'fill-extrusion-opacity': 1,
          },
        });
      });
    };
    //添加延安水系
    const addYanAnRiverFlow = () => {
      let layer = new mapboxL7.LineLayer({
        name: 'waterLake',
      })
        .source(yanAnWater)
        .size(4)
        .shape('line')
        .texture('arrow')
        .color('aqua')
        .animate({
          interval: 2, // 间隔
          duration: 3, // 持续时间,延时
          trailLength: 3, // 流线长度
        })
        .style({
          opacity: 0.8,
          lineTexture: true, // 开启线的贴图功能
          iconStep: 200, // 设置贴图纹理的间距
          borderWidth: 0.4, // 默认文 0,最大有效值为 0.5
          borderColor: '#fff', // 默认为 #ccc
        });
      newfiberMapbox.addLayer(layer);
    };
    //添加延安路网
    const addYanAnRoad = () => {
      let layer = new mapboxL7.LineLayer({
        name: 'dynamicRoad',
      })
        .source(yanAnRoad)
        .size(1.3)
        .shape('line')
        .color('rgb(184, 184, 184)')
        .animate({
          interval: 1, // 间隔
          duration: 1.5, // 持续时间,延时
          trailLength: 2, // 流线长度
        })
        .style({
          opacity: 0.6,
        });
      newfiberMapbox.addLayer(layer);
    };
    onMounted(() => {
      initeMap();
      bus.on('beansToMap', beansToMap);
      bus.on('setLayerVisible', setLayerVisible);
      bus.on('setLegendData', setLegendData);
      bus.on('setGeoJSON', setGeoJSON);
      bus.on('getGeojsonByType', getGeojsonByType);
      bus.on('removeLayers', removeLayers);
      bus.on('removeMapDatas', removeMapDatas);
      bus.on('setHighlight', setHighlight);
      bus.on('updateStyle', updateStyle);
    });

    onBeforeUnmount(() => {
      bus.off('beansToMap');
      bus.off('setLayerVisible');
      bus.off('setLegendData');
      bus.off('setGeoJSON');
      bus.off('getGeojsonByType');
      bus.off('removeMapDatas');
      bus.off('setHighlight');
      bus.off('updateStyle');
      if (newfiberMapbox) {
        newfiberMapbox.destroy();
        newfiberMapbox = null;
      }
    });

    return {
      ...toRefs(allData),
    };
  },
};
</script>
<style>
.mapPage {
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0px;
  top: 0px;
  z-index: 0;
  background: lavender;
}

#cesiumContainer {
  width: 100%;
  height: 100%;
  position: absolute;
}

.l7-control-mouse-location {
  background: none;
}

.l7-control-mouse-location {
  color: #ffffff;
}
</style>