百度地图历险记之LuShu路书全解_百度地图 路书_JSYRD的博客-CSDN博客


本站和网页 https://blog.csdn.net/qq_49814035/article/details/129722908 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

百度地图历险记之LuShu路书全解_百度地图 路书_JSYRD的博客-CSDN博客
百度地图历险记之LuShu路书全解
JSYRD
已于 2023-03-24 09:06:14 修改
934
收藏
文章标签:
javascript
前端
react.js
百度
web app
于 2023-03-23 01:58:22 首次发布
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_49814035/article/details/129722908
版权
百度地图历险记之LuShu路书全解
项目简介:
接了个双创项目的前端开发的活,主要用地图来展示一些信息,比如时间地点事件什么的。使用了Antd+react解决方案。
欢迎点个star支持下:思源siyuan
React-BMapGL文档 (baidu.com)有React中使用百度地图API的封装,可以直接使用,但很可惜事实上只封装了一小部分,很多功能并没有直接封装,但是是可以通过调用JspopularGL来实现的,这样我们的操作就更广一些了。
我们如果想要使用jspopularGL,就需要获得到map对象本身。根据文档,我们可以通过ref来实现:
获取map实例
如果你在业务中需要操作map对象,需要BMapGL.Map实例的话,可以通过<Map>组件实例的map属性访问到它。
<Map ref={ref => {this.map = ref.map}} />
但是实测,因为异步加载的原因,有时候会出现undefined或者null问题,所以我们可以通过再封装一层的方式:
export default class MyMap extends React.Component {
constructor(props) {
super(props);
...
this.created = flase;
...
_initMap(){
...
this.map = this.mapRef.map;
...
componentDidMount() {
if(!this.created) {
this._initMap();
this.created = true;
render() {
...
return(
<Map ref={ref => {this.mapRef = ref}}>
...
</Map>
来解决这个问题,这样相当于把ref.map的获取放到确保组件已经生成后,就不会产生空问题。同时也可以把Map抽象出成一个React.Components,在上层直接使用,简单方便。
如果你的上层也需要map对象本身,你可以使用
render() {
const content=
<MyMap
className="map"
ref={(ref) => {this.map = ref}}
/>
来获取。
LuShu的引入
为了美观 和狂拽酷炫 ,我们使用了React-BMapGL已经封装好的Arc 2D弧线来展示路径,效果还不错:
(数据是随机mock的,所以地名和坐标都是随机的,不代表任何现实真实含义)每个点的小图标是自行实现的,不展开叙述,后面博文可能会写
完成Arc部分之后,感觉可以加些更酷的元素进去,于是在open | 百度地图API SDK (baidu.com)里面找到了这个东西: 名字叫路书,看起来很不错,是个动画,可以沿着路径走,并且可以附上HTML元素,在飞机上方展示,于是决定引入。
从示例中找到源码:
https://bj.bcebos.com/v1/mapopen/github/BMapGLLib/Lushu/src/Lushu.min.js
首先遇到的第一个问题就是,不知道怎么用。第一次遇到这样的结构:
(function (){
//function body
})()
实际上就是说定义了一个函数并且直接执行之。只需要把它下载下来放到工作文件夹中,重命名一下,然后在我们需要使用的js文件中添加:
import "./Lushu"
就可以了,然后就会发现一堆报错。
实际上报错的原因大概只有
找不到BMapGL.*
针对这类,直接改成window.BMapGL.*就可以了
缺少某个变量
这个文件由于没有直接访问到BMapGL,所以在这些变量使用前定义一下就好,例如:
这两个变量前面加上const或者var就可以了,声明一下。
defaultIcon没有
我们可以手动定义一个,比如像示例里一样用base64编码的图片:
var defaultIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAwCAYAAACFUvPfAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAACcQAAAnEAGUaVEZAAABWWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgpMwidZAAAHTUlEQVRoBdVZa2gcVRQ+Z2b2kewm203TNPQRDSZEE7VP1IIoFUFQiig+QS0tqEhLoCJIsUIFQUVBpFQUH/gEtahYlPZHIX981BCbppramjS2Jm3TNNnNupvsZnfmHs+dZCeT7M5mM5ugHpjdmfP85txz7z17F+B/SOgGMxFhby94L/tBkfbLUiAaG3HCjS83Nq5A9/SQLxEeewUJN5BCAgliBtCzG6orfncDYr42ZqbmaySzikA+QLqZAd/C9ltUwGc6iDzz9eVG3xXoyUD4I3+TLej93uj47bbnRbt1DVohPMmoRm3IKoRBrd1DQ0Ebb1FuXYMmQ/QzogszUCHclsbyu2fwFuHBNejI8mAEAE/NwuRFhNauwXjNLP6CProGvRlRB4SuPGhuECpuzcNfMJZr0BIBChN0JgcN4pOdQ7HGHP4CMUoCraPoYRxcJjOJl8OrUFF3fkGkzpQszFNJoEnJyIl41gHKow3DiZsdZCWxSwK9saoqxtG7HRCEVYRdHReo3EHumq1Jy24irz481koKiEAksH8+fQSXQhfxjMxHzL9D8yW2sOzzfHK3PDPTsQFQCeke3t9eHgsn75yfM5SZTjrY+EEoO0+MjoYd5K7YJujQKjAAMcoeuHcQezoiybpivRmq2su6lxz1kTYZuvqwo9yFwATdgpjmNuL8lP16TYhn2ojM0pnLZ3jUf4mLQwJ3Ii5t3HEsmrzCSWG+/OmJSAoDzxJtrxpO3Jd9KvRdX48pIjhRSIdlzaowdsg+fA69osRWNgmo3+YxIAB3d0aTR9eFy87O5UlR4RgJs+OzXNjbP2lvCHjs58vxg3u7u9sD+lKPR8EgKoZPyuRQIGkT5eVjo9vq61OSV4isIF3D8ad4tr8plbPMDNFbv0Tiz08owk9pxRwVDTSvgaKae2kzoMHqNV7t1rBXe47tPAyWMkJMsK28ZzwAOkE6LYSS1KlvQogL/HoaB6liUcAWLskrETdheJxdHCHN91Nr49K/WZ5DWXzQdTn+ECF+yoGUeMaAaFqHWMYYj+l6DxBWMD87KvJbtp/Zhl/6kPfW7se6eckKlkea0Q3I8HAE/B7gcpOrUTun/91MwPjy6dWrZ6xOlp8T0eStqYx+qH88XXYplQHOlOnaUsgTaKFYyK1h22/noKPvIty1/ipoXlUtgUtK8zT4Aj367tbGVQPZeNZEPJdIBk7HU8r5ZBpkecpxlZeS51r4FyGoq67kuhfw1c+nYSg2zkVuRuFWlx4BXX1n36nB+ixoU7K3jbSq2osfcU0/vJyHZwVfhWich7EvMcG16lQIhazzy1TOzsmBEXi/rQvuvaEJNjWtBCFs/hE+jlys3b53M+pWpvO7+g9xCZZAzUkTrzXS356N3BU1jC95AvpkSRQimWBbDgqpFiWTlXBmcBQOHP0ddB7FJ25fBzWhANf1ZBQuleNkGNtbW1Z2SodWputCZYmmCr9YWeZlJoLB+vKSIzT7mnRVFJ4ilRD+Go6ByqvqvTc2QU1leRawnF6HuMfYmgUsHVo5PT4Sf5CXNrnkqbYlLxnL6H+wmn3J43fCIHs11+kpVHIZlJfpz+mlrGBTRvavNC95MstTS548rfqVE/2BmEh9umtdvf1Xv7X28l4BVRKwdBzyqObFy96H3cOxPTENyrKbi/ComiYM1kW5MYAuSNSWezeFNeUFxuyXPE6PPmEIgzcen/THfnnDoUxCN/pSBg0yi9nyYAflBmP22z5VHfNpynn2+5tcAZH0H3Y2rxpheQ7J7EwSMQgZgWkqU78yvFe2XpPXsG9Sc/LzRCRRx9t4TuZtGeecQJR3w8cPX+5vr6ysVH1/++RmFNRB93KmUDfUVCg4HttWxDZugebdkNtRK8w4R3lpbRF9h4TNNb+Ov6ZeWXJyibP3yY3LKn64qabFCsJaiVzNuTnWROSf1t5pdXwvUh04MP3sfPfnn+Tnd73eWcOUnBSKuo9XATvgOUycxSZo8+CQcMWUWqeuKK9tlucaRdBIKFXDoBsKqPIiRPvXh8vOFdCZl8gEnR6QE5KWsiWfYdCLG6vK/irWi0foDVwYtY76hD95PeIzR7kLgVnT8ueWPoxf89h9FRgNfjcfP2zTwvplDjZ8JCz2t4RCOWcjDvpFsU3Qkz+34LWiLGYrEa5xmoLcHx/OZIIHZ5uU+jw9EV14OjoyUsmAr3UwjXIxv75xBY47yF2zSwLtIe9KjnylQ/SPe6uD3zvISmKXBFojpYGjy11tBvGudgZI7H8AkTfFhaeSQPNv6zUMKbf5Jnp77bJK7lkWh1yDnjoXWZsHVrsm4KM8/AVjuQYdGkzwURc1zUIiz072Xbc86HziNMvAzaNr0KqmrOaAciLaqc1PyW/sjMW4N9dpN475wLKZ7ZZM22KCe/g3rq5aFp/mLc6d60xzN7mJIdk6OzqQDpcfWRyYM726yrT5NzOMZfhv5u9tfzO/uhGRe5fzO/uhGRe5fFJ1umig8mDxL/zT/0i0f6H9L8B7n+trJOMfuMAAAAAElFTkSuQmCC";
//如果不是默认实例,则使用默认的icon
if (!(this._opts.icon instanceof window.BMapGL.Icon)) {
this._opts.icon = defaultIcon;
这么长的这一段就是用base64编码的一个图片,当然也可以找个png转base64编码的工具自己魔改。
目前为止终于能用了。由于一开始比较懒并不想去分析源码,就选择去搜索了现有的关于lushu的使用方法,发现似乎lushu有很多版本。例如上文提到过的版本,和地图JS API示例 | 百度地图开放平台 (baidu.com)这里的大地线路书等等。目前为止功能较为全面的是这里的大地线路书中的版本:
api.map.baidu.com/library/LuShu/gl/src/LuShu_min.js
不知道是什么原因。
这个版本在基础功能之上实现了geodesic,autoCenter等功能,比较实用。
部署使用之后发现问题:lushu的运动轨迹和Arc的轨迹并不重合,于是决定开始自行魔改。
部分源码解读
首先明确目标:让lushu的运动轨迹和Arc的轨迹重合。所以大概思路是
明确Arc是如何绘制的明确lushu是如何运动的修改源码,使得lushu按照Arc的轨迹运动
首先来看Arc源码(node_modules/react-bmapgl/dist/Custom/Arc.js)
重点是if(this.props.data)中的部分。可以看到Arc的轨迹实际上是通过构造OdCurve,再使用OdCurve.getPoints()方法获得轨迹中点的坐标的。
OdCurve
通过传入2个或2个以上的坐标点,来依次生成od曲线坐标集。 该曲线为2D弯曲方式,且不同于大地曲线,大地曲是根据球面最短距离来计算的,距离太近的2个点基本不会弯曲,而这个Od曲线的生成算法不同,即使很短的距离也会弯曲。
OdCurve提供了两个方法:
getPoints
描述:getPoints({number}|{undefined})
解释:获取生成的Od曲线坐标集,传入的字段为曲线的分段数,默认值是20
setOptions
描述:setOptions({Object}options)
解释:修改坐标数组等属性
看到getPoints方法,我直呼牛B,这开发者是知道使用者想要什么的。
接下来再来看看lushu是如何运动的。
首先直接看构造方法:
var LuShu = (BMapGLLib.LuShu = function (map, path, opts) {
if (!path || path.length < 1) {
return;
this._map = map;
if (opts["geodesic"]) {
this._path = getGeodesicPath(path);
} else {
this._path = path;
this.i = 0;
this._setTimeoutQuene = [];
this._opts = { icon: null, speed: 400, defaultContent: "" };
if (!opts["landmarkPois"]) {
opts["landmarkPois"] = [];
this._setOptions(opts);
this._rotation = 0;
if (!(this._opts.icon instanceof BMapGL.Icon)) {
this._opts.icon = defaultIcon;
});
大致做了以下几件事:
设置好path,也就是this._path,具体用处在后面。设置了一些字段,比如this.i设置了opts
再来看我们让lushu开始时调用的lushu.start():
LuShu.prototype.start = function () {
var me = this,
len = me._path.length;
if (me.i && me.i < len - 1) {
if (!me._fromPause) {
return;
} else {
if (!me._fromStop) {
me._moveNext(++me.i);
} else {
me._addMarker();
me._timeoutFlag = setTimeout(function () {
me._addInfoWin();
if (me._opts.defaultContent == "") {
me.hideInfoWindow();
me._moveNext(me.i);
}, 400);
this._fromPause = false;
this._fromStop = false;
};
判断了一下从什么状态开始start的,我们直接看最后一个else里的内容:
首先把图标(marker)添加进来,然后设置了一个setTimeout,具体内容是把infowindow添加进来,然后执行了me._moveNext(me.i),这个函数就是所有的关键点了。我们先明确me.i是怎么来的,事实上它就是this.i,也就是在构造函数中设置的一个字段,我们进到_moveNext中来看其含义:
_moveNext: function (index) {
var me = this;
if (index < this._path.length - 1) {
me._move(me._path[index], me._path[index + 1], me._tween.linear);
},
到这里就很明显了,在构造函数中构造的path存放的是各个点(事实上,它是一个[{lng, lat}]类型的数组),而i则是用来标注当前已经走到第几个点。我们进到_move中去看到底是如何运动的。
_move: function (initPos, targetPos, effect) {
var me = this,
currentCount = 0,
timer = 10,
step = this._opts.speed / (1000 / timer),
init_pos = BMapGL.Projection.convertLL2MC(initPos),
target_pos = BMapGL.Projection.convertLL2MC(targetPos);
init_pos = new BMapGL.Pixel(init_pos.lng, init_pos.lat);
target_pos = new BMapGL.Pixel(target_pos.lng, target_pos.lat);
var mcDis = me._getDistance(init_pos, target_pos);
var direction = null;
if (mcDis > 30037726) {
if (target_pos.x < init_pos.x) {
target_pos.x += WORLD_SIZE_MC;
direction = "right";
} else {
target_pos.x -= WORLD_SIZE_MC;
direction = "left";
var count = Math.round(me._getDistance(init_pos, target_pos) / step);
if (count < 1) {
me._moveNext(++me.i);
return;
me._intervalFlag = setInterval(function () {
if (currentCount >= count) {
clearInterval(me._intervalFlag);
if (me.i > me._path.length) {
return;
me._moveNext(++me.i);
} else {
currentCount++;
var x = effect(init_pos.x, target_pos.x, currentCount, count),
y = effect(init_pos.y, target_pos.y, currentCount, count),
pos = BMapGL.Projection.convertMC2LL(new BMapGL.Point(x, y));
if (pos.lng > 180) {
pos.lng = pos.lng - 360;
if (pos.lng < -180) {
pos.lng = pos.lng + 360;
if (currentCount == 1) {
var proPos = null;
if (me.i - 1 >= 0) {
proPos = me._path[me.i - 1];
if (me._opts.enableRotation == true) {
me.setRotation(proPos, initPos, targetPos, direction);
if (me._opts.autoView) {
if (!me._map.getBounds().containsPoint(pos)) {
me._map.setCenter(pos);
if (me._opts.autoCenter) {
me._map.setCenter(pos, { noAnimation: true });
me._marker.setPosition(pos);
me._setInfoWin(pos);
}, timer);
},
_move的源码比较长,其实总共只分为两段:
设置一些变量,比如:
currentCounttimerstepcount 然后通过计算获得一些值,比如pos相关的部分。 设置运动,也就是setInterval里面的部分。
设置的这些变量似乎有些让人摸不着头脑,我们来分析一下。首先突破口是timer这个量,因为它在setInterval中被直接用到了,含义比较明确:代表着每次执行的间隔时间。那么这段代码的终止条件是什么呢,我们来看:
if (currentCount >= count) {
clearInterval(me._intervalFlag);
if (me.i > me._path.length) {
return;
me._moveNext(++me.i);
} else {
currentCount++;
...
可以看到,事实上是每次执行都会使currentCount自增,直到等于count,我们再回过头来看count的定义:
step = this._opts.speed / (1000 / timer),
var count = Math.round(me._getDistance(init_pos, target_pos) / step);
我们来列式子算一下:
step
=
speed
1000
timer
\text{step} = \frac{\text{speed}}{1000}\times \text{timer}
step=1000speed​×timer 由于timer是常量,我们可以写成:
step
speed
\text{step} \propto \text{speed}
step∝speed 那么
count
=
distance
step
\text{count}=\frac{\text{distance}}{\text{step}}
count=stepdistance​ 这是什么,这可不就是
=
t=\frac{s}{v}
t=vs​ 嘛,所以说可以简单理解为:
count表示完成这段运动一共需要多少"帧";currentCount表示现在运动到第几"帧"了;timer表示运动一帧所需要的时间(ms);step只是一个中间量;
继续往下分析:
} else {
currentCount++;
var x = effect(init_pos.x, target_pos.x, currentCount, count),
y = effect(init_pos.y, target_pos.y, currentCount, count),
pos = BMapGL.Projection.convertMC2LL(new BMapGL.Point(x, y));
...
me._marker.setPosition(pos);
me._setInfoWin(pos);
}, timer);
},
中间省略的是与运动直接关系不太大的(关于rotation后面会讲)部分,可以看到其实和我们猜测的一样,每次执行都通过effect函数来获得下一帧的坐标,然后调用setPosition()来修改位置,这样就可以做出动效来了。
有了这些之后,我们简单的思路就是:既然Arc使用了OdCurve,我们只需要在lushu中也得到同样的点路径,然后通过修改effect方法来在每帧中获取对应的点坐标即可。
1. 构造OdCurve
首先引入mapvgl:
var mapvgl_1 = require("mapvgl");
在lushu的构造方法中完全仿照Arc构造一个点列出来即可:
...
const MAX_FRAME = 300;
if (opts["geodesic"]) {
this._path = getGeodesicPath(path);
else if (opts["odCurve"]){ // 是否使用Odcurve
var lineData = [];
var curve = new mapvgl_1.OdCurve();
for(var i = 0 ; i < path.length-1 ; i++){
var start = path[i];
var end = path[i+1];
curve.setOptions({
points: [start, end]
});
var curveModelData = curve.getPoints(MAX_FRAME-1); //最细
lineData.push(curveModelData)
this.lineData = lineData;
this._path = path;
else {
this._path = path;
...
这里有个小trick:我使用了MAX_FRAME-1作为getPoints的参数,来获取到长度为MAX_FRAME的点列,这么做是因为我想要让lushu在每段Arc的运动时长相等,而不是速度相等,避免非常短和非常长的Arc在同一个展示中,导致lushu非常鸡肋。
因为lushu是通过currentCount来控制的,如果要每段都定时的话其实非常简单,只需要固定下来count就可以了。这样的话如果我需要更改这个时长,也可以通过设置count来实现。
而MAX_FRAME其实是为了方便其它时长的情况方便地获取到点列,直接通过(0, MAX_FRAME)到(0, count)的映射就可以获得到对应的点,而不需要每针对一个count就重新获取一个点列。
2. 修改effect
事实上,effect函数是一个回调函数,它在_moveNext中被传入:
_moveNext: function (index) {
var me = this;
if (index < this._path.length - 1) {
me._move(me._path[index], me._path[index + 1], me._tween.linear);
// me._tween.linear
},
我们找到linear:
_tween: {
linear: function (initPos, targetPos, currentCount, count) {
var b = initPos;
var c = targetPos - initPos;
var t = currentCount;
var d = count;
return (c * t) / d + b;
},
emmmm,也许当时开发的时候是想过拓展多种方式的,只是没实现留了个接口而已。正好我们也用得上,只是需要魔改一下:
_tween: {
linear: function (initPos, targetPos, currentCount, count) {
...
},
OdCurve: function (currentCount, count, lineData, i) {
var lineDataArrayIndex = Math.round(MAX_FRAME*currentCount/count)
return lineData[i][lineDataArrayIndex>=MAX_FRAME?MAX_FRAME-1:lineDataArrayIndex]
},
linear我这里就直接弃用了,所以参数也重新写了,这些参数的含义都已经解释过了,函数体本身也只做了一件非常简单的事:求出对应的映射点,然后把该点直接返回。
当然在effect的调用处我们也需要小改一下(_move的setInterval里):
} else {
currentCount++; // 下一帧
// var x = effect(init_pos.x, target_pos.x, currentCount, me.speed, "x"),
// y = effect(init_pos.y, target_pos.y, currentCount, me.speed, "y"),
var nextPoint = effect(currentCount, me.speed, me.lineData, i);
var x = nextPoint[0],
y = nextPoint[1],
pos = window.BMapGL.Projection.convertMC2LL(new window.BMapGL.Point(x, y));
...
就完成了。此时会发现,确实按照轨迹运动了,但是旋转非常鬼畜,令人匪夷所思。我们再来看关于Rotation的部分:
if (me._opts.enableRotation == true) {
me.setRotation(proPos, initPos, targetPos, direction);
这里给setRotation传进去了四个参数,意义比较明确(proPos应该是prePos打错了,但是问题也不大,反正都是proPos不影响运行,而且实际上这个变量都没被用过,也不知道什么原因),我们直接来看setRotation:
setRotation: function (prePos, curPos, targetPos, direction) {
var me = this;
var deg = 0;
curPos = me._map.pointToPixel(curPos);
targetPos = me._map.pointToPixel(targetPos);
if (targetPos.x != curPos.x) {
var tan = (targetPos.y - curPos.y) / (targetPos.x - curPos.x),
atan = Math.atan(tan);
deg = (atan * 360) / (2 * Math.PI);
if ((!direction && targetPos.x < curPos.x) || direction === "left") {
deg = -deg + 90 + 90;
} else {
deg = -deg;
me._marker.setRotation(-deg);
} else {
var disy = targetPos.y - curPos.y;
var bias = 0;
if (disy > 0) {
bias = -1;
} else {
bias = 1;
me._marker.setRotation(-bias * 90);
return;
},
其实也很好理解,看到tan和atan大概就明白是直接把方向改成两个点的连线方向。但是为甚么我们使用会出问题呢,原因是传入的是这段线的起始点和终点两个点,而不是我们魔改过后的路程点列中的每个点,所以只需要在_move开始的时候设置一个新的字段currentPos:
_move: function (initPos, targetPos, effect, i) {
var me = this,
currentCount = 0,
currentPos = initPos,
...
然后再把传入的参数改成
if (me._opts.enableRotation == true) {
me.setRotation(prePos, currentPos, pos, direction);
currentPos = pos;
就可以了。
By JSYRD
阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
JSYRD
关注
关注
点赞
收藏
觉得还不错?
一键收藏
打赏
知道了
评论
百度地图历险记之LuShu路书全解
百度地图有个东西叫LuShu,比较奇怪,解读了一下,希望有所帮助。
复制链接
扫一扫
百度路书Lushu.js
11-23
百度地图的路书。实现marker沿路线运动,并有暂停等功能百度地图的路书。
百度地图路书Lushu.min.js
11-23
百度地图的路书。实现marker沿路线运动,并有暂停等功能
参与评论
您还未登录,请先
登录
后发表或查看评论
百度地图路书js
07-20
百度地图路书js,可以直接调用本地,不需要链接调用百度
百度地图路书边走边画功能
ssiizhang的博客
04-14
1097
百度地图路书边走边画功能,附带速度控制和暂停功能
百度地图Web版,根据自定义的坐标点来制作路书(行车轨迹功能)
success_error的专栏
07-31
9353
第一步,导入百度地图基础JS文件:
第二步,导入路书的基础JS文件:
核心JS:
var allPoint = [];
var point = new BMap.Point(一个坐标的经度,一个坐标的纬度);
allPoint.push(point);
.....
可以加入无数个
//由点画出一条轨迹,并且加入到地图上
var polyline = ne
百度地图路书最终版.html
06-07
百度地图的路书轨迹的实例;坐标点转换具体地址;添加标注点,标注点动画实例;标注点的label的实例;信息窗口
【百度地图】路书轨迹显示
青烟小生的博客
06-07
3644
【百度地图】路书轨迹显示通过后端返回的坐标点列表,然后在地图上展示出轨迹,并且显示标点和显示窗口文案。效果如下引入百度地图,因为百度地图的轨迹(路书)模式只能是3.0才可以使用,所以注意自己引入的是否正确
先获取到gps坐标点列表(模拟数据)
先创建地图
一、直接展示路书轨迹
添加标点
给每一个标点添加数据,可以在点击标点的方法获取的数据里面可以获取到相对应的添加的数据
添加轨迹路线。先要更加返回的坐标数组,先对坐标点进行初始化,然后在渲染。下面还有具体的属性配置
往地图添加标点和路书
给路书轨迹的线添加箭
百度地图API路书实现历史轨迹回放
Wxhwyr的博客
06-09
706
路书的基本使用
路书的开始、暂停、继续
滑动条控制路书速度
滑动条控制路书进度
路书运动过程信息窗口内容改变
路书边运动边画轨迹(使用BMap.DrivingRoute对路径进行修正)
百度地图路书(BMapLib.LuShu)------在vue项目中使用原生实现在线和离线地图
yrrjiayou的博客
05-14
4855
百度地图路书(BMapLib.LuShu)------在vue项目中使用原生实现在线和离线地图
百度地图API自定义点路书,路书点击事件,路书速度动态改变
02-14
前一段时间研究百度地图路书,查了很多资料也看源码,总结了一下,动态改变标注的位置就类似于路书而且运动速度和轨迹可以随意控制,高速运动的标注也可以触发点击事件,添加多个互不影响其它标注和地图性能,可参考百度地图API 移动的marker,移动marker点击事件及动态改变速度。
convertMC2LL:将百度地图平面投影坐标(墨卡托)转换为经纬度坐标
06-19
convertMC2LL
将百度地图平面投影坐标(墨卡托)转换为经纬度坐标
用在什么场景
使用PHP来调用百度地图API,某些情况下得到的是投影坐标,需要转换为经纬度坐标
为什么要写这个东西
首先,百度地图最好用
第二,百度接口很不准,搜个西城区的地址给你定位到门头沟去
第三,百度有些隐藏接口非常好用
第四,隐藏接口坐标是投影坐标,需要转换成经纬度坐标
第五,只有百度知道怎么转换
第六,只有百度地图JS文件能看到源码
所以就写了这么个程序来将投影坐标转换为经纬度坐标。当然是根据百度地图js原来来改造的。
使用方法
非常简单
include 'src/Baidumap.php';
$baidu = new Baidumap();
$point = new b4(1294830854, 484857493);
$ll = $baidu->convertMC2LL($point);
var_du
利用百度地图的路书功能实现汽车实时定位
05-27
可直接在谷歌浏览器上运行
百度地图路书及(路书自定义路线及多路书自定义定位最佳视角,及百度地图坐标矫正)
07-03
路书自定义路线及多路书自定义定位最佳视角,及百度地图坐标矫正精确到0.2米,都是开发心得。供大家参考!
丁丁历险记读书笔记.docx
11-29
丁丁历险记读书笔记.docx
小学生丁丁历险记读书心得.docx
11-17
小学生丁丁历险记读书心得.docx
百度地图显示路径路书polyline
Tom_boy_的博客
06-20
541
百度地图显示路径路书polyline
百度路书 地图api 封装组件
whn1231的博客
11-23
389
<script type="text/javascript" src="https://api.map.baidu.com/api?v=2.0&ak=秘钥"></script><script type="text/javascript" src="https://api.map.baidu.com/library/LuShu/1.2/src/LuShu_min.js?s=1"></script>
python小蛇历险记
最新发布
08-10
Python小蛇历险记是一个简单的游戏,基于Python编程语言开发。游戏中,玩家扮演一条小蛇,通过控制蛇的移动方向,吃食物并避免撞到墙壁或自身身体。随着吃到更多的食物,蛇的身体会不断变长,游戏的难度也会逐渐增加。
这个游戏需要使用Python编程语言的基本知识来实现。你可以使用Python的图形库(如Pygame)来创建游戏窗口,并编写代码来处理用户输入、移动蛇的位置、绘制食物和蛇的身体等。
如果你对Python编程有一定的了解,你可以尝试自己动手编写这个游戏。你可以搜索一些关于Python小蛇游戏开发的教程或者示例代码,来帮助你入门。
“相关推荐”对你有帮助么?
非常没帮助
没帮助
一般
有帮助
非常有帮助
提交
JSYRD
CSDN认证博客专家
CSDN认证企业博客
码龄3年
暂无认证
原创
116万+
周排名
13万+
总排名
2万+
访问
等级
186
积分
粉丝
29
获赞
29
评论
161
收藏
私信
关注
热门文章
Ubuntu20.04 如何降低内核版本
22528
百度地图历险记之LuShu路书全解
934
首战Flutter开发tflite详细记录
238
分类专栏
ubuntu
1篇
最新评论
Ubuntu20.04 如何降低内核版本
lansetian123:
第5步已经把GRUB_DEFAULT设置为具体的内核版本了,为什么第10步还要重新设置GRUB_DEFAULT=0?似乎没有这个必要了吧?
Ubuntu20.04 如何降低内核版本
金焱111:
找了专业人士帮我修复了
Ubuntu20.04 如何降低内核版本
JSYRD:
如果设置没错的话,可能是其他原因,比如一些包不兼容旧内核
Ubuntu20.04 如何降低内核版本
JSYRD:
可以试试找个盘刷个live救一下
Ubuntu20.04 如何降低内核版本
金焱111:
作者在吗?我电脑崩了,改了grub文件后重启,一直卡在logo界面,也给后面的人一个警告,不要随便改降低内核
您愿意向朋友推荐“博客详情页”吗?
强烈不推荐
不推荐
一般般
推荐
强烈推荐
提交
最新文章
首战Flutter开发tflite详细记录
Ubuntu20.04 如何降低内核版本
2023年2篇
2021年1篇
目录
目录
分类专栏
ubuntu
1篇
目录
评论
被折叠的 条评论
为什么被折叠?
到【灌水乐园】发言
查看更多评论
添加红包
祝福语
请填写红包祝福语或标题
红包数量
红包个数最小为10个
红包总金额
红包金额最低5元
余额支付
当前余额3.43元
前往充值 >
需支付:10.00元
取消
确定
下一步
知道了
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝
规则
hope_wisdom 发出的红包
打赏作者
JSYRD
你的鼓励将是我创作的最大动力
¥1
¥2
¥4
¥6
¥10
¥20
扫码支付:¥1
获取中
扫码支付
您的余额不足,请更换扫码支付或充值
打赏作者
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额
抵扣说明:
1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。
余额充值