Merge pull request #7239 from ahocevar/linestring-text
Render text along lines
@@ -3,14 +3,8 @@ layout: example.html
|
|||||||
title: Street Labels
|
title: Street Labels
|
||||||
shortdesc: Render street names with a custom render.
|
shortdesc: Render street names with a custom render.
|
||||||
docs: >
|
docs: >
|
||||||
Example showing the use of a custom renderer to render text along a path. [Labelgun](https://github.com/Geovation/labelgun) is used to avoid label collisions. [label-segment](https://github.com/ahocevar/label-segment) makes sure that labels are placed on suitable street segments. [textpath](https://github.com/ahocevar/textpath) arranges the letters of a label along the geometry.
|
Example showing the use of a text style with `placement: 'line'` to render text along a path.
|
||||||
tags: "vector, label, collision detection, labelgun, linelabel"
|
tags: "vector, label, streets"
|
||||||
resources:
|
|
||||||
- https://cdn.polyfill.io/v2/polyfill.min.js?features=Set
|
|
||||||
- https://unpkg.com/rbush@2.0.1/rbush.min.js
|
|
||||||
- https://unpkg.com/labelgun@0.1.1/lib/labelgun.min.js
|
|
||||||
- https://unpkg.com/textpath@1.0.1/dist/textpath.js
|
|
||||||
- https://unpkg.com/label-segment@1.0.0/dist/label-segment.js
|
|
||||||
cloak:
|
cloak:
|
||||||
As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// NOCOMPILE
|
|
||||||
/* global labelgun, labelSegment, textPath */
|
|
||||||
goog.require('ol.Map');
|
goog.require('ol.Map');
|
||||||
goog.require('ol.View');
|
goog.require('ol.View');
|
||||||
goog.require('ol.extent');
|
goog.require('ol.extent');
|
||||||
@@ -8,64 +6,37 @@ goog.require('ol.layer.Tile');
|
|||||||
goog.require('ol.layer.Vector');
|
goog.require('ol.layer.Vector');
|
||||||
goog.require('ol.source.BingMaps');
|
goog.require('ol.source.BingMaps');
|
||||||
goog.require('ol.source.Vector');
|
goog.require('ol.source.Vector');
|
||||||
|
goog.require('ol.style.Fill');
|
||||||
goog.require('ol.style.Style');
|
goog.require('ol.style.Style');
|
||||||
|
goog.require('ol.style.Text');
|
||||||
var emptyFn = function() {};
|
|
||||||
var labelEngine = new labelgun['default'](emptyFn, emptyFn);
|
|
||||||
|
|
||||||
var context, pixelRatio; // Will be set in the map's postcompose listener
|
|
||||||
function measureText(text) {
|
|
||||||
return context.measureText(text).width * pixelRatio;
|
|
||||||
}
|
|
||||||
|
|
||||||
var extent, letters; // Will be set in the style's renderer function
|
|
||||||
function collectDrawData(letter, x, y, angle) {
|
|
||||||
ol.extent.extend(extent, [x, y, x, y]);
|
|
||||||
letters.push([x, y, angle, letter]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var style = new ol.style.Style({
|
var style = new ol.style.Style({
|
||||||
renderer: function(coords, state) {
|
text: new ol.style.Text({
|
||||||
var feature = state.feature;
|
font: 'bold 11px "Open Sans", "Arial Unicode MS", "sans-serif"',
|
||||||
var text = feature.get('name');
|
placement: 'line',
|
||||||
// Only create label when geometry has a long and straight segment
|
fill: new ol.style.Fill({
|
||||||
var path = labelSegment(coords, Math.PI / 8, measureText(text));
|
color: 'white'
|
||||||
if (path) {
|
})
|
||||||
extent = ol.extent.createEmpty();
|
|
||||||
letters = [];
|
|
||||||
textPath(text, path, measureText, collectDrawData);
|
|
||||||
ol.extent.buffer(extent, 5 * pixelRatio, extent);
|
|
||||||
var bounds = {
|
|
||||||
bottomLeft: ol.extent.getBottomLeft(extent),
|
|
||||||
topRight: ol.extent.getTopRight(extent)
|
|
||||||
};
|
|
||||||
labelEngine.ingestLabel(bounds, feature.getId(), 1, letters, text, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var rasterLayer = new ol.layer.Tile({
|
|
||||||
source: new ol.source.BingMaps({
|
|
||||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
|
|
||||||
imagerySet: 'Aerial'
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
var vectorLayer = new ol.layer.Vector({
|
|
||||||
source: new ol.source.Vector({
|
|
||||||
format: new ol.format.GeoJSON(),
|
|
||||||
url: 'data/geojson/vienna-streets.geojson'
|
|
||||||
}),
|
|
||||||
style: function(feature) {
|
|
||||||
if (feature.getGeometry().getType() == 'LineString' && feature.get('name')) {
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var viewExtent = [1817379, 6139595, 1827851, 6143616];
|
var viewExtent = [1817379, 6139595, 1827851, 6143616];
|
||||||
var map = new ol.Map({
|
var map = new ol.Map({
|
||||||
layers: [rasterLayer, vectorLayer],
|
layers: [new ol.layer.Tile({
|
||||||
|
source: new ol.source.BingMaps({
|
||||||
|
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5',
|
||||||
|
imagerySet: 'Aerial'
|
||||||
|
})
|
||||||
|
}), new ol.layer.Vector({
|
||||||
|
source: new ol.source.Vector({
|
||||||
|
format: new ol.format.GeoJSON(),
|
||||||
|
url: 'data/geojson/vienna-streets.geojson'
|
||||||
|
}),
|
||||||
|
style: function(feature) {
|
||||||
|
style.getText().setText(feature.get('name'));
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
})],
|
||||||
target: 'map',
|
target: 'map',
|
||||||
view: new ol.View({
|
view: new ol.View({
|
||||||
extent: viewExtent,
|
extent: viewExtent,
|
||||||
@@ -74,31 +45,3 @@ var map = new ol.Map({
|
|||||||
minZoom: 14
|
minZoom: 14
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
vectorLayer.on('precompose', function() {
|
|
||||||
labelEngine.destroy();
|
|
||||||
});
|
|
||||||
vectorLayer.on('postcompose', function(e) {
|
|
||||||
context = e.context;
|
|
||||||
pixelRatio = e.frameState.pixelRatio;
|
|
||||||
context.save();
|
|
||||||
context.font = 'normal 11px "Open Sans", "Arial Unicode MS"';
|
|
||||||
context.fillStyle = 'white';
|
|
||||||
context.textBaseline = 'middle';
|
|
||||||
context.textAlign = 'center';
|
|
||||||
var labels = labelEngine.getShown();
|
|
||||||
for (var i = 0, ii = labels.length; i < ii; ++i) {
|
|
||||||
// Render label letter by letter
|
|
||||||
var letters = labels[i].labelObject;
|
|
||||||
for (var j = 0, jj = letters.length; j < jj; ++j) {
|
|
||||||
var labelData = letters[j];
|
|
||||||
context.save();
|
|
||||||
context.translate(labelData[0], labelData[1]);
|
|
||||||
context.rotate(labelData[2]);
|
|
||||||
context.scale(pixelRatio, pixelRatio);
|
|
||||||
context.fillText(labelData[3], 0, 0);
|
|
||||||
context.restore();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
context.restore();
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -80,6 +80,25 @@ tags: "geojson, vector, openstreetmap, label"
|
|||||||
<option value="normal" selected="selected">Normal</option>
|
<option value="normal" selected="selected">Normal</option>
|
||||||
</select>
|
</select>
|
||||||
<br />
|
<br />
|
||||||
|
<label>Placement: </label>
|
||||||
|
<select disabled id="points-placement">
|
||||||
|
<option value="line">Line</option>
|
||||||
|
<option value="point" selected="selected">Point</option>
|
||||||
|
</select>
|
||||||
|
<br />
|
||||||
|
<label>Max Angle: </label>
|
||||||
|
<select disabled id="points-maxangle">
|
||||||
|
<option value="0.7853981633974483" selected="selected">45°</option>
|
||||||
|
<option value="2.0943951023931953">120°</option>
|
||||||
|
<option value="6.283185307179586">360°</option>
|
||||||
|
</select>
|
||||||
|
<br />
|
||||||
|
<label>Exceed Len: </label>
|
||||||
|
<select disabled id="points-exceedlength">
|
||||||
|
<option value="true">True</option>
|
||||||
|
<option value="false" selected="selected">False</option>
|
||||||
|
</select>
|
||||||
|
<br />
|
||||||
<label>Size: </label>
|
<label>Size: </label>
|
||||||
<input type="text" value="12px" id="points-size" />
|
<input type="text" value="12px" id="points-size" />
|
||||||
<br />
|
<br />
|
||||||
@@ -131,7 +150,8 @@ tags: "geojson, vector, openstreetmap, label"
|
|||||||
<br />
|
<br />
|
||||||
<label>Align: </label>
|
<label>Align: </label>
|
||||||
<select id="lines-align">
|
<select id="lines-align">
|
||||||
<option value="center" selected="selected">Center</option>
|
<option value="" selected="selected"></option>
|
||||||
|
<option value="center">Center</option>
|
||||||
<option value="end">End</option>
|
<option value="end">End</option>
|
||||||
<option value="left">Left</option>
|
<option value="left">Left</option>
|
||||||
<option value="right">Right</option>
|
<option value="right">Right</option>
|
||||||
@@ -169,6 +189,25 @@ tags: "geojson, vector, openstreetmap, label"
|
|||||||
<option value="normal">Normal</option>
|
<option value="normal">Normal</option>
|
||||||
</select>
|
</select>
|
||||||
<br />
|
<br />
|
||||||
|
<label>Placement: </label>
|
||||||
|
<select id="lines-placement">
|
||||||
|
<option value="line">Line</option>
|
||||||
|
<option value="point" selected="selected">Point</option>
|
||||||
|
</select>
|
||||||
|
<br />
|
||||||
|
<label>Max Angle: </label>
|
||||||
|
<select id="lines-maxangle">
|
||||||
|
<option value="0.7853981633974483" selected="selected">45°</option>
|
||||||
|
<option value="2.0943951023931953">120°</option>
|
||||||
|
<option value="6.283185307179586">360°</option>
|
||||||
|
</select>
|
||||||
|
<br />
|
||||||
|
<label>Exceed Len: </label>
|
||||||
|
<select id="lines-exceedlength">
|
||||||
|
<option value="true">True</option>
|
||||||
|
<option value="false" selected="selected">False</option>
|
||||||
|
</select>
|
||||||
|
<br />
|
||||||
<label>Size: </label>
|
<label>Size: </label>
|
||||||
<input type="text" value="12px" id="lines-size" />
|
<input type="text" value="12px" id="lines-size" />
|
||||||
<br />
|
<br />
|
||||||
@@ -220,7 +259,8 @@ tags: "geojson, vector, openstreetmap, label"
|
|||||||
<br />
|
<br />
|
||||||
<label>Align: </label>
|
<label>Align: </label>
|
||||||
<select id="polygons-align">
|
<select id="polygons-align">
|
||||||
<option value="center" selected="selected">Center</option>
|
<option value="" selected="selected"></option>
|
||||||
|
<option value="center">Center</option>
|
||||||
<option value="end">End</option>
|
<option value="end">End</option>
|
||||||
<option value="left">Left</option>
|
<option value="left">Left</option>
|
||||||
<option value="right">Right</option>
|
<option value="right">Right</option>
|
||||||
@@ -258,6 +298,25 @@ tags: "geojson, vector, openstreetmap, label"
|
|||||||
<option value="normal">Normal</option>
|
<option value="normal">Normal</option>
|
||||||
</select>
|
</select>
|
||||||
<br />
|
<br />
|
||||||
|
<label>Placement: </label>
|
||||||
|
<select id="polygons-placement">
|
||||||
|
<option value="line">Line</option>
|
||||||
|
<option value="point" selected="selected">Point</option>
|
||||||
|
</select>
|
||||||
|
<br />
|
||||||
|
<label>Max Angle: </label>
|
||||||
|
<select id="polygons-maxangle">
|
||||||
|
<option value="0.7853981633974483" selected="selected">45°</option>
|
||||||
|
<option value="2.0943951023931953">120°</option>
|
||||||
|
<option value="6.283185307179586">360°</option>
|
||||||
|
</select>
|
||||||
|
<br />
|
||||||
|
<label>Exceed Len: </label>
|
||||||
|
<select id="polygons-exceedlength">
|
||||||
|
<option value="true">True</option>
|
||||||
|
<option value="false" selected="selected">False</option>
|
||||||
|
</select>
|
||||||
|
<br />
|
||||||
<label>Size: </label>
|
<label>Size: </label>
|
||||||
<input type="text" value="10px" id="polygons-size" />
|
<input type="text" value="10px" id="polygons-size" />
|
||||||
<br />
|
<br />
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ var myDom = {
|
|||||||
rotation: document.getElementById('lines-rotation'),
|
rotation: document.getElementById('lines-rotation'),
|
||||||
font: document.getElementById('lines-font'),
|
font: document.getElementById('lines-font'),
|
||||||
weight: document.getElementById('lines-weight'),
|
weight: document.getElementById('lines-weight'),
|
||||||
|
placement: document.getElementById('lines-placement'),
|
||||||
|
maxangle: document.getElementById('lines-maxangle'),
|
||||||
|
exceedlength: document.getElementById('lines-exceedlength'),
|
||||||
size: document.getElementById('lines-size'),
|
size: document.getElementById('lines-size'),
|
||||||
offsetX: document.getElementById('lines-offset-x'),
|
offsetX: document.getElementById('lines-offset-x'),
|
||||||
offsetY: document.getElementById('lines-offset-y'),
|
offsetY: document.getElementById('lines-offset-y'),
|
||||||
@@ -50,6 +53,9 @@ var myDom = {
|
|||||||
rotation: document.getElementById('polygons-rotation'),
|
rotation: document.getElementById('polygons-rotation'),
|
||||||
font: document.getElementById('polygons-font'),
|
font: document.getElementById('polygons-font'),
|
||||||
weight: document.getElementById('polygons-weight'),
|
weight: document.getElementById('polygons-weight'),
|
||||||
|
placement: document.getElementById('polygons-placement'),
|
||||||
|
maxangle: document.getElementById('polygons-maxangle'),
|
||||||
|
exceedlength: document.getElementById('polygons-exceedlength'),
|
||||||
size: document.getElementById('polygons-size'),
|
size: document.getElementById('polygons-size'),
|
||||||
offsetX: document.getElementById('polygons-offset-x'),
|
offsetX: document.getElementById('polygons-offset-x'),
|
||||||
offsetY: document.getElementById('polygons-offset-y'),
|
offsetY: document.getElementById('polygons-offset-y'),
|
||||||
@@ -86,6 +92,9 @@ var createTextStyle = function(feature, resolution, dom) {
|
|||||||
var offsetX = parseInt(dom.offsetX.value, 10);
|
var offsetX = parseInt(dom.offsetX.value, 10);
|
||||||
var offsetY = parseInt(dom.offsetY.value, 10);
|
var offsetY = parseInt(dom.offsetY.value, 10);
|
||||||
var weight = dom.weight.value;
|
var weight = dom.weight.value;
|
||||||
|
var placement = dom.placement ? dom.placement.value : undefined;
|
||||||
|
var maxAngle = dom.maxangle ? parseFloat(dom.maxangle.value) : undefined;
|
||||||
|
var exceedLength = dom.exceedlength ? (dom.exceedlength.value == 'true') : undefined;
|
||||||
var rotation = parseFloat(dom.rotation.value);
|
var rotation = parseFloat(dom.rotation.value);
|
||||||
var font = weight + ' ' + size + ' ' + dom.font.value;
|
var font = weight + ' ' + size + ' ' + dom.font.value;
|
||||||
var fillColor = dom.color.value;
|
var fillColor = dom.color.value;
|
||||||
@@ -93,7 +102,7 @@ var createTextStyle = function(feature, resolution, dom) {
|
|||||||
var outlineWidth = parseInt(dom.outlineWidth.value, 10);
|
var outlineWidth = parseInt(dom.outlineWidth.value, 10);
|
||||||
|
|
||||||
return new ol.style.Text({
|
return new ol.style.Text({
|
||||||
textAlign: align,
|
textAlign: align == '' ? undefined : align,
|
||||||
textBaseline: baseline,
|
textBaseline: baseline,
|
||||||
font: font,
|
font: font,
|
||||||
text: getText(feature, resolution, dom),
|
text: getText(feature, resolution, dom),
|
||||||
@@ -101,6 +110,9 @@ var createTextStyle = function(feature, resolution, dom) {
|
|||||||
stroke: new ol.style.Stroke({color: outlineColor, width: outlineWidth}),
|
stroke: new ol.style.Stroke({color: outlineColor, width: outlineWidth}),
|
||||||
offsetX: offsetX,
|
offsetX: offsetX,
|
||||||
offsetY: offsetY,
|
offsetY: offsetY,
|
||||||
|
placement: placement,
|
||||||
|
maxAngle: maxAngle,
|
||||||
|
exceedLength: exceedLength,
|
||||||
rotation: rotation
|
rotation: rotation
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7658,8 +7658,11 @@ olx.style.StrokeOptions.prototype.width;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{font: (string|undefined),
|
* @typedef {{font: (string|undefined),
|
||||||
|
* exceedLength: (boolean|undefined),
|
||||||
|
* maxAngle: (number|undefined),
|
||||||
* offsetX: (number|undefined),
|
* offsetX: (number|undefined),
|
||||||
* offsetY: (number|undefined),
|
* offsetY: (number|undefined),
|
||||||
|
* placement: (ol.style.TextPlacement|string|undefined),
|
||||||
* scale: (number|undefined),
|
* scale: (number|undefined),
|
||||||
* rotateWithView: (boolean|undefined),
|
* rotateWithView: (boolean|undefined),
|
||||||
* rotation: (number|undefined),
|
* rotation: (number|undefined),
|
||||||
@@ -7672,6 +7675,15 @@ olx.style.StrokeOptions.prototype.width;
|
|||||||
olx.style.TextOptions;
|
olx.style.TextOptions;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When `placement` is set to `'line'`, allow text to exceed the length of the
|
||||||
|
* path that it follows. Default is `false`.
|
||||||
|
* @type {boolean|undefined}
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
olx.style.TextOptions.prototype.exceedLength;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Font style as CSS 'font' value, see:
|
* Font style as CSS 'font' value, see:
|
||||||
* {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font}.
|
* {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font}.
|
||||||
@@ -7682,6 +7694,16 @@ olx.style.TextOptions;
|
|||||||
olx.style.TextOptions.prototype.font;
|
olx.style.TextOptions.prototype.font;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When `placement` is set to `'line'`, allow a maximum angle between adjacent
|
||||||
|
* characters. The expected value is in radians, and the default is 45°
|
||||||
|
* (`Math.PI / 4`).
|
||||||
|
* @type {number|undefined}
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
olx.style.TextOptions.prototype.maxAngle;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Horizontal text offset in pixels. A positive will shift the text right.
|
* Horizontal text offset in pixels. A positive will shift the text right.
|
||||||
* Default is `0`.
|
* Default is `0`.
|
||||||
@@ -7700,6 +7722,14 @@ olx.style.TextOptions.prototype.offsetX;
|
|||||||
olx.style.TextOptions.prototype.offsetY;
|
olx.style.TextOptions.prototype.offsetY;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text placement.
|
||||||
|
* @type {ol.style.TextPlacement|undefined}
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
olx.style.TextOptions.prototype.placement;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scale.
|
* Scale.
|
||||||
* @type {number|undefined}
|
* @type {number|undefined}
|
||||||
@@ -7734,7 +7764,9 @@ olx.style.TextOptions.prototype.text;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Text alignment. Possible values: 'left', 'right', 'center', 'end' or 'start'.
|
* Text alignment. Possible values: 'left', 'right', 'center', 'end' or 'start'.
|
||||||
* Default is 'start'.
|
* Default is 'center' for `placement: 'point'`. For `placement: 'line'`, the
|
||||||
|
* default is to let the renderer choose a placement where `maxAngle` is not
|
||||||
|
* exceeded.
|
||||||
* @type {string|undefined}
|
* @type {string|undefined}
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
@@ -7743,7 +7775,7 @@ olx.style.TextOptions.prototype.textAlign;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Text base line. Possible values: 'bottom', 'top', 'middle', 'alphabetic',
|
* Text base line. Possible values: 'bottom', 'top', 'middle', 'alphabetic',
|
||||||
* 'hanging', 'ideographic'. Default is 'alphabetic'.
|
* 'hanging', 'ideographic'. Default is 'middle'.
|
||||||
* @type {string|undefined}
|
* @type {string|undefined}
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -8,8 +8,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pbf": "3.0.5",
|
"pbf": "3.0.5",
|
||||||
"pixelworks": "1.1.0",
|
"pixelworks": "1.1.0",
|
||||||
"rbush": "2.0.1",
|
"rbush": "2.0.1"
|
||||||
"@mapbox/vector-tile": "1.3.0"
|
|
||||||
},
|
},
|
||||||
"browserify": {
|
"browserify": {
|
||||||
"transform": [
|
"transform": [
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
goog.provide('ol.geom.flat.straightchunk');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} maxAngle Maximum acceptable angle delta between segments.
|
||||||
|
* @param {Array.<number>} flatCoordinates Flat coordinates.
|
||||||
|
* @param {number} offset Offset.
|
||||||
|
* @param {number} end End.
|
||||||
|
* @param {number} stride Stride.
|
||||||
|
* @return {Array.<number>} Start and end of the first suitable chunk of the
|
||||||
|
* given `flatCoordinates`.
|
||||||
|
*/
|
||||||
|
ol.geom.flat.straightchunk.lineString = function(maxAngle, flatCoordinates, offset, end, stride) {
|
||||||
|
var chunkStart = offset;
|
||||||
|
var chunkEnd = offset;
|
||||||
|
var chunkM = 0;
|
||||||
|
var m = 0;
|
||||||
|
var start = offset;
|
||||||
|
var acos, i, m12, m23, x1, y1, x12, y12, x23, y23;
|
||||||
|
for (i = offset; i < end; i += stride) {
|
||||||
|
var x2 = flatCoordinates[i];
|
||||||
|
var y2 = flatCoordinates[i + 1];
|
||||||
|
if (x1 !== undefined) {
|
||||||
|
x23 = x2 - x1;
|
||||||
|
y23 = y2 - y1;
|
||||||
|
m23 = Math.sqrt(x23 * x23 + y23 * y23);
|
||||||
|
if (x12 !== undefined) {
|
||||||
|
m += m12;
|
||||||
|
acos = Math.acos((x12 * x23 + y12 * y23) / (m12 * m23));
|
||||||
|
if (acos > maxAngle) {
|
||||||
|
if (m > chunkM) {
|
||||||
|
chunkM = m;
|
||||||
|
chunkStart = start;
|
||||||
|
chunkEnd = i;
|
||||||
|
}
|
||||||
|
m = 0;
|
||||||
|
start = i - stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m12 = m23;
|
||||||
|
x12 = x23;
|
||||||
|
y12 = y23;
|
||||||
|
}
|
||||||
|
x1 = x2;
|
||||||
|
y1 = y2;
|
||||||
|
}
|
||||||
|
m += m23;
|
||||||
|
return m > chunkM ? [start, i] : [chunkStart, chunkEnd];
|
||||||
|
};
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
goog.provide('ol.geom.flat.textpath');
|
||||||
|
|
||||||
|
goog.require('ol.math');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array.<number>} flatCoordinates Path to put text on.
|
||||||
|
* @param {number} offset Start offset of the `flatCoordinates`.
|
||||||
|
* @param {number} end End offset of the `flatCoordinates`.
|
||||||
|
* @param {number} stride Stride.
|
||||||
|
* @param {string} text Text to place on the path.
|
||||||
|
* @param {function(string):number} measure Measure function returning the
|
||||||
|
* width of the character passed as 1st argument.
|
||||||
|
* @param {number} startM m along the path where the text starts.
|
||||||
|
* @param {number} maxAngle Max angle between adjacent chars in radians.
|
||||||
|
* @param {Array.<Array.<number>>=} opt_result Array that will be populated with the
|
||||||
|
* result. Each entry consists of an array of x, y and z of the char to draw.
|
||||||
|
* If provided, this array will not be truncated to the number of characters of
|
||||||
|
* the `text`.
|
||||||
|
* @return {Array.<Array.<number>>} The result array of null if `maxAngle` was
|
||||||
|
* exceeded.
|
||||||
|
*/
|
||||||
|
ol.geom.flat.textpath.lineString = function(
|
||||||
|
flatCoordinates, offset, end, stride, text, measure, startM, maxAngle, opt_result) {
|
||||||
|
var result = opt_result ? opt_result : [];
|
||||||
|
|
||||||
|
// Keep text upright
|
||||||
|
var reverse = flatCoordinates[offset] > flatCoordinates[end - stride];
|
||||||
|
|
||||||
|
var numChars = text.length;
|
||||||
|
|
||||||
|
var x1 = flatCoordinates[offset];
|
||||||
|
var y1 = flatCoordinates[offset + 1];
|
||||||
|
offset += stride;
|
||||||
|
var x2 = flatCoordinates[offset];
|
||||||
|
var y2 = flatCoordinates[offset + 1];
|
||||||
|
var segmentM = 0;
|
||||||
|
var segmentLength = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
|
||||||
|
|
||||||
|
var index, previousAngle;
|
||||||
|
for (var i = 0; i < numChars; ++i) {
|
||||||
|
index = reverse ? numChars - i - 1 : i;
|
||||||
|
var char = text[index];
|
||||||
|
var charLength = measure(char);
|
||||||
|
var charM = startM + charLength / 2;
|
||||||
|
while (offset < end - stride && segmentM + segmentLength < charM) {
|
||||||
|
x1 = x2;
|
||||||
|
y1 = y2;
|
||||||
|
offset += stride;
|
||||||
|
x2 = flatCoordinates[offset];
|
||||||
|
y2 = flatCoordinates[offset + 1];
|
||||||
|
segmentM += segmentLength;
|
||||||
|
segmentLength = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
|
||||||
|
}
|
||||||
|
var segmentPos = charM - segmentM;
|
||||||
|
var angle = Math.atan2(y2 - y1, x2 - x1);
|
||||||
|
if (reverse) {
|
||||||
|
angle += angle > 0 ? -Math.PI : Math.PI;
|
||||||
|
}
|
||||||
|
if (previousAngle !== undefined) {
|
||||||
|
var delta = angle - previousAngle;
|
||||||
|
delta += (delta > Math.PI) ? -2 * Math.PI : (delta < -Math.PI) ? 2 * Math.PI : 0;
|
||||||
|
if (Math.abs(delta) > maxAngle) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
previousAngle = angle;
|
||||||
|
var interpolate = segmentPos / segmentLength;
|
||||||
|
var x = ol.math.lerp(x1, x2, interpolate);
|
||||||
|
var y = ol.math.lerp(y1, y2, interpolate);
|
||||||
|
result[index] = [x, y, angle];
|
||||||
|
startM += charLength;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
@@ -162,7 +162,7 @@ ol.render.canvas.ImageReplay.prototype.drawMultiPoint = function(multiPointGeome
|
|||||||
this.instructions.push([
|
this.instructions.push([
|
||||||
ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_,
|
ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_,
|
||||||
// Remaining arguments to DRAW_IMAGE are in alphabetical order
|
// Remaining arguments to DRAW_IMAGE are in alphabetical order
|
||||||
this.anchorX_, this.anchorY_, this.height_, this.opacity_,
|
this.anchorX_, this.anchorY_, this.height_, undefined, this.opacity_,
|
||||||
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
|
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
|
||||||
this.scale_, this.snapToPixel_, this.width_
|
this.scale_, this.snapToPixel_, this.width_
|
||||||
]);
|
]);
|
||||||
@@ -170,7 +170,7 @@ ol.render.canvas.ImageReplay.prototype.drawMultiPoint = function(multiPointGeome
|
|||||||
ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd,
|
ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd,
|
||||||
this.hitDetectionImage_,
|
this.hitDetectionImage_,
|
||||||
// Remaining arguments to DRAW_IMAGE are in alphabetical order
|
// Remaining arguments to DRAW_IMAGE are in alphabetical order
|
||||||
this.anchorX_, this.anchorY_, this.height_, this.opacity_,
|
this.anchorX_, this.anchorY_, this.height_, undefined, this.opacity_,
|
||||||
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
|
this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
|
||||||
this.scale_, this.snapToPixel_, this.width_
|
this.scale_, this.snapToPixel_, this.width_
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -789,21 +789,23 @@ ol.render.canvas.Immediate.prototype.setContextStrokeState_ = function(strokeSta
|
|||||||
ol.render.canvas.Immediate.prototype.setContextTextState_ = function(textState) {
|
ol.render.canvas.Immediate.prototype.setContextTextState_ = function(textState) {
|
||||||
var context = this.context_;
|
var context = this.context_;
|
||||||
var contextTextState = this.contextTextState_;
|
var contextTextState = this.contextTextState_;
|
||||||
|
var textAlign = textState.textAlign ?
|
||||||
|
textState.textAlign : ol.render.canvas.defaultTextAlign;
|
||||||
if (!contextTextState) {
|
if (!contextTextState) {
|
||||||
context.font = textState.font;
|
context.font = textState.font;
|
||||||
context.textAlign = textState.textAlign;
|
context.textAlign = textAlign;
|
||||||
context.textBaseline = textState.textBaseline;
|
context.textBaseline = textState.textBaseline;
|
||||||
this.contextTextState_ = {
|
this.contextTextState_ = {
|
||||||
font: textState.font,
|
font: textState.font,
|
||||||
textAlign: textState.textAlign,
|
textAlign: textAlign,
|
||||||
textBaseline: textState.textBaseline
|
textBaseline: textState.textBaseline
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
if (contextTextState.font != textState.font) {
|
if (contextTextState.font != textState.font) {
|
||||||
contextTextState.font = context.font = textState.font;
|
contextTextState.font = context.font = textState.font;
|
||||||
}
|
}
|
||||||
if (contextTextState.textAlign != textState.textAlign) {
|
if (contextTextState.textAlign != textAlign) {
|
||||||
contextTextState.textAlign = context.textAlign = textState.textAlign;
|
contextTextState.textAlign = textAlign;
|
||||||
}
|
}
|
||||||
if (contextTextState.textBaseline != textState.textBaseline) {
|
if (contextTextState.textBaseline != textState.textBaseline) {
|
||||||
contextTextState.textBaseline = context.textBaseline =
|
contextTextState.textBaseline = context.textBaseline =
|
||||||
|
|||||||
@@ -9,11 +9,12 @@ ol.render.canvas.Instruction = {
|
|||||||
CIRCLE: 2,
|
CIRCLE: 2,
|
||||||
CLOSE_PATH: 3,
|
CLOSE_PATH: 3,
|
||||||
CUSTOM: 4,
|
CUSTOM: 4,
|
||||||
DRAW_IMAGE: 5,
|
DRAW_CHARS: 5,
|
||||||
END_GEOMETRY: 6,
|
DRAW_IMAGE: 6,
|
||||||
FILL: 7,
|
END_GEOMETRY: 7,
|
||||||
MOVE_TO_LINE_TO: 8,
|
FILL: 8,
|
||||||
SET_FILL_STYLE: 9,
|
MOVE_TO_LINE_TO: 9,
|
||||||
SET_STROKE_STYLE: 10,
|
SET_FILL_STYLE: 10,
|
||||||
STROKE: 11
|
SET_STROKE_STYLE: 11,
|
||||||
|
STROKE: 12
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ goog.require('ol.extent');
|
|||||||
goog.require('ol.extent.Relationship');
|
goog.require('ol.extent.Relationship');
|
||||||
goog.require('ol.geom.GeometryType');
|
goog.require('ol.geom.GeometryType');
|
||||||
goog.require('ol.geom.flat.inflate');
|
goog.require('ol.geom.flat.inflate');
|
||||||
|
goog.require('ol.geom.flat.length');
|
||||||
|
goog.require('ol.geom.flat.textpath');
|
||||||
goog.require('ol.geom.flat.transform');
|
goog.require('ol.geom.flat.transform');
|
||||||
goog.require('ol.has');
|
goog.require('ol.has');
|
||||||
goog.require('ol.obj');
|
goog.require('ol.obj');
|
||||||
@@ -130,10 +132,69 @@ ol.render.canvas.Replay = function(tolerance, maxExtent, resolution, pixelRatio,
|
|||||||
* @type {!ol.Transform}
|
* @type {!ol.Transform}
|
||||||
*/
|
*/
|
||||||
this.resetTransform_ = ol.transform.create();
|
this.resetTransform_ = ol.transform.create();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {Array.<Array.<number>>}
|
||||||
|
*/
|
||||||
|
this.chars_ = [];
|
||||||
};
|
};
|
||||||
ol.inherits(ol.render.canvas.Replay, ol.render.VectorContext);
|
ol.inherits(ol.render.canvas.Replay, ol.render.VectorContext);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {CanvasRenderingContext2D} context Context.
|
||||||
|
* @param {number} x X.
|
||||||
|
* @param {number} y Y.
|
||||||
|
* @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image Image.
|
||||||
|
* @param {number} anchorX Anchor X.
|
||||||
|
* @param {number} anchorY Anchor Y.
|
||||||
|
* @param {number} height Height.
|
||||||
|
* @param {number} opacity Opacity.
|
||||||
|
* @param {number} originX Origin X.
|
||||||
|
* @param {number} originY Origin Y.
|
||||||
|
* @param {number} rotation Rotation.
|
||||||
|
* @param {number} scale Scale.
|
||||||
|
* @param {boolean} snapToPixel Snap to pixel.
|
||||||
|
* @param {number} width Width.
|
||||||
|
*/
|
||||||
|
ol.render.canvas.Replay.prototype.replayImage_ = function(context, x, y, image, anchorX, anchorY,
|
||||||
|
height, opacity, originX, originY, rotation, scale, snapToPixel, width) {
|
||||||
|
var localTransform = this.tmpLocalTransform_;
|
||||||
|
anchorX *= scale;
|
||||||
|
anchorY *= scale;
|
||||||
|
x -= anchorX;
|
||||||
|
y -= anchorY;
|
||||||
|
if (snapToPixel) {
|
||||||
|
x = Math.round(x);
|
||||||
|
y = Math.round(y);
|
||||||
|
}
|
||||||
|
if (rotation !== 0) {
|
||||||
|
var centerX = x + anchorX;
|
||||||
|
var centerY = y + anchorY;
|
||||||
|
ol.transform.compose(localTransform,
|
||||||
|
centerX, centerY, 1, 1, rotation, -centerX, -centerY);
|
||||||
|
context.setTransform.apply(context, localTransform);
|
||||||
|
}
|
||||||
|
var alpha = context.globalAlpha;
|
||||||
|
if (opacity != 1) {
|
||||||
|
context.globalAlpha = alpha * opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
var w = (width + originX > image.width) ? image.width - originX : width;
|
||||||
|
var h = (height + originY > image.height) ? image.height - originY : height;
|
||||||
|
|
||||||
|
context.drawImage(image, originX, originY, w, h, x, y, w * scale, h * scale);
|
||||||
|
|
||||||
|
if (opacity != 1) {
|
||||||
|
context.globalAlpha = alpha;
|
||||||
|
}
|
||||||
|
if (rotation !== 0) {
|
||||||
|
context.setTransform.apply(context, this.resetTransform_);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @protected
|
* @protected
|
||||||
* @param {Array.<number>} dashArray Dash array.
|
* @param {Array.<number>} dashArray Dash array.
|
||||||
@@ -340,9 +401,7 @@ ol.render.canvas.Replay.prototype.replay_ = function(
|
|||||||
var ii = instructions.length; // end of instructions
|
var ii = instructions.length; // end of instructions
|
||||||
var d = 0; // data index
|
var d = 0; // data index
|
||||||
var dd; // end of per-instruction data
|
var dd; // end of per-instruction data
|
||||||
var localTransform = this.tmpLocalTransform_;
|
var anchorX, anchorY, prevX, prevY, roundX, roundY;
|
||||||
var resetTransform = this.resetTransform_;
|
|
||||||
var prevX, prevY, roundX, roundY;
|
|
||||||
var pendingFill = 0;
|
var pendingFill = 0;
|
||||||
var pendingStroke = 0;
|
var pendingStroke = 0;
|
||||||
var coordinateCache = this.coordinateCache_;
|
var coordinateCache = this.coordinateCache_;
|
||||||
@@ -435,53 +494,63 @@ ol.render.canvas.Replay.prototype.replay_ = function(
|
|||||||
dd = /** @type {number} */ (instruction[2]);
|
dd = /** @type {number} */ (instruction[2]);
|
||||||
var image = /** @type {HTMLCanvasElement|HTMLVideoElement|Image} */
|
var image = /** @type {HTMLCanvasElement|HTMLVideoElement|Image} */
|
||||||
(instruction[3]);
|
(instruction[3]);
|
||||||
var scale = /** @type {number} */ (instruction[12]);
|
|
||||||
// Remaining arguments in DRAW_IMAGE are in alphabetical order
|
// Remaining arguments in DRAW_IMAGE are in alphabetical order
|
||||||
var anchorX = /** @type {number} */ (instruction[4]) * scale;
|
anchorX = /** @type {number} */ (instruction[4]);
|
||||||
var anchorY = /** @type {number} */ (instruction[5]) * scale;
|
anchorY = /** @type {number} */ (instruction[5]);
|
||||||
var height = /** @type {number} */ (instruction[6]);
|
var height = /** @type {number} */ (instruction[6]);
|
||||||
var opacity = /** @type {number} */ (instruction[7]);
|
var opacity = /** @type {number} */ (instruction[7]);
|
||||||
var originX = /** @type {number} */ (instruction[8]);
|
var originX = /** @type {number} */ (instruction[8]);
|
||||||
var originY = /** @type {number} */ (instruction[9]);
|
var originY = /** @type {number} */ (instruction[9]);
|
||||||
var rotateWithView = /** @type {boolean} */ (instruction[10]);
|
var rotateWithView = /** @type {boolean} */ (instruction[10]);
|
||||||
var rotation = /** @type {number} */ (instruction[11]);
|
var rotation = /** @type {number} */ (instruction[11]);
|
||||||
|
var scale = /** @type {number} */ (instruction[12]);
|
||||||
var snapToPixel = /** @type {boolean} */ (instruction[13]);
|
var snapToPixel = /** @type {boolean} */ (instruction[13]);
|
||||||
var width = /** @type {number} */ (instruction[14]);
|
var width = /** @type {number} */ (instruction[14]);
|
||||||
|
|
||||||
if (rotateWithView) {
|
if (rotateWithView) {
|
||||||
rotation += viewRotation;
|
rotation += viewRotation;
|
||||||
}
|
}
|
||||||
for (; d < dd; d += 2) {
|
for (; d < dd; d += 2) {
|
||||||
x = pixelCoordinates[d] - anchorX;
|
this.replayImage_(context, pixelCoordinates[d], pixelCoordinates[d + 1],
|
||||||
y = pixelCoordinates[d + 1] - anchorY;
|
image, anchorX, anchorY, height, opacity, originX, originY,
|
||||||
if (snapToPixel) {
|
rotation, scale, snapToPixel, width);
|
||||||
x = Math.round(x);
|
}
|
||||||
y = Math.round(y);
|
++i;
|
||||||
}
|
break;
|
||||||
if (rotation !== 0) {
|
case ol.render.canvas.Instruction.DRAW_CHARS:
|
||||||
var centerX = x + anchorX;
|
var begin = /** @type {number} */ (instruction[1]);
|
||||||
var centerY = y + anchorY;
|
var end = /** @type {number} */ (instruction[2]);
|
||||||
ol.transform.compose(localTransform,
|
var images = /** @type {Array.<HTMLCanvasElement>} */ (instruction[3]);
|
||||||
centerX, centerY, 1, 1, rotation, -centerX, -centerY);
|
// Remaining arguments in DRAW_CHARS are in alphabetical order
|
||||||
context.setTransform.apply(context, localTransform);
|
var baseline = /** @type {number} */ (instruction[4]);
|
||||||
}
|
var exceedLength = /** @type {number} */ (instruction[5]);
|
||||||
var alpha = context.globalAlpha;
|
var maxAngle = /** @type {number} */ (instruction[6]);
|
||||||
if (opacity != 1) {
|
var measure = /** @type {function(string):number} */ (instruction[7]);
|
||||||
context.globalAlpha = alpha * opacity;
|
var offsetY = /** @type {number} */ (instruction[8]);
|
||||||
}
|
var strokeWidth = /** @type {number} */ (instruction[9]);
|
||||||
|
var text = /** @type {string} */ (instruction[10]);
|
||||||
|
var align = /** @type {number} */ (instruction[11]);
|
||||||
|
var textScale = /** @type {number} */ (instruction[12]);
|
||||||
|
|
||||||
var w = (width + originX > image.width) ? image.width - originX : width;
|
var pathLength = ol.geom.flat.length.lineString(pixelCoordinates, begin, end, 2);
|
||||||
var h = (height + originY > image.height) ? image.height - originY : height;
|
var textLength = measure(text);
|
||||||
|
if (exceedLength || textLength <= pathLength) {
|
||||||
context.drawImage(image, originX, originY, w, h,
|
var startM = (pathLength - textLength) * align;
|
||||||
x, y, w * scale, h * scale);
|
var chars = ol.geom.flat.textpath.lineString(
|
||||||
|
pixelCoordinates, begin, end, 2, text, measure, startM, maxAngle, this.chars_);
|
||||||
if (opacity != 1) {
|
var numChars = text.length;
|
||||||
context.globalAlpha = alpha;
|
if (chars) {
|
||||||
}
|
for (var c = 0, cc = images.length; c < cc; ++c) {
|
||||||
if (rotation !== 0) {
|
var char = chars[c % numChars]; // x, y, rotation
|
||||||
context.setTransform.apply(context, resetTransform);
|
var label = images[c];
|
||||||
|
anchorX = label.width / 2;
|
||||||
|
anchorY = baseline * label.height + 2 * (0.5 - baseline) * strokeWidth - offsetY;
|
||||||
|
this.replayImage_(context, char[0], char[1], label, anchorX, anchorY,
|
||||||
|
label.height, 1, 0, 0, char[2], textScale, false, label.width);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
++i;
|
++i;
|
||||||
break;
|
break;
|
||||||
case ol.render.canvas.Instruction.END_GEOMETRY:
|
case ol.render.canvas.Instruction.END_GEOMETRY:
|
||||||
|
|||||||
@@ -2,12 +2,16 @@ goog.provide('ol.render.canvas.TextReplay');
|
|||||||
|
|
||||||
goog.require('ol');
|
goog.require('ol');
|
||||||
goog.require('ol.colorlike');
|
goog.require('ol.colorlike');
|
||||||
|
goog.require('ol.dom');
|
||||||
|
goog.require('ol.geom.flat.straightchunk');
|
||||||
|
goog.require('ol.geom.GeometryType');
|
||||||
goog.require('ol.has');
|
goog.require('ol.has');
|
||||||
goog.require('ol.render.canvas');
|
goog.require('ol.render.canvas');
|
||||||
goog.require('ol.render.canvas.Instruction');
|
goog.require('ol.render.canvas.Instruction');
|
||||||
goog.require('ol.render.canvas.Replay');
|
goog.require('ol.render.canvas.Replay');
|
||||||
goog.require('ol.render.replay');
|
goog.require('ol.render.replay');
|
||||||
goog.require('ol.structs.LRUCache');
|
goog.require('ol.structs.LRUCache');
|
||||||
|
goog.require('ol.style.TextPlacement');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,6 +28,12 @@ ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution, pixelRa
|
|||||||
|
|
||||||
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, pixelRatio, overlaps);
|
ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, pixelRatio, overlaps);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {Array.<HTMLCanvasElement>}
|
||||||
|
*/
|
||||||
|
this.labels_ = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -78,6 +88,24 @@ ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution, pixelRa
|
|||||||
*/
|
*/
|
||||||
this.textState_ = null;
|
this.textState_ = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.textKey_ = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.fillKey_ = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.strokeKey_ = '';
|
||||||
|
|
||||||
while (ol.render.canvas.TextReplay.labelCache_.canExpireCache()) {
|
while (ol.render.canvas.TextReplay.labelCache_.canExpireCache()) {
|
||||||
ol.render.canvas.TextReplay.labelCache_.pop();
|
ol.render.canvas.TextReplay.labelCache_.pop();
|
||||||
}
|
}
|
||||||
@@ -95,33 +123,65 @@ ol.render.canvas.TextReplay.labelCache_ = new ol.structs.LRUCache();
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} font Font to use for measuring.
|
* @param {string} font Font to use for measuring.
|
||||||
* @param {Array.<string>} lines Lines to measure.
|
* @return {ol.Size} Measurement.
|
||||||
* @param {Array.<number>} widths Array will be populated with the widths of
|
|
||||||
* each line.
|
|
||||||
* @return {ol.Size} Measuremnt.
|
|
||||||
*/
|
*/
|
||||||
ol.render.canvas.TextReplay.measureText = (function() {
|
ol.render.canvas.TextReplay.measureTextHeight = (function() {
|
||||||
var textContainer;
|
var textContainer;
|
||||||
return function(font, lines, widths) {
|
return function(font, lines, widths) {
|
||||||
if (!textContainer) {
|
if (!textContainer) {
|
||||||
textContainer = document.createElement('span');
|
textContainer = document.createElement('span');
|
||||||
|
textContainer.textContent = 'M';
|
||||||
textContainer.style.visibility = 'hidden';
|
textContainer.style.visibility = 'hidden';
|
||||||
textContainer.style.whiteSpace = 'nowrap';
|
textContainer.style.whiteSpace = 'nowrap';
|
||||||
}
|
}
|
||||||
textContainer.style.font = font;
|
textContainer.style.font = font;
|
||||||
document.body.appendChild(textContainer);
|
document.body.appendChild(textContainer);
|
||||||
|
var height = textContainer.offsetHeight;
|
||||||
|
document.body.removeChild(textContainer);
|
||||||
|
return height;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @this {Object}
|
||||||
|
* @param {CanvasRenderingContext2D} context Context.
|
||||||
|
* @param {number} pixelRatio Pixel ratio.
|
||||||
|
* @param {string} text Text.
|
||||||
|
* @return {number} Width.
|
||||||
|
*/
|
||||||
|
ol.render.canvas.TextReplay.getTextWidth = function(context, pixelRatio, text) {
|
||||||
|
var width = this[text];
|
||||||
|
if (!width) {
|
||||||
|
this[text] = width = context.measureText(text).width;
|
||||||
|
}
|
||||||
|
return width * pixelRatio;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} font Font to use for measuring.
|
||||||
|
* @param {Array.<string>} lines Lines to measure.
|
||||||
|
* @param {Array.<number>} widths Array will be populated with the widths of
|
||||||
|
* each line.
|
||||||
|
* @return {number} Width of the whole text.
|
||||||
|
*/
|
||||||
|
ol.render.canvas.TextReplay.measureTextWidths = (function() {
|
||||||
|
var context;
|
||||||
|
return function(font, lines, widths) {
|
||||||
|
if (!context) {
|
||||||
|
context = ol.dom.createCanvasContext2D(1, 1);
|
||||||
|
}
|
||||||
|
context.font = font;
|
||||||
var numLines = lines.length;
|
var numLines = lines.length;
|
||||||
var width = 0;
|
var width = 0;
|
||||||
var currentWidth, i;
|
var currentWidth, i;
|
||||||
for (i = 0; i < numLines; ++i) {
|
for (i = 0; i < numLines; ++i) {
|
||||||
textContainer.textContent = lines[i];
|
currentWidth = context.measureText(lines[i]).width;
|
||||||
currentWidth = textContainer.offsetWidth;
|
|
||||||
width = Math.max(width, currentWidth);
|
width = Math.max(width, currentWidth);
|
||||||
widths.push(currentWidth);
|
widths.push(currentWidth);
|
||||||
}
|
}
|
||||||
var measurement = [width, textContainer.offsetHeight * numLines];
|
return width;
|
||||||
document.body.removeChild(textContainer);
|
|
||||||
return measurement;
|
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@@ -129,51 +189,122 @@ ol.render.canvas.TextReplay.measureText = (function() {
|
|||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
ol.render.canvas.TextReplay.prototype.drawText = function(flatCoordinates, offset, end, stride, geometry, feature) {
|
ol.render.canvas.TextReplay.prototype.drawText = function(geometry, feature) {
|
||||||
var fillState = this.textFillState_;
|
var fillState = this.textFillState_;
|
||||||
var strokeState = this.textStrokeState_;
|
var strokeState = this.textStrokeState_;
|
||||||
var textState = this.textState_;
|
var textState = this.textState_;
|
||||||
if (this.text_ === '' || !textState || (!fillState && !strokeState)) {
|
if (this.text_ === '' || !textState || (!fillState && !strokeState)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.beginGeometry(geometry, feature);
|
this.beginGeometry(geometry, feature);
|
||||||
|
var begin = this.coordinates.length;
|
||||||
|
|
||||||
var myBegin = this.coordinates.length;
|
var geometryType = geometry.getType();
|
||||||
var myEnd =
|
var flatCoordinates = null;
|
||||||
this.appendFlatCoordinates(flatCoordinates, offset, end, stride, false, false);
|
var end = 2;
|
||||||
var fill = !!fillState;
|
var stride = 2;
|
||||||
var stroke = !!strokeState;
|
|
||||||
var pixelRatio = this.pixelRatio;
|
|
||||||
var textAlign = textState.textAlign;
|
|
||||||
var align = ol.render.replay.TEXT_ALIGN[textAlign];
|
|
||||||
var textBaseline = textState.textBaseline;
|
|
||||||
var baseline = ol.render.replay.TEXT_ALIGN[textBaseline];
|
|
||||||
var strokeWidth = stroke && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
|
||||||
|
|
||||||
|
if (this.textState_.placement === ol.style.TextPlacement.LINE) {
|
||||||
|
var ends;
|
||||||
|
flatCoordinates = geometry.getFlatCoordinates();
|
||||||
|
stride = geometry.getStride();
|
||||||
|
if (geometryType == ol.geom.GeometryType.LINE_STRING) {
|
||||||
|
ends = [flatCoordinates.length];
|
||||||
|
} else if (geometryType == ol.geom.GeometryType.MULTI_LINE_STRING) {
|
||||||
|
ends = geometry.getEnds();
|
||||||
|
} else if (geometryType == ol.geom.GeometryType.POLYGON) {
|
||||||
|
ends = geometry.getEnds().slice(0, 1);
|
||||||
|
} else if (geometryType == ol.geom.GeometryType.MULTI_POLYGON) {
|
||||||
|
var endss = geometry.getEndss();
|
||||||
|
ends = [];
|
||||||
|
for (var i = 0, ii = endss.length; i < ii; ++i) {
|
||||||
|
ends.push(endss[i][0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var textAlign = textState.textAlign;
|
||||||
|
var flatOffset = 0;
|
||||||
|
var flatEnd;
|
||||||
|
for (var o = 0, oo = ends.length; o < oo; ++o) {
|
||||||
|
if (textAlign == undefined) {
|
||||||
|
var range = ol.geom.flat.straightchunk.lineString(
|
||||||
|
textState.maxAngle, flatCoordinates, flatOffset, ends[o], stride);
|
||||||
|
flatOffset = range[0];
|
||||||
|
flatEnd = range[1];
|
||||||
|
} else {
|
||||||
|
flatEnd = ends[o];
|
||||||
|
}
|
||||||
|
end = this.appendFlatCoordinates(flatCoordinates, flatOffset, flatEnd, stride, false, false);
|
||||||
|
flatOffset = ends[o];
|
||||||
|
this.drawChars_(begin, end);
|
||||||
|
begin = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
switch (geometryType) {
|
||||||
|
case ol.geom.GeometryType.POINT:
|
||||||
|
case ol.geom.GeometryType.MULTI_POINT:
|
||||||
|
flatCoordinates = geometry.getFlatCoordinates();
|
||||||
|
end = flatCoordinates.length;
|
||||||
|
break;
|
||||||
|
case ol.geom.GeometryType.LINE_STRING:
|
||||||
|
flatCoordinates = /** @type {ol.geom.LineString} */ (geometry).getFlatMidpoint();
|
||||||
|
break;
|
||||||
|
case ol.geom.GeometryType.CIRCLE:
|
||||||
|
flatCoordinates = /** @type {ol.geom.Circle} */ (geometry).getCenter();
|
||||||
|
break;
|
||||||
|
case ol.geom.GeometryType.MULTI_LINE_STRING:
|
||||||
|
flatCoordinates = /** @type {ol.geom.MultiLineString} */ (geometry).getFlatMidpoints();
|
||||||
|
end = flatCoordinates.length;
|
||||||
|
break;
|
||||||
|
case ol.geom.GeometryType.POLYGON:
|
||||||
|
flatCoordinates = /** @type {ol.geom.Polygon} */ (geometry).getFlatInteriorPoint();
|
||||||
|
break;
|
||||||
|
case ol.geom.GeometryType.MULTI_POLYGON:
|
||||||
|
flatCoordinates = /** @type {ol.geom.MultiPolygon} */ (geometry).getFlatInteriorPoints();
|
||||||
|
end = flatCoordinates.length;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
end = this.appendFlatCoordinates(flatCoordinates, 0, end, stride, false, false);
|
||||||
|
this.drawTextImage_(begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.endGeometry(geometry, feature);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {string} text Text.
|
||||||
|
* @param {boolean} fill Fill.
|
||||||
|
* @param {boolean} stroke Stroke.
|
||||||
|
* @return {HTMLCanvasElement} Image.
|
||||||
|
*/
|
||||||
|
ol.render.canvas.TextReplay.prototype.getImage_ = function(text, fill, stroke) {
|
||||||
var label;
|
var label;
|
||||||
var text = this.text_;
|
var key = (stroke ? this.strokeKey_ : '') + this.textKey_ + text + (fill ? this.fillKey_ : '');
|
||||||
var key =
|
|
||||||
(stroke ?
|
|
||||||
(typeof strokeState.strokeStyle == 'string' ? strokeState.strokeStyle : ol.getUid(strokeState.strokeStyle)) +
|
|
||||||
strokeState.lineCap + strokeState.lineDashOffset + '|' + strokeWidth +
|
|
||||||
strokeState.lineJoin + strokeState.miterLimit +
|
|
||||||
'[' + strokeState.lineDash.join() + ']' : '') +
|
|
||||||
textState.font + textAlign + text +
|
|
||||||
(fill ?
|
|
||||||
(typeof fillState.fillStyle == 'string' ? fillState.fillStyle : ('|' + ol.getUid(fillState.fillStyle))) : '');
|
|
||||||
|
|
||||||
var lines = text.split('\n');
|
var lines = text.split('\n');
|
||||||
var numLines = lines.length;
|
var numLines = lines.length;
|
||||||
|
|
||||||
if (!ol.render.canvas.TextReplay.labelCache_.containsKey(key)) {
|
if (!ol.render.canvas.TextReplay.labelCache_.containsKey(key)) {
|
||||||
label = /** @type {HTMLCanvasElement} */ (document.createElement('canvas'));
|
var strokeState = this.textStrokeState_;
|
||||||
ol.render.canvas.TextReplay.labelCache_.set(key, label);
|
var fillState = this.textFillState_;
|
||||||
var context = label.getContext('2d');
|
var textState = this.textState_;
|
||||||
|
var pixelRatio = this.pixelRatio;
|
||||||
|
var align = ol.render.replay.TEXT_ALIGN[textState.textAlign || ol.render.canvas.defaultTextAlign];
|
||||||
|
var strokeWidth = stroke && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
||||||
|
|
||||||
var widths = [];
|
var widths = [];
|
||||||
var metrics = ol.render.canvas.TextReplay.measureText(textState.font, lines, widths);
|
var width = ol.render.canvas.TextReplay.measureTextWidths(textState.font, lines, widths);
|
||||||
var lineHeight = metrics[1] / numLines;
|
var lineHeight = ol.render.canvas.TextReplay.measureTextHeight(textState.font);
|
||||||
label.width = Math.ceil(metrics[0] + 2 * strokeWidth) * pixelRatio;
|
var height = lineHeight * numLines;
|
||||||
label.height = Math.ceil(metrics[1] + 2 * strokeWidth) * pixelRatio;
|
var renderWidth = (width + 2 * strokeWidth);
|
||||||
|
var context = ol.dom.createCanvasContext2D(
|
||||||
|
Math.ceil(renderWidth * pixelRatio),
|
||||||
|
Math.ceil((height + 2 * strokeWidth) * pixelRatio));
|
||||||
|
label = context.canvas;
|
||||||
|
ol.render.canvas.TextReplay.labelCache_.set(key, label);
|
||||||
context.scale(pixelRatio, pixelRatio);
|
context.scale(pixelRatio, pixelRatio);
|
||||||
context.font = textState.font;
|
context.font = textState.font;
|
||||||
if (stroke) {
|
if (stroke) {
|
||||||
@@ -191,39 +322,101 @@ ol.render.canvas.TextReplay.prototype.drawText = function(flatCoordinates, offse
|
|||||||
context.fillStyle = fillState.fillStyle;
|
context.fillStyle = fillState.fillStyle;
|
||||||
}
|
}
|
||||||
context.textBaseline = 'top';
|
context.textBaseline = 'top';
|
||||||
context.textAlign = 'left';
|
context.textAlign = 'center';
|
||||||
var x = align * label.width / pixelRatio + 2 * (0.5 - align) * strokeWidth;
|
var leftRight = (0.5 - align);
|
||||||
|
var x = align * label.width / pixelRatio + leftRight * 2 * strokeWidth;
|
||||||
var i;
|
var i;
|
||||||
if (stroke) {
|
if (stroke) {
|
||||||
for (i = 0; i < numLines; ++i) {
|
for (i = 0; i < numLines; ++i) {
|
||||||
context.strokeText(lines[i], x - align * widths[i], strokeWidth + i * lineHeight);
|
context.strokeText(lines[i], x + leftRight * widths[i], strokeWidth + i * lineHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fill) {
|
if (fill) {
|
||||||
for (i = 0; i < numLines; ++i) {
|
for (i = 0; i < numLines; ++i) {
|
||||||
context.fillText(lines[i], x - align * widths[i], strokeWidth + i * lineHeight);
|
context.fillText(lines[i], x + leftRight * widths[i], strokeWidth + i * lineHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
label = ol.render.canvas.TextReplay.labelCache_.get(key);
|
return ol.render.canvas.TextReplay.labelCache_.get(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {number} begin Begin.
|
||||||
|
* @param {number} end End.
|
||||||
|
*/
|
||||||
|
ol.render.canvas.TextReplay.prototype.drawTextImage_ = function(begin, end) {
|
||||||
|
var textState = this.textState_;
|
||||||
|
var strokeState = this.textStrokeState_;
|
||||||
|
var pixelRatio = this.pixelRatio;
|
||||||
|
var align = ol.render.replay.TEXT_ALIGN[textState.textAlign || ol.render.canvas.defaultTextAlign];
|
||||||
|
var baseline = ol.render.replay.TEXT_ALIGN[textState.textBaseline];
|
||||||
|
var strokeWidth = strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
||||||
|
|
||||||
|
var label = this.getImage_(this.text_, !!this.textFillState_, !!this.textStrokeState_);
|
||||||
|
|
||||||
var anchorX = align * label.width / pixelRatio + 2 * (0.5 - align) * strokeWidth;
|
var anchorX = align * label.width / pixelRatio + 2 * (0.5 - align) * strokeWidth;
|
||||||
var anchorY = baseline * label.height / pixelRatio + 2 * (0.5 - baseline) * strokeWidth;
|
var anchorY = baseline * label.height / pixelRatio + 2 * (0.5 - baseline) * strokeWidth;
|
||||||
|
this.instructions.push([ol.render.canvas.Instruction.DRAW_IMAGE, begin, end,
|
||||||
this.instructions.push([
|
label, (anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio,
|
||||||
ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, label,
|
|
||||||
(anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio,
|
|
||||||
label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_,
|
label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_,
|
||||||
this.textScale_, true, label.width
|
this.textScale_, true, label.width
|
||||||
]);
|
]);
|
||||||
this.hitDetectionInstructions.push([
|
this.hitDetectionInstructions.push([ol.render.canvas.Instruction.DRAW_IMAGE, begin, end,
|
||||||
ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, label,
|
label, (anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio,
|
||||||
(anchorX - this.textOffsetX_) * pixelRatio, (anchorY - this.textOffsetY_) * pixelRatio,
|
|
||||||
label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_,
|
label.height, 1, 0, 0, this.textRotateWithView_, this.textRotation_,
|
||||||
this.textScale_ / pixelRatio, true, label.width
|
this.textScale_ / pixelRatio, true, label.width
|
||||||
]);
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
this.endGeometry(geometry, feature);
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {number} begin Begin.
|
||||||
|
* @param {number} end End.
|
||||||
|
*/
|
||||||
|
ol.render.canvas.TextReplay.prototype.drawChars_ = function(begin, end) {
|
||||||
|
var pixelRatio = this.pixelRatio;
|
||||||
|
var strokeState = this.textStrokeState_;
|
||||||
|
var fill = !!this.textFillState_;
|
||||||
|
var stroke = !!strokeState;
|
||||||
|
var textState = this.textState_;
|
||||||
|
var baseline = ol.render.replay.TEXT_ALIGN[textState.textBaseline];
|
||||||
|
var strokeWidth = stroke && strokeState.lineWidth ? strokeState.lineWidth * pixelRatio : 0;
|
||||||
|
|
||||||
|
var labels = [];
|
||||||
|
var text = this.text_;
|
||||||
|
var numChars = this.text_.length;
|
||||||
|
var i;
|
||||||
|
|
||||||
|
if (stroke) {
|
||||||
|
for (i = 0; i < numChars; ++i) {
|
||||||
|
labels.push(this.getImage_(text.charAt(i), false, stroke));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fill) {
|
||||||
|
for (i = 0; i < numChars; ++i) {
|
||||||
|
labels.push(this.getImage_(text.charAt(i), fill, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = labels[0].getContext('2d');
|
||||||
|
var offsetY = this.textOffsetY_ * pixelRatio;
|
||||||
|
var align = ol.render.replay.TEXT_ALIGN[textState.textAlign || ol.render.canvas.defaultTextAlign];
|
||||||
|
var widths = {};
|
||||||
|
this.instructions.push([ol.render.canvas.Instruction.DRAW_CHARS,
|
||||||
|
begin, end, labels, baseline,
|
||||||
|
textState.exceedLength, textState.maxAngle,
|
||||||
|
ol.render.canvas.TextReplay.getTextWidth.bind(widths, context, pixelRatio),
|
||||||
|
offsetY, strokeWidth, this.text_, align, this.textScale_
|
||||||
|
]);
|
||||||
|
this.hitDetectionInstructions.push([ol.render.canvas.Instruction.DRAW_CHARS,
|
||||||
|
begin, end, labels, baseline,
|
||||||
|
textState.exceedLength, textState.maxAngle,
|
||||||
|
ol.render.canvas.TextReplay.getTextWidth.bind(widths, context, 1),
|
||||||
|
offsetY, strokeWidth, this.text_, align, this.textScale_ / pixelRatio
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -231,28 +424,26 @@ ol.render.canvas.TextReplay.prototype.drawText = function(flatCoordinates, offse
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) {
|
ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) {
|
||||||
|
var textState, fillState, strokeState;
|
||||||
if (!textStyle) {
|
if (!textStyle) {
|
||||||
this.text_ = '';
|
this.text_ = '';
|
||||||
} else {
|
} else {
|
||||||
var textFillStyle = textStyle.getFill();
|
var textFillStyle = textStyle.getFill();
|
||||||
if (!textFillStyle) {
|
if (!textFillStyle) {
|
||||||
this.textFillState_ = null;
|
fillState = this.textFillState_ = null;
|
||||||
} else {
|
} else {
|
||||||
var textFillStyleColor = textFillStyle.getColor();
|
var textFillStyleColor = textFillStyle.getColor();
|
||||||
var fillStyle = ol.colorlike.asColorLike(textFillStyleColor ?
|
var fillStyle = ol.colorlike.asColorLike(textFillStyleColor ?
|
||||||
textFillStyleColor : ol.render.canvas.defaultFillStyle);
|
textFillStyleColor : ol.render.canvas.defaultFillStyle);
|
||||||
if (!this.textFillState_) {
|
fillState = this.textFillState_;
|
||||||
this.textFillState_ = {
|
if (!fillState) {
|
||||||
fillStyle: fillStyle
|
fillState = this.textFillState_ = /** @type {ol.CanvasFillState} */ ({});
|
||||||
};
|
|
||||||
} else {
|
|
||||||
var textFillState = this.textFillState_;
|
|
||||||
textFillState.fillStyle = fillStyle;
|
|
||||||
}
|
}
|
||||||
|
fillState.fillStyle = fillStyle;
|
||||||
}
|
}
|
||||||
var textStrokeStyle = textStyle.getStroke();
|
var textStrokeStyle = textStyle.getStroke();
|
||||||
if (!textStrokeStyle) {
|
if (!textStrokeStyle) {
|
||||||
this.textStrokeState_ = null;
|
strokeState = this.textStrokeState_ = null;
|
||||||
} else {
|
} else {
|
||||||
var textStrokeStyleColor = textStrokeStyle.getColor();
|
var textStrokeStyleColor = textStrokeStyle.getColor();
|
||||||
var textStrokeStyleLineCap = textStrokeStyle.getLineCap();
|
var textStrokeStyleLineCap = textStrokeStyle.getLineCap();
|
||||||
@@ -275,26 +466,17 @@ ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) {
|
|||||||
textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;
|
textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;
|
||||||
var strokeStyle = ol.colorlike.asColorLike(textStrokeStyleColor ?
|
var strokeStyle = ol.colorlike.asColorLike(textStrokeStyleColor ?
|
||||||
textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle);
|
textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle);
|
||||||
if (!this.textStrokeState_) {
|
strokeState = this.textStrokeState_;
|
||||||
this.textStrokeState_ = {
|
if (!strokeState) {
|
||||||
lineCap: lineCap,
|
strokeState = this.textStrokeState_ = /** @type {ol.CanvasStrokeState} */ ({});
|
||||||
lineDash: lineDash,
|
|
||||||
lineDashOffset: lineDashOffset,
|
|
||||||
lineJoin: lineJoin,
|
|
||||||
lineWidth: lineWidth,
|
|
||||||
miterLimit: miterLimit,
|
|
||||||
strokeStyle: strokeStyle
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
var textStrokeState = this.textStrokeState_;
|
|
||||||
textStrokeState.lineCap = lineCap;
|
|
||||||
textStrokeState.lineDash = lineDash;
|
|
||||||
textStrokeState.lineDashOffset = lineDashOffset;
|
|
||||||
textStrokeState.lineJoin = lineJoin;
|
|
||||||
textStrokeState.lineWidth = lineWidth;
|
|
||||||
textStrokeState.miterLimit = miterLimit;
|
|
||||||
textStrokeState.strokeStyle = strokeStyle;
|
|
||||||
}
|
}
|
||||||
|
strokeState.lineCap = lineCap;
|
||||||
|
strokeState.lineDash = lineDash;
|
||||||
|
strokeState.lineDashOffset = lineDashOffset;
|
||||||
|
strokeState.lineJoin = lineJoin;
|
||||||
|
strokeState.lineWidth = lineWidth;
|
||||||
|
strokeState.miterLimit = miterLimit;
|
||||||
|
strokeState.strokeStyle = strokeStyle;
|
||||||
}
|
}
|
||||||
var textFont = textStyle.getFont();
|
var textFont = textStyle.getFont();
|
||||||
var textOffsetX = textStyle.getOffsetX();
|
var textOffsetX = textStyle.getOffsetX();
|
||||||
@@ -307,27 +489,35 @@ ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) {
|
|||||||
var textTextBaseline = textStyle.getTextBaseline();
|
var textTextBaseline = textStyle.getTextBaseline();
|
||||||
var font = textFont !== undefined ?
|
var font = textFont !== undefined ?
|
||||||
textFont : ol.render.canvas.defaultFont;
|
textFont : ol.render.canvas.defaultFont;
|
||||||
var textAlign = textTextAlign !== undefined ?
|
var textAlign = textTextAlign;
|
||||||
textTextAlign : ol.render.canvas.defaultTextAlign;
|
|
||||||
var textBaseline = textTextBaseline !== undefined ?
|
var textBaseline = textTextBaseline !== undefined ?
|
||||||
textTextBaseline : ol.render.canvas.defaultTextBaseline;
|
textTextBaseline : ol.render.canvas.defaultTextBaseline;
|
||||||
if (!this.textState_) {
|
textState = this.textState_;
|
||||||
this.textState_ = {
|
if (!textState) {
|
||||||
font: font,
|
textState = this.textState_ = /** @type {ol.CanvasTextState} */ ({});
|
||||||
textAlign: textAlign,
|
|
||||||
textBaseline: textBaseline
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
var textState = this.textState_;
|
|
||||||
textState.font = font;
|
|
||||||
textState.textAlign = textAlign;
|
|
||||||
textState.textBaseline = textBaseline;
|
|
||||||
}
|
}
|
||||||
|
textState.exceedLength = textStyle.getExceedLength();
|
||||||
|
textState.font = font;
|
||||||
|
textState.maxAngle = textStyle.getMaxAngle();
|
||||||
|
textState.placement = textStyle.getPlacement();
|
||||||
|
textState.textAlign = textAlign;
|
||||||
|
textState.textBaseline = textBaseline;
|
||||||
|
|
||||||
this.text_ = textText !== undefined ? textText : '';
|
this.text_ = textText !== undefined ? textText : '';
|
||||||
this.textOffsetX_ = textOffsetX !== undefined ? textOffsetX : 0;
|
this.textOffsetX_ = textOffsetX !== undefined ? textOffsetX : 0;
|
||||||
this.textOffsetY_ = textOffsetY !== undefined ? textOffsetY : 0;
|
this.textOffsetY_ = textOffsetY !== undefined ? textOffsetY : 0;
|
||||||
this.textRotateWithView_ = textRotateWithView !== undefined ? textRotateWithView : false;
|
this.textRotateWithView_ = textRotateWithView !== undefined ? textRotateWithView : false;
|
||||||
this.textRotation_ = textRotation !== undefined ? textRotation : 0;
|
this.textRotation_ = textRotation !== undefined ? textRotation : 0;
|
||||||
this.textScale_ = textScale !== undefined ? textScale : 1;
|
this.textScale_ = textScale !== undefined ? textScale : 1;
|
||||||
|
|
||||||
|
this.strokeKey_ = strokeState ?
|
||||||
|
(typeof strokeState.strokeStyle == 'string' ? strokeState.strokeStyle : ol.getUid(strokeState.strokeStyle)) +
|
||||||
|
strokeState.lineCap + strokeState.lineDashOffset + '|' + strokeState.lineWidth +
|
||||||
|
strokeState.lineJoin + strokeState.miterLimit + '[' + strokeState.lineDash.join() + ']' :
|
||||||
|
'';
|
||||||
|
this.textKey_ = textState.font + textState.textAlign;
|
||||||
|
this.fillKey_ = fillState ?
|
||||||
|
(typeof fillState.fillStyle == 'string' ? fillState.fillStyle : ('|' + ol.getUid(fillState.fillStyle))) :
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -108,14 +108,10 @@ ol.render.VectorContext.prototype.drawPolygon = function(polygonGeometry, featur
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Array.<number>} flatCoordinates Flat coordinates.
|
|
||||||
* @param {number} offset Offset.
|
|
||||||
* @param {number} end End.
|
|
||||||
* @param {number} stride Stride.
|
|
||||||
* @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
|
* @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
|
||||||
* @param {ol.Feature|ol.render.Feature} feature Feature.
|
* @param {ol.Feature|ol.render.Feature} feature Feature.
|
||||||
*/
|
*/
|
||||||
ol.render.VectorContext.prototype.drawText = function(flatCoordinates, offset, end, stride, geometry, feature) {};
|
ol.render.VectorContext.prototype.drawText = function(geometry, feature) {};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -88,19 +88,15 @@ ol.inherits(ol.render.webgl.Immediate, ol.render.VectorContext);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ol.render.webgl.ReplayGroup} replayGroup Replay group.
|
* @param {ol.render.webgl.ReplayGroup} replayGroup Replay group.
|
||||||
* @param {Array.<number>} flatCoordinates Flat coordinates.
|
* @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
|
||||||
* @param {number} offset Offset.
|
|
||||||
* @param {number} end End.
|
|
||||||
* @param {number} stride Stride.
|
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
ol.render.webgl.Immediate.prototype.drawText_ = function(replayGroup,
|
ol.render.webgl.Immediate.prototype.drawText_ = function(replayGroup, geometry) {
|
||||||
flatCoordinates, offset, end, stride) {
|
|
||||||
var context = this.context_;
|
var context = this.context_;
|
||||||
var replay = /** @type {ol.render.webgl.TextReplay} */ (
|
var replay = /** @type {ol.render.webgl.TextReplay} */ (
|
||||||
replayGroup.getReplay(0, ol.render.ReplayType.TEXT));
|
replayGroup.getReplay(0, ol.render.ReplayType.TEXT));
|
||||||
replay.setTextStyle(this.textStyle_);
|
replay.setTextStyle(this.textStyle_);
|
||||||
replay.drawText(flatCoordinates, offset, end, stride, null, null);
|
replay.drawText(geometry, null);
|
||||||
replay.finish(context);
|
replay.finish(context);
|
||||||
// default colors
|
// default colors
|
||||||
var opacity = 1;
|
var opacity = 1;
|
||||||
@@ -219,9 +215,7 @@ ol.render.webgl.Immediate.prototype.drawPoint = function(geometry, data) {
|
|||||||
replay.getDeleteResourcesFunction(context)();
|
replay.getDeleteResourcesFunction(context)();
|
||||||
|
|
||||||
if (this.textStyle_) {
|
if (this.textStyle_) {
|
||||||
var flatCoordinates = geometry.getFlatCoordinates();
|
this.drawText_(replayGroup, geometry);
|
||||||
var stride = geometry.getStride();
|
|
||||||
this.drawText_(replayGroup, flatCoordinates, 0, flatCoordinates.length, stride);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -247,9 +241,7 @@ ol.render.webgl.Immediate.prototype.drawMultiPoint = function(geometry, data) {
|
|||||||
replay.getDeleteResourcesFunction(context)();
|
replay.getDeleteResourcesFunction(context)();
|
||||||
|
|
||||||
if (this.textStyle_) {
|
if (this.textStyle_) {
|
||||||
var flatCoordinates = geometry.getFlatCoordinates();
|
this.drawText_(replayGroup, geometry);
|
||||||
var stride = geometry.getStride();
|
|
||||||
this.drawText_(replayGroup, flatCoordinates, 0, flatCoordinates.length, stride);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -275,8 +267,7 @@ ol.render.webgl.Immediate.prototype.drawLineString = function(geometry, data) {
|
|||||||
replay.getDeleteResourcesFunction(context)();
|
replay.getDeleteResourcesFunction(context)();
|
||||||
|
|
||||||
if (this.textStyle_) {
|
if (this.textStyle_) {
|
||||||
var flatMidpoint = geometry.getFlatMidpoint();
|
this.drawText_(replayGroup, geometry);
|
||||||
this.drawText_(replayGroup, flatMidpoint, 0, 2, 2);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -302,8 +293,7 @@ ol.render.webgl.Immediate.prototype.drawMultiLineString = function(geometry, dat
|
|||||||
replay.getDeleteResourcesFunction(context)();
|
replay.getDeleteResourcesFunction(context)();
|
||||||
|
|
||||||
if (this.textStyle_) {
|
if (this.textStyle_) {
|
||||||
var flatMidpoints = geometry.getFlatMidpoints();
|
this.drawText_(replayGroup, geometry);
|
||||||
this.drawText_(replayGroup, flatMidpoints, 0, flatMidpoints.length, 2);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -329,8 +319,7 @@ ol.render.webgl.Immediate.prototype.drawPolygon = function(geometry, data) {
|
|||||||
replay.getDeleteResourcesFunction(context)();
|
replay.getDeleteResourcesFunction(context)();
|
||||||
|
|
||||||
if (this.textStyle_) {
|
if (this.textStyle_) {
|
||||||
var flatInteriorPoint = geometry.getFlatInteriorPoint();
|
this.drawText_(replayGroup, geometry);
|
||||||
this.drawText_(replayGroup, flatInteriorPoint, 0, 2, 2);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -356,8 +345,7 @@ ol.render.webgl.Immediate.prototype.drawMultiPolygon = function(geometry, data)
|
|||||||
replay.getDeleteResourcesFunction(context)();
|
replay.getDeleteResourcesFunction(context)();
|
||||||
|
|
||||||
if (this.textStyle_) {
|
if (this.textStyle_) {
|
||||||
var flatInteriorPoints = geometry.getFlatInteriorPoints();
|
this.drawText_(replayGroup, geometry);
|
||||||
this.drawText_(replayGroup, flatInteriorPoints, 0, flatInteriorPoints.length, 2);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -383,7 +371,7 @@ ol.render.webgl.Immediate.prototype.drawCircle = function(geometry, data) {
|
|||||||
replay.getDeleteResourcesFunction(context)();
|
replay.getDeleteResourcesFunction(context)();
|
||||||
|
|
||||||
if (this.textStyle_) {
|
if (this.textStyle_) {
|
||||||
this.drawText_(replayGroup, geometry.getCenter(), 0, 2, 2);
|
this.drawText_(replayGroup, geometry);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ goog.provide('ol.render.webgl.TextReplay');
|
|||||||
goog.require('ol');
|
goog.require('ol');
|
||||||
goog.require('ol.colorlike');
|
goog.require('ol.colorlike');
|
||||||
goog.require('ol.dom');
|
goog.require('ol.dom');
|
||||||
|
goog.require('ol.geom.GeometryType');
|
||||||
goog.require('ol.has');
|
goog.require('ol.has');
|
||||||
goog.require('ol.render.replay');
|
goog.require('ol.render.replay');
|
||||||
goog.require('ol.render.webgl');
|
goog.require('ol.render.webgl');
|
||||||
@@ -118,9 +119,38 @@ ol.inherits(ol.render.webgl.TextReplay, ol.render.webgl.TextureReplay);
|
|||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
ol.render.webgl.TextReplay.prototype.drawText = function(flatCoordinates, offset,
|
ol.render.webgl.TextReplay.prototype.drawText = function(geometry, feature) {
|
||||||
end, stride, geometry, feature) {
|
|
||||||
if (this.text_) {
|
if (this.text_) {
|
||||||
|
var flatCoordinates = null;
|
||||||
|
var offset = 0;
|
||||||
|
var end = 2;
|
||||||
|
var stride = 2;
|
||||||
|
switch (geometry.getType()) {
|
||||||
|
case ol.geom.GeometryType.POINT:
|
||||||
|
case ol.geom.GeometryType.MULTI_POINT:
|
||||||
|
flatCoordinates = geometry.getFlatCoordinates();
|
||||||
|
end = flatCoordinates.length;
|
||||||
|
stride = geometry.getStride();
|
||||||
|
break;
|
||||||
|
case ol.geom.GeometryType.CIRCLE:
|
||||||
|
flatCoordinates = /** @type {ol.geom.Circle} */ (geometry).getCenter();
|
||||||
|
break;
|
||||||
|
case ol.geom.GeometryType.LINE_STRING:
|
||||||
|
flatCoordinates = /** @type {ol.geom.LineString} */ (geometry).getFlatMidpoint();
|
||||||
|
break;
|
||||||
|
case ol.geom.GeometryType.MULTI_LINE_STRING:
|
||||||
|
flatCoordinates = /** @type {ol.geom.MultiLineString} */ (geometry).getFlatMidpoints();
|
||||||
|
end = flatCoordinates.length;
|
||||||
|
break;
|
||||||
|
case ol.geom.GeometryType.POLYGON:
|
||||||
|
flatCoordinates = /** @type {ol.geom.Polygon} */ (geometry).getFlatInteriorPoint();
|
||||||
|
break;
|
||||||
|
case ol.geom.GeometryType.MULTI_POLYGON:
|
||||||
|
flatCoordinates = /** @type {ol.geom.MultiPolygon} */ (geometry).getFlatInteriorPoints();
|
||||||
|
end = flatCoordinates.length;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
this.startIndices.push(this.indices.length);
|
this.startIndices.push(this.indices.length);
|
||||||
this.startIndicesFeature.push(feature);
|
this.startIndicesFeature.push(feature);
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ ol.renderer.vector.renderCircleGeometry_ = function(replayGroup, geometry, style
|
|||||||
var textReplay = replayGroup.getReplay(
|
var textReplay = replayGroup.getReplay(
|
||||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||||
textReplay.setTextStyle(textStyle);
|
textReplay.setTextStyle(textStyle);
|
||||||
textReplay.drawText(geometry.getCenter(), 0, 2, 2, geometry, feature);
|
textReplay.drawText(geometry, feature);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -181,7 +181,7 @@ ol.renderer.vector.renderLineStringGeometry_ = function(replayGroup, geometry, s
|
|||||||
var textReplay = replayGroup.getReplay(
|
var textReplay = replayGroup.getReplay(
|
||||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||||
textReplay.setTextStyle(textStyle);
|
textReplay.setTextStyle(textStyle);
|
||||||
textReplay.drawText(geometry.getFlatMidpoint(), 0, 2, 2, geometry, feature);
|
textReplay.drawText(geometry, feature);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -206,9 +206,7 @@ ol.renderer.vector.renderMultiLineStringGeometry_ = function(replayGroup, geomet
|
|||||||
var textReplay = replayGroup.getReplay(
|
var textReplay = replayGroup.getReplay(
|
||||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||||
textReplay.setTextStyle(textStyle);
|
textReplay.setTextStyle(textStyle);
|
||||||
var flatMidpointCoordinates = geometry.getFlatMidpoints();
|
textReplay.drawText(geometry, feature);
|
||||||
textReplay.drawText(flatMidpointCoordinates, 0,
|
|
||||||
flatMidpointCoordinates.length, 2, geometry, feature);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -234,9 +232,7 @@ ol.renderer.vector.renderMultiPolygonGeometry_ = function(replayGroup, geometry,
|
|||||||
var textReplay = replayGroup.getReplay(
|
var textReplay = replayGroup.getReplay(
|
||||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||||
textReplay.setTextStyle(textStyle);
|
textReplay.setTextStyle(textStyle);
|
||||||
var flatInteriorPointCoordinates = geometry.getFlatInteriorPoints();
|
textReplay.drawText(geometry, feature);
|
||||||
textReplay.drawText(flatInteriorPointCoordinates, 0,
|
|
||||||
flatInteriorPointCoordinates.length, 2, geometry, feature);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -264,8 +260,7 @@ ol.renderer.vector.renderPointGeometry_ = function(replayGroup, geometry, style,
|
|||||||
var textReplay = replayGroup.getReplay(
|
var textReplay = replayGroup.getReplay(
|
||||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||||
textReplay.setTextStyle(textStyle);
|
textReplay.setTextStyle(textStyle);
|
||||||
textReplay.drawText(geometry.getFlatCoordinates(), 0, 2, 2, geometry,
|
textReplay.drawText(geometry, feature);
|
||||||
feature);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -293,9 +288,7 @@ ol.renderer.vector.renderMultiPointGeometry_ = function(replayGroup, geometry, s
|
|||||||
var textReplay = replayGroup.getReplay(
|
var textReplay = replayGroup.getReplay(
|
||||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||||
textReplay.setTextStyle(textStyle);
|
textReplay.setTextStyle(textStyle);
|
||||||
var flatCoordinates = geometry.getFlatCoordinates();
|
textReplay.drawText(geometry, feature);
|
||||||
textReplay.drawText(flatCoordinates, 0, flatCoordinates.length,
|
|
||||||
geometry.getStride(), geometry, feature);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -321,8 +314,7 @@ ol.renderer.vector.renderPolygonGeometry_ = function(replayGroup, geometry, styl
|
|||||||
var textReplay = replayGroup.getReplay(
|
var textReplay = replayGroup.getReplay(
|
||||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||||
textReplay.setTextStyle(textStyle);
|
textReplay.setTextStyle(textStyle);
|
||||||
textReplay.drawText(
|
textReplay.drawText(geometry, feature);
|
||||||
geometry.getFlatInteriorPoint(), 0, 2, 2, geometry, feature);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ goog.provide('ol.style.Text');
|
|||||||
|
|
||||||
|
|
||||||
goog.require('ol.style.Fill');
|
goog.require('ol.style.Fill');
|
||||||
|
goog.require('ol.style.TextPlacement');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,6 +66,24 @@ ol.style.Text = function(opt_options) {
|
|||||||
this.fill_ = options.fill !== undefined ? options.fill :
|
this.fill_ = options.fill !== undefined ? options.fill :
|
||||||
new ol.style.Fill({color: ol.style.Text.DEFAULT_FILL_COLOR_});
|
new ol.style.Fill({color: ol.style.Text.DEFAULT_FILL_COLOR_});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.maxAngle_ = options.maxAngle !== undefined ? options.maxAngle : Math.PI / 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {ol.style.TextPlacement|string}
|
||||||
|
*/
|
||||||
|
this.placement_ = options.placement !== undefined ? options.placement : ol.style.TextPlacement.POINT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
this.exceedLength_ = options.exceedLength !== undefined ? options.exceedLength : false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {ol.style.Stroke}
|
* @type {ol.style.Stroke}
|
||||||
@@ -103,6 +122,9 @@ ol.style.Text.DEFAULT_FILL_COLOR_ = '#333';
|
|||||||
ol.style.Text.prototype.clone = function() {
|
ol.style.Text.prototype.clone = function() {
|
||||||
return new ol.style.Text({
|
return new ol.style.Text({
|
||||||
font: this.getFont(),
|
font: this.getFont(),
|
||||||
|
placement: this.getPlacement(),
|
||||||
|
maxAngle: this.getMaxAngle(),
|
||||||
|
exceedLength: this.getExceedLength(),
|
||||||
rotation: this.getRotation(),
|
rotation: this.getRotation(),
|
||||||
rotateWithView: this.getRotateWithView(),
|
rotateWithView: this.getRotateWithView(),
|
||||||
scale: this.getScale(),
|
scale: this.getScale(),
|
||||||
@@ -117,6 +139,16 @@ ol.style.Text.prototype.clone = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the `exceedLength` configuration.
|
||||||
|
* @return {boolean} Let text exceed the length of the path they follow.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
ol.style.Text.prototype.getExceedLength = function() {
|
||||||
|
return this.exceedLength_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the font name.
|
* Get the font name.
|
||||||
* @return {string|undefined} Font.
|
* @return {string|undefined} Font.
|
||||||
@@ -127,6 +159,26 @@ ol.style.Text.prototype.getFont = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the maximum angle between adjacent characters.
|
||||||
|
* @return {number} Angle in radians.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
ol.style.Text.prototype.getMaxAngle = function() {
|
||||||
|
return this.maxAngle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the label placement.
|
||||||
|
* @return {ol.style.TextPlacement|string} Text placement.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
ol.style.Text.prototype.getPlacement = function() {
|
||||||
|
return this.placement_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the x-offset for the text.
|
* Get the x-offset for the text.
|
||||||
* @return {number} Horizontal text offset.
|
* @return {number} Horizontal text offset.
|
||||||
@@ -227,6 +279,17 @@ ol.style.Text.prototype.getTextBaseline = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the `exceedLength` property.
|
||||||
|
*
|
||||||
|
* @param {boolean} exceedLength Let text exceed the path that it follows.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
ol.style.Text.prototype.setExceedLength = function(exceedLength) {
|
||||||
|
this.exceedLength_ = exceedLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the font.
|
* Set the font.
|
||||||
*
|
*
|
||||||
@@ -238,6 +301,17 @@ ol.style.Text.prototype.setFont = function(font) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the maximum angle between adjacent characters.
|
||||||
|
*
|
||||||
|
* @param {number} maxAngle Angle in radians.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
ol.style.Text.prototype.setMaxAngle = function(maxAngle) {
|
||||||
|
this.maxAngle_ = maxAngle;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the x offset.
|
* Set the x offset.
|
||||||
*
|
*
|
||||||
@@ -260,6 +334,17 @@ ol.style.Text.prototype.setOffsetY = function(offsetY) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the text placement.
|
||||||
|
*
|
||||||
|
* @param {ol.style.TextPlacement|string} placement Placement.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
ol.style.Text.prototype.setPlacement = function(placement) {
|
||||||
|
this.placement_ = placement;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the fill.
|
* Set the fill.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
goog.provide('ol.style.TextPlacement');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text placement. One of `'point'`, `'line'`. Default is `'point'`. Note that
|
||||||
|
* `'line'` requires the underlying geometry to be a {@link ol.geom.LineString},
|
||||||
|
* {@link ol.geom.Polygon}, {@link ol.geom.MultiLineString} or
|
||||||
|
* {@link ol.geom.MultiPolygon}.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
ol.style.TextPlacement = {
|
||||||
|
POINT: 'point',
|
||||||
|
LINE: 'line'
|
||||||
|
};
|
||||||
@@ -90,7 +90,7 @@ ol.CanvasStrokeState;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{font: string,
|
* @typedef {{font: string,
|
||||||
* textAlign: string,
|
* textAlign: (string|undefined),
|
||||||
* textBaseline: string}}
|
* textBaseline: string}}
|
||||||
*/
|
*/
|
||||||
ol.CanvasTextState;
|
ol.CanvasTextState;
|
||||||
|
|||||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
@@ -1,7 +1,9 @@
|
|||||||
|
|
||||||
|
|
||||||
goog.require('ol.Feature');
|
goog.require('ol.Feature');
|
||||||
|
goog.require('ol.geom.LineString');
|
||||||
|
goog.require('ol.geom.MultiLineString');
|
||||||
|
goog.require('ol.geom.MultiPolygon');
|
||||||
goog.require('ol.geom.Point');
|
goog.require('ol.geom.Point');
|
||||||
|
goog.require('ol.geom.Polygon');
|
||||||
goog.require('ol.Map');
|
goog.require('ol.Map');
|
||||||
goog.require('ol.View');
|
goog.require('ol.View');
|
||||||
goog.require('ol.layer.Vector');
|
goog.require('ol.layer.Vector');
|
||||||
@@ -90,6 +92,54 @@ describe('ol.rendering.style.Text', function() {
|
|||||||
vectorSource.addFeature(feature);
|
vectorSource.addFeature(feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var nicePath = [
|
||||||
|
20, 33, 40, 31, 60, 30, 80, 31, 100, 33, 120, 37, 140, 39, 160, 40,
|
||||||
|
180, 39, 200, 37, 220, 33, 240, 31, 260, 30, 280, 31, 300, 33
|
||||||
|
];
|
||||||
|
var uglyPath = [163, 22, 159, 30, 150, 30, 143, 24, 151, 17];
|
||||||
|
var polygon = [151, 17, 163, 22, 159, 30, 150, 30, 143, 24, 151, 17];
|
||||||
|
|
||||||
|
function createLineString(coords, textAlign, maxAngle) {
|
||||||
|
var geom = new ol.geom.LineString();
|
||||||
|
geom.setFlatCoordinates('XY', coords);
|
||||||
|
var style = new ol.style.Style({
|
||||||
|
stroke: new ol.style.Stroke({
|
||||||
|
color: 'red'
|
||||||
|
}),
|
||||||
|
text: new ol.style.Text({
|
||||||
|
text: 'Hello world',
|
||||||
|
font: 'bold 14px sans-serif',
|
||||||
|
textAlign: textAlign,
|
||||||
|
maxAngle: maxAngle,
|
||||||
|
placement: 'line',
|
||||||
|
stroke: new ol.style.Stroke({
|
||||||
|
color: 'white'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
var feature = new ol.Feature(geom);
|
||||||
|
feature.setStyle(style);
|
||||||
|
vectorSource.addFeature(feature);
|
||||||
|
|
||||||
|
geom = geom.clone();
|
||||||
|
geom.translate(0, 5);
|
||||||
|
feature = new ol.Feature(geom);
|
||||||
|
style = style.clone();
|
||||||
|
style.getText().setTextBaseline('top');
|
||||||
|
feature.setStyle(style);
|
||||||
|
vectorSource.addFeature(feature);
|
||||||
|
|
||||||
|
geom = geom.clone();
|
||||||
|
geom.translate(0, -10);
|
||||||
|
feature = new ol.Feature(geom);
|
||||||
|
style = style.clone();
|
||||||
|
style.getText().setTextBaseline('bottom');
|
||||||
|
feature.setStyle(style);
|
||||||
|
vectorSource.addFeature(feature);
|
||||||
|
|
||||||
|
map.getView().fit(vectorSource.getExtent());
|
||||||
|
}
|
||||||
|
|
||||||
it('tests the canvas renderer without rotation', function(done) {
|
it('tests the canvas renderer without rotation', function(done) {
|
||||||
createMap('canvas');
|
createMap('canvas');
|
||||||
createFeatures();
|
createFeatures();
|
||||||
@@ -191,6 +241,136 @@ describe('ol.rendering.style.Text', function() {
|
|||||||
expectResemble(map, 'rendering/ol/style/expected/text-align-offset-canvas.png', 5, done);
|
expectResemble(map, 'rendering/ol/style/expected/text-align-offset-canvas.png', 5, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Text along an ugly upside down path, keep text upright', function() {
|
||||||
|
|
||||||
|
it('renders text along a linestring with auto-align', function(done) {
|
||||||
|
createMap('canvas');
|
||||||
|
createLineString(uglyPath);
|
||||||
|
expectResemble(map, 'rendering/ol/style/expected/text-linestring-auto.png', 3.6, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders text along a linestring with `textAlign: \'center\'`', function(done) {
|
||||||
|
createMap('canvas');
|
||||||
|
createLineString(uglyPath, 'center');
|
||||||
|
expectResemble(map, 'rendering/ol/style/expected/text-linestring-center.png', 3.6, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('omits text along a linestring with `textAlign: \'left\'` when > maxAngle', function(done) {
|
||||||
|
createMap('canvas');
|
||||||
|
createLineString(uglyPath, 'left');
|
||||||
|
vectorSource.getFeatures()[0].getStyle().getText().setTextAlign('left');
|
||||||
|
expectResemble(map, 'rendering/ol/style/expected/text-linestring-omit.png', IMAGE_TOLERANCE, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('omits text along a linestring with `textAlign: \'right\'` when > maxAngle', function(done) {
|
||||||
|
createMap('canvas');
|
||||||
|
createLineString(uglyPath, 'right');
|
||||||
|
vectorSource.getFeatures()[0].getStyle().getText().setTextAlign('left');
|
||||||
|
expectResemble(map, 'rendering/ol/style/expected/text-linestring-omit.png', IMAGE_TOLERANCE, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders text along a linestring with `textAlign: \'left\'` and no angle limit', function(done) {
|
||||||
|
createMap('canvas');
|
||||||
|
createLineString(uglyPath, 'left', Infinity);
|
||||||
|
expectResemble(map, 'rendering/ol/style/expected/text-linestring-left.png', 3.5, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Text along a nice path', function() {
|
||||||
|
|
||||||
|
it('renders text along a linestring', function(done) {
|
||||||
|
createMap('canvas');
|
||||||
|
createLineString(nicePath);
|
||||||
|
expectResemble(map, 'rendering/ol/style/expected/text-linestring-nice.png', 2.5, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders text along a linestring with `textAlign: \'left\'`', function(done) {
|
||||||
|
createMap('canvas');
|
||||||
|
createLineString(nicePath, 'left');
|
||||||
|
expectResemble(map, 'rendering/ol/style/expected/text-linestring-left-nice.png', 2.5, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders text along a rotated linestring', function(done) {
|
||||||
|
createMap('canvas');
|
||||||
|
map.getView().setRotation(Math.PI);
|
||||||
|
createLineString(nicePath);
|
||||||
|
expectResemble(map, 'rendering/ol/style/expected/text-linestring-nice-rotated.png', 4.5, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders text along a rotated linestring with `textAlign: \'left\'`', function(done) {
|
||||||
|
createMap('canvas');
|
||||||
|
map.getView().setRotation(Math.PI);
|
||||||
|
createLineString(nicePath, 'left');
|
||||||
|
expectResemble(map, 'rendering/ol/style/expected/text-linestring-left-nice-rotated.png', 4.5, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders text along a MultiLineString', function(done) {
|
||||||
|
createMap('canvas');
|
||||||
|
var line = new ol.geom.LineString();
|
||||||
|
line.setFlatCoordinates('XY', nicePath);
|
||||||
|
var geom = new ol.geom.MultiLineString(null);
|
||||||
|
geom.appendLineString(line);
|
||||||
|
line.translate(0, 50);
|
||||||
|
geom.appendLineString(line);
|
||||||
|
line.translate(0, -100);
|
||||||
|
geom.appendLineString(line);
|
||||||
|
var feature = new ol.Feature(geom);
|
||||||
|
feature.setStyle(new ol.style.Style({
|
||||||
|
text: new ol.style.Text({
|
||||||
|
text: 'Hello world',
|
||||||
|
placement: 'line',
|
||||||
|
font: 'bold 30px sans-serif'
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
vectorSource.addFeature(feature);
|
||||||
|
map.getView().fit(vectorSource.getExtent());
|
||||||
|
expectResemble(map, 'rendering/ol/style/expected/text-multilinestring.png', 6.9, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders text along a Polygon', function(done) {
|
||||||
|
createMap('canvas');
|
||||||
|
var geom = new ol.geom.Polygon(null);
|
||||||
|
geom.setFlatCoordinates('XY', polygon, [polygon.length]);
|
||||||
|
var feature = new ol.Feature(geom);
|
||||||
|
feature.setStyle(new ol.style.Style({
|
||||||
|
text: new ol.style.Text({
|
||||||
|
text: 'Hello world',
|
||||||
|
font: 'bold 24px sans-serif',
|
||||||
|
placement: 'line',
|
||||||
|
exceedLength: true
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
vectorSource.addFeature(feature);
|
||||||
|
map.getView().fit(vectorSource.getExtent());
|
||||||
|
expectResemble(map, 'rendering/ol/style/expected/text-polygon.png', IMAGE_TOLERANCE, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders text along a MultiPolygon', function(done) {
|
||||||
|
createMap('canvas');
|
||||||
|
var geom = new ol.geom.Polygon(null);
|
||||||
|
geom.setFlatCoordinates('XY', polygon, [polygon.length]);
|
||||||
|
var multiPolygon = new ol.geom.MultiPolygon(null);
|
||||||
|
multiPolygon.appendPolygon(geom);
|
||||||
|
geom.translate(0, 30);
|
||||||
|
multiPolygon.appendPolygon(geom);
|
||||||
|
geom.translate(0, -60);
|
||||||
|
multiPolygon.appendPolygon(geom);
|
||||||
|
var feature = new ol.Feature(multiPolygon);
|
||||||
|
feature.setStyle(new ol.style.Style({
|
||||||
|
text: new ol.style.Text({
|
||||||
|
text: 'Hello world',
|
||||||
|
font: 'bold 24px sans-serif',
|
||||||
|
placement: 'line',
|
||||||
|
exceedLength: true
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
vectorSource.addFeature(feature);
|
||||||
|
map.getView().fit(vectorSource.getExtent());
|
||||||
|
expectResemble(map, 'rendering/ol/style/expected/text-multipolygon.png', 4.4, done);
|
||||||
|
});
|
||||||
|
|
||||||
where('WebGL').it('tests the webgl renderer without rotation', function(done) {
|
where('WebGL').it('tests the webgl renderer without rotation', function(done) {
|
||||||
createMap('webgl');
|
createMap('webgl');
|
||||||
createFeatures();
|
createFeatures();
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
goog.require('ol.geom.flat.straightchunk');
|
||||||
|
|
||||||
|
|
||||||
|
describe('ol.geom.flat.straightchunk', function() {
|
||||||
|
|
||||||
|
describe('ol.geom.flat.straightchunk.lineString', function() {
|
||||||
|
|
||||||
|
describe('single segment with stride == 3', function() {
|
||||||
|
var flatCoords = [0, 0, 42, 1, 1, 42];
|
||||||
|
var stride = 3;
|
||||||
|
|
||||||
|
it('returns whole line with angle delta', function() {
|
||||||
|
var got = ol.geom.flat.straightchunk.lineString(Math.PI / 4, flatCoords, 0, 6, stride);
|
||||||
|
expect(got).to.eql([0, 6]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns whole line with zero angle delta', function() {
|
||||||
|
var got = ol.geom.flat.straightchunk.lineString(0, flatCoords, 0, 6, stride);
|
||||||
|
expect(got).to.eql([0, 6]);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('short line string', function() {
|
||||||
|
var flatCoords = [0, 0, 1, 0, 1, 1, 0, 1];
|
||||||
|
var stride = 2;
|
||||||
|
|
||||||
|
it('returns whole line if straight enough', function() {
|
||||||
|
var got = ol.geom.flat.straightchunk.lineString(Math.PI, flatCoords, 0, 8, stride);
|
||||||
|
expect(got).to.eql([0, 8]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns first matching chunk if all chunk lengths are the same', function() {
|
||||||
|
var got = ol.geom.flat.straightchunk.lineString(Math.PI / 4, flatCoords, 0, 8, stride);
|
||||||
|
expect(got).to.eql([0, 4]);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('longer line string', function() {
|
||||||
|
var flatCoords = [0, 0, 1, 0, 1, 1, 0, 1, 0, -1, -1, -1, -1, 0, -1, 2, -2, 4];
|
||||||
|
var stride = 2;
|
||||||
|
|
||||||
|
it('returns stright chunk from within the linestring', function() {
|
||||||
|
var got = ol.geom.flat.straightchunk.lineString(0, flatCoords, 0, 18, stride);
|
||||||
|
expect(got).to.eql([10, 16]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns long chunk at the end if angle and length within threshold', function() {
|
||||||
|
var got = ol.geom.flat.straightchunk.lineString(Math.PI / 4, flatCoords, 0, 18, stride);
|
||||||
|
expect(got).to.eql([10, 18]);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
goog.require('ol.geom.flat.textpath');
|
||||||
|
goog.require('ol.geom.flat.length');
|
||||||
|
|
||||||
|
describe('textpath', function() {
|
||||||
|
|
||||||
|
var horizontal = [0, 0, 100, 0];
|
||||||
|
var vertical = [0, 0, 0, 100];
|
||||||
|
var diagonal = [0, 0, 100, 100];
|
||||||
|
var reverse = [100, 0, 0, 100];
|
||||||
|
var angled = [0, 0, 100, 100, 200, 0];
|
||||||
|
var reverseangled = [151, 17, 163, 22, 159, 30, 150, 30, 143, 24, 151, 17];
|
||||||
|
|
||||||
|
function measure(text) {
|
||||||
|
return 10 * text.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
it('center-aligns text on a horizontal line', function() {
|
||||||
|
var startM = 50 - 15;
|
||||||
|
var instructions = ol.geom.flat.textpath.lineString(
|
||||||
|
horizontal, 0, horizontal.length, 2, 'foo', measure, startM, Infinity);
|
||||||
|
expect(instructions).to.eql([[40, 0, 0], [50, 0, 0], [60, 0, 0]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('left-aligns text on a horizontal line', function() {
|
||||||
|
var instructions = ol.geom.flat.textpath.lineString(
|
||||||
|
horizontal, 0, horizontal.length, 2, 'foo', measure, 0, Infinity);
|
||||||
|
expect(instructions).to.eql([[5, 0, 0], [15, 0, 0], [25, 0, 0]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('right-aligns text on a horizontal line', function() {
|
||||||
|
var startM = 100 - 30;
|
||||||
|
var instructions = ol.geom.flat.textpath.lineString(
|
||||||
|
horizontal, 0, horizontal.length, 2, 'foo', measure, startM, Infinity);
|
||||||
|
expect(instructions).to.eql([[75, 0, 0], [85, 0, 0], [95, 0, 0]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('draws text on a vertical line', function() {
|
||||||
|
var startM = 50 - 15;
|
||||||
|
var instructions = ol.geom.flat.textpath.lineString(
|
||||||
|
vertical, 0, vertical.length, 2, 'foo', measure, startM, Infinity);
|
||||||
|
var a = 90 * Math.PI / 180;
|
||||||
|
expect(instructions).to.eql([[0, 40, a], [0, 50, a], [0, 60, a]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('draws text on a diagonal line', function() {
|
||||||
|
var startM = Math.sqrt(2) * 50 - 15;
|
||||||
|
var instructions = ol.geom.flat.textpath.lineString(
|
||||||
|
diagonal, 0, diagonal.length, 2, 'foo', measure, startM, Infinity);
|
||||||
|
expect(instructions[0][2]).to.be(45 * Math.PI / 180);
|
||||||
|
expect(instructions[0][0]).to.be.lessThan(instructions[2][0]);
|
||||||
|
expect(instructions[0][1]).to.be.lessThan(instructions[2][1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('draws reverse text on a diagonal line', function() {
|
||||||
|
var startM = Math.sqrt(2) * 50 - 15;
|
||||||
|
var instructions = ol.geom.flat.textpath.lineString(
|
||||||
|
reverse, 0, reverse.length, 2, 'foo', measure, startM, Infinity);
|
||||||
|
expect(instructions[0][2]).to.be(-45 * Math.PI / 180);
|
||||||
|
expect(instructions[0][0]).to.be.lessThan(instructions[2][0]);
|
||||||
|
expect(instructions[0][1]).to.be.greaterThan(instructions[2][1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders long text with extrapolation', function() {
|
||||||
|
var startM = 50 - 75;
|
||||||
|
var instructions = ol.geom.flat.textpath.lineString(
|
||||||
|
horizontal, 0, horizontal.length, 2, 'foo-foo-foo-foo', measure, startM, Infinity);
|
||||||
|
expect(instructions[0]).to.eql([-20, 0, 0]);
|
||||||
|
expect(instructions[14]).to.eql([120, 0, 0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders angled text', function() {
|
||||||
|
var length = ol.geom.flat.length.lineString(angled, 0, angled.length, 2);
|
||||||
|
var startM = length / 2 - 15;
|
||||||
|
var instructions = ol.geom.flat.textpath.lineString(
|
||||||
|
angled, 0, angled.length, 2, 'foo', measure, startM, Infinity);
|
||||||
|
expect(instructions[0][2]).to.be(45 * Math.PI / 180);
|
||||||
|
expect(instructions[2][2]).to.be(-45 * Math.PI / 180);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('respects maxAngle', function() {
|
||||||
|
var length = ol.geom.flat.length.lineString(angled, 0, angled.length, 2);
|
||||||
|
var startM = length / 2 - 15;
|
||||||
|
var instructions = ol.geom.flat.textpath.lineString(
|
||||||
|
angled, 0, angled.length, 2, 'foo', measure, startM, Math.PI / 4);
|
||||||
|
expect(instructions).to.be(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses the smallest angle for maxAngleDelta', function() {
|
||||||
|
var length = ol.geom.flat.length.lineString(reverseangled, 0, reverseangled.length, 2);
|
||||||
|
var startM = length / 2 - 15;
|
||||||
|
var instructions = ol.geom.flat.textpath.lineString(
|
||||||
|
reverseangled, 0, reverseangled.length, 2, 'foo', measure, startM, Math.PI);
|
||||||
|
expect(instructions).to.not.be(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('respects the begin option', function() {
|
||||||
|
var length = ol.geom.flat.length.lineString(angled, 2, angled.length, 2);
|
||||||
|
var startM = length / 2 - 15;
|
||||||
|
var instructions = ol.geom.flat.textpath.lineString(
|
||||||
|
angled, 2, angled.length, 2, 'foo', measure, startM, Infinity);
|
||||||
|
expect(instructions[1][0]).to.be(150);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('respects the end option', function() {
|
||||||
|
var length = ol.geom.flat.length.lineString(angled, 0, 4, 2);
|
||||||
|
var startM = length / 2 - 15;
|
||||||
|
var instructions = ol.geom.flat.textpath.lineString(
|
||||||
|
angled, 0, 4, 2, 'foo', measure, startM, Infinity);
|
||||||
|
expect(instructions[1][0]).to.be(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses the provided result array', function() {
|
||||||
|
var result = [];
|
||||||
|
result[3] = undefined;
|
||||||
|
var startM = 50 - 15;
|
||||||
|
ol.geom.flat.textpath.lineString(
|
||||||
|
horizontal, 0, horizontal.length, 2, 'foo', measure, startM, Infinity, result);
|
||||||
|
expect(result).to.eql([[40, 0, 0], [50, 0, 0], [60, 0, 0], undefined]);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
goog.require('ol.dom');
|
goog.require('ol.dom');
|
||||||
|
goog.require('ol.geom.Point');
|
||||||
goog.require('ol.render.webgl.TextReplay');
|
goog.require('ol.render.webgl.TextReplay');
|
||||||
goog.require('ol.style.Fill');
|
goog.require('ol.style.Fill');
|
||||||
goog.require('ol.style.Stroke');
|
goog.require('ol.style.Stroke');
|
||||||
@@ -127,19 +126,19 @@ describe('ol.render.webgl.TextReplay', function() {
|
|||||||
var point;
|
var point;
|
||||||
|
|
||||||
point = [1000, 2000];
|
point = [1000, 2000];
|
||||||
replay.drawText(point, 0, 2, 2, null, null);
|
replay.drawText(new ol.geom.Point(point), null);
|
||||||
expect(replay.vertices).to.have.length(256);
|
expect(replay.vertices).to.have.length(256);
|
||||||
expect(replay.indices).to.have.length(48);
|
expect(replay.indices).to.have.length(48);
|
||||||
|
|
||||||
point = [2000, 3000];
|
point = [2000, 3000];
|
||||||
replay.drawText(point, 0, 2, 2, null, null);
|
replay.drawText(new ol.geom.Point(point), null);
|
||||||
expect(replay.vertices).to.have.length(512);
|
expect(replay.vertices).to.have.length(512);
|
||||||
expect(replay.indices).to.have.length(96);
|
expect(replay.indices).to.have.length(96);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets part of its state during drawing', function() {
|
it('sets part of its state during drawing', function() {
|
||||||
var point = [1000, 2000];
|
var point = [1000, 2000];
|
||||||
replay.drawText(point, 0, 2, 2, null, null);
|
replay.drawText(new ol.geom.Point(point), null);
|
||||||
|
|
||||||
var height = replay.currAtlas_.height;
|
var height = replay.currAtlas_.height;
|
||||||
var widths = replay.currAtlas_.width;
|
var widths = replay.currAtlas_.width;
|
||||||
@@ -163,7 +162,7 @@ describe('ol.render.webgl.TextReplay', function() {
|
|||||||
var point;
|
var point;
|
||||||
|
|
||||||
point = [1000, 2000];
|
point = [1000, 2000];
|
||||||
replay.drawText(point, 0, 2, 2, null, null);
|
replay.drawText(new ol.geom.Point(point), null);
|
||||||
expect(replay.vertices).to.have.length(0);
|
expect(replay.vertices).to.have.length(0);
|
||||||
expect(replay.indices).to.have.length(0);
|
expect(replay.indices).to.have.length(0);
|
||||||
});
|
});
|
||||||
|
|||||||