D3自定义曲线:区域的束插值 [英] D3 custom curve: bundle interpolation for areas

查看:89
本文介绍了D3自定义曲线:区域的束插值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑使用基础插值的D3JS图形:

Consider this D3JS graph which uses a basis interpolation:

在D3JS v3中,我可以在区域上使用 bundle 插值(.interpolate("bundle").tension(0))来实现这种类型的渲染:

In D3JS v3, I could use bundle interpolation (.interpolate("bundle").tension(0)) on areas to achieve this type of rendering instead:

请注意,图的各段如何与其邻域很好地吻合.这就是我所需要的.

Notice how each segment of the graph fits nicely with its neighbors. This is what I need.

对于D3JS v4和v5,捆绑插值的语法现在为:.curve(d3.curveBundle).但是,现在它是旨在用于d3.line,而不是d3 .area."

With D3JS v4 and v5, the syntax for bundle interpolation is now this: .curve(d3.curveBundle). However, it's now "intended to work with d3.line, not d3.area."

我最近从v3升级到v5,因此,我尝试创建自定义束曲线,该曲线也适用于区域,以保持我在v3上喜欢的插值类型.

I recently upgraded from v3 to v5, and so I'm trying to create a custom bundle curve that will work with areas too, to keep the interpolation type I enjoyed with v3.

我很近.这是我到目前为止的内容:

I'm very close. This is what I have so far:

///////////////////// Custom curves.

/** Bundle-ish.
 * Trying to adapt curveBundle for use with areas…
 */
function myBundle(context, beta) {
	this._basis = new d3.curveBasis(context);
	this._beta = beta;

	this._context = context; // temporary. shouldn't be needed for bundle.
}
myBundle.prototype = {

	areaStart: function() {
		this._line = 0;
	},
	areaEnd: function() {
		this._line = NaN;
	},
	lineStart: function() {
		this._x = [];
		this._y = [];
		this._basis.lineStart();
	},
	lineEnd: function() {
		var x = this._x,
				y = this._y,
				j = x.length - 1;

		if (j > 0) {
			var x0 = x[0],
					y0 = y[0],
					dx = x[j] - x0,
					dy = y[j] - y0,
					i = -1,
					t;

			while (++i <= j) {
				t = i / j;
				this._basis.point(
					this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),
					this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)
				);
			}
		}

		this._x = this._y = null;
		this._basis.lineEnd();
	},
	point: function(x, y) {
		this._x.push(+x);
		this._y.push(+y);
		// console.log( this._x.push(+x), this._y.push(+y) );
	}
};
myCurveBundle = (function custom(beta) {
	function myCurveBundle(context) {
		return beta === 1 ? new myBasis(context) : new myBundle(context, beta);
	}

	myCurveBundle.beta = function(beta) {
		return custom(+beta);
	};

	return myCurveBundle;
})(0.85);






///////////////////// The chart.

	var width = 960;
	var height = 540;
	var data = [];
	data.prosody = [116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.578, 125.552, 134.888, 144.225, 153.561, 162.898, 172.235, 181.571, 190.908, 200.244, 209.581, 218.917, 227.715, 218.849, 209.591, 200.333, 191.076, 181.818, 172.560, 163.302, 154.044, 144.787, 135.529, 126.271, 117.013, 107.755, 98.498, 89.240, 97.511, 118.857, 140.202, 161.547, 182.893, 192.100, 188.997, 185.895, 182.792, 179.690, 176.587, 173.485, 170.382, 167.280, 164.177, 161.075, 157.972, 154.870, 151.767, 148.665, 145.562, 142.460, 139.357, 136.255, 133.152, 130.050, 126.947, 124.244, 122.275, 120.307, 118.338, 116.369, 114.400, 112.431, 110.462, 108.493, 106.524, 104.555, 102.586, 100.617, 98.648, 99.659, 101.531, 103.402, 105.273, 107.145, 109.016, 110.887, 112.758, 114.630, 116.501, 118.372, 120.244, 122.115, 123.986, 125.857, 127.729, 129.600, 131.471, 133.343, 135.214, 137.085, 138.956, 140.828, 142.699, 144.570, 146.442, 148.313, 150.184, 149.175, 146.384, 143.594, 140.803, 138.013, 135.222, 132.432, 129.642, 126.851, 124.061, 121.270, 118.480, 115.689, 112.899, 110.109, 107.318, 104.528, 101.737, 98.947, 96.156, 93.366, 90.576, 87.785, 84.995, 82.204, 79.414, 76.623, 0, 0, 0, 0, 0, 0, 76.601, 78.414, 80.227, 82.041, 83.854, 85.667, 87.480, 89.294, 91.107, 92.920, 94.733, 96.547, 98.360, 100.173, 101.986, 103.800, 105.613, 107.426, 109.239, 111.053, 112.866, 114.679, 116.492, 115.917, 114.338, 112.760, 111.181, 109.602, 108.023, 106.444, 104.865, 103.286, 101.707, 100.128, 98.549, 96.970, 95.391, 93.812, 92.233, 90.654, 89.075, 87.534, 88.055, 88.646, 89.237, 89.827, 90.418, 91.009, 91.600, 92.191, 92.782, 93.373, 93.964, 94.555, 95.146, 95.737, 96.328, 96.919, 97.509, 98.100, 98.691, 99.282, 99.873, 100.062, 98.230, 96.399, 94.567, 92.736, 90.904, 89.072, 87.241, 85.409, 83.578, 81.746, 79.914, 78.083, 78.839, 80.880, 82.922, 84.964, 87.006, 89.048, 91.090, 93.132, 95.174, 97.216, 99.257, 101.299, 103.341, 105.383, 107.425, 109.467, 111.509, 113.551, 112.633, 110.755, 108.877, 106.999, 105.121, 103.243, 101.365, 99.487, 97.609, 95.731, 93.853, 91.975, 90.097, 88.219, 86.341, 84.463, 82.585, 80.707, 78.829, 76.951, 78.067, 81.290, 84.513, 87.736, 90.958, 94.181, 97.404, 100.627, 103.849, 107.072, 110.295, 113.517, 116.740, 119.963, 123.186, 126.408, 129.631, 132.854, 136.077, 139.299, 142.522, 145.745, 148.968, 152.190, 155.413, 154.840, 152.899, 150.958, 149.017, 147.076, 145.135, 143.194, 141.253, 139.312, 137.371, 135.429, 133.488, 131.547, 129.606, 127.665, 125.724, 124.874, 126.734, 128.594, 130.454, 132.314, 134.174, 136.034, 137.894, 139.754, 141.614, 143.474, 145.334, 147.194, 149.054, 150.914, 152.774, 154.634, 156.494, 158.354, 160.214, 162.074, 163.934, 165.664, 161.795, 157.761, 153.726, 149.692, 145.658, 141.624, 137.589, 133.555, 129.521, 125.487, 121.452, 117.418, 113.384, 109.350, 105.316, 101.281, 97.247, 93.213, 89.179, 85.144, 81.110, 77.076, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
	data.TextGrid = {  "phone" : [ /** segment type, beginning, and end of each segment **/ [ "sp", 0.0124716553288, 0.271882086168 ], [ "M", 0.271882086168, 0.401587301587 ], [ "OW", 0.401587301587, 0.521315192744 ], [ "S", 0.521315192744, 0.660997732426 ], [ "T", 0.660997732426, 0.710884353741 ], [ "AH", 0.710884353741, 0.760770975057 ], [ "V", 0.760770975057, 0.820634920635 ], [ "DH", 0.820634920635, 0.860544217687 ], [ "IY", 0.860544217687, 0.940362811791 ], [ "AH", 0.940362811791, 0.980272108844 ], [ "D", 0.980272108844, 1.04013605442 ], [ "V", 1.04013605442, 1.10997732426 ], [ "EH", 1.10997732426, 1.21972789116 ], [ "N", 1.21972789116, 1.289569161 ], [ "CH", 1.289569161, 1.42925170068 ], [ "ER", 1.42925170068, 1.51904761905 ], [ "Z", 1.51904761905, 1.57891156463 ], [ "R", 1.57891156463, 1.66870748299 ], [ "AH", 1.66870748299, 1.69863945578 ], [ "K", 1.69863945578, 1.75850340136 ], [ "AO", 1.75850340136, 1.88820861678 ], [ "R", 1.88820861678, 1.91814058957 ], [ "D", 1.91814058957, 1.95804988662 ], [ "AH", 1.95804988662, 1.99795918367 ], [ "D", 1.99795918367, 2.07777777778 ], [ "AH", 2.07777777778, 2.10770975057 ], [ "N", 2.10770975057, 2.18752834467 ], [ "DH", 2.18752834467, 2.22743764172 ], [ "AH", 2.22743764172, 2.2873015873 ], [ "S", 2.2873015873, 2.42698412698 ], [ "B", 2.42698412698, 2.51678004535 ], [ "UH", 2.51678004535, 2.68639455782 ], [ "K", 2.68639455782, 2.79614512472 ], [ "sp", 2.79614512472, 2.81609977324 ], [ "R", 2.81609977324, 2.95578231293 ], [ "IY", 2.95578231293, 3.00566893424 ], [ "L", 3.00566893424, 3.09546485261 ], [ "IY", 3.09546485261, 3.23514739229 ], [ "AH", 3.23514739229, 3.27505668934 ], [ "K", 3.27505668934, 3.41473922902 ], [ "ER", 3.41473922902, 3.68412698413 ], [ "D", 3.68412698413, 3.75396825397 ], [ "sp", 3.75396825397, 4.01337868481 ] ] }


	/**
	 * Set up D3JS
	 */
	var x = d3.scaleLinear()
		.domain([0, 401])
		.range([0, width]);
	var y = d3.scaleLinear()
		.domain([0, 800])
		.range([height, 0]);

	/** Center the stream vertically **/
	var shift = d3.scaleLinear()
		.domain([0, 0])
		.range([-height/2, 0]);

	/** Draw a stream segment **/
	var pathGenerator = d3.area()
		.curve( myCurveBundle.beta(0) )
		.x(function(d, i) { return x(i); })
		.y1(function(d) { return y(d + 72 ); }) /** 72 is just some arbitrary thickess given to the graph **/
		.y0(function(d) { return y(d); });

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



	/**
	 * Render the chart
	 */
	
	/** Draw the stream, on a per-segment basis **/
	var path = svg.selectAll("path")
		.data(data.TextGrid.phone)
		.enter().append("path")
			.attr("transform", function(d, i) { return "translate(" + x(Math.floor(d[1]*100)) + ", " + shift(i) + ")"; })
			.attr("class", function(d) { return "segment " + d[0]; })
			.on('click', function(d, i) { playFromTo(Math.floor(d[1] * 1000), Math.floor(d[2] * 1000)); })
			.attr("d", function(d) { return pathGenerator(data.prosody.slice( Math.floor(d[1]*100), Math.floor(d[2]*100)+1)); });

.segment { fill: #ccc; }
.segment.sp { display: none; }

/** Adapted from Margaret Horrigan for American English **/
.segment.IY { fill: #7AC141; }
.segment.IH { fill: #F9C5DC; }
.segment.UH { fill: #FF00FF; }
.segment.UW { fill: #0153A5; }
.segment.EY { fill: #8B8C90; }
.segment.EH { fill: #E61A25; }
.segment.AX { fill: #DF5435; }
.segment.ER { fill: #805EAA; }
.segment.AO { fill: #E2A856; }
.segment.OY { fill: #2E3094; }
.segment.OW { fill: #FC2B1C; }
.segment.AE { fill: #21201E; }
.segment.AH { fill: #DF5435; }
.segment.AA { fill: #bf181f; }
.segment.AY { fill: #FFFFFF; }
.segment.AW { fill: #7C4540; }

<script src="https://cdn.jsdelivr.net/npm/d3@5.4.0/dist/d3.min.js"></script>

(捆绑包代码改编自 bundle.js d3形状.)

(The bundle code is adapted from bundle.js in d3-shape.)

我很接近:如果您检查SVG,即使没有显示任何内容,您也会看到实际上确实创建了路径.

I'm very close: if you inspect the SVG, you'll see that, even though nothing is shown, paths actually do get created.

如果查看第一个可见"段(类segment M),您会发现它在中间某处包含 move 命令.

If you look at the first "visible" segment (class segment M) you'll see that it contains a move command somewhere in the middle:

M31.122194513715712,398.532825

如果我将其重命名为行命令,如下所示:

If I rename it to a line command, like so:

L31.122194513715712,398.532825

...然后该细分将显示.

…then that segment will show.

我对定制曲线的哪一部分负责感到困惑. 如何将M变成L?

I'm confused as to which part of the custom curve is responsible for that. How can I turn that M into an L?

生成的路径也恰好缺少最终Z.我该如何处理?

The resulting paths also happen to lack final Zs. How would I go about handling that?

关于D3JS中的自定义曲线,我没有找到太多帮助.欢迎任何帮助.

I haven't found much help regarding custom curves in D3JS. Any help is welcome.

推荐答案

调用areaStartareaEnd:

您似乎已经将areaStartareaEnd函数从d3.curveBasis复制到了自定义曲线中,该曲线主要是从d3.curveBundle绘制的.

Calling areaStart and areaEnd:

It looks like you've copied the areaStart and areaEnd functions from d3.curveBasis into your custom curve, which is mainly drawn from d3.curveBundle.

您不能只是将代码从d3.curveBasis复制到d3.curveBundle,因为this指的是不同的东西. this._basis(您的d3.curveBasis实例)无法访问this._line(它期望用于areaStartareaEnd的变量,并且可以通过您的customBundle访问).

You can't just copy the code from d3.curveBasis into d3.curveBundle because this refers to different things. this._basis (your instance of d3.curveBasis) can not access this._line (the variable it expects for areaStart and areaEnd, and is accessible via your customBundle).

您可以将this._line更改为this._basis._line,但是如果您注意到,d3.curveBundle中的所有行函数都调用它们各自的this._basis函数(例如lineStart调用this._basis.lineStart()).如果您在此处执行相同操作,则应等效:

You could change this._line to this._basis._line, but if you notice, all the line functions in d3.curveBundle call their respective this._basis functions (e.g. lineStart calls this._basis.lineStart()). If you do the same here it should be equivalent:

areaStart: {
    // this._basis._line = 0; // this should work, for now
    this._basis.areaStart(); // but this makes more sense semantically
},
areaEnd: {
    // this._basis._line = NaN; // this should work, for now
    this._basis.areaEnd(); // but this makes more sense semantically
}

这样做的另一个好处是,如果d3.curveBasis将来更改其实现,那么兼容的可能性就更大.

The added benefit of doing things this way is that if d3.curveBasis changes its implementation in the future, this has a higher chance of being compatible.

作为旁注,在构造函数中,使用new运算符创建this._basis的新实例:

As a side note, in your constructor you create a new instance of this._basis using the new operator:

this._basis = new d3.curveBasis(context);

通过newBasis构造函数在d3模块内部使用,但是在捆绑的库中,它是一个函数构造函数.可以是:

The Basis constructor via new is used internally in the d3 modules, but in the bundled library, it's a functional constructor. It can just be:

this._basis = d3.curveBasis(context);

尽管使用new似乎没有破坏任何东西.有关更多信息,请参见 https://stackoverflow.com/a/9468106/6184972 .

Though using new doesn't seem to be breaking anything. See https://stackoverflow.com/a/9468106/6184972 for more information.

您注意到,d3.curveBundle打算与d3.line一起使用,而不是与d3.area一起使用".值得一问的是,是否应该使用curveBundle渲染区域,因为忽略似乎是有意的.来自 https://github.com/d3/d3-shape/issues/70,@ mbostock写道:

As you note, d3.curveBundle is "intended to work with d3.line, not d3.area." It should be worth asking whether you should be using curveBundle to render areas, since the omission seems deliberate. From https://github.com/d3/d3-shape/issues/70, @mbostock writes:

正确的d3.curveBundle仅用于d3.line.它的 用于分层边缘捆绑,而不用于渲染区域.

Correct, d3.curveBundle is only intended to work with d3.line. It’s for hierarchical edge bundling, not for rendering areas.

另请参见 https://github.com/d3/d3-shape#curveBundle.

您可能应该将curveBundle与其他插值方法进行比较,以查看使用它是否会误导您的区域.

You should probably compare to curveBundle with other interpolation methods to see whether using it distorts your area in a misleading manner.

所有这些更改都可以在此小提琴中看到: https://jsfiddle.net/g4ya2qso/

All together, the changes can be seen in this fiddle: https://jsfiddle.net/g4ya2qso/

或者,由于功能非常类似于d3.curveBundle,因此您可以为.areaStart.areaEnd添加方法,并省略所有其他自定义代码,如下所示:

Alternatively, since the functionality resembles d3.curveBundle so much, you can just add methods for .areaStart and .areaEnd, and omit all of the other custom code, like so:

var myCurveBundle = (function custom(beta) {
    function myCustomBundle(context) {
      var bundle = d3.curveBundle.beta(beta)(context);
      bundle.areaStart = function () {
        bundle._basis.areaStart();
      };
      bundle.areaEnd = function () {
        bundle._basis.areaEnd();
      };
      return bundle;
    }
    myCustomBundle.beta = function(newBeta) {
      return custom(+newBeta);
    };
    return myCustomBundle;
})(0.85);

///////////////////// Custom curves.

/** Bundle-ish.
 * Trying to adapt curveBundle for use with areas…
 */
var myCurveBundle = (function custom(beta) {
  function myCustomBundle(context) {
    var bundle = d3.curveBundle.beta(beta)(context);
    bundle.areaStart = function () {
      bundle._basis.areaStart();
    };
    bundle.areaEnd = function () {
      bundle._basis.areaEnd();
    };
    return bundle;
  }
  myCustomBundle.beta = function(newBeta) {
    return custom(+newBeta);
  };
  return myCustomBundle;
})(0.85);

///////////////////// The chart.

	var width = 960;
	var height = 540;
	var data = [];
	data.prosody = [116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.473, 116.578, 125.552, 134.888, 144.225, 153.561, 162.898, 172.235, 181.571, 190.908, 200.244, 209.581, 218.917, 227.715, 218.849, 209.591, 200.333, 191.076, 181.818, 172.560, 163.302, 154.044, 144.787, 135.529, 126.271, 117.013, 107.755, 98.498, 89.240, 97.511, 118.857, 140.202, 161.547, 182.893, 192.100, 188.997, 185.895, 182.792, 179.690, 176.587, 173.485, 170.382, 167.280, 164.177, 161.075, 157.972, 154.870, 151.767, 148.665, 145.562, 142.460, 139.357, 136.255, 133.152, 130.050, 126.947, 124.244, 122.275, 120.307, 118.338, 116.369, 114.400, 112.431, 110.462, 108.493, 106.524, 104.555, 102.586, 100.617, 98.648, 99.659, 101.531, 103.402, 105.273, 107.145, 109.016, 110.887, 112.758, 114.630, 116.501, 118.372, 120.244, 122.115, 123.986, 125.857, 127.729, 129.600, 131.471, 133.343, 135.214, 137.085, 138.956, 140.828, 142.699, 144.570, 146.442, 148.313, 150.184, 149.175, 146.384, 143.594, 140.803, 138.013, 135.222, 132.432, 129.642, 126.851, 124.061, 121.270, 118.480, 115.689, 112.899, 110.109, 107.318, 104.528, 101.737, 98.947, 96.156, 93.366, 90.576, 87.785, 84.995, 82.204, 79.414, 76.623, 0, 0, 0, 0, 0, 0, 76.601, 78.414, 80.227, 82.041, 83.854, 85.667, 87.480, 89.294, 91.107, 92.920, 94.733, 96.547, 98.360, 100.173, 101.986, 103.800, 105.613, 107.426, 109.239, 111.053, 112.866, 114.679, 116.492, 115.917, 114.338, 112.760, 111.181, 109.602, 108.023, 106.444, 104.865, 103.286, 101.707, 100.128, 98.549, 96.970, 95.391, 93.812, 92.233, 90.654, 89.075, 87.534, 88.055, 88.646, 89.237, 89.827, 90.418, 91.009, 91.600, 92.191, 92.782, 93.373, 93.964, 94.555, 95.146, 95.737, 96.328, 96.919, 97.509, 98.100, 98.691, 99.282, 99.873, 100.062, 98.230, 96.399, 94.567, 92.736, 90.904, 89.072, 87.241, 85.409, 83.578, 81.746, 79.914, 78.083, 78.839, 80.880, 82.922, 84.964, 87.006, 89.048, 91.090, 93.132, 95.174, 97.216, 99.257, 101.299, 103.341, 105.383, 107.425, 109.467, 111.509, 113.551, 112.633, 110.755, 108.877, 106.999, 105.121, 103.243, 101.365, 99.487, 97.609, 95.731, 93.853, 91.975, 90.097, 88.219, 86.341, 84.463, 82.585, 80.707, 78.829, 76.951, 78.067, 81.290, 84.513, 87.736, 90.958, 94.181, 97.404, 100.627, 103.849, 107.072, 110.295, 113.517, 116.740, 119.963, 123.186, 126.408, 129.631, 132.854, 136.077, 139.299, 142.522, 145.745, 148.968, 152.190, 155.413, 154.840, 152.899, 150.958, 149.017, 147.076, 145.135, 143.194, 141.253, 139.312, 137.371, 135.429, 133.488, 131.547, 129.606, 127.665, 125.724, 124.874, 126.734, 128.594, 130.454, 132.314, 134.174, 136.034, 137.894, 139.754, 141.614, 143.474, 145.334, 147.194, 149.054, 150.914, 152.774, 154.634, 156.494, 158.354, 160.214, 162.074, 163.934, 165.664, 161.795, 157.761, 153.726, 149.692, 145.658, 141.624, 137.589, 133.555, 129.521, 125.487, 121.452, 117.418, 113.384, 109.350, 105.316, 101.281, 97.247, 93.213, 89.179, 85.144, 81.110, 77.076, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
	data.TextGrid = {  "phone" : [ /** segment type, beginning, and end of each segment **/ [ "sp", 0.0124716553288, 0.271882086168 ], [ "M", 0.271882086168, 0.401587301587 ], [ "OW", 0.401587301587, 0.521315192744 ], [ "S", 0.521315192744, 0.660997732426 ], [ "T", 0.660997732426, 0.710884353741 ], [ "AH", 0.710884353741, 0.760770975057 ], [ "V", 0.760770975057, 0.820634920635 ], [ "DH", 0.820634920635, 0.860544217687 ], [ "IY", 0.860544217687, 0.940362811791 ], [ "AH", 0.940362811791, 0.980272108844 ], [ "D", 0.980272108844, 1.04013605442 ], [ "V", 1.04013605442, 1.10997732426 ], [ "EH", 1.10997732426, 1.21972789116 ], [ "N", 1.21972789116, 1.289569161 ], [ "CH", 1.289569161, 1.42925170068 ], [ "ER", 1.42925170068, 1.51904761905 ], [ "Z", 1.51904761905, 1.57891156463 ], [ "R", 1.57891156463, 1.66870748299 ], [ "AH", 1.66870748299, 1.69863945578 ], [ "K", 1.69863945578, 1.75850340136 ], [ "AO", 1.75850340136, 1.88820861678 ], [ "R", 1.88820861678, 1.91814058957 ], [ "D", 1.91814058957, 1.95804988662 ], [ "AH", 1.95804988662, 1.99795918367 ], [ "D", 1.99795918367, 2.07777777778 ], [ "AH", 2.07777777778, 2.10770975057 ], [ "N", 2.10770975057, 2.18752834467 ], [ "DH", 2.18752834467, 2.22743764172 ], [ "AH", 2.22743764172, 2.2873015873 ], [ "S", 2.2873015873, 2.42698412698 ], [ "B", 2.42698412698, 2.51678004535 ], [ "UH", 2.51678004535, 2.68639455782 ], [ "K", 2.68639455782, 2.79614512472 ], [ "sp", 2.79614512472, 2.81609977324 ], [ "R", 2.81609977324, 2.95578231293 ], [ "IY", 2.95578231293, 3.00566893424 ], [ "L", 3.00566893424, 3.09546485261 ], [ "IY", 3.09546485261, 3.23514739229 ], [ "AH", 3.23514739229, 3.27505668934 ], [ "K", 3.27505668934, 3.41473922902 ], [ "ER", 3.41473922902, 3.68412698413 ], [ "D", 3.68412698413, 3.75396825397 ], [ "sp", 3.75396825397, 4.01337868481 ] ] }

	/**
	 * Set up D3JS
	 */
	var x = d3.scaleLinear()
		.domain([0, 401])
		.range([0, width]);
	var y = d3.scaleLinear()
		.domain([0, 800])
		.range([height, 0]);

	/** Center the stream vertically **/
	var shift = d3.scaleLinear()
		.domain([0, 0])
		.range([-height/2, 0]);

	/** Draw a stream segment **/
	var pathGenerator = d3.area()
		.curve( myCurveBundle.beta(0) )
		.x(function(d, i) { return x(i); })
		.y1(function(d) { return y(d + 72 ); }) /** 72 is just some arbitrary thickess given to the graph **/
		.y0(function(d) { return y(d); });

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

	/**
	 * Render the chart
	 */
	
	/** Draw the stream, on a per-segment basis **/
	var path = svg.selectAll("path")
		.data(data.TextGrid.phone)
		.enter().append("path")
			.attr("transform", function(d, i) { return "translate(" + x(Math.floor(d[1]*100)) + ", " + shift(i) + ")"; })
			.attr("class", function(d) { return "segment " + d[0]; })
			.on('click', function(d, i) { playFromTo(Math.floor(d[1] * 1000), Math.floor(d[2] * 1000)); })
			.attr("d", function(d) { return pathGenerator(data.prosody.slice( Math.floor(d[1]*100), Math.floor(d[2]*100)+1)); });

.segment { fill: #ccc; }
.segment.sp { display: none; }

/** Adapted from Margaret Horrigan for American English **/
.segment.IY { fill: #7AC141; }
.segment.IH { fill: #F9C5DC; }
.segment.UH { fill: #FF00FF; }
.segment.UW { fill: #0153A5; }
.segment.EY { fill: #8B8C90; }
.segment.EH { fill: #E61A25; }
.segment.AX { fill: #DF5435; }
.segment.ER { fill: #805EAA; }
.segment.AO { fill: #E2A856; }
.segment.OY { fill: #2E3094; }
.segment.OW { fill: #FC2B1C; }
.segment.AE { fill: #21201E; }
.segment.AH { fill: #DF5435; }
.segment.AA { fill: #bf181f; }
.segment.AY { fill: #FFFFFF; }
.segment.AW { fill: #7C4540; }

<script src="https://cdn.jsdelivr.net/npm/d3@5.4.0/dist/d3.min.js"></script>

这篇关于D3自定义曲线:区域的束插值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆