d3-geo
地图投影有时作为点的转换实现。比如球形墨卡托:
function mercator(x, y) {
return [x, Math.log(Math.tan(Math.PI / 4 + y / 2))];
}
如果你的几何包含连续无限的点集时,这是一个合理的 数学 方法。然而,计算机并没有无限的内存,所以我们必须使用离散几何,比如多边形和折线!
离散几何使得从球面投影到平面更加困难。球面多边形的边缘是geodesics(测地线)great arc()的部分),而不是直线。测地线投射到平面上,除了 Installing
使用 NPM
: npm install d3-geo
. 此外还可以下载 latest release. 可以直接从 d3js.org 以 standalone library 或作为 D3 4.0 的一部分直接引入. 支持 AMD
, CommonJS
和基础的标签引入形式. 如果使用标签引入会暴露 d3
全局变量:
<script src="https://d3js.org/d3-array.v1.min.js"></script>
<script src="https://d3js.org/d3-geo.v1.min.js"></script>
<script>
var projection = d3.geoNaturalEarth1(),
path = d3.geoPath(projection);
</script>
API Reference
- Paths
地理路径生成器, d3.geoPath 与 d3-shape 很像: 给定一个 GeoJSON 或者特征对象,会生成一个
SVG
路径字符串,也可以将其 渲染到 Canvas 上. 建议使用 Canvas 进行动态或者交互式投影以提高性能. 路径生成器可以与 projections 或 transforms 一起使用,或者可以直接将平面几何呈现到 Canvas 或 SVG 中."https://github.com/d3/d3-geo/blob/master/src/path/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
使用默认的设置创建一个新的地理路径生成器. 如果指定了 projection, 则设置 当前投影. 如果指定了 context 则设置当前 当前上下文.
"https://github.com/d3/d3-geo/blob/master/src/path/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
渲染指定的 object, 可以是一个 GeoJSON 特征或者几何对象:
- Point - 单个点.
- MultiPoint - 一组点集.
- LineString - 一组点集表示的连续的线.
- MultiLineString - 组点集数组表示的多条线.
- Polygon - 点集数组表示的多边形(可能有镂空).
- MultiPolygon - 表示多个多边形的点集.
- GeometryCollection - 一组几何对象.
- Feature - 包含上述几何对象之一的特征.
- FeatureCollection - 一组集合特征.
也支持类型为 Sphere, 在绘制地球轮廓时很有用; 球体没有坐标系. 任何额外的参数都会传递给 pointRadius 访问器.
显示多个特征时, 可以将其与特征集合结合:
svg.append("path") .datum({type: "FeatureCollection", features: features}) .attr("d", d3.geoPath());
或者使用多个
path
元素:svg.selectAll("path") .data(features) .enter().append("path") .attr("d", d3.geoPath());
多个 path 元素通常比单个 path 元素慢. 但是多个 path 在单独设置样式以及交互时很有用(比如点击和鼠标移入). Canvas 的渲染(可以参考Projections
投影可以将球面多边形几何映射为平面多边形几何.
D3
提供集中标准投影的实现:- Azimuthal(方位投影)
- Composite(合成投影)
- Conic(圆锥投影)
- Cylindrical(圆柱投影)
更多投影参考 d3-geo-projection. 你也可以使用 d3.geoProjection 或者 d3.geoProjectionMutator 实现 自定义投影
"https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
返回一个新的数组 [x, y](通常是像素) 来表示给定的 point 经过投影后的坐标. 给定的点必须是以度为单位的 [longitude, latitude] 形式. 如果给定的 point 没有定义投影位置则可能返回
null
, 比如当点在投影的裁剪边界之外时."https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
根据指定的点坐标 [x, y](通常是像素) 计算出该点对应的经过投影前的以度为单位的坐标 [longitude, latitude](逆投影). 如果指定的点没有定义投影位置时可能返回
null
, 例如当点在投影的裁剪边界之外时.这种方法只定义在可逆投影上.
"https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
为指定的输出 stream(流) 返回 projection stream(投影流). 任何输入的几何图形输出之前都会被投影. 一个典型的投影包括几个几何变换: 首先将输入几何图形转换为弧度, 三轴旋转, 裁剪或沿着对向子午线剪切, 最后通过自适应重采样, 缩放和平移投影到平面上.
"https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
如果指定了 angle 则以度为单位设置投影的裁剪角度并返回投影. 如果 angle 为
null
则切换为 对向子午线裁剪 而不是small-circle
裁剪. 如果没有指定 angle 则返回当前的裁剪角度, 默认为null
.small-circle
独立于通过 projection.clipExtent 定义的视窗裁剪.可以参考 projection.preclip, d3.geoClipAntimeridian, d3.geoClipCircle.
"https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
如果指定了 extent 则将投影的视窗裁剪范围设置为指定的像素包裹框并返回投影. extent 以数组 [[x₀, y₀], [x₁, y₁]] 的形式指定, 其中 x₀ 为视窗的左侧坐标, y₀ 为顶部, x₁ 为右侧, y₁ 为底部坐标. 如果 extent 为
null
则不会执行视窗裁剪. 如果 extent 没有指定则返回当前的视窗裁剪范围, 默认为null
. 视窗裁剪独立于通过 projection.clipAngle 设置的small-circle
裁剪.参考 projection.postclip, d3.geoClipRectangle.
"https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
如果指定了 scale 则将投影的缩放因子设置为指定的值并返回投影. 如果没有指定 scale 则返回当前的缩放因子, 默认的缩放因子由具体的投影方式决定. 缩放因子与投影点之间的距离成线性关系; 但是在不同的投影中不同.
"https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
如果指定了 translate 则将投影的平移偏移量设置为指定的二元数组 [tx, ty] 并返回投影. 如果没有指定 translate 则返回当前的平移偏移, 默认为 [480, 250]. 平移偏移量决定了 投影中心 的像素坐标. 默认的平移偏移量将 ⟨0°,0°⟩ 放置在 960×500 的区域中心.
"https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
如果指定了 center 则将投影的中心设置为指定的以度为单位的 longitude 和 latitude 组成的二元数组 center 并返回投影. 如果没有指定 center 则返回当前的投影中心, 默认为 ⟨0°,0°⟩.
"https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
如果指定了 angle 则将投影后的旋转角度设置为指定的以度为单位的角度并返回投影. 如果没有指定 angle 则返回当前投影角度, 默认为 0°. 注意, 在渲染期间旋转(比如使用 context.rotate) 可能比通过投影旋转更快.
"https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
如果指定了 rotation 则将投影的 三轴球形旋转 设置为指定的 angles, 角度必须是包含两个或三个元素的表示旋转角度的数组 [lambda, phi, gamma] 用以表示 每个球面轴. (分别对应 偏航,俯仰和横滚) 如果 gamma 没有指定则默认为
0
. d3.geoRotation 也同理. 如果没有指定 rotation 则返回当前的角度默认为 [0, 0, 0]."https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
如果指定了 precision 则将投影的 自适应重采样 阈值设置为指定的像素值并返回投影. 这个值对应 Douglas–Peucker 距离. 如果 precision 没有指定则返回投影当前的采样精度, 默认为 √0.5 ≅ 0.70710…
"https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
调整投影的 scale 和 translate 使给定的 GeoJSON object 适应在 extent 范围中. extent 以 [[x₀, y₀], [x₁, y₁]] 的形式指定, 其中 x₀ 为包裹框的左边界, y₀ 为上边界, x₁ 为右边界, y₁ 为下边界. 返回投影.
例如, 对 New Jersey State Plane projection 进行缩放和平移以将 GeoJSON 对象 nj 位于 960×500 的包裹框内, 并设置边距为 20:
var projection = d3.geoTransverseMercator() .rotate([74 + 30 / 60, -38 - 50 / 60]) .fitExtent([[20, 20], [940, 480]], nj);
在确定了缩放和平移之后, 任何 clip extent 将会被忽略. 用来计算给定对象包裹框的 precision 计算的有效等级为 150.
"https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
projection.fitExtent 的便捷用法, 其中左上角坐标为 [0, 0]. 下面两个用法是等效的:
projection.fitExtent([[0, 0], [width, height]], object); projection.fitSize([width, height], object);
Azimuthal Projections
方位投影把球体直接投射到平面上.
Composite Projections
复合投影由多个投影组成. 复合投影具有固定的裁剪, 中心以及旋转, 并且复合投影不支持 Conic Projections
圆锥投影将球体投射到圆锥上, 然后将圆锥展开到平面上. 圆锥投影有两条 Cylindrical Projections
圆柱投影将球体投射到一个圆柱体上, 然后将圆柱体展开到平面上. Pseudocylindrical projections(伪圆柱投影) 是圆柱投影的延伸.
Raw Projections
原始投影是一个用来实现自定义点转换功能的函数; 它们通常被传递给 d3.geoProjection 或 d3.geoProjectionMutator. 这个接口的暴露方便了相关投影的推导. 原始投影接收球面坐标 [lambda, phi] (弧度, 不是角度) 返回点坐标 [x, y], 通常是在以原点为中心的单位正方形中.
"https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
根据指定的 raw projection 构造一个新的投影 project. project 函数以 弧度 为单位接收 longitude and latitude, 通常被称为 lambda (λ) and phi (φ), 返回二元数组 [x, y] 表示其单位投影. project 函数不需要缩放或平移点, 因为它们是通过 projection.scale, projection.translate, 和 projection.center 投影自动应用的. 同样的, 也不需要像投影那样执行任何球面旋转, 比如在投影之前使用 projection.rotate 进行球面旋转.
例如, 球面墨卡托投影可以实现为:
var mercator = d3.geoProjection(function(x, y) { return [x, Math.log(Math.tan(Math.PI / 4 + y / 2))]; });
如果 project 函数暴露 invert 方法, 则返回的投影会暴露 projection.invert.
"https://github.com/d3/d3-geo/blob/master/src/projection/index.js" title="Source" target="_blank" rel="noopener noreferrer"><>
根据指定的 raw projection factory 构造一个新的投影并返回一个当原始投影变化时调用的 mutate 函数. factory 必须返回一个原始投影. 返回的 mutate 函数返回一个投影函数. 例如, 圆锥投影通常有两个可配的平行线. 合适的 factory 比如 d3.geoConicEqualAreaRaw 应该为:
// y0 and y1 represent two parallels function conicFactory(phi0, phi1) { return function conicRaw(lambda, phi) { return […, …]; }; }
适用
d3.geoProjectionMutator
时, 你可以实现一个允许平行线改变的标准投影, 将内部使用的原始投影重新分配给 d3.geoProjection:function conicCustom() { var phi0 = 29.5, phi1 = 45.5, mutate = d3.geoProjectionMutator(conicFactory), projection = mutate(phi0, phi1); projection.parallels = function(_) { return arguments.length ? mutate(phi0 = +_[0], phi1 = +_[1]) : [phi0, phi1]; }; return projection; }
在创建可变投影时, 通常不会暴露
mutate
函数.Spherical Math
d3.geoArea(object) <>
返回指定的
GeoJSON
对象的球形区域的立体角. 等价于 path.area 的球面形式.d3.geoBounds(object) <>
返回指定
GeoJSON
对象的球面包围框. 包裹框以二维数组形式表示: [[left, bottom], [right, top]], 其中 left 为最小经度, bottom 为最小纬度, right 为最大经度, top 为最大纬度. 所有坐标都以度为单位. (注意, 在投影平面坐标中, 最小纬度通常是最大y
值, 而最大纬度通常是最小y
值) 等价于 path.bounds 的球面形式.d3.geoCentroid(object) <>
返回指定
GeoJSON
对象的球形质心. 等价于 path.centroid 的球面形式.d3.geoDistance(a, b) <>
以弧度为单位返回两点 a 和 b 之间的弧长. 每个点都必须被指定为以度为单位的二元数组的形式: [longitude, latitude]. 等价于两点之间计算 path.measure 的球面形式.
d3.geoLength(object) <>
以弧度为单位返回指定
GeoJSON
对象的弧长. 如果是多边形则返回外环的周长加上任何内环的周长. 等价于 path.measure 的球面形式.d3.geoInterpolate(a, b) <>
在给定的两个点 a 和 b 之间返回一个插值函数. 每个点都必须被指定为以度为单位的二元数组的形式: [longitude, latitude]. 返回的插值函数接收单个参数 t, 其中 t 为从
0
到1
的数值. t 为0
时插值函数返回点 a, t 为1
时插值函数返回点 b. 中间值沿着经过 a 和 b great arc()弧从 a 插值到 b. 如果 a 和 b 正相对应, 则选择任意great arc()弧.d3.geoContains(object, point) <>
判断一个点是否被包含在指定的
GeoJSON
对象中, 如果是则返回true
, 否则返回false
. 指定的点必须被指定为以度为单位的二元数组的形式: [longitude, latitude]. 如果GeoJSON
为点或者多个点则启用精确测试, 如果是球则总是返回true
; 对于其他的几何类型, 则使用一个很小的阈值来判断是否被包含.d3.geoRotation(angles) <>
根据指定的 angles 返回一个旋转函数, 其中 angles 必须是一个二元或三元数值数组 [lambda, phi, gamma] 用来表示在每个球面轴 上的旋转角度. (分别对应 偏航,俯仰和横滚) 如果省略了 gamma 则默认为
0
. 参考 projection.rotate.rotation(point) <>
以角度为单位返回将给定的点经过旋转后新的点: [longitude, latitude]. 指定的点必须以度为单位的二元数组形式: [longitude, latitude].
rotation.invert(point) <>
根据指定的点返回该点经过旋转之前的点的坐标: [longitude, latitude]. 是 rotation 的逆运算, 同理指定的点也必须是以度为单位的二元数组形式.
Spherical Shapes
在生成 great arc(大圆弧的一部分)时, 只需要给 d3.geoPath 传入
GeoJSON LineString
对象即可.D3
的插值器使用大圆插值进行内部点插值, 因此不需要大圆弧生成器.d3.geoCircle() <>
返回一个新的圆生成器。
circle(arguments…) <>
使用当前的 center, radius 和 precision 返回一个新的
GeoJSON
几何对象, 类型为Polygon
, 近似于球体表面上的一个圆. 任何参数都传递给访问器.circle.center([center]) <>
如果指定了 center 则将当前圆生成器的中心设置为指定的以度为单位的点: [longitude, latitude] 并返回圆生成器. 中心点可以指定为一个函数; 无论何时生成一个圆, 都会调用此函数, 并将传递给圆生成器的任何参数. 如果 center 没有被指定则返回当前的中心访问器, 默认为:
function center() { return [0, 0]; }
circle.radius([radius]) <>
如果指定了 radius 则将当前圆生成器的半径设置为指定的角度(以角度为单位)并返回圆生成器. radius 可以指定为一个函数; 无论何时生成一个圆, 都会调用此函数, 并将传递给圆生成器的任何参数. 如果 radius 没有被指定则返回当前的半径访问器, 默认为:
function radius() { return 90; }
circle.precision([angle]) <>
如果指定的 precision 则将圆生成器的精度设置为指定的度并返回圆生成器. 精度可以指定为函数形式; 无论何时生成一个圆, 都会调用此函数, 并将传递给圆生成器的任何参数. 如果没有指定 precision 则返回当前的精度访问器, 默认为:
function precision() { return 6; }
小圆不遵循大圆弧,因此生成的多边形只是一个近似, 指定一个较小的精确角度可以提高多边形的精度, 但也增加了生成和渲染它的成本.
d3.geoGraticule() <>
构造用于创建经纬网的几何生成器: 一种由经线和纬线组成的均匀网格, 用于显示投影变形. 默认的经纬网的经纬线在 ±80° 之间每隔 10° 设置一条线. 对于极地地区则是 90°.
graticule() <>
返回一个
GeoJSON MultiLineString
几何对象, 该对象表示此分划线的所有经纬线.graticule.lines() <>
返回一个
GeoJSON LineString
几何对象数组, 每个经线对应一个对象.graticule.outline() <>
返回一个
GeoJSON
多边形几何对象, 表示这个经纬网的轮廓, 也就是经纬网的边界.graticule.extent([extent]) <>
如果指定了 extent 则设置经纬网的经度和纬度边界. 如果没有指定 extent 则返回当前纬度边界, 默认为 ⟨⟨-180°, -80° - ε⟩, ⟨180°, 80° + ε⟩⟩.
graticule.extentMajor([extent]) <>
如果指定了 extent 则设置经纬网的经度边界. 如果没有指定 extent 则返回当前经纬网经度边界, 默认为 ⟨⟨-180°, -90° + ε⟩, ⟨180°, 90° - ε⟩⟩.
graticule.extentMinor([extent]) <>
如果指定了 extent 则设置经纬网的纬度边界. 如果没有指定 extent 则返回当前纬度边界, 默认为 ⟨⟨-180°, -80° - ε⟩, ⟨180°, 80° + ε⟩⟩.
graticule.step([step]) <>
如果指定了 step 则设置经纬网的经度和纬度步长. 如果没有指定 step 则返回经纬网的纬度步长, 默认为 ⟨10°, 10°⟩.
graticule.stepMajor([step]) <>
如果指定了 step 则设置经纬网的经度步长. 如果没有指定 step 则返回经纬网的经度步长, 默认为 ⟨90°, 360°⟩.
graticule.stepMinor([step]) <>
如果指定了 step 则设置经纬网的纬度步长. 如果没有指定 step 则返回经纬网的经度步长, 默认为 ⟨10°, 10°⟩.
graticule.precision([angle]) <>
如果指定了 precision 则以度为单位设置经纬网的精度. 如果没有指定 precision 则返回当前精度, 默认为 2.5°.
d3.geoGraticule10() <>
一个方便的方法, 直接生成默认的 10° 的全球经纬网, 以
GeoJSON MultiLineString
对象形式返回。等价于:function geoGraticule10() { return d3.geoGraticule()(); }
Streams
D3
使用一系列函数调用进行几何转换, 过渡过程中的中间值不被保存以最小化开销. 流必须实现多个方法来接收输入几何图形. 流本质上是有状态的; point 的定义取决于该点是否在 line 内, 同样地线与环的区别是由 polygon 决定的. 尽管被命名为 “流” 但是这些方法是被同步调用的."https://github.com/d3/d3-geo/blob/master/src/stream.js" title="Source" target="_blank" rel="noopener noreferrer"><>
将指定的
GeoJSON
对象流到指定的投影流. 虽然features
和geometry
对象都支持作为输入, 但是流接口只描述几何形状, 因此其他特性属性对流来说是不可见的.stream.point(x, y[, z])
指示具有指定坐标 x 和 y (以及可选的 z )的点. 坐标系统未指定并且依赖于实现; 例如, projection streams 需要以角度为单位的球面坐标作为输入. 除了多边形和线上下文外, 点表示点对象(Point or MultiPoint). 在线或者多边形里, 点表示的是路径上的点坐标.
stream.lineStart()
表示线或者多边形的起点. 在多边形里, 表示环的起点. 多边形的第一个环是外环, 通常是顺时针方向. 任何随后的环表示多边形上的孔, 通常是逆时针方向的.
stream.lineEnd()
表示线或者多边形的终点. 在多边形里, 表示环的终点. 与
GeoJSON
不同, 环的冗余闭合坐标不通过 point 表示, 而是通过多边形中的lineEnd
隐含. 因此, 给定的多边形输入:{ "type": "Polygon", "coordinates": [ [[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]] ] }
将调用流的以下方法:
stream.polygonStart(); stream.lineStart(); stream.point(0, 0); stream.point(0, 1); stream.point(1, 1); stream.point(1, 0); // 结束,不会调用 stream.point(0, 0) stream.lineEnd(); stream.polygonEnd();
stream.polygonStart()
表示多边形的开始. 多边形的第一行表示外部环, 后面的任何一行表示内部孔.
stream.polygonEnd()
表示多边形的结束.
stream.sphere()
表示球(地球, 球心在 ⟨0,0,0⟩ 的单位球).
Transforms
变换是投影的推广. 变换实现了 projection.stream 并且可以被传递给 path.projection. 然而, 变换仅仅实现的是一个投影方法子集, 并且表示任意的几何变换, 而不仅仅是球面到平面的投影.
"https://github.com/d3/d3-geo/blob/master/src/transform.js" title="Source" target="_blank" rel="noopener noreferrer"><>
使用指定的方法对象定义一个任意的转换. 任何未定义的方法都将使用直通的方式将输入到输出流. 例如, 反转
y
维度(参考 identity.reflectY):var reflectY = d3.geoTransform({ point: function(x, y) { this.stream.point(x, -y); } });
或者定义仿射矩阵变换:
function matrix(a, b, c, d, tx, ty) { return d3.geoTransform({ point: function(x, y) { this.stream.point(a * x + b * y + tx, c * x + d * y + ty); } }); }
Clipping
投影分两个阶段完成几何图形的切割或剪裁.
preclip(stream)
预剪切发生在地理坐标中. 沿着180度经线切割. 或者沿着一个纬线切割是最常见的策略.
参考 projection.preclip.
postclip(stream)
后期剪切发生在平面上, 当一个投影有一定的边界时, 例如一个将投影限制在一个矩形框中.
参考 projection.postclip.
裁剪函数以 projection stream 转换的形式实现. 预剪切操作在球面坐标上,以弧度为单位. 后剪接操作在平面坐标上,以像素为单位.
d3.geoClipAntimeridian
一个剪切函数, 使跨越180度经线的几何图形流(线或多边形)被切成两半,每一边各一个. 通常用于预剪切.
d3.geoClipCircle(angle)
生成一个剪切函数, 该函数转换流使得几何图形以围绕投影 center 的小半径角为界. 通常用于预剪切.
d3.geoClipRectangle(x0, y0, x1, y1)
生成一个剪切函数, 该函数转换流使几何图形以矩形坐标框 [[x0, y0], [x1, y1]] 为边界. 通常用于后期剪切.