линия d3 и точки На карте из данных csv



Я пытаюсь построить отдельные точки данных, а также линейный путь, который проходит между этими точками, как в этом примере D3 остановка и перезапуск перехода вдоль пути, чтобы разрешить переход к координатам гео данных, с которыми мне уже помогали раньше.



Теперь я хочу использовать свои фактические данные, а не тестовый набор координат, но у меня возникли проблемы. Я пробовал как файл geoJson, так и csv для моих данных. Я использую csv-файл с lon и lat для точек и надеялся, что чтобы сделать линию из того же набора данных, то есть использовать один набор данных для точек и линии.

Я не могу заставить свою линию появиться в правильном месте - она находится в правом верхнем углу, но должна быть на / через точки. Я думаю, что это как-то связано с проекцией, но у меня возникли проблемы с правильным анализом данных, чтобы получить строку строки, как требуется. Я попытался использовать образец здесь https://bl.ocks.org/alandunning/cfb7dcd7951826b9eacd54f0647f48d3 - но получить пустой объекты??линия в красном точки в желтом



Мой вопрос заключается в том, как использовать csv lon lat с генератором линий D3 svg.
Вот мой код:



<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Working version 3</title>

<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-array.v1.min.js"></script>
<script src="https://d3js.org/d3-geo.v1.min.js"></script>
<script src="https://d3js.org/d3-queue.v3.min.js"></script>
<script src="https://d3js.org/topojson.v1.min.js"></script>
<style type="text/css">

circle {
fill: steelblue;
stroke: pink;
stroke-width: 3px;
}


.line{
fill: none;
stroke: red;
stroke-width: 6;

}

</style>
</head>
<body>

<script>

var w = 960,
h = 500;

var projection = d3.geoMercator()
.translate([w/2, h/2])
.scale([w * 0.16]);

var path = d3.geoPath()
.projection(projection);

var duration = 10000;

var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);

/*
var line = d3.line()
.x(function (d) {return projection([d.lon]);})
.y(function (d) {return projection([d.lat]);})
.curve(d3.curveBasis);

var line = d3.line()
.x(function(d){return projection(d[0].lon);})
.y(function(d){return projection(d[0].lat);})
.curve(d3.curveBasis);

/*ok line shows up but in wrong place
var line = d3.line()
.x(function(d) { return (d.lon); })
.y(function(d) { return (d.lat); })
.curve(d3.curveBasis);
*/

var line = d3.line()
.x(function(d) { return (d.lon); })
.y(function(d) { return (d.lat); })
.curve(d3.curveBasis);


//original
/*
var line = d3.line()
.x(function(d){return projection(d)[0];})
.y(function(d){return projection(d)[1];})
.curve(d3.curveBasis);
*/
//

//bring in data
d3.queue()
.defer(d3.json, "data/oceans.json")
.defer(d3.csv, "data/speckCities.csv")
.await(ready);

function ready (error, oceans, data){
if (error) throw error;

//console.log(data[0]);
//console.log(data[0].lon);




//map
svg.selectAll("path")
.data(oceans.features)
.enter()
.append("path")
.attr("d", path)
.style("fill", "#A8B2C3");

var linepath = svg.append("path")
.datum(data)
.attr("d", line)
.attr('class', 'line');

svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) {
return projection([d.lon, d.lat])[0];
})
.attr("cy", function(d) {
return projection([d.lon, d.lat])[1];
})
.attr("r", 5)
.style("fill", "yellow")
.style("stroke", "gray")
.style("stroke-width", 0.25)
.style("opacity", 0.75)
.append("title") //Simple tooltip
.text(function(d) {
return d.name ;
});

//




//

/*svg.selectAll(".point")
.data(coordinates)
.enter()
.append("circle")
.attr("r", 7)
.attr("transform", function(d) { return "translate(" + projection(d) + ")"; });


var circle = svg.append("circle")
.attr("r", 19)
.attr("transform", "translate(" + projection(d) + ")");

/*
var pauseValues = {
lastT: 0,
currentT: 0
};

function transition() {
circle.transition()
.duration(duration - (duration * pauseValues.lastT))
.attrTween("transform", translateAlong(linepath.node()))
.on("end", function(){
pauseValues = {
lastT: 0,
currentT: 0
};
transition()
});
}

function translateAlong(path) {
var l = path.getTotalLength();
return function(d, i, a) {
return function(t) {
t += pauseValues.lastT;
var p = path.getPointAtLength(t * l);
pauseValues.currentT = t;
return "translate(" + p.x + "," + p.y + ")";
};
};
}

d3.select('button').on('click',function(d,i){
var self = d3.select(this);
if (self.text() == "Pause"){
self.text('Play');
circle.transition()
.duration(0);
setTimeout(function(){
pauseValues.lastT = pauseValues.currentT;
}, 100);
}else{
self.text('Pause');
transition();
}
});
*/
}

</script>
</body>
</html>
574   1  

1 ответ:

Вы не проецируете свою линию:

var linepath = svg.append("path")
  .datum(data)
  .attr("d", line)
   .attr('class', 'line');

В этом случае ваши пары долгота/широта в вашем geojson преобразуются в прямые пиксельные координаты:

var line = d3.line()
    .x(function(d) { return (d.lon); })
    .y(function(d) { return (d.lat); })
    .curve(d3.curveBasis);

Поскольку координаты svg начинаются с [0,0] в левом верхнем углу, а ваши точки находятся примерно в 10 градусах к востоку или около того (положительная долгота) и в 50 градусах к северу или около того (положительная широта), ваша первая точка в линии появляется в 10 пикселях слева и в 50 пикселях сверху. Кроме того, поскольку значения svg y увеличиваются по мере движения вниз, но значения широты увеличиваются по мере движения на север (типично вверх на карте), ваша линия также выглядит перевернутой по оси y по сравнению с вашими точками.

Вы можете настроить линейную функцию на использование проекции для установки точек x и y:

var line = d3.line()
    .x(function(d) { return projection([d.lon,d.lat])[0] ; })
    .y(function(d) { return projection([d.lon,d.lat])[1]; })
    .curve(d3.curveBasis);

для проецирования точки вам нужны широта и долгота, поэтому функция проецирования принимает и то, и другое, и возвращает x и y, следовательно, [0] и [1], поэтому ваши закомментированные разделы не работают

Но это без необходимости, вы можете передать geojson прямо на путь (так же, как вы делаете для фона мира), то есть если ваши данные доступны в geojson (хотя это не трудно сделать geojson на лету):

var linepath = svg.append("path")
  .datum(data) // in geojson form
  .attr("d", path)  // use your path 
  .attr('class', 'line');

Это более точно, чем линия - отрезки между линиями в d3.линии являются прямыми или следуют предопределенной кривой, в декартовом координатном пространстве. А Д3.геопат следует за большим круговым расстоянием, поэтому отрезки между точками следуют кратчайшему пути на планете, более точная репрезентация, мысль временами, пожалуй, менее стилистическая.

чтобы создать geojson на лету, предположив, что ваши данные выглядят следующим образом: [{lon:number,lat:number},{lon:number,lat:number}] Вы можете использовать что-то вроде:

var points = data.map(function(d) { return [d.lon,d.lat] })
var geojson = { "type": "LineString", "coordinates": points }

Comments

    Ничего не найдено.