投影
投影的作用是将地球上的一个点(经纬度表示)映射到平面上的一个点. 我以墨卡托举例, 其他投影使用方式类似.
const aProjection = d3.geoMercator();
const latlong = [-122.431, 37.773]; // 经纬度坐标
const [x, y] = aProjection(latlong);
还可以结合geoPath来使用, geoPath用来创建一个地理路径生成器, 路径生成器接收GeoJSON格式的feature对象或geometry对象, 来生成svg path.
geoPath
const aProjection = d3.geoMercator();
// 指定投影
const path = d3.geoPath(aProjection);
// path.projection(aProjection); // 还可以这么指定projection
// 这是一个GeoJSON geometry对象
const point = {
type: 'Point',
coordinates: [61.210817, 35.650072],
};
// 注意, 这里虽然是一个点, 但是这个点也使用path来表示的
// 返回svg path命令字符串
path(point); // M335.4664235588574,196.6605620690608m0,4.5a4.5,4.5 0 1,1 0,-9a4.5,4.5 0 1,1 0,9z
// 在svg中生成path
d3.select('svg')
.append('path')
.datum(point)
.attr('d', path);
下面我来看一下GeoJson格式示例:
geoJson = {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {},
// Point: 点
geometry: {
type: "Point",
coordinates: [105.38, 31.57],
},
},
{
type: "Feature",
properties: {},
// MultiPoint: 多个点
geometry: {
type: "MultiPoint",
coordinates: [
[105.38, 31.57],
[100.38, 30.57]
],
},
},
{
type: "Feature",
properties: {},
// LineString: 线, 就是指线段.
// 记录的是线的端点坐标,可视化时会按照记录顺序联结。对于曲线(如贝塞尔曲线)目前还没有很好的表达,但是在地理数据中,曲线一般会用LineString去拟合,现实地理世界中也没有标准的曲线地理要素。
geometry: {
type: "LineString",
coordinates: [
[105.38, 31.57],
[100.38, 30.57]
],
},
},
{
type: "Feature",
properties: {},
// MultiLineString: 多条线段
geometry: {
type: "MultiLineString",
coordinates: [
[
[105.38, 31.57],
[100.38, 30.57],
],
[
[105.38, 31.57],
[100.38, 30.57],
]
],
},
},
{
type: "Feature",
properties: {},
// Polygon: 多边形
geometry: {
type: "Polygon",
coordinates: [
[
[106.10595703125, 33.33970700424026],
[106.32568359375, 32.41706632846282],
[108.03955078125, 32.2313896627376],
[108.25927734375, 33.15594830078649],
[106.10595703125, 33.33970700424026]
]
],
},
},
{
type: "Feature",
properties: {},
// MultiPolygon: 多个多边形
geometry: {
type: "MultiPolygon",
coordinates: [
// 第一个多边形
[
[
[106.10595703125, 33.33970700424026],
[106.32568359375, 32.41706632846282],
[108.03955078125, 32.2313896627376],
[108.25927734375, 33.15594830078649],
[106.10595703125, 33.33970700424026]
]
],
// 第二个多边形
[...],
],
},
},
],
}
path能接收参数为GeoJSON格式的feature对象或geometry对象:
// 类型为Point、MultiPoint、LineString、MultiLineString、Polygon、MultiPolygon的geometry对象
path({
type: "Point",
coordinates: [105.38, 31.57],
});
path({
type: "MultiPoint",
coordinates: [
[105.38, 31.57],
[100.38, 30.57]
],
});
...
// 或者传入feature对象
path({
type: "Feature",
properties: {},
// Point: 点
geometry: {
type: "Point",
coordinates: [105.38, 31.57],
},
});
// 或者传入整个FeatureCollection
path(geoJson);
在canvas上绘制
上面的例子中path生成了svg path命令字符串, 可以设置给svg path元素的d属性, 从而生成路径.
我们还可以在canvas绘制路径. 我们将canvas 2d context传入geoPath, 这样路径生成函数就会使用canvas api来绘制路径:
const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');
const aProjection = d3.geoMercator();
const path = d3.geoPath();
path.projection(aProjection);
// 指定context
// 如果不指定context, 调用路径生成器返回SVG path 字符串
// 如果指定context, 则调用canvas 2d相关api绘制路径
path.context(context);
context.fillStyle = '#ccc';
context.strokeStyle = '#000';
context.beginPath();
path(countries);
context.fill();
context.stroke();
path.area(object)
同样的参数object为GeoJSON格式的feature对象或geometry对象. 它返回该对象在平面上的面积, 注意是图形上的面积, 而不是实际的地理面积. 其中Point、MultiPoint、LineString、MultiLineString面积为0.
path.bounds(object)
返回边界[[x₀, y₀], [x₁, y₁]].
path.centroid(object)
返回中心(重心)
path.measure(object)
返回长度. 其中Point、MultiPoint为0.