UNPKG

3.96 kBJavaScriptView Raw
1// NOCOMPILE
2/* global labelgun */
3goog.require('ol.Map');
4goog.require('ol.View');
5goog.require('ol.extent');
6goog.require('ol.format.GeoJSON');
7goog.require('ol.layer.Vector');
8goog.require('ol.source.Vector');
9goog.require('ol.style.Fill');
10goog.require('ol.style.Stroke');
11goog.require('ol.style.Style');
12
13// Style for labels
14function setStyle(context) {
15 context.font = '12px Calibri,sans-serif';
16 context.fillStyle = '#000';
17 context.strokeStyle = '#fff';
18 context.lineWidth = 3;
19 context.textBaseline = 'hanging';
20 context.textAlign = 'start';
21}
22
23// A separate canvas context for measuring label width and height.
24var textMeasureContext = document.createElement('CANVAS').getContext('2d');
25setStyle(textMeasureContext);
26
27// The label height is approximated by the width of the text 'WI'.
28var height = textMeasureContext.measureText('WI').width;
29
30// A cache for reusing label images once they have been created.
31var textCache = {};
32
33var map = new ol.Map({
34 target: 'map',
35 view: new ol.View({
36 center: [0, 0],
37 zoom: 1
38 })
39});
40
41var emptyFn = function() {};
42var labelEngine = new labelgun['default'](emptyFn, emptyFn);
43
44function createLabel(canvas, text, coord) {
45 var halfWidth = canvas.width / 2;
46 var halfHeight = canvas.height / 2;
47 var bounds = {
48 bottomLeft: [Math.round(coord[0] - halfWidth), Math.round(coord[1] - halfHeight)],
49 topRight: [Math.round(coord[0] + halfWidth), Math.round(coord[1] + halfHeight)]
50 };
51 labelEngine.ingestLabel(bounds, coord.toString(), 1, canvas, text, false);
52}
53
54// For multi-polygons, we only label the widest polygon. This is done by sorting
55// by extent width in descending order, and take the first from the array.
56function sortByWidth(a, b) {
57 return ol.extent.getWidth(b.getExtent()) - ol.extent.getWidth(a.getExtent());
58}
59
60var labelStyle = new ol.style.Style({
61 renderer: function(coords, state) {
62 var text = state.feature.get('name');
63 createLabel(textCache[text], text, coords);
64 }
65});
66var countryStyle = new ol.style.Style({
67 fill: new ol.style.Fill({
68 color: 'rgba(255, 255, 255, 0.6)'
69 }),
70 stroke: new ol.style.Stroke({
71 color: '#319FD3',
72 width: 1
73 })
74});
75var styleWithLabel = [countryStyle, labelStyle];
76var styleWithoutLabel = [countryStyle];
77
78var pixelRatio; // This is set by the map's precompose listener
79var vectorLayer = new ol.layer.Vector({
80 source: new ol.source.Vector({
81 url: 'data/geojson/countries.geojson',
82 format: new ol.format.GeoJSON()
83 }),
84 style: function(feature, resolution) {
85 var text = feature.get('name');
86 var width = textMeasureContext.measureText(text).width;
87 var geometry = feature.getGeometry();
88 if (geometry.getType() == 'MultiPolygon') {
89 geometry = geometry.getPolygons().sort(sortByWidth)[0];
90 }
91 var extentWidth = ol.extent.getWidth(geometry.getExtent());
92 if (extentWidth / resolution > width) {
93 // Only consider label when it fits its geometry's extent
94 if (!(text in textCache)) {
95 // Draw the label to its own canvas and cache it.
96 var canvas = textCache[text] = document.createElement('CANVAS');
97 canvas.width = width * pixelRatio;
98 canvas.height = height * pixelRatio;
99 var context = canvas.getContext('2d');
100 context.scale(pixelRatio, pixelRatio);
101 setStyle(context);
102 context.strokeText(text, 0, 0);
103 context.fillText(text, 0, 0);
104 }
105 labelStyle.setGeometry(geometry.getInteriorPoint());
106 return styleWithLabel;
107 } else {
108 return styleWithoutLabel;
109 }
110 }
111});
112vectorLayer.on('precompose', function(e) {
113 pixelRatio = e.frameState.pixelRatio;
114 labelEngine.destroy();
115});
116vectorLayer.on('postcompose', function(e) {
117 var labels = labelEngine.getShown();
118 for (var i = 0, ii = labels.length; i < ii; ++i) {
119 var label = labels[i];
120 // Draw label to the map canvas
121 e.context.drawImage(label.labelObject, label.minX, label.minY);
122 }
123});
124
125map.addLayer(vectorLayer);