openlayers自带图形经常不满足项目需要, 本文演示openlayers如何结合canvas实现echarts 散点效果
封装 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>