Style texts and draw them on canvas
This commit is contained in:
@@ -1,47 +1,99 @@
|
|||||||
goog.provide('ol.render.webgl.TextReplay');
|
goog.provide('ol.render.webgl.TextReplay');
|
||||||
|
|
||||||
goog.require('ol');
|
goog.require('ol');
|
||||||
|
goog.require('ol.colorlike');
|
||||||
|
goog.require('ol.has');
|
||||||
|
goog.require('ol.render.webgl');
|
||||||
|
goog.require('ol.render.webgl.imagereplay.defaultshader');
|
||||||
|
goog.require('ol.render.webgl.Replay');
|
||||||
|
goog.require('ol.webgl');
|
||||||
|
goog.require('ol.webgl.Context');
|
||||||
|
|
||||||
|
|
||||||
if (ol.ENABLE_WEBGL) {
|
if (ol.ENABLE_WEBGL) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
* @abstract
|
* @extends {ol.render.webgl.Replay}
|
||||||
* @param {number} tolerance Tolerance.
|
* @param {number} tolerance Tolerance.
|
||||||
* @param {ol.Extent} maxExtent Max extent.
|
* @param {ol.Extent} maxExtent Max extent.
|
||||||
* @struct
|
* @struct
|
||||||
*/
|
*/
|
||||||
ol.render.webgl.TextReplay = function(tolerance, maxExtent) {};
|
ol.render.webgl.TextReplay = function(tolerance, maxExtent) {
|
||||||
|
ol.render.webgl.Replay.call(this, tolerance, maxExtent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ol.style.Text} textStyle Text style.
|
* @private
|
||||||
*/
|
* @type {ol.render.webgl.imagereplay.defaultshader.Locations}
|
||||||
ol.render.webgl.TextReplay.prototype.setTextStyle = function(textStyle) {};
|
*/
|
||||||
|
this.defaultLocations_ = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {Array.<Array.<?>>}
|
||||||
|
*/
|
||||||
|
this.styles_ = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {Array.<number>}
|
||||||
|
*/
|
||||||
|
this.styleIndices_ = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {Array.<HTMLCanvasElement>}
|
||||||
|
*/
|
||||||
|
this.images_ = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {Array.<WebGLTexture>}
|
||||||
|
*/
|
||||||
|
this.textures_ = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {{strokeColor: (ol.ColorLike|null),
|
||||||
|
* lineCap: (string|undefined),
|
||||||
|
* lineDash: Array.<number>,
|
||||||
|
* lineDashOffset: (number|undefined),
|
||||||
|
* lineJoin: (string|undefined),
|
||||||
|
* lineWidth: (number|undefined),
|
||||||
|
* miterLimit: (number|undefined),
|
||||||
|
* fillColor: (ol.ColorLike|null),
|
||||||
|
* text: string,
|
||||||
|
* font: (string|undefined),
|
||||||
|
* textAlign: (string|undefined),
|
||||||
|
* textBaseline: (string|undefined),
|
||||||
|
* offsetX: (number|undefined),
|
||||||
|
* offsetY: (number|undefined),
|
||||||
|
* scale: (number|undefined),
|
||||||
|
* rotation: (number|undefined),
|
||||||
|
* rotateWithView: (boolean|undefined)}
|
||||||
|
*/
|
||||||
|
this.state_ = {
|
||||||
|
strokeColor: null,
|
||||||
|
lineCap: undefined,
|
||||||
|
lineDash: null,
|
||||||
|
lineDashOffset: undefined,
|
||||||
|
lineJoin: undefined,
|
||||||
|
lineWidth: undefined,
|
||||||
|
miterLimit: undefined,
|
||||||
|
fillColor: null,
|
||||||
|
text: '',
|
||||||
|
font: undefined,
|
||||||
|
textAlign: undefined,
|
||||||
|
textBaseline: undefined,
|
||||||
|
offsetX: undefined,
|
||||||
|
offsetY: undefined,
|
||||||
|
scale: undefined,
|
||||||
|
rotation: undefined,
|
||||||
|
rotateWithView: undefined
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {ol.webgl.Context} context Context.
|
|
||||||
* @param {ol.Coordinate} center Center.
|
|
||||||
* @param {number} resolution Resolution.
|
|
||||||
* @param {number} rotation Rotation.
|
|
||||||
* @param {ol.Size} size Size.
|
|
||||||
* @param {number} pixelRatio Pixel ratio.
|
|
||||||
* @param {number} opacity Global opacity.
|
|
||||||
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
|
|
||||||
* to skip.
|
|
||||||
* @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
|
|
||||||
* @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
|
|
||||||
* @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
|
|
||||||
* this extent are checked.
|
|
||||||
* @return {T|undefined} Callback result.
|
|
||||||
* @template T
|
|
||||||
*/
|
|
||||||
ol.render.webgl.TextReplay.prototype.replay = function(context,
|
|
||||||
center, resolution, rotation, size, pixelRatio,
|
|
||||||
opacity, skippedFeaturesHash,
|
|
||||||
featureCallback, oneByOne, opt_hitExtent) {
|
|
||||||
return undefined;
|
|
||||||
};
|
};
|
||||||
|
ol.inherits(ol.render.webgl.TextReplay, ol.render.webgl.Replay);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Array.<number>} flatCoordinates Flat coordinates.
|
* @param {Array.<number>} flatCoordinates Flat coordinates.
|
||||||
@@ -52,7 +104,72 @@ if (ol.ENABLE_WEBGL) {
|
|||||||
* @param {ol.Feature|ol.render.Feature} feature Feature.
|
* @param {ol.Feature|ol.render.Feature} feature Feature.
|
||||||
*/
|
*/
|
||||||
ol.render.webgl.TextReplay.prototype.drawText = function(flatCoordinates, offset,
|
ol.render.webgl.TextReplay.prototype.drawText = function(flatCoordinates, offset,
|
||||||
end, stride, geometry, feature) {};
|
end, stride, geometry, feature) {
|
||||||
|
//For now we create one texture per feature. That is, only multiparts are grouped.
|
||||||
|
//TODO: speed up rendering with SDF, or at least glyph atlases
|
||||||
|
var state = this.state_;
|
||||||
|
if (state.text && (state.fillColor || state.strokeColor)) {
|
||||||
|
this.images_.push(this.createTextImage_());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @return {HTMLCanvasElement} Text image.
|
||||||
|
*/
|
||||||
|
ol.render.webgl.TextReplay.prototype.createTextImage_ = function() {
|
||||||
|
var state = this.state_;
|
||||||
|
var canvas = document.createElement('canvas');
|
||||||
|
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
ctx.font = state.font;
|
||||||
|
var lineHeight = Math.round(ctx.measureText('M').width * 1.5 + state.lineWidth * 2);
|
||||||
|
var lines = state.text.split('\n');
|
||||||
|
//FIXME: use pixelRatio
|
||||||
|
var textHeight = Math.ceil(lineHeight * lines.length * state.scale);
|
||||||
|
var longestLine = lines.map(function(str) {
|
||||||
|
return ctx.measureText(str).width;
|
||||||
|
}).reduce(function(max, curr) {
|
||||||
|
return Math.max(max, curr);
|
||||||
|
});
|
||||||
|
//FIXME: use pixelRatio
|
||||||
|
var textWidth = Math.ceil((longestLine + state.lineWidth * 2) * state.scale);
|
||||||
|
|
||||||
|
//Parameterize the canvas
|
||||||
|
canvas.width = textWidth;
|
||||||
|
canvas.height = textHeight;
|
||||||
|
ctx.fillStyle = state.fillColor;
|
||||||
|
ctx.strokeStyle = state.strokeColor;
|
||||||
|
ctx.lineWidth = state.lineWidth;
|
||||||
|
ctx.lineCap = state.lineCap;
|
||||||
|
ctx.lineJoin = state.lineJoin;
|
||||||
|
ctx.miterLimit = state.miterLimit;
|
||||||
|
ctx.textAlign = 'left';
|
||||||
|
ctx.textBaseline = 'top';
|
||||||
|
if (ol.has.CANVAS_LINE_DASH) {
|
||||||
|
//FIXME: use pixelRatio
|
||||||
|
ctx.setLineDash(state.lineDash);
|
||||||
|
ctx.lineDashOffset = state.lineDashOffset;
|
||||||
|
}
|
||||||
|
if (state.scale !== 1) {
|
||||||
|
//FIXME: use pixelRatio
|
||||||
|
ctx.setTransform(state.scale, 0, 0, state.scale, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Draw the text on the canvas
|
||||||
|
var lineY = 0;
|
||||||
|
for (var i = 0, ii = lines.length; i < ii; ++i) {
|
||||||
|
if (state.strokeColor) {
|
||||||
|
ctx.strokeText(lines[i], 0, lineY);
|
||||||
|
}
|
||||||
|
if (state.fillColor) {
|
||||||
|
ctx.fillText(lines[i], 0, lineY);
|
||||||
|
}
|
||||||
|
lineY += lineHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return canvas;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract
|
* @abstract
|
||||||
@@ -61,11 +178,65 @@ if (ol.ENABLE_WEBGL) {
|
|||||||
ol.render.webgl.TextReplay.prototype.finish = function(context) {};
|
ol.render.webgl.TextReplay.prototype.finish = function(context) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ol.webgl.Context} context WebGL context.
|
* @inheritDoc
|
||||||
* @return {function()} Delete resources function.
|
|
||||||
*/
|
*/
|
||||||
ol.render.webgl.TextReplay.prototype.getDeleteResourcesFunction = function(context) {
|
ol.render.webgl.TextReplay.prototype.getDeleteResourcesFunction = function(context) {
|
||||||
return ol.nullFunction;
|
var verticesBuffer = this.verticesBuffer;
|
||||||
|
var indicesBuffer = this.indicesBuffer;
|
||||||
|
var textures = this.textures_;
|
||||||
|
var gl = context.getGL();
|
||||||
|
return function() {
|
||||||
|
if (!gl.isContextLost()) {
|
||||||
|
var i, ii;
|
||||||
|
for (i = 0, ii = textures.length; i < ii; ++i) {
|
||||||
|
gl.deleteTexture(textures[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.deleteBuffer(verticesBuffer);
|
||||||
|
context.deleteBuffer(indicesBuffer);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ol.style.Text} textStyle Text style.
|
||||||
|
*/
|
||||||
|
ol.render.webgl.TextReplay.prototype.setTextStyle = function(textStyle) {
|
||||||
|
var state = this.state_;
|
||||||
|
if (!textStyle) {
|
||||||
|
state.text = '';
|
||||||
|
} else {
|
||||||
|
var textFillStyle = textStyle.getFill();
|
||||||
|
if (!textFillStyle) {
|
||||||
|
state.fillColor = null;
|
||||||
|
} else {
|
||||||
|
var textFillStyleColor = textFillStyle.getColor();
|
||||||
|
state.fillColor = ol.colorlike.asColorLike(textFillStyleColor ?
|
||||||
|
textFillStyleColor : ol.render.webgl.defaultFillStyle);
|
||||||
|
}
|
||||||
|
var textStrokeStyle = textStyle.getStroke();
|
||||||
|
if (!textStrokeStyle) {
|
||||||
|
state.strokeColor = null;
|
||||||
|
} else {
|
||||||
|
var textStrokeStyleColor = textFillStyle.getColor();
|
||||||
|
state.strokeColor = ol.colorlike.asColorLike(textStrokeStyleColor ?
|
||||||
|
textStrokeStyleColor : ol.render.webgl.defaultStrokeStyle);
|
||||||
|
state.lineWidth = textStrokeStyle.getWidth() || ol.render.webgl.defaultLineWidth;
|
||||||
|
state.lineCap = textStrokeStyle.getLineCap() || ol.render.webgl.defaultLineCap;
|
||||||
|
state.lineDash = textStrokeStyle.getLineDash() || ol.render.webgl.defaultLineDash;
|
||||||
|
state.lineDashOffset = textStrokeStyle.getLineDashOffset() || ol.render.webgl.defaultLineDashOffset;
|
||||||
|
state.lineJoin = textStrokeStyle.getLineJoin() || ol.render.webgl.defaultLineJoin;
|
||||||
|
state.miterLimit = textStrokeStyle.getMiterLimit() || ol.render.webgl.defaultMiterLimit;
|
||||||
|
}
|
||||||
|
state.font = textStyle.getFont() || ol.render.webgl.defaultFont;
|
||||||
|
state.offsetX = textStyle.getOffsetX() || 0;
|
||||||
|
state.offsetY = textStyle.getOffsetY() || 0;
|
||||||
|
state.rotateWithView = !!textStyle.getRotateWithView();
|
||||||
|
state.rotation = textStyle.getRotation() || 0;
|
||||||
|
state.scale = textStyle.getScale() || 1;
|
||||||
|
state.text = textStyle.getText() || '';
|
||||||
|
state.textAlign = textStyle.getTextAlign() || ol.render.webgl.defaultTextAlign;
|
||||||
|
state.textBaseline = textStyle.getTextBaseline() || ol.render.webgl.defaultTextBaseline;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user