Make text states available for replay time

This commit is contained in:
Andreas Hocevar
2017-11-15 23:13:21 +01:00
parent 4b0281bc8a
commit ad8e4debbe
4 changed files with 93 additions and 31 deletions

View File

@@ -15,6 +15,7 @@ goog.require('ol.obj');
goog.require('ol.render.VectorContext');
goog.require('ol.render.canvas');
goog.require('ol.render.canvas.Instruction');
goog.require('ol.render.replay');
goog.require('ol.transform');
@@ -691,29 +692,30 @@ ol.render.canvas.Replay.prototype.replay_ = function(
var baseline = /** @type {number} */ (instruction[3]);
declutterGroup = /** @type {ol.DeclutterGroup} */ (instruction[4]);
var exceedLength = /** @type {number} */ (instruction[5]);
var fill = /** @type {boolean} */ (instruction[6]);
var fillKey = /** @type {string} */ (instruction[6]);
var maxAngle = /** @type {number} */ (instruction[7]);
var measure = /** @type {function(string):number} */ (instruction[8]);
var offsetY = /** @type {number} */ (instruction[9]);
var stroke = /** @type {boolean} */ (instruction[10]);
var strokeKey = /** @type {string} */ (instruction[10]);
var strokeWidth = /** @type {number} */ (instruction[11]);
var text = /** @type {string} */ (instruction[12]);
var textAlign = /** @type {number} */ (instruction[13]);
var textKey = /** @type {string} */ (instruction[13]);
var textScale = /** @type {number} */ (instruction[14]);
var pathLength = ol.geom.flat.length.lineString(pixelCoordinates, begin, end, 2);
var textLength = measure(text);
if (exceedLength || textLength <= pathLength) {
var startM = (pathLength - textLength) * textAlign;
var textAlign = /** @type {ol.render.canvas.TextReplay} */ (this).textStates[textKey].textAlign;
var startM = (pathLength - textLength) * ol.render.replay.TEXT_ALIGN[textAlign];
var parts = ol.geom.flat.textpath.lineString(
pixelCoordinates, begin, end, 2, text, measure, startM, maxAngle);
if (parts) {
var c, cc, chars, label, part;
if (stroke) {
if (strokeKey) {
for (c = 0, cc = parts.length; c < cc; ++c) {
part = parts[c]; // x, y, anchorX, rotation, chunk
chars = /** @type {string} */ (part[4]);
label = /** @type {ol.render.canvas.TextReplay} */ (this).getImage(chars, false, true);
label = /** @type {ol.render.canvas.TextReplay} */ (this).getImage(chars, textKey, '', strokeKey);
anchorX = /** @type {number} */ (part[2]) + strokeWidth;
anchorY = baseline * label.height + (0.5 - baseline) * 2 * strokeWidth - offsetY;
this.replayImage_(context,
@@ -723,11 +725,11 @@ ol.render.canvas.Replay.prototype.replay_ = function(
ol.render.canvas.defaultPadding, null, null);
}
}
if (fill) {
if (fillKey) {
for (c = 0, cc = parts.length; c < cc; ++c) {
part = parts[c]; // x, y, anchorX, rotation, chunk
chars = /** @type {string} */ (part[4]);
label = /** @type {ol.render.canvas.TextReplay} */ (this).getImage(chars, true, false);
label = /** @type {ol.render.canvas.TextReplay} */ (this).getImage(chars, textKey, fillKey, '');
anchorX = /** @type {number} */ (part[2]);
anchorY = baseline * label.height - offsetY;
this.replayImage_(context,

View File

@@ -78,18 +78,33 @@ ol.render.canvas.TextReplay = function(
*/
this.textFillState_ = null;
/**
* @type {Object.<string, ol.CanvasFillState>}
*/
this.fillStates = {};
/**
* @private
* @type {?ol.CanvasStrokeState}
*/
this.textStrokeState_ = null;
/**
* @type {Object.<string, ol.CanvasStrokeState>}
*/
this.strokeStates = {};
/**
* @private
* @type {ol.CanvasTextState}
*/
this.textState_ = /** @type {ol.CanvasTextState} */ ({});
/**
* @type {Object.<string, ol.CanvasTextState>}
*/
this.textStates = {};
/**
* @private
* @type {string}
@@ -110,7 +125,7 @@ ol.render.canvas.TextReplay = function(
/**
* @private
* @type {Object.<string, number>}
* @type {Object.<string, Object.<string, number>>}
*/
this.widths_ = {};
@@ -248,7 +263,7 @@ ol.render.canvas.TextReplay.prototype.drawText = function(geometry, feature) {
this.endGeometry(geometry, feature);
} else {
var label = this.getImage(this.text_, !!this.textFillState_, !!this.textStrokeState_);
var label = this.getImage(this.text_, this.textKey_, this.fillKey_, this.strokeKey_);
var width = label.width / this.pixelRatio;
switch (geometryType) {
case ol.geom.GeometryType.POINT:
@@ -303,23 +318,24 @@ ol.render.canvas.TextReplay.prototype.drawText = function(geometry, feature) {
/**
* @param {string} text Text.
* @param {boolean} fill Fill.
* @param {boolean} stroke Stroke.
* @param {string} textKey Text style key.
* @param {string} fillKey Fill style key.
* @param {string} strokeKey Stroke style key.
* @return {HTMLCanvasElement} Image.
*/
ol.render.canvas.TextReplay.prototype.getImage = function(text, fill, stroke) {
ol.render.canvas.TextReplay.prototype.getImage = function(text, textKey, fillKey, strokeKey) {
var label;
var key = (stroke ? this.strokeKey_ : '') + this.textKey_ + text + (fill ? this.fillKey_ : '');
var key = strokeKey + textKey + text + fillKey;
var labelCache = ol.render.canvas.labelCache;
if (!labelCache.containsKey(key)) {
var strokeState = this.textStrokeState_;
var fillState = this.textFillState_;
var textState = this.textState_;
var strokeState = strokeKey ? this.strokeStates[strokeKey] || this.textStrokeState_ : null;
var fillState = fillKey ? this.fillStates[fillKey] || this.textFillState_ : null;
var textState = this.textStates[textKey] || this.textState_;
var pixelRatio = this.pixelRatio;
var scale = textState.scale * pixelRatio;
var align = ol.render.replay.TEXT_ALIGN[textState.textAlign || ol.render.canvas.defaultTextAlign];
var strokeWidth = stroke && strokeState.lineWidth ? strokeState.lineWidth : 0;
var strokeWidth = strokeKey && strokeState.lineWidth ? strokeState.lineWidth : 0;
var lines = text.split('\n');
var numLines = lines.length;
@@ -337,7 +353,7 @@ ol.render.canvas.TextReplay.prototype.getImage = function(text, fill, stroke) {
context.scale(scale, scale);
}
context.font = textState.font;
if (stroke) {
if (strokeKey) {
context.strokeStyle = strokeState.strokeStyle;
context.lineWidth = strokeWidth * (ol.has.SAFARI ? scale : 1);
context.lineCap = strokeState.lineCap;
@@ -348,7 +364,7 @@ ol.render.canvas.TextReplay.prototype.getImage = function(text, fill, stroke) {
context.lineDashOffset = strokeState.lineDashOffset;
}
}
if (fill) {
if (fillKey) {
context.fillStyle = fillState.fillStyle;
}
context.textBaseline = 'top';
@@ -356,12 +372,12 @@ ol.render.canvas.TextReplay.prototype.getImage = function(text, fill, stroke) {
var leftRight = (0.5 - align);
var x = align * label.width / scale + leftRight * strokeWidth;
var i;
if (stroke) {
if (strokeKey) {
for (i = 0; i < numLines; ++i) {
context.strokeText(lines[i], x + leftRight * widths[i], 0.5 * strokeWidth + i * lineHeight);
}
}
if (fill) {
if (fillKey) {
for (i = 0; i < numLines; ++i) {
context.fillText(lines[i], x + leftRight * widths[i], 0.5 * strokeWidth + i * lineHeight);
}
@@ -413,23 +429,56 @@ ol.render.canvas.TextReplay.prototype.drawTextImage_ = function(label, begin, en
* @param {ol.DeclutterGroup} declutterGroup Declutter group.
*/
ol.render.canvas.TextReplay.prototype.drawChars_ = function(begin, end, declutterGroup) {
var pixelRatio = this.pixelRatio;
var strokeState = this.textStrokeState_;
var fill = !!this.textFillState_;
var stroke = !!strokeState;
var textState = this.textState_;
var fillState = this.textFillState_;
var strokeKey = this.strokeKey_;
if (strokeState) {
if (!(strokeKey in this.strokeStates)) {
this.strokeStates[strokeKey] = /** @type {ol.CanvasStrokeState} */ ({
strokeStyle: strokeState.strokeStyle,
lineCap: strokeState.lineCap,
lineDashOffset: strokeState.lineDashOffset,
lineWidth: strokeState.lineWidth,
lineJoin: strokeState.lineJoin,
miterLimit: strokeState.miterLimit,
lineDash: strokeState.lineDash
});
}
}
var textKey = this.textKey_;
if (!(this.textKey_ in this.textStates)) {
this.textStates[this.textKey_] = /** @type {ol.CanvasTextState} */ ({
font: textState.font,
textAlign: textState.textAlign || ol.render.canvas.defaultTextAlign,
scale: textState.scale
});
}
var fillKey = this.fillKey_;
if (fillState) {
if (!(fillKey in this.fillStates)) {
this.fillStates[fillKey] = /** @type {ol.CanvasFillState} */ ({
fillStyle: fillState.fillStyle
});
}
}
var pixelRatio = this.pixelRatio;
var baseline = ol.render.replay.TEXT_ALIGN[textState.textBaseline];
var offsetY = this.textOffsetY_ * pixelRatio;
var textAlign = ol.render.replay.TEXT_ALIGN[textState.textAlign || ol.render.canvas.defaultTextAlign];
var text = this.text_;
var font = textState.font;
var textScale = textState.scale;
var strokeWidth = strokeState ? strokeState.lineWidth * textScale / 2 : 0;
var widths = this.widths_;
var widths = this.widths_[font];
if (!widths) {
this.widths_[font] = widths = {};
}
this.instructions.push([ol.render.canvas.Instruction.DRAW_CHARS,
begin, end, baseline, declutterGroup,
textState.exceedLength, fill, textState.maxAngle,
textState.exceedLength, fillKey, textState.maxAngle,
function(text) {
var width = widths[text];
if (!width) {
@@ -437,11 +486,11 @@ ol.render.canvas.TextReplay.prototype.drawChars_ = function(begin, end, declutte
}
return width * textScale * pixelRatio;
},
offsetY, stroke, strokeWidth * pixelRatio, text, textAlign, 1
offsetY, strokeKey, strokeWidth * pixelRatio, text, textKey, 1
]);
this.hitDetectionInstructions.push([ol.render.canvas.Instruction.DRAW_CHARS,
begin, end, baseline, declutterGroup,
textState.exceedLength, fill, textState.maxAngle,
textState.exceedLength, fillKey, textState.maxAngle,
function(text) {
var width = widths[text];
if (!width) {
@@ -449,7 +498,7 @@ ol.render.canvas.TextReplay.prototype.drawChars_ = function(begin, end, declutte
}
return width * textScale;
},
offsetY, stroke, strokeWidth, text, textAlign, 1 / pixelRatio
offsetY, strokeKey, strokeWidth, text, textKey, 1 / pixelRatio
]);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -304,6 +304,17 @@ describe('ol.rendering.style.Text', function() {
expectResemble(map, 'rendering/ol/style/expected/text-linestring-nice.png', 2.8, done);
});
it('uses correct font with different styles', function(done) {
createMap('canvas');
createLineString(nicePath);
map.getView().setResolution(0.25);
vectorSource.getFeatures()[0].getStyle().getText().setFont('18px monospace');
vectorSource.getFeatures()[1].getStyle().getText().setFont('italic 38px serif');
vectorSource.getFeatures()[1].getStyle().getText().setTextBaseline('middle');
vectorSource.getFeatures()[2].getStyle().getText().setTextBaseline('middle');
expectResemble(map, 'rendering/ol/style/expected/text-linestring-nice-multi-font.png', 7.54, done);
});
it('renders text along a linestring with scale != 1', function(done) {
createMap('canvas');
createLineString(nicePath, undefined, undefined, undefined, undefined, 2);