Update Google default icon hotspot anchors

Update Google default icon hotspot anchors
Correct icon scaling
Include icon anchor in textOffset calculation
This commit is contained in:
mike-000
2021-09-04 15:29:57 +01:00
parent d7af546ad3
commit c76e78d0b3
+71 -28
View File
@@ -9,6 +9,7 @@ import GeometryType from '../geom/GeometryType.js';
import Icon from '../style/Icon.js'; import Icon from '../style/Icon.js';
import IconAnchorUnits from '../style/IconAnchorUnits.js'; import IconAnchorUnits from '../style/IconAnchorUnits.js';
import IconOrigin from '../style/IconOrigin.js'; import IconOrigin from '../style/IconOrigin.js';
import ImageState from '../ImageState.js';
import LineString from '../geom/LineString.js'; import LineString from '../geom/LineString.js';
import MultiLineString from '../geom/MultiLineString.js'; import MultiLineString from '../geom/MultiLineString.js';
import MultiPoint from '../geom/MultiPoint.js'; import MultiPoint from '../geom/MultiPoint.js';
@@ -231,11 +232,6 @@ let DEFAULT_IMAGE_STYLE_SIZE;
*/ */
let DEFAULT_IMAGE_STYLE_SRC; let DEFAULT_IMAGE_STYLE_SRC;
/**
* @type {number}
*/
let DEFAULT_IMAGE_SCALE_MULTIPLIER;
/** /**
* @type {import("../style/Image.js").default} * @type {import("../style/Image.js").default}
*/ */
@@ -311,6 +307,15 @@ export function getDefaultStyleArray() {
return DEFAULT_STYLE_ARRAY; return DEFAULT_STYLE_ARRAY;
} }
/**
* Function that returns the scale needed to normalize an icon image to 32 pixels.
* @param {import("../size.js").Size} size Image size.
* @return {number} Scale.
*/
function resizeScaleFunction(size) {
return 32 / Math.min(size[0], size[1]);
}
function createStyleDefaults() { function createStyleDefaults() {
DEFAULT_COLOR = [255, 255, 255, 1]; DEFAULT_COLOR = [255, 255, 255, 1];
@@ -318,7 +323,7 @@ function createStyleDefaults() {
color: DEFAULT_COLOR, color: DEFAULT_COLOR,
}); });
DEFAULT_IMAGE_STYLE_ANCHOR = [20, 2]; // FIXME maybe [8, 32] ? DEFAULT_IMAGE_STYLE_ANCHOR = [20, 2];
DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS = IconAnchorUnits.PIXELS; DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS = IconAnchorUnits.PIXELS;
@@ -329,8 +334,6 @@ function createStyleDefaults() {
DEFAULT_IMAGE_STYLE_SRC = DEFAULT_IMAGE_STYLE_SRC =
'https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png'; 'https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png';
DEFAULT_IMAGE_SCALE_MULTIPLIER = 0.5;
DEFAULT_IMAGE_STYLE = new Icon({ DEFAULT_IMAGE_STYLE = new Icon({
anchor: DEFAULT_IMAGE_STYLE_ANCHOR, anchor: DEFAULT_IMAGE_STYLE_ANCHOR,
anchorOrigin: IconOrigin.BOTTOM_LEFT, anchorOrigin: IconOrigin.BOTTOM_LEFT,
@@ -338,7 +341,7 @@ function createStyleDefaults() {
anchorYUnits: DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS, anchorYUnits: DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS,
crossOrigin: 'anonymous', crossOrigin: 'anonymous',
rotation: 0, rotation: 0,
scale: DEFAULT_IMAGE_SCALE_MULTIPLIER, scale: resizeScaleFunction(DEFAULT_IMAGE_STYLE_SIZE),
size: DEFAULT_IMAGE_STYLE_SIZE, size: DEFAULT_IMAGE_STYLE_SIZE,
src: DEFAULT_IMAGE_STYLE_SRC, src: DEFAULT_IMAGE_STYLE_SRC,
}); });
@@ -939,16 +942,14 @@ function createNameStyleFunction(foundStyle, name) {
let textAlign = 'start'; let textAlign = 'start';
const imageStyle = foundStyle.getImage(); const imageStyle = foundStyle.getImage();
if (imageStyle) { if (imageStyle) {
let imageSize = imageStyle.getImageSize(); const imageSize = imageStyle.getSize();
if (imageSize === null) { if (imageSize && imageSize.length == 2) {
imageSize = DEFAULT_IMAGE_STYLE_SIZE;
}
if (imageSize.length == 2) {
const imageScale = imageStyle.getScaleArray(); const imageScale = imageStyle.getScaleArray();
const anchor = imageStyle.getAnchor();
// 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[0] * imageSize[0]) / 2; textOffset[0] = imageScale[0] * (imageSize[0] - anchor[0]);
textOffset[1] = (-imageScale[1] * imageSize[1]) / 2; textOffset[1] = imageScale[1] * (imageSize[1] / 2 - anchor[1]);
textAlign = 'left'; textAlign = 'left';
} }
} }
@@ -1276,14 +1277,21 @@ function iconStyleParser(node, objectStack) {
anchorXUnits = hotSpot.xunits; anchorXUnits = hotSpot.xunits;
anchorYUnits = hotSpot.yunits; anchorYUnits = hotSpot.yunits;
anchorOrigin = hotSpot.origin; anchorOrigin = hotSpot.origin;
} else if (src === DEFAULT_IMAGE_STYLE_SRC) {
anchor = DEFAULT_IMAGE_STYLE_ANCHOR;
anchorXUnits = DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS;
anchorYUnits = DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS;
} else if (/^http:\/\/maps\.(?:google|gstatic)\.com\//.test(src)) { } else if (/^http:\/\/maps\.(?:google|gstatic)\.com\//.test(src)) {
anchor = [0.5, 0]; // Google hotspots from https://kml4earth.appspot.com/icons.html#notes
anchorXUnits = IconAnchorUnits.FRACTION; if (/pushpin/.test(src)) {
anchorYUnits = IconAnchorUnits.FRACTION; anchor = DEFAULT_IMAGE_STYLE_ANCHOR;
anchorXUnits = DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS;
anchorYUnits = DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS;
} else if (/arrow-reverse/.test(src)) {
anchor = [54, 42];
anchorXUnits = DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS;
anchorYUnits = DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS;
} else if (/paddle/.test(src)) {
anchor = [32, 1];
anchorXUnits = DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS;
anchorYUnits = DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS;
}
} }
let offset; let offset;
@@ -1306,16 +1314,13 @@ function iconStyleParser(node, objectStack) {
rotation = toRadians(heading); rotation = toRadians(heading);
} }
let scale = /** @type {number|undefined} */ (object['scale']); const scale = /** @type {number|undefined} */ (object['scale']);
const color = /** @type {Array<number>|undefined} */ (object['color']); const color = /** @type {Array<number>|undefined} */ (object['color']);
if (drawIcon) { if (drawIcon) {
if (src == DEFAULT_IMAGE_STYLE_SRC) { if (src == DEFAULT_IMAGE_STYLE_SRC) {
size = DEFAULT_IMAGE_STYLE_SIZE; size = DEFAULT_IMAGE_STYLE_SIZE;
if (scale === undefined) {
scale = DEFAULT_IMAGE_SCALE_MULTIPLIER;
}
} }
const imageStyle = new Icon({ const imageStyle = new Icon({
@@ -1332,6 +1337,36 @@ function iconStyleParser(node, objectStack) {
src: this.iconUrlFunction_(src), src: this.iconUrlFunction_(src),
color: color, color: color,
}); });
const imageSize = imageStyle.getSize();
if (imageSize === null) {
const imageState = imageStyle.getImageState();
if (imageState === ImageState.IDLE || imageState === ImageState.LOADING) {
const listener = function () {
const imageState = imageStyle.getImageState();
if (
!(
imageState === ImageState.IDLE ||
imageState === ImageState.LOADING
)
) {
const imageSize = imageStyle.getSize();
if (imageSize && imageSize.length == 2) {
const resizeScale = resizeScaleFunction(imageSize);
imageStyle.setScale(scale * resizeScale);
}
imageStyle.unlistenImageChange(listener);
}
};
imageStyle.listenImageChange(listener);
if (imageState === ImageState.IDLE) {
imageStyle.load();
}
}
} else if (imageSize.length == 2) {
const resizeScale = resizeScaleFunction(imageSize);
imageStyle.setScale(scale * resizeScale);
}
styleObject['imageStyle'] = imageStyle; styleObject['imageStyle'] = imageStyle;
} else { } else {
// handle the case when we explicitly want to draw no icon. // handle the case when we explicitly want to draw no icon.
@@ -2617,7 +2652,15 @@ function writeIconStyle(node, style, objectStack) {
properties['Icon'] = iconProperties; properties['Icon'] = iconProperties;
const scale = style.getScale(); let scale = style.getScaleArray()[0];
let imageSize = size;
if (imageSize === null) {
imageSize = DEFAULT_IMAGE_STYLE_SIZE;
}
if (imageSize.length == 2) {
const resizeScale = resizeScaleFunction(imageSize);
scale = scale / resizeScale;
}
if (scale !== 1) { if (scale !== 1) {
properties['scale'] = scale; properties['scale'] = scale;
} }