Add breaking changes and gencode
This commit is contained in:
@@ -92,10 +92,23 @@
|
||||
.attr("fill", "black")
|
||||
.attr("color", "white");*/
|
||||
|
||||
lablels = getMarkerLabels(data);
|
||||
|
||||
// Call the update function
|
||||
update();
|
||||
|
||||
// Update on map interaction
|
||||
map.on("viewreset", update);
|
||||
map.on("move", update);
|
||||
map.on("moveend", update);
|
||||
}
|
||||
|
||||
function getMarkerLabels(data){
|
||||
// Add labels with background
|
||||
const maxWidth = 100;
|
||||
|
||||
labels = svg.selectAll("g.label")
|
||||
console.log("In markerlabels");
|
||||
const markerLabels = svg.selectAll("g.label")
|
||||
.data(data.features)
|
||||
.enter()
|
||||
.append("g")
|
||||
@@ -166,14 +179,9 @@
|
||||
g.attr("data-bbox-height", bbox.height);
|
||||
});
|
||||
|
||||
|
||||
// Call the update function
|
||||
update();
|
||||
|
||||
// Update on map interaction
|
||||
map.on("viewreset", update);
|
||||
map.on("move", update);
|
||||
map.on("moveend", update);
|
||||
console.log("EIT");
|
||||
console.log(markerLabels);
|
||||
return markerLabels;
|
||||
}
|
||||
|
||||
// Update d3 shapes' positions to the map's current state
|
||||
@@ -196,15 +204,81 @@
|
||||
//console.log(map.getZoom());
|
||||
|
||||
const labelNodes = labels.nodes();
|
||||
const mergedGroups = [];
|
||||
|
||||
for(let i = 0; i < labelNodes.length; i++){
|
||||
for(let j = i + 1; j < labelNodes.length; j++){
|
||||
if(isOverlapping(labelNodes[i], labelNodes[j])){
|
||||
console.log("OVERLAAAPPPP!!!");
|
||||
|
||||
console.log(labelNodes[i]);
|
||||
console.log(labelNodes[j]);
|
||||
const a = labelNodes[i];
|
||||
let groupFound = false;
|
||||
|
||||
for (let group of mergedGroups) {
|
||||
for (let j = 0; j < group.length; j++) {
|
||||
if (isOverlapping(a, group[j])) {
|
||||
console.log(a);
|
||||
group.push(a);
|
||||
groupFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (groupFound) break;
|
||||
}
|
||||
|
||||
if (!groupFound) {
|
||||
mergedGroups.push([a]);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Merge labels in overlapping groups
|
||||
for (const group of mergedGroups) {
|
||||
if (group.length === 1) continue;
|
||||
|
||||
// Gather merged text and coordinates
|
||||
const names = group.map(el => el.querySelector("text").getAttribute("feature-name"));
|
||||
const coords = group.map(el => {
|
||||
const transform = el.getAttribute("transform");
|
||||
const match = /translate\(([^,]+),\s*([^)]+)\)/.exec(transform);
|
||||
return { x: +match[1], y: +match[2] };
|
||||
});
|
||||
|
||||
// Average position
|
||||
const avgX = coords.reduce((sum, c) => sum + c.x, 0) / coords.length;
|
||||
const avgY = coords.reduce((sum, c) => sum + c.y, 0) / coords.length;
|
||||
|
||||
// Keep only the first label, update its text
|
||||
const main = group[0];
|
||||
const textEl = main.querySelector("text");
|
||||
|
||||
// Clear previous tspans or text
|
||||
textEl.innerHTML = "";
|
||||
|
||||
// Create a new <tspan> per name, each on a new line
|
||||
names.forEach((name, i) => {
|
||||
const tspan = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
|
||||
tspan.setAttribute("x", 0);
|
||||
tspan.setAttribute("dy", i === 0 ? "0" : "1.2em"); // first line dy=0, next lines shift down
|
||||
tspan.textContent = name;
|
||||
textEl.appendChild(tspan);
|
||||
});
|
||||
main.setAttribute("transform", `translate(${avgX}, ${avgY})`);
|
||||
|
||||
// 3. Resize and reposition the <rect> background
|
||||
const textBBox = textEl.getBBox();
|
||||
const g = main; // the parent <g> element
|
||||
const rect = g.querySelector("rect");
|
||||
|
||||
if (rect) {
|
||||
rect.setAttribute("x", textBBox.x - 4);
|
||||
rect.setAttribute("y", textBBox.y - 2);
|
||||
rect.setAttribute("width", textBBox.width + 8);
|
||||
rect.setAttribute("height", textBBox.height + 4);
|
||||
}
|
||||
|
||||
// Optional: Update bbox height for offsetting in update()
|
||||
g.setAttribute("data-bbox-height", textBBox.height);
|
||||
|
||||
// Hide others
|
||||
for (let i = 1; i < group.length; i++) {
|
||||
group[i].style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
109
data/berlin-parks-new.json
Normal file
109
data/berlin-parks-new.json
Normal file
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "Interval [Start] Roll Out (last touch -> end of roll out)"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
13.40280532836914,
|
||||
52.474311525275674
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "Volskpark Friedrichshain"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
13.432846069335938,
|
||||
52.527605775532116
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "Großer Tiergarten"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
13.356628417968748,
|
||||
52.51507176398948
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "Park am Gleisdreieck"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
13.376026153564451,
|
||||
52.49605502101946
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "Volskpark Humboldthain"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
13.383750915527344,
|
||||
52.54566934855766
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "Görlitzer Park"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
13.435592651367188,
|
||||
52.4976226461021
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "Volkspark Prenzlazer Berg"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
13.46323013305664,
|
||||
52.53700393747574
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "Tierpark Berlin"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
13.528633117675781,
|
||||
52.50347461927098
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
97
gemma.html
Normal file
97
gemma.html
Normal file
@@ -0,0 +1,97 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Mapbox GL JS + D3 Example</title>
|
||||
<link href="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.css" rel="stylesheet" />
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.js"></script>
|
||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||
<style>
|
||||
body { margin: 0; padding: 0; }
|
||||
#map { height: 1000px; width: 1600px; }
|
||||
.map-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none; /* Allow map interactions to pass through */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="map"></div>
|
||||
|
||||
<script>
|
||||
mapboxgl.accessToken = 'pk.eyJ1Ijoiam9yZGl0b3N0IiwiYSI6ImQtcVkyclEifQ.vwKrOGZoZSj3N-9MB6FF_A'; // Replace with your Mapbox access token
|
||||
|
||||
const map = new mapboxgl.Map({
|
||||
container: 'map',
|
||||
style: 'mapbox://style/mapbox/light-v9',
|
||||
center: [-74.0060, 40.7128], // New York City
|
||||
zoom: 10
|
||||
});
|
||||
|
||||
map.on('load', () => {
|
||||
// Sample data (replace with your actual data)
|
||||
const data = [
|
||||
{ longitude: -74.0060, latitude: 40.7128, value: 10, label: "A" },
|
||||
{ longitude: -73.9857, latitude: 40.7484, value: 20, label: "B" },
|
||||
{ longitude: -73.9960, latitude: 40.7589, value: 15, label: "C" },
|
||||
{ longitude: -73.9960, latitude: 40.7389, value: 25, label: "D"}
|
||||
];
|
||||
|
||||
const canvas = map.getCanvas();
|
||||
const svg = d3.select(canvas)
|
||||
.append("svg")
|
||||
.attr("class", "map-overlay")
|
||||
.attr("width", canvas.width)
|
||||
.attr("height", canvas.height);
|
||||
|
||||
// Create circles for each data point
|
||||
const circles = svg.selectAll("circle")
|
||||
.data(data)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("cx", (d) => map.project([d.longitude, d.latitude])[0])
|
||||
.attr("cy", (d) => map.project([d.longitude, d.latitude])[1])
|
||||
.attr("r", (d) => d.value / 5)
|
||||
.attr("fill", "steelblue")
|
||||
.attr("opacity", 0.7);
|
||||
|
||||
// Add labels to each circle
|
||||
const labels = svg.selectAll("text")
|
||||
.data(data)
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("x", (d) => map.project([d.longitude, d.latitude])[0])
|
||||
.attr("y", (d) => map.project([d.longitude, d.latitude])[1] - 10) // Adjust vertical position
|
||||
.text((d) => d.label)
|
||||
.attr("font-size", "12px")
|
||||
.attr("font-family", "Arial")
|
||||
.attr("fill", "white")
|
||||
.attr("text-anchor", "middle");
|
||||
|
||||
|
||||
|
||||
// Update circle positions on map move
|
||||
map.on('move', () => {
|
||||
circles.each(function (d) {
|
||||
const [x, y] = map.project([d.longitude, d.latitude]);
|
||||
d3.select(this)
|
||||
.attr("cx", x)
|
||||
.attr("cy", y);
|
||||
});
|
||||
|
||||
labels.each(function (d) {
|
||||
const [x, y] = map.project([d.longitude, d.latitude]);
|
||||
d3.select(this)
|
||||
.attr("x", x)
|
||||
.attr("y", y - 10);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
78
gpttest.html
Normal file
78
gpttest.html
Normal file
@@ -0,0 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Mapbox GL JS + D3.js Example</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link href="https://api.tiles.mapbox.com/mapbox-gl-js/v3.0.1/mapbox-gl.css" rel="stylesheet" />
|
||||
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v3.0.1/mapbox-gl.js"></script>
|
||||
<script src="https://d3js.org/d3.v4.min.js"></script>
|
||||
|
||||
<style>
|
||||
body { margin: 0; padding: 0; }
|
||||
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
|
||||
|
||||
/* SVG overlay on top of Mapbox canvas */
|
||||
svg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none; /* so it doesn't block map interaction */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
|
||||
<script>
|
||||
// 🔑 Replace with your own Mapbox access token
|
||||
mapboxgl.accessToken = 'pk.eyJ1Ijoiam9yZGl0b3N0IiwiYSI6ImQtcVkyclEifQ.vwKrOGZoZSj3N-9MB6FF_A';
|
||||
|
||||
// Initialize Mapbox map
|
||||
const map = new mapboxgl.Map({
|
||||
container: 'map',
|
||||
style: 'mapbox://styles/mapbox/light-v11',
|
||||
center: [-122.4194, 37.7749], // San Francisco
|
||||
zoom: 10
|
||||
});
|
||||
|
||||
// Sample data: Some points in San Francisco
|
||||
const data = [
|
||||
{ name: 'Golden Gate Bridge', coords: [-122.4783, 37.8199] },
|
||||
{ name: 'Alcatraz Island', coords: [-122.4231, 37.8267] },
|
||||
{ name: 'Downtown SF', coords: [-122.4194, 37.7749] }
|
||||
];
|
||||
|
||||
// Create SVG overlay once map is loaded
|
||||
map.on('load', () => {
|
||||
const container = map.getCanvasContainer();
|
||||
const svg = d3.select(container).append('svg');
|
||||
|
||||
// Bind data to SVG circles
|
||||
const circles = svg.selectAll('circle')
|
||||
.data(data)
|
||||
.enter()
|
||||
.append('circle')
|
||||
.attr('r', 16)
|
||||
.attr('fill', 'red');
|
||||
/*.attr('stroke', 'white')
|
||||
.attr('stroke-width', 2)
|
||||
.attr('opacity', 0.8);*/
|
||||
|
||||
// Update function to project geo coords to screen coords
|
||||
function updatePositions() {
|
||||
circles
|
||||
.attr('cx', d => map.project(d.coords).x)
|
||||
.attr('cy', d => map.project(d.coords).y);
|
||||
}
|
||||
|
||||
// Call update initially and on map move/zoom
|
||||
updatePositions();
|
||||
map.on('move', updatePositions);
|
||||
map.on('zoom', updatePositions);
|
||||
map.on('resize', updatePositions);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
132
qwencoder-test.html
Normal file
132
qwencoder-test.html
Normal file
@@ -0,0 +1,132 @@
|
||||
<!DOCTYPE html >
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>mapboxgl.js + d3.js tutorial - 03</title>
|
||||
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
|
||||
<link href="https://api.mapbox.com/mapbox-gl-js/v3.0.1/mapbox-gl.css" rel="stylesheet" />
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v3.0.1/mapbox-gl.js"></script>
|
||||
<script src="https://d3js.org/d3.v4.min.js"></script>
|
||||
<style media="screen">
|
||||
body { margin:0; padding:0; }
|
||||
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||
svg {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.park-label {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
fill: #333;
|
||||
text-anchor: middle;
|
||||
dominant-baseline: middle;
|
||||
pointer-events: none;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.park-icon {
|
||||
cursor: pointer;
|
||||
transition: 0.3s opacity;
|
||||
}
|
||||
.park-icon:hover {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map">
|
||||
</div>
|
||||
<script>
|
||||
//////////////////
|
||||
// Mapbox stuff
|
||||
//////////////////
|
||||
// Set-up map
|
||||
mapboxgl.accessToken = 'pk.eyJ1Ijoiam9yZGl0b3N0IiwiYSI6ImQtcVkyclEifQ.vwKrOGZoZSj3N-9MB6FF_A';
|
||||
var map = new mapboxgl.Map({
|
||||
container: 'map',
|
||||
style: 'mapbox://styles/mapbox/outdoors-v9',
|
||||
zoom: 11.5,
|
||||
center: [13.4426, 52.5100],
|
||||
});
|
||||
|
||||
//////////////////////////
|
||||
// Mapbox+D3 Connection
|
||||
//////////////////////////
|
||||
// Get Mapbox map canvas container
|
||||
var canvas = map.getCanvasContainer();
|
||||
// Overlay d3 on the map
|
||||
var svg = d3.select(canvas).append("svg");
|
||||
|
||||
// Load map and dataset
|
||||
map.on('load', function () {
|
||||
d3.json("data/berlin-parks.json", function(err, data) {
|
||||
drawData(data);
|
||||
});
|
||||
});
|
||||
|
||||
// Project GeoJSON coordinate to the map's current state
|
||||
function project(d) {
|
||||
return map.project(new mapboxgl.LngLat(+d[0], +d[1]));
|
||||
}
|
||||
|
||||
//////////////
|
||||
// D3 stuff
|
||||
//////////////
|
||||
// Draw GeoJSON data with d3
|
||||
var parkElements;
|
||||
function drawData(data) {
|
||||
console.log("draw data");
|
||||
|
||||
// Add icons and labels
|
||||
parkElements = svg.selectAll(".park-element")
|
||||
.data(data.features)
|
||||
.enter()
|
||||
.append("g")
|
||||
.attr("class", "park-element")
|
||||
.attr("transform", function(d) {
|
||||
var coord = project(d.geometry.coordinates);
|
||||
return "translate(" + coord.x + "," + coord.y + ")";
|
||||
})
|
||||
.on("click", function(d) {
|
||||
alert(d.properties.name);
|
||||
});
|
||||
|
||||
// Add park icon (using a simple SVG path for a tree/leaf)
|
||||
parkElements.append("path")
|
||||
.attr("class", "park-icon")
|
||||
.attr("d", "M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5a2.5 2.5 0 0 1 0-5 2.5 2.5 0 0 1 0 5z")
|
||||
.attr("fill", "#4CAF50")
|
||||
.attr("stroke", "#388E3C")
|
||||
.attr("stroke-width", 1)
|
||||
.attr("transform", "scale(0.7)")
|
||||
.attr("opacity", 0.9);
|
||||
|
||||
// Add park name label
|
||||
parkElements.append("text")
|
||||
.attr("class", "park-label")
|
||||
.text(function(d) {
|
||||
return d.properties.name || "Unnamed Park";
|
||||
})
|
||||
.attr("dy", 25); // Position below the icon
|
||||
|
||||
// Call the update function
|
||||
update();
|
||||
|
||||
// Update on map interaction
|
||||
map.on("viewreset", update);
|
||||
map.on("move", update);
|
||||
map.on("moveend", update);
|
||||
}
|
||||
|
||||
// Update d3 shapes' positions to the map's current state
|
||||
function update() {
|
||||
console.log("update");
|
||||
svg.selectAll(".park-element")
|
||||
.attr("transform", function(d) {
|
||||
var coord = project(d.geometry.coordinates);
|
||||
return "translate(" + coord.x + "," + coord.y + ")";
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
231
qwencoder.html
Normal file
231
qwencoder.html
Normal file
@@ -0,0 +1,231 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Mapbox GL JS + D3.js Integration</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v2.14.1/mapbox-gl.js"></script>
|
||||
<link href="https://api.mapbox.com/mapbox-gl-js/v2.14.1/mapbox-gl.css" rel="stylesheet">
|
||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
#map {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
#info {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.3);
|
||||
}
|
||||
#chart {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.3);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<div id="info">
|
||||
<h3>Mapbox + D3.js Demo</h3>
|
||||
<p>Interactive map with D3 data visualization</p>
|
||||
</div>
|
||||
<div id="chart">
|
||||
<h4>Population Distribution</h4>
|
||||
<svg id="bar-chart" width="280" height="150"></svg>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Initialize Mapbox GL JS
|
||||
mapboxgl.accessToken = 'pk.eyJ1Ijoiam9yZGl0b3N0IiwiYSI6ImQtcVkyclEifQ.vwKrOGZoZSj3N-9MB6FF_A'; // Replace with your token
|
||||
|
||||
const map = new mapboxgl.Map({
|
||||
container: 'map',
|
||||
style: 'mapbox://styles/mapbox/streets-v12',
|
||||
center: [-100, 40],
|
||||
zoom: 3
|
||||
});
|
||||
|
||||
// Sample data - in real app this could come from an API or file
|
||||
const sampleData = [
|
||||
{ name: "New York", population: 8336817, coordinates: [-74.006, 40.7128] },
|
||||
{ name: "Los Angeles", population: 3979576, coordinates: [-118.2437, 34.0522] },
|
||||
{ name: "Chicago", population: 2746388, coordinates: [-87.6298, 41.8781] },
|
||||
{ name: "Houston", population: 2320268, coordinates: [-95.3698, 29.7604] },
|
||||
{ name: "Phoenix", population: 1680992, coordinates: [-112.0740, 33.4484] },
|
||||
{ name: "Philadelphia", population: 1584064, coordinates: [-75.1652, 39.9526] }
|
||||
];
|
||||
|
||||
// Use D3 to process and visualize data
|
||||
const populationData = sampleData.map(d => d.population);
|
||||
const maxPopulation = Math.max(...populationData);
|
||||
|
||||
// Create bar chart with D3
|
||||
function createBarChart() {
|
||||
const svg = d3.select("#bar-chart");
|
||||
const width = +svg.attr("width");
|
||||
const height = +svg.attr("height");
|
||||
|
||||
// Clear existing content
|
||||
svg.selectAll("*").remove();
|
||||
|
||||
// Set up scales
|
||||
const xScale = d3.scaleBand()
|
||||
.domain(sampleData.map(d => d.name))
|
||||
.range([0, width])
|
||||
.padding(0.1);
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, maxPopulation])
|
||||
.range([height, 0]);
|
||||
|
||||
// Create bars
|
||||
svg.selectAll(".bar")
|
||||
.data(sampleData)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("class", "bar")
|
||||
.attr("x", d => xScale(d.name))
|
||||
.attr("width", xScale.bandwidth())
|
||||
.attr("y", d => yScale(d.population))
|
||||
.attr("height", d => height - yScale(d.population))
|
||||
.attr("fill", "#3b82f6");
|
||||
|
||||
// Add value labels
|
||||
svg.selectAll(".label")
|
||||
.data(sampleData)
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("class", "label")
|
||||
.attr("x", d => xScale(d.name) + xScale.bandwidth() / 2)
|
||||
.attr("y", d => yScale(d.population) - 5)
|
||||
.attr("text-anchor", "middle")
|
||||
.text(d => Math.round(d.population / 1000000) + "M");
|
||||
}
|
||||
|
||||
// Create map markers with D3 processing
|
||||
function createMarkers() {
|
||||
const markers = [];
|
||||
|
||||
sampleData.forEach((city, index) => {
|
||||
// Use D3 to process data for marker styling
|
||||
const normalizedPopulation = city.population / maxPopulation;
|
||||
|
||||
// Create marker element
|
||||
const el = document.createElement('div');
|
||||
el.className = 'marker';
|
||||
el.style.width = '20px';
|
||||
el.style.height = '20px';
|
||||
el.style.background = `rgba(59, 130, 246, ${normalizedPopulation})`;
|
||||
el.style.borderRadius = '50%';
|
||||
el.style.border = '2px solid white';
|
||||
el.style.boxShadow = '0 0 5px rgba(0,0,0,0.5)';
|
||||
|
||||
// Add click interaction
|
||||
el.addEventListener('click', () => {
|
||||
alert(`${city.name}: ${city.population.toLocaleString()} people`);
|
||||
});
|
||||
|
||||
// Create marker
|
||||
const marker = new mapboxgl.Marker(el)
|
||||
.setLngLat(city.coordinates)
|
||||
.addTo(map);
|
||||
|
||||
markers.push(marker);
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize everything when map is loaded
|
||||
map.on('load', function () {
|
||||
// Create D3 visualizations
|
||||
createBarChart();
|
||||
|
||||
// Create map markers
|
||||
createMarkers();
|
||||
|
||||
// Add a custom data layer using D3 processed data
|
||||
const geojsonData = {
|
||||
type: "FeatureCollection",
|
||||
features: sampleData.map(city => ({
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "Point",
|
||||
coordinates: city.coordinates
|
||||
},
|
||||
properties: {
|
||||
name: city.name,
|
||||
population: city.population
|
||||
}
|
||||
}))
|
||||
};
|
||||
|
||||
// Add source and layer for data visualization
|
||||
map.addSource('cities', {
|
||||
type: 'geojson',
|
||||
data: geojsonData
|
||||
});
|
||||
|
||||
map.addLayer({
|
||||
id: 'cities-points',
|
||||
type: 'circle',
|
||||
source: 'cities',
|
||||
paint: {
|
||||
'circle-radius': [
|
||||
'interpolate', ['linear'], ['get', 'population'],
|
||||
1000000, 5,
|
||||
8000000, 20
|
||||
],
|
||||
'circle-color': '#3b82f6',
|
||||
'circle-stroke-width': 1,
|
||||
'circle-stroke-color': '#ffffff'
|
||||
}
|
||||
});
|
||||
|
||||
// Add a simple legend using D3
|
||||
const legendData = [
|
||||
{ label: "Small", population: 1000000 },
|
||||
{ label: "Medium", population: 4000000 },
|
||||
{ label: "Large", population: 8000000 }
|
||||
];
|
||||
|
||||
const legendSvg = d3.select("#info")
|
||||
.append("div")
|
||||
.attr("id", "legend")
|
||||
.style("margin-top", "10px");
|
||||
|
||||
legendSvg.selectAll("circle")
|
||||
.data(legendData)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("r", d => Math.sqrt(d.population / 100000))
|
||||
.attr("cx", (d, i) => i * 30 + 10)
|
||||
.attr("cy", 20)
|
||||
.attr("fill", "#3b82f6");
|
||||
});
|
||||
|
||||
// Handle window resize
|
||||
window.addEventListener('resize', function() {
|
||||
map.resize();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
299
qwencoder2.html
Normal file
299
qwencoder2.html
Normal file
@@ -0,0 +1,299 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Mapbox GL JS + D3.js Integration - Hover Demo</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v2.14.1/mapbox-gl.js"></script>
|
||||
<link href="https://api.mapbox.com/mapbox-gl-js/v2.14.1/mapbox-gl.css" rel="stylesheet">
|
||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
#map {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
#info {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.3);
|
||||
}
|
||||
#chart {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.3);
|
||||
}
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
z-index: 1001;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<div id="info">
|
||||
<h3>Mapbox + D3.js Demo</h3>
|
||||
<p>Interactive map with D3 data visualization</p>
|
||||
</div>
|
||||
<div id="chart">
|
||||
<h4>Population Distribution</h4>
|
||||
<svg id="bar-chart" width="280" height="150"></svg>
|
||||
</div>
|
||||
<div id="tooltip" class="tooltip"></div>
|
||||
|
||||
<script>
|
||||
// Initialize Mapbox GL JS
|
||||
mapboxgl.accessToken = 'pk.eyJ1Ijoiam9yZGl0b3N0IiwiYSI6ImQtcVkyclEifQ.vwKrOGZoZSj3N-9MB6FF_A'; // Replace with your token
|
||||
|
||||
const map = new mapboxgl.Map({
|
||||
container: 'map',
|
||||
style: 'mapbox://styles/mapbox/streets-v12',
|
||||
center: [-100, 40],
|
||||
zoom: 3
|
||||
});
|
||||
|
||||
// Sample data - in real app this could come from an API or file
|
||||
const sampleData = [
|
||||
{ name: "New York", population: 8336817, coordinates: [-74.006, 40.7128] },
|
||||
{ name: "Los Angeles", population: 3979576, coordinates: [-118.2437, 34.0522] },
|
||||
{ name: "Chicago", population: 2746388, coordinates: [-87.6298, 41.8781] },
|
||||
{ name: "Houston", population: 2320268, coordinates: [-95.3698, 29.7604] },
|
||||
{ name: "Phoenix", population: 1680992, coordinates: [-112.0740, 33.4484] },
|
||||
{ name: "Philadelphia", population: 1584064, coordinates: [-75.1652, 39.9526] }
|
||||
];
|
||||
|
||||
// Use D3 to process and visualize data
|
||||
const populationData = sampleData.map(d => d.population);
|
||||
const maxPopulation = Math.max(...populationData);
|
||||
|
||||
// Create bar chart with D3
|
||||
function createBarChart() {
|
||||
const svg = d3.select("#bar-chart");
|
||||
const width = +svg.attr("width");
|
||||
const height = +svg.attr("height");
|
||||
|
||||
// Clear existing content
|
||||
svg.selectAll("*").remove();
|
||||
|
||||
// Set up scales
|
||||
const xScale = d3.scaleBand()
|
||||
.domain(sampleData.map(d => d.name))
|
||||
.range([0, width])
|
||||
.padding(0.1);
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, maxPopulation])
|
||||
.range([height, 0]);
|
||||
|
||||
// Create bars
|
||||
svg.selectAll(".bar")
|
||||
.data(sampleData)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("class", "bar")
|
||||
.attr("x", d => xScale(d.name))
|
||||
.attr("width", xScale.bandwidth())
|
||||
.attr("y", d => yScale(d.population))
|
||||
.attr("height", d => height - yScale(d.population))
|
||||
.attr("fill", "#3b82f6")
|
||||
.attr("stroke", "#1e40af")
|
||||
.attr("stroke-width", 1);
|
||||
|
||||
// Add value labels on bars
|
||||
svg.selectAll(".label")
|
||||
.data(sampleData)
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("class", "label")
|
||||
.attr("x", d => xScale(d.name) + xScale.bandwidth() / 2)
|
||||
.attr("y", d => yScale(d.population) - 5)
|
||||
.attr("text-anchor", "middle")
|
||||
.style("font-size", "10px")
|
||||
.style("fill", "#333")
|
||||
.text(d => Math.round(d.population / 1000000) + "M");
|
||||
}
|
||||
|
||||
// Create map markers with hover functionality
|
||||
function createMarkers() {
|
||||
const markers = [];
|
||||
|
||||
sampleData.forEach(city => {
|
||||
// Create marker element
|
||||
const el = document.createElement('div');
|
||||
el.className = 'marker';
|
||||
el.style.width = '20px';
|
||||
el.style.height = '20px';
|
||||
el.style.background = '#3b82f6';
|
||||
el.style.border = '2px solid white';
|
||||
el.style.borderRadius = '50%';
|
||||
el.style.boxShadow = '0 0 10px rgba(0,0,0,0.5)';
|
||||
el.style.cursor = 'pointer';
|
||||
|
||||
// Create marker
|
||||
const marker = new mapboxgl.Marker(el)
|
||||
.setLngLat(city.coordinates)
|
||||
.addTo(map);
|
||||
|
||||
markers.push({
|
||||
marker: marker,
|
||||
city: city
|
||||
});
|
||||
|
||||
// Add hover event listeners
|
||||
el.addEventListener('mouseenter', function(e) {
|
||||
showTooltip(city, e);
|
||||
});
|
||||
|
||||
el.addEventListener('mouseleave', function() {
|
||||
hideTooltip();
|
||||
});
|
||||
});
|
||||
|
||||
return markers;
|
||||
}
|
||||
|
||||
// Show tooltip on hover
|
||||
function showTooltip(city, event) {
|
||||
const tooltip = document.getElementById('tooltip');
|
||||
tooltip.innerHTML = `
|
||||
<strong>${city.name}</strong><br>
|
||||
Population: ${city.population.toLocaleString()}<br>
|
||||
Rank: ${(sampleData.findIndex(c => c.name === city.name) + 1).toLocaleString()}
|
||||
`;
|
||||
|
||||
// Position tooltip near mouse
|
||||
const rect = map.getContainer().getBoundingClientRect();
|
||||
const x = event.clientX - rect.left;
|
||||
const y = event.clientY - rect.top;
|
||||
|
||||
tooltip.style.left = (x + 10) + 'px';
|
||||
tooltip.style.top = (y - 30) + 'px';
|
||||
tooltip.style.opacity = 1;
|
||||
}
|
||||
|
||||
// Hide tooltip
|
||||
function hideTooltip() {
|
||||
const tooltip = document.getElementById('tooltip');
|
||||
tooltip.style.opacity = 0;
|
||||
}
|
||||
|
||||
// Initialize everything when map is loaded
|
||||
map.on('load', function () {
|
||||
// Create D3 visualizations
|
||||
createBarChart();
|
||||
|
||||
// Create map markers with hover functionality
|
||||
const markers = createMarkers();
|
||||
|
||||
// Add a custom data layer using D3 processed data
|
||||
const geojsonData = {
|
||||
type: "FeatureCollection",
|
||||
features: sampleData.map(city => ({
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "Point",
|
||||
coordinates: city.coordinates
|
||||
},
|
||||
properties: {
|
||||
name: city.name,
|
||||
population: city.population
|
||||
}
|
||||
}))
|
||||
};
|
||||
|
||||
// Add source and layer for data visualization
|
||||
map.addSource('cities', {
|
||||
type: 'geojson',
|
||||
data: geojsonData
|
||||
});
|
||||
|
||||
map.addLayer({
|
||||
id: 'cities-points',
|
||||
type: 'circle',
|
||||
source: 'cities',
|
||||
paint: {
|
||||
'circle-radius': [
|
||||
'interpolate', ['linear'], ['get', 'population'],
|
||||
1000000, 5,
|
||||
8000000, 20
|
||||
],
|
||||
'circle-color': '#3b82f6',
|
||||
'circle-stroke-width': 1,
|
||||
'circle-stroke-color': '#ffffff'
|
||||
}
|
||||
});
|
||||
|
||||
// Add hover effect to map points
|
||||
let hoveredCityId = null;
|
||||
|
||||
map.on('mousemove', function(e) {
|
||||
const features = map.queryRenderedFeatures(e.point, {
|
||||
layers: ['cities-points']
|
||||
});
|
||||
|
||||
// Change cursor style
|
||||
map.getContainer().style.cursor = features.length ? 'pointer' : '';
|
||||
|
||||
if (features.length) {
|
||||
const city = features[0].properties;
|
||||
showTooltip(city, e);
|
||||
} else {
|
||||
hideTooltip();
|
||||
}
|
||||
});
|
||||
|
||||
// Add a simple legend using D3
|
||||
const legendData = [
|
||||
{ label: "Small", population: 1000000 },
|
||||
{ label: "Medium", population: 4000000 },
|
||||
{ label: "Large", population: 8000000 }
|
||||
];
|
||||
|
||||
const legendSvg = d3.select("#info")
|
||||
.append("div")
|
||||
.attr("id", "legend")
|
||||
.style("margin-top", "10px");
|
||||
|
||||
legendSvg.selectAll("circle")
|
||||
.data(legendData)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("r", d => Math.sqrt(d.population / 100000))
|
||||
.attr("cx", (d, i) => i * 30 + 10)
|
||||
.attr("cy", 20)
|
||||
.attr("fill", "#3b82f6");
|
||||
});
|
||||
|
||||
// Handle window resize
|
||||
window.addEventListener('resize', function() {
|
||||
map.resize();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user