diff --git a/examples/d3.html b/examples/d3.html index eeff216b37..6dcbfecc66 100644 --- a/examples/d3.html +++ b/examples/d3.html @@ -3,7 +3,7 @@ layout: example.html title: d3 Integration shortdesc: Example of using OpenLayers and d3 together. docs: > -
The example loads TopoJSON geometries and uses d3 (d3.geo.path) to render these geometries to a canvas element that is then used as the image of an OpenLayers image layer.
d3.geo.path) to render these geometries to a SVG element.
tags: "d3"
resources:
- https://unpkg.com/d3@4.12.0/build/d3.js
diff --git a/examples/d3.js b/examples/d3.js
index 70a431d2b8..8294539a76 100644
--- a/examples/d3.js
+++ b/examples/d3.js
@@ -1,10 +1,70 @@
-import Map from '../src/ol/Map.js';
+import Map from '../src/ol/CompositeMap.js';
import View from '../src/ol/View.js';
import {getWidth, getCenter} from '../src/ol/extent.js';
-import {Image as ImageLayer, Tile as TileLayer} from '../src/ol/layer.js';
+import {Layer, Tile as TileLayer} from '../src/ol/layer.js';
+import SourceState from '../src/ol/source/State';
import {fromLonLat, toLonLat} from '../src/ol/proj.js';
-import {ImageCanvas as ImageCanvasSource, Stamen} from '../src/ol/source.js';
+import Stamen from '../src/ol/source/Stamen.js';
+class CanvasLayer extends Layer {
+
+ constructor(options) {
+ super(options);
+
+ this.features = options.features;
+
+ this.svg = d3.select(document.createElement('div')).append('svg')
+ .style('position', 'absolute');
+
+ this.svg.append('path')
+ .datum(this.features)
+ .attr('class', 'boundary');
+ }
+
+ getSourceState() {
+ return SourceState.READY;
+ }
+
+ render(frameState) {
+ const width = frameState.size[0];
+ const height = frameState.size[1];
+ const projection = frameState.viewState.projection;
+ const d3Projection = d3.geoMercator().scale(1).translate([0, 0]);
+ let d3Path = d3.geoPath().projection(d3Projection);
+
+ const pixelBounds = d3Path.bounds(this.features);
+ const pixelBoundsWidth = pixelBounds[1][0] - pixelBounds[0][0];
+ const pixelBoundsHeight = pixelBounds[1][1] - pixelBounds[0][1];
+
+ const geoBounds = d3.geoBounds(this.features);
+ const geoBoundsLeftBottom = fromLonLat(geoBounds[0], projection);
+ const geoBoundsRightTop = fromLonLat(geoBounds[1], projection);
+ let geoBoundsWidth = geoBoundsRightTop[0] - geoBoundsLeftBottom[0];
+ if (geoBoundsWidth < 0) {
+ geoBoundsWidth += getWidth(projection.getExtent());
+ }
+ const geoBoundsHeight = geoBoundsRightTop[1] - geoBoundsLeftBottom[1];
+
+ const widthResolution = geoBoundsWidth / pixelBoundsWidth;
+ const heightResolution = geoBoundsHeight / pixelBoundsHeight;
+ const r = Math.max(widthResolution, heightResolution);
+ const scale = r / frameState.viewState.resolution;
+
+ const center = toLonLat(getCenter(frameState.extent), projection);
+ d3Projection.scale(scale).center(center).translate([width / 2, height / 2]);
+
+ d3Path = d3Path.projection(d3Projection);
+ d3Path(this.features);
+
+ this.svg.attr('width', width);
+ this.svg.attr('height', height);
+
+ this.svg.select('path')
+ .attr('d', d3Path);
+
+ return this.svg.node();
+ }
+}
const map = new Map({
layers: [
@@ -26,62 +86,10 @@ const map = new Map({
* Load the topojson data and create an ol/layer/Image for that data.
*/
d3.json('data/topojson/us.json', function(error, us) {
- const features = topojson.feature(us, us.objects.counties);
- /**
- * This function uses d3 to render the topojson features to a canvas.
- * @param {module:ol/extent~Extent} extent Extent.
- * @param {number} resolution Resolution.
- * @param {number} pixelRatio Pixel ratio.
- * @param {module:ol/size~Size} size Size.
- * @param {module:ol/proj/Projection~Projection} projection Projection.
- * @return {HTMLCanvasElement} A canvas element.
- */
- const canvasFunction = function(extent, resolution, pixelRatio, size, projection) {
- const canvasWidth = size[0];
- const canvasHeight = size[1];
-
- const canvas = d3.select(document.createElement('canvas'));
- canvas.attr('width', canvasWidth).attr('height', canvasHeight);
-
- const context = canvas.node().getContext('2d');
-
- const d3Projection = d3.geoMercator().scale(1).translate([0, 0]);
- let d3Path = d3.geoPath().projection(d3Projection);
-
- const pixelBounds = d3Path.bounds(features);
- const pixelBoundsWidth = pixelBounds[1][0] - pixelBounds[0][0];
- const pixelBoundsHeight = pixelBounds[1][1] - pixelBounds[0][1];
-
- const geoBounds = d3.geoBounds(features);
- const geoBoundsLeftBottom = fromLonLat(geoBounds[0], projection);
- const geoBoundsRightTop = fromLonLat(geoBounds[1], projection);
- let geoBoundsWidth = geoBoundsRightTop[0] - geoBoundsLeftBottom[0];
- if (geoBoundsWidth < 0) {
- geoBoundsWidth += getWidth(projection.getExtent());
- }
- const geoBoundsHeight = geoBoundsRightTop[1] - geoBoundsLeftBottom[1];
-
- const widthResolution = geoBoundsWidth / pixelBoundsWidth;
- const heightResolution = geoBoundsHeight / pixelBoundsHeight;
- const r = Math.max(widthResolution, heightResolution);
- const scale = r / (resolution / pixelRatio);
-
- const center = toLonLat(getCenter(extent), projection);
- d3Projection.scale(scale).center(center)
- .translate([canvasWidth / 2, canvasHeight / 2]);
- d3Path = d3Path.projection(d3Projection).context(context);
- d3Path(features);
- context.stroke();
-
- return canvas.node();
- };
-
- const layer = new ImageLayer({
- source: new ImageCanvasSource({
- canvasFunction: canvasFunction,
- projection: 'EPSG:3857'
- })
+ const layer = new CanvasLayer({
+ features: topojson.feature(us, us.objects.counties)
});
+
map.addLayer(layer);
});