百度地图api实现渐变色轨迹线

使用百度地图api实现的渐变色轨迹线,效果如下:
渐变色轨迹线

实现方法:

1.百度地图api使用

首先引入百度地图api的依赖文件

    <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
    <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=1XjLLEhZhQNUzd93EjU5nOGQ"></script>

创建地图的实例:

        var SMap = new BMap.Map("map", {
            enableMapClick: false  //禁用点击事件
        });
        SMap.centerAndZoom(new BMap.Point(112.9353, 29.6952), 8); // 初始化地图,设置中心点坐标和地图级别
        SMap.enableScrollWheelZoom(); //启用滚轮放大缩小
        SMap.setMapStyle({
            styleJson: [{
                "featureType": "road",
                "elementType": "all",
                "stylers": {
                    "color": "#ffffff",
                    "visibility": "off"
                }
            }]
        });

2.数据准备

需要在地图上打点的坐标数据(点连成轨迹),数据太长只展示部分,数据的第三项为权值:

let pos = [
            [106.596514, 29.574914, 70],
            [106.632446, 29.620136, 70],
            [106.686345, 29.569259, 70],
            [106.745705, 29.594136, 70],
            [106.805208, 29.598407, 17],
            [106.850483, 29.583457, 17],
            [106.850483, 29.583457, 17]
		]

百度地图api不支持列表形式的坐标点,因此需要转换成point格式的数据:

        let totalPoints = [];
        //将坐标点转化成point格式
        for (let i = 0; i < pos.length; i++) {
            let bp = new BMap.Point(pos[i][0], pos[i][1]);
            totalPoints.push(bp);
        }

3.绘制轨迹

绘制这种有一定宽度的轨迹线的原理大致就是在百度地图的图层之上再添加一个canvas图层然后在绘制矩形填充颜色边框箭头之类的。
添加图层的api需要依赖一个第三方代码,下载链接在文章底部

 <script type="text/javascript" src="../src/CanvasLayer.js"></script>

绘制渐变颜色轨迹:

        //**********渐变颜色轨迹*************
        this.canvasLayer = new this.CanvasLayer({
            map: this.SMap,
            update,
        });
function update() {
            const ctx = self.canvasLayer.canvas.getContext('2d');
            if (!ctx) {
                return;
            }
            ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
            if (totalPoints.length !== 0) { // 绘制带速度颜色的轨迹 
                for (let i = 0, len = totalPoints.length; i < len - 2; i += 1) {
                    const pixel = self.SMap.pointToPixel(totalPoints[i]);

                    ///
                    const nextPixel = self.SMap.pointToPixel(totalPoints[i + 1]);
                    ctx.beginPath();
                    ctx.moveTo(pixel.x, pixel.y);
                    ctx.lineCap = 'round';
                    ctx.lineWidth = FLOODLINEWIDTH;
                    const grd = ctx.createLinearGradient(pixel.x, pixel.y, nextPixel.x,
                        nextPixel.y);
                    const nowValue = pos[i][2]
                    const nextValue = pos[i + 1][2]

                    grd.addColorStop(0, self.getColorByValue(nowValue));
                    grd.addColorStop(1, self.getColorByValue(nextValue));
                    ctx.strokeStyle = grd;
                    ctx.lineTo(nextPixel.x, nextPixel.y);
                    ctx.stroke();
                }
            }
        }

根据权值转换成颜色的函数:

        //将值转成十六进制颜色
        //0,180,0 --> 200, 200, 0 --> 200, 0, 0
        //value 0-100
        function getColorByValue(value) {
            let r = g = b = 0
            if (value <= 50) {
                g = 200
                r = parseInt(((value / 100) * 200))
            } else {
                r = 200
                g = parseInt(((100 - value) / 100) * 200)
            }
            let t1 = r.toString(16)
            t1 = t1.length == 1 ? ("0" + t1) : t1
            let t2 = g.toString(16)
            t2 = t2.length == 1 ? ("0" + t2) : t2
            let t3 = b.toString(16)
            t3 = t3.length == 1 ? ("0" + t3) : t3

            return '#' + t1 + t2 + t3
        }

添加轨迹箭头:

        //**********轨迹箭头*************
        this.canvasLayerPointer = new this.CanvasLayer({
            map: this.SMap,
            update: updatePointer,
        });
   // 箭头
        function updatePointer() {
            const ctx = self.canvasLayerPointer.canvas.getContext('2d');
            if (!ctx) {
                return;
            }
            ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
            if (totalPoints.length !== 0) {
                const lineObj = {};
                let pixelPart = 0;
                const pixelPartUnit = 40;
                for (let i = 0, len = totalPoints.length; i < len - 1; i += 1) {
                    const pixel = self.SMap.pointToPixel(totalPoints[i]);
                    const nextPixel = self.SMap.pointToPixel(totalPoints[i + 1]);
                    pixelPart += (((nextPixel.x - pixel.x) ** 2) + ((nextPixel.y - pixel.y) **
                        2)) ** 0.5;
                    if (pixelPart <= pixelPartUnit) {
                        // continue;
                    }
                    pixelPart = 0;
                    ctx.beginPath();
                    // 根据渲染像素距离渲染箭头
                    if (Math.abs(nextPixel.x - pixel.x) > 10 || Math.abs(nextPixel.y - pixel
                            .y) > 10) {
                        // 箭头一共需要5个点:起点、终点、中心点、箭头端点1、箭头端点2

                        const midPixel = new self.BMap.Pixel(
                            (pixel.x + nextPixel.x) / 2,
                            (pixel.y + nextPixel.y) / 2,
                        );

                        // 起点终点距离
                        const distance = (((nextPixel.x - pixel.x) ** 2) +
                            ((nextPixel.y - pixel.y) ** 2)) ** 0.5;
                        // 箭头长度
                        const pointerLong = 4;
                        const aPixel = {};
                        const bPixel = {};
                        if (nextPixel.x - pixel.x === 0) {
                            if (nextPixel.y - pixel.y > 0) {
                                aPixel.x = midPixel.x - (pointerLong * (0.5 ** 0.5));
                                aPixel.y = midPixel.y - (pointerLong * (0.5 ** 0.5));
                                bPixel.x = midPixel.x + (pointerLong * (0.5 ** 0.5));
                                bPixel.y = midPixel.y - (pointerLong * (0.5 ** 0.5));
                            } else if (nextPixel.y - pixel.y < 0) {
                                aPixel.x = midPixel.x - (pointerLong * (0.5 ** 0.5));
                                aPixel.y = midPixel.y + (pointerLong * (0.5 ** 0.5));
                                bPixel.x = midPixel.x + (pointerLong * (0.5 ** 0.5));
                                bPixel.y = midPixel.y + (pointerLong * (0.5 ** 0.5));
                            } else {
                                // continue;
                            }
                        } else {
                            const k0 = (
                                (
                                    (-(2 ** 0.5) * distance * pointerLong) +
                                    (2 * (nextPixel.y - pixel.y) * midPixel.y)
                                ) / (2 * (nextPixel.x - pixel.x))) + midPixel.x;
                            const k1 = -((nextPixel.y - pixel.y) / (nextPixel.x - pixel.x));
                            const a = (k1 ** 2) + 1;
                            const b = (2 * k1 * (k0 - midPixel.x)) - (2 * midPixel.y);
                            const c = (((k0 - midPixel.x) ** 2) + (midPixel.y ** 2)) - (
                                pointerLong ** 2);

                            aPixel.y = (-b + (((b * b) - (4 * a * c)) ** 0.5)) / (2 * a);
                            bPixel.y = (-b - (((b * b) - (4 * a * c)) ** 0.5)) / (2 * a);
                            aPixel.x = (k1 * aPixel.y) + k0;
                            bPixel.x = (k1 * bPixel.y) + k0;
                        }
                        ctx.moveTo(aPixel.x, aPixel.y);
                        ctx.lineWidth = 2;
                        ctx.strokeStyle = '#eee';
                        ctx.lineTo(midPixel.x, midPixel.y);
                        ctx.lineTo(bPixel.x, bPixel.y);
                        ctx.lineCap = 'round';
                        ctx.stroke();
                    }
                }
            }
        }

添加边框:

        //**********轨迹边框*************
        this.canvasLayerBack = new this.CanvasLayer({
            map: this.SMap,
            update: updateBack,
        });
        // 边框
        function updateBack() {
            const nextArray = [];
            const ctx = self.canvasLayerBack.canvas.getContext('2d');
            if (!ctx) {
                return;
            }
            ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
            if (totalPoints.length !== 0) {
                for (let i = 0, len = totalPoints.length; i < len - 2; i += 1) {
                    const pixel = self.SMap.pointToPixel(totalPoints[i]);
                    const nextPixel = self.SMap.pointToPixel(totalPoints[i + 1]);
                    ctx.beginPath();
                    ctx.moveTo(pixel.x, pixel.y);
                    ctx.lineWidth = FLOODLINEWIDTH + 3;
                    ctx.strokeStyle = '#8b8b89';
                    ctx.lineTo(nextPixel.x, nextPixel.y);
                    ctx.lineCap = 'round';
                    ctx.stroke();
                }
            }
        }

4.项目源代码

项目源代码下载

参考文章:

https://www.dazhuanlan.com/2019/10/11/5d9f6a1b1a71e/

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值