一、代码
css部分
页面主题内外边距设置为零,map容器使用绝对定位,width 100占满页面。
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
body部分
<div id='map'></div>
js部分
1、创建一个pulsingDot对象,后续将作为map.addImage的第二个参数。
对象参数:width,height,data(绘图数据,由context.getImageData()获得),context(canvas对象,用于绘图)。
对象方法:
onAdd():调用一次,负责创建一个canvas对象(context)给pulsingDot。
render():在mapbox中被循环调用,根据t参数的不同,每次调用生成的绘图数据(data)也不同。返回true,通知mapbox image被更新。
var pulsingDot = {
// pulsingDot对象属性
width: size,
height: size,
data: new Uint8Array(size * size * 4),
// onAdd方法,在addImage中被调用一次,创建一个画布对象赋值给pilsingDot.context。
onAdd: function() {
var canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;
this.context = canvas.getContext('2d');
},
// reder方法,在addImage后被循环调用。
render: function() {
// t是函数变量,由于是通过当前事件生成的,每次调用时值均不同。
var duration = 1000;
var t = (performance.now() % duration) / duration;
// 设置内圆半径,外圆半径,获取到初始化(onAdd)时创建的画布对象。
var radius = size / 2 * 0.3;
var outerRadius = size / 2 * 0.7 * t + radius;
var context = this.context;
// 使用t变量绘图,分外圆和内圆两部分
// draw outer circle
context.clearRect(0, 0, this.width, this.height);
context.beginPath();
context.arc(this.width / 2, this.height / 2, outerRadius, 0, Math.PI * 2);
context.fillStyle = 'rgba(255, 200, 200,' + (1 - t) + ')';
context.fill();
// draw inner circle
context.beginPath();
context.arc(this.width / 2, this.height / 2, radius, 0, Math.PI * 2);
context.fillStyle = 'rgba(255, 100, 100, 1)';
context.strokeStyle = 'white';
context.lineWidth = 2 + 4 * (1 - t);
context.fill();
context.stroke();
// 绘制完毕后,将绘图数据通过getImageData获取,赋值给pulsingDot.data
// update this image's data with data from the canvas
this.data = context.getImageData(0, 0, this.width, this.height).data;
// 使用该方法使地图重新绘制
// keep the map repainting
map.triggerRepaint();
// return `true` to let the map know that the image was updated
return true;
}
};
2、主函数,将pulsingDot对象以image的形式加载到地图上。
map.on('load', function () {
// 将这个封装了绘制动图方法的对象pulsingDot传入,使用addImage方法加载到地图上。
map.addImage('pulsing-dot', pulsingDot, { pixelRatio: 2 });
// 将map渲染到地图上,使用image(pulsing-dot)和一个feature(Point)。
map.addLayer({
"id": "points",
"type": "symbol",
"source": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [0, 0]
}
}]
}
},
"layout": {
"icon-image": "pulsing-dot"
}
});
});
二、学习总结
1、map.addLayer(layer,beforeId?)
向map中添加图层。
参数:
layer(必选) 需添加的样式图层,style规范中有详细解释。http://www.mapbox.cn/mapbox-gl-js/style-spec/#layersb
beforeId(可选) 渲染在哪个图层之上。
在本案例中使用情况如下:
map.addLayer({
// 独一无二的Layer名字(必选)
"id": "points",
// one of "fill", "line", "symbol", "circle", "heatmap", "fill-extrusion",
"raster", "hillshade", "background"(必选)
// fill: 带有可选的边框的填充多边形
// circle: 一个填充的实心圆
// symbol: 图标或文本
"type": "symbol",
// 源 定义该图层的描述信息 可在外部定义 使用id链接到这里 source Style规范见
// http://www.mapbox.cn/mapbox-gl-js/style-spec/#sources
"source": {
// 源的类型
"type": "geojson",
// 源的数据
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [0, 0]
}
}]
}
},
// 布局设计属性
"layout": {
"icon-image": "pulsing-dot"
}
});
2、map.addImage(id, image, option)
向map中添加image
参数:
id(必选) Image独一无二的名字
image(必选)
image((HTMLImageElement | ImageBitmap | ImageData | {width: number, height: number, data: (Uint8Array | Uint8ClampedArray)} | StyleImageInterface))
The image as an HTMLImageElement
, ImageData
, ImageBitmap
or object with width
, height
, and data
properties with the same format as ImageData
.
options((Object | null))
(default {}
)Options object.(可选)
本案例中,使用{width:
number
, height: number
, data: (Uint8Array
| Uint8ClampedArray
)} | StyleImageInterface
))},并且多了onAdd(),render()两个方法。
// 该对象由width,height,data(Uint8Array)构成
var pulsingDot = {
width: size,
height: size,
data: new Uint8Array(size * size * 4),
onAdd: function() {
var canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;
this.context = canvas.getContext('2d');
},
render: function() {
var duration = 1000;
var t = (performance.now() % duration) / duration;
var radius = size / 2 * 0.3;
var outerRadius = size / 2 * 0.7 * t + radius;
var context = this.context;
// draw outer circle
context.clearRect(0, 0, this.width, this.height);
context.beginPath();
context.arc(this.width / 2, this.height / 2, outerRadius, 0, Math.PI * 2);
context.fillStyle = 'rgba(255, 200, 200,' + (1 - t) + ')';
context.fill();
// draw inner circle
context.beginPath();
context.arc(this.width / 2, this.height / 2, radius, 0, Math.PI * 2);
context.fillStyle = 'rgba(255, 100, 100, 1)';
context.strokeStyle = 'white';
context.lineWidth = 2 + 4 * (1 - t);
context.fill();
context.stroke();
// update this image's data with data from the canvas
this.data = context.getImageData(0, 0, this.width, this.height).data;
// keep the map repainting
map.triggerRepaint();
// return `true` to let the map know that the image was updated
return true;
}
};