使用openlayers给地图添加内发光、外发光、内外阴影、三维立体效果

给地图添加内阴影、外阴影效果,可以使用ol的扩展库ol-ext

npm i ol-ext

引入两个类Mask遮罩和Crop裁剪

import Mask from "ol-ext/filter/Mask";
import Crop from "ol-ext/filter/Crop.js";

Mask主要用来设置内阴影效果,外阴影则是由Crop设置。

addShadowByExt() {
      axios
        .get("https://geo.datav.aliyun.com/areas_v3/bound/110000.json")
        .then((res) => {
          // 将 GeoJSON 数据解析为 ol.Feature 对象
          const features = new GeoJSON().readFeatures(res.data);
          const source = new VectorSource({
            features: features,
          });
          let layer = new VectorLayer({
            source: source,
          });
          this.map.addLayer(layer);
          //内发光
          let mask = this.addMask({
            fillColor: "#CC92E6",
            shadowColor: "#ff0",
            feature: features[0],
            inner: true,
          });
          //设置裁切
          this.setLayerFilterCrop(layer, features[0]);
          layer.addFilter(mask);
        });
    },
    //添加Mask
    addMask(options) {
      return new Mask({
        feature: options.feature,
        wrapX: false,
        inner: options.inner || false,
        fill: new Fill({ color: options.fillColor }),
        shadowColor: options.shadowColor || "rgba(0,0,0,0.5)",
        shadowWidth: options.shadowWidth || 10,
        // shadowMapUnits:true,
      });
    },
    setLayerFilterCrop(layer, feature) {
      /**
       * 设置图层裁切
       */
      const crop = new Crop({
        feature: feature,
        inner: false,
        active: true,
        wrapX: true,
        shadowWidth: 10,
        shadowColor: "#000",
      });
      layer.addFilter(crop);
    },

但是这种阴影不能调节偏移量,因此要设置阴影偏移量达到三维立体效果还需要利用canvas原理。

要想做出这种效果,需要在style的renderer函数中获取ctx上下文和图层用到的坐标数组coordinate。然后使用addOutlineShadow函数添加阴影。

我这里堆叠了好几层阴影,这样看着更立体些。

addRegionLayer() {
      let _this = this;
      const source = new VectorSource({
        url: "https://geo.datav.aliyun.com/areas_v3/bound/110000.json",
        format: new GeoJSON(),
      });
      this.vectorLayer = new VectorLayer({
        source: source,
        style: new Style({
          renderer(coordinate, state) {
            let arr = coordinate[0][0];
            const ctx = state.context;
            _this.addOutlineShadow(ctx, {
              fillStyle: "rgba(30, 60, 95,1)",
              shadowOffsetY: 30,
              shadowOffsetX: 2,
              shadowColor: "rgba(30, 60, 95,1)",
              strokeStyle: "rgba(30, 60, 95,1)",
              coodArr: arr,
            });
            _this.addOutlineShadow(ctx, {
              fillStyle: "transparent",
              shadowOffsetY: 20,
              shadowOffsetX: 2,
              shadowColor: "rgba( 56, 113, 139,1)",
              strokeStyle: "rgba(30, 60, 95,1)",
              coodArr: arr,
            });
            _this.addOutlineShadow(ctx, {
              fillStyle: "transparent",
              shadowOffsetY: 15,
              shadowOffsetX: 2,
              shadowColor: "rgba(255,255,255,1)",
              strokeStyle: "rgba(30, 60, 95,1)",
              shadowBlur: 10,
              coodArr: arr,
            });
            _this.addOutlineShadow(ctx, {
              fillStyle: "transparent",
              shadowOffsetY: 10,
              shadowOffsetX: 2,
              shadowColor: "rgba(83, 173, 214,1)",
              strokeStyle: "rgba(83, 173, 214,1)",
              coodArr: arr,
            });
            _this.addOutlineShadow(ctx, {
              fillStyle: "transparent",
              shadowOffsetY: 8,
              shadowOffsetX: 2,
              shadowColor: "rgba(255,255,255,1)",
              strokeStyle: "rgba(255,255,255,1)",
              shadowBlur: 10,
              coodArr: arr,
            });
            _this.addOutlineShadow(ctx, {
              fillStyle: "#fff",
              shadowOffsetY: 5,
              shadowOffsetX: 2,
              shadowColor: "rgba(70, 133, 171,1)",
              strokeStyle: "rgba(70, 133, 171,1)",
              shadowBlur: 10,
              coodArr: arr,
            });
            //白色
            _this.addOutlineShadow(ctx, {
              fillStyle: "rgba(70, 133, 171,1)",
              shadowOffsetY: 5,
              shadowOffsetX: 10,
              shadowColor: "rgba(255,255,255,1)",
              strokeStyle: "#50e3ff",
              shadowBlur: 15,
              coodArr: arr,
              lineWidth: 2,
            });
          },
        }),
      });
      this.map.addLayer(this.vectorLayer);
    },

 拿到canvas上下文了,就可以使用canvas的方法添加阴影效果了,最后再将拿到的坐标数组用canvas的方法绘制成多边形,就可以在地图上显示了。

事实上,这种方法不仅能绘制阴影,还可以绘制其他效果。

addOutlineShadow(ctx, option) {
      // 设置属性控制图形的外观
      ctx.fillStyle = option.fillStyle || "transparent";
      ctx.strokeStyle = option.strokeStyle || "transparent";
      ctx.lineWidth = option.lineWidth || 1;

      //  设置Y轴偏移量
      ctx.shadowOffsetY = option.shadowOffsetY || 20;
      //  设置X轴偏移量
      ctx.shadowOffsetX = option.shadowOffsetX || 2;
      //  设置模糊度
      ctx.shadowBlur = option.shadowBlur || 2;
      //  设置阴影颜色
      ctx.shadowColor = option.shadowColor || "#000";
      ctx.beginPath();
      let arr = option.coodArr || [];
      for (let i = 0; i < arr.length; i++) {
        const data = arr[i];
        if (i === 0) {
          ctx.moveTo(data[0], data[1]);
        } else {
          ctx.lineTo(data[0], data[1]);
        }
      }
      ctx.closePath();
      ctx.fill();
      ctx.stroke();
    },

完整代码:

<template>
  <div class="box">
    <h1>给地图添加内发光、外发光、内外阴影、三维立体效果</h1>
    <div id="map"></div>
  </div>
</template>

<script>
import GeoJSON from "ol/format/GeoJSON.js";
import Map from "ol/Map.js";
import View from "ol/View.js";
import { OSM, Vector as VectorSource, XYZ } from "ol/source.js";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer.js";
import { Fill, Stroke, Text, Style } from "ol/style.js";
import { LineString, MultiPolygon, Point, Polygon } from "ol/geom.js";
import Mask from "ol-ext/filter/Mask";
import Crop from "ol-ext/filter/Crop.js";
import axios from "axios";
export default {
  name: "",
  components: {},
  data() {
    return {
      vectorLayer: null,
      map: null,
    };
  },
  computed: {},
  created() {},
  methods: {
    addShadowByExt() {
      axios
        .get("https://geo.datav.aliyun.com/areas_v3/bound/110000.json")
        .then((res) => {
          // 将 GeoJSON 数据解析为 ol.Feature 对象
          const features = new GeoJSON().readFeatures(res.data);
          const source = new VectorSource({
            features: features,
          });
          let layer = new VectorLayer({
            source: source,
          });
          this.map.addLayer(layer);
          //内发光
          let mask = this.addMask({
            fillColor: "#CC92E6",
            shadowColor: "#ff0",
            feature: features[0],
            inner: true,
          });
          //设置裁切
          this.setLayerFilterCrop(layer, features[0]);
          layer.addFilter(mask);
        });
    },
    //添加Mask
    addMask(options) {
      return new Mask({
        feature: options.feature,
        wrapX: false,
        inner: options.inner || false,
        fill: new Fill({ color: options.fillColor }),
        shadowColor: options.shadowColor || "rgba(0,0,0,0.5)",
        shadowWidth: options.shadowWidth || 10,
        // shadowMapUnits:true,
      });
    },
    setLayerFilterCrop(layer, feature) {
      /**
       * 设置图层裁切
       */
      const crop = new Crop({
        feature: feature,
        inner: false,
        active: true,
        wrapX: true,
        shadowWidth: 10,
        shadowColor: "#000",
      });
      layer.addFilter(crop);
    },
    addRegionLayer() {
      let _this = this;
      const source = new VectorSource({
        url: "https://geo.datav.aliyun.com/areas_v3/bound/110000.json",
        format: new GeoJSON(),
      });
      this.vectorLayer = new VectorLayer({
        source: source,
        style: new Style({
          renderer(coordinate, state) {
            let arr = coordinate[0][0];
            const ctx = state.context;
            _this.addOutlineShadow(ctx, {
              fillStyle: "rgba(30, 60, 95,1)",
              shadowOffsetY: 30,
              shadowOffsetX: 2,
              shadowColor: "rgba(30, 60, 95,1)",
              strokeStyle: "rgba(30, 60, 95,1)",
              coodArr: arr,
            });
            _this.addOutlineShadow(ctx, {
              fillStyle: "transparent",
              shadowOffsetY: 20,
              shadowOffsetX: 2,
              shadowColor: "rgba( 56, 113, 139,1)",
              strokeStyle: "rgba(30, 60, 95,1)",
              coodArr: arr,
            });
            _this.addOutlineShadow(ctx, {
              fillStyle: "transparent",
              shadowOffsetY: 15,
              shadowOffsetX: 2,
              shadowColor: "rgba(255,255,255,1)",
              strokeStyle: "rgba(30, 60, 95,1)",
              shadowBlur: 10,
              coodArr: arr,
            });
            _this.addOutlineShadow(ctx, {
              fillStyle: "transparent",
              shadowOffsetY: 10,
              shadowOffsetX: 2,
              shadowColor: "rgba(83, 173, 214,1)",
              strokeStyle: "rgba(83, 173, 214,1)",
              coodArr: arr,
            });
            _this.addOutlineShadow(ctx, {
              fillStyle: "transparent",
              shadowOffsetY: 8,
              shadowOffsetX: 2,
              shadowColor: "rgba(255,255,255,1)",
              strokeStyle: "rgba(255,255,255,1)",
              shadowBlur: 10,
              coodArr: arr,
            });
            _this.addOutlineShadow(ctx, {
              fillStyle: "#fff",
              shadowOffsetY: 5,
              shadowOffsetX: 2,
              shadowColor: "rgba(70, 133, 171,1)",
              strokeStyle: "rgba(70, 133, 171,1)",
              shadowBlur: 10,
              coodArr: arr,
            });
            //白色
            _this.addOutlineShadow(ctx, {
              fillStyle: "rgba(70, 133, 171,1)",
              shadowOffsetY: 5,
              shadowOffsetX: 10,
              shadowColor: "rgba(255,255,255,1)",
              strokeStyle: "#50e3ff",
              shadowBlur: 15,
              coodArr: arr,
              lineWidth: 2,
            });
          },
        }),
      });
      this.map.addLayer(this.vectorLayer);
    },

    addOutlineShadow(ctx, option) {
      // 设置属性控制图形的外观
      ctx.fillStyle = option.fillStyle || "transparent";
      ctx.strokeStyle = option.strokeStyle || "transparent";
      ctx.lineWidth = option.lineWidth || 1;

      //  设置Y轴偏移量
      ctx.shadowOffsetY = option.shadowOffsetY || 20;
      //  设置X轴偏移量
      ctx.shadowOffsetX = option.shadowOffsetX || 2;
      //  设置模糊度
      ctx.shadowBlur = option.shadowBlur || 2;
      //  设置阴影颜色
      ctx.shadowColor = option.shadowColor || "#000";
      ctx.beginPath();
      let arr = option.coodArr || [];
      for (let i = 0; i < arr.length; i++) {
        const data = arr[i];
        if (i === 0) {
          ctx.moveTo(data[0], data[1]);
        } else {
          ctx.lineTo(data[0], data[1]);
        }
      }
      ctx.closePath();
      ctx.fill();
      ctx.stroke();
    },
  },
  mounted() {
    const view = new View({
      projection: "EPSG:4326",
      center: [116.389, 39.903],
      zoom: 7,
    });
    this.map = new Map({
      layers: [],
      target: "map",
      view: view,
    });
    this.addRegionLayer();
    // this.addShadowByExt();
  },
};
</script>

<style lang="scss" scoped>
#map {
  width: 100%;
  height: 500px;
}
.box {
  height: 100%;
}
</style>

 

### 回答1: OpenLayers是一个开源的JavaScript库,可用于创建交互式地图应用程序。它支持三维地图视图,可以通过整合第三方库和API实现。 在OpenLayers中,通过使用Cesium库,可以实现三维地图的可视化效果。Cesium是一个开源的JavaScript库,用于创建地球三维渲染的虚拟环境。OpenLayers与Cesium的整合可以使得用户能够在网页上查看和交互式操作三维地图使用OpenLayers创建三维地图可以带来很多好处。首先,它可以使得用户能够以三维的方式浏览地理数据。通过在地球上添加多个图层和数据源,用户可以深入了解地理信息,并进行数据分析和可视化。其次,OpenLayers三维地图具有高度的交互性,用户可以通过拖动、缩放和旋转地球来自由探索地理区域。再者,OpenLayers提供了灵活的地图控件和工具,可以帮助用户进行标记、测量、查询等操作,增强了地理数据的分析和应用能力。 OpenLayers三维地图也广泛应用于各个领域。比如在地理信息系统(GIS)中,三维地图可以被用来可视化地形、建筑物、水域等地理要素,辅助决策和规划。在旅游服务中,通过将地理信息与三维地图相结合,可以帮助用户更直观地了解旅游景点的地理位置和周边环境。在教育领域,OpenLayers三维地图可以用来创建交互式的地理教学资源,提高学生对地球地理的理解和记忆。总之,OpenLayers三维地图在多个领域中发挥着重要作用,为用户提供了强大的地理数据可视化和分析能力。 ### 回答2: OpenLayers是一个开源的JavaScript库,可以用于创建基于Web的地图应用程序。除了支持常规的二维地图功能OpenLayers还提供了对三维地图的支持。 OpenLayers三维地图功能主要依赖于Cesium库。Cesium是另一个开源的JavaScript库,专门用于创建高性能的三维地球视图。通过将OpenLayers与Cesium结合使用,可以实现在Web应用程序中展示和操作三维地图使用OpenLayers三维地图功能,可以展示地球的真实形状和地表特征,例如山脉、河流、海洋等。用户可以通过平移、旋转和缩放操作来浏览地球的不同部分。此OpenLayers还支持添加自定义的三维对象,如建筑物、车辆等,以增强地图的可视化效果。 在使用OpenLayers创建三维地图应用程序时,开发者可以利用丰富的API来实现各种功能。例如,可以添加地图图层、标记、地理信息系统数据等。同时,OpenLayers还提供了丰富的控件和工具,如缩放控制、导航工具等,以便用户在三维地图中进行交互操作。 总之,OpenLayers三维地图功能为开发者提供了创建交互式的、具有真实感的三维地图应用程序的能力,使用户能够更直观地了解地球的地理信息和地貌特征。 ### 回答3: OpenLayers是一个开源的JavaScript库,用于创建互动的Web地图应用程序。它支持二维和三维地图,并提供各种功能和工具来实现地图的可视化、交互和分析。 在OpenLayers中,三维地图可以通过使用合适的WebGL库(如Cesium)来实现。通过将OpenLayers与Cesium集成,我们可以在应用程序中实现三维地图的可视化和交互。 OpenLayers提供了一些专门为三维地图设计的类和方法,可以轻松地创建和管理三维地图。通过使用这些功能,我们可以在Web应用程序中显示具有高程和可视化效果三维地图,例如山脉、河流和建筑物。 使用OpenLayers进行三维地图开发的好处之一是其广泛的功能和工具。OpenLayers提供了丰富的API,可用于在三维地图添加标记、线条、多边形和其他要素。还可以实现地图的交互功能,如缩放、平移和旋转。 另一个优点是OpenLayers与其他GIS工具和数据格式的兼容性。它支持各种地图服务和数据格式,可以轻松地集成和展示部数据源。这使得OpenLayers成为一个强大的工具,可以用于开发具有丰富地理信息的复杂地图应用程序。 综上所述,OpenLayers是一个多功能、易于使用且功能强大的JavaScript库,可以用于创建和管理三维地图。通过结合适当的WebGL库,我们可以轻松地实现具有高程和可视化效果三维地图,并使用OpenLayers的丰富功能和工具进行交互和分析。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值