Skip to content

Instantly share code, notes, and snippets.

@Hirosaji
Last active February 9, 2023 23:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hirosaji/04b37b81e05800f4531b8941da42eec1 to your computer and use it in GitHub Desktop.
Save Hirosaji/04b37b81e05800f4531b8941da42eec1 to your computer and use it in GitHub Desktop.
Mapbox - Extruding circles (simple)
Mapbox - Extruding circles (simple)
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src='https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.css' rel='stylesheet' />
<script src="https://cdn.jsdelivr.net/npm/@turf/turf@5/turf.min.js"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
<style>
#mapID { height: 700px; }
#position {
position:absolute; top: 0; height: 70px; width: 500px;
background-color: #fff;
padding: 30px;
margin: 10px;
font-family: 'Courier New', Courier, monospace;
}
h4 {
margin: 0 0 5px 0;
}
p {
margin: 0 0 5px 0;
}
</style>
</head>
<body>
<div id="mapID"></div>
<script src="map.js"></script>
<div id="position">
<h4>Visualize: Japanese towers with observation decks</h4>
<p>Let's touch the polygon, and check the tower info.</p>
<p style="color: grey;">(Other Ver. <a href="https://bl.ocks.org/hirosaji/868b7f86af4b1fce305c5963684f29e6">stacked</a>/<a href="https://bl.ocks.org/hirosaji/314f95dd4323eebb8ae2466faa5ca266">choropleth</a>/<a href="https://bl.ocks.org/hirosaji/adf6a4c8d1995c3b6276569dac760f78">gradient</a>)</p>
</body>
(function () {
"use strict";
mapboxgl.accessToken = 'pk.eyJ1IjoiaGlyb3NhamkiLCJhIjoiY2szOWlqZWNzMDJueTNjcWhyNjhqdXBnOSJ9._6mJT202QqpnMuK-jvMr3g';
const mapObj = new mapboxgl.Map({
container: 'mapID',
style: 'mapbox://styles/hirosaji/cklfggkyj4ytl17qhtxrp2qco',
center: [135.68380, 36.85676],
zoom: 5.2,
pitch: 60.00,
bearing: -17.60,
interactive: true
});
const loadFiles = [
d3.csv("tower_height.csv")
];
let hoveredTowerId;
Promise.all(loadFiles).then(function (csv) {
const geojson = {
"type": "FeatureCollection",
"features": csv[0].map(function(d) {
return {
type: "Feature",
properties: {
name: d.name,
full_value: parseFloat(d.full_height),
observatory_value: parseFloat(d.observatory_height)
},
geometry: {
type: "Point",
coordinates: [
parseFloat(d.lng),
parseFloat(d.lat)
]
}
}
})
}
const position = d3.select("#position");
mapObj.on('load', function() {
mapObj.addLayer({
'id': 'sky',
'type': 'sky',
'paint': {
'sky-type': 'atmosphere',
'sky-atmosphere-sun': [0.0, 0.0],
'sky-atmosphere-sun-intensity': 15
}
});
mapObj.addSource("data", {
type: "geojson",
data: geojson,
});
mapObj.addLayer({
'id': 'tower_points',
'type': 'circle',
'source': 'data',
'paint': {
'circle-opacity': 0
}
});
mapObj.addSource('extrusion_source', {
"type": "geojson",
"data": {
type: 'FeatureCollection',
features: []
}
});
mapObj.addLayer({
'id': 'extrusion',
'type': 'fill-extrusion',
'source': 'extrusion_source',
'paint': {
'fill-extrusion-color': [
'case',
['boolean', ['feature-state', 'hover'], false],
'red',
'blue'
],
'fill-extrusion-height': ['get', 'height'],
'fill-extrusion-base': ['get', 'base'],
'fill-extrusion-opacity': 0.6
}
});
function update() {
const qfs = mapObj.queryRenderedFeatures({
layers: ['tower_points']
});
const data = {
"type": "FeatureCollection",
"features": []
};
const radiusPX = 3;
qfs.forEach(function (object, i) {
const center = object.geometry.coordinates
let xy = mapObj.project(center);
xy.x += radiusPX;
let LL = mapObj.unproject(xy);
LL = turf.point([LL.lng, LL.lat]);
const radius = turf.distance(center, LL, {
units: 'meters'
}) + 0.00000001;
object.properties.height = object.properties.full_value * 600;
object.properties.base = 0;
object.properties.index = i;
const options = {
steps: 16,
units: 'meters',
properties: object.properties
};
const feature = turf.circle(center, radius, options);
feature.id = i;
data.features.push(feature);
})
mapObj.getSource('extrusion_source').setData(data);
}
mapObj.on('data', function(e) {
if (e.sourceId !== 'data') return
update()
})
})
mapObj.on('mousemove', 'extrusion', function(e) {
mapObj.getCanvasContainer().style.cursor = 'pointer';
if (hoveredTowerId) {
mapObj.setFeatureState(
{ source: 'extrusion_source', id: hoveredTowerId },
{ hover: false }
);
}
hoveredTowerId = e.features[0].id;
mapObj.setFeatureState(
{ source: 'extrusion_source', id: hoveredTowerId },
{ hover: true }
);
updatePosition(e.features[0].properties)
});
mapObj.on('mouseleave', 'extrusion', function() {
mapObj.getCanvasContainer().style.cursor = 'default';
mapObj.setFeatureState(
{ source: 'extrusion_source', id: hoveredTowerId },
{ hover: false }
);
hoveredTowerId = null;
});
const updatePosition = function(props) {
const info =
'<p>Name: ' + props.name + '</p>' +
'<p>Height of tower: ' + props.full_value + 'm</p>' +
'<p>Height of observatory: ' + props.observatory_value + 'm</p>';
position.html(info);
};
})
})();
name full_height observatory_height lat lng
東京スカイツリー 634 451.2 35.70998 139.810643
東京タワー 332.6 250 35.658617 139.745552
福岡タワー 234 123 33.593331 130.351525
名古屋テレビ塔 180 100 35.17155 136.907637
梅田スカイビル 173 170 34.705374 135.490524
ゴールドタワー 158 127 34.31177 133.808595
海峡ゆめタワー 153 143 33.95065 130.928888
さっぽろテレビ塔 147.2 90.38 43.061132 141.35639
秋田市ポートタワー 143 100 39.75176 140.061947
ツインアーチ138 138 100 35.357704 136.80906
東山スカイタワー 134 100 35.156694 136.97884
瀬戸大橋タワー 132 108 34.352083 133.825236
千葉ポートタワー 125 112 35.600432 140.097845
クロスランドタワー 118 100 36.656613 136.87863
神戸ポートタワー 108 90.8 34.684904 135.18552
五稜郭タワー 107 90 41.794766 140.754021
横浜マリンタワー 106 100 35.446179 139.635689
通天閣 103 91 34.651962 135.506152
別府タワー 90 55 33.281325 131.506216
銚子ポートタワー 57.5 46.95 35.740915 140.862859
東尋坊タワー 55 52 36.166928 136.231465
夢みなとタワー 43 37 35.519779 133.259184
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment