openlayers配合canvas实现echarts 散点效果

315 阅读2分钟

openlayers自带图形经常不满足项目需要, 本文演示openlayers如何结合canvas实现echarts 散点效果

20240314_171435.gif

封装 circle 类

class Circle {
  constructor(options) {
    //定义默认配置
    let defaultOptions = {
      fillStyle: 'black',
      strokeStyle: 'black',
      scaleX: 1,
      scaleY: 1,
      r: 0,
      opacity: 1
    }

    // 合并到实例上
    Object.assign(this, defaultOptions, options)
  }
  // 克隆当前实例
  clone() {
    let { fillStyle, scaleX, scaleY, x, y, r, opacity } = this

    return new Circle({
      fillStyle,
      scaleX,
      scaleY,
      x,
      y,
      r,
      opacity
    })
  }
  // 绘制方法, 接受canvas上下文
  render(ctx) {
    let { fillStyle, scaleX, scaleY, x, y, r, opacity } = this

    //保存配置
    ctx.save()
    //平移到x,y位置
    ctx.translate(x, y)
    //定义缩放
    ctx.scale(scaleX, scaleY)
    //透明度
    ctx.globalAlpha = opacity

    ctx.fillStyle = fillStyle

    ctx.beginPath()
    ctx.arc(0, 0, r, 0, Math.PI * 2)
    ctx.fill()
    ctx.closePath()

    //恢复画布环境
    ctx.restore()
  }
}

在canvas上实现散点动画

这里借用了gsap动画库(超级好用)

<template>
  <div id="container" style="width: 1000px; height: 500px"></div>
</template>

<script setup>
import gsap from 'gsap'
import { Circle } from './utils'

let canvas = document.createElement('canvas')
let w = 100,
  h = 100
canvas.width = w
canvas.height = h
let ctx = canvas.getContext('2d')

let circle = new Circle({
  x: w / 2,
  y: h / 2,
  r: 10,
  opacity: 1
})

let circle1 = circle.clone()
let circle2 = circle.clone()

gsap.to([circle, circle1, circle2], {
  r: 30,
  duration: 3,
  repeat: -1,
  opacity: 0,
  stagger: '1',
  onUpdate() {
    ctx.clearRect(0, 0, w, h)
    circle.render(ctx)
    circle1.render(ctx)
    circle2.render(ctx)
  }
})

onMounted(() => {
  document.querySelector('#container').appendChild(canvas)
})
</script>
<style lang="scss" scoped></style>


openlayers结合canvas

<template>
  <div id="map" style="width: 100%; height: 100vh"></div>
</template>

<script setup>
import Map from 'ol/Map'
import View from 'ol/View'
import TileLayer from 'ol/layer/Tile'
import XYZ from 'ol/source/XYZ'
import { Point } from 'ol/geom'
import { Icon, Style } from 'ol/style.js'
import Feature from 'ol/Feature'
import VectorSource from 'ol/source/Vector'
import VectorLayer from 'ol/layer/Vector'
import { Circle } from './utils'
import gsap from 'gsap'

//自己的天地图token
let tk = ''

var map = new Map({
  view: new View({
    center: [122.144657, 29.944429], // 地图中心点
    zoom: 10, //缩放层级
    projection: 'EPSG:4326' //地图投影
  }),
  layers: [
    new TileLayer({
      source: new XYZ({
        url: `http://t1.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=${tk}`
      })
    }),
    new TileLayer({
      source: new XYZ({
        url: `http://t1.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=`
      })
    })
  ]
})

onMounted(() => {
  map.setTarget(document.querySelector('#map'))
})

//创建canvas画布
let canvas = document.createElement('canvas')
let w = 100,
  h = 100
canvas.width = w
canvas.height = h
let ctx = canvas.getContext('2d')

//创建圆类
let circle = new Circle({
  x: w / 2,
  y: h / 2,
  r: 10,
  opacity: 1
})

//克隆两个小圆
let circle1 = circle.clone()
let circle2 = circle.clone()

let style = new Style({
  image: new Icon({
    img: canvas, // 通过Icon传入canvas
    imgSize: [w, h]
  })
})

let source = new VectorSource()

// Point的坐标代表了canvas在地图上的位置
let feature = new Feature(new Point([122.144657, 29.944429]))
source.addFeature(feature)

feature.setStyle(style)

let layer = new VectorLayer({
  source: source
})
map.addLayer(layer)

let gs = gsap.to([circle, circle1, circle2], {
  r: 30,
  duration: 3,
  repeat: -1,
  opacity: 0,
  stagger: '1',
  onUpdate() {
    //更新canvas画布
    ctx.clearRect(0, 0, w, h
    circle.render(ctx)
    circle1.render(ctx)
    circle2.render(ctx)
    
    //更新图层,也可以使用map.render(), 更新对应图层效率更高
    layer.changed()
  }
})

onUnmounted(() => {
    // vue使用gsap记得停止动画哦
  gs.revert()
})
</script>