Skip to content

Commit

Permalink
feat(point): Intent to ship point.radialGradient
Browse files Browse the repository at this point in the history
Implement point.radialGradient option

Fix #3405
  • Loading branch information
netil committed Sep 7, 2023
1 parent 787fd15 commit 7b51fd6
Show file tree
Hide file tree
Showing 9 changed files with 340 additions and 33 deletions.
65 changes: 65 additions & 0 deletions demo/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -3946,6 +3946,71 @@ d3.select(".chart_area")
}
}
],
RadialGradientPoint: [
{
options: {
data: {
columns: [
["data1", 30, 200, 100, 400, 100, 250],
["data2", 130, 100, 130, 200, 150, 50]
],
type: "scatter"
},
point: {
r: 20,
radialGradient: true,
opacity: 1,
sensitivity: "radius"
},
axis: {
x: {
type: "category"
}
}
}
},
{
options: {
data: {
columns: [
["data1", 30, 200, 100, 400, 100, 250],
["data2", 130, 100, 130, 200, 150, 50]
],
type: "bubble"
},
point: {
r: 10,
radialGradient: {
cx: 0.5,
cy: 0.5,
r: 0.5,
stops: [
[0.3, "#fff", 0.8],
[0.6, "green", 0.35],
[1, null, 1]
]
},
opacity: 1,
sensitivity: "radius"
}
}
},
{
options: {
data: {
columns: [
["data1", 30, 200, 100, 400, 100, 250],
["data2", 130, 100, 130, 200, 150, 50]
],
type: "line"
},
point: {
r: 7,
radialGradient: true,
}
}
}
],
RectanglePoints: {
options: {
data: {
Expand Down
72 changes: 49 additions & 23 deletions src/ChartInternal/internals/color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,9 @@ export default {
},

/**
* Update linear gradient definition (for area & bar only)
* Update linear/radial gradient definition
* - linear: area & bar only
* - radial: type which has data points only
* @private
*/
updateLinearGradient(): void {
Expand All @@ -213,31 +215,55 @@ export default {

targets.forEach(d => {
const id = `${datetimeId}-gradient${$$.getTargetSelectorSuffix(d.id)}`;
const radialGradient = $$.hasPointType() && config.point_radialGradient;
const supportedType = ($$.isAreaType(d) && "area") || ($$.isBarType(d) && "bar");
const isRotated = config.axis_rotated;

if (supportedType && defs.select(`#${id}`).empty()) {
if ((radialGradient || supportedType) && defs.select(`#${id}`).empty()) {
const color = $$.color(d);
const {
x = isRotated ? [1, 0] : [0, 0],
y = isRotated ? [0, 0] : [0, 1],
stops = [[0, color, 1], [1, color, 0]]
} = config[`${supportedType}_linearGradient`];

const linearGradient = defs.append("linearGradient")
.attr("id", `${id}`)
.attr("x1", x[0])
.attr("x2", x[1])
.attr("y1", y[0])
.attr("y2", y[1]);

stops.forEach(v => {
const stopColor = isFunction(v[1]) ? v[1].bind($$.api)(d.id) : v[1];

linearGradient.append("stop")
.attr("offset", v[0])
.attr("stop-color", stopColor || color)
.attr("stop-opacity", v[2]);
const gradient = {
defs: <null|d3Selection>null,
stops: <[number, string|Function|null, number][]>[]
};

if (radialGradient) {
const {
cx = 0.3,
cy = 0.3,
r = 0.7,
stops = [[0.1, color, 0], [0.9, color, 1]]
} = radialGradient;

gradient.stops = stops;
gradient.defs = defs.append("radialGradient")
.attr("id", `${id}`)
.attr("cx", cx)
.attr("cy", cy)
.attr("r", r);
} else {
const isRotated = config.axis_rotated;
const {
x = isRotated ? [1, 0] : [0, 0],
y = isRotated ? [0, 0] : [0, 1],
stops = [[0, color, 1], [1, color, 0]]
} = config[`${supportedType}_linearGradient`];

gradient.stops = stops;
gradient.defs = defs.append("linearGradient")
.attr("id", `${id}`)
.attr("x1", x[0])
.attr("x2", x[1])
.attr("y1", y[0])
.attr("y2", y[1]);
}

gradient.stops.forEach((v: [number, string|Function|null, number]) => {
const [offset, stopColor, stopOpacity] = v;
const colorValue = isFunction(stopColor) ? stopColor.bind($$.api)(d.id) : stopColor;

gradient.defs && gradient.defs.append("stop")
.attr("offset", offset)
.attr("stop-color", colorValue || color)
.attr("stop-opacity", stopOpacity);
});
}
});
Expand Down
20 changes: 18 additions & 2 deletions src/ChartInternal/shape/point.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ export default {
const $root = isSub ? $el.subchart : $el;

if (config.point_show && !state.toggling) {
config.point_radialGradient && $$.updateLinearGradient();

const circles = $root.main.selectAll(`.${$CIRCLE.circles}`)
.selectAll(`.${$CIRCLE.circle}`)
.data(d => (
Expand All @@ -142,14 +144,28 @@ export default {

circles.enter()
.filter(Boolean)
.append($$.point("create", this, $$.pointR.bind($$), $$.getStylePropValue($$.color)));
.append($$.point("create", this, $$.pointR.bind($$), $$.updateCircleColor.bind($$)));

$root.circle = $root.main.selectAll(`.${$CIRCLE.circles} .${$CIRCLE.circle}`)
.style("stroke", $$.getStylePropValue($$.color))
.style("opacity", $$.initialOpacityForCircle.bind($$));
}
},

/**
* Update circle color
* @param {object} d Data object
* @returns {string} Color string
* @private
*/
updateCircleColor(d: IDataRow): string {
const $$ = this;
const fn = $$.getStylePropValue($$.color);

return $$.config.point_radialGradient ?
$$.getGradienColortUrl(d.id) : (fn ? fn(d) : null);
},

redrawCircle(cx: Function, cy: Function, withTransition: boolean, flow, isSub = false) {
const $$ = this;
const {state: {rendered}, $el, $T} = $$;
Expand All @@ -160,7 +176,7 @@ export default {
return [];
}

const fn = $$.point("update", $$, cx, cy, $$.getStylePropValue($$.color), withTransition, flow, selectedCircles);
const fn = $$.point("update", $$, cx, cy, $$.updateCircleColor.bind($$), withTransition, flow, selectedCircles);
const posAttr = $$.isCirclePoint() ? "c" : "";

const t = getRandom();
Expand Down
41 changes: 41 additions & 0 deletions src/config/Options/common/point.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ export default {
* @property {boolean} [point.show=true] Whether to show each point in line.
* @property {number|Function} [point.r=2.5] The radius size of each point.
* - **NOTE:** Disabled for 'bubble' type
* @property {boolean|object} [point.radialGradient=false] Set the radial gradient on point.<br><br>
* Or customize by giving below object value:
* - cx {number}: `cx` value (default: `0.3`)
* - cy {number}: `cy` value (default: `0.3`)
* - r {number}: `r` value (default: `0.7`)
* - stops {Array}: Each item should be having `[offset, stop-color, stop-opacity]` values.
* - (default: `[[0.1, $DATA_COLOR, 1], [0.9, $DATA_COLOR, 0]]`)
* @property {boolean} [point.focus.expand.enabled=true] Whether to expand each point on focus.
* @property {number} [point.focus.expand.r=point.r*1.75] The radius size of each point on focus.
* - **NOTE:** For 'bubble' type, the default is `bubbleSize*1.15`
Expand Down Expand Up @@ -59,6 +66,7 @@ export default {
* (ex. `<polygon points='2.5 0 0 5 5 5'></polygon>`)
* @see [Demo: point type](https://naver.github.io/billboard.js/demo/#Point.RectanglePoints)
* @see [Demo: point focus only](https://naver.github.io/billboard.js/demo/#Point.FocusOnly)
* @see [Demo: point radialGradient](https://naver.github.io/billboard.js/demo/#Point.RadialGradientPoint)
* @see [Demo: point sensitivity](https://naver.github.io/billboard.js/demo/#Point.PointSensitivity)
* @example
* point: {
Expand All @@ -71,6 +79,32 @@ export default {
* return r;
* },
*
* // will generate follwing radialGradient:
* // for more info: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/radialGradient
* // <radualGradient cx="0.3" cy="0.3" r="0.7">
* // <stop offset="0.1" stop-color="$DATA_COLOR" stop-opacity="1"></stop>
* // <stop offset="0.9" stop-color="$DATA_COLOR" stop-opacity="0"></stop>
* // </radialrGradient>
* radialGradient: true,
*
* // Or customized gradient
* radialGradient: {
* cx: 0.3, // cx attributes
* cy: 0.5, // cy attributes
* r: 0.7, // r attributes
* stops: [
* // offset, stop-color, stop-opacity
* [0, "#7cb5ec", 1],
*
* // setting 'null' for stop-color, will set its original data color
* [0.5, null, 0],
*
* // setting 'function' for stop-color, will pass data id as argument.
* // It should return color string or null value
* [1, function(id) { return id === "data1" ? "red" : "blue"; }, 0],
* ]
* },
*
* focus: {
* expand: {
* enabled: true,
Expand Down Expand Up @@ -117,6 +151,13 @@ export default {
*/
point_show: true,
point_r: 2.5,
point_radialGradient: <
boolean | {
cx?: number;
cy?: number;
r?: number;
stops?: [number, string | null | Function, number]
}> false,
point_sensitivity: <number|"radius"|((d: IDataPoint) => number)> 10,
point_focus_expand_enabled: true,
point_focus_expand_r: <number|undefined> undefined,
Expand Down
14 changes: 10 additions & 4 deletions src/config/Options/shape/area.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ export default {
* @property {boolean} [area.front=true] Set area node to be positioned over line node.
* @property {boolean|object} [area.linearGradient=false] Set the linear gradient on area.<br><br>
* Or customize by giving below object value:
* - x {Array}: `x1`, `x2` value
* - y {Array}: `y1`, `y2` value
* - x {Array}: `x1`, `x2` value (default: `[0, 0]`)
* - y {Array}: `y1`, `y2` value (default: `[0, 1]`)
* - stops {Array}: Each item should be having `[offset, stop-color, stop-opacity]` values.
* - (default: `[[0, $DATA_COLOR, 1], [1, $DATA_COLOR, 0]]`)
* @property {boolean} [area.zerobased=true] Set if min or max value will be 0 on area chart.
* @see [MDN's &lt;linearGradient>](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient), [&lt;stop>](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/stop)
* @see [Demo](https://naver.github.io/billboard.js/demo/#Chart.AreaChart)
Expand All @@ -37,6 +38,7 @@ export default {
* front: false,
*
* // will generate follwing linearGradient:
* // for more info: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient
* // <linearGradient x1="0" x2="0" y1="0" y2="1">
* // <stop offset="0" stop-color="$DATA_COLOR" stop-opacity="1"></stop>
* // <stop offset="1" stop-color="$DATA_COLOR" stop-opacity="0"></stop>
Expand Down Expand Up @@ -65,7 +67,11 @@ export default {
area_below: false,
area_front: true,
area_linearGradient: <
boolean|{x?: number[]; y?: number[]; stops?: [number, string|Function|null, number]}
> false,
boolean | {
x?: [number, number];
y?:[number, number];
stops?: [number, string | null | Function, number]
}
> false,
area_zerobased: true
};
14 changes: 10 additions & 4 deletions src/config/Options/shape/bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ export default {
* @property {number} [bar.label.threshold=0] Set threshold ratio to show/hide labels.
* @property {boolean|object} [bar.linearGradient=false] Set the linear gradient on bar.<br><br>
* Or customize by giving below object value:
* - x {Array}: `x1`, `x2` value
* - y {Array}: `y1`, `y2` value
* - x {Array}: `x1`, `x2` value (default: `[0, 0]`)
* - y {Array}: `y1`, `y2` value (default: `[0, 1]`)
* - stops {Array}: Each item should be having `[offset, stop-color, stop-opacity]` values.
* - (default: `[[0, $DATA_COLOR, 1], [1, $DATA_COLOR, 0]]`)
* @property {boolean} [bar.overlap=false] Bars will be rendered at same position, which will be overlapped each other. (for non-grouped bars only)
* @property {number} [bar.padding=0] The padding pixel value between each bar.
* @property {number} [bar.radius] Set the radius of bar edge in pixel.
Expand Down Expand Up @@ -53,6 +54,7 @@ export default {
* },
*
* // will generate follwing linearGradient:
* // for more info: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient
* // <linearGradient x1="0" x2="0" y1="0" y2="1">
* // <stop offset="0" stop-color="$DATA_COLOR" stop-opacity="1"></stop>
* // <stop offset="1" stop-color="$DATA_COLOR" stop-opacity="0"></stop>
Expand Down Expand Up @@ -121,8 +123,12 @@ export default {
bar_indices_removeNull: false,
bar_label_threshold: 0,
bar_linearGradient: <
boolean|{x?: number[]; y?: number[]; stops?: [number, string|Function|null, number]}
> false,
boolean | {
x?: [number, number];
y?:[number, number];
stops?: [number, string | null | Function, number]
}
> false,
bar_overlap: false,
bar_padding: 0,
bar_radius: <number|{ratio: number}|undefined> undefined,
Expand Down
Loading

0 comments on commit 7b51fd6

Please sign in to comment.