added Mercator scaling
This commit is contained in:
parent
46a7d921d2
commit
a3f72b83c1
@ -130,126 +130,64 @@ function init2DVisualization() {
|
|||||||
.attr('width', width)
|
.attr('width', width)
|
||||||
.attr('height', height);
|
.attr('height', height);
|
||||||
|
|
||||||
// Add a background rectangle representing the ocean
|
// Create projection
|
||||||
d3Svg.append('rect')
|
|
||||||
.attr('width', width)
|
|
||||||
.attr('height', height)
|
|
||||||
.attr('fill', '#a4d1e9'); // Ocean blue
|
|
||||||
|
|
||||||
// Create projection (Mercator) similar to standard world maps
|
|
||||||
d3Projection = d3.geoMercator()
|
d3Projection = d3.geoMercator()
|
||||||
.scale(width / (2 * Math.PI) * 0.9)
|
.scale(width / (2 * Math.PI) * 0.9)
|
||||||
.translate([width / 2, height / 1.8]);
|
.translate([width / 2, height / 2]);
|
||||||
|
|
||||||
// Create path generator
|
// Create path generator
|
||||||
d3Path = d3.geoPath()
|
d3Path = d3.geoPath()
|
||||||
.projection(d3Projection);
|
.projection(d3Projection);
|
||||||
|
|
||||||
// Draw graticule (grid lines)
|
// Add a background rectangle representing the ocean
|
||||||
const graticule = d3.geoGraticule()
|
d3Svg.append('rect')
|
||||||
.step([15, 15]); // Grid every 15 degrees
|
.attr('width', width)
|
||||||
|
.attr('height', height)
|
||||||
|
.attr('fill', '#a4d1e9');
|
||||||
|
|
||||||
d3Svg.append('path')
|
// Load and draw actual world map data
|
||||||
.datum(graticule)
|
d3.json('https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json').then(world => {
|
||||||
.attr('class', 'graticule')
|
// Draw countries
|
||||||
.attr('d', d3Path)
|
const countries = topojson.feature(world, world.objects.countries);
|
||||||
.style('fill', 'none')
|
|
||||||
.style('stroke', '#ffffff')
|
|
||||||
.style('stroke-width', '0.5px')
|
|
||||||
.style('opacity', 0.5);
|
|
||||||
|
|
||||||
// Draw equator
|
d3Svg.append('g')
|
||||||
const equator = {
|
.attr('class', 'countries')
|
||||||
type: "LineString",
|
.selectAll('path')
|
||||||
coordinates: [[-180, 0], [-90, 0], [0, 0], [90, 0], [180, 0]]
|
.data(countries.features)
|
||||||
};
|
.enter()
|
||||||
|
.append('path')
|
||||||
|
.attr('d', d3Path)
|
||||||
|
.attr('fill', '#d3b683')
|
||||||
|
.attr('stroke', '#a89070')
|
||||||
|
.attr('stroke-width', 0.5)
|
||||||
|
.attr('opacity', 0.8);
|
||||||
|
|
||||||
d3Svg.append('path')
|
// Add graticule (grid lines)
|
||||||
.datum(equator)
|
const graticule = d3.geoGraticule()
|
||||||
.attr('class', 'equator')
|
.step([15, 15]);
|
||||||
.attr('d', d3Path)
|
|
||||||
.style('fill', 'none')
|
|
||||||
.style('stroke', '#00ffff')
|
|
||||||
.style('stroke-width', '2px');
|
|
||||||
|
|
||||||
// Draw prime meridian (0° longitude)
|
|
||||||
// const primeMeridian = {
|
|
||||||
// type: "LineString",
|
|
||||||
// coordinates: [[0, -90], [0, -45], [0, 0], [0, 45], [0, 90]]
|
|
||||||
// };
|
|
||||||
|
|
||||||
// d3Svg.append('path')
|
|
||||||
// .datum(primeMeridian)
|
|
||||||
// .attr('class', 'prime-meridian')
|
|
||||||
// .attr('d', d3Path)
|
|
||||||
// .style('fill', 'none')
|
|
||||||
// .style('stroke', '#ff0000')
|
|
||||||
// .style('stroke-width', '2px');
|
|
||||||
|
|
||||||
// Draw continental outlines (simplified)
|
|
||||||
// This just adds some landmass-like shapes to make it feel more Earth-like
|
|
||||||
const mockContinents = [
|
|
||||||
{ // North America (simplified)
|
|
||||||
type: "Polygon",
|
|
||||||
coordinates: [[
|
|
||||||
[-140, 70], [-120, 60], [-100, 50], [-80, 30],
|
|
||||||
[-90, 20], [-100, 15], [-120, 30], [-130, 50], [-140, 70]
|
|
||||||
]]
|
|
||||||
},
|
|
||||||
{ // South America (simplified)
|
|
||||||
type: "Polygon",
|
|
||||||
coordinates: [[
|
|
||||||
[-80, 10], [-60, 0], [-50, -10], [-60, -30],
|
|
||||||
[-70, -50], [-80, -30], [-90, -10], [-80, 10]
|
|
||||||
]]
|
|
||||||
},
|
|
||||||
{ // Europe/Africa (very simplified)
|
|
||||||
type: "Polygon",
|
|
||||||
coordinates: [[
|
|
||||||
[0, 60], [20, 40], [30, 30], [20, 10], [10, 0],
|
|
||||||
[20, -10], [30, -30], [20, -40], [0, -30], [-10, 0], [0, 60]
|
|
||||||
]]
|
|
||||||
},
|
|
||||||
{ // Asia (simplified)
|
|
||||||
type: "Polygon",
|
|
||||||
coordinates: [[
|
|
||||||
[30, 60], [60, 70], [100, 60], [130, 40], [110, 20],
|
|
||||||
[100, 0], [80, 10], [60, 30], [40, 40], [30, 60]
|
|
||||||
]]
|
|
||||||
},
|
|
||||||
{ // Australia (simplified)
|
|
||||||
type: "Polygon",
|
|
||||||
coordinates: [[
|
|
||||||
[110, -20], [130, -25], [140, -35], [130, -40],
|
|
||||||
[120, -35], [110, -30], [110, -20]
|
|
||||||
]]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// Add continent outlines with very low opacity to provide visual reference
|
|
||||||
mockContinents.forEach(continent => {
|
|
||||||
d3Svg.append('path')
|
d3Svg.append('path')
|
||||||
.datum(continent)
|
.datum(graticule)
|
||||||
.attr('class', 'continent-outline')
|
.attr('class', 'graticule')
|
||||||
.attr('d', d3Path);
|
.attr('d', d3Path)
|
||||||
});
|
.style('fill', 'none')
|
||||||
|
.style('stroke', '#ffffff')
|
||||||
|
.style('stroke-width', '0.5px')
|
||||||
|
.style('opacity', 0.3);
|
||||||
|
|
||||||
// Add labels for orientation
|
// Draw equator
|
||||||
const labels = [
|
const equator = {
|
||||||
{ text: "North Pole", coords: [0, 85], anchor: "middle" },
|
type: "LineString",
|
||||||
{ text: "South Pole", coords: [0, -85], anchor: "middle" },
|
coordinates: [[-180, 0], [-90, 0], [0, 0], [90, 0], [180, 0]]
|
||||||
{ text: "Equator", coords: [-170, 0], anchor: "start" },
|
};
|
||||||
//{ text: "Prime Meridian", coords: [5, 45], anchor: "start" }
|
|
||||||
];
|
|
||||||
|
|
||||||
labels.forEach(label => {
|
d3Svg.append('path')
|
||||||
const [x, y] = d3Projection(label.coords);
|
.datum(equator)
|
||||||
d3Svg.append('text')
|
.attr('class', 'equator')
|
||||||
.attr('x', x)
|
.attr('d', d3Path)
|
||||||
.attr('y', y)
|
.style('fill', 'none')
|
||||||
.attr('class', 'map-label')
|
.style('stroke', '#00ffff')
|
||||||
.attr('text-anchor', label.anchor)
|
.style('stroke-width', '2px');
|
||||||
.text(label.text);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,11 +284,16 @@ function createD3Map(points) {
|
|||||||
// Only draw the point if it projects properly
|
// Only draw the point if it projects properly
|
||||||
const projected = d3Projection([lon, lat]);
|
const projected = d3Projection([lon, lat]);
|
||||||
if (projected) {
|
if (projected) {
|
||||||
|
// Calculate scale factor based on latitude to mimic Mercator distortion
|
||||||
|
// 1/cos(latitude in radians) gives us the characteristic Mercator scaling
|
||||||
|
const latRad = lat * Math.PI / 180;
|
||||||
|
const scaleFactor = Math.min(3, 1 / Math.cos(latRad)); // Cap at 3x to avoid extreme sizes
|
||||||
|
|
||||||
pointsGroup.append('circle')
|
pointsGroup.append('circle')
|
||||||
.attr('class', 'planet-point')
|
.attr('class', 'planet-point')
|
||||||
.attr('cx', projected[0])
|
.attr('cx', projected[0])
|
||||||
.attr('cy', projected[1])
|
.attr('cy', projected[1])
|
||||||
.attr('r', 1.5)
|
.attr('r', 1.5 * scaleFactor) // Scale radius by the Mercator factor
|
||||||
.style('fill', `rgb(${point.color[0] * 255}, ${point.color[1] * 255}, ${point.color[2] * 255})`)
|
.style('fill', `rgb(${point.color[0] * 255}, ${point.color[1] * 255}, ${point.color[2] * 255})`)
|
||||||
.style('opacity', 0.8);
|
.style('opacity', 0.8);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user