Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
package.render.canvas.Executor.js Maven / Gradle / Ivy
import CanvasInstruction from './Instruction.js' ;
import ZIndexContext from '../canvas/ZIndexContext.js' ;
import {TEXT_ALIGN} from './TextBuilder.js' ;
import {
apply as applyTransform,
compose as composeTransform,
create as createTransform,
setFromArray as transformSetFromArray,
} from '../../transform.js' ;
import {createEmpty, createOrUpdate, intersects} from '../../extent.js' ;
import {
defaultPadding,
defaultTextAlign,
defaultTextBaseline,
drawImageOrLabel,
getTextDimensions,
measureAndCacheTextWidth,
} 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' ;
const tmpExtent = createEmpty();
const p1 = [];
const p2 = [];
const p3 = [];
const p4 = [];
function getDeclutterBox (replayImageOrLabelArgs) {
return replayImageOrLabelArgs[3 ].declutterBox;
}
const rtlRegEx = new RegExp(
'[' +
String.fromCharCode(0x00591 ) + '-' + String.fromCharCode(0x008ff ) +
String.fromCharCode(0x0fb1d ) + '-' + String.fromCharCode(0x0fdff ) +
String.fromCharCode(0x0fe70 ) + '-' + String.fromCharCode(0x0fefc ) +
String.fromCharCode(0x10800 ) + '-' + String.fromCharCode(0x10fff ) +
String.fromCharCode(0x1e800 ) + '-' + String.fromCharCode(0x1efff ) +
']'
);
function horizontalTextAlign (text, align) {
if (align === 'start' ) {
align = rtlRegEx.test(text) ? 'right' : 'left' ;
} else if (align === 'end' ) {
align = rtlRegEx.test(text) ? 'left' : 'right' ;
}
return TEXT_ALIGN[align];
}
function createTextChunks (acc, line, i) {
if (i > 0 ) {
acc.push('\n' , '' );
}
acc.push(line, '' );
return acc;
}
class Executor {
constructor(
resolution,
pixelRatio,
overlaps,
instructions,
deferredRendering,
) {
this.overlaps = overlaps;
this.pixelRatio = pixelRatio;
this.resolution = resolution;
this.alignAndScaleFill_;
this.instructions = instructions.instructions;
this.coordinates = instructions.coordinates;
this.coordinateCache_ = {};
this.renderedTransform_ = createTransform();
this.hitDetectionInstructions = instructions.hitDetectionInstructions;
this.pixelCoordinates_ = null ;
this.viewRotation_ = 0 ;
this.fillStates = instructions.fillStates || {};
this.strokeStates = instructions.strokeStates || {};
this.textStates = instructions.textStates || {};
this.widths_ = {};
this.labels_ = {};
this.zIndexContext_ = deferredRendering ? new ZIndexContext() : null ;
}
getZIndexContext() {
return this.zIndexContext_;
}
createLabel(text, textKey, fillKey, strokeKey) {
const key = text + textKey + fillKey + strokeKey;
if (this.labels_[key]) {
return this.labels_[key];
}
const strokeState = strokeKey ? this.strokeStates[strokeKey] : null ;
const fillState = fillKey ? this.fillStates[fillKey] : null ;
const textState = this.textStates[textKey];
const pixelRatio = this.pixelRatio;
const scale = [
textState.scale[0 ] * pixelRatio,
textState.scale[1 ] * pixelRatio,
];
const align = textState.justify
? TEXT_ALIGN[textState.justify]
: horizontalTextAlign(
Array .isArray(text) ? text[0 ] : text,
textState.textAlign || defaultTextAlign,
);
const strokeWidth =
strokeKey && strokeState.lineWidth ? strokeState.lineWidth : 0 ;
const chunks = Array .isArray(text)
? text
: String(text).split('\n' ).reduce(createTextChunks, []);
const {width, height, widths, heights, lineWidths} = getTextDimensions(
textState,
chunks,
);
const renderWidth = width + strokeWidth;
const contextInstructions = [];
const w = (renderWidth + 2 ) * scale[0 ];
const h = (height + strokeWidth) * scale[1 ];
const label = {
width: w < 0 ? Math.floor(w) : Math.ceil(w),
height: h < 0 ? Math.floor(h) : Math.ceil(h),
contextInstructions: contextInstructions,
};
if (scale[0 ] != 1 || scale[1 ] != 1 ) {
contextInstructions.push('scale' , scale);
}
if (strokeKey) {
contextInstructions.push('strokeStyle' , strokeState.strokeStyle);
contextInstructions.push('lineWidth' , strokeWidth);
contextInstructions.push('lineCap' , strokeState.lineCap);
contextInstructions.push('lineJoin' , strokeState.lineJoin);
contextInstructions.push('miterLimit' , strokeState.miterLimit);
contextInstructions.push('setLineDash' , [strokeState.lineDash]);
contextInstructions.push('lineDashOffset' , strokeState.lineDashOffset);
}
if (fillKey) {
contextInstructions.push('fillStyle' , fillState.fillStyle);
}
contextInstructions.push('textBaseline' , 'middle' );
contextInstructions.push('textAlign' , 'center' );
const leftRight = 0.5 - align;
let x = align * renderWidth + leftRight * strokeWidth;
const strokeInstructions = [];
const fillInstructions = [];
let lineHeight = 0 ;
let lineOffset = 0 ;
let widthHeightIndex = 0 ;
let lineWidthIndex = 0 ;
let previousFont;
for (let i = 0 , ii = chunks.length; i < ii; i += 2 ) {
const text = chunks[i];
if (text === '\n' ) {
lineOffset += lineHeight;
lineHeight = 0 ;
x = align * renderWidth + leftRight * strokeWidth;
++lineWidthIndex;
continue ;
}
const font = chunks[i + 1 ] || textState.font;
if (font !== previousFont) {
if (strokeKey) {
strokeInstructions.push('font' , font);
}
if (fillKey) {
fillInstructions.push('font' , font);
}
previousFont = font;
}
lineHeight = Math.max(lineHeight, heights[widthHeightIndex]);
const fillStrokeArgs = [
text,
x +
leftRight * widths[widthHeightIndex] +
align * (widths[widthHeightIndex] - lineWidths[lineWidthIndex]),
0.5 * (strokeWidth + lineHeight) + lineOffset,
];
x += widths[widthHeightIndex];
if (strokeKey) {
strokeInstructions.push('strokeText' , fillStrokeArgs);
}
if (fillKey) {
fillInstructions.push('fillText' , fillStrokeArgs);
}
++widthHeightIndex;
}
Array .prototype.push.apply(contextInstructions, strokeInstructions);
Array .prototype.push.apply(contextInstructions, fillInstructions);
this.labels_[key] = label;
return label;
}
replayTextBackground_(
context,
p1,
p2,
p3,
p4,
fillInstruction,
strokeInstruction,
) {
context.beginPath();
context.moveTo.apply(context, p1);
context.lineTo.apply(context, p2);
context.lineTo.apply(context, p3);
context.lineTo.apply(context, p4);
context.lineTo.apply(context, p1);
if (fillInstruction) {
this.alignAndScaleFill_ = (fillInstruction[2 ]);
this.fill_(context);
}
if (strokeInstruction) {
this.setStrokeStyle_(
context,
(strokeInstruction),
);
context.stroke();
}
}
calculateImageOrLabelDimensions_(
sheetWidth,
sheetHeight,
centerX,
centerY,
width,
height,
anchorX,
anchorY,
originX,
originY,
rotation,
scale,
snapToPixel,
padding,
fillStroke,
feature,
) {
anchorX *= scale[0 ];
anchorY *= scale[1 ];
let x = centerX - anchorX;
let y = centerY - anchorY;
const w = width + originX > sheetWidth ? sheetWidth - originX : width;
const h = height + originY > sheetHeight ? sheetHeight - originY : height;
const boxW = padding[3 ] + w * scale[0 ] + padding[1 ];
const boxH = padding[0 ] + h * scale[1 ] + padding[2 ];
const boxX = x - padding[3 ];
const boxY = y - padding[0 ];
if (fillStroke || rotation !== 0 ) {
p1[0 ] = boxX;
p4[0 ] = boxX;
p1[1 ] = boxY;
p2[1 ] = boxY;
p2[0 ] = boxX + boxW;
p3[0 ] = p2[0 ];
p3[1 ] = boxY + boxH;
p4[1 ] = p3[1 ];
}
let transform;
if (rotation !== 0 ) {
transform = composeTransform(
createTransform(),
centerX,
centerY,
1 ,
1 ,
rotation,
-centerX,
-centerY,
);
applyTransform(transform, p1);
applyTransform(transform, p2);
applyTransform(transform, p3);
applyTransform(transform, p4);
createOrUpdate(
Math.min(p1[0 ], p2[0 ], p3[0 ], p4[0 ]),
Math.min(p1[1 ], p2[1 ], p3[1 ], p4[1 ]),
Math.max(p1[0 ], p2[0 ], p3[0 ], p4[0 ]),
Math.max(p1[1 ], p2[1 ], p3[1 ], p4[1 ]),
tmpExtent,
);
} else {
createOrUpdate(
Math.min(boxX, boxX + boxW),
Math.min(boxY, boxY + boxH),
Math.max(boxX, boxX + boxW),
Math.max(boxY, boxY + boxH),
tmpExtent,
);
}
if (snapToPixel) {
x = Math.round(x);
y = Math.round(y);
}
return {
drawImageX: x,
drawImageY: y,
drawImageW: w,
drawImageH: h,
originX: originX,
originY: originY,
declutterBox: {
minX: tmpExtent[0 ],
minY: tmpExtent[1 ],
maxX: tmpExtent[2 ],
maxY: tmpExtent[3 ],
value: feature,
},
canvasTransform: transform,
scale: scale,
};
}
replayImageOrLabel_(
context,
scaledCanvasSize,
imageOrLabel,
dimensions,
opacity,
fillInstruction,
strokeInstruction,
) {
const fillStroke = !!(fillInstruction || strokeInstruction);
const box = dimensions.declutterBox;
const strokePadding = strokeInstruction
? (strokeInstruction[2 ] * dimensions.scale[0 ]) / 2
: 0 ;
const intersects =
box.minX - strokePadding <= scaledCanvasSize[0 ] &&
box.maxX + strokePadding >= 0 &&
box.minY - strokePadding <= scaledCanvasSize[1 ] &&
box.maxY + strokePadding >= 0 ;
if (intersects) {
if (fillStroke) {
this.replayTextBackground_(
context,
p1,
p2,
p3,
p4,
(fillInstruction),
(strokeInstruction),
);
}
drawImageOrLabel(
context,
dimensions.canvasTransform,
opacity,
imageOrLabel,
dimensions.originX,
dimensions.originY,
dimensions.drawImageW,
dimensions.drawImageH,
dimensions.drawImageX,
dimensions.drawImageY,
dimensions.scale,
);
}
return true ;
}
fill_(context) {
const alignAndScale = this.alignAndScaleFill_;
if (alignAndScale) {
const origin = applyTransform(this.renderedTransform_, [0 , 0 ]);
const repeatSize = 512 * this.pixelRatio;
context.save();
context.translate(origin[0 ] % repeatSize, origin[1 ] % repeatSize);
if (alignAndScale !== 1 ) {
context.scale(alignAndScale, alignAndScale);
}
context.rotate(this.viewRotation_);
}
context.fill();
if (alignAndScale) {
context.restore();
}
}
setStrokeStyle_(context, instruction) {
context.strokeStyle =
(instruction[1 ]);
context.lineWidth = (instruction[2 ]);
context.lineCap = (instruction[3 ]);
context.lineJoin = (instruction[4 ]);
context.miterLimit = (instruction[5 ]);
context.lineDashOffset = (instruction[7 ]);
context.setLineDash( (instruction[6 ]));
}
drawLabelWithPointPlacement_(text, textKey, strokeKey, fillKey) {
const textState = this.textStates[textKey];
const label = this.createLabel(text, textKey, fillKey, strokeKey);
const strokeState = this.strokeStates[strokeKey];
const pixelRatio = this.pixelRatio;
const align = horizontalTextAlign(
Array .isArray(text) ? text[0 ] : text,
textState.textAlign || defaultTextAlign,
);
const baseline = TEXT_ALIGN[textState.textBaseline || defaultTextBaseline];
const strokeWidth =
strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0 ;
const width = label.width / pixelRatio - 2 * textState.scale[0 ];
const anchorX = align * width + 2 * (0.5 - align) * strokeWidth;
const anchorY =
(baseline * label.height) / pixelRatio +
2 * (0.5 - baseline) * strokeWidth;
return {
label: label,
anchorX: anchorX,
anchorY: anchorY,
};
}
execute_(
context,
scaledCanvasSize,
transform,
instructions,
snapToPixel,
featureCallback,
hitExtent,
declutterTree,
) {
const zIndexContext = this.zIndexContext_;
let pixelCoordinates;
if (this.pixelCoordinates_ && equals(transform, this.renderedTransform_)) {
pixelCoordinates = this.pixelCoordinates_;
} else {
if (!this.pixelCoordinates_) {
this.pixelCoordinates_ = [];
}
pixelCoordinates = transform2D(
this.coordinates,
0 ,
this.coordinates.length,
2 ,
transform,
this.pixelCoordinates_,
);
transformSetFromArray(this.renderedTransform_, transform);
}
let i = 0 ;
const ii = instructions.length;
let d = 0 ;
let dd;
let anchorX,
anchorY,
declutterMode,
prevX,
prevY,
roundX,
roundY,
image,
text,
textKey,
strokeKey,
fillKey;
let pendingFill = 0 ;
let pendingStroke = 0 ;
let lastFillInstruction = null ;
let lastStrokeInstruction = null ;
const coordinateCache = this.coordinateCache_;
const viewRotation = this.viewRotation_;
const viewRotationFromTransform =
Math.round(Math.atan2(-transform[1 ], transform[0 ]) * 1e12 ) / 1e12 ;
const state = ({
context: context,
pixelRatio: this.pixelRatio,
resolution: this.resolution,
rotation: viewRotation,
});
const batchSize =
this.instructions != instructions || this.overlaps ? 0 : 200 ;
let feature;
let x, y, currentGeometry;
while (i < ii) {
const instruction = instructions[i];
const type = (
instruction[0 ]
);
switch (type) {
case CanvasInstruction.BEGIN_GEOMETRY:
feature = (
instruction[1 ]
);
currentGeometry = instruction[3 ];
if (!feature.getGeometry()) {
i = (instruction[2 ]);
} else if (
hitExtent !== undefined &&
!intersects(hitExtent, currentGeometry.getExtent())
) {
i = (instruction[2 ]) + 1 ;
} else {
++i;
}
if (zIndexContext) {
zIndexContext.zIndex = instruction[4 ];
}
break ;
case CanvasInstruction.BEGIN_PATH:
if (pendingFill > batchSize) {
this.fill_(context);
pendingFill = 0 ;
}
if (pendingStroke > batchSize) {
context.stroke();
pendingStroke = 0 ;
}
if (!pendingFill && !pendingStroke) {
context.beginPath();
prevX = NaN;
prevY = NaN;
}
++i;
break ;
case CanvasInstruction.CIRCLE:
d = (instruction[1 ]);
const x1 = pixelCoordinates[d];
const y1 = pixelCoordinates[d + 1 ];
const x2 = pixelCoordinates[d + 2 ];
const y2 = pixelCoordinates[d + 3 ];
const dx = x2 - x1;
const dy = y2 - y1;
const r = Math.sqrt(dx * dx + dy * dy);
context.moveTo(x1 + r, y1);
context.arc(x1, y1, r, 0 , 2 * Math.PI, true );
++i;
break ;
case CanvasInstruction.CLOSE_PATH:
context.closePath();
++i;
break ;
case CanvasInstruction.CUSTOM:
d = (instruction[1 ]);
dd = instruction[2 ];
const geometry =
(
instruction[3 ]
);
const renderer = instruction[4 ];
const fn = instruction[5 ];
state.geometry = geometry;
state.feature = feature;
if (!(i in coordinateCache)) {
coordinateCache[i] = [];
}
const coords = coordinateCache[i];
if (fn) {
fn(pixelCoordinates, d, dd, 2 , coords);
} else {
coords[0 ] = pixelCoordinates[d];
coords[1 ] = pixelCoordinates[d + 1 ];
coords.length = 2 ;
}
if (zIndexContext) {
zIndexContext.zIndex = instruction[6 ];
}
renderer(coords, state);
++i;
break ;
case CanvasInstruction.DRAW_IMAGE:
d = (instruction[1 ]);
dd = (instruction[2 ]);
image =
(
instruction[3 ]
);
anchorX = (instruction[4 ]);
anchorY = (instruction[5 ]);
let height = (instruction[6 ]);
const opacity = (instruction[7 ]);
const originX = (instruction[8 ]);
const originY = (instruction[9 ]);
const rotateWithView = (instruction[10 ]);
let rotation = (instruction[11 ]);
const scale = (
instruction[12 ]
);
let width = (instruction[13 ]);
declutterMode = instruction[14 ] || 'declutter' ;
const declutterImageWithText =
(
instruction[15 ]
);
if (!image && instruction.length >= 20 ) {
text = (instruction[19 ]);
textKey = (instruction[20 ]);
strokeKey = (instruction[21 ]);
fillKey = (instruction[22 ]);
const labelWithAnchor = this.drawLabelWithPointPlacement_(
text,
textKey,
strokeKey,
fillKey,
);
image = labelWithAnchor.label;
instruction[3 ] = image;
const textOffsetX = (instruction[23 ]);
anchorX = (labelWithAnchor.anchorX - textOffsetX) * this.pixelRatio;
instruction[4 ] = anchorX;
const textOffsetY = (instruction[24 ]);
anchorY = (labelWithAnchor.anchorY - textOffsetY) * this.pixelRatio;
instruction[5 ] = anchorY;
height = image.height;
instruction[6 ] = height;
width = image.width;
instruction[13 ] = width;
}
let geometryWidths;
if (instruction.length > 25 ) {
geometryWidths = (instruction[25 ]);
}
let padding, backgroundFill, backgroundStroke;
if (instruction.length > 17 ) {
padding = (instruction[16 ]);
backgroundFill = (instruction[17 ]);
backgroundStroke = (instruction[18 ]);
} else {
padding = defaultPadding;
backgroundFill = false ;
backgroundStroke = false ;
}
if (rotateWithView && viewRotationFromTransform) {
rotation += viewRotation;
} else if (!rotateWithView && !viewRotationFromTransform) {
rotation -= viewRotation;
}
let widthIndex = 0 ;
for (; d < dd; d += 2 ) {
if (
geometryWidths &&
geometryWidths[widthIndex++] < width / this.pixelRatio
) {
continue ;
}
const dimensions = this.calculateImageOrLabelDimensions_(
image.width,
image.height,
pixelCoordinates[d],
pixelCoordinates[d + 1 ],
width,
height,
anchorX,
anchorY,
originX,
originY,
rotation,
scale,
snapToPixel,
padding,
backgroundFill || backgroundStroke,
feature,
);
const args = [
context,
scaledCanvasSize,
image,
dimensions,
opacity,
backgroundFill
? (lastFillInstruction)
: null ,
backgroundStroke
? (lastStrokeInstruction)
: null ,
];
if (declutterTree) {
let imageArgs, imageDeclutterMode, imageDeclutterBox;
if (declutterImageWithText) {
const index = dd - d;
if (!declutterImageWithText[index]) {
declutterImageWithText[index] = {args, declutterMode};
continue ;
}
const imageDeclutter = declutterImageWithText[index];
imageArgs = imageDeclutter.args;
imageDeclutterMode = imageDeclutter.declutterMode;
delete declutterImageWithText[index];
imageDeclutterBox = getDeclutterBox(imageArgs);
}
let renderImage, renderText;
if (
imageArgs &&
(imageDeclutterMode !== 'declutter' ||
!declutterTree.collides(imageDeclutterBox))
) {
renderImage = true ;
}
if (
declutterMode !== 'declutter' ||
!declutterTree.collides(dimensions.declutterBox)
) {
renderText = true ;
}
if (
imageDeclutterMode === 'declutter' &&
declutterMode === 'declutter'
) {
const render = renderImage && renderText;
renderImage = render;
renderText = render;
}
if (renderImage) {
if (imageDeclutterMode !== 'none' ) {
declutterTree.insert(imageDeclutterBox);
}
this.replayImageOrLabel_.apply(this, imageArgs);
}
if (renderText) {
if (declutterMode !== 'none' ) {
declutterTree.insert(dimensions.declutterBox);
}
this.replayImageOrLabel_.apply(this, args);
}
} else {
this.replayImageOrLabel_.apply(this, args);
}
}
++i;
break ;
case CanvasInstruction.DRAW_CHARS:
const begin = (instruction[1 ]);
const end = (instruction[2 ]);
const baseline = (instruction[3 ]);
const overflow = (instruction[4 ]);
fillKey = (instruction[5 ]);
const maxAngle = (instruction[6 ]);
const measurePixelRatio = (instruction[7 ]);
const offsetY = (instruction[8 ]);
strokeKey = (instruction[9 ]);
const strokeWidth = (instruction[10 ]);
text = (instruction[11 ]);
textKey = (instruction[12 ]);
const pixelRatioScale = [
(instruction[13 ]),
(instruction[13 ]),
];
declutterMode = instruction[14 ] || 'declutter' ;
const textState = this.textStates[textKey];
const font = textState.font;
const textScale = [
textState.scale[0 ] * measurePixelRatio,
textState.scale[1 ] * measurePixelRatio,
];
let cachedWidths;
if (font in this.widths_) {
cachedWidths = this.widths_[font];
} else {
cachedWidths = {};
this.widths_[font] = cachedWidths;
}
const pathLength = lineStringLength(pixelCoordinates, begin, end, 2 );
const textLength =
Math.abs(textScale[0 ]) *
measureAndCacheTextWidth(font, text, cachedWidths);
if (overflow || textLength <= pathLength) {
const textAlign = this.textStates[textKey].textAlign;
const startM =
(pathLength - textLength) * horizontalTextAlign(text, textAlign);
const parts = drawTextOnPath(
pixelCoordinates,
begin,
end,
2 ,
text,
startM,
maxAngle,
Math.abs(textScale[0 ]),
measureAndCacheTextWidth,
font,
cachedWidths,
viewRotationFromTransform ? 0 : this.viewRotation_,
);
drawChars: if (parts) {
const replayImageOrLabelArgs = [];
let c, cc, chars, label, part;
if (strokeKey) {
for (c = 0 , cc = parts.length; c < cc; ++c) {
part = parts[c];
chars = (part[4 ]);
label = this.createLabel(chars, textKey, '' , strokeKey);
anchorX =
(part[2 ]) +
(textScale[0 ] < 0 ? -strokeWidth : strokeWidth);
anchorY =
baseline * label.height +
((0.5 - baseline) * 2 * strokeWidth * textScale[1 ]) /
textScale[0 ] -
offsetY;
const dimensions = this.calculateImageOrLabelDimensions_(
label.width,
label.height,
part[0 ],
part[1 ],
label.width,
label.height,
anchorX,
anchorY,
0 ,
0 ,
part[3 ],
pixelRatioScale,
false ,
defaultPadding,
false ,
feature,
);
if (
declutterTree &&
declutterMode === 'declutter' &&
declutterTree.collides(dimensions.declutterBox)
) {
break drawChars;
}
replayImageOrLabelArgs.push([
context,
scaledCanvasSize,
label,
dimensions,
1 ,
null ,
null ,
]);
}
}
if (fillKey) {
for (c = 0 , cc = parts.length; c < cc; ++c) {
part = parts[c];
chars = (part[4 ]);
label = this.createLabel(chars, textKey, fillKey, '' );
anchorX = (part[2 ]);
anchorY = baseline * label.height - offsetY;
const dimensions = this.calculateImageOrLabelDimensions_(
label.width,
label.height,
part[0 ],
part[1 ],
label.width,
label.height,
anchorX,
anchorY,
0 ,
0 ,
part[3 ],
pixelRatioScale,
false ,
defaultPadding,
false ,
feature,
);
if (
declutterTree &&
declutterMode === 'declutter' &&
declutterTree.collides(dimensions.declutterBox)
) {
break drawChars;
}
replayImageOrLabelArgs.push([
context,
scaledCanvasSize,
label,
dimensions,
1 ,
null ,
null ,
]);
}
}
if (declutterTree && declutterMode !== 'none' ) {
declutterTree.load(replayImageOrLabelArgs.map(getDeclutterBox));
}
for (let i = 0 , ii = replayImageOrLabelArgs.length; i < ii; ++i) {
this.replayImageOrLabel_.apply(this, replayImageOrLabelArgs[i]);
}
}
}
++i;
break ;
case CanvasInstruction.END_GEOMETRY:
if (featureCallback !== undefined) {
feature = (
instruction[1 ]
);
const result = featureCallback(
feature,
currentGeometry,
declutterMode,
);
if (result) {
return result;
}
}
++i;
break ;
case CanvasInstruction.FILL:
if (batchSize) {
pendingFill++;
} else {
this.fill_(context);
}
++i;
break ;
case CanvasInstruction.MOVE_TO_LINE_TO:
d = (instruction[1 ]);
dd = (instruction[2 ]);
x = pixelCoordinates[d];
y = pixelCoordinates[d + 1 ];
context.moveTo(x, y);
prevX = (x + 0.5 ) | 0 ;
prevY = (y + 0.5 ) | 0 ;
for (d += 2 ; d < dd; d += 2 ) {
x = pixelCoordinates[d];
y = pixelCoordinates[d + 1 ];
roundX = (x + 0.5 ) | 0 ;
roundY = (y + 0.5 ) | 0 ;
if (d == dd - 2 || roundX !== prevX || roundY !== prevY) {
context.lineTo(x, y);
prevX = roundX;
prevY = roundY;
}
}
++i;
break ;
case CanvasInstruction.SET_FILL_STYLE:
lastFillInstruction = instruction;
this.alignAndScaleFill_ = instruction[2 ];
if (pendingFill) {
this.fill_(context);
pendingFill = 0 ;
if (pendingStroke) {
context.stroke();
pendingStroke = 0 ;
}
}
context.fillStyle = instruction[1 ];
++i;
break ;
case CanvasInstruction.SET_STROKE_STYLE:
lastStrokeInstruction = instruction;
if (pendingStroke) {
context.stroke();
pendingStroke = 0 ;
}
this.setStrokeStyle_(context, (instruction));
++i;
break ;
case CanvasInstruction.STROKE:
if (batchSize) {
pendingStroke++;
} else {
context.stroke();
}
++i;
break ;
default :
++i;
break ;
}
}
if (pendingFill) {
this.fill_(context);
}
if (pendingStroke) {
context.stroke();
}
return undefined;
}
execute(
context,
scaledCanvasSize,
transform,
viewRotation,
snapToPixel,
declutterTree,
) {
this.viewRotation_ = viewRotation;
this.execute_(
context,
scaledCanvasSize,
transform,
this.instructions,
snapToPixel,
undefined,
undefined,
declutterTree,
);
}
executeHitDetection(
context,
transform,
viewRotation,
featureCallback,
hitExtent,
) {
this.viewRotation_ = viewRotation;
return this.execute_(
context,
[context.canvas.width, context.canvas.height],
transform,
this.hitDetectionInstructions,
true ,
featureCallback,
hitExtent,
);
}
}
export default Executor;