Draw labels in a postrender function

Position labels relative to the viewport when view is rotated
This commit is contained in:
mike-000
2020-02-20 13:31:41 +00:00
committed by GitHub
parent 4a11bcccbb
commit c28793ae04

View File

@@ -15,7 +15,7 @@ import {
getTransform,
transformExtent
} from '../proj.js';
import {getCenter, intersects, equals, getIntersection, isEmpty} from '../extent.js';
import {getCenter, getHeight, getWidth, intersects, equals, getIntersection, isEmpty} from '../extent.js';
import {clamp} from '../math.js';
import Style from '../style/Style.js';
import Feature from '../Feature.js';
@@ -23,6 +23,8 @@ import {meridian, parallel} from '../geom/flat/geodesic.js';
import GeometryLayout from '../geom/GeometryLayout.js';
import Point from '../geom/Point.js';
import Collection from '../Collection.js';
import {getVectorContext} from '../render.js';
import EventType from '../render/EventType.js';
/**
@@ -382,6 +384,8 @@ class Graticule extends VectorLayer {
this.meridiansLabels_ = [];
this.parallelsLabels_ = [];
this.addEventListener(EventType.POSTRENDER, this.drawLabels_.bind(this));
}
/**
@@ -419,6 +423,7 @@ class Graticule extends VectorLayer {
/**
* @type {?import("../extent.js").Extent}
* @private
*/
this.loadedExtent_ = null;
@@ -486,10 +491,10 @@ class Graticule extends VectorLayer {
// first make sure we have enough features in the pool
let featureCount = this.meridians_.length + this.parallels_.length;
if (this.meridiansLabels_) {
featureCount += this.meridiansLabels_.length;
featureCount += this.meridians_.length;
}
if (this.parallelsLabels_) {
featureCount += this.parallelsLabels_.length;
featureCount += this.parallels_.length;
}
let feature;
@@ -516,27 +521,6 @@ class Graticule extends VectorLayer {
feature.setStyle(this.lineStyle_);
featuresColl.push(feature);
}
let labelData;
if (this.meridiansLabels_) {
for (i = 0, l = this.meridiansLabels_.length; i < l; ++i) {
labelData = this.meridiansLabels_[i];
feature = this.featurePool_[poolIndex++];
feature.setGeometry(labelData.geom);
feature.setStyle(this.lonLabelStyle_);
feature.set('graticule_label', labelData.text);
featuresColl.push(feature);
}
}
if (this.parallelsLabels_) {
for (i = 0, l = this.parallelsLabels_.length; i < l; ++i) {
labelData = this.parallelsLabels_[i];
feature = this.featurePool_[poolIndex++];
feature.setGeometry(labelData.geom);
feature.setStyle(this.latLabelStyle_);
feature.set('graticule_label', labelData.text);
featuresColl.push(feature);
}
}
}
/**
@@ -553,11 +537,15 @@ class Graticule extends VectorLayer {
const lineString = this.getMeridian_(lon, minLat, maxLat, squaredTolerance, index);
if (intersects(lineString.getExtent(), extent)) {
if (this.meridiansLabels_) {
const textPoint = this.getMeridianPoint_(lineString, extent, index);
this.meridiansLabels_[index] = {
geom: textPoint,
text: this.lonLabelFormatter_(lon)
};
const text = this.lonLabelFormatter_(lon);
if (index in this.meridiansLabels_) {
this.meridiansLabels_[index].text = text;
} else {
this.meridiansLabels_[index] = {
geom: new Point([]),
text: text
};
}
}
this.meridians_[index++] = lineString;
}
@@ -578,17 +566,83 @@ class Graticule extends VectorLayer {
const lineString = this.getParallel_(lat, minLon, maxLon, squaredTolerance, index);
if (intersects(lineString.getExtent(), extent)) {
if (this.parallelsLabels_) {
const textPoint = this.getParallelPoint_(lineString, extent, index);
this.parallelsLabels_[index] = {
geom: textPoint,
text: this.latLabelFormatter_(lat)
};
const text = this.latLabelFormatter_(lat);
if (index in this.parallelsLabels_) {
this.parallelsLabels_[index].text = text;
} else {
this.parallelsLabels_[index] = {
geom: new Point([]),
text: text
};
}
}
this.parallels_[index++] = lineString;
}
return index;
}
/**
* @param {import("../render/Event.js").RenderEvent} event Render event.
* @private
*/
drawLabels_(event) {
const rotation = event.frameState.viewState.rotation;
const extent = event.frameState.extent;
let rotationCenter, rotationExtent;
if (rotation) {
rotationCenter = getCenter(extent);
const width = getWidth(extent);
const height = getHeight(extent);
const cr = Math.abs(Math.cos(rotation));
const sr = Math.abs(Math.sin(rotation));
const unrotatedWidth = (sr * height - cr * width) / (sr * sr - cr * cr);
const unrotatedHeight = (sr * width - cr * height) / (sr * sr - cr * cr);
rotationExtent = [
rotationCenter[0] - unrotatedWidth / 2, rotationCenter[1] - unrotatedHeight / 2,
rotationCenter[0] + unrotatedWidth / 2, rotationCenter[1] + unrotatedHeight / 2
];
}
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, this.renderedExtent_, 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));
}
}
if (this.parallelsLabels_) {
for (index = 0, l = this.parallels_.length; index < l; ++index) {
const lineString = this.parallels_[index];
if (!rotation) {
textPoint = this.getParallelPoint_(lineString, this.renderedExtent_, index);
} else {
const clone = lineString.clone();
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));
}
}
}
/**
* @param {import("../extent.js").Extent} extent Extent.
* @param {import("../coordinate.js").Coordinate} center Center.
@@ -745,19 +799,23 @@ class Graticule extends VectorLayer {
*/
getMeridianPoint_(lineString, extent, index) {
const flatCoordinates = lineString.getFlatCoordinates();
const clampedBottom = Math.max(extent[1], flatCoordinates[1]);
const clampedTop = Math.min(extent[3], flatCoordinates[flatCoordinates.length - 1]);
let bottom = 1;
let top = flatCoordinates.length - 1;
if (flatCoordinates[bottom] > flatCoordinates[top]) {
bottom = top;
top = 1;
}
const clampedBottom = Math.max(extent[1], flatCoordinates[bottom]);
const clampedTop = Math.min(extent[3], flatCoordinates[top]);
const lat = clamp(
extent[1] + Math.abs(extent[1] - extent[3]) * this.lonLabelPosition_,
clampedBottom, clampedTop);
const coordinate = [flatCoordinates[0], lat];
let point;
if (index in this.meridiansLabels_) {
point = this.meridiansLabels_[index].geom;
point.setCoordinates(coordinate);
} else {
point = new Point(coordinate);
}
const coordinate0 = flatCoordinates[bottom - 1] +
(flatCoordinates[top - 1] - flatCoordinates[bottom - 1]) * (lat - flatCoordinates[bottom]) /
(flatCoordinates[top] - flatCoordinates[bottom]);
const coordinate = [coordinate0, lat];
const point = this.meridiansLabels_[index].geom;
point.setCoordinates(coordinate);
return point;
}
@@ -801,19 +859,23 @@ class Graticule extends VectorLayer {
*/
getParallelPoint_(lineString, extent, index) {
const flatCoordinates = lineString.getFlatCoordinates();
const clampedLeft = Math.max(extent[0], flatCoordinates[0]);
const clampedRight = Math.min(extent[2], flatCoordinates[flatCoordinates.length - 2]);
let left = 0;
let right = flatCoordinates.length - 2;
if (flatCoordinates[left] > flatCoordinates[right]) {
left = right;
right = 0;
}
const clampedLeft = Math.max(extent[0], flatCoordinates[left]);
const clampedRight = Math.min(extent[2], flatCoordinates[right]);
const lon = clamp(
extent[0] + Math.abs(extent[0] - extent[2]) * this.latLabelPosition_,
clampedLeft, clampedRight);
const coordinate = [lon, flatCoordinates[1]];
let point;
if (index in this.parallelsLabels_) {
point = this.parallelsLabels_[index].geom;
point.setCoordinates(coordinate);
} else {
point = new Point(coordinate);
}
const coordinate1 = flatCoordinates[left + 1] +
(flatCoordinates[right + 1] - flatCoordinates[left + 1]) * (lon - flatCoordinates[left]) /
(flatCoordinates[right] - flatCoordinates[left]);
const coordinate = [lon, coordinate1];
const point = this.parallelsLabels_[index].geom;
point.setCoordinates(coordinate);
return point;
}