geoView.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. "use strict";
  2. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  3. if (k2 === undefined) k2 = k;
  4. var desc = Object.getOwnPropertyDescriptor(m, k);
  5. if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
  6. desc = { enumerable: true, get: function() { return m[k]; } };
  7. }
  8. Object.defineProperty(o, k2, desc);
  9. }) : (function(o, m, k, k2) {
  10. if (k2 === undefined) k2 = k;
  11. o[k2] = m[k];
  12. }));
  13. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  14. Object.defineProperty(o, "default", { enumerable: true, value: v });
  15. }) : function(o, v) {
  16. o["default"] = v;
  17. });
  18. var __importStar = (this && this.__importStar) || function (mod) {
  19. if (mod && mod.__esModule) return mod;
  20. var result = {};
  21. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  22. __setModuleDefault(result, mod);
  23. return result;
  24. };
  25. var __rest = (this && this.__rest) || function (s, e) {
  26. var t = {};
  27. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
  28. t[p] = s[p];
  29. if (s != null && typeof Object.getOwnPropertySymbols === "function")
  30. for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  31. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
  32. t[p[i]] = s[p[i]];
  33. }
  34. return t;
  35. };
  36. Object.defineProperty(exports, "__esModule", { value: true });
  37. exports.GeoView = void 0;
  38. const scale_1 = require("@antv/scale");
  39. const util_1 = require("@antv/util");
  40. const d3_geo_1 = require("d3-geo");
  41. const mark_1 = require("../utils/mark");
  42. const d3Projection = __importStar(require("./d3Projection"));
  43. /**
  44. * Get projection factory from d3-projection.
  45. */
  46. function normalizeProjection(type) {
  47. if (typeof type === 'function')
  48. return type;
  49. const name = `geo${(0, util_1.upperFirst)(type)}`;
  50. const projection = d3Projection[name];
  51. if (!projection)
  52. throw new Error(`Unknown coordinate: ${type}`);
  53. return projection;
  54. }
  55. /**
  56. * @see https://github.com/mapbox/geojson-merge/blob/master/index.js
  57. */
  58. function mergeGeoJSON(gjs) {
  59. return {
  60. type: 'FeatureCollection',
  61. features: gjs.flatMap((gj) => normalizeGeoJSON(gj).features),
  62. };
  63. }
  64. function normalizeGeoJSON(gj) {
  65. const types = {
  66. Point: 'geometry',
  67. MultiPoint: 'geometry',
  68. LineString: 'geometry',
  69. MultiLineString: 'geometry',
  70. Polygon: 'geometry',
  71. MultiPolygon: 'geometry',
  72. GeometryCollection: 'geometry',
  73. Feature: 'feature',
  74. FeatureCollection: 'featureCollection',
  75. };
  76. if (!gj || !gj.type)
  77. return null;
  78. const type = types[gj.type];
  79. if (!type)
  80. return null;
  81. if (type === 'geometry') {
  82. return {
  83. type: 'FeatureCollection',
  84. features: [
  85. {
  86. type: 'Feature',
  87. properties: {},
  88. geometry: gj,
  89. },
  90. ],
  91. };
  92. }
  93. else if (type === 'feature') {
  94. return {
  95. type: 'FeatureCollection',
  96. features: [gj],
  97. };
  98. }
  99. else if (type === 'featureCollection') {
  100. return gj;
  101. }
  102. }
  103. /**
  104. * Specify the options for d3 projection
  105. * @see https://github.com/d3/d3-geo#projections
  106. * @todo Specify key each by each.
  107. */
  108. function setProjectionOptions(projection, options) {
  109. var _a;
  110. for (const [key, value] of Object.entries(options)) {
  111. (_a = projection[key]) === null || _a === void 0 ? void 0 : _a.call(projection, value);
  112. }
  113. }
  114. function setProjectionSize(projection, nodes, layout, options) {
  115. const defaultOutline = () => {
  116. const geoNodes = nodes.filter(isGeoPath);
  117. // For geoPath with sphere mark, use it as outline.
  118. const sphere = geoNodes.find((d) => d.sphere);
  119. if (sphere)
  120. return { type: 'Sphere' };
  121. // Merge all GeoJSON as the outline.
  122. return mergeGeoJSON(geoNodes.filter((d) => !d.sphere).flatMap((d) => d.data.value));
  123. };
  124. const { outline = defaultOutline() } = options;
  125. const { size = 'fitExtent' } = options;
  126. if (size === 'fitExtent') {
  127. return setFitExtent(projection, outline, layout);
  128. }
  129. else if (size === 'fitWidth') {
  130. return setFitWidth(projection, outline, layout);
  131. }
  132. }
  133. function setFitExtent(projection, object, layout) {
  134. const { x, y, width, height } = layout;
  135. projection.fitExtent([
  136. [x, y],
  137. [width, height],
  138. ], object);
  139. }
  140. function setFitWidth(projection, object, layout) {
  141. const { width, height } = layout;
  142. const [[x0, y0], [x1, y1]] = (0, d3_geo_1.geoPath)(projection.fitWidth(width, object)).bounds(object);
  143. const dy = Math.ceil(y1 - y0);
  144. const l = Math.min(Math.ceil(x1 - x0), dy);
  145. const s = (projection.scale() * (l - 1)) / l;
  146. const [tx, ty] = projection.translate();
  147. const t = ty + (height - dy) / 2;
  148. projection.scale(s).translate([tx, t]).precision(0.2);
  149. }
  150. /**
  151. * @todo Remove this.
  152. */
  153. function normalizeDataSource(node) {
  154. const { data } = node;
  155. if (Array.isArray(data))
  156. return Object.assign(Object.assign({}, node), { data: { value: data } });
  157. const { type } = data;
  158. if (type === 'graticule10') {
  159. return Object.assign(Object.assign({}, node), { data: { value: [(0, d3_geo_1.geoGraticule10)()] } });
  160. }
  161. else if (type === 'sphere') {
  162. // Sphere is not a standard type of GeoJSON.
  163. // Mark this geoPath as sphere geoPath.
  164. return Object.assign(Object.assign({}, node), { sphere: true, data: { value: [{ type: 'Sphere' }] } });
  165. }
  166. return node;
  167. }
  168. function isGeoPath(d) {
  169. return d.type === 'geoPath';
  170. }
  171. /**
  172. * A view with geo coordinate.
  173. */
  174. const GeoView = () => {
  175. return (options) => {
  176. const { children, coordinate: projection = {} } = options;
  177. if (!Array.isArray(children))
  178. return [];
  179. // Get projection factory.
  180. const { type = 'equalEarth' } = projection, projectionOptions = __rest(projection, ["type"]);
  181. const createProjection = normalizeProjection(type);
  182. const nodes = children.map(normalizeDataSource);
  183. // Set path generator lazily.
  184. let path;
  185. // A custom geo coordinate.
  186. function Geo() {
  187. return [
  188. [
  189. 'custom',
  190. (x, y, width, height) => {
  191. // Create and set projection.
  192. const visual = createProjection();
  193. const layout = { x, y, width, height };
  194. setProjectionSize(visual, nodes, layout, projectionOptions);
  195. setProjectionOptions(visual, projectionOptions);
  196. // Create path generator.
  197. path = (0, d3_geo_1.geoPath)(visual);
  198. // Normalize projection and projection.invert,
  199. // which normalize projected points.
  200. const scaleX = new scale_1.Linear({
  201. domain: [x, x + width],
  202. });
  203. const scaleY = new scale_1.Linear({
  204. domain: [y, y + height],
  205. });
  206. const normalize = (point) => {
  207. const visualPoint = visual(point);
  208. if (!visualPoint)
  209. return null;
  210. const [vx, vy] = visualPoint;
  211. return [scaleX.map(vx), scaleY.map(vy)];
  212. };
  213. const normalizeInvert = (point) => {
  214. if (!point)
  215. return null;
  216. const [px, py] = point;
  217. const visualPoint = [scaleX.invert(px), scaleY.invert(py)];
  218. return visual.invert(visualPoint);
  219. };
  220. return {
  221. transform: (point) => normalize(point),
  222. untransform: (point) => normalizeInvert(point),
  223. };
  224. },
  225. ],
  226. ];
  227. }
  228. function GeoPath(options) {
  229. const { style, tooltip = {} } = options;
  230. return Object.assign(Object.assign({}, options), { type: 'path', tooltip: (0, mark_1.maybeTooltip)(tooltip, {
  231. title: 'id',
  232. items: [{ channel: 'color' }],
  233. }), style: Object.assign(Object.assign({}, style), { d: (d) => path(d) || [] }) });
  234. }
  235. const t = (d) => (isGeoPath(d) ? GeoPath(d) : d);
  236. return [
  237. Object.assign(Object.assign({}, options), { type: 'view', scale: {
  238. x: { type: 'identity' },
  239. y: { type: 'identity' },
  240. }, axis: false, coordinate: { type: Geo }, children: nodes.flatMap(t) }),
  241. ];
  242. };
  243. };
  244. exports.GeoView = GeoView;
  245. exports.GeoView.props = {};
  246. //# sourceMappingURL=geoView.js.map