# 数据源与图层
# 主要特点:
- 无需区分绘制、布局和其他属性。
- 所有属性都可以表示为camelCase 而不是kebab-case。
- 层操作可以作用于多个层(由数组、正则表达式或过滤器函数给出),而不仅仅是一层。
- 源类型、图层类型和属性名称合并到函数名称中:
addGeoJSON()
,addCircleLayer()
,setCircleRadius()
,getTextFont()
... - 添加层和源是幂等的:调用
addLineLayer()
多次创建,然后更新层。 - 其他一些便利功能:
show()
,hide()
,onLoad()
,setData()
,fontsInUse()
- 更好的点击和悬停功能:
hoverPointer()
,hoverFeatureState()
,hoverPopup()
,clickLayer()
- 某些功能表现更好:(
removeLayer()
如果图层不存在则不会出错),removeSource()
(自动删除附加图层),setFilter()
(一次在多个图层上工作),setData()
如果没有提供 GeoJSON ,则清除数据。
# 使用图层
props
添加图层时传递的对象可以自由混合绘制、布局等属性。可以在camelCase 或kebab-case 中指定属性键:
map.addCircleLayer('trees-circle', 'trees', {
circleColor: 'green', // paint property
circleRadius: ['interpolate', ['zoom'], 12, 3, 15, 5], // paint property
circleSortKey: ['get', 'tree-sort-key'], // layout property
filter: ['!=', 'type', 'stump'], // other property
});
1
2
3
4
5
6
2
3
4
5
6
几乎所有适用于现有层(例如show()
)的方法都可以适用于多个层。有四种方法可以指定要修改的图层:
- 字符串:
map.show('trees-label'); map.show('trees-circle');
- 字符串数组:
map.show(['trees-label', 'trees-circle'])
; - 正则表达式:
map.show(/^trees-/)
; - 接受一个层并返回真实值的函数:
map.show(layer => layer.source === 'trees');
# 添加源
添加源的方法返回一个对象,可以链接该对象以允许向其中添加层:
map.addGeoJSONSource( 'properties' )
.addCircleLayer( 'properties-line' , { lineWidth : 3 })
.addSymbolLayer( 'properties-fill' , { fillColor : 'hsla(30,30%,60%,0.5)' })
1
2
3
2
3
添加和删除图层
// 方便地添加线要素,混合绘制,布局等属性。
// 请注意,您可以对所有属性名称使用驼峰命名法。
map.addLineLayer( 'mylines' , 'mysource' , {
lineWidth : 3 ,
lineCap : 'round' ,
minzoom : 11
});
// 还有 addFillLayer, addFillExtrusionLayer, addRasterLayer, addVideoLayer, addSymbolLayer, addHillshadeLayer, addHeatmapLayer
map.addCircleLayer( 'mycircles' , 'mysource' , { circleStrokeColor : 'red' });
// 如果图层已经存在,调用 add*Layer 只会更新任何属性
map.addCircleLayer( 'mycircles' , 'mysource' , { circleStrokeColor : 'red' , circleRadius : 4 , filter: ['==', 'type', 'active'});
// 当然,如果需要,在另一个图层“之前”添加图层:
map.addLineLayer( 'mylayer' , 'mysource' , { lineColor : 'red' }, 'toplayer' );
// 如果图层不存在,removeLayer() 不会抛出错误
map.removeLayer([ 'towns' , 'town-labels' ]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 添加和删除源
// 创建 GeoJSON 源的更简单方法:
map.addGeoJSON( 'mysource' , geojson);
// 或者使用初始空白数据创建一个 GeoJSON 源。如果您单独加载, 数据并且稍后将调用`setData()`这将非常方便。
map.addGeoJSON( 'mysource' );
// 创建矢量切片源的更简单方法:
map.addVector( 'mysource' , 'xxx' );
map.addVector( 'mysource' , 'https://example.com/tiles/{z}/{x}/{y}.pbf' );
// 其他属性仍然有效
map.addVector( 'mysource' , 'https://example.com/tiles/{z}/{x}/{y}.pbf' , { maxzoom : 13 });
// 还有 addRaster(), addRasterDem(), addImage(), addVideo()
// 调用任何 add* 函数只会更新源定义(如果源定义已经存在)。
// 使用这些源自动删除任何层。如果源不存在,则不是错误。
map.removeSource(['buildings', 'roads']);
// 您也可以使用返回的对象方便地添加图层:
map.addGeoJSON( 'buildings' , 'data/buildings.geojson' )
.addFillExtrusion( 'buildings-3d' , {
fillExtrusionHeight : 100 ,
fillExtrusionColor : 'grey'
}).addLineLayer( 'buildings-footprint' , {
lineColor : ' lightblue '
});
// 替换现有图层上的源。(实际上删除并重新添加它。)
map.setLayerSource( 'buildings' , 'newsource' );
map.setLayerSource([ 'buildings-3d' , 'buildings-outline]' , 'newsource' , 'newsourcelayer' );
// 要更改源图层,请传递第三个参数或 null 以清除它(如果从矢量切片切换到 geojson)
map.setLayerSource( 'buildings' , 'mylocalbuildings' , null );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 设置属性和更新数据
// 每个属性都有一个 setXxx() 形式:
map.setTextSize( 'mylayer' , 12 );
// 它们都同时作用于多个层:
map.setLineWidth([ 'mylayer' , 'mylayer-highlight' ], 4 );
map.setLineOpacity( /^ border- / , 0 );
map.setFillColor( layer => layer.source === 'farms' , 'green' );
// 还有一个更熟悉的 setProperty() 形式。
map.setProperty( 'mylayer' , 'line-width' , 3 );
// 现有属性不会被触及
map.setProperty( 'mylayer' , {
textSize : 12 ,
textColor : 'red'
});
// 每个函数都有一个 `get...` 版本。
map.getFillColor( 'water' )
// 更新源数据的更简单方法:
map.setData( 'mysource' , data);
// 您可以省略 data 参数以清除 GeoJSON 源:
map.setData( 'mysource' );
// 更容易记住打开和关闭图层的方法:
map.show( 'mylayer' );
map.hide( 'mylayer' );
map.toggle([ 'mylayer' , 'myotherlayer' ], isVisible);
// 为避免名称冲突,例如与 'raster' 的名称冲突,您可以使用更长的形式
// 以 ...Layer() 或 ...Source()结尾
map.addRasterSource( 'myrastersource' , { type : 'raster' , url : 'xxx' , tileSize : 256 });
map.addRasterLayer( 'myrasterlayer' , 'myrastersource' , { rasterSaturation : 0.5 });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 悬停和点击
// 悬停在此图层上时使用鼠标“手指”光标。
map.hoverPointer( 'mylayer' );
// 如果您传递多个图层,它会正确处理从一个图层移动到另一个图层
// 悬停在该图层上时使用鼠标“手指”光标。
map.hoverPointer([ 'regions-border' , 'regions-fill' ]);
// 当鼠标移动到该层的特征上时,将“悬停”特征状态设置为真或假。
// 要求特性有一个 `id`。
map.hoverFeatureState( 'mylayer' );
// 想要将悬停功能状态应用于不同的源?
// 例如,您将鼠标悬停在标签上,但想要突出显示周围的边界。
map.hoverFeatureState( 'town-labels' , 'boundaries' , 'town-boundaries' );
// 您还可以添加其他事件处理程序:
map.hoverFeatureState( 'mylayer' , 'mysource' , 'mysourcelayer' ,
e => console.log(`Entered ${e.features[0].id}`),
e => console.log(`Left ${e.oldFeatureid}`);
// 当一个功能悬停或点击时显示一个弹出窗口。
// 第三个参数是一个选项对象,传递给 Popup 构造函数。
// 回调被调用为: (feature, popup) => htmlString
map.hoverPopup( 'mylayer' , f => `<h3> ${f.properties.Name} </h3> ${f.properties.Description} ` , { anchor : 'left' });
map.clickPopup( 'mylayer' , f => `<h3> ${f.properties.Name} </h3> ${f.properties.Description} ` , { maxWidth : 500 });
// clickLayer() 类似于 .on('click)',但可以接受一个数组并向事件中添加一个 'features' 成员用于点击的内容。
map.clickLayer([ 'towns' , 'town-labels' ], e => panel.selectedId = e.features[ 0 ].id);
// clickOneLayer 按顺序测试多个层,在第一个命中的 上触发回调。回调被传递 { 功能,功能,层,事件 }。
map.clickOneLayer([ 'town-labels' , 'state-boundaries' ], e => {
if (e.layer === 'town-labels') {
setView('town');
panel.selectedId = e.features[0].id;
} else if (e.layer === 'state-boundaries') {
setView('state');
panel.selectedId = e.features[0].id;
}
});
// 可选地传入一个额外的回调,该回调为错过所有图层的点击而触发:
map.clickOneLayer(['town-labels', 'state-boundaries'], e => {...}, e => {
console.log('Missed everything');
});
// 所有这些函数都返回一个“撤消”函数,删除添加的处理程序:
const remove = map.hoverPopup( 'mylayer' , showPopupFunc);
//...
remove(); // 不再有悬停弹出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 其他功能
// 与 on('load') 类似,但在地图加载后的任何时候都会立即(并且可靠地)触发。
map.onLoad(回调);
// 如果没有回调,则返回一个承诺:
await map.onLoad();
// 获取图层定义。
const layer = map.getLayerStyle( 'mylayer' );
// 首先将所有其他属性重置为默认值。忽略非绘制、非布局属性。
map.setLayerStyle( 'mylayer' , {
lineWidth : 3
});
// properties() 将对象转换为 `kebab-case`写法的图层对象
map.addLayer(map.properties({
id : 'mylayer' ,
source : 'mysource' ,
type : 'line' ,
lineWidth : 3 ,
lineCap : 'round' ,
minzoom : 11 ,
filter : [ '==' , 'status' , 'confirmed' ]
}));
// layerStyle() 很灵活,可以根据需要传递尽可能多的 id, source, 和 type
map.layerStyle( 'mylayer' , 'mysource' , 'line' , { ... })
map.layerStyle( 'mylayer' , 'mysource' , { ... })
map.layerStyle( 'mylayer' , { ... })
map.layerStyle({ ... })
// 隐藏/显示/切换附加到此源地图的所有图层
map.hideSource('buildings');
map.showSource('buildings');
map.toggleSource('buildings', true);
// 一次更新多个过滤器。
map.setFilter([ 'buildings-fill' , 'buildings-outline' , 'buildings-label' ], [...]);
// 一步方便地将图像加载到地图中
map.loadImage( 'marker' , '/assets/marker-pin.png' );
map.loadImage( 'marker' , '/assets/marker-pin@2x.png' , { pixelRatio : 2 }).then( /* ... */) ;
// 更新地图样式的根“transition”属性
map.setTransition({ delay : 1000 , delay : 0 });
// 使用 fontsUsed() 获取符号层中使用的字体列表。用于快速显示一些文本。
const fonts = map.fontsInUse();
map.addSymbolLayer( 'labels' , 'mysource' , { textFont : fonts[ 0 ], textField : '{label}' });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 例子
map.onload( () => {
map.addGeoJSON('towns');
map.addCircleLayer('small-towns', 'towns', { circleColor: 'green', filter: ['==', 'size', 'small']});
map.addCircleLayer('large-towns', 'towns', {
circleColor: 'red',
filter: ['==', 'size', ['large']],
circleStrokeWidth: ['case', ['to-boolean', ['feature-state', 'hover']], 5, 1]
);
map.setCircleRadius(['small-towns', 'large-towns'], 12);
map.hoverPointer(['small-towns', 'large-towns']);
map.hoverFeatureState('large-towns');
// 更新数据
d3.json('http://example.com/towns.json', data => map.setData('towns', data));
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14