Newer
Older
urbanLifeline_YanAn / src / views / oneMap / map / newfiberMapBox.vue
@zhangqy zhangqy on 18 Oct 23 KB 效果提交
<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 { buffer } from "ol/size";
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 = [];
      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.addLayer({
        id: "buildingLayer",
        type: "fill-extrusion",
        source: {
          type: "geojson",
          data: buildingGeojson,
        },
        // //绘画功能
        paint: {
          // Get the fill-extrusion-color from the source 'color' property.   从source 'color'属性获取fill- extrusive -color。
          // 'fill-extrusion-color':'rgba(200, 100, 240, 0.4)',
          // "fill-extrusion-color":['get','color'],//加载数据中的颜色
          "fill-extrusion-color": {
            //根据数值中加载相对应颜色
            property: "height_3", // this will be your density property form you geojson
            stops: [
              [10, "#009bdd"],
              [20, "#009bdd"],
              [30, "#009bdd"],
              [80, "#00a8de"],
              [100, "#24edff"],
              [125, "#24edff"],
              [300, "#24edff"],
            ],
          },
          //    从source 'height'属性获取填充-挤出-高度。
          "fill-extrusion-height": ["get", "height_3"],
          "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>