Draw labels in a postrender function
Position labels relative to the viewport when view is rotated
This commit is contained in:
+116
-54
@@ -15,7 +15,7 @@ import {
|
|||||||
getTransform,
|
getTransform,
|
||||||
transformExtent
|
transformExtent
|
||||||
} from '../proj.js';
|
} 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 {clamp} from '../math.js';
|
||||||
import Style from '../style/Style.js';
|
import Style from '../style/Style.js';
|
||||||
import Feature from '../Feature.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 GeometryLayout from '../geom/GeometryLayout.js';
|
||||||
import Point from '../geom/Point.js';
|
import Point from '../geom/Point.js';
|
||||||
import Collection from '../Collection.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.meridiansLabels_ = [];
|
||||||
this.parallelsLabels_ = [];
|
this.parallelsLabels_ = [];
|
||||||
|
|
||||||
|
this.addEventListener(EventType.POSTRENDER, this.drawLabels_.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -419,6 +423,7 @@ class Graticule extends VectorLayer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {?import("../extent.js").Extent}
|
* @type {?import("../extent.js").Extent}
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
this.loadedExtent_ = null;
|
this.loadedExtent_ = null;
|
||||||
|
|
||||||
@@ -486,10 +491,10 @@ class Graticule extends VectorLayer {
|
|||||||
// first make sure we have enough features in the pool
|
// first make sure we have enough features in the pool
|
||||||
let featureCount = this.meridians_.length + this.parallels_.length;
|
let featureCount = this.meridians_.length + this.parallels_.length;
|
||||||
if (this.meridiansLabels_) {
|
if (this.meridiansLabels_) {
|
||||||
featureCount += this.meridiansLabels_.length;
|
featureCount += this.meridians_.length;
|
||||||
}
|
}
|
||||||
if (this.parallelsLabels_) {
|
if (this.parallelsLabels_) {
|
||||||
featureCount += this.parallelsLabels_.length;
|
featureCount += this.parallels_.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
let feature;
|
let feature;
|
||||||
@@ -516,27 +521,6 @@ class Graticule extends VectorLayer {
|
|||||||
feature.setStyle(this.lineStyle_);
|
feature.setStyle(this.lineStyle_);
|
||||||
featuresColl.push(feature);
|
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);
|
const lineString = this.getMeridian_(lon, minLat, maxLat, squaredTolerance, index);
|
||||||
if (intersects(lineString.getExtent(), extent)) {
|
if (intersects(lineString.getExtent(), extent)) {
|
||||||
if (this.meridiansLabels_) {
|
if (this.meridiansLabels_) {
|
||||||
const textPoint = this.getMeridianPoint_(lineString, extent, index);
|
const text = this.lonLabelFormatter_(lon);
|
||||||
this.meridiansLabels_[index] = {
|
if (index in this.meridiansLabels_) {
|
||||||
geom: textPoint,
|
this.meridiansLabels_[index].text = text;
|
||||||
text: this.lonLabelFormatter_(lon)
|
} else {
|
||||||
};
|
this.meridiansLabels_[index] = {
|
||||||
|
geom: new Point([]),
|
||||||
|
text: text
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.meridians_[index++] = lineString;
|
this.meridians_[index++] = lineString;
|
||||||
}
|
}
|
||||||
@@ -578,17 +566,83 @@ class Graticule extends VectorLayer {
|
|||||||
const lineString = this.getParallel_(lat, minLon, maxLon, squaredTolerance, index);
|
const lineString = this.getParallel_(lat, minLon, maxLon, squaredTolerance, index);
|
||||||
if (intersects(lineString.getExtent(), extent)) {
|
if (intersects(lineString.getExtent(), extent)) {
|
||||||
if (this.parallelsLabels_) {
|
if (this.parallelsLabels_) {
|
||||||
const textPoint = this.getParallelPoint_(lineString, extent, index);
|
const text = this.latLabelFormatter_(lat);
|
||||||
this.parallelsLabels_[index] = {
|
if (index in this.parallelsLabels_) {
|
||||||
geom: textPoint,
|
this.parallelsLabels_[index].text = text;
|
||||||
text: this.latLabelFormatter_(lat)
|
} else {
|
||||||
};
|
this.parallelsLabels_[index] = {
|
||||||
|
geom: new Point([]),
|
||||||
|
text: text
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.parallels_[index++] = lineString;
|
this.parallels_[index++] = lineString;
|
||||||
}
|
}
|
||||||
return index;
|
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("../extent.js").Extent} extent Extent.
|
||||||
* @param {import("../coordinate.js").Coordinate} center Center.
|
* @param {import("../coordinate.js").Coordinate} center Center.
|
||||||
@@ -745,19 +799,23 @@ class Graticule extends VectorLayer {
|
|||||||
*/
|
*/
|
||||||
getMeridianPoint_(lineString, extent, index) {
|
getMeridianPoint_(lineString, extent, index) {
|
||||||
const flatCoordinates = lineString.getFlatCoordinates();
|
const flatCoordinates = lineString.getFlatCoordinates();
|
||||||
const clampedBottom = Math.max(extent[1], flatCoordinates[1]);
|
let bottom = 1;
|
||||||
const clampedTop = Math.min(extent[3], flatCoordinates[flatCoordinates.length - 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(
|
const lat = clamp(
|
||||||
extent[1] + Math.abs(extent[1] - extent[3]) * this.lonLabelPosition_,
|
extent[1] + Math.abs(extent[1] - extent[3]) * this.lonLabelPosition_,
|
||||||
clampedBottom, clampedTop);
|
clampedBottom, clampedTop);
|
||||||
const coordinate = [flatCoordinates[0], lat];
|
const coordinate0 = flatCoordinates[bottom - 1] +
|
||||||
let point;
|
(flatCoordinates[top - 1] - flatCoordinates[bottom - 1]) * (lat - flatCoordinates[bottom]) /
|
||||||
if (index in this.meridiansLabels_) {
|
(flatCoordinates[top] - flatCoordinates[bottom]);
|
||||||
point = this.meridiansLabels_[index].geom;
|
const coordinate = [coordinate0, lat];
|
||||||
point.setCoordinates(coordinate);
|
const point = this.meridiansLabels_[index].geom;
|
||||||
} else {
|
point.setCoordinates(coordinate);
|
||||||
point = new Point(coordinate);
|
|
||||||
}
|
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -801,19 +859,23 @@ class Graticule extends VectorLayer {
|
|||||||
*/
|
*/
|
||||||
getParallelPoint_(lineString, extent, index) {
|
getParallelPoint_(lineString, extent, index) {
|
||||||
const flatCoordinates = lineString.getFlatCoordinates();
|
const flatCoordinates = lineString.getFlatCoordinates();
|
||||||
const clampedLeft = Math.max(extent[0], flatCoordinates[0]);
|
let left = 0;
|
||||||
const clampedRight = Math.min(extent[2], flatCoordinates[flatCoordinates.length - 2]);
|
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(
|
const lon = clamp(
|
||||||
extent[0] + Math.abs(extent[0] - extent[2]) * this.latLabelPosition_,
|
extent[0] + Math.abs(extent[0] - extent[2]) * this.latLabelPosition_,
|
||||||
clampedLeft, clampedRight);
|
clampedLeft, clampedRight);
|
||||||
const coordinate = [lon, flatCoordinates[1]];
|
const coordinate1 = flatCoordinates[left + 1] +
|
||||||
let point;
|
(flatCoordinates[right + 1] - flatCoordinates[left + 1]) * (lon - flatCoordinates[left]) /
|
||||||
if (index in this.parallelsLabels_) {
|
(flatCoordinates[right] - flatCoordinates[left]);
|
||||||
point = this.parallelsLabels_[index].geom;
|
const coordinate = [lon, coordinate1];
|
||||||
point.setCoordinates(coordinate);
|
const point = this.parallelsLabels_[index].geom;
|
||||||
} else {
|
point.setCoordinates(coordinate);
|
||||||
point = new Point(coordinate);
|
|
||||||
}
|
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user