Support for rotation
This commit is contained in:
BIN
rendering/cases/linestring-style-rotation/expected.png
Normal file
BIN
rendering/cases/linestring-style-rotation/expected.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
70
rendering/cases/linestring-style-rotation/main.js
Normal file
70
rendering/cases/linestring-style-rotation/main.js
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import Map from '../../../src/ol/CompositeMap.js';
|
||||||
|
import View from '../../../src/ol/View.js';
|
||||||
|
import Feature from '../../../src/ol/Feature.js';
|
||||||
|
import LineString from '../../../src/ol/geom/LineString.js';
|
||||||
|
import VectorLayer from '../../../src/ol/layer/Vector.js';
|
||||||
|
import VectorSource from '../../../src/ol/source/Vector.js';
|
||||||
|
import Style from '../../../src/ol/style/Style.js';
|
||||||
|
import Stroke from '../../../src/ol/style/Stroke.js';
|
||||||
|
|
||||||
|
|
||||||
|
const vectorSource = new VectorSource();
|
||||||
|
let feature;
|
||||||
|
|
||||||
|
feature = new Feature({
|
||||||
|
geometry: new LineString([[-60, 60], [45, 60]])
|
||||||
|
});
|
||||||
|
vectorSource.addFeature(feature);
|
||||||
|
|
||||||
|
feature = new Feature({
|
||||||
|
geometry: new LineString([[-60, -50], [30, 10]])
|
||||||
|
});
|
||||||
|
feature.setStyle(new Style({
|
||||||
|
stroke: new Stroke({color: '#f00', width: 3})
|
||||||
|
}));
|
||||||
|
vectorSource.addFeature(feature);
|
||||||
|
|
||||||
|
feature = new Feature({
|
||||||
|
geometry: new LineString([[-110, -100], [0, 100], [100, -90]])
|
||||||
|
});
|
||||||
|
feature.setStyle(new Style({
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: 'rgba(55, 55, 55, 0.75)',
|
||||||
|
width: 5,
|
||||||
|
lineCap: 'square',
|
||||||
|
lineDash: [4, 8],
|
||||||
|
lineJoin: 'round'
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
vectorSource.addFeature(feature);
|
||||||
|
|
||||||
|
feature = new Feature({
|
||||||
|
geometry: new LineString([[-80, 80], [80, 80], [-40, -90]])
|
||||||
|
});
|
||||||
|
feature.setStyle([
|
||||||
|
new Style({
|
||||||
|
stroke: new Stroke({color: '#F2F211', width: 5})
|
||||||
|
}),
|
||||||
|
new Style({
|
||||||
|
stroke: new Stroke({color: '#292921', width: 1})
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
vectorSource.addFeature(feature);
|
||||||
|
|
||||||
|
|
||||||
|
new Map({
|
||||||
|
pixelRatio: 1,
|
||||||
|
layers: [
|
||||||
|
new VectorLayer({
|
||||||
|
source: vectorSource
|
||||||
|
})
|
||||||
|
],
|
||||||
|
target: 'map',
|
||||||
|
view: new View({
|
||||||
|
center: [0, 0],
|
||||||
|
resolution: 1,
|
||||||
|
rotation: Math.PI / 4
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
render();
|
||||||
@@ -30,9 +30,13 @@ class CompositeMapRenderer extends MapRenderer {
|
|||||||
* @type {HTMLDivElement}
|
* @type {HTMLDivElement}
|
||||||
*/
|
*/
|
||||||
this.element_ = document.createElement('div');
|
this.element_ = document.createElement('div');
|
||||||
|
const style = this.element_.style;
|
||||||
|
style.display = 'flex';
|
||||||
|
style.alignItems = 'center';
|
||||||
|
style.justifyContent = 'center';
|
||||||
|
style.width = '100%';
|
||||||
|
style.height = '100%';
|
||||||
|
|
||||||
this.element_.style.width = '100%';
|
|
||||||
this.element_.style.height = '100%';
|
|
||||||
this.element_.className = CLASS_UNSELECTABLE;
|
this.element_.className = CLASS_UNSELECTABLE;
|
||||||
|
|
||||||
const container = map.getViewport();
|
const container = map.getViewport();
|
||||||
@@ -82,9 +86,6 @@ class CompositeMapRenderer extends MapRenderer {
|
|||||||
stableSort(layerStatesArray, sortByZIndex);
|
stableSort(layerStatesArray, sortByZIndex);
|
||||||
|
|
||||||
const rotation = frameState.viewState.rotation;
|
const rotation = frameState.viewState.rotation;
|
||||||
if (rotation) {
|
|
||||||
// TODO: apply rotation
|
|
||||||
}
|
|
||||||
|
|
||||||
const viewResolution = frameState.viewState.resolution;
|
const viewResolution = frameState.viewState.resolution;
|
||||||
|
|
||||||
@@ -99,10 +100,17 @@ class CompositeMapRenderer extends MapRenderer {
|
|||||||
const layerRenderer = this.getLayerRenderer(layer);
|
const layerRenderer = this.getLayerRenderer(layer);
|
||||||
if (layerRenderer.prepareFrame(frameState, layerState)) {
|
if (layerRenderer.prepareFrame(frameState, layerState)) {
|
||||||
const element = layerRenderer.renderFrame(frameState, layerState);
|
const element = layerRenderer.renderFrame(frameState, layerState);
|
||||||
|
|
||||||
const opacity = layerState.opacity;
|
const opacity = layerState.opacity;
|
||||||
if (opacity !== element.style.opacity) {
|
if (opacity !== element.style.opacity) {
|
||||||
element.style.opacity = opacity;
|
element.style.opacity = opacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const transform = 'rotate(' + rotation + 'rad)';
|
||||||
|
if (transform !== element.style.transform) {
|
||||||
|
element.style.transform = transform;
|
||||||
|
}
|
||||||
|
|
||||||
this.children_.push(element);
|
this.children_.push(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,6 +184,27 @@ class CanvasLayerRenderer extends LayerRenderer {
|
|||||||
return composeTransform(this.transform_, dx1, dy1, sx, sy, angle, dx2, dy2);
|
return composeTransform(this.transform_, dx1, dy1, sx, sy, angle, dx2, dy2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a transform for rendering to an element that will be rotated after rendering.
|
||||||
|
* @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
|
||||||
|
* @param {number} width Width of the rendered element (in pixels).
|
||||||
|
* @param {number} height Height of the rendered element (in pixels).
|
||||||
|
* @param {number} offsetX Offset on the x-axis in view coordinates.
|
||||||
|
* @protected
|
||||||
|
* @return {!import("../../transform.js").Transform} Transform.
|
||||||
|
*/
|
||||||
|
getRenderTransform(frameState, width, height, offsetX) {
|
||||||
|
const viewState = frameState.viewState;
|
||||||
|
const pixelRatio = frameState.pixelRatio;
|
||||||
|
const dx1 = width / 2;
|
||||||
|
const dy1 = height / 2;
|
||||||
|
const sx = pixelRatio / viewState.resolution;
|
||||||
|
const sy = -sx;
|
||||||
|
const dx2 = -viewState.center[0] + offsetX;
|
||||||
|
const dy2 = -viewState.center[1];
|
||||||
|
return composeTransform(this.transform_, dx1, dy1, sx, sy, 0, dx2, dy2);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract
|
* @abstract
|
||||||
* @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
|
* @param {import("../../PluggableMap.js").FrameState} frameState Frame state.
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
|||||||
*/
|
*/
|
||||||
this.context = createCanvasContext2D();
|
this.context = createCanvasContext2D();
|
||||||
|
|
||||||
|
const canvas = this.context.canvas;
|
||||||
|
canvas.style.position = 'absolute';
|
||||||
|
|
||||||
listen(labelCache, EventType.CLEAR, this.handleFontsChanged_, this);
|
listen(labelCache, EventType.CLEAR, this.handleFontsChanged_, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,12 +278,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
|||||||
const viewHints = frameState.viewHints;
|
const viewHints = frameState.viewHints;
|
||||||
const snapToPixel = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
|
const snapToPixel = !(viewHints[ViewHint.ANIMATING] || viewHints[ViewHint.INTERACTING]);
|
||||||
|
|
||||||
// TODO: deal with rotation (this should not be necessary)
|
let transform = this.getRenderTransform(frameState, width, height, 0);
|
||||||
if (rotation) {
|
|
||||||
rotateAtOffset(context, -rotation, width / 2, height / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
let transform = this.getTransform(frameState, 0);
|
|
||||||
const skippedFeatureUids = layerState.managed ? frameState.skippedFeatureUids : {};
|
const skippedFeatureUids = layerState.managed ? frameState.skippedFeatureUids : {};
|
||||||
replayGroup.replay(context, transform, rotation, skippedFeatureUids, snapToPixel);
|
replayGroup.replay(context, transform, rotation, skippedFeatureUids, snapToPixel);
|
||||||
|
|
||||||
@@ -292,7 +290,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
|||||||
while (startX < projectionExtent[0]) {
|
while (startX < projectionExtent[0]) {
|
||||||
--world;
|
--world;
|
||||||
offsetX = worldWidth * world;
|
offsetX = worldWidth * world;
|
||||||
transform = this.getTransform(frameState, offsetX);
|
transform = this.getRenderTransform(frameState, width, height, offsetX);
|
||||||
replayGroup.replay(context, transform, rotation, skippedFeatureUids, snapToPixel);
|
replayGroup.replay(context, transform, rotation, skippedFeatureUids, snapToPixel);
|
||||||
startX += worldWidth;
|
startX += worldWidth;
|
||||||
}
|
}
|
||||||
@@ -301,17 +299,12 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
|||||||
while (startX > projectionExtent[2]) {
|
while (startX > projectionExtent[2]) {
|
||||||
++world;
|
++world;
|
||||||
offsetX = worldWidth * world;
|
offsetX = worldWidth * world;
|
||||||
transform = this.getTransform(frameState, offsetX);
|
transform = this.getRenderTransform(frameState, width, height, offsetX);
|
||||||
replayGroup.replay(context, transform, rotation, skippedFeatureUids, snapToPixel);
|
replayGroup.replay(context, transform, rotation, skippedFeatureUids, snapToPixel);
|
||||||
startX -= worldWidth;
|
startX -= worldWidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: deal with rotation (this should not be necessary)
|
|
||||||
if (rotation) {
|
|
||||||
rotateAtOffset(context, rotation, width / 2, height / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.getLayer().hasListener(RenderEventType.RENDER)) {
|
if (this.getLayer().hasListener(RenderEventType.RENDER)) {
|
||||||
this.dispatchRenderEvent(context, frameState, transform);
|
this.dispatchRenderEvent(context, frameState, transform);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user