原文链接及内容

运行界面

本文将创建一个带有自定义格式的拖放交互组件,它可以用来处理KMZ文件。除了在拖放示例中曾经使用的格式外,这里还使用了一种自定义格式(子类化KML)来处理KMZ文件。必须从KMZ数组缓冲数据流同步提取KML和图标。这里使用了JSZip 2.x第三方库,它具有更好的浏览器兼容性,并且比最新的JSZip-sync代码更简单。但这里不支持投影变换,并且仅适用于EPSG:4326EPSG:3857中的数据。

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
140
141
142
143
144
import Map from 'ol/Map.js';
import View from 'ol/View.js';
import {
DragAndDrop,
defaults as defaultInteractions,
} from 'ol/interaction.js';
import {GPX, GeoJSON, IGC, KML, TopoJSON} from 'ol/format.js';
import {OSM, Vector as VectorSource} from 'ol/source.js';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer.js';

// Create functions to extract KML and icons from KMZ array buffer,
// which must be done synchronously.
const zip = new JSZip();

function getKMLData(buffer) {
let kmlData;
zip.load(buffer);
const kmlFile = zip.file(/\.kml$/i)[0];
if (kmlFile) {
kmlData = kmlFile.asText();
}
return kmlData;
}

function getKMLImage(href) {
const index = window.location.href.lastIndexOf('/');
if (index !== -1) {
const kmlFile = zip.file(href.slice(index + 1));
if (kmlFile) {
return URL.createObjectURL(new Blob([kmlFile.asArrayBuffer()]));
}
}
return href;
}

// Define a KMZ format class by subclassing ol/format/KML
class KMZ extends KML {
constructor(opt_options) {
const options = opt_options || {};
options.iconUrlFunction = getKMLImage;
super(options);
}

getType() {
return 'arraybuffer';
}

readFeature(source, options) {
const kmlData = getKMLData(source);
return super.readFeature(kmlData, options);
}

readFeatures(source, options) {
const kmlData = getKMLData(source);
return super.readFeatures(kmlData, options);
}
}

// Set up map with Drag and Drop interaction
const dragAndDropInteraction = new DragAndDrop({
formatConstructors: [KMZ, GPX, GeoJSON, IGC, KML, TopoJSON],
});

const map = new Map({
interactions: defaultInteractions().extend([dragAndDropInteraction]),
layers: [
new TileLayer({
source: new OSM(),
}),
],
target: 'map',
view: new View({
center: [0, 0],
zoom: 2,
}),
});

dragAndDropInteraction.on('addfeatures', function (event) {
const vectorSource = new VectorSource({
features: event.features,
});
map.addLayer(
new VectorLayer({
source: vectorSource,
})
);
map.getView().fit(vectorSource.getExtent());
});

const displayFeatureInfo = function (pixel) {
const features = [];
map.forEachFeatureAtPixel(pixel, function (feature) {
features.push(feature);
});
if (features.length > 0) {
const info = [];
let i, ii;
for (i = 0, ii = features.length; i < ii; ++i) {
const description =
features[i].get('description') ||
features[i].get('name') ||
features[i].get('_name') ||
features[i].get('layer');
if (description) {
info.push(description);
}
}
document.getElementById('info').innerHTML = info.join('<br/>') || '&nbsp';
} else {
document.getElementById('info').innerHTML = '&nbsp;';
}
};

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

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

// Sample data download
// 示例数据下载
const link = document.getElementById('download');

function download(fullpath, filename) {
fetch(fullpath)
.then(function (response) {
return response.blob();
})
.then(function (blob) {
link.href = URL.createObjectURL(blob);
link.download = filename;
link.click();
});
}

document.getElementById('download-kmz').addEventListener('click', function () {
download('data/kmz/iceland.kmz', 'iceland.kmz');
});

界面布局文件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
34
35
36
37
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Custom Drag-and-Drop (KMZ)</title>
<link rel="stylesheet" href="node_modules/ol/ol.css">
<style>
.map {
width: 100%;
height: 400px;
}
#info {
width: 100%;
height: 24rem;
overflow: scroll;
display: flex;
align-items: baseline;
border: 1px solid black;
justify-content: flex-start;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<br />
<div>
<a id="download" download></a>
<button id="download-kmz">Download sample</button>
</div>
<br />
<div id="info">&nbsp;</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://cdnjs.cloudflare.com/ajax/libs/jszip/2.6.1/jszip.min.js"></script>
<script type="module" src="main.js"></script>
</body>
</html>