From a3fcaef699dd2c5b127cb8bea9f15c6c39b1b9c4 Mon Sep 17 00:00:00 2001 From: Tom Wanzek Date: Thu, 18 Aug 2016 17:48:06 -0400 Subject: [PATCH] d3-geo * added definitions and tests --- d3-geo/d3-geo-tests.ts | 625 +++++++++++++++++++++++++++++++++++++++++ d3-geo/index.d.ts | 358 +++++++++++++++++++++++ d3-geo/tsconfig.json | 19 ++ 3 files changed, 1002 insertions(+) create mode 100644 d3-geo/d3-geo-tests.ts create mode 100644 d3-geo/index.d.ts create mode 100644 d3-geo/tsconfig.json diff --git a/d3-geo/d3-geo-tests.ts b/d3-geo/d3-geo-tests.ts new file mode 100644 index 0000000000..2e9f3e8719 --- /dev/null +++ b/d3-geo/d3-geo-tests.ts @@ -0,0 +1,625 @@ +/** + * Typescript definition tests for d3/d3-geo module + * + * Note: These tests are intended to test the definitions only + * in the sense of typing and call signature consistency. They + * are not intended as functional tests. + */ + +import * as d3Geo from 'd3-geo'; +import { Selection } from 'd3-selection'; + +// ---------------------------------------------------------------------- +// Tests setup +// ---------------------------------------------------------------------- + +interface SampleProperties1 { + name: string; +} + +interface SampleProperties2 { + name: string; + value: number; +} + +const samplePolygon: GeoJSON.Polygon = { + type: 'Polygon', + coordinates: [ + [[0, 0], [0, 90], [90, 0], [0, 0]] + ] +}; + +const sampleSphere: d3Geo.GeoSphere = { + type: 'Sphere' +}; + +const sampleGeometryCollection: GeoJSON.GeometryCollection = { + type: 'GeometryCollection', + geometries: [ + samplePolygon, + samplePolygon + ] +}; + +const sampleExtendedGeometryCollection: d3Geo.ExtendedGeometryCollection = { + type: 'GeometryCollection', + geometries: [ + samplePolygon, + sampleSphere + ] +}; + +const sampleFeature: GeoJSON.Feature = { + type: 'Feature', + geometry: samplePolygon, + properties: { + name: 'Alabama' + } +}; + +const sampleExtendedFeature1: d3Geo.ExtendedFeature = { + type: 'Feature', + geometry: samplePolygon, + properties: { + name: 'Alabama' + } +}; + +const sampleExtendedFeature2: d3Geo.ExtendedFeature = { + type: 'Feature', + geometry: sampleSphere, + properties: { + name: 'earth', + value: 42 + } +}; + +const sampleFeatureCollection: GeoJSON.FeatureCollection = { + type: 'FeatureCollection', + features: [ + sampleFeature, + sampleFeature + ] +}; + +const sampleExtendedFeatureCollection: d3Geo.ExtendedFeatureCollection | d3Geo.ExtendedFeature> = { + type: 'FeatureCollection', + features: [ + sampleExtendedFeature1, + sampleExtendedFeature2 + ] +}; + +// ---------------------------------------------------------------------- +// Spherical Math +// ---------------------------------------------------------------------- + +// geoArea(...) ========================================================= + +let area: number = d3Geo.geoArea(samplePolygon); +area = d3Geo.geoArea(sampleSphere); +area = d3Geo.geoArea(sampleGeometryCollection); +area = d3Geo.geoArea(sampleExtendedGeometryCollection); +area = d3Geo.geoArea(sampleFeature); +area = d3Geo.geoArea(sampleExtendedFeature1); +area = d3Geo.geoArea(sampleExtendedFeature2); +area = d3Geo.geoArea(sampleFeatureCollection); +area = d3Geo.geoArea(sampleExtendedFeatureCollection); + +// geoBounds(...) ========================================================= + +let bounds: [[number, number], [number, number]] = d3Geo.geoBounds(samplePolygon); +bounds = d3Geo.geoBounds(sampleSphere); +bounds = d3Geo.geoBounds(sampleGeometryCollection); +bounds = d3Geo.geoBounds(sampleExtendedGeometryCollection); +bounds = d3Geo.geoBounds(sampleFeature); +bounds = d3Geo.geoBounds(sampleExtendedFeature1); +bounds = d3Geo.geoBounds(sampleExtendedFeature2); +bounds = d3Geo.geoBounds(sampleFeatureCollection); +bounds = d3Geo.geoBounds(sampleExtendedFeatureCollection); + +// geoCentroid(...) ======================================================= + +let centroid: [number, number] = d3Geo.geoCentroid(samplePolygon); +centroid = d3Geo.geoCentroid(sampleSphere); +centroid = d3Geo.geoCentroid(sampleGeometryCollection); +centroid = d3Geo.geoCentroid(sampleExtendedGeometryCollection); +centroid = d3Geo.geoCentroid(sampleFeature); +centroid = d3Geo.geoCentroid(sampleExtendedFeature1); +centroid = d3Geo.geoCentroid(sampleExtendedFeature2); +centroid = d3Geo.geoCentroid(sampleFeatureCollection); +centroid = d3Geo.geoCentroid(sampleExtendedFeatureCollection); + +// geoDistance(...) ======================================================= + +let distance: number = d3Geo.geoDistance([54, 2], [53, 1]); + +// geoLength(...) ========================================================= + +let length: number = d3Geo.geoLength(samplePolygon); +length = d3Geo.geoLength(sampleSphere); +length = d3Geo.geoLength(sampleGeometryCollection); +length = d3Geo.geoLength(sampleExtendedGeometryCollection); +length = d3Geo.geoLength(sampleFeature); +length = d3Geo.geoLength(sampleExtendedFeature1); +length = d3Geo.geoLength(sampleExtendedFeature2); +length = d3Geo.geoLength(sampleFeatureCollection); +length = d3Geo.geoLength(sampleExtendedFeatureCollection); + +// geoInterpolate(...) ==================================================== + +let interpolateFct: (t: number) => [number, number] = d3Geo.geoInterpolate([54, 2], [53, 1]); + +// geoRotation(...) ======================================================= + +// create rotation ----------------------------------------------------- + +let rotation: d3Geo.GeoRotation = d3Geo.geoRotation([90, 45]); +let rotation2: d3Geo.GeoRotation = d3Geo.geoRotation([90, 45, 27.5]); + +// use rotation -------------------------------------------------------- + +let point: [number, number] = rotation([54, 2]); +let inverted: [number, number] = rotation.invert([54, 2]); + +// ---------------------------------------------------------------------- +// Spherical Shapes - geoCircle +// ---------------------------------------------------------------------- + +// Create GeoCircleGenerator ============================================ + +// simple use case +let circleGeneratorSimple: d3Geo.GeoCircleGenerator = d3Geo.geoCircle(); + +// complex use as part of object +class Circulator { + + constructor(radius: number, precision: number) { + this.r = radius; + this.p = precision; + this.circleGenerator = d3Geo.geoCircle() + .radius(function (datum) { + let t: Circulator = this; + let d: [number, number] | undefined = datum; + return this.r; + }) + .precision(function (datum) { + let t: Circulator = this; + let d: [number, number] | undefined = datum; + return this.p; + }) + .center(function (datum) { + let t: Circulator = this; + let d: [number, number] | undefined = datum; + return d ? d : [0, 0]; + }); + } + private r: number; + private p: number; + private circleGenerator: d3Geo.GeoCircleGenerator; + + public getCirclePolygon(center?: [number, number]): GeoJSON.Polygon { + if (center && center.length === 2 && typeof center[0] === 'number' && typeof center[1] === 'number') { + return this.circleGenerator(center); + } else { + return this.circleGenerator(); + } + } +} + +let circulator = new Circulator(50, 2); + +// Configure CircleGenerator ============================================ + +// center(...) ---------------------------------------------------------- + +let centerFctSimple: ((this: any, d: any, ...args: any[]) => [number, number]) = circleGeneratorSimple.center(); + +let c: [number, number] = [54, 2]; + +circleGeneratorSimple = circleGeneratorSimple.center(() => c); +circleGeneratorSimple = circleGeneratorSimple.center(c); + +// radius(...) ----------------------------------------------------------- + +let radius: ((...args: any[]) => number) = circleGeneratorSimple.radius(); +circleGeneratorSimple = circleGeneratorSimple.radius(() => 5); +circleGeneratorSimple = circleGeneratorSimple.radius(2); + +// precision(...) -------------------------------------------------------- + +let precision: ((...args: any[]) => number) = circleGeneratorSimple.precision(); +circleGeneratorSimple = circleGeneratorSimple.precision(() => 5); +circleGeneratorSimple = circleGeneratorSimple.precision(2); + +// Use CircleGenerator ==================================================== + +// use simple geoCircleGenerator +let circlePolygon: GeoJSON.Polygon = circleGeneratorSimple(); + +// use encapsulated geoCircleGenerator +circlePolygon = circulator.getCirclePolygon([5, 5]); +circlePolygon = circulator.getCirclePolygon(); + + +// ---------------------------------------------------------------------- +// Spherical Shapes - geoGraticule +// ---------------------------------------------------------------------- + +// Create GeoGraticuleGenerator ========================================= + +let graticuleGenerator: d3Geo.GeoGraticuleGenerator = d3Geo.geoGraticule(); + +// Configure GeoGraticuleGenerator ======================================= + +// extent(...) ----------------------------------------------------------- + +let extent: [[number, number], [number, number]] = graticuleGenerator.extent(); +graticuleGenerator = graticuleGenerator.extent([[-180, -80], [180, 80]]); + +// extentMajor(...) --------------------------------------------------------- + +let extentMajor: [[number, number], [number, number]] = graticuleGenerator.extentMajor(); +graticuleGenerator = graticuleGenerator.extentMajor([[-180, -80], [180, 80]]); + +// extentMinor(...) --------------------------------------------------------- + +let extentMinor: [[number, number], [number, number]] = graticuleGenerator.extentMinor(); +graticuleGenerator = graticuleGenerator.extentMinor([[-180, -80], [180, 80]]); + +// step(...) ---------------------------------------------------------------- + +let step: [number, number] = graticuleGenerator.step(); +graticuleGenerator = graticuleGenerator.step([10, 10]); + +// stepMajor(...) ----------------------------------------------------------- + +let stepMajor: [number, number] = graticuleGenerator.stepMajor(); +graticuleGenerator = graticuleGenerator.stepMajor([10, 10]); + +// stepMinor(...) ------------------------------------------------------------ + +let stepMinor: [number, number] = graticuleGenerator.stepMinor(); +graticuleGenerator = graticuleGenerator.stepMinor([10, 10]); + +// precision(...) ------------------------------------------------------------- + +let precision1: number = graticuleGenerator.precision(); +graticuleGenerator = graticuleGenerator.precision(5); + +// Use GeoGraticuleGenerator ============================================ + +let multiString: GeoJSON.MultiLineString = graticuleGenerator(); +let lines: GeoJSON.LineString[] = graticuleGenerator.lines(); +let polygon2: GeoJSON.Polygon = graticuleGenerator.outline(); + +// ---------------------------------------------------------------------- +// Raw Projections +// ---------------------------------------------------------------------- + +// Pre-Defined Raw Projection Factories ================================= + +let azimuthalEqualAreaRaw: d3Geo.GeoRawProjection = d3Geo.geoAzimuthalEqualAreaRaw(); +let azimuthalEquidistantRaw: d3Geo.GeoRawProjection = d3Geo.geoAzimuthalEquidistantRaw(); +let conicConformalRaw: d3Geo.GeoRawProjection = d3Geo.geoConicConformalRaw(0, 0); +let conicEqualAreaRaw: d3Geo.GeoRawProjection = d3Geo.geoConicEqualAreaRaw(0, 0); +let conicEquidistantRaw: d3Geo.GeoRawProjection = d3Geo.geoConicEquidistantRaw(0, 0); +let equirectangularRaw: d3Geo.GeoRawProjection = d3Geo.geoEquirectangularRaw(); +let gnomonicRaw: d3Geo.GeoRawProjection = d3Geo.geoGnomonicRaw(); +let mercatorRaw: d3Geo.GeoRawProjection = d3Geo.geoMercatorRaw(); +let orthographicRaw: d3Geo.GeoRawProjection = d3Geo.geoOrthographicRaw(); +let stereographicRaw: d3Geo.GeoRawProjection = d3Geo.geoStereographicRaw(); +let transverseMercatorRaw: d3Geo.GeoRawProjection = d3Geo.geoTransverseMercatorRaw(); + +// Use Raw Projection ===================================================== + +let rawProjectionPoint: [number, number] = azimuthalEqualAreaRaw(54, 2); +let rawProjectionInvertedPoint: [number, number] = azimuthalEqualAreaRaw.invert(180, 6); + + + +// ---------------------------------------------------------------------- +// Pre-Defined Projections +// ---------------------------------------------------------------------- + +// Create predefined Projection from factory ============================= + +let albers: d3Geo.GeoConicProjection = d3Geo.geoAlbers(); +let albersUsa: d3Geo.GeoProjection = d3Geo.geoAlbersUsa(); +let azimuthalEqualArea: d3Geo.GeoProjection = d3Geo.geoAzimuthalEqualArea(); +let azimuthalEquidistant: d3Geo.GeoProjection = d3Geo.geoAzimuthalEquidistant(); +let conicConformal: d3Geo.GeoConicProjection = d3Geo.geoConicConformal(); +let conicEqualArea: d3Geo.GeoConicProjection = d3Geo.geoConicEqualArea(); +let conicEquidistant: d3Geo.GeoConicProjection = d3Geo.geoConicEquidistant(); +let cquirectangular: d3Geo.GeoProjection = d3Geo.geoEquirectangular(); +let gnomonic: d3Geo.GeoProjection = d3Geo.geoGnomonic(); +let mercator: d3Geo.GeoProjection = d3Geo.geoMercator(); +let orthographic: d3Geo.GeoProjection = d3Geo.geoOrthographic(); +let stereographic: d3Geo.GeoProjection = d3Geo.geoStereographic(); +let transverseMercator: d3Geo.GeoProjection = d3Geo.geoTransverseMercator(); + +// ---------------------------------------------------------------------- +// Create New Projections +// ---------------------------------------------------------------------- + + +let geoProjection: d3Geo.GeoProjection = d3Geo.geoProjection(azimuthalEqualAreaRaw); + +let mutate: () => d3Geo.GeoProjection = d3Geo.geoProjectionMutator(() => azimuthalEqualAreaRaw); +let constructedProjection: d3Geo.GeoProjection = mutate(); + +// Use Projection ========================================================== + +let projected: [number, number] = constructedProjection([54, 2]); +let inverted2: [number, number] = constructedProjection.invert([54, 2]); + +// TODO ????? +// let stream: d3Geo.Stream = constructedProjection.stream([54, 2]); + +let clipAngle: number = constructedProjection.clipAngle(); +constructedProjection = constructedProjection.clipAngle(null); +constructedProjection = constructedProjection.clipAngle(45); + +let clipExtent: [[number, number], [number, number]] = constructedProjection.clipExtent(); +constructedProjection = constructedProjection.clipExtent(null); +constructedProjection = constructedProjection.clipExtent([[0, 0], [1, 1]]); + +let scale: number = constructedProjection.scale(); +constructedProjection = constructedProjection.scale(45); + +let translate: [number, number] = constructedProjection.translate(); +constructedProjection = constructedProjection.translate([480, 250]); + +let center: [number, number] = constructedProjection.center(); +constructedProjection = constructedProjection.center([0, 0]); + +let rotate: [number, number, number] = constructedProjection.rotate(); +constructedProjection = constructedProjection.rotate([0, 0]); +constructedProjection = constructedProjection.rotate([0, 0, 0]); + +let precision2: number = constructedProjection.precision(); +constructedProjection = constructedProjection.precision(0.707); + +constructedProjection = constructedProjection.fitExtent([[0, 0], [960, 500]], samplePolygon); +constructedProjection = constructedProjection.fitExtent([[0, 0], [960, 500]], sampleSphere); +constructedProjection = constructedProjection.fitExtent([[0, 0], [960, 500]], sampleGeometryCollection); +constructedProjection = constructedProjection.fitExtent([[0, 0], [960, 500]], sampleExtendedGeometryCollection); +constructedProjection = constructedProjection.fitExtent([[0, 0], [960, 500]], sampleFeature); +constructedProjection = constructedProjection.fitExtent([[0, 0], [960, 500]], sampleExtendedFeature1); +constructedProjection = constructedProjection.fitExtent([[0, 0], [960, 500]], sampleExtendedFeature2); +constructedProjection = constructedProjection.fitExtent([[0, 0], [960, 500]], sampleFeatureCollection); +constructedProjection = constructedProjection.fitExtent([[0, 0], [960, 500]], sampleExtendedFeatureCollection); + +constructedProjection = constructedProjection.fitSize([960, 500], samplePolygon); +constructedProjection = constructedProjection.fitSize([960, 500], sampleSphere); +constructedProjection = constructedProjection.fitSize([960, 500], sampleGeometryCollection); +constructedProjection = constructedProjection.fitSize([960, 500], sampleExtendedGeometryCollection); +constructedProjection = constructedProjection.fitSize([960, 500], sampleFeature); +constructedProjection = constructedProjection.fitSize([960, 500], sampleExtendedFeature1); +constructedProjection = constructedProjection.fitSize([960, 500], sampleExtendedFeature2); +constructedProjection = constructedProjection.fitSize([960, 500], sampleFeatureCollection); +constructedProjection = constructedProjection.fitSize([960, 500], sampleExtendedFeatureCollection); + +// ---------------------------------------------------------------------- +// GeoConicProjection interface +// ---------------------------------------------------------------------- + +// parallels(...) ------------------------------------------------------ +let parallels: [number, number] = conicConformal.parallels(); +conicConformal = conicConformal.parallels([20, 20]); + +// test method inheritance from GeoProjection --------------------------- + +conicConformal = conicConformal.fitSize([960, 500], samplePolygon); // inherited + +// ---------------------------------------------------------------------- +// GeoPath Generator +// ---------------------------------------------------------------------- + +// Create geoPath Generator ============================================= + +let geoPathCanvas: d3Geo.GeoPath; +geoPathCanvas = d3Geo.geoPath(); + +let geoPathSVG: d3Geo.GeoPath>; +geoPathSVG = d3Geo.geoPath>(); + +// Configure geoPath Generator ========================================== + +// projection(...) ------------------------------------------------------ + +geoPathCanvas = geoPathCanvas.projection(azimuthalEqualArea); +let geoPathProjectionMinimal: d3Geo.GeoStreamWrapper = geoPathCanvas.projection(); +let geoPathProjectionUnion: d3Geo.GeoProjection | d3Geo.GeoConicProjection | d3Geo.GeoStreamWrapper = geoPathCanvas.projection(); +let geoPathProjection: d3Geo.GeoProjection = geoPathCanvas.projection(); + +geoPathSVG = geoPathSVG.projection(conicConformal); +let geoPathConicProjection: d3Geo.GeoConicProjection = geoPathSVG.projection(); +// geoPathConicProjection = geoPathSVG.projection(); // fails without casting to GeoConicProjection, or alternatively custom typeguard +// geoPathConicProjection = geoPathSVG.projection(); // fails as SampleProperties does not extend minimal interface + +// context(...) ------------------------------------------------------ + +// minimal context interface +geoPathCanvas = geoPathCanvas.context({ + beginPath: () => { return; }, + moveTo: (x: number, y: number) => { return; }, + lineTo: (x: number, y: number) => { return; }, + arc: (x, y, radius, startAngle, endAngle) => { return; }, + closePath: () => { return; } +}); + + +let geoPathContext: d3Geo.GeoContext = geoPathCanvas.context(); + +// reset +geoPathCanvas = geoPathCanvas.context(null); + +// With canvas 2D rendering context +let canvasContext: CanvasRenderingContext2D; + +geoPathCanvas = geoPathCanvas.context(canvasContext); + +canvasContext = geoPathCanvas.context(); +// canvasContext = geoPathSimple.context(); // fails without casting to CanvasRenderingContext2D +// canvasContext = geoPathSimple.context(); // fails as SampleProperties does not extend GeoCanvas + +// pointRadius(...) ------------------------------------------------------ + +geoPathCanvas = geoPathCanvas.pointRadius(5); +let geoPathCanvasPointRadiusAccessor: (this: any, d: d3Geo.GeoPermissibleObjects, ...args: any[]) => number = geoPathCanvas.pointRadius(); + +geoPathSVG = geoPathSVG.pointRadius(function (datum) { + let that: SVGPathElement = this; + let d: d3Geo.ExtendedFeature = datum; + return datum.properties.name === 'Alabama' ? 10 : 15; +}); + +let geoPathSVGPointRadiusAccessor: (this: SVGPathElement, d: d3Geo.ExtendedFeature, ...args: any[]) => number = geoPathSVG.pointRadius(); +// let geoPathSVGPointRadiusAccessorWrong1: (this: SVGCircleElement, d: d3Geo.ExtendedFeature, ...args: any[]) => number = geoPathSVG.pointRadius(); // fails, mismatch in this context +// let geoPathSVGPointRadiusAccessorWrong2: (this: SVGPathElement, d: d3Geo.GeoGeometryObjects, ...args: any[]) => number = geoPathSVG.pointRadius(); // fails, mismatch in object datum type + +// Use geoPath Generator ================================================ + +// area(...) ------------------------------------------------------ + +let geoPathArea: number = geoPathCanvas.area(samplePolygon); +geoPathArea = geoPathCanvas.area(sampleSphere); +geoPathArea = geoPathCanvas.area(sampleGeometryCollection); +geoPathArea = geoPathCanvas.area(sampleExtendedGeometryCollection); +geoPathArea = geoPathCanvas.area(sampleFeature); +geoPathArea = geoPathCanvas.area(sampleExtendedFeature1); +geoPathArea = geoPathCanvas.area(sampleExtendedFeature2); +geoPathArea = geoPathCanvas.area(sampleFeatureCollection); +geoPathArea = geoPathCanvas.area(sampleExtendedFeatureCollection); + +// geoPathArea = geoPathSVG.area(sampleExtendedFeatureCollection); // fails, wrong data object type + + +// bounds(...) ------------------------------------------------------ + +let geoPathBounds: [[number, number], [number, number]] = geoPathCanvas.bounds(samplePolygon); +geoPathBounds = geoPathCanvas.bounds(sampleSphere); +geoPathBounds = geoPathCanvas.bounds(sampleGeometryCollection); +geoPathBounds = geoPathCanvas.bounds(sampleExtendedGeometryCollection); +geoPathBounds = geoPathCanvas.bounds(sampleFeature); +geoPathBounds = geoPathCanvas.bounds(sampleExtendedFeature1); +geoPathBounds = geoPathCanvas.bounds(sampleExtendedFeature2); +geoPathBounds = geoPathCanvas.bounds(sampleFeatureCollection); +geoPathBounds = geoPathCanvas.bounds(sampleExtendedFeatureCollection); + +// geoPathBounds = geoPathSVG.bounds(sampleExtendedFeatureCollection); // fails, wrong data object type + +// centroid(...) ------------------------------------------------------ + +let geoPathCentroid: [number, number] = geoPathCanvas.centroid(samplePolygon); +geoPathCentroid = geoPathCanvas.centroid(sampleSphere); +geoPathCentroid = geoPathCanvas.centroid(sampleGeometryCollection); +geoPathCentroid = geoPathCanvas.centroid(sampleExtendedGeometryCollection); +geoPathCentroid = geoPathCanvas.centroid(sampleFeature); +geoPathCentroid = geoPathCanvas.centroid(sampleExtendedFeature1); +geoPathCentroid = geoPathCanvas.centroid(sampleExtendedFeature2); +geoPathCentroid = geoPathCanvas.centroid(sampleFeatureCollection); +geoPathCentroid = geoPathCanvas.centroid(sampleExtendedFeatureCollection); + +// geoPathCentroid = geoPathSVG.centroid(sampleExtendedFeatureCollection); // fails, wrong data object type + +// render path to context of get path string---------------------------- + +// render to GeoContext/Canvas + +geoPathCanvas(samplePolygon); +geoPathCanvas(sampleSphere); +geoPathCanvas(sampleGeometryCollection); +geoPathCanvas(sampleExtendedGeometryCollection); +geoPathCanvas(sampleFeature); +geoPathCanvas(sampleExtendedFeature1); +geoPathCanvas(sampleExtendedFeature2); +geoPathCanvas(sampleFeatureCollection); +geoPathCanvas(sampleExtendedFeatureCollection); + +// Use path string generator for SVGPathElement + +let svgPath: Selection, any, any>; +svgPath.attr('d', geoPathSVG); + +let svgCircleWrong: Selection, any, any>; +// svgCircleWrong.attr('d', geoPathSVG); // fails, mismatch in `this` context + +let svgPathWrong: Selection; +// svgPathWrong.attr('d', geoPathSVG); // fails, mismatch in datum type + +// ---------------------------------------------------------------------- +// geoClipExtent +// ---------------------------------------------------------------------- + +let geoClipExtent: d3Geo.GeoExtent = d3Geo.geoClipExtent(); + +// extent(...) ---------------------------------------------------------- + +let extent2: [[number, number], [number, number]] = geoClipExtent.extent(); +geoClipExtent = geoClipExtent.extent([[0, 0], [960, 500]]); + +// stream(...) ---------------------------------------------------------- + +let stream: d3Geo.GeoStream; +stream = geoClipExtent.stream(stream); + +// ---------------------------------------------------------------------- +// Stream interface +// ---------------------------------------------------------------------- + +stream.point(0, 0); +stream.point(0, 0, 0); +stream.lineStart(); +stream.lineEnd(); +stream.polygonStart(); +stream.polygonEnd(); +stream.sphere(); + +// ---------------------------------------------------------------------- +// Context interface +// ---------------------------------------------------------------------- +let context: d3Geo.GeoContext = { + beginPath: () => { return; }, + moveTo: (x: number, y: number) => { return; }, + lineTo: (x: number, y: number) => { return; }, + arc: (x, y, radius, startAngle, endAngle) => { return; }, + closePath: () => { return; } +}; + +// ---------------------------------------------------------------------- +// Projection Streams +// ---------------------------------------------------------------------- + +// geoTransform(...) ==================================================== + +let transformFunction: { stream: (s: d3Geo.GeoStream) => {} } = d3Geo.geoTransform({}); + +interface CustomTranformProto extends d3Geo.GeoTransformPrototype { + a: number; +} + +let customTransformProto: CustomTranformProto; + +customTransformProto = { + point: function (x, y) { + return this.stream.point(x + this.a, -y); + }, + a: 10 +}; + +let t: { stream: (s: d3Geo.GeoStream) => (CustomTranformProto & d3Geo.GeoStream) } = d3Geo.geoTransform(customTransformProto); + +// geoStream(...) ======================================================== + +d3Geo.geoStream(samplePolygon, stream); +d3Geo.geoStream(sampleSphere, stream); +d3Geo.geoStream(sampleGeometryCollection, stream); +d3Geo.geoStream(sampleExtendedGeometryCollection, stream); +d3Geo.geoStream(sampleFeature, stream); +d3Geo.geoStream(sampleExtendedFeature1, stream); +d3Geo.geoStream(sampleExtendedFeature2, stream); +d3Geo.geoStream(sampleFeatureCollection, stream); +d3Geo.geoStream(sampleExtendedFeatureCollection, stream); + diff --git a/d3-geo/index.d.ts b/d3-geo/index.d.ts new file mode 100644 index 0000000000..beac52518d --- /dev/null +++ b/d3-geo/index.d.ts @@ -0,0 +1,358 @@ +// Type definitions for D3JS d3-geo module 1.2.0 +// Project: https://github.com/d3/d3-geo/ +// Definitions by: Hugues Stefanski , Tom Wanzek , Alex Ford , Boris Yankov +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +/// + +// ---------------------------------------------------------------------- +// Shared Interfaces and Types +// ---------------------------------------------------------------------- + +/** + * A basic geometry for a sphere, which is supported by d3-geo + * beyond the GeoJSON geometries. + */ +export interface GeoSphere { + type: 'Sphere'; +} + +/** + * Type Alias for GeoJSON Geometry Object and GeoSphere additional + * geometry supported by d3-geo + */ +export type GeoGeometryObjects = GeoJSON.GeometryObject | GeoSphere; + +/** + * A GeoJSON-style GeometryCollection which supports GeoJSON geometry objects + * and additionally GeoSphere + */ +export interface ExtendedGeometryCollection { + type: string; + bbox?: number[]; + crs?: GeoJSON.CoordinateReferenceSystem; + geometries: GeometryType[]; +} + +/** + * A GeoJSON-style Feature which support features built on GeoJSON GeometryObjects + * or GeoSphere + */ +export interface ExtendedFeature extends GeoJSON.GeoJsonObject { + geometry: GeometryType; + properties: Properties; + id?: string; +} + +/** + * A GeoJSON-style FeatureCollection which supports GeoJSON features + * and features built on GeoSphere + */ +export interface ExtendedFeatureCollection> extends GeoJSON.GeoJsonObject { + features: FeatureType[]; +} + +/** + * Type Alias for permissible objects which can be used with d3-geo + * methods + */ +export type GeoPermissibleObjects = GeoGeometryObjects | ExtendedGeometryCollection | ExtendedFeature | ExtendedFeatureCollection>; + +// ---------------------------------------------------------------------- +// Spherical Math +// ---------------------------------------------------------------------- + +/**Returns the spherical area of the specified GeoJSON feature in steradians. */ +export function geoArea(feature: ExtendedFeature): number; +export function geoArea(feature: ExtendedFeatureCollection>): number; +export function geoArea(feature: GeoGeometryObjects): number; +export function geoArea(feature: ExtendedGeometryCollection): number; + +/**Returns the spherical bounding box for the specified GeoJSON feature. The bounding box is represented by a two-dimensional array: [[left, bottom], [right, top]], where left is the minimum longitude, bottom is the minimum latitude, right is maximum longitude, and top is the maximum latitude. All coordinates are given in degrees. */ +export function geoBounds(feature: ExtendedFeature): [[number, number], [number, number]]; +export function geoBounds(feature: ExtendedFeatureCollection>): [[number, number], [number, number]]; +export function geoBounds(feature: GeoGeometryObjects): [[number, number], [number, number]]; +export function geoBounds(feature: ExtendedGeometryCollection): [[number, number], [number, number]]; + +/**Returns the spherical centroid of the specified GeoJSON feature. See also path.centroid, which computes the projected planar centroid.*/ +export function geoCentroid(feature: ExtendedFeature): [number, number]; +export function geoCentroid(feature: ExtendedFeatureCollection>): [number, number]; +export function geoCentroid(feature: GeoGeometryObjects): [number, number]; +export function geoCentroid(feature: ExtendedGeometryCollection): [number, number]; + +/**Returns the great-arc distance in radians between the two points a and b. Each point must be specified as a two-element array [longitude, latitude] in degrees. */ +export function geoDistance(a: [number, number], b: [number, number]): number; + +/**Returns the great-arc length of the specified GeoJSON feature in radians.*/ +export function geoLength(feature: ExtendedFeature): number; +export function geoLength(feature: ExtendedFeatureCollection>): number; +export function geoLength(feature: GeoGeometryObjects): number; +export function geoLength(feature: ExtendedGeometryCollection): number; + +/**Returns an interpolator function given two points a and b. Each point must be specified as a two-element array [longitude, latitude] in degrees. */ +export function geoInterpolate(a: [number, number], b: [number, number]): (t: number) => [number, number]; + + +export interface GeoRotation { + (point: [number, number]): [number, number]; + invert(point: [number, number]): [number, number]; +} + +/**Returns a rotation function for the given angles, which must be a two- or three-element array of numbers [lambda, phi, gamma] specifying the rotation angles in degrees about each spherical axis. */ +export function geoRotation(angles: [number, number] | [number, number, number]): GeoRotation; + + +// ---------------------------------------------------------------------- +// Spherical Shapes +// ---------------------------------------------------------------------- + +// geoCircle ============================================================ + +export interface GeoCircleGenerator { + /**Returns a new GeoJSON geometry object of type “Polygon” approximating a circle on the surface of a sphere, with the current center, radius and precision. */ + (this: This, d?: Datum, ...args: any[]): GeoJSON.Polygon; + center(): ((this: This, d: Datum, ...args: any[]) => [number, number]); + center(center: [number, number]): this; + center(center: ((this: This, d: Datum, ...args: any[]) => [number, number])): this; + + radius(): ((this: This, d: Datum, ...args: any[]) => number); + radius(radius: number): this; + radius(radius: ((this: This, d: Datum, ...args: any[]) => number)): this; + + precision(): ((this: This, d: Datum, ...args: any[]) => number); + precision(precision: number): this; + precision(precision: (this: This, d: Datum, ...args: any[]) => number): this; +} + +export function geoCircle(): GeoCircleGenerator; +export function geoCircle(): GeoCircleGenerator; +export function geoCircle(): GeoCircleGenerator; + +// geoGraticule ============================================================ + +export interface GeoGraticuleGenerator { + /**Returns a GeoJSON MultiLineString geometry object representing all meridians and parallels for this graticule. */ + (): GeoJSON.MultiLineString; + + lines(): GeoJSON.LineString[]; + outline(): GeoJSON.Polygon; + extent(): [[number, number], [number, number]]; + extent(extent: [[number, number], [number, number]]): this; + extentMajor(): [[number, number], [number, number]]; + extentMajor(extent: [[number, number], [number, number]]): this; + extentMinor(): [[number, number], [number, number]]; + extentMinor(extent: [[number, number], [number, number]]): this; + step(): [number, number]; + step(step: [number, number]): this; + stepMajor(): [number, number]; + stepMajor(step: [number, number]): this; + stepMinor(): [number, number]; + stepMinor(step: [number, number]): this; + precision(): number; + precision(angle: number): this; +} + +export function geoGraticule(): GeoGraticuleGenerator; + +// ---------------------------------------------------------------------- +// Projections +// ---------------------------------------------------------------------- + +export interface GeoStream { + lineEnd(): void; + lineStart(): void; + point(x: number, y: number, z?: number): void; + polygonEnd(): void; + polygonStart(): void; + sphere?(): void; +} + +export interface GeoStreamWrapper { + stream(stream: GeoStream): GeoStream; +} + + +export interface GeoRawProjection { + (longitude: number, latitude: number): [number, number]; + invert?(x: number, y: number): [number, number]; +} + + +export interface GeoProjection extends GeoStreamWrapper { + /**Returns a new array x, y representing the projected point of the given point. The point must be specified as a two-element array [longitude, latitude] in degrees. */ + (point: [number, number]): [number, number] | null; + + center(): [number, number]; + center(point: [number, number]): this; + + clipAngle(): number | null; + clipAngle(angle: null): this; + clipAngle(angle: number): this; + + clipExtent(): [[number, number], [number, number]] | null; + clipExtent(extent: null): this; + clipExtent(extent: [[number, number], [number, number]]): this; + + /**Sets the projection’s scale and translate to fit the specified GeoJSON object in the center of the given extent. */ + fitExtent(extent: [[number, number], [number, number]], object: ExtendedFeature): this; + fitExtent(extent: [[number, number], [number, number]], object: ExtendedFeatureCollection>): this; + fitExtent(extent: [[number, number], [number, number]], object: GeoGeometryObjects): this; + fitExtent(extent: [[number, number], [number, number]], object: ExtendedGeometryCollection): this; + + + /**A convenience method for projection.fitExtent where the top-left corner of the extent is [0,0]. */ + fitSize(size: [number, number], object: ExtendedFeature): this; + fitSize(size: [number, number], object: ExtendedFeatureCollection>): this; + fitSize(size: [number, number], object: GeoGeometryObjects): this; + fitSize(size: [number, number], object: ExtendedGeometryCollection): this; + + /**Returns a new array [longitude, latitude] in degrees representing the unprojected point of the given projected point. */ + invert?(point: [number, number]): [number, number] | null; + + precision(): number; + precision(precision: number): this; + + rotate(): [number, number, number]; + rotate(angles: [number, number] | [number, number, number]): this; + + scale(): number; + scale(scale: number): this; + + translate(): [number, number]; + translate(point: [number, number]): this; +} + +export interface GeoConicProjection extends GeoProjection { + parallels(value: [number, number]): this; + parallels(): [number, number]; +} + + +// geoPath ============================================================== + +export interface GeoContext { + arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, anticlockwise?: boolean): void; + beginPath(): void; + closePath(): void; + lineTo(x: number, y: number): void; + moveTo(x: number, y: number): void; +} + +export interface GeoPath { + + (this: This, object: DatumObject, ...args: any[]): string; + + area(object: DatumObject): number; + bounds(object: DatumObject): [[number, number], [number, number]]; + centroid(object: DatumObject): [number, number]; + context(): C | null; + context(context: GeoContext | null): this; + + /** + * Get the current projection. The generic parameter can be used to cast the result to the + * correct, known type of the projection, e.g. GeoProjection or GeoConicProjection. Otherwise, + * the return type defaults to the minimum type requirement for a projection which + * can be passed into a GeoPath. + */ + projection

(): P | null; + + /** + * Set the projection to the identity projection + */ + projection(projection: null): this; + + /** + * Set the projection to be used with the geo path generator. + */ + projection(projection: GeoProjection): this; + + /** + * Set the projection to be used with the geo path generator to a custom projection. + * Custom projections must minimally contain a stream method. + */ + projection(projection: GeoStreamWrapper): this; + + pointRadius(): (this: This, object: DatumObject, ...args: any[]) => number; + pointRadius(value: number): this; + pointRadius(value: (this: This, object: DatumObject, ...args: any[]) => number): this; + +} + +export function geoPath(): GeoPath; +export function geoPath(): GeoPath; +export function geoPath(): GeoPath; + +// Raw Projections ======================================================== + +export function geoAzimuthalEqualAreaRaw(): GeoRawProjection; +export function geoAzimuthalEquidistantRaw(): GeoRawProjection; +export function geoConicConformalRaw(phi0: number, phi1: number): GeoRawProjection; +export function geoConicEqualAreaRaw(phi0: number, phi1: number): GeoRawProjection; +export function geoConicEquidistantRaw(phi0: number, phi1: number): GeoRawProjection; +export function geoEquirectangularRaw(): GeoRawProjection; +export function geoGnomonicRaw(): GeoRawProjection; +export function geoMercatorRaw(): GeoRawProjection; +export function geoOrthographicRaw(): GeoRawProjection; +export function geoStereographicRaw(): GeoRawProjection; +export function geoTransverseMercatorRaw(): GeoRawProjection; + +// geoProjection ========================================================== + +export function geoProjection(project: GeoRawProjection): GeoProjection; + +// geoProjectionMutator ==================================================== + +export function geoProjectionMutator(factory: (...args: any[]) => GeoRawProjection): () => GeoProjection; + +// Pre-Defined Projections ================================================= + +export function geoAlbers(): GeoConicProjection; +export function geoAlbersUsa(): GeoProjection; +export function geoAzimuthalEqualArea(): GeoProjection; +export function geoAzimuthalEquidistant(): GeoProjection; +export function geoConicConformal(): GeoConicProjection; +export function geoConicEqualArea(): GeoConicProjection; +export function geoConicEquidistant(): GeoConicProjection; +export function geoEquirectangular(): GeoProjection; +export function geoGnomonic(): GeoProjection; +export function geoMercator(): GeoProjection; +export function geoOrthographic(): GeoProjection; +export function geoStereographic(): GeoProjection; +export function geoTransverseMercator(): GeoProjection; + +// geoClipExtent ============================================================= + +export interface GeoExtent { + extent(): [[number, number], [number, number]]; + extent(extent: [[number, number], [number, number]]): this; + stream(stream: GeoStream): GeoStream; +} + + +export function geoClipExtent(): GeoExtent; + +// ---------------------------------------------------------------------- +// Projection Streams +// ---------------------------------------------------------------------- + +// geoTransform(...) ==================================================== + +export interface GeoTransformPrototype { + lineEnd?(this: this & { stream: GeoStream }): void; + lineStart?(this: this & { stream: GeoStream }): void; + point?(this: this & { stream: GeoStream }, x: number, y: number, z?: number): void; + polygonEnd?(this: this & { stream: GeoStream }): void; + polygonStart?(this: this & { stream: GeoStream }): void; + sphere?(this: this & { stream: GeoStream }): void; +} +// TODO: Review whether GeoStreamWrapper should be included into return value union type, i.e. ({ stream: (s: GeoStream) => (T & GeoStream & GeoStreamWrapper)})? +// It probably should be omitted for purposes of this API. The stream method added to (T & GeoStream) is more of a private member used internally to +// implement the Transform factory +export function geoTransform(prototype: T): { stream: (s: GeoStream) => (T & GeoStream) }; + +// geoStream(...) ======================================================= + +export function geoStream(object: ExtendedFeature, stream: GeoStream): void; +export function geoStream(object: ExtendedFeatureCollection>, stream: GeoStream): void; +export function geoStream(object: GeoGeometryObjects, stream: GeoStream): void; +export function geoStream(object: ExtendedGeometryCollection, stream: GeoStream): void; diff --git a/d3-geo/tsconfig.json b/d3-geo/tsconfig.json new file mode 100644 index 0000000000..2ec957f5d4 --- /dev/null +++ b/d3-geo/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "noImplicitAny": true, + "strictNullChecks": false, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "d3-geo-tests.ts" + ] +}