阅读量:0
在有些业务中,对场景中的广告牌样式要求比较高,需要动态显示一些数据,这个时候,我们可以通过将复杂背景样式制作成图片,通过canvas绘制图片和动态数据,从而达到比较好的显示效果。
1 CanvasMarker 类封装
CanvasMarker.js
/* * @Description: * @Author: maizi * @Date: 2022-05-27 11:36:22 * @LastEditTime: 2024-07-23 15:34:06 * @LastEditors: maizi */ const merge = require('deepmerge') const defaultStyle = { scale: 0.2, text: '0.0' } const monitorPanel = require('@/assets/img/monitorPanel.png') class CanvasMarker { constructor(viewer, coords, options = {}) { this.viewer = viewer; this.coords = coords; this.options = options; this.props = this.options.props; this.baseHeight = this.coords[2] || 10; this.style = merge(defaultStyle, this.options.style || {}); this.entity = null; this.canvas = null this.init(); } init() { let img = new Image(); img.src = monitorPanel; img.onload = ()=> { this.picture = img; this.canvas = this.createCanvas() } this.entity = new Cesium.Entity({ type: "canvas_point", props: this.props, position:Cesium.Cartesian3.fromDegrees(this.coords[0], this.coords[1], this.baseHeight), billboard: { image: new Cesium.CallbackProperty(() => { return this.canvas.toDataURL("image/png"); }), scale:new Cesium.CallbackProperty(() => { return this.style.scale }), color: new Cesium.Color(1, 1, 1), disableDepthTestDistance: Number.POSITIVE_INFINITY, }, }); } createCanvas() { let canvas = null; if (this.canvas) { canvas = this.canvas } else { canvas = document.createElement("canvas"); canvas.width = 512; canvas.height = 329; } let ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(this.picture, 0, 0); ctx.fillStyle = "rgb(255, 255, 255)", ctx.font = "80px sans-serif", ctx.textBaseline = "middle", ctx.fillText("温度:", 50, canvas.height / 2); ctx.fillText(this.style.text, 270, canvas.height / 2); ctx.fillText("℃", 380, canvas.height / 2); // // 导出canvas为图片 // var dataURL = canvas.toDataURL("image/png"); // var link = document.createElement('a'); // link.download = 'canvas-image.png'; // link.href = dataURL; // link.click(); return canvas; } setSelect(enabled) { if (enabled) { this.addPoint() } else { this.removePoint() } } addPoint() { this.point = new Cesium.Entity({ position: Cesium.Cartesian3.fromDegrees(this.coords[0], this.coords[1], this.baseHeight), point: { color: Cesium.Color.DARKBLUE.withAlpha(.4), pixelSize: 6, outlineColor: Cesium.Color.YELLOW.withAlpha(.8), outlineWidth: 4, disableDepthTestDistance: Number.POSITIVE_INFINITY } }); this.viewer.entities.add(this.point) } removePoint() { if (this.point) { this.viewer.entities.remove(this.point) this.point = null } } updateStyle(style) { this.style = merge(this.style, style || {}); this.createCanvas() } } export { CanvasMarker }
2 完整示例代码
MapWorks.js
import GUI from 'lil-gui'; // 初始视图定位在中国 import { CanvasMarker } from './CanvasMarker' Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(90, -20, 110, 90); //天地图key const key = '39673271636382067f0b0937ab9a9677' let viewer = null; let eventHandler = null; let canvasLayer = null let canvasList = [] let selectGraphic = null let gui = null function initMap(container) { viewer = new Cesium.Viewer(container, { animation: false, baseLayerPicker: false, fullscreenButton: false, geocoder: false, homeButton: false, infoBox: false, sceneModePicker: false, selectionIndicator: false, timeline: false, navigationHelpButton: false, scene3DOnly: true, orderIndependentTranslucency: false, contextOptions: { webgl: { alpha: true } } }) viewer._cesiumWidget._creditContainer.style.display = 'none' viewer.scene.fxaa = true viewer.scene.postProcessStages.fxaa.enabled = true if (Cesium.FeatureDetection.supportsImageRenderingPixelated()) { // 判断是否支持图像渲染像素化处理 viewer.resolutionScale = window.devicePixelRatio } // 移除默认影像 removeAll() // 地形深度测试 viewer.scene.globe.depthTestAgainstTerrain = true // 背景色 viewer.scene.globe.baseColor = new Cesium.Color(0.0, 0.0, 0.0, 0) // 太阳光照 viewer.scene.globe.enableLighting = true; // 初始化图层 initLayer() // 鼠标事件 initClickEvent() //调试 window.viewer = viewer } function initClickEvent() { eventHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); initLeftClickEvent() initMouseMoveEvent() } function initLeftClickEvent() { eventHandler.setInputAction((e) => { if (selectGraphic) { selectGraphic.setSelect(false) selectGraphic = null } if (gui) { gui.destroy() } let pickedObj = viewer.scene.pick(e.position); if (pickedObj && pickedObj.id) { if (pickedObj.id.type === 'canvas_point') { selectGraphic = getGraphicById(pickedObj.id.id) if (selectGraphic) { selectGraphic.setSelect(true) initGui() } } } },Cesium.ScreenSpaceEventType.LEFT_CLICK) } function initMouseMoveEvent() { eventHandler.setInputAction((e) => { const pickedObj = viewer.scene.pick(e.endPosition); if (pickedObj && pickedObj.id) { if (pickedObj.id.type === 'canvas_point') { // 改变鼠标状态 viewer._element.style.cursor = ""; document.body.style.cursor = "pointer"; } else { viewer._element.style.cursor = ""; document.body.style.cursor = "default"; } } else { viewer._element.style.cursor = ""; document.body.style.cursor = "default"; } },Cesium.ScreenSpaceEventType.MOUSE_MOVE) } function getGraphicById(id) { let graphic = null for (let i = 0; i < canvasList.length; i++) { if (canvasList[i].entity.id === id) { graphic = canvasList[i] break } } return graphic } function initGui() { let params = { ...selectGraphic.style } gui = new GUI() let layerFolder = gui.title('参数设置') layerFolder.add(params, 'scale', 0.1, 2).step(0.1).onChange(function (value) { selectGraphic.updateStyle(params) }) } function addTdtLayer(options) { let url = `https://t{s}.tianditu.gov.cn/DataServer?T=${options.type}&x={x}&y={y}&l={z}&tk=${key}` const layerProvider = new Cesium.UrlTemplateImageryProvider({ url: url, subdomains: ['0','1','2','3','4','5','6','7'], tilingScheme: new Cesium.WebMercatorTilingScheme(), maximumLevel: 18 }); viewer.imageryLayers.addImageryProvider(layerProvider); } function initLayer() { addTdtLayer({ type: 'img_w' }) addTdtLayer({ type: 'cia_w' }) canvasLayer = new Cesium.CustomDataSource('canvasMarker') viewer.dataSources.add(canvasLayer) } function loadCanvasMarker(points) { points.forEach(item => { const canvasMarker = new CanvasMarker(viewer, item) canvasList.push(canvasMarker) canvasLayer.entities.add(canvasMarker.entity) }); viewer.flyTo(canvasLayer) updateText() } function updateText() { setInterval(()=>{ canvasList.forEach((item) => { const text = Math.floor(30 * Math.random()) item.updateStyle({ text: text }) }) }, 2000) } function removeAll() { viewer.imageryLayers.removeAll(); } function destroy() { viewer.entities.removeAll(); viewer.imageryLayers.removeAll(); viewer.destroy(); } export { initMap, loadCanvasMarker, destroy }
CanvasMarker.vue
<!-- * @Description: * @Author: maizi * @Date: 2023-04-07 17:03:50 * @LastEditTime: 2023-04-11 18:07:29 * @LastEditors: maizi --> <template> <div id="container"> </div> </template> <script> import * as MapWorks from './js/MapWorks' export default { name: 'CanvasMarker', mounted() { this.init(); }, methods:{ init(){ let container = document.getElementById("container"); MapWorks.initMap(container) //创建告警点 let points = [ [104.074822, 30.659807, 60], [104.076822, 30.653807, 60], [104.075822, 30.652807, 60], [104.072822, 30.654807, 60] ]; MapWorks.loadCanvasMarker(points) } }, beforeDestroy(){ //实例被销毁前调用,页面关闭、路由跳转、v-if和改变key值 MapWorks.destroy(); } } </script> <style lang="scss" scoped> #container{ width: 100%; height: 100%; background: rgba(7, 12, 19, 1); overflow: hidden; background-size: 40px 40px, 40px 40px; background-image: linear-gradient(hsla(0, 0%, 100%, 0.05) 1px, transparent 0), linear-gradient(90deg, hsla(0, 0%, 100%, 0.05) 1px, transparent 0); } </style>