如何填充d3.js中两行x段之间的区域?

时间:2017-11-30 12:06:59

标签: d3.js

我对d3很新,目前正在制作多线图表(在angular2 / typescript中)。 基础数据是离散的,但线条是使用curveMonotoneX弯曲的。

this.x = d3Scale.scaleLinear().range([0, this.width]);
this.y = d3Scale.scaleLinear().range([this.height, 0]);
this.line = d3Shape.line()
        .curve(d3Shape.curveMonotoneX)
        .x( (d: any) => this.x(d.x) )
        .y( (d: any) => this.y(d.y) );

我的目标是,每当它悬停时,填充当前x段(两个离散x值之间的段)的两行之间的区域,如下所示: Area between two lines

不幸的是,我找不到一种方法来绘制与curveMonotoneX仅为此特定线段创建的曲线相同的曲线。 如果我仅使用两个x值的数据绘制一条线,那么该线不会像预期的那样弯曲,而只是线性的,因为曲线也整合了相邻的点,现在也没有了。

到目前为止,我最好的尝试是存储this.line(data)的输出字符串,并根据this.x(data)的限制x坐标手动查找正确的子字符串。但是,由于路径字符串由多个命令组成,这些命令具有不同数量的参数'总是找到正确的子串indeces非常困难。

所以问题是:

  • 在两条线之间填充区域的最佳方法是什么?段?
  • 如何获得与原始线完全相同的线段?是否必须手动提取或有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

这是一个使用linearGradient的示例,其中的函数可以找到给定x坐标的y坐标。具有0不透明度的矩形捕获鼠标事件以显示和更新linearGradients的停靠点和线坐标

https://bl.ocks.org/tomshanley/01a87c81b5ed86b6d55e566403c175ba

创建一个区域形状,其中y0和y1函数使用两条线中的y值。

#setup.py

from distutils.core import setup
import py2exe

setup(
    windows = [
        {
            "script": "MainFile.py",
            "icon_resources": [(1, "myicon.ico")]
        }
    ],
options={
        "py2exe":
        {
            "dll_excludes" : ["MSVCP90.dll"],
            "includes": ['encodings', 'encodings.*']
        }
        }
)

区域的填充设置为linearGradient,其具有使用mousemove事件更新的“stop”。停止的百分比处于设定状态,以便白色和灰色突然改变,以给出鼠标位置两侧的实心填充的印象。

let curve = d3.curveCatmullRom.alpha(0.5)

let area = d3.area()
    .x(function (d, i) { return xScale(i) })
    .y0(function (d) { return yScale(d.data1) })
    .y1(function (d) { return yScale(d.data2) })
    .curve(curve);

let line1 = d3.line()
    .x(function (d, i) { return xScale(i) })
    .y(function (d) { return yScale(d.data1) })
    .curve(curve);

let line2 = d3.line()
    .x(function (d, i) { return xScale(i) })
    .y(function (d) { return yScale(d.data2) })
    .curve(curve);

你的草图包括区域填充的每一侧的线条,我使用两条线条创建,y1和y2属性通过遍历每条路径来设置,直到你到达x坐标相同的点(或者只是大于)鼠标的x位置。

let x = d3.mouse(this)[0]
let middle = x / width

offset1 = (middle - 0.1) < 0 ? 0 : (middle - 0.1)
offset2 = (middle + 0.1) > 1 ? 1 : (middle + 0.1)

stopsData = [
      { "offset": 0, "stopColour": "#FFFFFF" },
      { "offset": offset1, "stopColour": "#FFFFFF" },
      { "offset": offset1, "stopColour": "#777777" },
      { "offset": offset2, "stopColour": "#777777" },
      { "offset": offset2, "stopColour": "#FFFFFF" },
      { "offset": 1, "stopColour": "#FFFFFF" }
 ]

gradient.selectAll("stop")
      .data(stopsData)
      .attr("offset", function (d) { return d.offset })
      .attr("stop-color", function (d) { return d.stopColour })