重用 Axis Scale 覆盖设置域

Reusing Axis Scale overwrites set domain

我在一个页面上有多个图表,它们都应该具有相同的大小,所以我没有为每个图表复制粘贴大量代码,重用通用设置可能是个好主意:

var xAxisScaleTime = d3.scaleTime().range([0, graph_width ]);
var xAxisScaleLinear = d3.scaleLinear().range([0, graphwidth ]);

var yAxisScaleLin = d3.scaleLinear().range( [ graph_height , 0]);
var yAxisScaleLog = d3.scaleLog().range( [  graph_height , 0]);

//etc...

每个图的域可能不同。所以我这样设置它们:

// Most Graphs will share the same Time-Domain
var GraphT_X = xAxisScaleTime.domain([ starttime, endtime]); 

// Graphs have different Domains for Y
var Graph1_Y = yAxisScaleLin.domain([[ Graph_1_min, Graph_1_max]);
var Graph2_Y = yAxisScaleLin.domain([[ Graph_2_min, Graph_2_max]);

//etc...

但后来我设置了多个图表,结果都是一样的:


//For the sake of short code I skipped Viewbox, widht, height, classes, etc. here


var Graph_1 = d3.select("#Graph1")
              .append("svg")
              .append("g");

// add the X Axis Graph_1
Graph_1.append("g")
       .call( d3.axisBottom( GraphT_X )
            .ticks(d3.timeDay)
            .tickFormat(d3.timeFormat("%d.%m")));

// add the Y Axis Graph_1
Graph_1.append("g")
       .call( d3.axisLeft(Graph1_Y) // <--- Using first Y-Axis here
            .ticks(5, ".0f"));

var Graph_2 = d3.select("#Graph2")
              .append("svg")
              .append("g");

// add the X Axis Graph_1
Graph_2.append("g")
       .call( d3.axisBottom( GraphT_X )
            .ticks(d3.timeDay)
            .tickFormat(d3.timeFormat("%d.%m")));

// add the Y Axis Graph_2
Graph_2.append("g")
       .call( d3.axisLeft( Graph2_Y ) // <--- Using different/second Y-Axis here
            .ticks(8, ".0f"));

这看起来干净漂亮。但是浏览器总是呈现相同的图形,就好像 Graph1_Y 被我定义的 Graph2_Y.

覆盖了一样

它应该看起来像这样:

这可能不是 D3 中的错误,而是一些 javascript 继承。 任何人都知道如何在重用像 yAxisScaleLin 这样的比例变量时解决这个问题? 因为定义 10 倍以上的 Axis 范围在某种程度上不像我想要的代码那么清晰。

This seems as clean and pretty as it can get. But the browser always renders the same Graph, as if Graph1_Y gets overwritten as I define Graph2_Y

这正是您在这里所做的:

// Graphs have different Domains for Y
var Graph1_Y = yAxisScaleLin.domain([[ Graph_1_min, Graph_1_max]);
var Graph2_Y = yAxisScaleLin.domain([[ Graph_2_min, Graph_2_max]);

yAxisScaleLin.domain([values]) 既修改又 return 本身:yAxisScaleLin - 它不 return 一个新的比例对象。所以 Graph1_YGraph2_Y 都是对同一个比例对象的引用。

可能的解决方案

如果 .domain() returned 一个新的比例而不是调用它的相同比例,您的代码将工作,这是您假设会发生的情况。但是,有一种方法可以让您 return 基于现有比例的新比例对象:

 var graph1_Y = yAxisCaleLin.copy().domain(...

scale.copy() 方法 return 是调用它的比例的副本,包括其所有属性的副本。然后您可以将域设置为新值。

    var scale = d3.scaleLinear().range([0,1]); 
    
    var a = scale.copy().domain([0, 1]);
    var b = scale.copy().domain([2, 3]);
    
    console.log(a.domain().toString());
    console.log(b.domain().toString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>