資料層叢集圖
此範例示範如何操作資料層叢集圖,包含以下功能:
- 啟用叢集樣式:透過
map.data.enableCluster()啟用叢集圖,並設定叢集半徑與樣式 - 新增初始資料點:於
style.load後新增初始叢集點與非叢集點 - 按鈕控制:使用按鈕控制新增/清除/顯示叢集點與非叢集點功能
info
詳細使用參數說明請參考「資料層叢集」。
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>資料層叢集圖</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://kw3dmap.localking.com.tw/openapi/loader/mapPlus-1.3.9.loader.js" crossorigin="anonymous" referrerpolicy="origin"></script>
<!-- Bootstrap CDN -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css"
/>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm"
crossorigin="anonymous"
></script>
<style>
body { margin: 0; padding: 0; }
#map { width: 100vw; height: 100vh; }
#toolbar {
position: absolute;
top: 16px;
right: 16px;
width: fit-content;
z-index: 10;
}
</style>
</head>
<body>
<div id="map"></div>
<aside id="toolbar" class="d-flex flex-column align-items-center gap-3 bg-white p-2 pb-3 rounded-2 shadow">
<div class="pb-2 border-bottom border-secondary-subtle">
<img
src="https://kw3dmap.autoking.com.tw/kingway-logo.png"
alt="Kingway map"
width="44"
height="44"
/>
</div>
<div class="btn-group-vertical" role="group">
<input type="checkbox" class="btn-check" id="btnAddCluster" autocomplete="off" />
<label
class="btn btn-outline-primary"
for="btnAddCluster"
data-bs-toggle="tooltip"
data-bs-placement="left"
data-bs-title="新增叢集點"
>
<i class="bi bi-plus-circle-fill"></i>
</label>
<input type="checkbox" class="btn-check" id="btnAddNonCluster" autocomplete="off" />
<label
class="btn btn-outline-primary"
for="btnAddNonCluster"
data-bs-toggle="tooltip"
data-bs-placement="left"
data-bs-title="新增非叢集點"
>
<i class="bi bi-plus-circle"></i>
</label>
<input type="checkbox" class="btn-check" id="btnClearCluster" autocomplete="off" />
<label
class="btn btn-outline-primary"
for="btnClearCluster"
data-bs-toggle="tooltip"
data-bs-placement="left"
data-bs-title="清除叢集點"
>
<i class="bi bi-trash-fill"></i>
</label>
<input type="checkbox" class="btn-check" id="btnClearNonCluster" autocomplete="off" />
<label
class="btn btn-outline-primary"
for="btnClearNonCluster"
data-bs-toggle="tooltip"
data-bs-placement="left"
data-bs-title="清除非叢集點"
>
<i class="bi bi-trash"></i>
</label>
</div>
<div class="btn-group-vertical" role="group">
<input type="checkbox" class="btn-check" id="switchCluster" autocomplete="off" checked />
<label
class="btn btn-outline-primary"
for="switchCluster"
data-bs-toggle="tooltip"
data-bs-placement="left"
data-bs-title="顯示叢集點"
>
<i class="bi bi-geo-alt-fill"></i>
</label>
<input type="checkbox" class="btn-check" id="switchNonCluster" autocomplete="off" checked />
<label
class="btn btn-outline-primary"
for="switchNonCluster"
data-bs-toggle="tooltip"
data-bs-placement="left"
data-bs-title="顯示非叢集點"
>
<i class="bi bi-geo-alt"></i>
</label>
</div>
</aside>
<script type="module">
const map = await new mapPlus(document.getElementById("map"), {
accessKey: 'get_your_key',
accessToken: 'get_your_token',
style: 'https://kw3dmap.localking.com.tw/openapi/map/kwmap.etxt',
center: [121.53559860212545, 25.028808142529132],
zoom: 11,
});
// Bootstrap 提示訊息 初始化
const tooltipList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
[...tooltipList].map((tooltip) => new bootstrap.Tooltip(tooltip));
let pointCount = 0;
const randomInRange = (base, span) => base + Math.random() * span;
const createPointFeature = (prefix, addToCluster) => {
pointCount += 1;
return {
geometry: new mapPlus.Data.Point({
lng: randomInRange(121.4, 0.3),
lat: randomInRange(24.9, 0.2),
}),
properties: {
id: prefix + "_" + pointCount,
name: (addToCluster ? "叢集點" : "非叢集點") + pointCount,
description: "第 " + pointCount + " 個資料點",
addToCluster, // 當 addToCluster 為 true 則為叢集點,false 則為非叢集點
},
};
};
/* ══════════════════════════════════════════════════════════════════════════
* 啟用叢集樣式:
- 調整 radius 可設置叢集半徑。
- 調整 maxZoom 可設置停止叢集化的最大縮放級別。
- 調整 styles 可自訂叢集圖的樣式(可分別調整叢集圓圈/文字/點樣式)
══════════════════════════════════════════════════════════════════════════ */
// 啟用叢集圖
map.data.enableCluster(true, {
// 叢集半徑
radius: 50,
// 叢集圖層會停止叢集化的最大縮放級別
maxZoom: 14,
// 自訂叢集圖的樣式
styles: {
// 叢集圓圈樣式
circle: {
// 叢集圓圈的顏色陣列
colors: ["#ff6b6b", "#45b7d1", "#3498db"],
// 叢集圓圈的大小陣列
sizes: [25, 35, 45],
// 叢集圓圈的透明度
opacity: 0.9,
// 叢集圓圈外框顏色
// strokeColor: "#000000",
// 叢集圓圈外框寬度
// strokeWidth: 4,
},
// 叢集圓圈文字樣式
text: {
// 叢集圓圈文字顏色
color: "#FFFFFF",
// 叢集圓圈文字大小
size: 14,
// 叢集圓圈文字字體
font: ["Noto Sans Regular"],
},
// 叢集點樣式
point: {
// 叢集點的顏色
color: "#ff6b6b",
// 叢集點的大小
size: 6,
// 叢集點的外框顏色
// strokeColor: "#000000",
// 叢集點的外框寬度
// strokeWidth: 4
},
// 非叢集點樣式
nonCluster: {
// 非叢集點的顏色
color: "#4ecdc4",
// 非叢集點的大小
size: 6,
// 非叢集點的外框顏色
// strokeColor: "#000000",
// 非叢集點的外框寬度
// strokeWidth: 4
},
},
});
// 新增初始資料點
const addPoints = (count, addToCluster, prefix) => {
for (let i = 0; i < count; i += 1) {
map.data.add(createPointFeature(prefix, addToCluster));
}
};
map.on("style.load", () => {
addPoints(50, true, "cluster");
addPoints(20, false, "non_cluster");
});
const clearPointsByClusterType = (target) => {
map.data.setStyle((fea) => {
const flag = !!fea.getProperty("addToCluster");
if (flag === target) map.data.removeFeature(fea);
});
};
// 使用按鈕控制新增/清除/顯示叢集點與非叢集點功能
document.getElementById("btnAddCluster").addEventListener("change", ({ target }) => {
// 新增叢集點
addPoints(30, true, "cluster");
target.checked = false;
});
document.getElementById("btnAddNonCluster").addEventListener("change", ({ target }) => {
// 新增非叢集點
addPoints(30, false, "non_cluster");
target.checked = false;
});
document.getElementById("btnClearCluster").addEventListener("change", ({ target }) => {
// 清除叢集點
clearPointsByClusterType(true);
target.checked = false;
});
document.getElementById("btnClearNonCluster").addEventListener("change", ({ target }) => {
// 清除非叢集點
clearPointsByClusterType(false);
target.checked = false;
});
document.getElementById("switchCluster").addEventListener("change", ({ target }) => {
// 顯示或隱藏叢集點
map.data.toggleClusterPoints(target.checked);
});
document.getElementById("switchNonCluster").addEventListener("change", ({ target }) => {
// 顯示或隱藏非叢集點
map.data.toggleNonClusterPoints(target.checked);
});
</script>
</body>
</html>
<script src="https://kw3dmap.localking.com.tw/openapi/loader/mapPlus-1.3.9.loader.js" crossorigin="anonymous" referrerpolicy="origin"></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm"
crossorigin="anonymous"
></script>
<script type="module">
const map = await new mapPlus(document.getElementById("map"), {
accessKey: 'get_your_key',
accessToken: 'get_your_token',
style: 'https://kw3dmap.localking.com.tw/openapi/map/kwmap.etxt',
center: [121.53559860212545, 25.028808142529132],
zoom: 11,
});
// Bootstrap 提示訊息 初始化
const tooltipList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
[...tooltipList].map((tooltip) => new bootstrap.Tooltip(tooltip));
let pointCount = 0;
const randomInRange = (base, span) => base + Math.random() * span;
const createPointFeature = (prefix, addToCluster) => {
pointCount += 1;
return {
geometry: new mapPlus.Data.Point({
lng: randomInRange(121.4, 0.3),
lat: randomInRange(24.9, 0.2),
}),
properties: {
id: prefix + "_" + pointCount,
name: (addToCluster ? "叢集點" : "非叢集點") + pointCount,
description: "第 " + pointCount + " 個資料點",
addToCluster, // 當 addToCluster 為 true 則為叢集點,false 則為非叢集點
},
};
};
/* ══════════════════════════════════════════════════════════════════════════
* 啟用叢集樣式:
- 調整 radius 可設置叢集半徑。
- 調整 maxZoom 可設置停止叢集化的最大縮放級別。
- 調整 styles 可自訂叢集圖的樣式(可分別調整叢集圓圈/文字/點樣式)
══════════════════════════════════════════════════════════════════════════ */
// 啟用叢集圖
map.data.enableCluster(true, {
// 叢集半徑
radius: 50,
// 叢集圖層會停止叢集化的最大縮放級別
maxZoom: 14,
// 自訂叢集圖的樣式
styles: {
// 叢集圓圈樣式
circle: {
// 叢集圓圈的顏色陣列
colors: ["#ff6b6b", "#45b7d1", "#3498db"],
// 叢集圓圈的大小陣列
sizes: [25, 35, 45],
// 叢集圓圈的透明度
opacity: 0.9,
// 叢集圓圈外框顏色
// strokeColor: "#000000",
// 叢集圓圈外框寬度
// strokeWidth: 4,
},
// 叢集圓圈文字樣式
text: {
// 叢集圓圈文字顏色
color: "#FFFFFF",
// 叢集圓圈文字大小
size: 14,
// 叢集圓圈文字字體
font: ["Noto Sans Regular"],
},
// 叢集點樣式
point: {
// 叢集點的顏色
color: "#ff6b6b",
// 叢集點的大小
size: 6,
// 叢集點的外框顏色
// strokeColor: "#000000",
// 叢集點的外框寬度
// strokeWidth: 4
},
// 非叢集點樣式
nonCluster: {
// 非叢集點的顏色
color: "#4ecdc4",
// 非叢集點的大小
size: 6,
// 非叢集點的外框顏色
// strokeColor: "#000000",
// 非叢集點的外框寬度
// strokeWidth: 4
},
},
});
// 新增初始資料點
const addPoints = (count, addToCluster, prefix) => {
for (let i = 0; i < count; i += 1) {
map.data.add(createPointFeature(prefix, addToCluster));
}
};
map.on("style.load", () => {
addPoints(50, true, "cluster");
addPoints(20, false, "non_cluster");
});
const clearPointsByClusterType = (target) => {
map.data.setStyle((fea) => {
const flag = !!fea.getProperty("addToCluster");
if (flag === target) map.data.removeFeature(fea);
});
};
// 使用按鈕控制新增/清除/顯示叢集點與非叢集點功能
document.getElementById("btnAddCluster").addEventListener("change", ({ target }) => {
// 新增叢集點
addPoints(30, true, "cluster");
target.checked = false;
});
document.getElementById("btnAddNonCluster").addEventListener("change", ({ target }) => {
// 新增非叢集點
addPoints(30, false, "non_cluster");
target.checked = false;
});
document.getElementById("btnClearCluster").addEventListener("change", ({ target }) => {
// 清除叢集點
clearPointsByClusterType(true);
target.checked = false;
});
document.getElementById("btnClearNonCluster").addEventListener("change", ({ target }) => {
// 清除非叢集點
clearPointsByClusterType(false);
target.checked = false;
});
document.getElementById("switchCluster").addEventListener("change", ({ target }) => {
// 顯示或隱藏叢集點
map.data.toggleClusterPoints(target.checked);
});
document.getElementById("switchNonCluster").addEventListener("change", ({ target }) => {
// 顯示或隱藏非叢集點
map.data.toggleNonClusterPoints(target.checked);
});
</script>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css"
/>
<style>
body { margin: 0; padding: 0; }
#map { width: 100vw; height: 100vh; }
#toolbar {
position: absolute;
top: 16px;
right: 16px;
width: fit-content;
z-index: 10;
}
</style>