126 lines
3.9 KiB
JavaScript
126 lines
3.9 KiB
JavaScript
// NOCOMPILE
|
|
/* global labelgun */
|
|
goog.require('ol.Map');
|
|
goog.require('ol.View');
|
|
goog.require('ol.extent');
|
|
goog.require('ol.format.GeoJSON');
|
|
goog.require('ol.layer.Vector');
|
|
goog.require('ol.source.Vector');
|
|
goog.require('ol.style.Fill');
|
|
goog.require('ol.style.Stroke');
|
|
goog.require('ol.style.Style');
|
|
|
|
// Style for labels
|
|
function setStyle(context) {
|
|
context.font = '12px Calibri,sans-serif';
|
|
context.fillStyle = '#000';
|
|
context.strokeStyle = '#fff';
|
|
context.lineWidth = 3;
|
|
context.textBaseline = 'hanging';
|
|
context.textAlign = 'start';
|
|
}
|
|
|
|
// A separate canvas context for measuring label width and height.
|
|
var textMeasureContext = document.createElement('CANVAS').getContext('2d');
|
|
setStyle(textMeasureContext);
|
|
|
|
// The label height is approximated by the width of the text 'WI'.
|
|
var height = textMeasureContext.measureText('WI').width;
|
|
|
|
// A cache for reusing label images once they have been created.
|
|
var textCache = {};
|
|
|
|
var map = new ol.Map({
|
|
target: 'map',
|
|
view: new ol.View({
|
|
center: [0, 0],
|
|
zoom: 1
|
|
})
|
|
});
|
|
|
|
var emptyFn = function() {};
|
|
var labelEngine = new labelgun['default'](emptyFn, emptyFn);
|
|
|
|
function createLabel(canvas, text, coord) {
|
|
var halfWidth = canvas.width / 2;
|
|
var halfHeight = canvas.height / 2;
|
|
var bounds = {
|
|
bottomLeft: [Math.round(coord[0] - halfWidth), Math.round(coord[1] - halfHeight)],
|
|
topRight: [Math.round(coord[0] + halfWidth), Math.round(coord[1] + halfHeight)]
|
|
};
|
|
labelEngine.ingestLabel(bounds, coord.toString(), 1, canvas, text, false);
|
|
}
|
|
|
|
// For multi-polygons, we only label the widest polygon. This is done by sorting
|
|
// by extent width in descending order, and take the first from the array.
|
|
function sortByWidth(a, b) {
|
|
return ol.extent.getWidth(b.getExtent()) - ol.extent.getWidth(a.getExtent());
|
|
}
|
|
|
|
var labelStyle = new ol.style.Style({
|
|
renderer: function(coords, state) {
|
|
var text = state.feature.get('name');
|
|
createLabel(textCache[text], text, coords);
|
|
}
|
|
});
|
|
var countryStyle = new ol.style.Style({
|
|
fill: new ol.style.Fill({
|
|
color: 'rgba(255, 255, 255, 0.6)'
|
|
}),
|
|
stroke: new ol.style.Stroke({
|
|
color: '#319FD3',
|
|
width: 1
|
|
})
|
|
});
|
|
var styleWithLabel = [countryStyle, labelStyle];
|
|
var styleWithoutLabel = [countryStyle];
|
|
|
|
var pixelRatio; // This is set by the map's precompose listener
|
|
var vectorLayer = new ol.layer.Vector({
|
|
source: new ol.source.Vector({
|
|
url: 'data/geojson/countries.geojson',
|
|
format: new ol.format.GeoJSON()
|
|
}),
|
|
style: function(feature, resolution) {
|
|
var text = feature.get('name');
|
|
var width = textMeasureContext.measureText(text).width;
|
|
var geometry = feature.getGeometry();
|
|
if (geometry.getType() == 'MultiPolygon') {
|
|
geometry = geometry.getPolygons().sort(sortByWidth)[0];
|
|
}
|
|
var extentWidth = ol.extent.getWidth(geometry.getExtent());
|
|
if (extentWidth / resolution > width) {
|
|
// Only consider label when it fits its geometry's extent
|
|
if (!(text in textCache)) {
|
|
// Draw the label to its own canvas and cache it.
|
|
var canvas = textCache[text] = document.createElement('CANVAS');
|
|
canvas.width = width * pixelRatio;
|
|
canvas.height = height * pixelRatio;
|
|
var context = canvas.getContext('2d');
|
|
context.scale(pixelRatio, pixelRatio);
|
|
setStyle(context);
|
|
context.strokeText(text, 0, 0);
|
|
context.fillText(text, 0, 0);
|
|
}
|
|
labelStyle.setGeometry(geometry.getInteriorPoint());
|
|
return styleWithLabel;
|
|
} else {
|
|
return styleWithoutLabel;
|
|
}
|
|
}
|
|
});
|
|
vectorLayer.on('precompose', function(e) {
|
|
pixelRatio = e.frameState.pixelRatio;
|
|
labelEngine.destroy();
|
|
});
|
|
vectorLayer.on('postcompose', function(e) {
|
|
var labels = labelEngine.getShown();
|
|
for (var i = 0, ii = labels.length; i < ii; ++i) {
|
|
var label = labels[i];
|
|
// Draw label to the map canvas
|
|
e.context.drawImage(label.labelObject, label.minX, label.minY);
|
|
}
|
|
});
|
|
|
|
map.addLayer(vectorLayer);
|