Make code prettier
This updates ESLint and our shared eslint-config-openlayers to use Prettier. Most formatting changes were automatically applied with this:
npm run lint -- --fix
A few manual changes were required:
* In `examples/offscreen-canvas.js`, the `//eslint-disable-line` comment needed to be moved to the appropriate line to disable the error about the `'worker-loader!./offscreen-canvas.worker.js'` import.
* In `examples/webpack/exapmle-builder.js`, spaces could not be added after a couple `function`s for some reason. While editing this, I reworked `ExampleBuilder` to be a class.
* In `src/ol/format/WMSGetFeatureInfo.js`, the `// @ts-ignore` comment needed to be moved down one line so it applied to the `parsersNS` argument.
This commit is contained in:
@@ -43,7 +43,6 @@ class RenderBox extends Disposable {
|
||||
* @type {import("../pixel.js").Pixel}
|
||||
*/
|
||||
this.endPixel_ = null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,9 +105,12 @@ class RenderBox extends Disposable {
|
||||
startPixel,
|
||||
[startPixel[0], endPixel[1]],
|
||||
endPixel,
|
||||
[endPixel[0], startPixel[1]]
|
||||
[endPixel[0], startPixel[1]],
|
||||
];
|
||||
const coordinates = pixels.map(this.map_.getCoordinateFromPixelInternal, this.map_);
|
||||
const coordinates = pixels.map(
|
||||
this.map_.getCoordinateFromPixelInternal,
|
||||
this.map_
|
||||
);
|
||||
// close the polygon
|
||||
coordinates[4] = coordinates[0].slice();
|
||||
if (!this.geometry_) {
|
||||
@@ -126,5 +128,4 @@ class RenderBox extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default RenderBox;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
import Event from '../events/Event.js';
|
||||
|
||||
class RenderEvent extends Event {
|
||||
|
||||
/**
|
||||
* @param {import("./EventType.js").default} type Type.
|
||||
* @param {import("../transform.js").Transform=} opt_inversePixelTransform Transform for
|
||||
@@ -14,7 +13,6 @@ class RenderEvent extends Event {
|
||||
* @param {?CanvasRenderingContext2D=} opt_context Context.
|
||||
*/
|
||||
constructor(type, opt_inversePixelTransform, opt_frameState, opt_context) {
|
||||
|
||||
super(type);
|
||||
|
||||
/**
|
||||
@@ -39,9 +37,7 @@ class RenderEvent extends Event {
|
||||
* @api
|
||||
*/
|
||||
this.context = opt_context;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default RenderEvent;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
* @enum {string}
|
||||
*/
|
||||
export default {
|
||||
|
||||
/**
|
||||
* Triggered before a layer is rendered.
|
||||
* @event module:ol/render/Event~RenderEvent#prerender
|
||||
@@ -44,6 +43,5 @@ export default {
|
||||
* @event module:ol/render/Event~RenderEvent#rendercomplete
|
||||
* @api
|
||||
*/
|
||||
RENDERCOMPLETE: 'rendercomplete'
|
||||
|
||||
RENDERCOMPLETE: 'rendercomplete',
|
||||
};
|
||||
|
||||
@@ -1,23 +1,32 @@
|
||||
/**
|
||||
* @module ol/render/Feature
|
||||
*/
|
||||
import {extend} from '../array.js';
|
||||
import {createOrUpdateFromCoordinate, createOrUpdateFromFlatCoordinates, getCenter, getHeight} from '../extent.js';
|
||||
import GeometryType from '../geom/GeometryType.js';
|
||||
import {linearRingss as linearRingssCenter} from '../geom/flat/center.js';
|
||||
import {getInteriorPointOfArray, getInteriorPointsOfMultiArray} from '../geom/flat/interiorpoint.js';
|
||||
import {interpolatePoint} from '../geom/flat/interpolate.js';
|
||||
import {
|
||||
compose as composeTransform,
|
||||
create as createTransform,
|
||||
} from '../transform.js';
|
||||
import {
|
||||
createOrUpdateFromCoordinate,
|
||||
createOrUpdateFromFlatCoordinates,
|
||||
getCenter,
|
||||
getHeight,
|
||||
} from '../extent.js';
|
||||
import {extend} from '../array.js';
|
||||
import {
|
||||
getInteriorPointOfArray,
|
||||
getInteriorPointsOfMultiArray,
|
||||
} from '../geom/flat/interiorpoint.js';
|
||||
import {get as getProjection} from '../proj.js';
|
||||
import {interpolatePoint} from '../geom/flat/interpolate.js';
|
||||
import {linearRingss as linearRingssCenter} from '../geom/flat/center.js';
|
||||
import {transform2D} from '../geom/flat/transform.js';
|
||||
import {create as createTransform, compose as composeTransform} from '../transform.js';
|
||||
|
||||
|
||||
/**
|
||||
* @type {import("../transform.js").Transform}
|
||||
*/
|
||||
const tmpTransform = createTransform();
|
||||
|
||||
|
||||
/**
|
||||
* Lightweight, read-only, {@link module:ol/Feature~Feature} and {@link module:ol/geom/Geometry~Geometry} like
|
||||
* structure, optimized for vector tile rendering and styling. Geometry access
|
||||
@@ -80,7 +89,6 @@ class RenderFeature {
|
||||
* @type {Object<string, *>}
|
||||
*/
|
||||
this.properties_ = properties;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,11 +108,15 @@ class RenderFeature {
|
||||
*/
|
||||
getExtent() {
|
||||
if (!this.extent_) {
|
||||
this.extent_ = this.type_ === GeometryType.POINT ?
|
||||
createOrUpdateFromCoordinate(this.flatCoordinates_) :
|
||||
createOrUpdateFromFlatCoordinates(
|
||||
this.flatCoordinates_, 0, this.flatCoordinates_.length, 2);
|
||||
|
||||
this.extent_ =
|
||||
this.type_ === GeometryType.POINT
|
||||
? createOrUpdateFromCoordinate(this.flatCoordinates_)
|
||||
: createOrUpdateFromFlatCoordinates(
|
||||
this.flatCoordinates_,
|
||||
0,
|
||||
this.flatCoordinates_.length,
|
||||
2
|
||||
);
|
||||
}
|
||||
return this.extent_;
|
||||
}
|
||||
@@ -116,7 +128,13 @@ class RenderFeature {
|
||||
if (!this.flatInteriorPoints_) {
|
||||
const flatCenter = getCenter(this.getExtent());
|
||||
this.flatInteriorPoints_ = getInteriorPointOfArray(
|
||||
this.flatCoordinates_, 0, /** @type {Array<number>} */ (this.ends_), 2, flatCenter, 0);
|
||||
this.flatCoordinates_,
|
||||
0,
|
||||
/** @type {Array<number>} */ (this.ends_),
|
||||
2,
|
||||
flatCenter,
|
||||
0
|
||||
);
|
||||
}
|
||||
return this.flatInteriorPoints_;
|
||||
}
|
||||
@@ -127,9 +145,18 @@ class RenderFeature {
|
||||
getFlatInteriorPoints() {
|
||||
if (!this.flatInteriorPoints_) {
|
||||
const flatCenters = linearRingssCenter(
|
||||
this.flatCoordinates_, 0, /** @type {Array<Array<number>>} */ (this.ends_), 2);
|
||||
this.flatCoordinates_,
|
||||
0,
|
||||
/** @type {Array<Array<number>>} */ (this.ends_),
|
||||
2
|
||||
);
|
||||
this.flatInteriorPoints_ = getInteriorPointsOfMultiArray(
|
||||
this.flatCoordinates_, 0, /** @type {Array<Array<number>>} */ (this.ends_), 2, flatCenters);
|
||||
this.flatCoordinates_,
|
||||
0,
|
||||
/** @type {Array<Array<number>>} */ (this.ends_),
|
||||
2,
|
||||
flatCenters
|
||||
);
|
||||
}
|
||||
return this.flatInteriorPoints_;
|
||||
}
|
||||
@@ -140,7 +167,12 @@ class RenderFeature {
|
||||
getFlatMidpoint() {
|
||||
if (!this.flatMidpoints_) {
|
||||
this.flatMidpoints_ = interpolatePoint(
|
||||
this.flatCoordinates_, 0, this.flatCoordinates_.length, 2, 0.5);
|
||||
this.flatCoordinates_,
|
||||
0,
|
||||
this.flatCoordinates_.length,
|
||||
2,
|
||||
0.5
|
||||
);
|
||||
}
|
||||
return this.flatMidpoints_;
|
||||
}
|
||||
@@ -156,8 +188,7 @@ class RenderFeature {
|
||||
const ends = /** @type {Array<number>} */ (this.ends_);
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
const end = ends[i];
|
||||
const midpoint = interpolatePoint(
|
||||
flatCoordinates, offset, end, 2, 0.5);
|
||||
const midpoint = interpolatePoint(flatCoordinates, offset, end, 2, 0.5);
|
||||
extend(this.flatMidpoints_, midpoint);
|
||||
offset = end;
|
||||
}
|
||||
@@ -255,30 +286,39 @@ class RenderFeature {
|
||||
const pixelExtent = source.getExtent();
|
||||
const projectedExtent = source.getWorldExtent();
|
||||
const scale = getHeight(projectedExtent) / getHeight(pixelExtent);
|
||||
composeTransform(tmpTransform,
|
||||
projectedExtent[0], projectedExtent[3],
|
||||
scale, -scale, 0,
|
||||
0, 0);
|
||||
transform2D(this.flatCoordinates_, 0, this.flatCoordinates_.length, 2,
|
||||
tmpTransform, this.flatCoordinates_);
|
||||
composeTransform(
|
||||
tmpTransform,
|
||||
projectedExtent[0],
|
||||
projectedExtent[3],
|
||||
scale,
|
||||
-scale,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
transform2D(
|
||||
this.flatCoordinates_,
|
||||
0,
|
||||
this.flatCoordinates_.length,
|
||||
2,
|
||||
tmpTransform,
|
||||
this.flatCoordinates_
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array<number>|Array<Array<number>>} Ends or endss.
|
||||
*/
|
||||
RenderFeature.prototype.getEnds = function() {
|
||||
RenderFeature.prototype.getEnds = function () {
|
||||
return this.ends_;
|
||||
};
|
||||
RenderFeature.prototype.getEndss = RenderFeature.prototype.getEnds;
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array<number>} Flat coordinates.
|
||||
*/
|
||||
RenderFeature.prototype.getFlatCoordinates =
|
||||
RenderFeature.prototype.getOrientedFlatCoordinates;
|
||||
|
||||
RenderFeature.prototype.getOrientedFlatCoordinates;
|
||||
|
||||
export default RenderFeature;
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
/**
|
||||
* @module ol/render/canvas
|
||||
*/
|
||||
import {getFontParameters} from '../css.js';
|
||||
import {createCanvasContext2D} from '../dom.js';
|
||||
import {clear} from '../obj.js';
|
||||
import BaseObject from '../Object.js';
|
||||
import EventTarget from '../events/Target.js';
|
||||
import {WORKER_OFFSCREEN_CANVAS} from '../has.js';
|
||||
import {clear} from '../obj.js';
|
||||
import {createCanvasContext2D} from '../dom.js';
|
||||
import {getFontParameters} from '../css.js';
|
||||
import {toString} from '../transform.js';
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} FillState
|
||||
* @property {import("../colorlike.js").ColorLike} fillStyle
|
||||
@@ -43,7 +42,6 @@ import {toString} from '../transform.js';
|
||||
* @property {number} [miterLimit]
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} StrokeState
|
||||
* @property {CanvasLineCap} lineCap
|
||||
@@ -55,7 +53,6 @@ import {toString} from '../transform.js';
|
||||
* @property {import("../colorlike.js").ColorLike} strokeStyle
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} TextState
|
||||
* @property {string} font
|
||||
@@ -82,90 +79,77 @@ import {toString} from '../transform.js';
|
||||
* @typedef {Array<*>} DeclutterGroup
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Declutter groups for support of multi geometries.
|
||||
* @typedef {Array<DeclutterGroup>} DeclutterGroups
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {string}
|
||||
*/
|
||||
export const defaultFont = '10px sans-serif';
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {import("../colorlike.js").ColorLike}
|
||||
*/
|
||||
export const defaultFillStyle = '#000';
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {CanvasLineCap}
|
||||
*/
|
||||
export const defaultLineCap = 'round';
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Array<number>}
|
||||
*/
|
||||
export const defaultLineDash = [];
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
export const defaultLineDashOffset = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {CanvasLineJoin}
|
||||
*/
|
||||
export const defaultLineJoin = 'round';
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {number}
|
||||
*/
|
||||
export const defaultMiterLimit = 10;
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {import("../colorlike.js").ColorLike}
|
||||
*/
|
||||
export const defaultStrokeStyle = '#000';
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {string}
|
||||
*/
|
||||
export const defaultTextAlign = 'center';
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {string}
|
||||
*/
|
||||
export const defaultTextBaseline = 'middle';
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {Array<number>}
|
||||
*/
|
||||
export const defaultPadding = [0, 0, 0, 0];
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {number}
|
||||
@@ -186,7 +170,7 @@ export const checkedFonts = new BaseObject();
|
||||
* @deprecated
|
||||
*/
|
||||
export const labelCache = new EventTarget();
|
||||
labelCache.setSize = function() {
|
||||
labelCache.setSize = function () {
|
||||
console.warn('labelCache is deprecated.'); //eslint-disable-line
|
||||
};
|
||||
|
||||
@@ -205,12 +189,11 @@ let measureFont;
|
||||
*/
|
||||
export const textHeights = {};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the label cache when a font becomes available.
|
||||
* @param {string} fontSpec CSS font spec.
|
||||
*/
|
||||
export const registerFont = (function() {
|
||||
export const registerFont = (function () {
|
||||
const retries = 100;
|
||||
const size = '32px ';
|
||||
const referenceFonts = ['monospace', 'serif'];
|
||||
@@ -228,9 +211,22 @@ export const registerFont = (function() {
|
||||
let available = true;
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const referenceFont = referenceFonts[i];
|
||||
referenceWidth = measureTextWidth(fontStyle + ' ' + fontWeight + ' ' + size + referenceFont, text);
|
||||
referenceWidth = measureTextWidth(
|
||||
fontStyle + ' ' + fontWeight + ' ' + size + referenceFont,
|
||||
text
|
||||
);
|
||||
if (fontFamily != referenceFont) {
|
||||
const width = measureTextWidth(fontStyle + ' ' + fontWeight + ' ' + size + fontFamily + ',' + referenceFont, text);
|
||||
const width = measureTextWidth(
|
||||
fontStyle +
|
||||
' ' +
|
||||
fontWeight +
|
||||
' ' +
|
||||
size +
|
||||
fontFamily +
|
||||
',' +
|
||||
referenceFont,
|
||||
text
|
||||
);
|
||||
// If width and referenceWidth are the same, then the fallback was used
|
||||
// instead of the font we wanted, so the font is not available.
|
||||
available = available && width != referenceWidth;
|
||||
@@ -266,7 +262,7 @@ export const registerFont = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
return function(fontSpec) {
|
||||
return function (fontSpec) {
|
||||
const font = getFontParameters(fontSpec);
|
||||
if (!font) {
|
||||
return;
|
||||
@@ -288,25 +284,28 @@ export const registerFont = (function() {
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} font Font to use for measuring.
|
||||
* @return {import("../size.js").Size} Measurement.
|
||||
*/
|
||||
export const measureTextHeight = (function() {
|
||||
export const measureTextHeight = (function () {
|
||||
/**
|
||||
* @type {HTMLDivElement}
|
||||
*/
|
||||
let div;
|
||||
const heights = textHeights;
|
||||
return function(fontSpec) {
|
||||
return function (fontSpec) {
|
||||
let height = heights[fontSpec];
|
||||
if (height == undefined) {
|
||||
if (WORKER_OFFSCREEN_CANVAS) {
|
||||
const font = getFontParameters(fontSpec);
|
||||
const metrics = measureText(fontSpec, 'Žg');
|
||||
const lineHeight = isNaN(Number(font.lineHeight)) ? 1.2 : Number(font.lineHeight);
|
||||
textHeights[fontSpec] = lineHeight * (metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent);
|
||||
const lineHeight = isNaN(Number(font.lineHeight))
|
||||
? 1.2
|
||||
: Number(font.lineHeight);
|
||||
textHeights[fontSpec] =
|
||||
lineHeight *
|
||||
(metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent);
|
||||
} else {
|
||||
if (!div) {
|
||||
div = document.createElement('div');
|
||||
@@ -368,7 +367,6 @@ export function measureAndCacheTextWidth(font, text, cache) {
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} font Font to use for measuring.
|
||||
* @param {Array<string>} lines Lines to measure.
|
||||
@@ -387,7 +385,6 @@ export function measureTextWidths(font, lines, widths) {
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {CanvasRenderingContext2D} context Context.
|
||||
* @param {number} rotation Rotation.
|
||||
@@ -402,7 +399,6 @@ export function rotateAtOffset(context, rotation, offsetX, offsetY) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {CanvasRenderingContext2D} context Context.
|
||||
* @param {import("../transform.js").Transform|null} transform Transform.
|
||||
@@ -416,8 +412,19 @@ export function rotateAtOffset(context, rotation, offsetX, offsetY) {
|
||||
* @param {number} y Y.
|
||||
* @param {number} scale Scale.
|
||||
*/
|
||||
export function drawImageOrLabel(context,
|
||||
transform, opacity, labelOrImage, originX, originY, w, h, x, y, scale) {
|
||||
export function drawImageOrLabel(
|
||||
context,
|
||||
transform,
|
||||
opacity,
|
||||
labelOrImage,
|
||||
originX,
|
||||
originY,
|
||||
w,
|
||||
h,
|
||||
x,
|
||||
y,
|
||||
scale
|
||||
) {
|
||||
context.save();
|
||||
|
||||
if (opacity !== 1) {
|
||||
@@ -427,14 +434,24 @@ export function drawImageOrLabel(context,
|
||||
context.setTransform.apply(context, transform);
|
||||
}
|
||||
|
||||
if ((/** @type {*} */ (labelOrImage).contextInstructions)) {
|
||||
if (/** @type {*} */ (labelOrImage).contextInstructions) {
|
||||
// label
|
||||
context.translate(x, y);
|
||||
context.scale(scale, scale);
|
||||
executeLabelInstructions(/** @type {Label} */ (labelOrImage), context);
|
||||
} else {
|
||||
// image
|
||||
context.drawImage(/** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */ (labelOrImage), originX, originY, w, h, x, y, w * scale, h * scale);
|
||||
context.drawImage(
|
||||
/** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */ (labelOrImage),
|
||||
originX,
|
||||
originY,
|
||||
w,
|
||||
h,
|
||||
x,
|
||||
y,
|
||||
w * scale,
|
||||
h * scale
|
||||
);
|
||||
}
|
||||
|
||||
context.restore();
|
||||
@@ -448,7 +465,10 @@ function executeLabelInstructions(label, context) {
|
||||
const contextInstructions = label.contextInstructions;
|
||||
for (let i = 0, ii = contextInstructions.length; i < ii; i += 2) {
|
||||
if (Array.isArray(contextInstructions[i + 1])) {
|
||||
context[contextInstructions[i]].apply(context, contextInstructions[i + 1]);
|
||||
context[contextInstructions[i]].apply(
|
||||
context,
|
||||
contextInstructions[i + 1]
|
||||
);
|
||||
} else {
|
||||
context[contextInstructions[i]] = contextInstructions[i + 1];
|
||||
}
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
/**
|
||||
* @module ol/render/canvas/Builder
|
||||
*/
|
||||
import {equals, reverseSubArray} from '../../array.js';
|
||||
import CanvasInstruction from './Instruction.js';
|
||||
import GeometryType from '../../geom/GeometryType.js';
|
||||
import Relationship from '../../extent/Relationship.js';
|
||||
import VectorContext from '../VectorContext.js';
|
||||
import {asColorLike} from '../../colorlike.js';
|
||||
import {buffer, clone, coordinateRelationship} from '../../extent.js';
|
||||
import Relationship from '../../extent/Relationship.js';
|
||||
import GeometryType from '../../geom/GeometryType.js';
|
||||
import {inflateCoordinates, inflateCoordinatesArray, inflateMultiCoordinatesArray} from '../../geom/flat/inflate.js';
|
||||
import VectorContext from '../VectorContext.js';
|
||||
import {defaultFillStyle, defaultStrokeStyle,
|
||||
defaultMiterLimit, defaultLineWidth, defaultLineJoin, defaultLineDashOffset,
|
||||
defaultLineDash, defaultLineCap} from '../canvas.js';
|
||||
import CanvasInstruction from './Instruction.js';
|
||||
|
||||
import {
|
||||
defaultFillStyle,
|
||||
defaultLineCap,
|
||||
defaultLineDash,
|
||||
defaultLineDashOffset,
|
||||
defaultLineJoin,
|
||||
defaultLineWidth,
|
||||
defaultMiterLimit,
|
||||
defaultStrokeStyle,
|
||||
} from '../canvas.js';
|
||||
import {equals, reverseSubArray} from '../../array.js';
|
||||
import {
|
||||
inflateCoordinates,
|
||||
inflateCoordinatesArray,
|
||||
inflateMultiCoordinatesArray,
|
||||
} from '../../geom/flat/inflate.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} SerializableInstructions
|
||||
@@ -24,7 +34,6 @@ import CanvasInstruction from './Instruction.js';
|
||||
* @property {!Object<string, import("../canvas.js").StrokeState>} [strokeStates] The stroke states (decluttering).
|
||||
*/
|
||||
|
||||
|
||||
class CanvasBuilder extends VectorContext {
|
||||
/**
|
||||
* @param {number} tolerance Tolerance.
|
||||
@@ -114,7 +123,6 @@ class CanvasBuilder extends VectorContext {
|
||||
* @type {import("../canvas.js").FillStrokeState}
|
||||
*/
|
||||
this.state = /** @type {import("../canvas.js").FillStrokeState} */ ({});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,9 +132,11 @@ class CanvasBuilder extends VectorContext {
|
||||
*/
|
||||
applyPixelRatio(dashArray) {
|
||||
const pixelRatio = this.pixelRatio;
|
||||
return pixelRatio == 1 ? dashArray : dashArray.map(function(dash) {
|
||||
return dash * pixelRatio;
|
||||
});
|
||||
return pixelRatio == 1
|
||||
? dashArray
|
||||
: dashArray.map(function (dash) {
|
||||
return dash * pixelRatio;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,8 +149,14 @@ class CanvasBuilder extends VectorContext {
|
||||
* @protected
|
||||
* @return {number} My end.
|
||||
*/
|
||||
appendFlatCoordinates(flatCoordinates, offset, end, stride, closed, skipFirst) {
|
||||
|
||||
appendFlatCoordinates(
|
||||
flatCoordinates,
|
||||
offset,
|
||||
end,
|
||||
stride,
|
||||
closed,
|
||||
skipFirst
|
||||
) {
|
||||
let myEnd = this.coordinates.length;
|
||||
const extent = this.getBufferedMaxExtent();
|
||||
if (skipFirst) {
|
||||
@@ -195,7 +211,14 @@ class CanvasBuilder extends VectorContext {
|
||||
drawCustomCoordinates_(flatCoordinates, offset, ends, stride, builderEnds) {
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
const end = ends[i];
|
||||
const builderEnd = this.appendFlatCoordinates(flatCoordinates, offset, end, stride, false, false);
|
||||
const builderEnd = this.appendFlatCoordinates(
|
||||
flatCoordinates,
|
||||
offset,
|
||||
end,
|
||||
stride,
|
||||
false,
|
||||
false
|
||||
);
|
||||
builderEnds.push(builderEnd);
|
||||
offset = end;
|
||||
}
|
||||
@@ -221,33 +244,79 @@ class CanvasBuilder extends VectorContext {
|
||||
offset = 0;
|
||||
for (let i = 0, ii = endss.length; i < ii; ++i) {
|
||||
const myEnds = [];
|
||||
offset = this.drawCustomCoordinates_(flatCoordinates, offset, endss[i], stride, myEnds);
|
||||
offset = this.drawCustomCoordinates_(
|
||||
flatCoordinates,
|
||||
offset,
|
||||
endss[i],
|
||||
stride,
|
||||
myEnds
|
||||
);
|
||||
builderEndss.push(myEnds);
|
||||
}
|
||||
this.instructions.push([CanvasInstruction.CUSTOM,
|
||||
builderBegin, builderEndss, geometry, renderer, inflateMultiCoordinatesArray]);
|
||||
} else if (type == GeometryType.POLYGON || type == GeometryType.MULTI_LINE_STRING) {
|
||||
this.instructions.push([
|
||||
CanvasInstruction.CUSTOM,
|
||||
builderBegin,
|
||||
builderEndss,
|
||||
geometry,
|
||||
renderer,
|
||||
inflateMultiCoordinatesArray,
|
||||
]);
|
||||
} else if (
|
||||
type == GeometryType.POLYGON ||
|
||||
type == GeometryType.MULTI_LINE_STRING
|
||||
) {
|
||||
builderEnds = [];
|
||||
flatCoordinates = (type == GeometryType.POLYGON) ?
|
||||
/** @type {import("../../geom/Polygon.js").default} */ (geometry).getOrientedFlatCoordinates() :
|
||||
geometry.getFlatCoordinates();
|
||||
offset = this.drawCustomCoordinates_(flatCoordinates, 0,
|
||||
flatCoordinates =
|
||||
type == GeometryType.POLYGON
|
||||
? /** @type {import("../../geom/Polygon.js").default} */ (geometry).getOrientedFlatCoordinates()
|
||||
: geometry.getFlatCoordinates();
|
||||
offset = this.drawCustomCoordinates_(
|
||||
flatCoordinates,
|
||||
0,
|
||||
/** @type {import("../../geom/Polygon.js").default|import("../../geom/MultiLineString.js").default} */ (geometry).getEnds(),
|
||||
stride, builderEnds);
|
||||
this.instructions.push([CanvasInstruction.CUSTOM,
|
||||
builderBegin, builderEnds, geometry, renderer, inflateCoordinatesArray]);
|
||||
} else if (type == GeometryType.LINE_STRING || type == GeometryType.MULTI_POINT) {
|
||||
stride,
|
||||
builderEnds
|
||||
);
|
||||
this.instructions.push([
|
||||
CanvasInstruction.CUSTOM,
|
||||
builderBegin,
|
||||
builderEnds,
|
||||
geometry,
|
||||
renderer,
|
||||
inflateCoordinatesArray,
|
||||
]);
|
||||
} else if (
|
||||
type == GeometryType.LINE_STRING ||
|
||||
type == GeometryType.MULTI_POINT
|
||||
) {
|
||||
flatCoordinates = geometry.getFlatCoordinates();
|
||||
builderEnd = this.appendFlatCoordinates(
|
||||
flatCoordinates, 0, flatCoordinates.length, stride, false, false);
|
||||
this.instructions.push([CanvasInstruction.CUSTOM,
|
||||
builderBegin, builderEnd, geometry, renderer, inflateCoordinates]);
|
||||
flatCoordinates,
|
||||
0,
|
||||
flatCoordinates.length,
|
||||
stride,
|
||||
false,
|
||||
false
|
||||
);
|
||||
this.instructions.push([
|
||||
CanvasInstruction.CUSTOM,
|
||||
builderBegin,
|
||||
builderEnd,
|
||||
geometry,
|
||||
renderer,
|
||||
inflateCoordinates,
|
||||
]);
|
||||
} else if (type == GeometryType.POINT) {
|
||||
flatCoordinates = geometry.getFlatCoordinates();
|
||||
this.coordinates.push(flatCoordinates[0], flatCoordinates[1]);
|
||||
builderEnd = this.coordinates.length;
|
||||
this.instructions.push([CanvasInstruction.CUSTOM,
|
||||
builderBegin, builderEnd, geometry, renderer]);
|
||||
this.instructions.push([
|
||||
CanvasInstruction.CUSTOM,
|
||||
builderBegin,
|
||||
builderEnd,
|
||||
geometry,
|
||||
renderer,
|
||||
]);
|
||||
}
|
||||
this.endGeometry(feature);
|
||||
}
|
||||
@@ -259,9 +328,19 @@ class CanvasBuilder extends VectorContext {
|
||||
*/
|
||||
beginGeometry(geometry, feature) {
|
||||
const extent = geometry.getExtent();
|
||||
this.beginGeometryInstruction1_ = [CanvasInstruction.BEGIN_GEOMETRY, feature, 0, extent];
|
||||
this.beginGeometryInstruction1_ = [
|
||||
CanvasInstruction.BEGIN_GEOMETRY,
|
||||
feature,
|
||||
0,
|
||||
extent,
|
||||
];
|
||||
this.instructions.push(this.beginGeometryInstruction1_);
|
||||
this.beginGeometryInstruction2_ = [CanvasInstruction.BEGIN_GEOMETRY, feature, 0, extent];
|
||||
this.beginGeometryInstruction2_ = [
|
||||
CanvasInstruction.BEGIN_GEOMETRY,
|
||||
feature,
|
||||
0,
|
||||
extent,
|
||||
];
|
||||
this.hitDetectionInstructions.push(this.beginGeometryInstruction2_);
|
||||
}
|
||||
|
||||
@@ -272,7 +351,7 @@ class CanvasBuilder extends VectorContext {
|
||||
return {
|
||||
instructions: this.instructions,
|
||||
hitDetectionInstructions: this.hitDetectionInstructions,
|
||||
coordinates: this.coordinates
|
||||
coordinates: this.coordinates,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -310,33 +389,41 @@ class CanvasBuilder extends VectorContext {
|
||||
const state = this.state;
|
||||
if (fillStyle) {
|
||||
const fillStyleColor = fillStyle.getColor();
|
||||
state.fillStyle = asColorLike(fillStyleColor ?
|
||||
fillStyleColor : defaultFillStyle);
|
||||
state.fillStyle = asColorLike(
|
||||
fillStyleColor ? fillStyleColor : defaultFillStyle
|
||||
);
|
||||
} else {
|
||||
state.fillStyle = undefined;
|
||||
}
|
||||
if (strokeStyle) {
|
||||
const strokeStyleColor = strokeStyle.getColor();
|
||||
state.strokeStyle = asColorLike(strokeStyleColor ?
|
||||
strokeStyleColor : defaultStrokeStyle);
|
||||
state.strokeStyle = asColorLike(
|
||||
strokeStyleColor ? strokeStyleColor : defaultStrokeStyle
|
||||
);
|
||||
const strokeStyleLineCap = strokeStyle.getLineCap();
|
||||
state.lineCap = strokeStyleLineCap !== undefined ?
|
||||
strokeStyleLineCap : defaultLineCap;
|
||||
state.lineCap =
|
||||
strokeStyleLineCap !== undefined ? strokeStyleLineCap : defaultLineCap;
|
||||
const strokeStyleLineDash = strokeStyle.getLineDash();
|
||||
state.lineDash = strokeStyleLineDash ?
|
||||
strokeStyleLineDash.slice() : defaultLineDash;
|
||||
state.lineDash = strokeStyleLineDash
|
||||
? strokeStyleLineDash.slice()
|
||||
: defaultLineDash;
|
||||
const strokeStyleLineDashOffset = strokeStyle.getLineDashOffset();
|
||||
state.lineDashOffset = strokeStyleLineDashOffset ?
|
||||
strokeStyleLineDashOffset : defaultLineDashOffset;
|
||||
state.lineDashOffset = strokeStyleLineDashOffset
|
||||
? strokeStyleLineDashOffset
|
||||
: defaultLineDashOffset;
|
||||
const strokeStyleLineJoin = strokeStyle.getLineJoin();
|
||||
state.lineJoin = strokeStyleLineJoin !== undefined ?
|
||||
strokeStyleLineJoin : defaultLineJoin;
|
||||
state.lineJoin =
|
||||
strokeStyleLineJoin !== undefined
|
||||
? strokeStyleLineJoin
|
||||
: defaultLineJoin;
|
||||
const strokeStyleWidth = strokeStyle.getWidth();
|
||||
state.lineWidth = strokeStyleWidth !== undefined ?
|
||||
strokeStyleWidth : defaultLineWidth;
|
||||
state.lineWidth =
|
||||
strokeStyleWidth !== undefined ? strokeStyleWidth : defaultLineWidth;
|
||||
const strokeStyleMiterLimit = strokeStyle.getMiterLimit();
|
||||
state.miterLimit = strokeStyleMiterLimit !== undefined ?
|
||||
strokeStyleMiterLimit : defaultMiterLimit;
|
||||
state.miterLimit =
|
||||
strokeStyleMiterLimit !== undefined
|
||||
? strokeStyleMiterLimit
|
||||
: defaultMiterLimit;
|
||||
|
||||
if (state.lineWidth > this.maxLineWidth) {
|
||||
this.maxLineWidth = state.lineWidth;
|
||||
@@ -383,9 +470,13 @@ class CanvasBuilder extends VectorContext {
|
||||
createStroke(state) {
|
||||
return [
|
||||
CanvasInstruction.SET_STROKE_STYLE,
|
||||
state.strokeStyle, state.lineWidth * this.pixelRatio, state.lineCap,
|
||||
state.lineJoin, state.miterLimit,
|
||||
this.applyPixelRatio(state.lineDash), state.lineDashOffset * this.pixelRatio
|
||||
state.strokeStyle,
|
||||
state.lineWidth * this.pixelRatio,
|
||||
state.lineCap,
|
||||
state.lineJoin,
|
||||
state.miterLimit,
|
||||
this.applyPixelRatio(state.lineDash),
|
||||
state.lineDashOffset * this.pixelRatio,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -415,13 +506,16 @@ class CanvasBuilder extends VectorContext {
|
||||
const lineJoin = state.lineJoin;
|
||||
const lineWidth = state.lineWidth;
|
||||
const miterLimit = state.miterLimit;
|
||||
if (state.currentStrokeStyle != strokeStyle ||
|
||||
state.currentLineCap != lineCap ||
|
||||
(lineDash != state.currentLineDash && !equals(state.currentLineDash, lineDash)) ||
|
||||
state.currentLineDashOffset != lineDashOffset ||
|
||||
state.currentLineJoin != lineJoin ||
|
||||
state.currentLineWidth != lineWidth ||
|
||||
state.currentMiterLimit != miterLimit) {
|
||||
if (
|
||||
state.currentStrokeStyle != strokeStyle ||
|
||||
state.currentLineCap != lineCap ||
|
||||
(lineDash != state.currentLineDash &&
|
||||
!equals(state.currentLineDash, lineDash)) ||
|
||||
state.currentLineDashOffset != lineDashOffset ||
|
||||
state.currentLineJoin != lineJoin ||
|
||||
state.currentLineWidth != lineWidth ||
|
||||
state.currentMiterLimit != miterLimit
|
||||
) {
|
||||
if (strokeStyle !== undefined) {
|
||||
applyStroke.call(this, state);
|
||||
}
|
||||
@@ -459,7 +553,7 @@ class CanvasBuilder extends VectorContext {
|
||||
if (!this.bufferedMaxExtent_) {
|
||||
this.bufferedMaxExtent_ = clone(this.maxExtent);
|
||||
if (this.maxLineWidth > 0) {
|
||||
const width = this.resolution * (this.maxLineWidth + 1) / 2;
|
||||
const width = (this.resolution * (this.maxLineWidth + 1)) / 2;
|
||||
buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_);
|
||||
}
|
||||
}
|
||||
@@ -467,5 +561,4 @@ class CanvasBuilder extends VectorContext {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default CanvasBuilder;
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
* @module ol/render/canvas/BuilderGroup
|
||||
*/
|
||||
|
||||
import {createEmpty} from '../../extent.js';
|
||||
import Builder from './Builder.js';
|
||||
import ImageBuilder from './ImageBuilder.js';
|
||||
import LineStringBuilder from './LineStringBuilder.js';
|
||||
import PolygonBuilder from './PolygonBuilder.js';
|
||||
import TextBuilder from './TextBuilder.js';
|
||||
|
||||
import {createEmpty} from '../../extent.js';
|
||||
|
||||
/**
|
||||
* @type {Object<import("./BuilderType").default, typeof Builder>}
|
||||
@@ -19,10 +18,9 @@ const BATCH_CONSTRUCTORS = {
|
||||
'Image': ImageBuilder,
|
||||
'LineString': LineStringBuilder,
|
||||
'Polygon': PolygonBuilder,
|
||||
'Text': TextBuilder
|
||||
'Text': TextBuilder,
|
||||
};
|
||||
|
||||
|
||||
class BuilderGroup {
|
||||
/**
|
||||
* @param {number} tolerance Tolerance.
|
||||
@@ -32,7 +30,6 @@ class BuilderGroup {
|
||||
* @param {boolean} declutter Decluttering enabled.
|
||||
*/
|
||||
constructor(tolerance, maxExtent, resolution, pixelRatio, declutter) {
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
@@ -126,8 +123,12 @@ class BuilderGroup {
|
||||
let replay = replays[builderType];
|
||||
if (replay === undefined) {
|
||||
const Constructor = BATCH_CONSTRUCTORS[builderType];
|
||||
replay = new Constructor(this.tolerance_, this.maxExtent_,
|
||||
this.resolution_, this.pixelRatio_);
|
||||
replay = new Constructor(
|
||||
this.tolerance_,
|
||||
this.maxExtent_,
|
||||
this.resolution_,
|
||||
this.pixelRatio_
|
||||
);
|
||||
replays[builderType] = replay;
|
||||
}
|
||||
return replay;
|
||||
|
||||
@@ -11,5 +11,5 @@ export default {
|
||||
IMAGE: 'Image',
|
||||
LINE_STRING: 'LineString',
|
||||
POLYGON: 'Polygon',
|
||||
TEXT: 'Text'
|
||||
TEXT: 'Text',
|
||||
};
|
||||
|
||||
@@ -1,25 +1,38 @@
|
||||
/**
|
||||
* @module ol/render/canvas/Executor
|
||||
*/
|
||||
import {equals} from '../../array.js';
|
||||
import {createEmpty, createOrUpdate,
|
||||
createOrUpdateEmpty, extend, intersects} from '../../extent.js';
|
||||
import {lineStringLength} from '../../geom/flat/length.js';
|
||||
import {drawTextOnPath} from '../../geom/flat/textpath.js';
|
||||
import {transform2D} from '../../geom/flat/transform.js';
|
||||
import {drawImageOrLabel, defaultPadding, defaultTextBaseline} from '../canvas.js';
|
||||
import CanvasInstruction from './Instruction.js';
|
||||
import {TEXT_ALIGN} from './TextBuilder.js';
|
||||
import {
|
||||
create as createTransform,
|
||||
compose as composeTransform,
|
||||
apply as applyTransform,
|
||||
setFromArray as transformSetFromArray
|
||||
} from '../../transform.js';
|
||||
import {defaultTextAlign, measureTextHeight, measureAndCacheTextWidth, measureTextWidths} from '../canvas.js';
|
||||
import RBush from 'rbush/rbush.js';
|
||||
import {TEXT_ALIGN} from './TextBuilder.js';
|
||||
import {WORKER_OFFSCREEN_CANVAS} from '../../has.js';
|
||||
|
||||
import {
|
||||
apply as applyTransform,
|
||||
compose as composeTransform,
|
||||
create as createTransform,
|
||||
setFromArray as transformSetFromArray,
|
||||
} from '../../transform.js';
|
||||
import {
|
||||
createEmpty,
|
||||
createOrUpdate,
|
||||
createOrUpdateEmpty,
|
||||
extend,
|
||||
intersects,
|
||||
} from '../../extent.js';
|
||||
import {
|
||||
defaultPadding,
|
||||
defaultTextBaseline,
|
||||
drawImageOrLabel,
|
||||
} from '../canvas.js';
|
||||
import {
|
||||
defaultTextAlign,
|
||||
measureAndCacheTextWidth,
|
||||
measureTextHeight,
|
||||
measureTextWidths,
|
||||
} from '../canvas.js';
|
||||
import {drawTextOnPath} from '../../geom/flat/textpath.js';
|
||||
import {equals} from '../../array.js';
|
||||
import {lineStringLength} from '../../geom/flat/length.js';
|
||||
import {transform2D} from '../../geom/flat/transform.js';
|
||||
|
||||
/**
|
||||
* @typedef {Object} SerializableInstructions
|
||||
@@ -50,7 +63,6 @@ const p3 = [];
|
||||
/** @type {import("../../coordinate.js").Coordinate} */
|
||||
const p4 = [];
|
||||
|
||||
|
||||
class Executor {
|
||||
/**
|
||||
* @param {number} resolution Resolution.
|
||||
@@ -59,7 +71,6 @@ class Executor {
|
||||
* @param {SerializableInstructions} instructions The serializable instructions
|
||||
*/
|
||||
constructor(resolution, pixelRatio, overlaps, instructions) {
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
@@ -178,7 +189,8 @@ class Executor {
|
||||
const pixelRatio = this.pixelRatio;
|
||||
const scale = textState.scale * pixelRatio;
|
||||
const align = TEXT_ALIGN[textState.textAlign || defaultTextAlign];
|
||||
const strokeWidth = strokeKey && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
||||
const strokeWidth =
|
||||
strokeKey && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
||||
|
||||
const lines = text.split('\n');
|
||||
const numLines = lines.length;
|
||||
@@ -193,7 +205,7 @@ class Executor {
|
||||
// make canvas 2 pixels wider to account for italic text width measurement errors
|
||||
width: Math.ceil((renderWidth + 2) * scale),
|
||||
height: Math.ceil((height + strokeWidth) * scale),
|
||||
contextInstructions: contextInstructions
|
||||
contextInstructions: contextInstructions,
|
||||
};
|
||||
if (scale != 1) {
|
||||
contextInstructions.push('scale', [scale, scale]);
|
||||
@@ -217,17 +229,25 @@ class Executor {
|
||||
}
|
||||
contextInstructions.push('textBaseline', 'middle');
|
||||
contextInstructions.push('textAlign', 'center');
|
||||
const leftRight = (0.5 - align);
|
||||
const leftRight = 0.5 - align;
|
||||
const x = align * renderWidth + leftRight * strokeWidth;
|
||||
let i;
|
||||
if (strokeKey) {
|
||||
for (i = 0; i < numLines; ++i) {
|
||||
contextInstructions.push('strokeText', [lines[i], x + leftRight * widths[i], 0.5 * (strokeWidth + lineHeight) + i * lineHeight]);
|
||||
contextInstructions.push('strokeText', [
|
||||
lines[i],
|
||||
x + leftRight * widths[i],
|
||||
0.5 * (strokeWidth + lineHeight) + i * lineHeight,
|
||||
]);
|
||||
}
|
||||
}
|
||||
if (fillKey) {
|
||||
for (i = 0; i < numLines; ++i) {
|
||||
contextInstructions.push('fillText', [lines[i], x + leftRight * widths[i], 0.5 * (strokeWidth + lineHeight) + i * lineHeight]);
|
||||
contextInstructions.push('fillText', [
|
||||
lines[i],
|
||||
x + leftRight * widths[i],
|
||||
0.5 * (strokeWidth + lineHeight) + i * lineHeight,
|
||||
]);
|
||||
}
|
||||
}
|
||||
this.labels_[key] = label;
|
||||
@@ -243,7 +263,15 @@ class Executor {
|
||||
* @param {Array<*>} fillInstruction Fill instruction.
|
||||
* @param {Array<*>} strokeInstruction Stroke instruction.
|
||||
*/
|
||||
replayTextBackground_(context, p1, p2, p3, p4, fillInstruction, strokeInstruction) {
|
||||
replayTextBackground_(
|
||||
context,
|
||||
p1,
|
||||
p2,
|
||||
p3,
|
||||
p4,
|
||||
fillInstruction,
|
||||
strokeInstruction
|
||||
) {
|
||||
context.beginPath();
|
||||
context.moveTo.apply(context, p1);
|
||||
context.lineTo.apply(context, p2);
|
||||
@@ -255,7 +283,10 @@ class Executor {
|
||||
this.fill_(context);
|
||||
}
|
||||
if (strokeInstruction) {
|
||||
this.setStrokeStyle_(context, /** @type {Array<*>} */ (strokeInstruction));
|
||||
this.setStrokeStyle_(
|
||||
context,
|
||||
/** @type {Array<*>} */ (strokeInstruction)
|
||||
);
|
||||
context.stroke();
|
||||
}
|
||||
}
|
||||
@@ -306,8 +337,14 @@ class Executor {
|
||||
x -= anchorX;
|
||||
y -= anchorY;
|
||||
|
||||
const w = (width + originX > imageOrLabel.width) ? imageOrLabel.width - originX : width;
|
||||
const h = (height + originY > imageOrLabel.height) ? imageOrLabel.height - originY : height;
|
||||
const w =
|
||||
width + originX > imageOrLabel.width
|
||||
? imageOrLabel.width - originX
|
||||
: width;
|
||||
const h =
|
||||
height + originY > imageOrLabel.height
|
||||
? imageOrLabel.height - originY
|
||||
: height;
|
||||
const boxW = padding[3] + w * scale + padding[1];
|
||||
const boxH = padding[0] + h * scale + padding[2];
|
||||
const boxX = x - padding[3];
|
||||
@@ -328,7 +365,16 @@ class Executor {
|
||||
if (rotation !== 0) {
|
||||
const centerX = x + anchorX;
|
||||
const centerY = y + anchorY;
|
||||
transform = composeTransform(tmpTransform, centerX, centerY, 1, 1, rotation, -centerX, -centerY);
|
||||
transform = composeTransform(
|
||||
tmpTransform,
|
||||
centerX,
|
||||
centerY,
|
||||
1,
|
||||
1,
|
||||
rotation,
|
||||
-centerX,
|
||||
-centerY
|
||||
);
|
||||
|
||||
applyTransform(tmpTransform, p1);
|
||||
applyTransform(tmpTransform, p2);
|
||||
@@ -345,10 +391,14 @@ class Executor {
|
||||
createOrUpdate(boxX, boxY, boxX + boxW, boxY + boxH, tmpExtent);
|
||||
}
|
||||
const canvas = context.canvas;
|
||||
const strokePadding = strokeInstruction ? (strokeInstruction[2] * scale / 2) : 0;
|
||||
const strokePadding = strokeInstruction
|
||||
? (strokeInstruction[2] * scale) / 2
|
||||
: 0;
|
||||
const intersects =
|
||||
tmpExtent[0] - strokePadding <= canvas.width && tmpExtent[2] + strokePadding >= 0 &&
|
||||
tmpExtent[1] - strokePadding <= canvas.height && tmpExtent[3] + strokePadding >= 0;
|
||||
tmpExtent[0] - strokePadding <= canvas.width &&
|
||||
tmpExtent[2] + strokePadding >= 0 &&
|
||||
tmpExtent[1] - strokePadding <= canvas.height &&
|
||||
tmpExtent[3] + strokePadding >= 0;
|
||||
|
||||
if (snapToPixel) {
|
||||
x = Math.round(x);
|
||||
@@ -360,22 +410,59 @@ class Executor {
|
||||
return;
|
||||
}
|
||||
extend(declutterGroup, tmpExtent);
|
||||
const declutterArgs = intersects ?
|
||||
[context, transform ? transform.slice(0) : null, opacity, imageOrLabel, originX, originY, w, h, x, y, scale] :
|
||||
null;
|
||||
const declutterArgs = intersects
|
||||
? [
|
||||
context,
|
||||
transform ? transform.slice(0) : null,
|
||||
opacity,
|
||||
imageOrLabel,
|
||||
originX,
|
||||
originY,
|
||||
w,
|
||||
h,
|
||||
x,
|
||||
y,
|
||||
scale,
|
||||
]
|
||||
: null;
|
||||
if (declutterArgs) {
|
||||
if (fillStroke) {
|
||||
declutterArgs.push(fillInstruction, strokeInstruction, p1.slice(0), p2.slice(0), p3.slice(0), p4.slice(0));
|
||||
declutterArgs.push(
|
||||
fillInstruction,
|
||||
strokeInstruction,
|
||||
p1.slice(0),
|
||||
p2.slice(0),
|
||||
p3.slice(0),
|
||||
p4.slice(0)
|
||||
);
|
||||
}
|
||||
declutterGroup.push(declutterArgs);
|
||||
}
|
||||
} else if (intersects) {
|
||||
if (fillStroke) {
|
||||
this.replayTextBackground_(context, p1, p2, p3, p4,
|
||||
this.replayTextBackground_(
|
||||
context,
|
||||
p1,
|
||||
p2,
|
||||
p3,
|
||||
p4,
|
||||
/** @type {Array<*>} */ (fillInstruction),
|
||||
/** @type {Array<*>} */ (strokeInstruction));
|
||||
/** @type {Array<*>} */ (strokeInstruction)
|
||||
);
|
||||
}
|
||||
drawImageOrLabel(context, transform, opacity, imageOrLabel, originX, originY, w, h, x, y, scale);
|
||||
drawImageOrLabel(
|
||||
context,
|
||||
transform,
|
||||
opacity,
|
||||
imageOrLabel,
|
||||
originX,
|
||||
originY,
|
||||
w,
|
||||
h,
|
||||
x,
|
||||
y,
|
||||
scale
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,7 +518,7 @@ class Executor {
|
||||
minY: /** @type {number} */ (declutterGroup[1]),
|
||||
maxX: /** @type {number} */ (declutterGroup[2]),
|
||||
maxY: /** @type {number} */ (declutterGroup[3]),
|
||||
value: feature
|
||||
value: feature,
|
||||
};
|
||||
if (!declutterTree) {
|
||||
declutterTree = new RBush(9);
|
||||
@@ -446,9 +533,15 @@ class Executor {
|
||||
context.globalAlpha = opacity;
|
||||
}
|
||||
if (declutterData.length > 11) {
|
||||
this.replayTextBackground_(declutterData[0],
|
||||
declutterData[13], declutterData[14], declutterData[15], declutterData[16],
|
||||
declutterData[11], declutterData[12]);
|
||||
this.replayTextBackground_(
|
||||
declutterData[0],
|
||||
declutterData[13],
|
||||
declutterData[14],
|
||||
declutterData[15],
|
||||
declutterData[16],
|
||||
declutterData[11],
|
||||
declutterData[12]
|
||||
);
|
||||
}
|
||||
drawImageOrLabel.apply(undefined, declutterData);
|
||||
if (currentAlpha !== opacity) {
|
||||
@@ -480,17 +573,20 @@ class Executor {
|
||||
const pixelRatio = this.pixelRatio;
|
||||
const align = TEXT_ALIGN[textState.textAlign || defaultTextAlign];
|
||||
const baseline = TEXT_ALIGN[textState.textBaseline || defaultTextBaseline];
|
||||
const strokeWidth = strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
||||
const strokeWidth =
|
||||
strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
||||
|
||||
// Remove the 2 pixels we added in createLabel() for the anchor
|
||||
const width = label.width / pixelRatio - 2 * textState.scale;
|
||||
const anchorX = align * width + 2 * (0.5 - align) * strokeWidth;
|
||||
const anchorY = baseline * label.height / pixelRatio + 2 * (0.5 - baseline) * strokeWidth;
|
||||
const anchorY =
|
||||
(baseline * label.height) / pixelRatio +
|
||||
2 * (0.5 - baseline) * strokeWidth;
|
||||
|
||||
return {
|
||||
label: label,
|
||||
anchorX: anchorX,
|
||||
anchorY: anchorY
|
||||
anchorY: anchorY,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -524,15 +620,30 @@ class Executor {
|
||||
this.pixelCoordinates_ = [];
|
||||
}
|
||||
pixelCoordinates = transform2D(
|
||||
this.coordinates, 0, this.coordinates.length, 2,
|
||||
transform, this.pixelCoordinates_);
|
||||
this.coordinates,
|
||||
0,
|
||||
this.coordinates.length,
|
||||
2,
|
||||
transform,
|
||||
this.pixelCoordinates_
|
||||
);
|
||||
transformSetFromArray(this.renderedTransform_, transform);
|
||||
}
|
||||
let i = 0; // instruction index
|
||||
const ii = instructions.length; // end of instructions
|
||||
let d = 0; // data index
|
||||
let dd; // end of per-instruction data
|
||||
let anchorX, anchorY, prevX, prevY, roundX, roundY, declutterGroup, declutterGroups, image, text, textKey;
|
||||
let anchorX,
|
||||
anchorY,
|
||||
prevX,
|
||||
prevY,
|
||||
roundX,
|
||||
roundY,
|
||||
declutterGroup,
|
||||
declutterGroups,
|
||||
image,
|
||||
text,
|
||||
textKey;
|
||||
let strokeKey, fillKey;
|
||||
let pendingFill = 0;
|
||||
let pendingStroke = 0;
|
||||
@@ -540,18 +651,20 @@ class Executor {
|
||||
let lastStrokeInstruction = null;
|
||||
const coordinateCache = this.coordinateCache_;
|
||||
const viewRotation = this.viewRotation_;
|
||||
const viewRotationFromTransform = Math.round(Math.atan2(-transform[1], transform[0]) * 1e12) / 1e12;
|
||||
const viewRotationFromTransform =
|
||||
Math.round(Math.atan2(-transform[1], transform[0]) * 1e12) / 1e12;
|
||||
|
||||
const state = /** @type {import("../../render.js").State} */ ({
|
||||
context: context,
|
||||
pixelRatio: this.pixelRatio,
|
||||
resolution: this.resolution,
|
||||
rotation: viewRotation
|
||||
rotation: viewRotation,
|
||||
});
|
||||
|
||||
// When the batch size gets too big, performance decreases. 200 is a good
|
||||
// balance between batch size and number of fill/stroke instructions.
|
||||
const batchSize = this.instructions != instructions || this.overlaps ? 0 : 200;
|
||||
const batchSize =
|
||||
this.instructions != instructions || this.overlaps ? 0 : 200;
|
||||
let /** @type {import("../../Feature.js").FeatureLike} */ feature;
|
||||
let x, y;
|
||||
while (i < ii) {
|
||||
@@ -562,7 +675,10 @@ class Executor {
|
||||
feature = /** @type {import("../../Feature.js").FeatureLike} */ (instruction[1]);
|
||||
if (!feature.getGeometry()) {
|
||||
i = /** @type {number} */ (instruction[2]);
|
||||
} else if (opt_hitExtent !== undefined && !intersects(opt_hitExtent, instruction[3])) {
|
||||
} else if (
|
||||
opt_hitExtent !== undefined &&
|
||||
!intersects(opt_hitExtent, instruction[3])
|
||||
) {
|
||||
i = /** @type {number} */ (instruction[2]) + 1;
|
||||
} else {
|
||||
++i;
|
||||
@@ -647,7 +763,12 @@ class Executor {
|
||||
textKey = /** @type {string} */ (instruction[19]);
|
||||
strokeKey = /** @type {string} */ (instruction[20]);
|
||||
fillKey = /** @type {string} */ (instruction[21]);
|
||||
const labelWithAnchor = this.drawLabelWithPointPlacement_(text, textKey, strokeKey, fillKey);
|
||||
const labelWithAnchor = this.drawLabelWithPointPlacement_(
|
||||
text,
|
||||
textKey,
|
||||
strokeKey,
|
||||
fillKey
|
||||
);
|
||||
image = labelWithAnchor.label;
|
||||
instruction[3] = image;
|
||||
const textOffsetX = /** @type {number} */ (instruction[22]);
|
||||
@@ -688,7 +809,10 @@ class Executor {
|
||||
let widthIndex = 0;
|
||||
let declutterGroupIndex = 0;
|
||||
for (; d < dd; d += 2) {
|
||||
if (geometryWidths && geometryWidths[widthIndex++] < width / this.pixelRatio) {
|
||||
if (
|
||||
geometryWidths &&
|
||||
geometryWidths[widthIndex++] < width / this.pixelRatio
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if (declutterGroups) {
|
||||
@@ -700,18 +824,35 @@ class Executor {
|
||||
}
|
||||
declutterGroup = declutterGroups[index];
|
||||
}
|
||||
this.replayImageOrLabel_(context,
|
||||
pixelCoordinates[d], pixelCoordinates[d + 1], image, anchorX, anchorY,
|
||||
declutterGroup, height, opacity, originX, originY, rotation, scale,
|
||||
snapToPixel, width, padding,
|
||||
backgroundFill ? /** @type {Array<*>} */ (lastFillInstruction) : null,
|
||||
backgroundStroke ? /** @type {Array<*>} */ (lastStrokeInstruction) : null);
|
||||
this.replayImageOrLabel_(
|
||||
context,
|
||||
pixelCoordinates[d],
|
||||
pixelCoordinates[d + 1],
|
||||
image,
|
||||
anchorX,
|
||||
anchorY,
|
||||
declutterGroup,
|
||||
height,
|
||||
opacity,
|
||||
originX,
|
||||
originY,
|
||||
rotation,
|
||||
scale,
|
||||
snapToPixel,
|
||||
width,
|
||||
padding,
|
||||
backgroundFill
|
||||
? /** @type {Array<*>} */ (lastFillInstruction)
|
||||
: null,
|
||||
backgroundStroke
|
||||
? /** @type {Array<*>} */ (lastStrokeInstruction)
|
||||
: null
|
||||
);
|
||||
if (declutterGroup) {
|
||||
if (declutterGroupIndex === Math.floor(declutterGroupIndex)) {
|
||||
this.declutterItems.push(this, declutterGroup, feature);
|
||||
}
|
||||
declutterGroupIndex += 1 / declutterGroup[4];
|
||||
|
||||
}
|
||||
}
|
||||
++i;
|
||||
@@ -745,12 +886,24 @@ class Executor {
|
||||
}
|
||||
|
||||
const pathLength = lineStringLength(pixelCoordinates, begin, end, 2);
|
||||
const textLength = textScale * measureAndCacheTextWidth(font, text, cachedWidths);
|
||||
const textLength =
|
||||
textScale * measureAndCacheTextWidth(font, text, cachedWidths);
|
||||
if (overflow || textLength <= pathLength) {
|
||||
const textAlign = this.textStates[textKey].textAlign;
|
||||
const startM = (pathLength - textLength) * TEXT_ALIGN[textAlign];
|
||||
const parts = drawTextOnPath(
|
||||
pixelCoordinates, begin, end, 2, text, startM, maxAngle, textScale, measureAndCacheTextWidth, font, cachedWidths);
|
||||
pixelCoordinates,
|
||||
begin,
|
||||
end,
|
||||
2,
|
||||
text,
|
||||
startM,
|
||||
maxAngle,
|
||||
textScale,
|
||||
measureAndCacheTextWidth,
|
||||
font,
|
||||
cachedWidths
|
||||
);
|
||||
if (parts) {
|
||||
let c, cc, chars, label, part;
|
||||
if (strokeKey) {
|
||||
@@ -759,12 +912,30 @@ class Executor {
|
||||
chars = /** @type {string} */ (part[4]);
|
||||
label = this.createLabel(chars, textKey, '', strokeKey);
|
||||
anchorX = /** @type {number} */ (part[2]) + strokeWidth;
|
||||
anchorY = baseline * label.height + (0.5 - baseline) * 2 * strokeWidth - offsetY;
|
||||
this.replayImageOrLabel_(context,
|
||||
/** @type {number} */ (part[0]), /** @type {number} */ (part[1]), label,
|
||||
anchorX, anchorY, declutterGroup, label.height, 1, 0, 0,
|
||||
/** @type {number} */ (part[3]), pixelRatioScale, false, label.width,
|
||||
defaultPadding, null, null);
|
||||
anchorY =
|
||||
baseline * label.height +
|
||||
(0.5 - baseline) * 2 * strokeWidth -
|
||||
offsetY;
|
||||
this.replayImageOrLabel_(
|
||||
context,
|
||||
/** @type {number} */ (part[0]),
|
||||
/** @type {number} */ (part[1]),
|
||||
label,
|
||||
anchorX,
|
||||
anchorY,
|
||||
declutterGroup,
|
||||
label.height,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
/** @type {number} */ (part[3]),
|
||||
pixelRatioScale,
|
||||
false,
|
||||
label.width,
|
||||
defaultPadding,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
if (fillKey) {
|
||||
@@ -774,11 +945,26 @@ class Executor {
|
||||
label = this.createLabel(chars, textKey, fillKey, '');
|
||||
anchorX = /** @type {number} */ (part[2]);
|
||||
anchorY = baseline * label.height - offsetY;
|
||||
this.replayImageOrLabel_(context,
|
||||
/** @type {number} */ (part[0]), /** @type {number} */ (part[1]), label,
|
||||
anchorX, anchorY, declutterGroup, label.height, 1, 0, 0,
|
||||
/** @type {number} */ (part[3]), pixelRatioScale, false, label.width,
|
||||
defaultPadding, null, null);
|
||||
this.replayImageOrLabel_(
|
||||
context,
|
||||
/** @type {number} */ (part[0]),
|
||||
/** @type {number} */ (part[1]),
|
||||
label,
|
||||
anchorX,
|
||||
anchorY,
|
||||
declutterGroup,
|
||||
label.height,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
/** @type {number} */ (part[3]),
|
||||
pixelRatioScale,
|
||||
false,
|
||||
label.width,
|
||||
defaultPadding,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -884,7 +1070,14 @@ class Executor {
|
||||
*/
|
||||
execute(context, transform, viewRotation, snapToPixel) {
|
||||
this.viewRotation_ = viewRotation;
|
||||
this.execute_(context, transform, this.instructions, snapToPixel, undefined, undefined);
|
||||
this.execute_(
|
||||
context,
|
||||
transform,
|
||||
this.instructions,
|
||||
snapToPixel,
|
||||
undefined,
|
||||
undefined
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -906,10 +1099,15 @@ class Executor {
|
||||
opt_hitExtent
|
||||
) {
|
||||
this.viewRotation_ = viewRotation;
|
||||
return this.execute_(context, transform,
|
||||
this.hitDetectionInstructions, true, opt_featureCallback, opt_hitExtent);
|
||||
return this.execute_(
|
||||
context,
|
||||
transform,
|
||||
this.hitDetectionInstructions,
|
||||
true,
|
||||
opt_featureCallback,
|
||||
opt_hitExtent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default Executor;
|
||||
|
||||
@@ -2,14 +2,17 @@
|
||||
* @module ol/render/canvas/ExecutorGroup
|
||||
*/
|
||||
|
||||
import {numberSafeCompareFunction} from '../../array.js';
|
||||
import {createCanvasContext2D} from '../../dom.js';
|
||||
import {buffer, createEmpty, extendCoordinate} from '../../extent.js';
|
||||
import {transform2D} from '../../geom/flat/transform.js';
|
||||
import {isEmpty} from '../../obj.js';
|
||||
import BuilderType from './BuilderType.js';
|
||||
import {create as createTransform, compose as composeTransform} from '../../transform.js';
|
||||
import Executor from './Executor.js';
|
||||
import {buffer, createEmpty, extendCoordinate} from '../../extent.js';
|
||||
import {
|
||||
compose as composeTransform,
|
||||
create as createTransform,
|
||||
} from '../../transform.js';
|
||||
import {createCanvasContext2D} from '../../dom.js';
|
||||
import {isEmpty} from '../../obj.js';
|
||||
import {numberSafeCompareFunction} from '../../array.js';
|
||||
import {transform2D} from '../../geom/flat/transform.js';
|
||||
|
||||
/**
|
||||
* @const
|
||||
@@ -21,10 +24,9 @@ const ORDER = [
|
||||
BuilderType.LINE_STRING,
|
||||
BuilderType.IMAGE,
|
||||
BuilderType.TEXT,
|
||||
BuilderType.DEFAULT
|
||||
BuilderType.DEFAULT,
|
||||
];
|
||||
|
||||
|
||||
class ExecutorGroup {
|
||||
/**
|
||||
* @param {import("../../extent.js").Extent} maxExtent Max extent for clipping. When a
|
||||
@@ -38,8 +40,14 @@ class ExecutorGroup {
|
||||
* The serializable instructions.
|
||||
* @param {number=} opt_renderBuffer Optional rendering buffer.
|
||||
*/
|
||||
constructor(maxExtent, resolution, pixelRatio, overlaps, allInstructions, opt_renderBuffer) {
|
||||
|
||||
constructor(
|
||||
maxExtent,
|
||||
resolution,
|
||||
pixelRatio,
|
||||
overlaps,
|
||||
allInstructions,
|
||||
opt_renderBuffer
|
||||
) {
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../../extent.js").Extent}
|
||||
@@ -121,12 +129,15 @@ class ExecutorGroup {
|
||||
for (const builderType in instructionByZindex) {
|
||||
const instructions = instructionByZindex[builderType];
|
||||
executors[builderType] = new Executor(
|
||||
this.resolution_, this.pixelRatio_, this.overlaps_, instructions);
|
||||
this.resolution_,
|
||||
this.pixelRatio_,
|
||||
this.overlaps_,
|
||||
instructions
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array<BuilderType>} executors Executors.
|
||||
* @return {boolean} Has executors of the provided types.
|
||||
@@ -143,7 +154,6 @@ class ExecutorGroup {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {import("../../coordinate.js").Coordinate} coordinate Coordinate.
|
||||
* @param {number} resolution Resolution.
|
||||
@@ -162,21 +172,31 @@ class ExecutorGroup {
|
||||
callback,
|
||||
declutteredFeatures
|
||||
) {
|
||||
|
||||
hitTolerance = Math.round(hitTolerance);
|
||||
const contextSize = hitTolerance * 2 + 1;
|
||||
const transform = composeTransform(this.hitDetectionTransform_,
|
||||
hitTolerance + 0.5, hitTolerance + 0.5,
|
||||
1 / resolution, -1 / resolution,
|
||||
const transform = composeTransform(
|
||||
this.hitDetectionTransform_,
|
||||
hitTolerance + 0.5,
|
||||
hitTolerance + 0.5,
|
||||
1 / resolution,
|
||||
-1 / resolution,
|
||||
-rotation,
|
||||
-coordinate[0], -coordinate[1]);
|
||||
-coordinate[0],
|
||||
-coordinate[1]
|
||||
);
|
||||
|
||||
if (!this.hitDetectionContext_) {
|
||||
this.hitDetectionContext_ = createCanvasContext2D(contextSize, contextSize);
|
||||
this.hitDetectionContext_ = createCanvasContext2D(
|
||||
contextSize,
|
||||
contextSize
|
||||
);
|
||||
}
|
||||
const context = this.hitDetectionContext_;
|
||||
|
||||
if (context.canvas.width !== contextSize || context.canvas.height !== contextSize) {
|
||||
if (
|
||||
context.canvas.width !== contextSize ||
|
||||
context.canvas.height !== contextSize
|
||||
) {
|
||||
context.canvas.width = contextSize;
|
||||
context.canvas.height = contextSize;
|
||||
} else {
|
||||
@@ -190,7 +210,11 @@ class ExecutorGroup {
|
||||
if (this.renderBuffer_ !== undefined) {
|
||||
hitExtent = createEmpty();
|
||||
extendCoordinate(hitExtent, coordinate);
|
||||
buffer(hitExtent, resolution * (this.renderBuffer_ + hitTolerance), hitExtent);
|
||||
buffer(
|
||||
hitExtent,
|
||||
resolution * (this.renderBuffer_ + hitTolerance),
|
||||
hitExtent
|
||||
);
|
||||
}
|
||||
|
||||
const mask = getCircleArray(hitTolerance);
|
||||
@@ -202,14 +226,21 @@ class ExecutorGroup {
|
||||
* @return {?} Callback result.
|
||||
*/
|
||||
function featureCallback(feature) {
|
||||
const imageData = context.getImageData(0, 0, contextSize, contextSize).data;
|
||||
const imageData = context.getImageData(0, 0, contextSize, contextSize)
|
||||
.data;
|
||||
for (let i = 0; i < contextSize; i++) {
|
||||
for (let j = 0; j < contextSize; j++) {
|
||||
if (mask[i][j]) {
|
||||
if (imageData[(j * contextSize + i) * 4 + 3] > 0) {
|
||||
let result;
|
||||
if (!(declutteredFeatures && (builderType == BuilderType.IMAGE || builderType == BuilderType.TEXT)) ||
|
||||
declutteredFeatures.indexOf(feature) !== -1) {
|
||||
if (
|
||||
!(
|
||||
declutteredFeatures &&
|
||||
(builderType == BuilderType.IMAGE ||
|
||||
builderType == BuilderType.TEXT)
|
||||
) ||
|
||||
declutteredFeatures.indexOf(feature) !== -1
|
||||
) {
|
||||
result = callback(feature);
|
||||
}
|
||||
if (result) {
|
||||
@@ -236,7 +267,13 @@ class ExecutorGroup {
|
||||
builderType = ORDER[j];
|
||||
executor = executors[builderType];
|
||||
if (executor !== undefined) {
|
||||
result = executor.executeHitDetection(context, transform, rotation, featureCallback, hitExtent);
|
||||
result = executor.executeHitDetection(
|
||||
context,
|
||||
transform,
|
||||
rotation,
|
||||
featureCallback,
|
||||
hitExtent
|
||||
);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
@@ -260,8 +297,7 @@ class ExecutorGroup {
|
||||
const maxX = maxExtent[2];
|
||||
const maxY = maxExtent[3];
|
||||
const flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY];
|
||||
transform2D(
|
||||
flatClipCoords, 0, 8, 2, transform, flatClipCoords);
|
||||
transform2D(flatClipCoords, 0, 8, 2, transform, flatClipCoords);
|
||||
return flatClipCoords;
|
||||
}
|
||||
|
||||
@@ -281,8 +317,14 @@ class ExecutorGroup {
|
||||
* Default is {@link module:ol/render/replay~ORDER}
|
||||
* @param {Object<string, import("../canvas.js").DeclutterGroup>=} opt_declutterReplays Declutter replays.
|
||||
*/
|
||||
execute(context, transform, viewRotation, snapToPixel, opt_builderTypes, opt_declutterReplays) {
|
||||
|
||||
execute(
|
||||
context,
|
||||
transform,
|
||||
viewRotation,
|
||||
snapToPixel,
|
||||
opt_builderTypes,
|
||||
opt_declutterReplays
|
||||
) {
|
||||
/** @type {Array<number>} */
|
||||
const zs = Object.keys(this.executorsByZIndex_).map(Number);
|
||||
zs.sort(numberSafeCompareFunction);
|
||||
@@ -303,8 +345,11 @@ class ExecutorGroup {
|
||||
const builderType = builderTypes[j];
|
||||
replay = replays[builderType];
|
||||
if (replay !== undefined) {
|
||||
if (opt_declutterReplays &&
|
||||
(builderType == BuilderType.IMAGE || builderType == BuilderType.TEXT)) {
|
||||
if (
|
||||
opt_declutterReplays &&
|
||||
(builderType == BuilderType.IMAGE ||
|
||||
builderType == BuilderType.TEXT)
|
||||
) {
|
||||
const declutter = opt_declutterReplays[zIndexKey];
|
||||
if (!declutter) {
|
||||
opt_declutterReplays[zIndexKey] = [replay, transform.slice(0)];
|
||||
@@ -324,17 +369,15 @@ class ExecutorGroup {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This cache is used for storing calculated pixel circles for increasing performance.
|
||||
* It is a static property to allow each Replaygroup to access it.
|
||||
* @type {Object<number, Array<Array<(boolean|undefined)>>>}
|
||||
*/
|
||||
const circleArrayCache = {
|
||||
0: [[true]]
|
||||
0: [[true]],
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This method fills a row in the array from the given coordinate to the
|
||||
* middle with `true`.
|
||||
@@ -356,7 +399,6 @@ function fillCircleArrayRowToMiddle(array, x, y) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This methods creates a circle inside a fitting array. Points inside the
|
||||
* circle are marked by true, points on the outside are undefined.
|
||||
@@ -402,7 +444,6 @@ export function getCircleArray(radius) {
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {!Object<string, Array<*>>} declutterReplays Declutter replays.
|
||||
* @param {CanvasRenderingContext2D} context Context.
|
||||
@@ -411,18 +452,27 @@ export function getCircleArray(radius) {
|
||||
* @param {boolean} snapToPixel Snap point symbols and text to integer pixels.
|
||||
* @param {Array<import("../../PluggableMap.js").DeclutterItems>} declutterItems Declutter items.
|
||||
*/
|
||||
export function replayDeclutter(declutterReplays, context, rotation, opacity, snapToPixel, declutterItems) {
|
||||
const zs = Object.keys(declutterReplays).map(Number).sort(numberSafeCompareFunction);
|
||||
export function replayDeclutter(
|
||||
declutterReplays,
|
||||
context,
|
||||
rotation,
|
||||
opacity,
|
||||
snapToPixel,
|
||||
declutterItems
|
||||
) {
|
||||
const zs = Object.keys(declutterReplays)
|
||||
.map(Number)
|
||||
.sort(numberSafeCompareFunction);
|
||||
for (let z = 0, zz = zs.length; z < zz; ++z) {
|
||||
const executorData = declutterReplays[zs[z].toString()];
|
||||
let currentExecutor;
|
||||
for (let i = 0, ii = executorData.length; i < ii;) {
|
||||
for (let i = 0, ii = executorData.length; i < ii; ) {
|
||||
const executor = executorData[i++];
|
||||
if (executor !== currentExecutor) {
|
||||
currentExecutor = executor;
|
||||
declutterItems.push({
|
||||
items: executor.declutterItems,
|
||||
opacity: opacity
|
||||
opacity: opacity,
|
||||
});
|
||||
}
|
||||
const transform = executorData[i++];
|
||||
@@ -431,5 +481,4 @@ export function replayDeclutter(declutterReplays, context, rotation, opacity, sn
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default ExecutorGroup;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* @module ol/render/canvas/ImageBuilder
|
||||
*/
|
||||
import CanvasInstruction from './Instruction.js';
|
||||
import CanvasBuilder from './Builder.js';
|
||||
import CanvasInstruction from './Instruction.js';
|
||||
|
||||
class CanvasImageBuilder extends CanvasBuilder {
|
||||
/**
|
||||
@@ -91,7 +91,6 @@ class CanvasImageBuilder extends CanvasBuilder {
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
this.width_ = undefined;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +102,14 @@ class CanvasImageBuilder extends CanvasBuilder {
|
||||
* @return {number} My end.
|
||||
*/
|
||||
drawCoordinates_(flatCoordinates, offset, end, stride) {
|
||||
return this.appendFlatCoordinates(flatCoordinates, offset, end, stride, false, false);
|
||||
return this.appendFlatCoordinates(
|
||||
flatCoordinates,
|
||||
offset,
|
||||
end,
|
||||
stride,
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,20 +124,47 @@ class CanvasImageBuilder extends CanvasBuilder {
|
||||
const flatCoordinates = pointGeometry.getFlatCoordinates();
|
||||
const stride = pointGeometry.getStride();
|
||||
const myBegin = this.coordinates.length;
|
||||
const myEnd = this.drawCoordinates_(flatCoordinates, 0, flatCoordinates.length, stride);
|
||||
const myEnd = this.drawCoordinates_(
|
||||
flatCoordinates,
|
||||
0,
|
||||
flatCoordinates.length,
|
||||
stride
|
||||
);
|
||||
this.instructions.push([
|
||||
CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.image_,
|
||||
CanvasInstruction.DRAW_IMAGE,
|
||||
myBegin,
|
||||
myEnd,
|
||||
this.image_,
|
||||
// Remaining arguments to DRAW_IMAGE are in alphabetical order
|
||||
this.anchorX_, this.anchorY_, this.declutterGroups_, this.height_, this.opacity_,
|
||||
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
|
||||
this.scale_ * this.pixelRatio, this.width_
|
||||
this.anchorX_,
|
||||
this.anchorY_,
|
||||
this.declutterGroups_,
|
||||
this.height_,
|
||||
this.opacity_,
|
||||
this.originX_,
|
||||
this.originY_,
|
||||
this.rotateWithView_,
|
||||
this.rotation_,
|
||||
this.scale_ * this.pixelRatio,
|
||||
this.width_,
|
||||
]);
|
||||
this.hitDetectionInstructions.push([
|
||||
CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.hitDetectionImage_,
|
||||
CanvasInstruction.DRAW_IMAGE,
|
||||
myBegin,
|
||||
myEnd,
|
||||
this.hitDetectionImage_,
|
||||
// Remaining arguments to DRAW_IMAGE are in alphabetical order
|
||||
this.anchorX_, this.anchorY_, this.declutterGroups_, this.height_, this.opacity_,
|
||||
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
|
||||
this.scale_, this.width_
|
||||
this.anchorX_,
|
||||
this.anchorY_,
|
||||
this.declutterGroups_,
|
||||
this.height_,
|
||||
this.opacity_,
|
||||
this.originX_,
|
||||
this.originY_,
|
||||
this.rotateWithView_,
|
||||
this.rotation_,
|
||||
this.scale_,
|
||||
this.width_,
|
||||
]);
|
||||
this.endGeometry(feature);
|
||||
}
|
||||
@@ -149,20 +182,46 @@ class CanvasImageBuilder extends CanvasBuilder {
|
||||
const stride = multiPointGeometry.getStride();
|
||||
const myBegin = this.coordinates.length;
|
||||
const myEnd = this.drawCoordinates_(
|
||||
flatCoordinates, 0, flatCoordinates.length, stride);
|
||||
flatCoordinates,
|
||||
0,
|
||||
flatCoordinates.length,
|
||||
stride
|
||||
);
|
||||
this.instructions.push([
|
||||
CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.image_,
|
||||
CanvasInstruction.DRAW_IMAGE,
|
||||
myBegin,
|
||||
myEnd,
|
||||
this.image_,
|
||||
// Remaining arguments to DRAW_IMAGE are in alphabetical order
|
||||
this.anchorX_, this.anchorY_, this.declutterGroups_, this.height_, this.opacity_,
|
||||
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
|
||||
this.scale_ * this.pixelRatio, this.width_
|
||||
this.anchorX_,
|
||||
this.anchorY_,
|
||||
this.declutterGroups_,
|
||||
this.height_,
|
||||
this.opacity_,
|
||||
this.originX_,
|
||||
this.originY_,
|
||||
this.rotateWithView_,
|
||||
this.rotation_,
|
||||
this.scale_ * this.pixelRatio,
|
||||
this.width_,
|
||||
]);
|
||||
this.hitDetectionInstructions.push([
|
||||
CanvasInstruction.DRAW_IMAGE, myBegin, myEnd, this.hitDetectionImage_,
|
||||
CanvasInstruction.DRAW_IMAGE,
|
||||
myBegin,
|
||||
myEnd,
|
||||
this.hitDetectionImage_,
|
||||
// Remaining arguments to DRAW_IMAGE are in alphabetical order
|
||||
this.anchorX_, this.anchorY_, this.declutterGroups_, this.height_, this.opacity_,
|
||||
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
|
||||
this.scale_, this.width_
|
||||
this.anchorX_,
|
||||
this.anchorY_,
|
||||
this.declutterGroups_,
|
||||
this.height_,
|
||||
this.opacity_,
|
||||
this.originX_,
|
||||
this.originY_,
|
||||
this.rotateWithView_,
|
||||
this.rotation_,
|
||||
this.scale_,
|
||||
this.width_,
|
||||
]);
|
||||
this.endGeometry(feature);
|
||||
}
|
||||
@@ -214,5 +273,4 @@ class CanvasImageBuilder extends CanvasBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default CanvasImageBuilder;
|
||||
|
||||
@@ -5,16 +5,30 @@
|
||||
// FIXME need to handle large thick features (where pixel size matters)
|
||||
// FIXME add offset and end to ol/geom/flat/transform~transform2D?
|
||||
|
||||
import {equals} from '../../array.js';
|
||||
import {asColorLike} from '../../colorlike.js';
|
||||
import {intersects} from '../../extent.js';
|
||||
import GeometryType from '../../geom/GeometryType.js';
|
||||
import {transformGeom2D} from '../../geom/SimpleGeometry.js';
|
||||
import {transform2D} from '../../geom/flat/transform.js';
|
||||
import VectorContext from '../VectorContext.js';
|
||||
import {defaultTextAlign, defaultFillStyle, defaultLineCap, defaultLineDash, defaultLineDashOffset, defaultLineJoin, defaultLineWidth, defaultMiterLimit, defaultStrokeStyle, defaultTextBaseline, defaultFont} from '../canvas.js';
|
||||
import {create as createTransform, compose as composeTransform} from '../../transform.js';
|
||||
|
||||
import {asColorLike} from '../../colorlike.js';
|
||||
import {
|
||||
compose as composeTransform,
|
||||
create as createTransform,
|
||||
} from '../../transform.js';
|
||||
import {
|
||||
defaultFillStyle,
|
||||
defaultFont,
|
||||
defaultLineCap,
|
||||
defaultLineDash,
|
||||
defaultLineDashOffset,
|
||||
defaultLineJoin,
|
||||
defaultLineWidth,
|
||||
defaultMiterLimit,
|
||||
defaultStrokeStyle,
|
||||
defaultTextAlign,
|
||||
defaultTextBaseline,
|
||||
} from '../canvas.js';
|
||||
import {equals} from '../../array.js';
|
||||
import {intersects} from '../../extent.js';
|
||||
import {transform2D} from '../../geom/flat/transform.js';
|
||||
import {transformGeom2D} from '../../geom/SimpleGeometry.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
@@ -35,7 +49,15 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
* @param {number=} opt_squaredTolerance Optional squared tolerance for simplification.
|
||||
* @param {import("../../proj.js").TransformFunction=} opt_userTransform Transform from user to view projection.
|
||||
*/
|
||||
constructor(context, pixelRatio, extent, transform, viewRotation, opt_squaredTolerance, opt_userTransform) {
|
||||
constructor(
|
||||
context,
|
||||
pixelRatio,
|
||||
extent,
|
||||
transform,
|
||||
viewRotation,
|
||||
opt_squaredTolerance,
|
||||
opt_userTransform
|
||||
) {
|
||||
super();
|
||||
|
||||
/**
|
||||
@@ -241,7 +263,6 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
* @type {import("../../transform.js").Transform}
|
||||
*/
|
||||
this.tmpLocalTransform_ = createTransform();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,8 +277,13 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
return;
|
||||
}
|
||||
const pixelCoordinates = transform2D(
|
||||
flatCoordinates, offset, end, 2, this.transform_,
|
||||
this.pixelCoordinates_);
|
||||
flatCoordinates,
|
||||
offset,
|
||||
end,
|
||||
2,
|
||||
this.transform_,
|
||||
this.pixelCoordinates_
|
||||
);
|
||||
const context = this.context_;
|
||||
const localTransform = this.tmpLocalTransform_;
|
||||
const alpha = context.globalAlpha;
|
||||
@@ -274,16 +300,29 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
if (rotation !== 0 || this.imageScale_ != 1) {
|
||||
const centerX = x + this.imageAnchorX_;
|
||||
const centerY = y + this.imageAnchorY_;
|
||||
composeTransform(localTransform,
|
||||
centerX, centerY,
|
||||
this.imageScale_, this.imageScale_,
|
||||
composeTransform(
|
||||
localTransform,
|
||||
centerX,
|
||||
centerY,
|
||||
this.imageScale_,
|
||||
this.imageScale_,
|
||||
rotation,
|
||||
-centerX, -centerY);
|
||||
-centerX,
|
||||
-centerY
|
||||
);
|
||||
context.setTransform.apply(context, localTransform);
|
||||
}
|
||||
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);
|
||||
@@ -312,8 +351,13 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
}
|
||||
this.setContextTextState_(this.textState_);
|
||||
const pixelCoordinates = transform2D(
|
||||
flatCoordinates, offset, end, stride, this.transform_,
|
||||
this.pixelCoordinates_);
|
||||
flatCoordinates,
|
||||
offset,
|
||||
end,
|
||||
stride,
|
||||
this.transform_,
|
||||
this.pixelCoordinates_
|
||||
);
|
||||
const context = this.context_;
|
||||
let rotation = this.textRotation_;
|
||||
if (this.textRotateWithView_) {
|
||||
@@ -323,11 +367,16 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
const x = pixelCoordinates[offset] + this.textOffsetX_;
|
||||
const y = pixelCoordinates[offset + 1] + this.textOffsetY_;
|
||||
if (rotation !== 0 || this.textScale_ != 1) {
|
||||
const localTransform = composeTransform(this.tmpLocalTransform_,
|
||||
x, y,
|
||||
this.textScale_, this.textScale_,
|
||||
const localTransform = composeTransform(
|
||||
this.tmpLocalTransform_,
|
||||
x,
|
||||
y,
|
||||
this.textScale_,
|
||||
this.textScale_,
|
||||
rotation,
|
||||
-x, -y);
|
||||
-x,
|
||||
-y
|
||||
);
|
||||
context.setTransform.apply(context, localTransform);
|
||||
}
|
||||
if (this.textStrokeState_) {
|
||||
@@ -354,8 +403,13 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
moveToLineTo_(flatCoordinates, offset, end, stride, close) {
|
||||
const context = this.context_;
|
||||
const pixelCoordinates = transform2D(
|
||||
flatCoordinates, offset, end, stride, this.transform_,
|
||||
this.pixelCoordinates_);
|
||||
flatCoordinates,
|
||||
offset,
|
||||
end,
|
||||
stride,
|
||||
this.transform_,
|
||||
this.pixelCoordinates_
|
||||
);
|
||||
context.moveTo(pixelCoordinates[0], pixelCoordinates[1]);
|
||||
let length = pixelCoordinates.length;
|
||||
if (close) {
|
||||
@@ -380,7 +434,13 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
*/
|
||||
drawRings_(flatCoordinates, offset, ends, stride) {
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
offset = this.moveToLineTo_(flatCoordinates, offset, ends[i], stride, true);
|
||||
offset = this.moveToLineTo_(
|
||||
flatCoordinates,
|
||||
offset,
|
||||
ends[i],
|
||||
stride,
|
||||
true
|
||||
);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
@@ -404,14 +464,22 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
this.setContextStrokeState_(this.strokeState_);
|
||||
}
|
||||
const pixelCoordinates = transformGeom2D(
|
||||
geometry, this.transform_, this.pixelCoordinates_);
|
||||
geometry,
|
||||
this.transform_,
|
||||
this.pixelCoordinates_
|
||||
);
|
||||
const dx = pixelCoordinates[2] - pixelCoordinates[0];
|
||||
const dy = pixelCoordinates[3] - pixelCoordinates[1];
|
||||
const radius = Math.sqrt(dx * dx + dy * dy);
|
||||
const context = this.context_;
|
||||
context.beginPath();
|
||||
context.arc(
|
||||
pixelCoordinates[0], pixelCoordinates[1], radius, 0, 2 * Math.PI);
|
||||
pixelCoordinates[0],
|
||||
pixelCoordinates[1],
|
||||
radius,
|
||||
0,
|
||||
2 * Math.PI
|
||||
);
|
||||
if (this.fillState_) {
|
||||
context.fill();
|
||||
}
|
||||
@@ -455,28 +523,44 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
const type = geometry.getType();
|
||||
switch (type) {
|
||||
case GeometryType.POINT:
|
||||
this.drawPoint(/** @type {import("../../geom/Point.js").default} */ (geometry));
|
||||
this.drawPoint(
|
||||
/** @type {import("../../geom/Point.js").default} */ (geometry)
|
||||
);
|
||||
break;
|
||||
case GeometryType.LINE_STRING:
|
||||
this.drawLineString(/** @type {import("../../geom/LineString.js").default} */ (geometry));
|
||||
this.drawLineString(
|
||||
/** @type {import("../../geom/LineString.js").default} */ (geometry)
|
||||
);
|
||||
break;
|
||||
case GeometryType.POLYGON:
|
||||
this.drawPolygon(/** @type {import("../../geom/Polygon.js").default} */ (geometry));
|
||||
this.drawPolygon(
|
||||
/** @type {import("../../geom/Polygon.js").default} */ (geometry)
|
||||
);
|
||||
break;
|
||||
case GeometryType.MULTI_POINT:
|
||||
this.drawMultiPoint(/** @type {import("../../geom/MultiPoint.js").default} */ (geometry));
|
||||
this.drawMultiPoint(
|
||||
/** @type {import("../../geom/MultiPoint.js").default} */ (geometry)
|
||||
);
|
||||
break;
|
||||
case GeometryType.MULTI_LINE_STRING:
|
||||
this.drawMultiLineString(/** @type {import("../../geom/MultiLineString.js").default} */ (geometry));
|
||||
this.drawMultiLineString(
|
||||
/** @type {import("../../geom/MultiLineString.js").default} */ (geometry)
|
||||
);
|
||||
break;
|
||||
case GeometryType.MULTI_POLYGON:
|
||||
this.drawMultiPolygon(/** @type {import("../../geom/MultiPolygon.js").default} */ (geometry));
|
||||
this.drawMultiPolygon(
|
||||
/** @type {import("../../geom/MultiPolygon.js").default} */ (geometry)
|
||||
);
|
||||
break;
|
||||
case GeometryType.GEOMETRY_COLLECTION:
|
||||
this.drawGeometryCollection(/** @type {import("../../geom/GeometryCollection.js").default} */ (geometry));
|
||||
this.drawGeometryCollection(
|
||||
/** @type {import("../../geom/GeometryCollection.js").default} */ (geometry)
|
||||
);
|
||||
break;
|
||||
case GeometryType.CIRCLE:
|
||||
this.drawCircle(/** @type {import("../../geom/Circle.js").default} */ (geometry));
|
||||
this.drawCircle(
|
||||
/** @type {import("../../geom/Circle.js").default} */ (geometry)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
@@ -522,7 +606,10 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
*/
|
||||
drawPoint(geometry) {
|
||||
if (this.squaredTolerance_) {
|
||||
geometry = /** @type {import("../../geom/Point.js").default} */ (geometry.simplifyTransformed(this.squaredTolerance_, this.userTransform_));
|
||||
geometry = /** @type {import("../../geom/Point.js").default} */ (geometry.simplifyTransformed(
|
||||
this.squaredTolerance_,
|
||||
this.userTransform_
|
||||
));
|
||||
}
|
||||
const flatCoordinates = geometry.getFlatCoordinates();
|
||||
const stride = geometry.getStride();
|
||||
@@ -542,7 +629,10 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
*/
|
||||
drawMultiPoint(geometry) {
|
||||
if (this.squaredTolerance_) {
|
||||
geometry = /** @type {import("../../geom/MultiPoint.js").default} */ (geometry.simplifyTransformed(this.squaredTolerance_, this.userTransform_));
|
||||
geometry = /** @type {import("../../geom/MultiPoint.js").default} */ (geometry.simplifyTransformed(
|
||||
this.squaredTolerance_,
|
||||
this.userTransform_
|
||||
));
|
||||
}
|
||||
const flatCoordinates = geometry.getFlatCoordinates();
|
||||
const stride = geometry.getStride();
|
||||
@@ -562,7 +652,10 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
*/
|
||||
drawLineString(geometry) {
|
||||
if (this.squaredTolerance_) {
|
||||
geometry = /** @type {import("../../geom/LineString.js").default} */ (geometry.simplifyTransformed(this.squaredTolerance_, this.userTransform_));
|
||||
geometry = /** @type {import("../../geom/LineString.js").default} */ (geometry.simplifyTransformed(
|
||||
this.squaredTolerance_,
|
||||
this.userTransform_
|
||||
));
|
||||
}
|
||||
if (!intersects(this.extent_, geometry.getExtent())) {
|
||||
return;
|
||||
@@ -572,8 +665,13 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
const context = this.context_;
|
||||
const flatCoordinates = geometry.getFlatCoordinates();
|
||||
context.beginPath();
|
||||
this.moveToLineTo_(flatCoordinates, 0, flatCoordinates.length,
|
||||
geometry.getStride(), false);
|
||||
this.moveToLineTo_(
|
||||
flatCoordinates,
|
||||
0,
|
||||
flatCoordinates.length,
|
||||
geometry.getStride(),
|
||||
false
|
||||
);
|
||||
context.stroke();
|
||||
}
|
||||
if (this.text_ !== '') {
|
||||
@@ -590,7 +688,10 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
*/
|
||||
drawMultiLineString(geometry) {
|
||||
if (this.squaredTolerance_) {
|
||||
geometry = /** @type {import("../../geom/MultiLineString.js").default} */ (geometry.simplifyTransformed(this.squaredTolerance_, this.userTransform_));
|
||||
geometry = /** @type {import("../../geom/MultiLineString.js").default} */ (geometry.simplifyTransformed(
|
||||
this.squaredTolerance_,
|
||||
this.userTransform_
|
||||
));
|
||||
}
|
||||
const geometryExtent = geometry.getExtent();
|
||||
if (!intersects(this.extent_, geometryExtent)) {
|
||||
@@ -605,7 +706,13 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
const stride = geometry.getStride();
|
||||
context.beginPath();
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
offset = this.moveToLineTo_(flatCoordinates, offset, ends[i], stride, false);
|
||||
offset = this.moveToLineTo_(
|
||||
flatCoordinates,
|
||||
offset,
|
||||
ends[i],
|
||||
stride,
|
||||
false
|
||||
);
|
||||
}
|
||||
context.stroke();
|
||||
}
|
||||
@@ -623,7 +730,10 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
*/
|
||||
drawPolygon(geometry) {
|
||||
if (this.squaredTolerance_) {
|
||||
geometry = /** @type {import("../../geom/Polygon.js").default} */ (geometry.simplifyTransformed(this.squaredTolerance_, this.userTransform_));
|
||||
geometry = /** @type {import("../../geom/Polygon.js").default} */ (geometry.simplifyTransformed(
|
||||
this.squaredTolerance_,
|
||||
this.userTransform_
|
||||
));
|
||||
}
|
||||
if (!intersects(this.extent_, geometry.getExtent())) {
|
||||
return;
|
||||
@@ -637,8 +747,12 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
}
|
||||
const context = this.context_;
|
||||
context.beginPath();
|
||||
this.drawRings_(geometry.getOrientedFlatCoordinates(),
|
||||
0, /** @type {Array<number>} */ (geometry.getEnds()), geometry.getStride());
|
||||
this.drawRings_(
|
||||
geometry.getOrientedFlatCoordinates(),
|
||||
0,
|
||||
/** @type {Array<number>} */ (geometry.getEnds()),
|
||||
geometry.getStride()
|
||||
);
|
||||
if (this.fillState_) {
|
||||
context.fill();
|
||||
}
|
||||
@@ -659,7 +773,10 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
*/
|
||||
drawMultiPolygon(geometry) {
|
||||
if (this.squaredTolerance_) {
|
||||
geometry = /** @type {import("../../geom/MultiPolygon.js").default} */ (geometry.simplifyTransformed(this.squaredTolerance_, this.userTransform_));
|
||||
geometry = /** @type {import("../../geom/MultiPolygon.js").default} */ (geometry.simplifyTransformed(
|
||||
this.squaredTolerance_,
|
||||
this.userTransform_
|
||||
));
|
||||
}
|
||||
if (!intersects(this.extent_, geometry.getExtent())) {
|
||||
return;
|
||||
@@ -704,7 +821,7 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
if (!contextFillState) {
|
||||
context.fillStyle = fillState.fillStyle;
|
||||
this.contextFillState_ = {
|
||||
fillStyle: fillState.fillStyle
|
||||
fillStyle: fillState.fillStyle,
|
||||
};
|
||||
} else {
|
||||
if (contextFillState.fillStyle != fillState.fillStyle) {
|
||||
@@ -738,7 +855,7 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
lineJoin: strokeState.lineJoin,
|
||||
lineWidth: strokeState.lineWidth,
|
||||
miterLimit: strokeState.miterLimit,
|
||||
strokeStyle: strokeState.strokeStyle
|
||||
strokeStyle: strokeState.strokeStyle,
|
||||
};
|
||||
} else {
|
||||
if (contextStrokeState.lineCap != strokeState.lineCap) {
|
||||
@@ -747,7 +864,9 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
}
|
||||
if (context.setLineDash) {
|
||||
if (!equals(contextStrokeState.lineDash, strokeState.lineDash)) {
|
||||
context.setLineDash(contextStrokeState.lineDash = strokeState.lineDash);
|
||||
context.setLineDash(
|
||||
(contextStrokeState.lineDash = strokeState.lineDash)
|
||||
);
|
||||
}
|
||||
if (contextStrokeState.lineDashOffset != strokeState.lineDashOffset) {
|
||||
contextStrokeState.lineDashOffset = strokeState.lineDashOffset;
|
||||
@@ -780,8 +899,9 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
setContextTextState_(textState) {
|
||||
const context = this.context_;
|
||||
const contextTextState = this.contextTextState_;
|
||||
const textAlign = textState.textAlign ?
|
||||
textState.textAlign : defaultTextAlign;
|
||||
const textAlign = textState.textAlign
|
||||
? textState.textAlign
|
||||
: defaultTextAlign;
|
||||
if (!contextTextState) {
|
||||
context.font = textState.font;
|
||||
context.textAlign = /** @type {CanvasTextAlign} */ (textAlign);
|
||||
@@ -789,7 +909,7 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
this.contextTextState_ = {
|
||||
font: textState.font,
|
||||
textAlign: textAlign,
|
||||
textBaseline: textState.textBaseline
|
||||
textBaseline: textState.textBaseline,
|
||||
};
|
||||
} else {
|
||||
if (contextTextState.font != textState.font) {
|
||||
@@ -820,8 +940,9 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
} else {
|
||||
const fillStyleColor = fillStyle.getColor();
|
||||
this.fillState_ = {
|
||||
fillStyle: asColorLike(fillStyleColor ?
|
||||
fillStyleColor : defaultFillStyle)
|
||||
fillStyle: asColorLike(
|
||||
fillStyleColor ? fillStyleColor : defaultFillStyle
|
||||
),
|
||||
};
|
||||
}
|
||||
if (!strokeStyle) {
|
||||
@@ -835,20 +956,30 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
const strokeStyleWidth = strokeStyle.getWidth();
|
||||
const strokeStyleMiterLimit = strokeStyle.getMiterLimit();
|
||||
this.strokeState_ = {
|
||||
lineCap: strokeStyleLineCap !== undefined ?
|
||||
strokeStyleLineCap : defaultLineCap,
|
||||
lineDash: strokeStyleLineDash ?
|
||||
strokeStyleLineDash : defaultLineDash,
|
||||
lineDashOffset: strokeStyleLineDashOffset ?
|
||||
strokeStyleLineDashOffset : defaultLineDashOffset,
|
||||
lineJoin: strokeStyleLineJoin !== undefined ?
|
||||
strokeStyleLineJoin : defaultLineJoin,
|
||||
lineWidth: this.pixelRatio_ * (strokeStyleWidth !== undefined ?
|
||||
strokeStyleWidth : defaultLineWidth),
|
||||
miterLimit: strokeStyleMiterLimit !== undefined ?
|
||||
strokeStyleMiterLimit : defaultMiterLimit,
|
||||
strokeStyle: asColorLike(strokeStyleColor ?
|
||||
strokeStyleColor : defaultStrokeStyle)
|
||||
lineCap:
|
||||
strokeStyleLineCap !== undefined
|
||||
? strokeStyleLineCap
|
||||
: defaultLineCap,
|
||||
lineDash: strokeStyleLineDash ? strokeStyleLineDash : defaultLineDash,
|
||||
lineDashOffset: strokeStyleLineDashOffset
|
||||
? strokeStyleLineDashOffset
|
||||
: defaultLineDashOffset,
|
||||
lineJoin:
|
||||
strokeStyleLineJoin !== undefined
|
||||
? strokeStyleLineJoin
|
||||
: defaultLineJoin,
|
||||
lineWidth:
|
||||
this.pixelRatio_ *
|
||||
(strokeStyleWidth !== undefined
|
||||
? strokeStyleWidth
|
||||
: defaultLineWidth),
|
||||
miterLimit:
|
||||
strokeStyleMiterLimit !== undefined
|
||||
? strokeStyleMiterLimit
|
||||
: defaultMiterLimit,
|
||||
strokeStyle: asColorLike(
|
||||
strokeStyleColor ? strokeStyleColor : defaultStrokeStyle
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -898,8 +1029,9 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
} else {
|
||||
const textFillStyleColor = textFillStyle.getColor();
|
||||
this.textFillState_ = {
|
||||
fillStyle: asColorLike(textFillStyleColor ?
|
||||
textFillStyleColor : defaultFillStyle)
|
||||
fillStyle: asColorLike(
|
||||
textFillStyleColor ? textFillStyleColor : defaultFillStyle
|
||||
),
|
||||
};
|
||||
}
|
||||
const textStrokeStyle = textStyle.getStroke();
|
||||
@@ -914,20 +1046,31 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
const textStrokeStyleWidth = textStrokeStyle.getWidth();
|
||||
const textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit();
|
||||
this.textStrokeState_ = {
|
||||
lineCap: textStrokeStyleLineCap !== undefined ?
|
||||
textStrokeStyleLineCap : defaultLineCap,
|
||||
lineDash: textStrokeStyleLineDash ?
|
||||
textStrokeStyleLineDash : defaultLineDash,
|
||||
lineDashOffset: textStrokeStyleLineDashOffset ?
|
||||
textStrokeStyleLineDashOffset : defaultLineDashOffset,
|
||||
lineJoin: textStrokeStyleLineJoin !== undefined ?
|
||||
textStrokeStyleLineJoin : defaultLineJoin,
|
||||
lineWidth: textStrokeStyleWidth !== undefined ?
|
||||
textStrokeStyleWidth : defaultLineWidth,
|
||||
miterLimit: textStrokeStyleMiterLimit !== undefined ?
|
||||
textStrokeStyleMiterLimit : defaultMiterLimit,
|
||||
strokeStyle: asColorLike(textStrokeStyleColor ?
|
||||
textStrokeStyleColor : defaultStrokeStyle)
|
||||
lineCap:
|
||||
textStrokeStyleLineCap !== undefined
|
||||
? textStrokeStyleLineCap
|
||||
: defaultLineCap,
|
||||
lineDash: textStrokeStyleLineDash
|
||||
? textStrokeStyleLineDash
|
||||
: defaultLineDash,
|
||||
lineDashOffset: textStrokeStyleLineDashOffset
|
||||
? textStrokeStyleLineDashOffset
|
||||
: defaultLineDashOffset,
|
||||
lineJoin:
|
||||
textStrokeStyleLineJoin !== undefined
|
||||
? textStrokeStyleLineJoin
|
||||
: defaultLineJoin,
|
||||
lineWidth:
|
||||
textStrokeStyleWidth !== undefined
|
||||
? textStrokeStyleWidth
|
||||
: defaultLineWidth,
|
||||
miterLimit:
|
||||
textStrokeStyleMiterLimit !== undefined
|
||||
? textStrokeStyleMiterLimit
|
||||
: defaultMiterLimit,
|
||||
strokeStyle: asColorLike(
|
||||
textStrokeStyleColor ? textStrokeStyleColor : defaultStrokeStyle
|
||||
),
|
||||
};
|
||||
}
|
||||
const textFont = textStyle.getFont();
|
||||
@@ -940,25 +1083,26 @@ class CanvasImmediateRenderer extends VectorContext {
|
||||
const textTextAlign = textStyle.getTextAlign();
|
||||
const textTextBaseline = textStyle.getTextBaseline();
|
||||
this.textState_ = {
|
||||
font: textFont !== undefined ?
|
||||
textFont : defaultFont,
|
||||
textAlign: textTextAlign !== undefined ?
|
||||
textTextAlign : defaultTextAlign,
|
||||
textBaseline: textTextBaseline !== undefined ?
|
||||
textTextBaseline : defaultTextBaseline
|
||||
font: textFont !== undefined ? textFont : defaultFont,
|
||||
textAlign:
|
||||
textTextAlign !== undefined ? textTextAlign : defaultTextAlign,
|
||||
textBaseline:
|
||||
textTextBaseline !== undefined
|
||||
? textTextBaseline
|
||||
: defaultTextBaseline,
|
||||
};
|
||||
this.text_ = textText !== undefined ? textText : '';
|
||||
this.textOffsetX_ =
|
||||
textOffsetX !== undefined ? (this.pixelRatio_ * textOffsetX) : 0;
|
||||
textOffsetX !== undefined ? this.pixelRatio_ * textOffsetX : 0;
|
||||
this.textOffsetY_ =
|
||||
textOffsetY !== undefined ? (this.pixelRatio_ * textOffsetY) : 0;
|
||||
this.textRotateWithView_ = textRotateWithView !== undefined ? textRotateWithView : false;
|
||||
textOffsetY !== undefined ? this.pixelRatio_ * textOffsetY : 0;
|
||||
this.textRotateWithView_ =
|
||||
textRotateWithView !== undefined ? textRotateWithView : false;
|
||||
this.textRotation_ = textRotation !== undefined ? textRotation : 0;
|
||||
this.textScale_ = this.pixelRatio_ * (textScale !== undefined ?
|
||||
textScale : 1);
|
||||
this.textScale_ =
|
||||
this.pixelRatio_ * (textScale !== undefined ? textScale : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default CanvasImmediateRenderer;
|
||||
|
||||
@@ -18,32 +18,27 @@ const Instruction = {
|
||||
MOVE_TO_LINE_TO: 9,
|
||||
SET_FILL_STYLE: 10,
|
||||
SET_STROKE_STYLE: 11,
|
||||
STROKE: 12
|
||||
STROKE: 12,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @type {Array<Instruction>}
|
||||
*/
|
||||
export const fillInstruction = [Instruction.FILL];
|
||||
|
||||
|
||||
/**
|
||||
* @type {Array<Instruction>}
|
||||
*/
|
||||
export const strokeInstruction = [Instruction.STROKE];
|
||||
|
||||
|
||||
/**
|
||||
* @type {Array<Instruction>}
|
||||
*/
|
||||
export const beginPathInstruction = [Instruction.BEGIN_PATH];
|
||||
|
||||
|
||||
/**
|
||||
* @type {Array<Instruction>}
|
||||
*/
|
||||
export const closePathInstruction = [Instruction.CLOSE_PATH];
|
||||
|
||||
|
||||
export default Instruction;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
/**
|
||||
* @module ol/render/canvas/LineStringBuilder
|
||||
*/
|
||||
import CanvasInstruction, {strokeInstruction, beginPathInstruction} from './Instruction.js';
|
||||
import CanvasBuilder from './Builder.js';
|
||||
import CanvasInstruction, {
|
||||
beginPathInstruction,
|
||||
strokeInstruction,
|
||||
} from './Instruction.js';
|
||||
|
||||
class CanvasLineStringBuilder extends CanvasBuilder {
|
||||
/**
|
||||
@@ -26,8 +29,18 @@ class CanvasLineStringBuilder extends CanvasBuilder {
|
||||
drawFlatCoordinates_(flatCoordinates, offset, end, stride) {
|
||||
const myBegin = this.coordinates.length;
|
||||
const myEnd = this.appendFlatCoordinates(
|
||||
flatCoordinates, offset, end, stride, false, false);
|
||||
const moveToLineToInstruction = [CanvasInstruction.MOVE_TO_LINE_TO, myBegin, myEnd];
|
||||
flatCoordinates,
|
||||
offset,
|
||||
end,
|
||||
stride,
|
||||
false,
|
||||
false
|
||||
);
|
||||
const moveToLineToInstruction = [
|
||||
CanvasInstruction.MOVE_TO_LINE_TO,
|
||||
myBegin,
|
||||
myEnd,
|
||||
];
|
||||
this.instructions.push(moveToLineToInstruction);
|
||||
this.hitDetectionInstructions.push(moveToLineToInstruction);
|
||||
return end;
|
||||
@@ -46,14 +59,27 @@ class CanvasLineStringBuilder extends CanvasBuilder {
|
||||
}
|
||||
this.updateStrokeStyle(state, this.applyStroke);
|
||||
this.beginGeometry(lineStringGeometry, feature);
|
||||
this.hitDetectionInstructions.push([
|
||||
CanvasInstruction.SET_STROKE_STYLE,
|
||||
state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
|
||||
state.miterLimit, state.lineDash, state.lineDashOffset
|
||||
], beginPathInstruction);
|
||||
this.hitDetectionInstructions.push(
|
||||
[
|
||||
CanvasInstruction.SET_STROKE_STYLE,
|
||||
state.strokeStyle,
|
||||
state.lineWidth,
|
||||
state.lineCap,
|
||||
state.lineJoin,
|
||||
state.miterLimit,
|
||||
state.lineDash,
|
||||
state.lineDashOffset,
|
||||
],
|
||||
beginPathInstruction
|
||||
);
|
||||
const flatCoordinates = lineStringGeometry.getFlatCoordinates();
|
||||
const stride = lineStringGeometry.getStride();
|
||||
this.drawFlatCoordinates_(flatCoordinates, 0, flatCoordinates.length, stride);
|
||||
this.drawFlatCoordinates_(
|
||||
flatCoordinates,
|
||||
0,
|
||||
flatCoordinates.length,
|
||||
stride
|
||||
);
|
||||
this.hitDetectionInstructions.push(strokeInstruction);
|
||||
this.endGeometry(feature);
|
||||
}
|
||||
@@ -71,17 +97,30 @@ class CanvasLineStringBuilder extends CanvasBuilder {
|
||||
}
|
||||
this.updateStrokeStyle(state, this.applyStroke);
|
||||
this.beginGeometry(multiLineStringGeometry, feature);
|
||||
this.hitDetectionInstructions.push([
|
||||
CanvasInstruction.SET_STROKE_STYLE,
|
||||
state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
|
||||
state.miterLimit, state.lineDash, state.lineDashOffset
|
||||
], beginPathInstruction);
|
||||
this.hitDetectionInstructions.push(
|
||||
[
|
||||
CanvasInstruction.SET_STROKE_STYLE,
|
||||
state.strokeStyle,
|
||||
state.lineWidth,
|
||||
state.lineCap,
|
||||
state.lineJoin,
|
||||
state.miterLimit,
|
||||
state.lineDash,
|
||||
state.lineDashOffset,
|
||||
],
|
||||
beginPathInstruction
|
||||
);
|
||||
const ends = multiLineStringGeometry.getEnds();
|
||||
const flatCoordinates = multiLineStringGeometry.getFlatCoordinates();
|
||||
const stride = multiLineStringGeometry.getStride();
|
||||
let offset = 0;
|
||||
for (let i = 0, ii = ends.length; i < ii; ++i) {
|
||||
offset = this.drawFlatCoordinates_(flatCoordinates, offset, /** @type {number} */ (ends[i]), stride);
|
||||
offset = this.drawFlatCoordinates_(
|
||||
flatCoordinates,
|
||||
offset,
|
||||
/** @type {number} */ (ends[i]),
|
||||
stride
|
||||
);
|
||||
}
|
||||
this.hitDetectionInstructions.push(strokeInstruction);
|
||||
this.endGeometry(feature);
|
||||
@@ -92,7 +131,10 @@ class CanvasLineStringBuilder extends CanvasBuilder {
|
||||
*/
|
||||
finish() {
|
||||
const state = this.state;
|
||||
if (state.lastStroke != undefined && state.lastStroke != this.coordinates.length) {
|
||||
if (
|
||||
state.lastStroke != undefined &&
|
||||
state.lastStroke != this.coordinates.length
|
||||
) {
|
||||
this.instructions.push(strokeInstruction);
|
||||
}
|
||||
this.reverseHitDetectionInstructions();
|
||||
@@ -104,7 +146,10 @@ class CanvasLineStringBuilder extends CanvasBuilder {
|
||||
* @param {import("../canvas.js").FillStrokeState} state State.
|
||||
*/
|
||||
applyStroke(state) {
|
||||
if (state.lastStroke != undefined && state.lastStroke != this.coordinates.length) {
|
||||
if (
|
||||
state.lastStroke != undefined &&
|
||||
state.lastStroke != this.coordinates.length
|
||||
) {
|
||||
this.instructions.push(strokeInstruction);
|
||||
state.lastStroke = this.coordinates.length;
|
||||
}
|
||||
@@ -114,5 +159,4 @@ class CanvasLineStringBuilder extends CanvasBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default CanvasLineStringBuilder;
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
/**
|
||||
* @module ol/render/canvas/PolygonBuilder
|
||||
*/
|
||||
import {snap} from '../../geom/flat/simplify.js';
|
||||
import {defaultFillStyle} from '../canvas.js';
|
||||
import CanvasInstruction, {
|
||||
fillInstruction, strokeInstruction, beginPathInstruction, closePathInstruction
|
||||
} from './Instruction.js';
|
||||
import CanvasBuilder from './Builder.js';
|
||||
|
||||
import CanvasInstruction, {
|
||||
beginPathInstruction,
|
||||
closePathInstruction,
|
||||
fillInstruction,
|
||||
strokeInstruction,
|
||||
} from './Instruction.js';
|
||||
import {defaultFillStyle} from '../canvas.js';
|
||||
import {snap} from '../../geom/flat/simplify.js';
|
||||
|
||||
class CanvasPolygonBuilder extends CanvasBuilder {
|
||||
/**
|
||||
@@ -38,8 +40,19 @@ class CanvasPolygonBuilder extends CanvasBuilder {
|
||||
for (let i = 0; i < numEnds; ++i) {
|
||||
const end = ends[i];
|
||||
const myBegin = this.coordinates.length;
|
||||
const myEnd = this.appendFlatCoordinates(flatCoordinates, offset, end, stride, true, !stroke);
|
||||
const moveToLineToInstruction = [CanvasInstruction.MOVE_TO_LINE_TO, myBegin, myEnd];
|
||||
const myEnd = this.appendFlatCoordinates(
|
||||
flatCoordinates,
|
||||
offset,
|
||||
end,
|
||||
stride,
|
||||
true,
|
||||
!stroke
|
||||
);
|
||||
const moveToLineToInstruction = [
|
||||
CanvasInstruction.MOVE_TO_LINE_TO,
|
||||
myBegin,
|
||||
myEnd,
|
||||
];
|
||||
this.instructions.push(moveToLineToInstruction);
|
||||
this.hitDetectionInstructions.push(moveToLineToInstruction);
|
||||
if (stroke) {
|
||||
@@ -77,21 +90,32 @@ class CanvasPolygonBuilder extends CanvasBuilder {
|
||||
if (state.fillStyle !== undefined) {
|
||||
this.hitDetectionInstructions.push([
|
||||
CanvasInstruction.SET_FILL_STYLE,
|
||||
defaultFillStyle
|
||||
defaultFillStyle,
|
||||
]);
|
||||
}
|
||||
if (state.strokeStyle !== undefined) {
|
||||
this.hitDetectionInstructions.push([
|
||||
CanvasInstruction.SET_STROKE_STYLE,
|
||||
state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
|
||||
state.miterLimit, state.lineDash, state.lineDashOffset
|
||||
state.strokeStyle,
|
||||
state.lineWidth,
|
||||
state.lineCap,
|
||||
state.lineJoin,
|
||||
state.miterLimit,
|
||||
state.lineDash,
|
||||
state.lineDashOffset,
|
||||
]);
|
||||
}
|
||||
const flatCoordinates = circleGeometry.getFlatCoordinates();
|
||||
const stride = circleGeometry.getStride();
|
||||
const myBegin = this.coordinates.length;
|
||||
this.appendFlatCoordinates(
|
||||
flatCoordinates, 0, flatCoordinates.length, stride, false, false);
|
||||
flatCoordinates,
|
||||
0,
|
||||
flatCoordinates.length,
|
||||
stride,
|
||||
false,
|
||||
false
|
||||
);
|
||||
const circleInstruction = [CanvasInstruction.CIRCLE, myBegin];
|
||||
this.instructions.push(beginPathInstruction, circleInstruction);
|
||||
this.hitDetectionInstructions.push(beginPathInstruction, circleInstruction);
|
||||
@@ -122,20 +146,30 @@ class CanvasPolygonBuilder extends CanvasBuilder {
|
||||
if (state.fillStyle !== undefined) {
|
||||
this.hitDetectionInstructions.push([
|
||||
CanvasInstruction.SET_FILL_STYLE,
|
||||
defaultFillStyle
|
||||
defaultFillStyle,
|
||||
]);
|
||||
}
|
||||
if (state.strokeStyle !== undefined) {
|
||||
this.hitDetectionInstructions.push([
|
||||
CanvasInstruction.SET_STROKE_STYLE,
|
||||
state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
|
||||
state.miterLimit, state.lineDash, state.lineDashOffset
|
||||
state.strokeStyle,
|
||||
state.lineWidth,
|
||||
state.lineCap,
|
||||
state.lineJoin,
|
||||
state.miterLimit,
|
||||
state.lineDash,
|
||||
state.lineDashOffset,
|
||||
]);
|
||||
}
|
||||
const ends = polygonGeometry.getEnds();
|
||||
const flatCoordinates = polygonGeometry.getOrientedFlatCoordinates();
|
||||
const stride = polygonGeometry.getStride();
|
||||
this.drawFlatCoordinatess_(flatCoordinates, 0, /** @type {Array<number>} */ (ends), stride);
|
||||
this.drawFlatCoordinatess_(
|
||||
flatCoordinates,
|
||||
0,
|
||||
/** @type {Array<number>} */ (ends),
|
||||
stride
|
||||
);
|
||||
this.endGeometry(feature);
|
||||
}
|
||||
|
||||
@@ -155,14 +189,19 @@ class CanvasPolygonBuilder extends CanvasBuilder {
|
||||
if (state.fillStyle !== undefined) {
|
||||
this.hitDetectionInstructions.push([
|
||||
CanvasInstruction.SET_FILL_STYLE,
|
||||
defaultFillStyle
|
||||
defaultFillStyle,
|
||||
]);
|
||||
}
|
||||
if (state.strokeStyle !== undefined) {
|
||||
this.hitDetectionInstructions.push([
|
||||
CanvasInstruction.SET_STROKE_STYLE,
|
||||
state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
|
||||
state.miterLimit, state.lineDash, state.lineDashOffset
|
||||
state.strokeStyle,
|
||||
state.lineWidth,
|
||||
state.lineCap,
|
||||
state.lineJoin,
|
||||
state.miterLimit,
|
||||
state.lineDash,
|
||||
state.lineDashOffset,
|
||||
]);
|
||||
}
|
||||
const endss = multiPolygonGeometry.getEndss();
|
||||
@@ -170,7 +209,12 @@ class CanvasPolygonBuilder extends CanvasBuilder {
|
||||
const stride = multiPolygonGeometry.getStride();
|
||||
let offset = 0;
|
||||
for (let i = 0, ii = endss.length; i < ii; ++i) {
|
||||
offset = this.drawFlatCoordinatess_(flatCoordinates, offset, endss[i], stride);
|
||||
offset = this.drawFlatCoordinatess_(
|
||||
flatCoordinates,
|
||||
offset,
|
||||
endss[i],
|
||||
stride
|
||||
);
|
||||
}
|
||||
this.endGeometry(feature);
|
||||
}
|
||||
@@ -210,5 +254,4 @@ class CanvasPolygonBuilder extends CanvasBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default CanvasPolygonBuilder;
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
/**
|
||||
* @module ol/render/canvas/TextBuilder
|
||||
*/
|
||||
import {getUid} from '../../util.js';
|
||||
import CanvasBuilder from './Builder.js';
|
||||
import CanvasInstruction from './Instruction.js';
|
||||
import GeometryType from '../../geom/GeometryType.js';
|
||||
import TextPlacement from '../../style/TextPlacement.js';
|
||||
import {asColorLike} from '../../colorlike.js';
|
||||
import {
|
||||
defaultFillStyle,
|
||||
defaultFont,
|
||||
defaultLineCap,
|
||||
defaultLineDash,
|
||||
defaultLineDashOffset,
|
||||
defaultLineJoin,
|
||||
defaultLineWidth,
|
||||
defaultMiterLimit,
|
||||
defaultPadding,
|
||||
defaultStrokeStyle,
|
||||
defaultTextAlign,
|
||||
defaultTextBaseline,
|
||||
registerFont,
|
||||
} from '../canvas.js';
|
||||
import {getUid} from '../../util.js';
|
||||
import {intersects} from '../../extent.js';
|
||||
import {matchingChunk} from '../../geom/flat/straightchunk.js';
|
||||
import GeometryType from '../../geom/GeometryType.js';
|
||||
import {defaultTextAlign, defaultPadding, defaultLineCap, defaultLineDashOffset, defaultLineDash, defaultLineJoin, defaultFillStyle, registerFont, defaultFont, defaultLineWidth, defaultMiterLimit, defaultStrokeStyle, defaultTextBaseline} from '../canvas.js';
|
||||
import CanvasInstruction from './Instruction.js';
|
||||
import CanvasBuilder from './Builder.js';
|
||||
import TextPlacement from '../../style/TextPlacement.js';
|
||||
/**
|
||||
* @const
|
||||
* @enum {number}
|
||||
@@ -25,10 +39,9 @@ export const TEXT_ALIGN = {
|
||||
'hanging': 0.2,
|
||||
'alphabetic': 0.8,
|
||||
'ideographic': 0.8,
|
||||
'bottom': 1
|
||||
'bottom': 1,
|
||||
};
|
||||
|
||||
|
||||
class CanvasTextBuilder extends CanvasBuilder {
|
||||
/**
|
||||
* @param {number} tolerance Tolerance.
|
||||
@@ -176,7 +189,9 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
} else if (geometryType == GeometryType.MULTI_LINE_STRING) {
|
||||
ends = /** @type {import("../../geom/MultiLineString.js").default} */ (geometry).getEnds();
|
||||
} else if (geometryType == GeometryType.POLYGON) {
|
||||
ends = /** @type {import("../../geom/Polygon.js").default} */ (geometry).getEnds().slice(0, 1);
|
||||
ends = /** @type {import("../../geom/Polygon.js").default} */ (geometry)
|
||||
.getEnds()
|
||||
.slice(0, 1);
|
||||
} else if (geometryType == GeometryType.MULTI_POLYGON) {
|
||||
const endss = /** @type {import("../../geom/MultiPolygon.js").default} */ (geometry).getEndss();
|
||||
ends = [];
|
||||
@@ -190,7 +205,13 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
let flatEnd;
|
||||
for (let o = 0, oo = ends.length; o < oo; ++o) {
|
||||
if (textAlign == undefined) {
|
||||
const range = matchingChunk(textState.maxAngle, flatCoordinates, flatOffset, ends[o], stride);
|
||||
const range = matchingChunk(
|
||||
textState.maxAngle,
|
||||
flatCoordinates,
|
||||
flatOffset,
|
||||
ends[o],
|
||||
stride
|
||||
);
|
||||
flatOffset = range[0];
|
||||
flatEnd = range[1];
|
||||
} else {
|
||||
@@ -201,16 +222,16 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
}
|
||||
end = this.coordinates.length;
|
||||
flatOffset = ends[o];
|
||||
const declutterGroup = this.declutterGroups_ ?
|
||||
(o === 0 ? this.declutterGroups_[0] : [].concat(this.declutterGroups_[0])) :
|
||||
null;
|
||||
const declutterGroup = this.declutterGroups_
|
||||
? o === 0
|
||||
? this.declutterGroups_[0]
|
||||
: [].concat(this.declutterGroups_[0])
|
||||
: null;
|
||||
this.drawChars_(begin, end, declutterGroup);
|
||||
begin = end;
|
||||
}
|
||||
this.endGeometry(feature);
|
||||
|
||||
} else {
|
||||
|
||||
let geometryWidths = null;
|
||||
if (!textState.overflow) {
|
||||
geometryWidths = [];
|
||||
@@ -254,12 +275,22 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
break;
|
||||
default:
|
||||
}
|
||||
end = this.appendFlatCoordinates(flatCoordinates, 0, end, stride, false, false);
|
||||
end = this.appendFlatCoordinates(
|
||||
flatCoordinates,
|
||||
0,
|
||||
end,
|
||||
stride,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
this.saveTextStates_();
|
||||
|
||||
if (textState.backgroundFill || textState.backgroundStroke) {
|
||||
this.setFillStrokeStyle(textState.backgroundFill, textState.backgroundStroke);
|
||||
this.setFillStrokeStyle(
|
||||
textState.backgroundFill,
|
||||
textState.backgroundStroke
|
||||
);
|
||||
if (textState.backgroundFill) {
|
||||
this.updateFillStyle(this.state, this.createFill);
|
||||
this.hitDetectionInstructions.push(this.createFill(this.state));
|
||||
@@ -276,24 +307,63 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
// For clarity, we pass NaN for offsetX, offsetY, width and height, which will be computed at
|
||||
// render time.
|
||||
const pixelRatio = this.pixelRatio;
|
||||
this.instructions.push([CanvasInstruction.DRAW_IMAGE, begin, end,
|
||||
null, NaN, NaN, this.declutterGroups_, NaN, 1, 0, 0,
|
||||
this.textRotateWithView_, this.textRotation_, 1, NaN,
|
||||
textState.padding == defaultPadding ?
|
||||
defaultPadding : textState.padding.map(function(p) {
|
||||
return p * pixelRatio;
|
||||
}),
|
||||
!!textState.backgroundFill, !!textState.backgroundStroke,
|
||||
this.text_, this.textKey_, this.strokeKey_, this.fillKey_,
|
||||
this.textOffsetX_, this.textOffsetY_, geometryWidths
|
||||
this.instructions.push([
|
||||
CanvasInstruction.DRAW_IMAGE,
|
||||
begin,
|
||||
end,
|
||||
null,
|
||||
NaN,
|
||||
NaN,
|
||||
this.declutterGroups_,
|
||||
NaN,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
this.textRotateWithView_,
|
||||
this.textRotation_,
|
||||
1,
|
||||
NaN,
|
||||
textState.padding == defaultPadding
|
||||
? defaultPadding
|
||||
: textState.padding.map(function (p) {
|
||||
return p * pixelRatio;
|
||||
}),
|
||||
!!textState.backgroundFill,
|
||||
!!textState.backgroundStroke,
|
||||
this.text_,
|
||||
this.textKey_,
|
||||
this.strokeKey_,
|
||||
this.fillKey_,
|
||||
this.textOffsetX_,
|
||||
this.textOffsetY_,
|
||||
geometryWidths,
|
||||
]);
|
||||
this.hitDetectionInstructions.push([CanvasInstruction.DRAW_IMAGE, begin, end,
|
||||
null, NaN, NaN, this.declutterGroups_, NaN, 1, 0, 0,
|
||||
this.textRotateWithView_, this.textRotation_, 1 / this.pixelRatio, NaN,
|
||||
this.hitDetectionInstructions.push([
|
||||
CanvasInstruction.DRAW_IMAGE,
|
||||
begin,
|
||||
end,
|
||||
null,
|
||||
NaN,
|
||||
NaN,
|
||||
this.declutterGroups_,
|
||||
NaN,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
this.textRotateWithView_,
|
||||
this.textRotation_,
|
||||
1 / this.pixelRatio,
|
||||
NaN,
|
||||
textState.padding,
|
||||
!!textState.backgroundFill, !!textState.backgroundStroke,
|
||||
this.text_, this.textKey_, this.strokeKey_, this.fillKey_,
|
||||
this.textOffsetX_, this.textOffsetY_, geometryWidths
|
||||
!!textState.backgroundFill,
|
||||
!!textState.backgroundStroke,
|
||||
this.text_,
|
||||
this.textKey_,
|
||||
this.strokeKey_,
|
||||
this.fillKey_,
|
||||
this.textOffsetX_,
|
||||
this.textOffsetY_,
|
||||
geometryWidths,
|
||||
]);
|
||||
|
||||
this.endGeometry(feature);
|
||||
@@ -318,7 +388,7 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
lineWidth: strokeState.lineWidth,
|
||||
lineJoin: strokeState.lineJoin,
|
||||
miterLimit: strokeState.miterLimit,
|
||||
lineDash: strokeState.lineDash
|
||||
lineDash: strokeState.lineDash,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -328,14 +398,14 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
font: textState.font,
|
||||
textAlign: textState.textAlign || defaultTextAlign,
|
||||
textBaseline: textState.textBaseline || defaultTextBaseline,
|
||||
scale: textState.scale
|
||||
scale: textState.scale,
|
||||
};
|
||||
}
|
||||
const fillKey = this.fillKey_;
|
||||
if (fillState) {
|
||||
if (!(fillKey in this.fillStates)) {
|
||||
this.fillStates[fillKey] = {
|
||||
fillStyle: fillState.fillStyle
|
||||
fillStyle: fillState.fillStyle,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -356,26 +426,49 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
const fillKey = this.fillKey_;
|
||||
this.saveTextStates_();
|
||||
|
||||
|
||||
const pixelRatio = this.pixelRatio;
|
||||
const baseline = TEXT_ALIGN[textState.textBaseline];
|
||||
|
||||
const offsetY = this.textOffsetY_ * pixelRatio;
|
||||
const text = this.text_;
|
||||
const textScale = textState.scale;
|
||||
const strokeWidth = strokeState ? strokeState.lineWidth * textScale / 2 : 0;
|
||||
const strokeWidth = strokeState
|
||||
? (strokeState.lineWidth * textScale) / 2
|
||||
: 0;
|
||||
|
||||
this.instructions.push([CanvasInstruction.DRAW_CHARS,
|
||||
begin, end, baseline, declutterGroup,
|
||||
textState.overflow, fillKey, textState.maxAngle,
|
||||
this.instructions.push([
|
||||
CanvasInstruction.DRAW_CHARS,
|
||||
begin,
|
||||
end,
|
||||
baseline,
|
||||
declutterGroup,
|
||||
textState.overflow,
|
||||
fillKey,
|
||||
textState.maxAngle,
|
||||
pixelRatio,
|
||||
offsetY, strokeKey, strokeWidth * pixelRatio, text, textKey, 1
|
||||
]);
|
||||
this.hitDetectionInstructions.push([CanvasInstruction.DRAW_CHARS,
|
||||
begin, end, baseline, declutterGroup,
|
||||
textState.overflow, fillKey, textState.maxAngle,
|
||||
offsetY,
|
||||
strokeKey,
|
||||
strokeWidth * pixelRatio,
|
||||
text,
|
||||
textKey,
|
||||
1,
|
||||
offsetY, strokeKey, strokeWidth, text, textKey, 1 / pixelRatio
|
||||
]);
|
||||
this.hitDetectionInstructions.push([
|
||||
CanvasInstruction.DRAW_CHARS,
|
||||
begin,
|
||||
end,
|
||||
baseline,
|
||||
declutterGroup,
|
||||
textState.overflow,
|
||||
fillKey,
|
||||
textState.maxAngle,
|
||||
1,
|
||||
offsetY,
|
||||
strokeKey,
|
||||
strokeWidth,
|
||||
text,
|
||||
textKey,
|
||||
1 / pixelRatio,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -401,7 +494,8 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
this.textFillState_ = fillState;
|
||||
}
|
||||
fillState.fillStyle = asColorLike(
|
||||
textFillStyle.getColor() || defaultFillStyle);
|
||||
textFillStyle.getColor() || defaultFillStyle
|
||||
);
|
||||
}
|
||||
|
||||
const textStrokeStyle = textStyle.getStroke();
|
||||
@@ -421,14 +515,15 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
strokeState.lineCap = textStrokeStyle.getLineCap() || defaultLineCap;
|
||||
strokeState.lineDash = lineDash ? lineDash.slice() : defaultLineDash;
|
||||
strokeState.lineDashOffset =
|
||||
lineDashOffset === undefined ? defaultLineDashOffset : lineDashOffset;
|
||||
lineDashOffset === undefined ? defaultLineDashOffset : lineDashOffset;
|
||||
strokeState.lineJoin = textStrokeStyle.getLineJoin() || defaultLineJoin;
|
||||
strokeState.lineWidth =
|
||||
lineWidth === undefined ? defaultLineWidth : lineWidth;
|
||||
lineWidth === undefined ? defaultLineWidth : lineWidth;
|
||||
strokeState.miterLimit =
|
||||
miterLimit === undefined ? defaultMiterLimit : miterLimit;
|
||||
miterLimit === undefined ? defaultMiterLimit : miterLimit;
|
||||
strokeState.strokeStyle = asColorLike(
|
||||
textStrokeStyle.getColor() || defaultStrokeStyle);
|
||||
textStrokeStyle.getColor() || defaultStrokeStyle
|
||||
);
|
||||
}
|
||||
|
||||
textState = this.textState_;
|
||||
@@ -440,7 +535,8 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
textState.maxAngle = textStyle.getMaxAngle();
|
||||
textState.placement = textStyle.getPlacement();
|
||||
textState.textAlign = textStyle.getTextAlign();
|
||||
textState.textBaseline = textStyle.getTextBaseline() || defaultTextBaseline;
|
||||
textState.textBaseline =
|
||||
textStyle.getTextBaseline() || defaultTextBaseline;
|
||||
textState.backgroundFill = textStyle.getBackgroundFill();
|
||||
textState.backgroundStroke = textStyle.getBackgroundStroke();
|
||||
textState.padding = textStyle.getPadding() || defaultPadding;
|
||||
@@ -453,21 +549,36 @@ class CanvasTextBuilder extends CanvasBuilder {
|
||||
this.text_ = textStyle.getText() || '';
|
||||
this.textOffsetX_ = textOffsetX === undefined ? 0 : textOffsetX;
|
||||
this.textOffsetY_ = textOffsetY === undefined ? 0 : textOffsetY;
|
||||
this.textRotateWithView_ = textRotateWithView === undefined ? false : textRotateWithView;
|
||||
this.textRotateWithView_ =
|
||||
textRotateWithView === undefined ? false : textRotateWithView;
|
||||
this.textRotation_ = textRotation === undefined ? 0 : textRotation;
|
||||
|
||||
this.strokeKey_ = strokeState ?
|
||||
(typeof strokeState.strokeStyle == 'string' ? strokeState.strokeStyle : getUid(strokeState.strokeStyle)) +
|
||||
strokeState.lineCap + strokeState.lineDashOffset + '|' + strokeState.lineWidth +
|
||||
strokeState.lineJoin + strokeState.miterLimit + '[' + strokeState.lineDash.join() + ']' :
|
||||
'';
|
||||
this.textKey_ = textState.font + textState.scale + (textState.textAlign || '?') + (textState.textBaseline || '?');
|
||||
this.fillKey_ = fillState ?
|
||||
(typeof fillState.fillStyle == 'string' ? fillState.fillStyle : ('|' + getUid(fillState.fillStyle))) :
|
||||
'';
|
||||
this.strokeKey_ = strokeState
|
||||
? (typeof strokeState.strokeStyle == 'string'
|
||||
? strokeState.strokeStyle
|
||||
: getUid(strokeState.strokeStyle)) +
|
||||
strokeState.lineCap +
|
||||
strokeState.lineDashOffset +
|
||||
'|' +
|
||||
strokeState.lineWidth +
|
||||
strokeState.lineJoin +
|
||||
strokeState.miterLimit +
|
||||
'[' +
|
||||
strokeState.lineDash.join() +
|
||||
']'
|
||||
: '';
|
||||
this.textKey_ =
|
||||
textState.font +
|
||||
textState.scale +
|
||||
(textState.textAlign || '?') +
|
||||
(textState.textBaseline || '?');
|
||||
this.fillKey_ = fillState
|
||||
? typeof fillState.fillStyle == 'string'
|
||||
? fillState.fillStyle
|
||||
: '|' + getUid(fillState.fillStyle)
|
||||
: '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default CanvasTextBuilder;
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
*/
|
||||
|
||||
import CanvasImmediateRenderer from './Immediate.js';
|
||||
import {createCanvasContext2D} from '../../dom.js';
|
||||
import {Icon} from '../../style.js';
|
||||
import IconAnchorUnits from '../../style/IconAnchorUnits.js';
|
||||
import GeometryType from '../../geom/GeometryType.js';
|
||||
import IconAnchorUnits from '../../style/IconAnchorUnits.js';
|
||||
import {Icon} from '../../style.js';
|
||||
import {createCanvasContext2D} from '../../dom.js';
|
||||
import {intersects} from '../../extent.js';
|
||||
import {numberSafeCompareFunction} from '../../array.js';
|
||||
|
||||
@@ -24,13 +24,27 @@ import {numberSafeCompareFunction} from '../../array.js';
|
||||
* @param {number} rotation Rotation.
|
||||
* @return {ImageData} Hit detection image data.
|
||||
*/
|
||||
export function createHitDetectionImageData(size, transforms, features, styleFunction, extent, resolution, rotation) {
|
||||
export function createHitDetectionImageData(
|
||||
size,
|
||||
transforms,
|
||||
features,
|
||||
styleFunction,
|
||||
extent,
|
||||
resolution,
|
||||
rotation
|
||||
) {
|
||||
const width = size[0] / 2;
|
||||
const height = size[1] / 2;
|
||||
const context = createCanvasContext2D(width, height);
|
||||
context.imageSmoothingEnabled = false;
|
||||
const canvas = context.canvas;
|
||||
const renderer = new CanvasImmediateRenderer(context, 0.5, extent, null, rotation);
|
||||
const renderer = new CanvasImmediateRenderer(
|
||||
context,
|
||||
0.5,
|
||||
extent,
|
||||
null,
|
||||
rotation
|
||||
);
|
||||
const featureCount = features.length;
|
||||
// Stretch hit detection index to use the whole available color range
|
||||
const indexFactor = Math.floor((256 * 256 * 256 - 1) / featureCount);
|
||||
@@ -80,19 +94,21 @@ export function createHitDetectionImageData(size, transforms, features, styleFun
|
||||
const height = imgSize ? imgSize[1] : img.height;
|
||||
const iconContext = createCanvasContext2D(width, height);
|
||||
iconContext.drawImage(img, 0, 0);
|
||||
style.setImage(new Icon({
|
||||
img: img,
|
||||
imgSize: imgSize,
|
||||
anchor: image.getAnchor(),
|
||||
anchorXUnits: IconAnchorUnits.PIXELS,
|
||||
anchorYUnits: IconAnchorUnits.PIXELS,
|
||||
offset: image.getOrigin(),
|
||||
size: image.getSize(),
|
||||
opacity: image.getOpacity(),
|
||||
scale: image.getScale(),
|
||||
rotation: image.getRotation(),
|
||||
rotateWithView: image.getRotateWithView()
|
||||
}));
|
||||
style.setImage(
|
||||
new Icon({
|
||||
img: img,
|
||||
imgSize: imgSize,
|
||||
anchor: image.getAnchor(),
|
||||
anchorXUnits: IconAnchorUnits.PIXELS,
|
||||
anchorYUnits: IconAnchorUnits.PIXELS,
|
||||
offset: image.getOrigin(),
|
||||
size: image.getSize(),
|
||||
opacity: image.getOpacity(),
|
||||
scale: image.getScale(),
|
||||
rotation: image.getRotation(),
|
||||
rotateWithView: image.getRotateWithView(),
|
||||
})
|
||||
);
|
||||
}
|
||||
const zIndex = Number(style.getZIndex());
|
||||
let byGeometryType = featuresByZIndex[zIndex];
|
||||
@@ -106,12 +122,17 @@ export function createHitDetectionImageData(size, transforms, features, styleFun
|
||||
}
|
||||
const geometry = style.getGeometryFunction()(feature);
|
||||
if (geometry && intersects(extent, geometry.getExtent())) {
|
||||
byGeometryType[geometry.getType().replace('Multi', '')].push(geometry, style);
|
||||
byGeometryType[geometry.getType().replace('Multi', '')].push(
|
||||
geometry,
|
||||
style
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const zIndexKeys = Object.keys(featuresByZIndex).map(Number).sort(numberSafeCompareFunction);
|
||||
const zIndexKeys = Object.keys(featuresByZIndex)
|
||||
.map(Number)
|
||||
.sort(numberSafeCompareFunction);
|
||||
for (let i = 0, ii = zIndexKeys.length; i < ii; ++i) {
|
||||
const byGeometryType = featuresByZIndex[zIndexKeys[i]];
|
||||
for (const type in byGeometryType) {
|
||||
@@ -140,11 +161,13 @@ export function createHitDetectionImageData(size, transforms, features, styleFun
|
||||
export function hitDetect(pixel, features, imageData) {
|
||||
const resultFeatures = [];
|
||||
if (imageData) {
|
||||
const index = (Math.round(pixel[0] / 2) + Math.round(pixel[1] / 2) * imageData.width) * 4;
|
||||
const index =
|
||||
(Math.round(pixel[0] / 2) + Math.round(pixel[1] / 2) * imageData.width) *
|
||||
4;
|
||||
const r = imageData.data[index];
|
||||
const g = imageData.data[index + 1];
|
||||
const b = imageData.data[index + 2];
|
||||
const i = b + (256 * (g + (256 * r)));
|
||||
const i = b + 256 * (g + 256 * r);
|
||||
const indexFactor = Math.floor((256 * 256 * 256 - 1) / features.length);
|
||||
if (i && i % indexFactor === 0) {
|
||||
resultFeatures.push(features[i / indexFactor - 1]);
|
||||
|
||||
Reference in New Issue
Block a user