-
Notifications
You must be signed in to change notification settings - Fork 355
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(plugin): Intent to ship TableView plugin
Implement new TableView plugin Close #1873
- Loading branch information
Showing
10 changed files
with
551 additions
and
3 deletions.
There are no files selected for viewing
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/** | ||
* Copyright (c) 2021 ~ present NAVER Corp. | ||
* billboard.js project is licensed under the MIT license | ||
*/ | ||
/** | ||
* TableView plugin option class | ||
* @class TableviewOptions | ||
* @param {Options} options TableView plugin options | ||
* @augments Plugin | ||
* @returns {TableviewOptions} | ||
* @private | ||
*/ | ||
export default class Options { | ||
constructor() { | ||
return { | ||
/** | ||
* Set tableview holder selector. | ||
* - **NOTE:** If not set, will append new holder element dynamically right after chart element. | ||
* @name selector | ||
* @memberof plugin-tableview | ||
* @type {string} | ||
* @default undefined | ||
* @example | ||
* selector: "#table-holder" | ||
*/ | ||
selector: undefined, | ||
|
||
/** | ||
* Set category title text | ||
* @name categoryTitle | ||
* @memberof plugin-tableview | ||
* @type {string} | ||
* @default "Category" | ||
* @example | ||
* categoryTitle: "#table-holder" | ||
*/ | ||
categoryTitle: "Category", | ||
|
||
/** | ||
* Set category text format function. | ||
* @name categoryFormat | ||
* @memberof plugin-tableview | ||
* @type {Function} | ||
* @returns {string} | ||
* @default function(v) { // will return formatted value according x Axis type }} | ||
* @example | ||
* categoryFormat: "#table-holder" | ||
*/ | ||
categoryFormat: function(v: Date|number|string): string { | ||
let category = v; | ||
|
||
if (this.$$.axis.isCategorized()) { | ||
category = this.$$.categoryName(v); | ||
} else if (this.$$.axis.isTimeSeries()) { | ||
category = (v as Date).toLocaleDateString(); | ||
} | ||
|
||
return category as string; | ||
}, | ||
|
||
/** | ||
* Set tableview holder class name. | ||
* @name class | ||
* @memberof plugin-tableview | ||
* @type {string} | ||
* @default undefined | ||
* @example | ||
* class: "table-class-name" | ||
*/ | ||
class: undefined, | ||
|
||
/** | ||
* Set to apply default style(`.bb-tableview`) to tableview element. | ||
* @name style | ||
* @memberof plugin-tableview | ||
* @type {boolean} | ||
* @default true | ||
* @example | ||
* style: false | ||
*/ | ||
style: true, | ||
|
||
/** | ||
* Set tableview title text. | ||
* - **NOTE:** If set [title.text](https://naver.github.io/billboard.js/release/latest/doc/Options.html#.title), will be used when this option value is empty. | ||
* @name title | ||
* @memberof plugin-tableview | ||
* @type {string} | ||
* @default undefined | ||
* @example | ||
* title: "Table Title Text" | ||
*/ | ||
title: undefined, | ||
|
||
/** | ||
* Update tableview from data visibility update(ex. legend toggle). | ||
* @name updateOnToggle | ||
* @memberof plugin-tableview | ||
* @type {boolean} | ||
* @default true | ||
* @example | ||
* legendToggleUpdate: false | ||
*/ | ||
updateOnToggle: true | ||
}; | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/** | ||
* Copyright (c) 2021 ~ present NAVER Corp. | ||
* billboard.js project is licensed under the MIT license | ||
*/ | ||
/** | ||
* Constants values for plugin option | ||
* @ignore | ||
*/ | ||
const defaultStyle = { | ||
id: "__tableview-style__", | ||
class: "bb-tableview", | ||
rule: `.bb-tableview { | ||
border-collapse:collapse; | ||
border-spacing:0; | ||
background:#fff; | ||
min-width:100%; | ||
margin-top:10px; | ||
font-family:sans-serif; | ||
font-size:.9em; | ||
} | ||
.bb-tableview tr:hover { | ||
background:#eef7ff; | ||
} | ||
.bb-tableview thead tr { | ||
background:#f8f8f8; | ||
} | ||
.bb-tableview caption,.bb-tableview td,.bb-tableview th { | ||
text-align: center; | ||
border:1px solid silver; | ||
padding:.5em; | ||
} | ||
.bb-tableview caption { | ||
font-size:1.1em; | ||
font-weight:700; | ||
margin-bottom: -1px; | ||
}` | ||
}; | ||
|
||
// template | ||
const tpl = { | ||
body: `<caption>{=title}</caption> | ||
<thead><tr>{=thead}</tr></thead> | ||
<tbody>{=tbody}</tbody>`, | ||
thead: `<th scope="col">{=title}</th>`, | ||
tbodyHeader: `<th scope="row">{=value}</th>`, | ||
tbody: `<td>{=value}</td>` | ||
}; | ||
|
||
export { | ||
defaultStyle, | ||
tpl | ||
}; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
/** | ||
* Copyright (c) 2021 ~ present NAVER Corp. | ||
* billboard.js project is licensed under the MIT license | ||
*/ | ||
import Plugin from "../Plugin"; | ||
import Options from "./Options"; | ||
import {defaultStyle, tpl} from "./const"; | ||
import {loadConfig} from "../../config/config"; | ||
import {isNumber, tplProcess} from "../../module/util"; | ||
|
||
/** | ||
* Table view plugin.<br> | ||
* Generates table view for bound dataset. | ||
* - **NOTE:** | ||
* - Plugins aren't built-in. Need to be loaded or imported to be used. | ||
* - Non required modules from billboard.js core, need to be installed separately. | ||
* @class plugin-tableview | ||
* @param {object} options table view plugin options | ||
* @augments Plugin | ||
* @returns {TableView} | ||
* @example | ||
* // Plugin must be loaded before the use. | ||
* <script src="$YOUR_PATH/plugin/billboardjs-plugin-tableview.js"></script> | ||
* | ||
* var chart = bb.generate({ | ||
* ... | ||
* plugins: [ | ||
* new bb.plugin.tableview({ | ||
* selector: "#my-table-view", | ||
* categoryTitle: "Category", | ||
* categoryFormat: function(v) { | ||
* // do some transformation | ||
* ... | ||
* return v; | ||
* }, | ||
* class: "my-class-name", | ||
* style: true, | ||
* title: "My Data List", | ||
* updateOnToggle: false | ||
* }), | ||
* ] | ||
* }); | ||
* @example | ||
* import {bb} from "billboard.js"; | ||
* import TableView from "billboard.js/dist/billboardjs-plugin-tableview.esm"; | ||
* | ||
* bb.generate({ | ||
* ... | ||
* plugins: [ | ||
* new TableView({ ... }) | ||
* ] | ||
* }) | ||
*/ | ||
export default class TableView extends Plugin { | ||
static version = `0.0.1`; | ||
private config; | ||
private element; | ||
|
||
constructor(options) { | ||
super(options); | ||
this.config = new Options(); | ||
|
||
return this; | ||
} | ||
|
||
$beforeInit(): void { | ||
loadConfig.call(this, this.options); | ||
} | ||
|
||
$init(): void { | ||
const {class: className, selector, style} = this.config; | ||
let element = document.querySelector( | ||
selector || `.${className || defaultStyle.class}` | ||
); | ||
|
||
if (!element) { | ||
const chart = this.$$.$el.chart.node(); | ||
|
||
element = document.createElement("table"); | ||
chart.parentNode.insertBefore(element, chart.nextSibling); | ||
} | ||
|
||
if (element.tagName !== "TABLE") { | ||
const table = document.createElement("table"); | ||
|
||
element.appendChild(table); | ||
element = table; | ||
} | ||
|
||
// append default css style | ||
if (style && !document.getElementById(defaultStyle.id)) { | ||
const s = document.createElement("style"); | ||
|
||
s.id = defaultStyle.id; | ||
s.innerHTML = defaultStyle.rule; | ||
|
||
(document.head || document.getElementsByTagName("head")[0]) | ||
.appendChild(s); | ||
} | ||
|
||
element.classList.add(...[style && defaultStyle.class, className].filter(Boolean)); | ||
|
||
this.element = element; | ||
} | ||
|
||
/** | ||
* Generate table | ||
* @private | ||
*/ | ||
generateTable(): void { | ||
const {$$, config, element} = this; | ||
const dataToShow = $$.filterTargetsToShow($$.data.targets); | ||
|
||
let thead = tplProcess(tpl.thead, { | ||
title: dataToShow.length ? this.config.categoryTitle : "" | ||
}); | ||
let tbody = ""; | ||
const rows: number|string[][] = []; | ||
|
||
dataToShow.forEach(v => { | ||
thead += tplProcess(tpl.thead, {title: v.id}); | ||
|
||
// make up value rows | ||
v.values.forEach((d, i: number) => { | ||
if (!rows[i]) { | ||
rows[i] = [d.x]; | ||
} | ||
|
||
rows[i].push(d.value); | ||
}); | ||
}); | ||
|
||
rows.forEach(v => { | ||
tbody += `<tr>${ | ||
v.map((d, i) => tplProcess(i ? tpl.tbody : tpl.tbodyHeader, { | ||
value: i === 0 ? | ||
config.categoryFormat.bind(this)(d) : | ||
(isNumber(d) ? d.toLocaleString() : "") | ||
})).join("") | ||
}</tr>`; | ||
}); | ||
|
||
const rx = /<[^>]+><\/[^>]+>/g; | ||
const r = tplProcess(tpl.body, { | ||
...config, | ||
title: config.title || $$.config.title_text || "", | ||
thead, | ||
tbody | ||
}).replace(rx, ""); | ||
|
||
element.innerHTML = r; | ||
} | ||
|
||
$redraw(): void { | ||
const {state} = this.$$; | ||
const doNotUpdate = state.resizing || (!this.config.updateOnToggle && state.toggling); | ||
|
||
!doNotUpdate && this.generateTable(); | ||
} | ||
|
||
$willDestroy(): void { | ||
this.element.parentNode.removeChild(this.element); | ||
|
||
// remove default css style when left one chart instance | ||
if (this.$$.charts.length === 1) { | ||
const s = document.getElementById(defaultStyle.id); | ||
|
||
s?.parentNode?.removeChild(s); | ||
} | ||
} | ||
} |
Oops, something went wrong.