javascript - D3根据数据更新颜色

标签 javascript d3.js

我正在使用 D3 根据数据绘制线条并为其着色。我现在想根据同一数据集中的不同特征来更新这些线条的颜色,但我的颜色更改功能(colorP2)不起作用——我知道这种颜色更改看起来没什么用,但稍后会通过按钮触发.

有什么想法吗?下面是我的代码。

[更新] 正如 Andrew Reed 所指出的,代码中有一个与我的问题无关的错误,我在下面的代码中修复并标记了该错误。

index.html

<html>
<head>
<style>
.line {
    stroke-width: 4px;
    fill: none;
}
</style>
</head>

<script src="https://d3js.org/d3.v6.min.js"></script>
<script type="module">
  import {drawLines} from './drawLines.js';

  d3.json("test.geojson").then(drawLines);
</script>

<body>
    <svg id='map'></svg>
    <button onclick="colorP1()">colorP1</button>
    <button onclick="colorP2()">colorP2</button>
    <!-- <svg id="data" class="map_frame"></svg> -->

</body>
</html>

drawLines.js

function colorInterpolate(data, property) {
    let max_d = d3.max(data.features.map(d => d.properties[property]));
    let range = [max_d, 1];
    return d3.scaleSequential().domain(range).interpolator(d3.interpolateViridis); 
}

export function drawLines(data) {

    let width = 900,
        height = 500,
        initialScale = 1 << 23,
        initialCenter = [-74.200698022608137, 40.034504451003734]

    let svg = d3.select('#map')
        .attr('height', height)
        .attr('width', width)

    let projection = d3.geoMercator()
        .scale(initialScale)
        .center(initialCenter)
        .translate([width / 2, height / 2])

    let path = d3.geoPath(projection)

    let myColor = colorInterpolate(data, 'p1');

    let lines = svg.append('g')

    lines.selectAll('path')
        .data(data.features)
        .join('path') // previously wrong, error was unrelated to question, as pointed out by Andrew.
        .attr('class', 'line')
        .attr('d', path)
        .attr("stroke", function(d) {
                return myColor(d.properties.p1);
            })

    colorP2();

    function colorP2() {
        let myColor = colorInterpolate(data, 'p2');
        lines.selectAll('path')
            .data(data.features)
            .join()
            .attr("stroke", function(d) {
                    return myColor(d.properties.p2);
                })
    }
}

测试.geojson

{
"type": "FeatureCollection",
"name": "lines",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "id": 3, "p1": 1, "p2": 3}, "geometry": { "type": "LineString", "coordinates": [ [ -74.201304101157845, 40.033790926216739 ], [ -74.201226425025339, 40.033761910802717 ], [ -74.201164135201353, 40.033738641825124 ] ] } },
{ "type": "Feature", "properties": { "id": 4, "p1": 2, "p2": 2}, "geometry": { "type": "LineString", "coordinates": [ [ -74.200521185229846, 40.034804885753857 ], [ -74.200535458528648, 40.034780636493231 ], [ -74.200698022608137, 40.034504451003734 ], [ -74.200932444446437, 40.034106179618831 ], [ -74.201017665586349, 40.033961391736824 ] ] } }
]
}

最佳答案

解决方案

最终,您不需要在颜色更改函数中加入任何数据:元素已经存在,并且数据绑定(bind)到它们。连接旨在确保数据数组中的每一项都存在一个 DOM 元素。相反,只需选择元素并更改其属性/样式即可:

  lines.selectAll('path')
       .attr("stroke", function(d) { return myColor(d.properties.p2); })

问题

我强烈怀疑您还没有完全分享您的确切代码 - 如果您分享了,则不应绘制任何内容,因为路径将放置在无效的 SVG 元素中:<undefined></undefined> .

通常,您可以使用联接来重新选择元素(即使不需要),因为它会返回输入和更新选择。但你没有使用 selection.join()正确地在这里。首次添加路径时,您通常会指定要加入的元素类型作为传递给 .join 的参数。 ,而不是使用 selection.append() :

       selection.join('path')

不指定要创建的元素类型将创建如下元素:<undefined></undefined> 。源代码显示了如何在 join 语句中输入元素:

 enter.append(onenter + ""); 

哪里onenter是传递给 .join 的第一个参数.

由于您尚未指定有效的 SVG 元素,SVG 不知道如何渲染它或其子元素(路径):

var svg = d3.select("svg");

var rects = svg.selectAll("rect")
  .data([1,2])
  .join()
  .append("rect")
  .attr("x", d=>d*100+50)
  .attr("y", 100)
  .attr("width", 30)
  .attr("height", 30)
  .attr("fill","crimson");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<svg></svg>

最终您应该使用 .join("path") - 为了进行比较,以下详细说明了每个内容所发生的情况:

  • 选择.join()
  • selection.join().append("p")
  • selection.join("p");

// Don't specify any tag:
var a = d3.select("div")
  .selectAll(null) // this doesn't affect the type of element entered in the join
  .data([1])
  .join()
  .text("a");
  
console.log(".join() :", a.node(), "parent:", a.node().parentNode);

// join without specifying a tag, then append
var b = d3.select("div")
  .selectAll(null)
  .data([1])
  .join()
  .append("p")
  .text("b");
  
console.log(".join().append('p') : ", b.node(), "parent:", b.node().parentNode);

// Specify the type of element to join (the correct method):
var c = d3.select("div")
  .selectAll(null)
  .data([1])
  .join("p")
  .text("c");
  
console.log(".join('p') :", c.node(), "parent:", c.node().parentNode);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<div></div>

关于javascript - D3根据数据更新颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65299334/

相关文章:

javascript - 修改 HTML 内容以更新 D3js 中的节点?

javascript - Youtube 数据 API 集成问题

javascript - D3 - 当悬停从同一数据条目的不同属性创建的圆形元素时,如何显示/隐藏文本元素?

svg - nvd3 图表 - x 轴标签

javascript - 无法同时应用缩放和平移到一组元素

javascript - 删除浏览器只读样式

影响错误元素的 Javascript

javascript - Vuetify - 更改表页脚中选择输入的样式

javascript - 在 d3 时间轴上显示每隔一个刻度标签?

javascript - 加载外部 XML 文件后对其进行操作