Я пытаюсь нарисовать карту (полигоны районов города) с помощью d3js. И все, что я получаю, это бежевый прямоугольник.
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>Lpgz crime rates</title>
<script src = "https://d3js.org/d3.v6.min.js"></script>
<style>
#map {
width: 800px;
height: 600px;
border: 1px solid black;
}
.map path {
stroke: #999;
stroke-width: 0.5;
}
</style>
</head>
<body>
<svg id = "map" viewBox = "0 0 800 600"></svg>
<script>
const width = 800;
const height = 600;
const margin = 20;
const svg = d3.select('#map')
.attr('width', width)
.attr('height', height);
Promise.all([
d3.json('data/Leipzig_ortsteile.geojson'),
d3.json('data/crime_rates.json')
]).then(([ortsteile, crimeRates]) => {
console.info("GeoJSON data:", ortsteile.features);
console.info("Crime rates data:", crimeRates);
const projection = d3.geoMercator()
.fitSize([width, height], ortsteile);
const pathGenerator = d3.geoPath().projection(projection);
const colorScale = d3.scaleSequential(d3.interpolateReds)
.domain([0, d3.max(Object.values(crimeRates))]);
const paths = svg.selectAll('path')
.data(ortsteile.features)
.enter()
.append('path')
.attr('d', d => {
const pathData = pathGenerator(d);
console.info(`Path data for ${d.properties.Name}:`, pathData);
return pathData;
})
.attr('fill', d => {
const rate = crimeRates[d.properties.Name];
console.info(`Area: ${d.properties.Name}, Crime rate: ${rate}`);
return rate ? colorScale(rate) : '#ccc';
})
.attr('stroke', '#999')
.attr('stroke-width', '0.5');
console.info("SVG Paths:", paths);
}).catch(err => console.error("Error loading data:", err));
</script>
</body>
</html>
Вот как геоджсон выглядит внутри:
{
"type": "FeatureCollection",
"name": "log_lat",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "FID": 0, "OT": "00", "Name": "Zentrum" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 12.37927526130802, 51.344360566287889 ], [ 12.379117566590359, 51.344399728002436 ], [ 12.378953533569369, 51. ....
Я попробовал несколько вариантов, включая центрирование по координатам центра города, изменение размеров... Я не получаю никаких ошибок, и выходные данные на консоли выглядят нормально (для меня).
@AndrewReid спасибо за ваш комментарий! Пробовал перематывать с помощью Mapshaper.org, но ничего не изменилось...
Возможно, я ошибся, включив в качестве опции Mapshaper - D3 использует порядок намотки, противоположный спецификации geojson (хотя, по иронии судьбы, спецификация geojson также указывает 2D-координаты и, следовательно, подразумевается внутри снаружи, и поэтому порядок намотки не имеет значения. D3 - один из них). из немногих инструментов для обработки координат как трехмерных точек на глобусе, где порядок намотки имеет значение, но противоречит спецификации geojson в отношении направления намотки - но я отвлекся), поэтому Mapshaper может на самом деле наматывать их неправильно. Однако, возможно, я что-то еще упустил, можете ли вы вообще поделиться геоджоном?
@AndrewReid Я добавил файл сюда: github.com/iurshina/lpz_crime/blob/master/data/… Должно быть что-то с D3, потому что везде он выглядит нормально... (но я бэкенд-специалист и у меня очень мало опыта работы с js и геоданными, это может быть что-то очень глупое...)





Проблема в том, что с вашим кодом все в порядке.
Прошу прощения, что в моем комментарии была ссылка на мапшейпер - этот сервис исправляет намотку, тогда как D3 требует, чтобы она была некорректной. Я включил его, поскольку этот сервис удобен для пользователя и не требует какого-либо кода (а также, как правило, совместим с D3), в отличие от двух других проверенных вариантов. Но я никогда не использовал его раньше.
Ваш файл будет работать практически в любой другой среде карт/графиков, поскольку они рассматривают широту и долготу как плоские. Следствием этого является то, что порядок намотки не имеет значения для этих каркасов: для многоугольника внешняя часть всегда является неограниченной, а внутренняя часть ограничена.
Для D3 широта и долгота указаны на глобусе, поэтому неограниченной части нет. Весь экран имеет тот же цвет, что и последний нарисованный объект, и охватывает весь земной шар, за исключением нужной области. Таким образом, FitSize подходит для всего земного шара.
Один из способов убедиться, что ваш geojson настроен неправильно, — это вручную настроить проекцию на увеличение интересующей вас области и удалить любую заливку. Обычно вы должны увидеть контур всех ваших объектов (если все ваши объекты представляют собой тарабарщину, то у вас есть еще одна проблема: вы проецируете уже спроецированные данные).
Ниже у меня есть полный пример использования Turf для перемотки назад, хотя я понимаю, что мой связанный пример не совсем полный.
<html>
<head>
<script src = " https://cdn.jsdelivr.net/npm/@turf/[email protected]/turf.min.js "></script>
<script src = "https://d3js.org/d3.v6.min.js"></script>
</head>
<body>
<script>
d3.json("target.json").then(function(data) {
var fixed = data.features.map(function(feature) {
return turf.rewind(feature,{reverse:true});
})
data.features = fixed;
d3.select("body").append("p")
.text(JSON.stringify(data));
})
</script>
Похоже на проблему с порядком намотки, вы можете перемотать с помощью газона или перемотать вручную — хотя последний вариант может привести к неправильной перемотке любых правильно намотанных элементов. Вероятно, после этого вы захотите сохранить json и использовать его вместо обработки каждой загрузки карты. Я думаю, что mapshaper.org также предлагает команду перемотки ( -чистая перемотка).