Skip to content

Commit

Permalink
refactor(option): refactor useCssRule implementation
Browse files Browse the repository at this point in the history
- Split related methods to style.ts
- Expand applying to legend and Arc elements

Ref naver#2736
  • Loading branch information
netil committed Jun 23, 2022
1 parent cf60291 commit 97bdcd0
Show file tree
Hide file tree
Showing 12 changed files with 120 additions and 65 deletions.
13 changes: 2 additions & 11 deletions src/ChartInternal/ChartInternal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import redraw from "./internals/redraw";
import scale from "./internals/scale";
import shape from "./shape/shape";
import size from "./internals/size";
import style from "./internals/style";
import text from "./internals/text";
import title from "./internals/title";
import tooltip from "./internals/tooltip";
Expand Down Expand Up @@ -266,22 +267,11 @@ export default class ChartInternal {
const $$ = <any> this;
const {config, format, state} = $$;
const isRotated = config.axis_rotated;
const useCssRule = config.boost_useCssRule;

// color settings
$$.color = $$.generateColor();
$$.colorByRule = $$.color;
$$.colorTextByRule = $$.updateTextColor.bind($$);
$$.levelColor = $$.generateLevelColor();

if (useCssRule) {
state.colorRule = {};

// to not apply inline color setting
$$.colorByRule = null;
$$.colorTextByRule = null;
}

// when 'padding=false' is set, disable axes and subchart. Because they are useless.
if (config.padding === false) {
config.axis_x_show = false;
Expand Down Expand Up @@ -812,6 +802,7 @@ extend(ChartInternal.prototype, [
scale,
shape,
size,
style,
text,
title,
tooltip,
Expand Down
2 changes: 1 addition & 1 deletion src/ChartInternal/internals/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,5 @@ export default {
selectorLegends(ids): string[] | null {
return ids?.length ?
ids.map(id => this.selectorLegend(id)) : null;
},
}
};
26 changes: 1 addition & 25 deletions src/ChartInternal/internals/color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {scaleOrdinal as d3ScaleOrdinal} from "d3-scale";
import {document} from "../../module/browser";
import {$ARC, $COLOR, $SHAPE} from "../../config/classes";
import {KEY} from "../../module/Cache";
import {addCssRules, notEmpty, isFunction, isObject, isString} from "../../module/util";
import {notEmpty, isFunction, isObject, isString} from "../../module/util";
import {IArcData, IDataRow} from "../data/IData";
import {d3Selection} from "../../../types";

Expand Down Expand Up @@ -75,30 +75,6 @@ function getColorFromCss(element: d3Selection): string[] {
const schemeCategory10 = ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"];

export default {
/**
* Add props color css rule to given selector
* @param {Function} fn Color function
* @param {string} selector CSS selector
* @param {Array} props CSS props list
* @returns {Function}
* @private
*/
setColorByRule(fn: Function, selector: string, props: string[]): Function {
const $$ = this;
const {config, state: {colorRule, style}} = $$;
const colorFn = fn || $$.color;

return config.boost_useCssRule ? (selection: d3Selection) => {
selection.each((d: IDataRow) => {
const color = colorFn.call($$, d);
const shapeSelector = `${$SHAPE.shapes}${$$.getTargetSelectorSuffix(d.id)} .${selector}`;

(shapeSelector in colorRule) && style.sheet.deleteRule(colorRule[shapeSelector]);
$$.state.colorRule[shapeSelector] = addCssRules(style, shapeSelector, props.map(v => `${v}: ${color}`));
});
} : () => {};
},

generateColor(): Function {
const $$ = this;
const {$el, config} = $$;
Expand Down
27 changes: 21 additions & 6 deletions src/ChartInternal/internals/legend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,9 +370,10 @@ export default {
*/
setLegendItem(item): void {
const $$ = this;
const {api, config, state} = $$;
const {$el, api, config, state} = $$;
const isTouch = state.inputType === "touch";
const hasGauge = $$.hasType("gauge");
const useCssRule = config.boost_useCssRule;

item
.attr("class", function(id) {
Expand All @@ -384,8 +385,22 @@ export default {
.style("visibility", id => ($$.isLegendToShow(id) ? null : "hidden"));

if (config.interaction_enabled) {
if (useCssRule) {
[
[`.${$LEGEND.legendItem}`, "cursor:pointer"],
[`.${$LEGEND.legendItem} text`, "pointer-events:none"],
[`.${$LEGEND.legendItemPoint} text`, "pointer-events:none"],
[`.${$LEGEND.legendItemTile}`, "pointer-events:none"],
[`.${$LEGEND.legendItemEvent}`, "fill-opacity:0"]
].forEach(v => {
const [selector, props] = v;

$$.setCssRule(false, selector, [props])($el.legend);
});
}

item
.style("cursor", "pointer")
.style("cursor", $$.getStylePropValue("pointer"))
.on("click", function(event, id) {
if (!callFn(config.legend_item_onclick, api, id)) {
if (event.altKey) {
Expand Down Expand Up @@ -579,13 +594,13 @@ export default {
.each(function(id, i) {
updatePositions(this, id, i);
})
.style("pointer-events", "none")
.style("pointer-events", $$.getStylePropValue("none"))
.attr("x", isLegendRightOrInset ? xForLegendText : pos)
.attr("y", isLegendRightOrInset ? pos : yForLegendText);

l.append("rect")
.attr("class", $LEGEND.legendItemEvent)
.style("fill-opacity", "0")
.style("fill-opacity", $$.getStylePropValue("0"))
.attr("x", isLegendRightOrInset ? xForLegendRect : pos)
.attr("y", isLegendRightOrInset ? pos : yForLegendRect);

Expand Down Expand Up @@ -618,7 +633,7 @@ export default {
})
.attr("class", $LEGEND.legendItemPoint)
.style("fill", getColor)
.style("pointer-events", "none")
.style("pointer-events", $$.getStylePropValue("none"))
.attr("href", (data, idx, selection) => {
const node = selection[idx];
const nodeName = node.nodeName.toLowerCase();
Expand All @@ -630,7 +645,7 @@ export default {
l.append("line")
.attr("class", $LEGEND.legendItemTile)
.style("stroke", getColor)
.style("pointer-events", "none")
.style("pointer-events", $$.getStylePropValue("none"))
.attr("x1", isLegendRightOrInset ? x1ForLegendTile : pos)
.attr("y1", isLegendRightOrInset ? pos : yForLegendTile)
.attr("x2", isLegendRightOrInset ? x2ForLegendTile : pos)
Expand Down
54 changes: 54 additions & 0 deletions src/ChartInternal/internals/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Copyright (c) 2017 ~ present NAVER Corp.
* billboard.js project is licensed under the MIT license
*/
import {$SHAPE} from "../../config/classes";
import {d3Selection} from "../../../types/types";
import {IDataRow} from "../data/IData";
import {addCssRules, isFunction, isString} from "../../module/util";

export default {
/**
* Add props color css rule to given selector
* @param {boolean} withShape Set shpes' prefix class
* @param {string} selector CSS selector
* @param {Array} props CSS props list
* @param {Function} propsFn Function to retrieve value or determine for props
* @returns {Function}
* @private
*/
setCssRule(withShape: boolean, selector: string, props: string[], propsFn: Function): Function {
const $$ = this;
const {config, state: {cssRule, style}} = $$;

return config.boost_useCssRule ? (selection: d3Selection) => {
selection.each((d: IDataRow) => {
const res = propsFn && propsFn?.call($$, d);
const shapeSelector = `${
withShape ? `.${$SHAPE.shapes + $$.getTargetSelectorSuffix(d.id)}` : ""
}${selector}`;

(selector in cssRule) && style.sheet.deleteRule(cssRule[shapeSelector]);
$$.state.cssRule[shapeSelector] = addCssRules(
style,
shapeSelector,
props.filter(Boolean).map(v => (
isString(res) && v.indexOf(":") === -1 ? `${v}: ${res}` : (v || "")
))
);
});
} : () => {};
},

/**
* Get style prop value
* @param {Function|string} v Value
* @returns {string|null}
* @private
*/
getStylePropValue(v: Function|string): string|null {
const {config: {boost_useCssRule: useCssRule}} = this;

return useCssRule ? null : isFunction(v) ? v.bind(this) : v;
}
};
7 changes: 3 additions & 4 deletions src/ChartInternal/internals/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,7 @@ export default {
const mainTextEnter = mainTextUpdate.enter().append("g")
.style("opacity", "0")
.attr("class", classChartText)
.call($$.setColorByRule($$.updateTextColor, $TEXT.text, ["fill"]))
.style("pointer-events", "none");
.call($$.setCssRule(true, ` .${$TEXT.text}`, ["fill", "pointer-events:none"], $$.updateTextColor));

mainTextEnter.append("g")
.attr("class", classTexts);
Expand Down Expand Up @@ -167,7 +166,7 @@ export default {

return (config.axis_rotated ? (isEndAnchor ? "end" : "start") : "middle");
})
.style("fill", $$.colorTextByRule)
.style("fill", $$.getStylePropValue($$.updateTextColor))
.style("fill-opacity", "0")
.each(function(d, i, texts) {
const node = d3Select(this);
Expand Down Expand Up @@ -267,7 +266,7 @@ export default {
const rotateString = angle ? `rotate(${angle})` : "";

$$.$el.text
.style("fill", $$.colorTextByRule)
.style("fill", $$.getStylePropValue($$.updateTextColor))
.attr("filter", $$.updateTextBacgroundColor.bind($$))
.style("fill-opacity", forFlow ? 0 : $$.opacityForText.bind($$))
.each(function(d: IDataRow, i: number) {
Expand Down
7 changes: 4 additions & 3 deletions src/ChartInternal/shape/arc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,8 @@ export default {
.attr("class", d => classChartArc(d) + classFocus(d.data));

const mainPieEnter = mainPieUpdate.enter().append("g")
.attr("class", classChartArc);
.attr("class", classChartArc)
.call(this.setCssRule(false, `.${$ARC.chartArcs} text`, ["pointer-events:none", "text-anchor:middle"]));

mainPieEnter.append("g")
.attr("class", classArcs)
Expand All @@ -524,8 +525,8 @@ export default {
mainPieEnter.append("text")
.attr("dy", hasGauge && !$$.hasMultiTargets() ? "-.1em" : ".35em")
.style("opacity", "0")
.style("text-anchor", "middle")
.style("pointer-events", "none");
.style("text-anchor", $$.getStylePropValue("middle"))
.style("pointer-events", $$.getStylePropValue("none"));

$el.text = chartArcs.selectAll(`.${$COMMON.target} text`);
// MEMO: can not keep same color..., but not bad to update color in redraw
Expand Down
11 changes: 6 additions & 5 deletions src/ChartInternal/shape/bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export default {
$el.bar = $el.main.select(`.${$COMMON.chart}`)
// should positioned at the beginning of the shape node to not overlap others
.insert("g", ":first-child")
.attr("class", $BAR.chartBars);
.attr("class", $BAR.chartBars)
.call(this.setCssRule(false, `.${$BAR.chartBars}`, ["pointer-events:none"]));

// set clip-path attribute when condition meet
// https://github.com/naver/billboard.js/issues/2421
Expand Down Expand Up @@ -52,13 +53,13 @@ export default {
const mainBarEnter = mainBarUpdate.enter().append("g")
.attr("class", classChartBar)
.style("opacity", "0")
.style("pointer-events", "none");
.style("pointer-events", $$.getStylePropValue("none"));

// Bars for each data
mainBarEnter.append("g")
.attr("class", classBars)
.style("cursor", d => (isSelectable?.bind?.($$.api)(d) ? "pointer" : null))
.call($$.setColorByRule(null, $BAR.bar, ["fill"]));
.call($$.setCssRule(true, ` .${$BAR.bar}`, ["fill"], $$.color));
},

/**
Expand All @@ -84,7 +85,7 @@ export default {

$root.bar = bar.enter().append("path")
.attr("class", classBar)
.style("fill", $$.colorByRule)
.style("fill", $$.getStylePropValue($$.color))
.merge(bar)
.style("opacity", initialOpacity);
},
Expand All @@ -103,7 +104,7 @@ export default {
return [
$$.$T(bar, withTransition, getRandom())
.attr("d", d => (isNumber(d.value) || $$.isBarRangeType(d)) && drawFn(d))
.style("fill", $$.colorByRule)
.style("fill", $$.getStylePropValue($$.color))
.style("opacity", null)
];
},
Expand Down
5 changes: 3 additions & 2 deletions src/ChartInternal/shape/line.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export default {
const {$el} = this;

$el.line = $el.main.select(`.${$COMMON.chart}`).append("g")
.attr("class", $LINE.chartLines);
.attr("class", $LINE.chartLines)
.call(this.setCssRule(false, `.${$LINE.chartLines}`, ["pointer-events:none"]));
},

updateTargetsForLine(t): void {
Expand All @@ -36,7 +37,7 @@ export default {
const mainLineEnter = mainLineUpdate.enter().append("g")
.attr("class", classChartLine)
.style("opacity", "0")
.style("pointer-events", "none");
.style("pointer-events", $$.getStylePropValue("none"));

// Lines for each data
mainLineEnter.append("g")
Expand Down
14 changes: 8 additions & 6 deletions src/ChartInternal/shape/point.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,10 @@ export default {

enterNode.append("g")
.attr("class", classCircles)
.style("cursor", d => (isFunction(isSelectable) && isSelectable(d) ? "pointer" : null))
.call($$.setColorByRule(null, $CIRCLE.circle, ["fill", "stroke"]))
.call(selection => {
$$.setCssRule(true, `.${$CIRCLE.circles}`, ["cursor:pointer"], isSelectable)(selection);
$$.setCssRule(true, ` .${$CIRCLE.circle}`, ["fill", "stroke"], $$.color)(selection);
})
.style("opacity", function() {
const parent = d3Select(this.parentNode);

Expand Down Expand Up @@ -139,10 +141,10 @@ export default {

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

$root.circle = $root.main.selectAll(`.${$CIRCLE.circles} .${$CIRCLE.circle}`)
.style("stroke", $$.colorByRule)
.style("stroke", $$.getStylePropValue($$.color))
.style("opacity", $$.initialOpacityForCircle.bind($$));
}
},
Expand All @@ -157,7 +159,7 @@ export default {
return [];
}

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

const t = getRandom();
Expand Down Expand Up @@ -195,7 +197,7 @@ export default {
const cx = (hasRadar ? $$.radarCircleX : $$.circleX).bind($$);
const cy = (hasRadar ? $$.radarCircleY : $$.circleY).bind($$);
const withTransition = toggling || isUndefined(d);
const fn = $$.point("update", $$, cx, cy, $$.colorByRule, resizing ? false : withTransition);
const fn = $$.point("update", $$, cx, cy, $$.getStylePropValue($$.color), resizing ? false : withTransition);

if (d) {
circle = circle
Expand Down
2 changes: 1 addition & 1 deletion src/config/Store/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default class State {
hasRadar: false,

// for data CSS rule index (used when boost.useCssRule is true)
colorRule: {},
cssRule: {},

current: {
// chart whole dimension
Expand Down
Loading

0 comments on commit 97bdcd0

Please sign in to comment.