原文链接及内容

运行界面

本例解析KML文件并将要素渲染为矢量图层。该层被赋予一个样式(ol/style/Style),该样式将时区填充为黄色,而颜色的透明度是基于当前时间到当地中午的偏移量计算的。

main.js代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import KML from 'ol/format/KML.js';
import Map from 'ol/Map.js';
import Stamen from 'ol/source/Stamen.js';
import VectorSource from 'ol/source/Vector.js';
import View from 'ol/View.js';
import {Fill, Stroke, Style} from 'ol/style.js';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer.js';

/*
* Compute the style of the feature. Here we want the opacity of polygons to
* be based on the offset from local noon. For example, a timezone where it is
* currently noon would have an opacity of 0.75. And a timezone where it is
* currently midnight would have an opacity of 0. This doesn't account for
* daylight savings, so don't use it to plan your vacation.
* 计算要素的样式,在这里,我们希望多边形的不透明度基于当前时间到当地中午的偏移量。
* 例如,当前处于正午的时区的不透明度为0.75,而当前处于午夜的时区的不透明度为0。
* 这并不包括夏令时,所以不要用它来计划你的假期。
*/
const styleFunction = function (feature) {
const tzOffset = feature.get('tz-offset');
const local = new Date();
local.setTime(
local.getTime() + (local.getTimezoneOffset() + (tzOffset || 0)) * 60000
);
// offset from local noon (in hours)
let delta = Math.abs(12 - (local.getHours() + local.getMinutes() / 60));
if (delta > 12) {
delta = 24 - delta;
}
const opacity = 0.75 * (1 - delta / 12);
return new Style({
fill: new Fill({
color: [0xff, 0xff, 0x33, opacity],
}),
stroke: new Stroke({
color: '#ffffff',
}),
});
};

const vector = new VectorLayer({
source: new VectorSource({
url: 'data/kml/timezones.kml',
format: new KML({
extractStyles: false,
}),
}),
style: styleFunction,
});

/**
* @param {string} name e.g. GMT -08:30
* @return {number|null} The offset from UTC in minutes
*/
function parseOffsetFromUtc(name) {
const match = name.match(/([+-]?)(\d{2}):(\d{2})$/);
if (!match) {
return null;
}
const sign = match[1] === '-' ? -1 : 1;
const hours = Number(match[2]);
const minutes = Number(match[3]);
return sign * (60 * hours + minutes);
}

vector.getSource().on('featuresloadend', function (evt) {
evt.features.forEach(function (feature) {
const tzOffset = parseOffsetFromUtc(feature.get('name'));
feature.set('tz-offset', tzOffset, true);
});
});

const raster = new TileLayer({
source: new Stamen({
layer: 'toner',
}),
});

const map = new Map({
layers: [raster, vector],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2,
}),
});

const info = document.getElementById('info');
info.style.pointerEvents = 'none';
const tooltip = new bootstrap.Tooltip(info, {
animation: false,
customClass: 'pe-none',
offset: [0, 5],
title: '-',
trigger: 'manual',
});

let currentFeature;
const displayFeatureInfo = function (pixel, target) {
const feature = target.closest('.ol-control')
? undefined
: map.forEachFeatureAtPixel(pixel, function (feature) {
return feature;
});
if (feature) {
info.style.left = pixel[0] + 'px';
info.style.top = pixel[1] + 'px';
if (feature !== currentFeature) {
tooltip.setContent({'.tooltip-inner': feature.get('name')});
}
if (currentFeature) {
tooltip.update();
} else {
tooltip.show();
}
} else {
tooltip.hide();
}
currentFeature = feature;
};

map.on('pointermove', function (evt) {
if (evt.dragging) {
tooltip.hide();
currentFeature = undefined;
return;
}
const pixel = map.getEventPixel(evt.originalEvent);
displayFeatureInfo(pixel, evt.originalEvent.target);
});

map.on('click', function (evt) {
displayFeatureInfo(evt.pixel, evt.originalEvent.target);
});

map.getTargetElement().addEventListener('pointerleave', function () {
tooltip.hide();
currentFeature = undefined;
});

界面布局文件index.html代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Timezones in KML</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="node_modules/ol/ol.css">
<style>
.map {
width: 100%;
height: 400px;
}
#map {
position: relative;
}
#info {
position: absolute;
height: 1px;
width: 1px;
z-index: 100;
}
</style>
</head>
<body>
<div id="map" class="map">
<div id="info"></div>
</div>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://cdn.jsdelivr.net/npm/elm-pep@1.0.6/dist/elm-pep.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"></script>
<script type="module" src="main.js"></script>
</body>
</html>