allow scale to be two dimensional
add getScaleArray() method test two dimension scale icons test two dimension scale text add example of icon and label scaling use smaller icon and larger interval test two dimensional scale icons test two dimensional scale icons
|
After Width: | Height: | Size: 427 B |
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
layout: example.html
|
||||||
|
title: Icon Scale
|
||||||
|
shortdesc: Example of scaling icons and labels.
|
||||||
|
docs: >
|
||||||
|
Icons and labels can be scaled in both dimensions if required. A negative value will flip the image
|
||||||
|
or text around its anchor point (reversed text is <b>not</b> suitable for line placement). A newline
|
||||||
|
character inserted in label text is interpreted in a <b>vector layer</b>, but will not be shown in
|
||||||
|
a <b>vector context</b>.
|
||||||
|
tags: "vector, style, icon, label, scale"
|
||||||
|
resources:
|
||||||
|
- https://code.jquery.com/jquery-2.2.3.min.js
|
||||||
|
- https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css
|
||||||
|
- https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js
|
||||||
|
---
|
||||||
|
<div id="map" class="map"><div id="popup"></div></div>
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
import Feature from '../src/ol/Feature.js';
|
||||||
|
import Map from '../src/ol/Map.js';
|
||||||
|
import Overlay from '../src/ol/Overlay.js';
|
||||||
|
import Point from '../src/ol/geom/Point.js';
|
||||||
|
import TileJSON from '../src/ol/source/TileJSON.js';
|
||||||
|
import VectorSource from '../src/ol/source/Vector.js';
|
||||||
|
import View from '../src/ol/View.js';
|
||||||
|
import {Icon, Style, Text} from '../src/ol/style.js';
|
||||||
|
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||||
|
import {fromLonLat} from '../src/ol/proj.js';
|
||||||
|
import {getVectorContext} from '../src/ol/render.js';
|
||||||
|
|
||||||
|
const rasterLayer = new TileLayer({
|
||||||
|
source: new TileJSON({
|
||||||
|
url: 'https://a.tiles.mapbox.com/v3/aj.1x1-degrees.json',
|
||||||
|
crossOrigin: '',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const iconFeature = new Feature({
|
||||||
|
geometry: new Point(fromLonLat([0, -10])),
|
||||||
|
name: 'Fish.1',
|
||||||
|
});
|
||||||
|
|
||||||
|
const feature1 = new Feature({
|
||||||
|
geometry: new Point(fromLonLat([0, -10])),
|
||||||
|
name: 'Fish.1 Island',
|
||||||
|
});
|
||||||
|
|
||||||
|
const feature2 = new Feature({
|
||||||
|
geometry: new Point(fromLonLat([-30, 10])),
|
||||||
|
name: 'Fish.2 Island',
|
||||||
|
});
|
||||||
|
|
||||||
|
const iconStyle = new Style({
|
||||||
|
image: new Icon({
|
||||||
|
anchor: [0.5, 0.9],
|
||||||
|
src: 'data/fish.png',
|
||||||
|
crossOrigin: '',
|
||||||
|
scale: [0, 0],
|
||||||
|
rotation: Math.PI / 4,
|
||||||
|
}),
|
||||||
|
text: new Text({
|
||||||
|
text: 'FISH\nTEXT',
|
||||||
|
scale: [0, 0],
|
||||||
|
rotation: Math.PI / 4,
|
||||||
|
textAlign: 'center',
|
||||||
|
textBaseline: 'top',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
let j = 45;
|
||||||
|
|
||||||
|
iconFeature.setStyle(function () {
|
||||||
|
const x = Math.sin((i * Math.PI) / 180) * 3;
|
||||||
|
const y = Math.sin((j * Math.PI) / 180) * 4;
|
||||||
|
iconStyle.getImage().setScale([x, y]);
|
||||||
|
iconStyle.getText().setScale([x, y]);
|
||||||
|
return iconStyle;
|
||||||
|
});
|
||||||
|
|
||||||
|
rasterLayer.on('postrender', function (event) {
|
||||||
|
const vectorContext = getVectorContext(event);
|
||||||
|
const x = Math.cos((i * Math.PI) / 180) * 3;
|
||||||
|
const y = Math.cos((j * Math.PI) / 180) * 4;
|
||||||
|
iconStyle.getImage().setScale([x, y]);
|
||||||
|
iconStyle.getText().setScale([x, y]);
|
||||||
|
vectorContext.drawFeature(feature2, iconStyle);
|
||||||
|
});
|
||||||
|
|
||||||
|
const vectorSource = new VectorSource({
|
||||||
|
features: [iconFeature, feature1, feature2],
|
||||||
|
});
|
||||||
|
|
||||||
|
const vectorLayer = new VectorLayer({
|
||||||
|
source: vectorSource,
|
||||||
|
});
|
||||||
|
|
||||||
|
const map = new Map({
|
||||||
|
layers: [rasterLayer, vectorLayer],
|
||||||
|
target: document.getElementById('map'),
|
||||||
|
view: new View({
|
||||||
|
center: fromLonLat([-15, 0]),
|
||||||
|
zoom: 3,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
setInterval(function () {
|
||||||
|
i = (i + 4) % 360;
|
||||||
|
j = (j + 5) % 360;
|
||||||
|
vectorSource.changed();
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
const element = document.getElementById('popup');
|
||||||
|
|
||||||
|
const popup = new Overlay({
|
||||||
|
element: element,
|
||||||
|
positioning: 'bottom-center',
|
||||||
|
stopEvent: false,
|
||||||
|
offset: [0, -50],
|
||||||
|
});
|
||||||
|
map.addOverlay(popup);
|
||||||
|
|
||||||
|
// display popup on click
|
||||||
|
map.on('click', function (evt) {
|
||||||
|
const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) {
|
||||||
|
return feature;
|
||||||
|
});
|
||||||
|
$(element).popover('destroy');
|
||||||
|
if (feature) {
|
||||||
|
const coordinates = feature.getGeometry().getCoordinates();
|
||||||
|
popup.setPosition(coordinates);
|
||||||
|
$(element).popover({
|
||||||
|
placement: 'top',
|
||||||
|
html: true,
|
||||||
|
animation: false,
|
||||||
|
content: feature.get('name'),
|
||||||
|
});
|
||||||
|
$(element).popover('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// change mouse cursor when over marker
|
||||||
|
map.on('pointermove', function (e) {
|
||||||
|
if (e.dragging) {
|
||||||
|
$(element).popover('destroy');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const pixel = map.getEventPixel(e.originalEvent);
|
||||||
|
const hit = map.hasFeatureAtPixel(pixel);
|
||||||
|
map.getTarget().style.cursor = hit ? 'pointer' : '';
|
||||||
|
});
|
||||||
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,117 @@
|
|||||||
|
import Feature from '../../../src/ol/Feature.js';
|
||||||
|
import Icon from '../../../src/ol/style/Icon.js';
|
||||||
|
import Map from '../../../src/ol/Map.js';
|
||||||
|
import Point from '../../../src/ol/geom/Point.js';
|
||||||
|
import Style from '../../../src/ol/style/Style.js';
|
||||||
|
import VectorLayer from '../../../src/ol/layer/Vector.js';
|
||||||
|
import VectorSource from '../../../src/ol/source/Vector.js';
|
||||||
|
import View from '../../../src/ol/View.js';
|
||||||
|
|
||||||
|
const features = [];
|
||||||
|
for (let i = 0; i < 2; ++i) {
|
||||||
|
const x = i * 5;
|
||||||
|
features.push(
|
||||||
|
new Feature({
|
||||||
|
geometry: new Point([x + 2, 2]),
|
||||||
|
scale: [1.5, 1],
|
||||||
|
anchor: [1, 0.5],
|
||||||
|
rotated: i,
|
||||||
|
}),
|
||||||
|
new Feature({
|
||||||
|
geometry: new Point([x + 3, 2]),
|
||||||
|
scale: [1.5, 1],
|
||||||
|
anchor: [0.5, 0.5],
|
||||||
|
rotated: i,
|
||||||
|
}),
|
||||||
|
new Feature({
|
||||||
|
geometry: new Point([x + 4, 2]),
|
||||||
|
scale: [1.5, 1],
|
||||||
|
anchor: [0, 0.5],
|
||||||
|
rotated: i,
|
||||||
|
}),
|
||||||
|
new Feature({
|
||||||
|
geometry: new Point([x + 2, 4]),
|
||||||
|
scale: [-1, 1],
|
||||||
|
anchor: [0, 0.5],
|
||||||
|
rotated: i,
|
||||||
|
}),
|
||||||
|
new Feature({
|
||||||
|
geometry: new Point([x + 3, 4]),
|
||||||
|
scale: [-1, 1],
|
||||||
|
anchor: [0.5, 0.5],
|
||||||
|
rotated: i,
|
||||||
|
}),
|
||||||
|
new Feature({
|
||||||
|
geometry: new Point([x + 4, 4]),
|
||||||
|
scale: [-1, 1],
|
||||||
|
anchor: [1, 0.5],
|
||||||
|
rotated: i,
|
||||||
|
}),
|
||||||
|
new Feature({
|
||||||
|
geometry: new Point([x + 2, 6]),
|
||||||
|
scale: [1, -1],
|
||||||
|
anchor: [0.5, 1],
|
||||||
|
rotated: i,
|
||||||
|
}),
|
||||||
|
new Feature({
|
||||||
|
geometry: new Point([x + 3, 6]),
|
||||||
|
scale: [1, -1],
|
||||||
|
anchor: [0.5, 0.5],
|
||||||
|
rotated: i,
|
||||||
|
}),
|
||||||
|
new Feature({
|
||||||
|
geometry: new Point([x + 4, 6]),
|
||||||
|
scale: [1, -1],
|
||||||
|
anchor: [0.5, 0],
|
||||||
|
rotated: i,
|
||||||
|
}),
|
||||||
|
new Feature({
|
||||||
|
geometry: new Point([x + 2, 8]),
|
||||||
|
scale: [1, 1.5],
|
||||||
|
anchor: [0.5, 0],
|
||||||
|
rotated: i,
|
||||||
|
}),
|
||||||
|
new Feature({
|
||||||
|
geometry: new Point([x + 3, 8]),
|
||||||
|
scale: [1, 1.5],
|
||||||
|
anchor: [0.5, 0.5],
|
||||||
|
rotated: i,
|
||||||
|
}),
|
||||||
|
new Feature({
|
||||||
|
geometry: new Point([x + 4, 8]),
|
||||||
|
scale: [1, 1.5],
|
||||||
|
anchor: [0.5, 1],
|
||||||
|
rotated: i,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const vectorSource = new VectorSource({
|
||||||
|
features: features,
|
||||||
|
});
|
||||||
|
|
||||||
|
const style = new Style({
|
||||||
|
image: new Icon({
|
||||||
|
src: '/data/fish.png',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const vectorLayer = new VectorLayer({
|
||||||
|
source: vectorSource,
|
||||||
|
style: function (feature) {
|
||||||
|
style.getImage().setScale(feature.get('scale'));
|
||||||
|
style.getImage().setAnchor(feature.get('anchor'));
|
||||||
|
style.getImage().setRotation((feature.get('rotated') * Math.PI) / 4);
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const map = new Map({
|
||||||
|
pixelRatio: 1,
|
||||||
|
layers: [vectorLayer],
|
||||||
|
target: 'map',
|
||||||
|
view: new View(),
|
||||||
|
});
|
||||||
|
map.getView().fit([0, 0, 11, 11]);
|
||||||
|
|
||||||
|
render();
|
||||||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
@@ -59,7 +59,7 @@ feature1.setStyle(
|
|||||||
vectorSource.addFeature(feature1);
|
vectorSource.addFeature(feature1);
|
||||||
|
|
||||||
const lineString2 = lineString1.clone();
|
const lineString2 = lineString1.clone();
|
||||||
lineString2.translate(0, 30);
|
lineString2.translate(0, 20);
|
||||||
const feature2 = new Feature({geometry: lineString2});
|
const feature2 = new Feature({geometry: lineString2});
|
||||||
feature2.setStyle(
|
feature2.setStyle(
|
||||||
new Style({
|
new Style({
|
||||||
@@ -123,7 +123,7 @@ feature4.setStyle(
|
|||||||
vectorSource.addFeature(feature4);
|
vectorSource.addFeature(feature4);
|
||||||
|
|
||||||
const lineString5 = lineString4.clone();
|
const lineString5 = lineString4.clone();
|
||||||
lineString5.translate(0, 30);
|
lineString5.translate(0, 20);
|
||||||
const feature5 = new Feature({geometry: lineString5});
|
const feature5 = new Feature({geometry: lineString5});
|
||||||
feature5.setStyle(
|
feature5.setStyle(
|
||||||
new Style({
|
new Style({
|
||||||
@@ -141,7 +141,7 @@ feature5.setStyle(
|
|||||||
vectorSource.addFeature(feature5);
|
vectorSource.addFeature(feature5);
|
||||||
|
|
||||||
const lineString6 = lineString5.clone();
|
const lineString6 = lineString5.clone();
|
||||||
lineString6.translate(0, 30);
|
lineString6.translate(0, 20);
|
||||||
const feature6 = new Feature({geometry: lineString6});
|
const feature6 = new Feature({geometry: lineString6});
|
||||||
feature6.setStyle(
|
feature6.setStyle(
|
||||||
new Style({
|
new Style({
|
||||||
@@ -160,6 +160,28 @@ feature6.setStyle(
|
|||||||
);
|
);
|
||||||
vectorSource.addFeature(feature6);
|
vectorSource.addFeature(feature6);
|
||||||
|
|
||||||
|
const lineString7 = lineString6.clone();
|
||||||
|
lineString7.translate(0, 30);
|
||||||
|
const feature7 = new Feature({geometry: lineString7});
|
||||||
|
feature7.setStyle(
|
||||||
|
new Style({
|
||||||
|
stroke: new Stroke({color: 'blue'}),
|
||||||
|
text: new Text({
|
||||||
|
text: 'Reflection',
|
||||||
|
font: 'normal 400 12px/1 Ubuntu',
|
||||||
|
scale: [2, -1],
|
||||||
|
textBaseline: 'bottom',
|
||||||
|
textAlign: 'right',
|
||||||
|
placement: 'line',
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: '#FFFF00',
|
||||||
|
width: 1,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
vectorSource.addFeature(feature7);
|
||||||
|
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
pixelRatio: 1,
|
pixelRatio: 1,
|
||||||
layers: [
|
layers: [
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 8.6 KiB |
@@ -110,15 +110,23 @@ feature.setStyle(
|
|||||||
);
|
);
|
||||||
vectorSource.addFeature(feature);
|
vectorSource.addFeature(feature);
|
||||||
|
|
||||||
// background and padding
|
// two dimensional scale
|
||||||
feature = new Feature({
|
feature = new Feature({
|
||||||
geometry: new Point([-10, 0]),
|
geometry: new Point([100, 20]),
|
||||||
});
|
});
|
||||||
feature.setStyle(
|
feature.setStyle(
|
||||||
new Style({
|
new Style({
|
||||||
text: new Text({
|
text: new Text({
|
||||||
text: 'hello',
|
text: 'mirror',
|
||||||
font: '12px Ubuntu',
|
font: '12px Ubuntu',
|
||||||
|
scale: [-1, 2],
|
||||||
|
rotateWithView: true,
|
||||||
|
fill: new Fill({
|
||||||
|
color: 'red',
|
||||||
|
}),
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: '#000',
|
||||||
|
}),
|
||||||
padding: [1, 2, 3, 5],
|
padding: [1, 2, 3, 5],
|
||||||
backgroundFill: new Fill({
|
backgroundFill: new Fill({
|
||||||
color: 'rgba(55, 55, 55, 0.25)',
|
color: 'rgba(55, 55, 55, 0.25)',
|
||||||
|
|||||||
|
After Width: | Height: | Size: 427 B |
@@ -915,11 +915,11 @@ function createNameStyleFunction(foundStyle, name) {
|
|||||||
imageSize = DEFAULT_IMAGE_STYLE_SIZE;
|
imageSize = DEFAULT_IMAGE_STYLE_SIZE;
|
||||||
}
|
}
|
||||||
if (imageSize.length == 2) {
|
if (imageSize.length == 2) {
|
||||||
const imageScale = imageStyle.getScale();
|
const imageScale = imageStyle.getScaleArray();
|
||||||
// Offset the label to be centered to the right of the icon,
|
// Offset the label to be centered to the right of the icon,
|
||||||
// if there is one.
|
// if there is one.
|
||||||
textOffset[0] = (imageScale * imageSize[0]) / 2;
|
textOffset[0] = (imageScale[0] * imageSize[0]) / 2;
|
||||||
textOffset[1] = (-imageScale * imageSize[1]) / 2;
|
textOffset[1] = (-imageScale[1] * imageSize[1]) / 2;
|
||||||
textAlign = 'left';
|
textAlign = 'left';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ import {toString} from '../transform.js';
|
|||||||
* @property {boolean} [overflow]
|
* @property {boolean} [overflow]
|
||||||
* @property {import("../style/Fill.js").default} [backgroundFill]
|
* @property {import("../style/Fill.js").default} [backgroundFill]
|
||||||
* @property {import("../style/Stroke.js").default} [backgroundStroke]
|
* @property {import("../style/Stroke.js").default} [backgroundStroke]
|
||||||
* @property {number} [scale]
|
* @property {import("../size.js").Size} [scale]
|
||||||
* @property {Array<number>} [padding]
|
* @property {Array<number>} [padding]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -410,7 +410,7 @@ export function rotateAtOffset(context, rotation, offsetX, offsetY) {
|
|||||||
* @param {number} h Height.
|
* @param {number} h Height.
|
||||||
* @param {number} x X.
|
* @param {number} x X.
|
||||||
* @param {number} y Y.
|
* @param {number} y Y.
|
||||||
* @param {number} scale Scale.
|
* @param {import("../size.js").Size} scale Scale.
|
||||||
*/
|
*/
|
||||||
export function drawImageOrLabel(
|
export function drawImageOrLabel(
|
||||||
context,
|
context,
|
||||||
@@ -437,10 +437,25 @@ export function drawImageOrLabel(
|
|||||||
if (/** @type {*} */ (labelOrImage).contextInstructions) {
|
if (/** @type {*} */ (labelOrImage).contextInstructions) {
|
||||||
// label
|
// label
|
||||||
context.translate(x, y);
|
context.translate(x, y);
|
||||||
context.scale(scale, scale);
|
context.scale(scale[0], scale[1]);
|
||||||
executeLabelInstructions(/** @type {Label} */ (labelOrImage), context);
|
executeLabelInstructions(/** @type {Label} */ (labelOrImage), context);
|
||||||
|
} else if (scale[0] < 0 || scale[1] < 0) {
|
||||||
|
// flipped image
|
||||||
|
context.translate(x, y);
|
||||||
|
context.scale(scale[0], scale[1]);
|
||||||
|
context.drawImage(
|
||||||
|
/** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */ (labelOrImage),
|
||||||
|
originX,
|
||||||
|
originY,
|
||||||
|
w,
|
||||||
|
h,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
w,
|
||||||
|
h
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// image
|
// if image not flipped translate and scale can be avoided
|
||||||
context.drawImage(
|
context.drawImage(
|
||||||
/** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */ (labelOrImage),
|
/** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */ (labelOrImage),
|
||||||
originX,
|
originX,
|
||||||
@@ -449,8 +464,8 @@ export function drawImageOrLabel(
|
|||||||
h,
|
h,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
w * scale,
|
w * scale[0],
|
||||||
h * scale
|
h * scale[1]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -187,7 +187,10 @@ class Executor {
|
|||||||
const fillState = fillKey ? this.fillStates[fillKey] : null;
|
const fillState = fillKey ? this.fillStates[fillKey] : null;
|
||||||
const textState = this.textStates[textKey];
|
const textState = this.textStates[textKey];
|
||||||
const pixelRatio = this.pixelRatio;
|
const pixelRatio = this.pixelRatio;
|
||||||
const scale = textState.scale * pixelRatio;
|
const scale = [
|
||||||
|
textState.scale[0] * pixelRatio,
|
||||||
|
textState.scale[1] * pixelRatio,
|
||||||
|
];
|
||||||
const align = TEXT_ALIGN[textState.textAlign || defaultTextAlign];
|
const align = TEXT_ALIGN[textState.textAlign || defaultTextAlign];
|
||||||
const strokeWidth =
|
const strokeWidth =
|
||||||
strokeKey && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
strokeKey && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
||||||
@@ -200,15 +203,17 @@ class Executor {
|
|||||||
const height = lineHeight * numLines;
|
const height = lineHeight * numLines;
|
||||||
const renderWidth = width + strokeWidth;
|
const renderWidth = width + strokeWidth;
|
||||||
const contextInstructions = [];
|
const contextInstructions = [];
|
||||||
|
// make canvas 2 pixels wider to account for italic text width measurement errors
|
||||||
|
const w = (renderWidth + 2) * scale[0];
|
||||||
|
const h = (height + strokeWidth) * scale[1];
|
||||||
/** @type {import("../canvas.js").Label} */
|
/** @type {import("../canvas.js").Label} */
|
||||||
const label = {
|
const label = {
|
||||||
// make canvas 2 pixels wider to account for italic text width measurement errors
|
width: w < 0 ? Math.floor(w) : Math.ceil(w),
|
||||||
width: Math.ceil((renderWidth + 2) * scale),
|
height: h < 0 ? Math.floor(h) : Math.ceil(h),
|
||||||
height: Math.ceil((height + strokeWidth) * scale),
|
|
||||||
contextInstructions: contextInstructions,
|
contextInstructions: contextInstructions,
|
||||||
};
|
};
|
||||||
if (scale != 1) {
|
if (scale[0] != 1 || scale[1] != 1) {
|
||||||
contextInstructions.push('scale', [scale, scale]);
|
contextInstructions.push('scale', scale);
|
||||||
}
|
}
|
||||||
contextInstructions.push('font', textState.font);
|
contextInstructions.push('font', textState.font);
|
||||||
if (strokeKey) {
|
if (strokeKey) {
|
||||||
@@ -310,7 +315,7 @@ class Executor {
|
|||||||
* @param {number} originX Origin X.
|
* @param {number} originX Origin X.
|
||||||
* @param {number} originY Origin Y.
|
* @param {number} originY Origin Y.
|
||||||
* @param {number} rotation Rotation.
|
* @param {number} rotation Rotation.
|
||||||
* @param {number} scale Scale.
|
* @param {import("../../size.js").Size} scale Scale.
|
||||||
* @param {boolean} snapToPixel Snap to pixel.
|
* @param {boolean} snapToPixel Snap to pixel.
|
||||||
* @param {number} width Width.
|
* @param {number} width Width.
|
||||||
* @param {Array<number>} padding Padding.
|
* @param {Array<number>} padding Padding.
|
||||||
@@ -339,8 +344,8 @@ class Executor {
|
|||||||
strokeInstruction
|
strokeInstruction
|
||||||
) {
|
) {
|
||||||
const fillStroke = fillInstruction || strokeInstruction;
|
const fillStroke = fillInstruction || strokeInstruction;
|
||||||
anchorX *= scale;
|
anchorX *= scale[0];
|
||||||
anchorY *= scale;
|
anchorY *= scale[1];
|
||||||
x -= anchorX;
|
x -= anchorX;
|
||||||
y -= anchorY;
|
y -= anchorY;
|
||||||
|
|
||||||
@@ -352,8 +357,8 @@ class Executor {
|
|||||||
height + originY > imageOrLabel.height
|
height + originY > imageOrLabel.height
|
||||||
? imageOrLabel.height - originY
|
? imageOrLabel.height - originY
|
||||||
: height;
|
: height;
|
||||||
const boxW = padding[3] + w * scale + padding[1];
|
const boxW = padding[3] + w * scale[0] + padding[1];
|
||||||
const boxH = padding[0] + h * scale + padding[2];
|
const boxH = padding[0] + h * scale[1] + padding[2];
|
||||||
const boxX = x - padding[3];
|
const boxX = x - padding[3];
|
||||||
const boxY = y - padding[0];
|
const boxY = y - padding[0];
|
||||||
|
|
||||||
@@ -399,7 +404,7 @@ class Executor {
|
|||||||
}
|
}
|
||||||
const canvas = context.canvas;
|
const canvas = context.canvas;
|
||||||
const strokePadding = strokeInstruction
|
const strokePadding = strokeInstruction
|
||||||
? (strokeInstruction[2] * scale) / 2
|
? (strokeInstruction[2] * scale[0]) / 2
|
||||||
: 0;
|
: 0;
|
||||||
const intersects =
|
const intersects =
|
||||||
tmpExtent[0] - strokePadding <= canvas.width / contextScale &&
|
tmpExtent[0] - strokePadding <= canvas.width / contextScale &&
|
||||||
@@ -586,7 +591,7 @@ class Executor {
|
|||||||
strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
||||||
|
|
||||||
// Remove the 2 pixels we added in createLabel() for the anchor
|
// Remove the 2 pixels we added in createLabel() for the anchor
|
||||||
const width = label.width / pixelRatio - 2 * textState.scale;
|
const width = label.width / pixelRatio - 2 * textState.scale[0];
|
||||||
const anchorX = align * width + 2 * (0.5 - align) * strokeWidth;
|
const anchorX = align * width + 2 * (0.5 - align) * strokeWidth;
|
||||||
const anchorY =
|
const anchorY =
|
||||||
(baseline * label.height) / pixelRatio +
|
(baseline * label.height) / pixelRatio +
|
||||||
@@ -765,7 +770,7 @@ class Executor {
|
|||||||
const originY = /** @type {number} */ (instruction[10]);
|
const originY = /** @type {number} */ (instruction[10]);
|
||||||
const rotateWithView = /** @type {boolean} */ (instruction[11]);
|
const rotateWithView = /** @type {boolean} */ (instruction[11]);
|
||||||
let rotation = /** @type {number} */ (instruction[12]);
|
let rotation = /** @type {number} */ (instruction[12]);
|
||||||
const scale = /** @type {number} */ (instruction[13]);
|
const scale = /** @type {import("../../size.js").Size} */ (instruction[13]);
|
||||||
let width = /** @type {number} */ (instruction[14]);
|
let width = /** @type {number} */ (instruction[14]);
|
||||||
|
|
||||||
if (!image && instruction.length >= 19) {
|
if (!image && instruction.length >= 19) {
|
||||||
@@ -883,11 +888,17 @@ class Executor {
|
|||||||
const strokeWidth = /** @type {number} */ (instruction[11]);
|
const strokeWidth = /** @type {number} */ (instruction[11]);
|
||||||
text = /** @type {string} */ (instruction[12]);
|
text = /** @type {string} */ (instruction[12]);
|
||||||
textKey = /** @type {string} */ (instruction[13]);
|
textKey = /** @type {string} */ (instruction[13]);
|
||||||
const pixelRatioScale = /** @type {number} */ (instruction[14]);
|
const pixelRatioScale = [
|
||||||
|
/** @type {number} */ (instruction[14]),
|
||||||
|
/** @type {number} */ (instruction[14]),
|
||||||
|
];
|
||||||
|
|
||||||
const textState = this.textStates[textKey];
|
const textState = this.textStates[textKey];
|
||||||
const font = textState.font;
|
const font = textState.font;
|
||||||
const textScale = textState.scale * measurePixelRatio;
|
const textScale = [
|
||||||
|
textState.scale[0] * measurePixelRatio,
|
||||||
|
textState.scale[1] * measurePixelRatio,
|
||||||
|
];
|
||||||
|
|
||||||
let cachedWidths;
|
let cachedWidths;
|
||||||
if (font in this.widths_) {
|
if (font in this.widths_) {
|
||||||
@@ -899,7 +910,8 @@ class Executor {
|
|||||||
|
|
||||||
const pathLength = lineStringLength(pixelCoordinates, begin, end, 2);
|
const pathLength = lineStringLength(pixelCoordinates, begin, end, 2);
|
||||||
const textLength =
|
const textLength =
|
||||||
textScale * measureAndCacheTextWidth(font, text, cachedWidths);
|
Math.abs(textScale[0]) *
|
||||||
|
measureAndCacheTextWidth(font, text, cachedWidths);
|
||||||
if (overflow || textLength <= pathLength) {
|
if (overflow || textLength <= pathLength) {
|
||||||
const textAlign = this.textStates[textKey].textAlign;
|
const textAlign = this.textStates[textKey].textAlign;
|
||||||
const startM = (pathLength - textLength) * TEXT_ALIGN[textAlign];
|
const startM = (pathLength - textLength) * TEXT_ALIGN[textAlign];
|
||||||
@@ -911,7 +923,7 @@ class Executor {
|
|||||||
text,
|
text,
|
||||||
startM,
|
startM,
|
||||||
maxAngle,
|
maxAngle,
|
||||||
textScale,
|
Math.abs(textScale[0]),
|
||||||
measureAndCacheTextWidth,
|
measureAndCacheTextWidth,
|
||||||
font,
|
font,
|
||||||
cachedWidths
|
cachedWidths
|
||||||
@@ -926,7 +938,8 @@ class Executor {
|
|||||||
anchorX = /** @type {number} */ (part[2]) + strokeWidth;
|
anchorX = /** @type {number} */ (part[2]) + strokeWidth;
|
||||||
anchorY =
|
anchorY =
|
||||||
baseline * label.height +
|
baseline * label.height +
|
||||||
(0.5 - baseline) * 2 * strokeWidth -
|
((0.5 - baseline) * 2 * strokeWidth * textScale[1]) /
|
||||||
|
textScale[0] -
|
||||||
offsetY;
|
offsetY;
|
||||||
this.replayImageOrLabel_(
|
this.replayImageOrLabel_(
|
||||||
context,
|
context,
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class CanvasImageBuilder extends CanvasBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {number|undefined}
|
* @type {import("../../size.js").Size|undefined}
|
||||||
*/
|
*/
|
||||||
this.scale_ = undefined;
|
this.scale_ = undefined;
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ class CanvasImageBuilder extends CanvasBuilder {
|
|||||||
this.originY_,
|
this.originY_,
|
||||||
this.rotateWithView_,
|
this.rotateWithView_,
|
||||||
this.rotation_,
|
this.rotation_,
|
||||||
this.scale_ * this.pixelRatio,
|
[this.scale_[0] * this.pixelRatio, this.scale_[1] * this.pixelRatio],
|
||||||
this.width_,
|
this.width_,
|
||||||
]);
|
]);
|
||||||
this.hitDetectionInstructions.push([
|
this.hitDetectionInstructions.push([
|
||||||
@@ -202,7 +202,7 @@ class CanvasImageBuilder extends CanvasBuilder {
|
|||||||
this.originY_,
|
this.originY_,
|
||||||
this.rotateWithView_,
|
this.rotateWithView_,
|
||||||
this.rotation_,
|
this.rotation_,
|
||||||
this.scale_ * this.pixelRatio,
|
[this.scale_[0] * this.pixelRatio, this.scale_[1] * this.pixelRatio],
|
||||||
this.width_,
|
this.width_,
|
||||||
]);
|
]);
|
||||||
this.hitDetectionInstructions.push([
|
this.hitDetectionInstructions.push([
|
||||||
@@ -268,7 +268,7 @@ class CanvasImageBuilder extends CanvasBuilder {
|
|||||||
this.originY_ = origin[1];
|
this.originY_ = origin[1];
|
||||||
this.rotateWithView_ = imageStyle.getRotateWithView();
|
this.rotateWithView_ = imageStyle.getRotateWithView();
|
||||||
this.rotation_ = imageStyle.getRotation();
|
this.rotation_ = imageStyle.getRotation();
|
||||||
this.scale_ = imageStyle.getScale();
|
this.scale_ = imageStyle.getScaleArray();
|
||||||
this.width_ = size[0];
|
this.width_ = size[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,9 +188,9 @@ class CanvasImmediateRenderer extends VectorContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {number}
|
* @type {import("../../size.js").Size}
|
||||||
*/
|
*/
|
||||||
this.imageScale_ = 0;
|
this.imageScale_ = [0, 0];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -230,9 +230,9 @@ class CanvasImmediateRenderer extends VectorContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {number}
|
* @type {import("../../size.js").Size}
|
||||||
*/
|
*/
|
||||||
this.textScale_ = 0;
|
this.textScale_ = [0, 0];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -297,35 +297,51 @@ class CanvasImmediateRenderer extends VectorContext {
|
|||||||
for (let i = 0, ii = pixelCoordinates.length; i < ii; i += 2) {
|
for (let i = 0, ii = pixelCoordinates.length; i < ii; i += 2) {
|
||||||
const x = pixelCoordinates[i] - this.imageAnchorX_;
|
const x = pixelCoordinates[i] - this.imageAnchorX_;
|
||||||
const y = pixelCoordinates[i + 1] - this.imageAnchorY_;
|
const y = pixelCoordinates[i + 1] - this.imageAnchorY_;
|
||||||
if (rotation !== 0 || this.imageScale_ != 1) {
|
if (
|
||||||
|
rotation !== 0 ||
|
||||||
|
this.imageScale_[0] != 1 ||
|
||||||
|
this.imageScale_[1] != 1
|
||||||
|
) {
|
||||||
const centerX = x + this.imageAnchorX_;
|
const centerX = x + this.imageAnchorX_;
|
||||||
const centerY = y + this.imageAnchorY_;
|
const centerY = y + this.imageAnchorY_;
|
||||||
composeTransform(
|
composeTransform(
|
||||||
localTransform,
|
localTransform,
|
||||||
centerX,
|
centerX,
|
||||||
centerY,
|
centerY,
|
||||||
this.imageScale_,
|
1,
|
||||||
this.imageScale_,
|
1,
|
||||||
rotation,
|
rotation,
|
||||||
-centerX,
|
-centerX,
|
||||||
-centerY
|
-centerY
|
||||||
);
|
);
|
||||||
context.setTransform.apply(context, localTransform);
|
context.setTransform.apply(context, localTransform);
|
||||||
|
context.translate(centerX, centerY);
|
||||||
|
context.scale(this.imageScale_[0], this.imageScale_[1]);
|
||||||
|
context.drawImage(
|
||||||
|
this.image_,
|
||||||
|
this.imageOriginX_,
|
||||||
|
this.imageOriginY_,
|
||||||
|
this.imageWidth_,
|
||||||
|
this.imageHeight_,
|
||||||
|
-this.imageAnchorX_,
|
||||||
|
-this.imageAnchorY_,
|
||||||
|
this.imageWidth_,
|
||||||
|
this.imageHeight_
|
||||||
|
);
|
||||||
|
context.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
|
} else {
|
||||||
|
context.drawImage(
|
||||||
|
this.image_,
|
||||||
|
this.imageOriginX_,
|
||||||
|
this.imageOriginY_,
|
||||||
|
this.imageWidth_,
|
||||||
|
this.imageHeight_,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
this.imageWidth_,
|
||||||
|
this.imageHeight_
|
||||||
|
);
|
||||||
}
|
}
|
||||||
context.drawImage(
|
|
||||||
this.image_,
|
|
||||||
this.imageOriginX_,
|
|
||||||
this.imageOriginY_,
|
|
||||||
this.imageWidth_,
|
|
||||||
this.imageHeight_,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
this.imageWidth_,
|
|
||||||
this.imageHeight_
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (rotation !== 0 || this.imageScale_ != 1) {
|
|
||||||
context.setTransform(1, 0, 0, 1, 0, 0);
|
|
||||||
}
|
}
|
||||||
if (this.imageOpacity_ != 1) {
|
if (this.imageOpacity_ != 1) {
|
||||||
context.globalAlpha = alpha;
|
context.globalAlpha = alpha;
|
||||||
@@ -366,28 +382,39 @@ class CanvasImmediateRenderer extends VectorContext {
|
|||||||
for (; offset < end; offset += stride) {
|
for (; offset < end; offset += stride) {
|
||||||
const x = pixelCoordinates[offset] + this.textOffsetX_;
|
const x = pixelCoordinates[offset] + this.textOffsetX_;
|
||||||
const y = pixelCoordinates[offset + 1] + this.textOffsetY_;
|
const y = pixelCoordinates[offset + 1] + this.textOffsetY_;
|
||||||
if (rotation !== 0 || this.textScale_ != 1) {
|
if (
|
||||||
|
rotation !== 0 ||
|
||||||
|
this.textScale_[0] != 1 ||
|
||||||
|
this.textScale_[1] != 1
|
||||||
|
) {
|
||||||
const localTransform = composeTransform(
|
const localTransform = composeTransform(
|
||||||
this.tmpLocalTransform_,
|
this.tmpLocalTransform_,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
this.textScale_,
|
1,
|
||||||
this.textScale_,
|
1,
|
||||||
rotation,
|
rotation,
|
||||||
-x,
|
-x,
|
||||||
-y
|
-y
|
||||||
);
|
);
|
||||||
context.setTransform.apply(context, localTransform);
|
context.setTransform.apply(context, localTransform);
|
||||||
|
context.translate(x, y);
|
||||||
|
context.scale(this.textScale_[0], this.textScale_[1]);
|
||||||
|
if (this.textStrokeState_) {
|
||||||
|
context.strokeText(this.text_, 0, 0);
|
||||||
|
}
|
||||||
|
if (this.textFillState_) {
|
||||||
|
context.fillText(this.text_, 0, 0);
|
||||||
|
}
|
||||||
|
context.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
|
} else {
|
||||||
|
if (this.textStrokeState_) {
|
||||||
|
context.strokeText(this.text_, x, y);
|
||||||
|
}
|
||||||
|
if (this.textFillState_) {
|
||||||
|
context.fillText(this.text_, x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.textStrokeState_) {
|
|
||||||
context.strokeText(this.text_, x, y);
|
|
||||||
}
|
|
||||||
if (this.textFillState_) {
|
|
||||||
context.fillText(this.text_, x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rotation !== 0 || this.textScale_ != 1) {
|
|
||||||
context.setTransform(1, 0, 0, 1, 0, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -994,22 +1021,30 @@ class CanvasImmediateRenderer extends VectorContext {
|
|||||||
if (!imageStyle) {
|
if (!imageStyle) {
|
||||||
this.image_ = null;
|
this.image_ = null;
|
||||||
} else {
|
} else {
|
||||||
const imageAnchor = imageStyle.getAnchor();
|
|
||||||
// FIXME pixel ratio
|
|
||||||
const imageImage = imageStyle.getImage(1);
|
|
||||||
const imageOrigin = imageStyle.getOrigin();
|
|
||||||
const imageSize = imageStyle.getSize();
|
const imageSize = imageStyle.getSize();
|
||||||
this.imageAnchorX_ = imageAnchor[0];
|
if (!imageSize) {
|
||||||
this.imageAnchorY_ = imageAnchor[1];
|
this.image_ = null;
|
||||||
this.imageHeight_ = imageSize[1];
|
} else {
|
||||||
this.image_ = imageImage;
|
const imageAnchor = imageStyle.getAnchor();
|
||||||
this.imageOpacity_ = imageStyle.getOpacity();
|
// FIXME pixel ratio
|
||||||
this.imageOriginX_ = imageOrigin[0];
|
const imageImage = imageStyle.getImage(1);
|
||||||
this.imageOriginY_ = imageOrigin[1];
|
const imageOrigin = imageStyle.getOrigin();
|
||||||
this.imageRotateWithView_ = imageStyle.getRotateWithView();
|
const imageScale = imageStyle.getScaleArray();
|
||||||
this.imageRotation_ = imageStyle.getRotation();
|
this.imageAnchorX_ = imageAnchor[0];
|
||||||
this.imageScale_ = imageStyle.getScale() * this.pixelRatio_;
|
this.imageAnchorY_ = imageAnchor[1];
|
||||||
this.imageWidth_ = imageSize[0];
|
this.imageHeight_ = imageSize[1];
|
||||||
|
this.image_ = imageImage;
|
||||||
|
this.imageOpacity_ = imageStyle.getOpacity();
|
||||||
|
this.imageOriginX_ = imageOrigin[0];
|
||||||
|
this.imageOriginY_ = imageOrigin[1];
|
||||||
|
this.imageRotateWithView_ = imageStyle.getRotateWithView();
|
||||||
|
this.imageRotation_ = imageStyle.getRotation();
|
||||||
|
this.imageScale_ = [
|
||||||
|
this.pixelRatio_ * imageScale[0],
|
||||||
|
this.pixelRatio_ * imageScale[1],
|
||||||
|
];
|
||||||
|
this.imageWidth_ = imageSize[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1078,7 +1113,7 @@ class CanvasImmediateRenderer extends VectorContext {
|
|||||||
const textOffsetY = textStyle.getOffsetY();
|
const textOffsetY = textStyle.getOffsetY();
|
||||||
const textRotateWithView = textStyle.getRotateWithView();
|
const textRotateWithView = textStyle.getRotateWithView();
|
||||||
const textRotation = textStyle.getRotation();
|
const textRotation = textStyle.getRotation();
|
||||||
const textScale = textStyle.getScale();
|
const textScale = textStyle.getScaleArray();
|
||||||
const textText = textStyle.getText();
|
const textText = textStyle.getText();
|
||||||
const textTextAlign = textStyle.getTextAlign();
|
const textTextAlign = textStyle.getTextAlign();
|
||||||
const textTextBaseline = textStyle.getTextBaseline();
|
const textTextBaseline = textStyle.getTextBaseline();
|
||||||
@@ -1099,8 +1134,10 @@ class CanvasImmediateRenderer extends VectorContext {
|
|||||||
this.textRotateWithView_ =
|
this.textRotateWithView_ =
|
||||||
textRotateWithView !== undefined ? textRotateWithView : false;
|
textRotateWithView !== undefined ? textRotateWithView : false;
|
||||||
this.textRotation_ = textRotation !== undefined ? textRotation : 0;
|
this.textRotation_ = textRotation !== undefined ? textRotation : 0;
|
||||||
this.textScale_ =
|
this.textScale_ = [
|
||||||
this.pixelRatio_ * (textScale !== undefined ? textScale : 1);
|
this.pixelRatio_ * textScale[0],
|
||||||
|
this.pixelRatio_ * textScale[1],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -303,6 +303,27 @@ class CanvasTextBuilder extends CanvasBuilder {
|
|||||||
|
|
||||||
this.beginGeometry(geometry, feature);
|
this.beginGeometry(geometry, feature);
|
||||||
|
|
||||||
|
// adjust padding for negative scale
|
||||||
|
let padding = textState.padding;
|
||||||
|
if (
|
||||||
|
padding != defaultPadding &&
|
||||||
|
(textState.scale[0] < 0 || textState.scale[1] < 0)
|
||||||
|
) {
|
||||||
|
let p0 = textState.padding[0];
|
||||||
|
let p1 = textState.padding[1];
|
||||||
|
let p2 = textState.padding[2];
|
||||||
|
let p3 = textState.padding[3];
|
||||||
|
if (textState.scale[0] < 0) {
|
||||||
|
p1 = -p1;
|
||||||
|
p3 = -p3;
|
||||||
|
}
|
||||||
|
if (textState.scale[1] < 0) {
|
||||||
|
p0 = -p0;
|
||||||
|
p2 = -p2;
|
||||||
|
}
|
||||||
|
padding = [p0, p1, p2, p3];
|
||||||
|
}
|
||||||
|
|
||||||
// The image is unknown at this stage so we pass null; it will be computed at render time.
|
// The image is unknown at this stage so we pass null; it will be computed at render time.
|
||||||
// For clarity, we pass NaN for offsetX, offsetY, width and height, which will be computed at
|
// For clarity, we pass NaN for offsetX, offsetY, width and height, which will be computed at
|
||||||
// render time.
|
// render time.
|
||||||
@@ -321,11 +342,11 @@ class CanvasTextBuilder extends CanvasBuilder {
|
|||||||
0,
|
0,
|
||||||
this.textRotateWithView_,
|
this.textRotateWithView_,
|
||||||
this.textRotation_,
|
this.textRotation_,
|
||||||
1,
|
[1, 1],
|
||||||
NaN,
|
NaN,
|
||||||
textState.padding == defaultPadding
|
padding == defaultPadding
|
||||||
? defaultPadding
|
? defaultPadding
|
||||||
: textState.padding.map(function (p) {
|
: padding.map(function (p) {
|
||||||
return p * pixelRatio;
|
return p * pixelRatio;
|
||||||
}),
|
}),
|
||||||
!!textState.backgroundFill,
|
!!textState.backgroundFill,
|
||||||
@@ -338,6 +359,7 @@ class CanvasTextBuilder extends CanvasBuilder {
|
|||||||
this.textOffsetY_,
|
this.textOffsetY_,
|
||||||
geometryWidths,
|
geometryWidths,
|
||||||
]);
|
]);
|
||||||
|
const scale = 1 / pixelRatio;
|
||||||
this.hitDetectionInstructions.push([
|
this.hitDetectionInstructions.push([
|
||||||
CanvasInstruction.DRAW_IMAGE,
|
CanvasInstruction.DRAW_IMAGE,
|
||||||
begin,
|
begin,
|
||||||
@@ -352,9 +374,9 @@ class CanvasTextBuilder extends CanvasBuilder {
|
|||||||
0,
|
0,
|
||||||
this.textRotateWithView_,
|
this.textRotateWithView_,
|
||||||
this.textRotation_,
|
this.textRotation_,
|
||||||
1 / this.pixelRatio,
|
[scale, scale],
|
||||||
NaN,
|
NaN,
|
||||||
textState.padding,
|
padding,
|
||||||
!!textState.backgroundFill,
|
!!textState.backgroundFill,
|
||||||
!!textState.backgroundStroke,
|
!!textState.backgroundStroke,
|
||||||
this.text_,
|
this.text_,
|
||||||
@@ -431,9 +453,8 @@ class CanvasTextBuilder extends CanvasBuilder {
|
|||||||
|
|
||||||
const offsetY = this.textOffsetY_ * pixelRatio;
|
const offsetY = this.textOffsetY_ * pixelRatio;
|
||||||
const text = this.text_;
|
const text = this.text_;
|
||||||
const textScale = textState.scale;
|
|
||||||
const strokeWidth = strokeState
|
const strokeWidth = strokeState
|
||||||
? (strokeState.lineWidth * textScale) / 2
|
? (strokeState.lineWidth * Math.abs(textState.scale[0])) / 2
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
this.instructions.push([
|
this.instructions.push([
|
||||||
@@ -529,7 +550,7 @@ class CanvasTextBuilder extends CanvasBuilder {
|
|||||||
textState = this.textState_;
|
textState = this.textState_;
|
||||||
const font = textStyle.getFont() || defaultFont;
|
const font = textStyle.getFont() || defaultFont;
|
||||||
registerFont(font);
|
registerFont(font);
|
||||||
const textScale = textStyle.getScale();
|
const textScale = textStyle.getScaleArray();
|
||||||
textState.overflow = textStyle.getOverflow();
|
textState.overflow = textStyle.getOverflow();
|
||||||
textState.font = font;
|
textState.font = font;
|
||||||
textState.maxAngle = textStyle.getMaxAngle();
|
textState.maxAngle = textStyle.getMaxAngle();
|
||||||
@@ -540,7 +561,7 @@ class CanvasTextBuilder extends CanvasBuilder {
|
|||||||
textState.backgroundFill = textStyle.getBackgroundFill();
|
textState.backgroundFill = textStyle.getBackgroundFill();
|
||||||
textState.backgroundStroke = textStyle.getBackgroundStroke();
|
textState.backgroundStroke = textStyle.getBackgroundStroke();
|
||||||
textState.padding = textStyle.getPadding() || defaultPadding;
|
textState.padding = textStyle.getPadding() || defaultPadding;
|
||||||
textState.scale = textScale === undefined ? 1 : textScale;
|
textState.scale = textScale === undefined ? [1, 1] : textScale;
|
||||||
|
|
||||||
const textOffsetX = textStyle.getOffsetX();
|
const textOffsetX = textStyle.getOffsetX();
|
||||||
const textOffsetY = textStyle.getOffsetY();
|
const textOffsetY = textStyle.getOffsetY();
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import {getUid} from '../util.js';
|
|||||||
* @property {import("./IconOrigin.js").default} [offsetOrigin='top-left'] Origin of the offset: `bottom-left`, `bottom-right`,
|
* @property {import("./IconOrigin.js").default} [offsetOrigin='top-left'] Origin of the offset: `bottom-left`, `bottom-right`,
|
||||||
* `top-left` or `top-right`.
|
* `top-left` or `top-right`.
|
||||||
* @property {number} [opacity=1] Opacity of the icon.
|
* @property {number} [opacity=1] Opacity of the icon.
|
||||||
* @property {number} [scale=1] Scale.
|
* @property {number|import("../size.js").Size} [scale=1] Scale.
|
||||||
* @property {boolean} [rotateWithView=false] Whether to rotate the icon with the view.
|
* @property {boolean} [rotateWithView=false] Whether to rotate the icon with the view.
|
||||||
* @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).
|
* @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).
|
||||||
* @property {import("../size.js").Size} [size] Icon size in pixel. Can be used together with `offset` to define the
|
* @property {import("../size.js").Size} [size] Icon size in pixel. Can be used together with `offset` to define the
|
||||||
@@ -69,7 +69,7 @@ class Icon extends ImageStyle {
|
|||||||
const rotation = options.rotation !== undefined ? options.rotation : 0;
|
const rotation = options.rotation !== undefined ? options.rotation : 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {number}
|
* @type {number|import("../size.js").Size}
|
||||||
*/
|
*/
|
||||||
const scale = options.scale !== undefined ? options.scale : 1;
|
const scale = options.scale !== undefined ? options.scale : 1;
|
||||||
|
|
||||||
@@ -215,6 +215,7 @@ class Icon extends ImageStyle {
|
|||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
clone() {
|
clone() {
|
||||||
|
const scale = this.getScale();
|
||||||
return new Icon({
|
return new Icon({
|
||||||
anchor: this.anchor_.slice(),
|
anchor: this.anchor_.slice(),
|
||||||
anchorOrigin: this.anchorOrigin_,
|
anchorOrigin: this.anchorOrigin_,
|
||||||
@@ -230,7 +231,7 @@ class Icon extends ImageStyle {
|
|||||||
offsetOrigin: this.offsetOrigin_,
|
offsetOrigin: this.offsetOrigin_,
|
||||||
size: this.size_ !== null ? this.size_.slice() : undefined,
|
size: this.size_ !== null ? this.size_.slice() : undefined,
|
||||||
opacity: this.getOpacity(),
|
opacity: this.getOpacity(),
|
||||||
scale: this.getScale(),
|
scale: Array.isArray(scale) ? scale.slice() : scale,
|
||||||
rotation: this.getRotation(),
|
rotation: this.getRotation(),
|
||||||
rotateWithView: this.getRotateWithView(),
|
rotateWithView: this.getRotateWithView(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,13 +2,14 @@
|
|||||||
* @module ol/style/Image
|
* @module ol/style/Image
|
||||||
*/
|
*/
|
||||||
import {abstract} from '../util.js';
|
import {abstract} from '../util.js';
|
||||||
|
import {toSize} from '../size.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} Options
|
* @typedef {Object} Options
|
||||||
* @property {number} opacity
|
* @property {number} opacity
|
||||||
* @property {boolean} rotateWithView
|
* @property {boolean} rotateWithView
|
||||||
* @property {number} rotation
|
* @property {number} rotation
|
||||||
* @property {number} scale
|
* @property {number|import("../size.js").Size} scale
|
||||||
* @property {Array<number>} displacement
|
* @property {Array<number>} displacement
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -45,10 +46,16 @@ class ImageStyle {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {number}
|
* @type {number|import("../size.js").Size}
|
||||||
*/
|
*/
|
||||||
this.scale_ = options.scale;
|
this.scale_ = options.scale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {import("../size.js").Size}
|
||||||
|
*/
|
||||||
|
this.scaleArray_ = toSize(options.scale);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {Array<number>}
|
* @type {Array<number>}
|
||||||
@@ -62,9 +69,10 @@ class ImageStyle {
|
|||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
clone() {
|
clone() {
|
||||||
|
const scale = this.getScale();
|
||||||
return new ImageStyle({
|
return new ImageStyle({
|
||||||
opacity: this.getOpacity(),
|
opacity: this.getOpacity(),
|
||||||
scale: this.getScale(),
|
scale: Array.isArray(scale) ? scale.slice() : scale,
|
||||||
rotation: this.getRotation(),
|
rotation: this.getRotation(),
|
||||||
rotateWithView: this.getRotateWithView(),
|
rotateWithView: this.getRotateWithView(),
|
||||||
displacement: this.getDisplacement().slice(),
|
displacement: this.getDisplacement().slice(),
|
||||||
@@ -100,13 +108,21 @@ class ImageStyle {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the symbolizer scale.
|
* Get the symbolizer scale.
|
||||||
* @return {number} Scale.
|
* @return {number|import("../size.js").Size} Scale.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
getScale() {
|
getScale() {
|
||||||
return this.scale_;
|
return this.scale_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the symbolizer scale array.
|
||||||
|
* @return {import("../size.js").Size} Scale array.
|
||||||
|
*/
|
||||||
|
getScaleArray() {
|
||||||
|
return this.scaleArray_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the displacement of the shape
|
* Get the displacement of the shape
|
||||||
* @return {Array<number>} Shape's center displacement
|
* @return {Array<number>} Shape's center displacement
|
||||||
@@ -219,11 +235,12 @@ class ImageStyle {
|
|||||||
/**
|
/**
|
||||||
* Set the scale.
|
* Set the scale.
|
||||||
*
|
*
|
||||||
* @param {number} scale Scale.
|
* @param {number|import("../size.js").Size} scale Scale.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
setScale(scale) {
|
setScale(scale) {
|
||||||
this.scale_ = scale;
|
this.scale_ = scale;
|
||||||
|
this.scaleArray_ = toSize(scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
import Fill from './Fill.js';
|
import Fill from './Fill.js';
|
||||||
import TextPlacement from './TextPlacement.js';
|
import TextPlacement from './TextPlacement.js';
|
||||||
|
import {toSize} from '../size.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default fill color to use if no fill was set at construction time; a
|
* The default fill color to use if no fill was set at construction time; a
|
||||||
@@ -23,7 +24,7 @@ const DEFAULT_FILL_COLOR = '#333';
|
|||||||
* @property {boolean} [overflow=false] For polygon labels or when `placement` is set to `'line'`, allow text to exceed
|
* @property {boolean} [overflow=false] For polygon labels or when `placement` is set to `'line'`, allow text to exceed
|
||||||
* the width of the polygon at the label position or the length of the path that it follows.
|
* the width of the polygon at the label position or the length of the path that it follows.
|
||||||
* @property {import("./TextPlacement.js").default|string} [placement='point'] Text placement.
|
* @property {import("./TextPlacement.js").default|string} [placement='point'] Text placement.
|
||||||
* @property {number} [scale] Scale.
|
* @property {number|import("../size.js").Size} [scale] Scale.
|
||||||
* @property {boolean} [rotateWithView=false] Whether to rotate the text with the view.
|
* @property {boolean} [rotateWithView=false] Whether to rotate the text with the view.
|
||||||
* @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).
|
* @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).
|
||||||
* @property {string} [text] Text content.
|
* @property {string} [text] Text content.
|
||||||
@@ -74,10 +75,16 @@ class Text {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {number|undefined}
|
* @type {number|import("../size.js").Size|undefined}
|
||||||
*/
|
*/
|
||||||
this.scale_ = options.scale;
|
this.scale_ = options.scale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {import("../size.js").Size}
|
||||||
|
*/
|
||||||
|
this.scaleArray_ = toSize(options.scale !== undefined ? options.scale : 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {string|undefined}
|
* @type {string|undefined}
|
||||||
@@ -172,6 +179,7 @@ class Text {
|
|||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
clone() {
|
clone() {
|
||||||
|
const scale = this.getScale();
|
||||||
return new Text({
|
return new Text({
|
||||||
font: this.getFont(),
|
font: this.getFont(),
|
||||||
placement: this.getPlacement(),
|
placement: this.getPlacement(),
|
||||||
@@ -179,7 +187,7 @@ class Text {
|
|||||||
overflow: this.getOverflow(),
|
overflow: this.getOverflow(),
|
||||||
rotation: this.getRotation(),
|
rotation: this.getRotation(),
|
||||||
rotateWithView: this.getRotateWithView(),
|
rotateWithView: this.getRotateWithView(),
|
||||||
scale: this.getScale(),
|
scale: Array.isArray(scale) ? scale.slice() : scale,
|
||||||
text: this.getText(),
|
text: this.getText(),
|
||||||
textAlign: this.getTextAlign(),
|
textAlign: this.getTextAlign(),
|
||||||
textBaseline: this.getTextBaseline(),
|
textBaseline: this.getTextBaseline(),
|
||||||
@@ -280,13 +288,21 @@ class Text {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the text scale.
|
* Get the text scale.
|
||||||
* @return {number|undefined} Scale.
|
* @return {number|import("../size.js").Size|undefined} Scale.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
getScale() {
|
getScale() {
|
||||||
return this.scale_;
|
return this.scale_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the symbolizer scale array.
|
||||||
|
* @return {import("../size.js").Size} Scale array.
|
||||||
|
*/
|
||||||
|
getScaleArray() {
|
||||||
|
return this.scaleArray_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the stroke style for the text.
|
* Get the stroke style for the text.
|
||||||
* @return {import("./Stroke.js").default} Stroke style.
|
* @return {import("./Stroke.js").default} Stroke style.
|
||||||
@@ -443,11 +459,12 @@ class Text {
|
|||||||
/**
|
/**
|
||||||
* Set the scale.
|
* Set the scale.
|
||||||
*
|
*
|
||||||
* @param {number|undefined} scale Scale.
|
* @param {number|import("../size.js").Size|undefined} scale Scale.
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
setScale(scale) {
|
setScale(scale) {
|
||||||
this.scale_ = scale;
|
this.scale_ = scale;
|
||||||
|
this.scaleArray_ = toSize(scale !== undefined ? scale : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||