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

很多人用openlayers做地图时都很苦恼,做不了炫酷的效果,连阴影效果都不支持,其实,是可以的。

style大家用的多,但是很少有人知道style上有个参数叫renderer。它是一个函数,一共可以接收到两个参数,ctx上下文和图层用到的坐标数组coordinate

this.vectorLayer = new VectorLayer({
        source: source,
        style: new Style({
          renderer(coordinate, state) {
    

            }
        })
})

而canvas本身是支持阴影效果的,以下属性都是:

ctx.shadowOffsetY、ctx.shadowOffsetX、ctx.shadowBlur、ctx.shadowColor

所以,我们可以在renderer函数里拿到cavans的上下文自己给它添加阴影效果。

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();
    },

可以堆叠好几层阴影,将他们换成不同的颜色,这样看着更立体些。

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);
    },

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

以上方法其实主要是为了做3d效果加阴影,可如果你只是简单的想加一点阴影效果,那么大可不必那么复杂,可以用下面这种:

给地图添加内阴影、外阴影效果,可以使用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);
    },

两种方式的完整代码:

<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>

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值