Skip to content

Commit

Permalink
feat(render): Add forced init option on lazy rendering
Browse files Browse the repository at this point in the history
Make to initialize when chart element isn't visible, but
render.lazy=false is set

Fix #3106
  • Loading branch information
netil authored Sep 20, 2024
1 parent d762dbd commit 218ce46
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 14 deletions.
11 changes: 11 additions & 0 deletions src/Chart/Chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export default class Chart {

constructor(options) {
const $$ = new ChartInternal(this);
// let hook = () => {};

this.internal = $$;

Expand All @@ -120,6 +121,10 @@ export default class Chart {
const isChild = target !== argThis;
const isNotNil = notEmpty(fn[key]);
const hasChild = isNotNil && Object.keys(fn[key]).length > 0;
// const hookFn = function(...params) {
// hook();
// return fn[key].bind(argThis)(...params);
// }

if (isFunc && ((!isChild && hasChild) || isChild)) {
target[key] = fn[key].bind(argThis);
Expand All @@ -137,6 +142,12 @@ export default class Chart {

$$.beforeInit();
$$.init();

// if ($$.config.render.lazy !== false && hasStyle($$.$el.chart, {"display": "none", "visibility": "hidden"})) {
// hook = () => {
// logError(`The call of APIs won't work. Please, make sure if chart element is %cvisible.`);
// };
// }
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/ChartInternal/ChartInternal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
extend,
getOption,
getRandom,
hasStyle,
isFunction,
isObject,
isString,
Expand Down Expand Up @@ -253,10 +254,9 @@ export default class ChartInternal {
initToRender(forced?: boolean): void {
const $$ = <any>this;
const {config, state, $el: {chart}} = $$;
const isHidden = () =>
chart.style("display") === "none" || chart.style("visibility") === "hidden";
const isHidden = () => hasStyle(chart, {display: "none", visibility: "hidden"});

const isLazy = config.render.lazy || isHidden();
const isLazy = config.render.lazy === false ? false : config.render.lazy || isHidden();
const MutationObserver = window.MutationObserver;

if (isLazy && MutationObserver && config.render.observe !== false && !forced) {
Expand Down
5 changes: 4 additions & 1 deletion src/config/Options/common/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,10 @@ export default {
* @memberof Options
* @type {object}
* @property {object} [render] render object
* @property {boolean} [render.lazy=true] Make to not render at initialization (enabled by default when bind element's visibility is hidden).
* @property {boolean} [render.lazy=true] Make to not render at initialization.
* - **NOTE**:
* - Enabled by default when bind element's visibility is hidden.
* - When set to `false`, will initialize the chart regardless the bind element's visibility state, but in this case chart can't be guaranteed to be rendered properly.
* @property {boolean} [render.observe=true] Observe bind element's visibility(`display` or `visiblity` inline css property or class value) & render when is visible automatically (for IEs, only works IE11+). When set to **false**, call [`.flush()`](./Chart.html#flush) to render.
* @see [Demo](https://naver.github.io/billboard.js/demo/#ChartOptions.LazyRender)
* @example
Expand Down
18 changes: 11 additions & 7 deletions src/module/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,30 @@ function checkModuleImport(ctx) {

type &&
logError(`Please, make sure if %c${camelize(type)}`,
"module has been imported and specified correctly.");
"module has been imported and specified correctly.",
"https://github.com/naver/billboard.js/wiki/CHANGELOG-v2#modularization-by-its-functionality");
}

/**
* Log error and throw error
* @param {string} head Message header
* @param {string} tail Message tail
* @param {string} info Info message
* @private
*/
function logError(head, tail) {
function logError(head, tail?: string, info?: string) {
const prefix = "[billboard.js]";
const info =
"https://github.com/naver/billboard.js/wiki/CHANGELOG-v2#modularization-by-its-functionality";
const hasConsole = window.console?.error;

if (hasConsole) {
const tailMsg = tail ?
["background:red;color:white;display:block;font-size:15px", tail] :
[];

console.error(`❌ ${prefix} ${head}`,
"background:red;color:white;display:block;font-size:15px", tail);
console.info("%cℹ️", "font-size:15px", info);
"background:red;color:white;display:block;font-size:15px", ...tailMsg);
info && console.info("%cℹ️", "font-size:15px", info);
}

throw Error(`${prefix} ${head.replace(/\%c([a-z-]+)/i, "'$1' ")} ${tail}`);
throw Error(`${prefix} ${head.replace(/\%c([a-z-]+)/i, "'$1' ")} ${tail ?? ""}`);
}
23 changes: 23 additions & 0 deletions src/module/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export {
getTransformCTM,
getTranslation,
getUnique,
hasStyle,
hasValue,
hasViewBox,
isArray,
Expand Down Expand Up @@ -817,6 +818,28 @@ function hasViewBox(svg: d3Selection): boolean {
return attr ? /(\d+(\.\d+)?){3}/.test(attr) : false;
}

/**
* Determine if given node has the specified style
* @param {d3Selection|SVGElement} node Target node
* @param {object} condition Conditional style props object
* @param {boolean} all If true, all condition should be matched
* @returns {boolean}
*/
function hasStyle(node, condition: {[key: string]: string}, all = false): boolean {
const isD3Node = !!node.node;
let has = false;

for (const [key, value] of Object.entries(condition)) {
has = isD3Node ? node.style(key) === value : node.style[key] === value;

if (all === false && has) {
break;
}
}

return has;
}

/**
* Return if the current doc is visible or not
* @returns {boolean}
Expand Down
1 change: 1 addition & 0 deletions test/assets/module/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const {
getTranslation,
getTransformCTM,
getUnique,
hasStyle,
hasValue,
hasViewBox,
isArray,
Expand Down
32 changes: 29 additions & 3 deletions test/internals/bb-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ describe("Interface & initialization", () => {
}));

it("check lazy rendering on callbacks", () => new Promise(done => {
const el: any = document.body.querySelector("#chart");
const el = <HTMLDivElement>document.body.querySelector("#chart");

// hide to lazy render
el.style.display = "none";
Expand All @@ -528,7 +528,9 @@ describe("Interface & initialization", () => {
expect(el.innerHTML).to.be.empty;

// onresize, resized shouldn't be called on resize
chart.resize({width: 500});
expect(
chart.resize({width: 500})
).to.throw;

for (let x in spy) {
expect(spy[x].called).to.be.false;
Expand All @@ -550,7 +552,7 @@ describe("Interface & initialization", () => {
expect(spy.resized.called).to.be.true;

done(1);
}, 300);
}, 300);
}, 300);
}), 4000);

Expand Down Expand Up @@ -582,6 +584,30 @@ describe("Interface & initialization", () => {
done(1);
}, 300);
}));

it("should forcely linitialize even chart element visibility is hidden.", () =>{
const el = <HTMLDivElement>document.body.querySelector("#chart");

// hide to lazy render
el.style.display = "none";

chart = util.generate({
data: {
columns: [
["data1", 300, 350, 300, 0, 0, 0],
["data2", 130, 100, 140, 200, 150, 50]
],
type: "line"
},
render: {
lazy: false
}
});

expect(chart.$.svg.node().innerHTML).to.be.not.empty;

el.style.display = "";
});
});

describe("check for background", () => {
Expand Down

0 comments on commit 218ce46

Please sign in to comment.