# 三.地震标记
# 1.地震图
解析 KML 文件并将要素呈现为矢量图层。给定图层 a style 以相对于震级的大小来渲染地震位置。
查看代码详情
<template>
<div ref="map" class="map"><div id="info"></div></div>
</template>
<script>
let {
Map,
View,
layer: { Tile: TileLayer, Vector: VectorLayer },
source: { Stamen, Vector: VectorSource },
style: { Circle: CircleStyle, Fill, Stroke, Style },
format: { KML },
} = ol;
export default {
mounted() {
const styleCache = {};
const styleFunction = function (feature) {
const name = feature.get("name");
const magnitude = parseFloat(name.substr(2));
const radius = 5 + 20 * (magnitude - 5);
let style = styleCache[radius];
if (!style) {
style = new Style({
image: new CircleStyle({
radius: radius,
fill: new Fill({
color: "rgba(255, 153, 0, 0.4)",
}),
stroke: new Stroke({
color: "rgba(255, 204, 0, 0.2)",
width: 1,
}),
}),
});
styleCache[radius] = style;
}
return style;
};
const map = new Map({
layers: [
new TileLayer({
source: new Stamen({
layer: "toner",
}),
}),
new VectorLayer({
source: new VectorSource({
url: this.$withBase("/data/kml/2012_Earthquakes_Mag5.kml"),
format: new KML({
extractStyles: false,
}),
}),
style: styleFunction,
}),
],
target: this.$refs.map,
view: new View({
center: [12579156, 3274244],
zoom: 2,
}),
});
// const info = $("#info");
// info.tooltip({
// animation: false,
// trigger: "manual",
// });
// const displayFeatureInfo = function (pixel) {
// info.css({
// left: pixel[0] + "px",
// top: pixel[1] - 15 + "px",
// });
// const feature = map.forEachFeatureAtPixel(pixel, function (feature) {
// return feature;
// });
// if (feature) {
// info.attr("data-original-title", feature.get("name")).tooltip("show");
// } else {
// info.tooltip("hide");
// }
// };
// map.on("pointermove", function (evt) {
// if (evt.dragging) {
// info.tooltip("hide");
// return;
// }
// displayFeatureInfo(map.getEventPixel(evt.originalEvent));
// });
// map.on("click", function (evt) {
// displayFeatureInfo(evt.pixel);
// });
},
};
</script>
<style></style>
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
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
# 2.自定义地震图
使用 toContext
创建自定义图标符号
查看代码详情
<template>
<div ref="map" class="map"></div>
</template>
<script>
let {
format: { KML },
geom: { Polygon },
Map,
View,
layer: { Tile: TileLayer, Vector: VectorLayer },
source: { Stamen, Vector: VectorSource },
style: { Fill, Icon, Stroke, Style },
render: { toContext },
} = ol;
export default {
mounted() {
const symbol = [
[0, 0],
[4, 2],
[6, 0],
[10, 5],
[6, 3],
[4, 5],
[0, 0],
];
let scale;
const scaleFunction = function (coordinate) {
return [coordinate[0] * scale, coordinate[1] * scale];
};
const styleCache = {};
const map = new Map({
layers: [
new TileLayer({
source: new Stamen({
layer: "toner",
}),
}),
new VectorLayer({
source: new VectorSource({
url: this.$withBase("/data/kml/2012_Earthquakes_Mag5.kml"),
format: new KML({
extractStyles: false,
}),
}),
style: function (feature) {
const name = feature.get("name");
const magnitude = parseFloat(name.substr(2));
const size = parseInt(10 + 40 * (magnitude - 5), 10);
scale = size / 10;
let style = styleCache[size];
if (!style) {
const canvas = document.createElement("canvas");
const vectorContext = toContext(canvas.getContext("2d"), {
size: [size, size],
pixelRatio: 1,
});
vectorContext.setStyle(
new Style({
fill: new Fill({ color: "rgba(255, 153, 0, 0.4)" }),
stroke: new Stroke({
color: "rgba(255, 204, 0, 0.2)",
width: 2,
}),
})
);
vectorContext.drawGeometry(
new Polygon([symbol.map(scaleFunction)])
);
style = new Style({
image: new Icon({
img: canvas,
imgSize: [size, size],
rotation: 1.2,
}),
});
styleCache[size] = style;
}
return style;
},
}),
],
target: this.$refs.map,
view: new View({
center: [12579156, 3274244],
zoom: 2,
}),
});
},
};
</script>
<style></style>
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
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
# 3.地震群
查看代码详情
<template>
<div ref="map" class="map"></div>
</template>
<script>
let {
interaction: { Select, defaults: defaultInteractions },
Map,
View,
layer: { Tile: TileLayer, Vector: VectorLayer },
source: { Cluster, Stamen, Vector: VectorSource },
style: { Circle: CircleStyle, Fill, RegularShape, Stroke, Style, Text },
format: { KML },
extent: { createEmpty, extend, getHeight, getWidth },
} = ol;
export default {
mounted() {
const earthquakeFill = new Fill({
color: "rgba(255, 153, 0, 0.8)",
});
const earthquakeStroke = new Stroke({
color: "rgba(255, 204, 0, 0.2)",
width: 1,
});
const textFill = new Fill({
color: "#fff",
});
const textStroke = new Stroke({
color: "rgba(0, 0, 0, 0.6)",
width: 3,
});
const invisibleFill = new Fill({
color: "rgba(255, 255, 255, 0.01)",
});
function createEarthquakeStyle(feature) {
const name = feature.get("name");
const magnitude = parseFloat(name.substr(2));
const radius = 5 + 20 * (magnitude - 5);
return new Style({
geometry: feature.getGeometry(),
image: new RegularShape({
radius1: radius,
radius2: 3,
points: 5,
angle: Math.PI,
fill: earthquakeFill,
stroke: earthquakeStroke,
}),
});
}
let maxFeatureCount;
let vector = null;
const calculateClusterInfo = function (resolution) {
maxFeatureCount = 0;
const features = vector.getSource().getFeatures();
let feature, radius;
for (let i = features.length - 1; i >= 0; --i) {
feature = features[i];
const originalFeatures = feature.get("features");
const extent = createEmpty();
let j, jj;
for (j = 0, jj = originalFeatures.length; j < jj; ++j) {
extend(extent, originalFeatures[j].getGeometry().getExtent());
}
maxFeatureCount = Math.max(maxFeatureCount, jj);
radius = (0.25 * (getWidth(extent) + getHeight(extent))) / resolution;
feature.set("radius", radius);
}
};
let currentResolution;
function styleFunction(feature, resolution) {
if (resolution != currentResolution) {
calculateClusterInfo(resolution);
currentResolution = resolution;
}
let style;
const size = feature.get("features").length;
if (size > 1) {
style = new Style({
image: new CircleStyle({
radius: feature.get("radius"),
fill: new Fill({
color: [255, 153, 0, Math.min(0.8, 0.4 + size / maxFeatureCount)],
}),
}),
text: new Text({
text: size.toString(),
fill: textFill,
stroke: textStroke,
}),
});
} else {
const originalFeature = feature.get("features")[0];
style = createEarthquakeStyle(originalFeature);
}
return style;
}
function selectStyleFunction(feature) {
const styles = [
new Style({
image: new CircleStyle({
radius: feature.get("radius"),
fill: invisibleFill,
}),
}),
];
const originalFeatures = feature.get("features");
let originalFeature;
for (let i = originalFeatures.length - 1; i >= 0; --i) {
originalFeature = originalFeatures[i];
styles.push(createEarthquakeStyle(originalFeature));
}
return styles;
}
vector = new VectorLayer({
source: new Cluster({
distance: 40,
source: new VectorSource({
url: this.$withBase("/data/kml/2012_Earthquakes_Mag5.kml"),
format: new KML({
extractStyles: false,
}),
}),
}),
style: styleFunction,
});
const raster = new TileLayer({
source: new Stamen({
layer: "toner",
}),
});
const map = new Map({
layers: [raster, vector],
interactions: defaultInteractions().extend([
new Select({
condition: function (evt) {
return evt.type == "pointermove" || evt.type == "singleclick";
},
style: selectStyleFunction,
}),
]),
target: this.$refs.map,
view: new View({
center: [12579156, 3274244],
zoom: 2,
}),
});
},
};
</script>
<style></style>
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# 4.地震热图
查看代码详情
<template>
<div ref="map" class="map"></div>
</template>
<script>
let {
Map,
View,
layer: { Tile: TileLayer, Heatmap: HeatmapLayer },
source: { Stamen, Vector: VectorSource },
format: { KML },
} = ol;
export default {
mounted() {
const blur = document.getElementById("blur");
const radius = document.getElementById("radius");
const vector = new HeatmapLayer({
source: new VectorSource({
url: this.$withBase("/data/kml/2012_Earthquakes_Mag5.kml"),
format: new KML({
extractStyles: false,
}),
}),
blur: parseInt(blur.value, 10),
radius: parseInt(radius.value, 10),
weight: function (feature) {
const name = feature.get("name");
const magnitude = parseFloat(name.substr(2));
return magnitude - 5;
},
});
new Map({
layers: [
new TileLayer({
source: new Stamen({
layer: "toner",
}),
}),
vector,
],
target: this.$refs.map,
view: new View({
center: [12579156, 3274244],
zoom: 2,
}),
});
const blurHandler = function () {
vector.setBlur(parseInt(blur.value, 10));
};
blur.addEventListener("input", blurHandler);
blur.addEventListener("change", blurHandler);
const radiusHandler = function () {
vector.setRadius(parseInt(radius.value, 10));
};
radius.addEventListener("input", radiusHandler);
radius.addEventListener("change", radiusHandler);
},
};
</script>
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
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