Baidu - Echarts 地图实例测试,并绘制平滑圆弧路径

百度Echarts实例地址:
http://echarts.baidu.com/examples.html

同事想做一个地图,地图上的几个点通过动态的线连接起来。但是在实例里没找到类似的。
然后仔细分析了一下 《公交路线图》(下图)这个,查看它的数据源结构,是一长串的坐标数组:


image

如果我把这个长数组缩短为2个坐标,就是起点+终点,那么是不是就是我需要的结果?试了一下:


image

果然是这样,效果丑了点,但是看得过去。通过这个实验发现这个图的原理就是你定义一条 line ,echarts会根据你提供的坐标绘制路径。然后在选项里他实际上绘制了2遍,一遍是浅色半透明的路径,一遍是移动的光点。

然后并不满足于此,因为看到别人的图这个路径是平滑的曲线。大致找了一下api,没有找到类似的可以直接配置的选项。然后看到有一个实例是绘制各种不同的路径曲线,它的实现靠自己定义一个路径函数,生成坐标数组。然后想了一下,决定自己实现一个。
实现功能:

  • 提供两点坐标A,B,可以确定以线段AB为弦,弧度为π/6(根据自己需要调整,最大π)的圆。

          // arc 为弧AB的弧度
          function getCircleRadio(A, B, arc) {
              return Math.sqrt(Math.pow(B[0]-A[0], 2)+Math.pow(B[1]-A[1], 2)) / (2*Math.sin(arc/2));
          }
    
  • 计算出半径R,圆心坐标O
    这是个高中数学题啊?赶紧拿起笔开始算公式。经过一系列简(bai)单(du)推(sou)算(suo),可以得到一个二元二次方程组:

    • y0 - ym = k(x0 - xm); 过圆心O与AB中点M的直线斜率k,k根据AB的斜率算出(垂直)
    • (x0-xa)² + (y0-ya)² = r²;圆的方程

    经过消元得到一元二次方程,然后确定系数 a,b,c,直接求出两个根。这里我们只取其中一个,比如负根,这样圆心会在左侧。
    (这里我没有自己化简。。是直接百度来的。深刻认识到自己数学知识的匮乏)

      function getCircleOrigin(A, B, r) {
              var x0 = 0, y0 = 0;
              if (A[0] == B[0]) {
                  x0 = A[0] - Math.sqrt( r*r - Math.pow((B[1]-A[1]/2), 2));
                  y0 = (A[1] + B[1])/2;
              } else if (A[1] == B[1]) {
                  x0 = (A[0] + B[0])/2;
                  y0 = A[1] + Math.sqrt( r*r - Math.pow((B[0]-A[0]/2), 2));
              } else {
                  var M = [(A[0] + B[0])/2, (A[1] + B[1])/2],
                      k = (A[0]-B[0])/(B[1]-A[1]),
                      a = 1.0 + k * k,
                      b = -2 * M[0] - k * k * (A[0] + B[0]),
                      c = M[0] * M[0] + k * k * (A[0] + B[0]) * (A[0] + B[0]) / 4.0 - (r * r - ((M[0] - A[0]) * (M[0] - A[0]) + (M[1] - A[1]) * (M[1] - A[1])));
                  x0 = (-1.0 * b - Math.sqrt(b * b -4 * a * c)) / (2 * a);
                  y0 = k * x0 - k * M[0] + M[1];
              }
              return [x0, y0];
          }
    
  • 把弧AB等分,返回这n个坐标
    根据圆的坐标点公式:

    • y = y0 + r*sin(rad)
    • x = x0 + r*cos(rad)
      考虑到坐标系不同我把sin和cos换了一下,这里需要先算出端点A的初始弧度 :
        // 半径
        var R = getCircleRadio(A, B, arc);
        // 圆心坐标
        var Ori = getCircleOrigin(A, B, R)
        for (var i=0; i<n; i++) {
            // 等分弧度
            var angl = arc*i / n,
            // 初始弧度
                arc0 = Math.asin((A[0]-Ori[0])/R);
            var x = Ori[0] + Math.sin(arc0 + angl)*R;
            var y = Ori[1] + Math.cos(arc0 + angl)*R;
            points.push([x, y]);
        }

然后贴上完整代码(在百度的实例里粘贴可以看到效果):

    app.title = '北京公交路线 - 线特效';

function getData(point) {
    var A = point[0],
        B = point[1],
        n = 30,
        arc = Math.PI / 4,
        points = [];

    function getCircleRadio(A, B, arc) {
        return Math.sqrt(Math.pow(B[0]-A[0], 2)+Math.pow(B[1]-A[1], 2)) / (2*Math.sin(arc/2));
    }

    function getCircleOrigin(A, B, r) {
        var x0 = 0, y0 = 0;
        if (A[0] == B[0]) {
            x0 = A[0] - Math.sqrt( r*r - Math.pow((B[1]-A[1]/2), 2));
            y0 = (A[1] + B[1])/2;
        } else if (A[1] == B[1]) {
            x0 = (A[0] + B[0])/2;
            y0 = A[1] + Math.sqrt( r*r - Math.pow((B[0]-A[0]/2), 2));
        } else {
            var M = [(A[0] + B[0])/2, (A[1] + B[1])/2],
                k = (A[0]-B[0])/(B[1]-A[1]),
                a = 1.0 + k * k,
                b = -2 * M[0] - k * k * (A[0] + B[0]),
                c = M[0] * M[0] + k * k * (A[0] + B[0]) * (A[0] + B[0]) / 4.0 - (r * r - ((M[0] - A[0]) * (M[0] - A[0]) + (M[1] - A[1]) * (M[1] - A[1])));
            x0 = (-1.0 * b - Math.sqrt(b * b -4 * a * c)) / (2 * a);
            y0 = k * x0 - k * M[0] + M[1];
        }
        return [x0, y0];
    }
    var R = getCircleRadio(A, B, arc);
    var Ori = getCircleOrigin(A, B, R)
    for (var i=0; i<n; i++) {
        var angl = arc*i / n,
            arc0 = Math.asin((A[0]-Ori[0])/R);
        var x = Ori[0] + Math.sin(arc0 + angl)*R;
        var y = Ori[1] + Math.cos(arc0 + angl)*R;
        points.push([x, y]);
    }
    return points;
}

$.get('data/asset/data/lines-bus.json', function(data) {
    var hStep = 300 / (data.length - 1);
    var busLines = [{
        coords: getData([[116.4383, 40.1471], [120.5383, 23.1471]]),
        lineStyle: {
            normal: {
                color: echarts.color.modifyHSL('#5A94DF', Math.round(350))
            }
        }
    },
        {
            coords: getData([[116.4383, 40.1471], [114.5383, 25.1471]]),
            lineStyle: {
                normal: {
                    color: echarts.color.modifyHSL('#5A94DF', Math.round(160))
                }
            }
        },
        {
            coords: getData([[116.4383, 40.1471], [118.5383, 33.1471]]),
            lineStyle: {
                normal: {
                    color: echarts.color.modifyHSL('#5A94DF', Math.round(140))
                }
            }
        },
        {
            coords: getData([[116.4383, 40.1471], [123.5383, 28.1471]]),
            lineStyle: {
                normal: {
                    color: echarts.color.modifyHSL('#5A94DF', Math.round(250))
                }
            }
        }];
    myChart.setOption(option = {
        bmap: {
            center: [116.46, 29.92],
            zoom: 6,
            roam: true,
            mapStyle: {
                'styleJson': [
                    {
                        'featureType': 'water',
                        'elementType': 'all',
                        'stylers': {
                            'color': '#031628'
                        }
                    },
                    {
                        'featureType': 'land',
                        'elementType': 'geometry',
                        'stylers': {
                            'color': '#000102'
                        }
                    },
                    {
                        'featureType': 'highway',
                        'elementType': 'all',
                        'stylers': {
                            'visibility': 'off'
                        }
                    },
                    {
                        'featureType': 'arterial',
                        'elementType': 'geometry.fill',
                        'stylers': {
                            'color': '#000000'
                        }
                    },
                    {
                        'featureType': 'arterial',
                        'elementType': 'geometry.stroke',
                        'stylers': {
                            'color': '#0b3d51'
                        }
                    },
                    {
                        'featureType': 'local',
                        'elementType': 'geometry',
                        'stylers': {
                            'color': '#000000'
                        }
                    },
                    {
                        'featureType': 'railway',
                        'elementType': 'geometry.fill',
                        'stylers': {
                            'color': '#000000'
                        }
                    },
                    {
                        'featureType': 'railway',
                        'elementType': 'geometry.stroke',
                        'stylers': {
                            'color': '#08304b'
                        }
                    },
                    {
                        'featureType': 'subway',
                        'elementType': 'geometry',
                        'stylers': {
                            'lightness': -70
                        }
                    },
                    {
                        'featureType': 'building',
                        'elementType': 'geometry.fill',
                        'stylers': {
                            'color': '#000000'
                        }
                    },
                    {
                        'featureType': 'all',
                        'elementType': 'labels.text.fill',
                        'stylers': {
                            'color': '#857f7f'
                        }
                    },
                    {
                        'featureType': 'all',
                        'elementType': 'labels.text.stroke',
                        'stylers': {
                            'color': '#000000'
                        }
                    },
                    {
                        'featureType': 'building',
                        'elementType': 'geometry',
                        'stylers': {
                            'color': '#022338'
                        }
                    },
                    {
                        'featureType': 'green',
                        'elementType': 'geometry',
                        'stylers': {
                            'color': '#062032'
                        }
                    },
                    {
                        'featureType': 'boundary',
                        'elementType': 'all',
                        'stylers': {
                            'color': '#465b6c'
                        }
                    },
                    {
                        'featureType': 'manmade',
                        'elementType': 'all',
                        'stylers': {
                            'color': '#022338'
                        }
                    },
                    {
                        'featureType': 'label',
                        'elementType': 'all',
                        'stylers': {
                            'visibility': 'off'
                        }
                    }
                ]
            }
        },
        series: [{
            type: 'lines',
            coordinateSystem: 'bmap',
            polyline: true,
            data: busLines,
            silent: true,
            lineStyle: {
                normal: {
                    // color: '#c23531',
                    // color: 'rgb(200, 35, 45)',
                    opacity: 0.3,

                    width: 2
                }
            },
            progressiveThreshold: 500,
            progressive: 200
        }, {
            type: 'lines',
            coordinateSystem: 'bmap',
            polyline: true,
            data: busLines,
            lineStyle: {
                normal: {
                    width: 0
                }
            },
            effect: {
                constantSpeed: 50,
                show: true,
                trailLength: 0.5,
                symbolSize: 2
            },
            zlevel: 1
        }]
    });
});

效果图:


image

留点尾巴

这里直接用了百度地图api,各个点的坐标也是实际的经纬度。按我理解应该可以定义自己的坐标系,然后选择自己的地图,不过具体怎么实现没有再深入研究。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容