From 4ca966bd92a060e2bcc138ba1c1d2ad4f9b71e26 Mon Sep 17 00:00:00 2001 From: mike-000 <49240900+mike-000@users.noreply.github.com> Date: Wed, 11 Mar 2020 14:09:33 +0000 Subject: [PATCH] show labels in wrapped worlds test labels in wrapped world --- src/ol/layer/Graticule.js | 91 ++++++++++++++++++++-------------- test/spec/ol/graticule.test.js | 48 ++++++++++++++++-- 2 files changed, 100 insertions(+), 39 deletions(-) diff --git a/src/ol/layer/Graticule.js b/src/ol/layer/Graticule.js index 0fbc0cea50..6bc7360dfa 100644 --- a/src/ol/layer/Graticule.js +++ b/src/ol/layer/Graticule.js @@ -17,6 +17,7 @@ import { import { applyTransform, containsCoordinate, + containsExtent, equals, getCenter, getHeight, @@ -622,9 +623,9 @@ class Graticule extends VectorLayer { drawLabels_(event) { const rotation = event.frameState.viewState.rotation; const extent = event.frameState.extent; - let rotationCenter, rotationExtent; + const rotationCenter = getCenter(extent); + let rotationExtent = extent; if (rotation) { - rotationCenter = getCenter(extent); const width = getWidth(extent); const height = getHeight(extent); const cr = Math.abs(Math.cos(rotation)); @@ -637,42 +638,60 @@ class Graticule extends VectorLayer { ]; } - const vectorContext = getVectorContext(event); - let poolIndex = this.meridians_.length + this.parallels_.length; - let feature, index, l, textPoint; - - if (this.meridiansLabels_) { - for (index = 0, l = this.meridiansLabels_.length; index < l; ++index) { - const lineString = this.meridians_[index]; - if (!rotation) { - textPoint = this.getMeridianPoint_(lineString, extent, index); - } else { - const clone = lineString.clone(); - clone.rotate(-rotation, rotationCenter); - textPoint = this.getMeridianPoint_(clone, rotationExtent, index); - textPoint.rotate(rotation, rotationCenter); - } - feature = this.featurePool_[poolIndex++]; - feature.setGeometry(textPoint); - feature.set('graticule_label', this.meridiansLabels_[index].text); - vectorContext.drawFeature(feature, this.lonLabelStyle_(feature)); - } + let startWorld = 0; + let endWorld = 0; + let labelsAtStart = this.latLabelPosition_ < 0.5; + const projectionExtent = this.projection_.getExtent(); + const worldWidth = getWidth(projectionExtent); + if (this.getSource().getWrapX() && this.projection_.canWrapX() && !containsExtent(projectionExtent, extent)) { + startWorld = Math.floor((extent[0] - projectionExtent[0]) / worldWidth); + endWorld = Math.ceil((extent[2] - projectionExtent[2]) / worldWidth); + const inverted = Math.abs(rotation) > Math.PI / 2; + labelsAtStart = labelsAtStart !== inverted; } - if (this.parallelsLabels_) { - for (index = 0, l = this.parallels_.length; index < l; ++index) { - const lineString = this.parallels_[index]; - if (!rotation) { - textPoint = this.getParallelPoint_(lineString, extent, index); - } else { - const clone = lineString.clone(); - clone.rotate(-rotation, rotationCenter); - textPoint = this.getParallelPoint_(clone, rotationExtent, index); - textPoint.rotate(rotation, rotationCenter); + const vectorContext = getVectorContext(event); + + for (let world = startWorld; world <= endWorld; ++world) { + let poolIndex = this.meridians_.length + this.parallels_.length; + let feature, index, l, textPoint; + + if (this.meridiansLabels_) { + for (index = 0, l = this.meridiansLabels_.length; index < l; ++index) { + const lineString = this.meridians_[index]; + if (!rotation && world === 0) { + textPoint = this.getMeridianPoint_(lineString, extent, index); + } else { + const clone = lineString.clone(); + clone.translate(world * worldWidth, 0); + clone.rotate(-rotation, rotationCenter); + textPoint = this.getMeridianPoint_(clone, rotationExtent, index); + textPoint.rotate(rotation, rotationCenter); + } + feature = this.featurePool_[poolIndex++]; + feature.setGeometry(textPoint); + feature.set('graticule_label', this.meridiansLabels_[index].text); + vectorContext.drawFeature(feature, this.lonLabelStyle_(feature)); + } + } + if (this.parallelsLabels_) { + if (world === startWorld && labelsAtStart || world === endWorld && !labelsAtStart) { + for (index = 0, l = this.parallels_.length; index < l; ++index) { + const lineString = this.parallels_[index]; + if (!rotation && world === 0) { + textPoint = this.getParallelPoint_(lineString, extent, index); + } else { + const clone = lineString.clone(); + clone.translate(world * worldWidth, 0); + clone.rotate(-rotation, rotationCenter); + textPoint = this.getParallelPoint_(clone, rotationExtent, index); + textPoint.rotate(rotation, rotationCenter); + } + feature = this.featurePool_[poolIndex++]; + feature.setGeometry(textPoint); + feature.set('graticule_label', this.parallelsLabels_[index].text); + vectorContext.drawFeature(feature, this.latLabelStyle_(feature)); + } } - feature = this.featurePool_[poolIndex++]; - feature.setGeometry(textPoint); - feature.set('graticule_label', this.parallelsLabels_[index].text); - vectorContext.drawFeature(feature, this.latLabelStyle_(feature)); } } } diff --git a/test/spec/ol/graticule.test.js b/test/spec/ol/graticule.test.js index 269c496578..366358cd82 100644 --- a/test/spec/ol/graticule.test.js +++ b/test/spec/ol/graticule.test.js @@ -1,6 +1,6 @@ import Graticule from '../../../src/ol/layer/Graticule.js'; import Map from '../../../src/ol/Map.js'; -import {get as getProjection} from '../../../src/ol/proj.js'; +import {fromLonLat, get as getProjection} from '../../../src/ol/proj.js'; import Stroke from '../../../src/ol/style/Stroke.js'; import Text from '../../../src/ol/style/Text.js'; import Feature from '../../../src/ol/Feature.js'; @@ -31,7 +31,48 @@ describe('ol.layer.Graticule', function() { expect(graticule.parallelsLabels_).to.be(null); }); - it('creates a graticule with labels', function() { + it('creates a graticule with normal world labels', function() { + const feature = new Feature(); + graticule = new Graticule({ + showLabels: true, + wrapX: false + }); + new Map({ + layers: [graticule] + }); + const extent = [-25614353.926475704, -7827151.696402049, + 25614353.926475704, 7827151.696402049]; + const projection = getProjection('EPSG:3857'); + const resolution = 39135.75848201024; + graticule.loaderFunction(extent, resolution, projection); + const event = { + context: document.createElement('canvas').getContext('2d'), + inversePixelTransform: [1, 0, 0, 1, 0, 0], + frameState: { + coordinateToPixelTransform: [1, 0, 0, 1, 0, 0], + extent: extent, + pixelRatio: 1, + viewState: { + projection: projection, + resolution: resolution, + rotation: 0 + } + } + }; + graticule.drawLabels_(event); + expect(graticule.meridiansLabels_.length).to.be(13); + expect(graticule.meridiansLabels_[0].text).to.be('0° 00′ 00″'); + expect(graticule.meridiansLabels_[0].geom.getCoordinates()[0]).to.roughlyEqual(0, 1e-9); + expect(graticule.parallelsLabels_.length).to.be(3); + expect(graticule.parallelsLabels_[0].text).to.be('0° 00′ 00″'); + expect(graticule.parallelsLabels_[0].geom.getCoordinates()[1]).to.roughlyEqual(0, 1e-9); + feature.set('graticule_label', graticule.meridiansLabels_[0].text); + expect(graticule.lonLabelStyle_(feature).getText().getText()).to.be('0° 00′ 00″'); + feature.set('graticule_label', graticule.parallelsLabels_[0].text); + expect(graticule.latLabelStyle_(feature).getText().getText()).to.be('0° 00′ 00″'); + }); + + it('creates a graticule with wrapped world labels', function() { const feature = new Feature(); graticule = new Graticule({ showLabels: true @@ -61,7 +102,8 @@ describe('ol.layer.Graticule', function() { graticule.drawLabels_(event); expect(graticule.meridiansLabels_.length).to.be(13); expect(graticule.meridiansLabels_[0].text).to.be('0° 00′ 00″'); - expect(graticule.meridiansLabels_[0].geom.getCoordinates()[0]).to.roughlyEqual(0, 1e-9); + const coordinates = fromLonLat([360, 0]); + expect(graticule.meridiansLabels_[0].geom.getCoordinates()[0]).to.roughlyEqual(coordinates[0], 1e-9); expect(graticule.parallelsLabels_.length).to.be(3); expect(graticule.parallelsLabels_[0].text).to.be('0° 00′ 00″'); expect(graticule.parallelsLabels_[0].geom.getCoordinates()[1]).to.roughlyEqual(0, 1e-9);