Last active
June 6, 2019 08:56
-
-
Save kevinweber/bdcf28ec47de7cc8263de1ffa50b29a4 to your computer and use it in GitHub Desktop.
d3.js: Custom curve with rounded steps. Based on d3.curveStep.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Rounded step curve by Kevin Weber. Based on d3.curveStep. | |
* | |
* Configuration options: | |
* `distance`: Distance between two points that are connected by a bezier curve. Range: 0 to 1. Default: 0.5 | |
* `shift`: Shift the middle of the bezier curve along the x-axis. The range of the shift depends on the distance. If distance equals 0, the shift ranges from 0 to 1. Default: 0.5 | |
* `tilt`: Determines how steep the curve should be. 0 makes the bezier curve straight/diagonal while 1 makes it vertical in the middle. Range: 0 to 1. Default: 0.5 | |
*/ | |
export default class CustomCurve { | |
/** | |
* Constructor | |
* | |
* @param {object} context d3.js curve context | |
* @param {object} config Optional configuration | |
*/ | |
constructor(context, config) { | |
this.context = context; | |
this.config = { | |
distance: 0.5, // Range: 0 to 1 | |
shift: 0.5, // Range: (0 - distance) to (1 - distance) | |
tilt: 0.5, // Range: 0 to 1 | |
...config, | |
}; | |
this._t = this.config.shift; | |
} | |
areaStart() { | |
this._line = 0; | |
} | |
areaEnd() { | |
this._line = NaN; | |
} | |
lineStart() { | |
this._x = this._y = NaN; | |
this._point = 0; | |
} | |
lineEnd() { | |
if (0 < this._t && this._t < 1 && this._point === 2) this.context.lineTo(this._x, this._y); | |
if (this._line || (this._line !== 0 && this._point === 1)) this.context.closePath(); | |
if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line; | |
} | |
point(x, y) { | |
x = +x, y = +y; | |
switch (this._point) { | |
case 0: | |
this._point = 1; | |
this._line ? this.context.lineTo(x, y) : this.context.moveTo(x, y); | |
break; | |
case 1: | |
this._point = 2; // Proceed | |
default: | |
{ | |
if (this._t <= 0) { | |
this.context.lineTo(this._x, y); | |
this.context.lineTo(x, y); | |
} else { | |
const x1 = this._x * (1 - this._t) + x * this._t; | |
const pointOffset = (x - this._x) * (this.config.distance / 2); | |
const tilt = this.config.tilt; | |
const points = { | |
a: [x1 - pointOffset, this._y], // Point on left divider | |
// b: [x1, (this._y + (y - this._y) / 2)], // Point in between | |
c: [x1 + pointOffset, y], // Point on right divider | |
}; | |
const yDistance = points.c[1] - points.a[1]; | |
const xDistance = points.c[0] - points.a[0]; | |
const controlPoints = { | |
ab1: [points.a[0] + xDistance * tilt, points.a[1]], // Control point starting from poin on left divider | |
// ab2: [points.b[0], points.b[1] - yDistance * 0.5], // First control point starting from point in between | |
// bc1: [points.b[0], points.b[1] + yDistance * 0.5], // Second control point starting from point in between | |
bc2: [points.c[0] - xDistance * tilt, points.c[1]], // Control point starting from poin on right divider | |
}; | |
this.context.lineTo(...points.a); | |
this.context.bezierCurveTo(...controlPoints.ab1, ...controlPoints.bc2, ...points.c); | |
// NOTE: The following lines might be helpful in case we consider drawing two curves connected by the point in the middle (points.b) | |
// this.context.bezierCurveTo(...controlPoints.ab1, ...controlPoints.ab2, ...points.b); | |
// this.context.bezierCurveTo(...controlPoints.bc1, ...controlPoints.bc2, ...points.c); | |
} | |
break; | |
} | |
} | |
this._x = x, this._y = y; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import CurveStepRounded from './d3.curveStepRounded.js'; | |
... | |
// Instead of `d3.curveStep` add this function: | |
function (context) { | |
return new CurveStepRounded(context, { | |
distance: 0.9, | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment