超图系列 - 绘制自定义点位

45 阅读2分钟

效果

image.png

使用

const points = [  
    { name: '这是携带icon并且很长的文字', theme: 'icon', center: [120.153576, 30.287459] },  
    { name: '很短', theme: 'icon', center: [120.582112, 29.997117] },  
    { name: '无Icon的文字', theme: 'normal', center: [121.549792, 29.868388] },  
];  
new LayerBoxOperations('LevelOne', points, { show: true });

封装方法

// SuperMap3D实例或Cesium实例
import SuperMap3DLayer from '@/pages/screen/SuperMap3DLayer';  
  
interface Theme {  
    bg: string[];  
    arrow: string[];  
    icon?: string;  
}  
  
interface Themes {  
    normal: Theme;  
    icon: Theme;  
}  
interface Options {  
    show: boolean;  
    theme?: 'normal' | 'town' | 'village' | 'province' | 'country';  
}
export default class LayerBoxOperations {  
    points: any;  

    private entities: any;  

    private options: any;  

    private themes: Themes;  

    private layerName: string;  

    constructor(layerName: string, points: any[], options) {  
        this.layerName = layerName;  
        this.points = [  
            { name: '这是携带icon并且很长的文字', theme: 'icon', center: [120.153576, 30.287459] },  
            { name: '很短', theme: 'icon', center: [120.582112, 29.997117] },  
            { name: '无Icon的文字', theme: 'normal', center: [121.549792, 29.868388] },  
        ];  
        this.options = options;  
        this.themes = {  
            normal: {  
                bg: ['#558DFF', '#DF82FF'],  
                arrow: ['rgba(85,141,255,0)', '#DF82FF'],  
            },  
            icon: {  
                bg: ['#558DFF', '#DF82FF'],  
                arrow: ['rgba(38,55,95,0)', '#6699FF'],  
                icon: 'bg_g.png',  
            },  
        };
     
        this.entities = [];  
        this.renderPoints();  
    }  

    createGradientTextImage(text) {  
        return new Promise((resolve) => {  
            // 创建一个 canvas 元素  
            const canvas = document.createElement('canvas');  
            const context = canvas.getContext('2d');  

            const option = this.themes[theme];  
            const hasIcon = theme === 'ICON';
            const baseText = 20;  
            // 根据文字长度不同 设置 canvas 的大小  
            canvas.width = baseText * text.length;  
            if (hasIcon) {  
                canvas.width += 30;  
            }  
            canvas.height = 86;  
            // 画出左下角的三角形  
            context.beginPath();  
            context.moveTo(canvas.width / 2 - 15, 30);  
            context.lineTo(canvas.width / 2 + 15, 30);  
            context.lineTo(canvas.width / 2, 72);  
            context.closePath();  

            const gradient2 = context.createLinearGradient(15, 0, 15, 72);  
            gradient2.addColorStop(0, option.arrow[0]);  
            gradient2.addColorStop(1, option.arrow[1]);  
            // 使用相同的渐变来填充三角形  
            context.fillStyle = gradient2;  
            context.fill();  

            // 创建一个渐变  
            const gradient = context.createLinearGradient(0, 0, canvas.width, 40);  
            gradient.addColorStop(0, option.bg[0]);  
            gradient.addColorStop(1, option.bg[1]);  

            // 设置 context 的属性  
            context.fillStyle = gradient;  
            context.font = '16px Arial';  
            context.textAlign = 'center';  
            context.textBaseline = 'middle';  
            context.shadowColor = 'rgba(0, 0, 0, 0.5)'; // 阴影颜色  
            context.shadowBlur = 8; // 阴影模糊度  
            context.shadowOffsetY = 1; // 阴影在Y轴的偏移量  
            // 画出渐变背景  
            context.fillRect(0, 0, canvas.width, 40);  

            // 设置文字的颜色和内容  
            context.fillStyle = 'white';  
            if (hasIcon) {  
                context.fillText(text, canvas.width / 2 + 15, 20);  
                // 绘制图标  
                const img = new Image();  
                img.onload = function () {  
                    context.drawImage(img, 8, 3, 34, 34); // 参数是图像,x位置,y位置,宽度,高度  
                    resolve(canvas.toDataURL());  
                };  
                img.src = `/static/screen/${option.icon}`;  
            } else {  
                context.fillText(text, canvas.width / 2, 20);  
                resolve(canvas.toDataURL());  
            }  
        });  
    }  

    renderPoints() {  
        for (let i = 0; i < this.points.length; i++) {  
            const point = this.points[i];  
            if (!point.center) break;  
            // 渲染点的名称  
            this.createGradientTextImage(point.name).then((imageUrl) => {  
                const entitie = {  
                    show: this.options.show || false,  
                    position: SuperMap3D.Cartesian3.fromDegrees(point.center[0], point.center[1]),  
                    dataset: point,  
                    billboard: {  
                    image: imageUrl,  
                    disableDepthTestDistance: Number.POSITIVE_INFINITY,  
                    },  
                    name: this.layerName,  
                };  
                this.entities.push(entitie);  
                SuperMap3DLayer.viewer.entities.add(entitie);  
            });  
        }  
    }  
}