lightview
Version:
Small, simple, powerful web UI and micro front end creation ... Great ideas from Svelte, React, Vue and Riot combined.
113 lines (112 loc) • 5.32 kB
JavaScript
const chart = (self,{packages = ["corechart"],options={},columns=[],rows=[],type,optionsTransform, rowTransform}={}) => {
options = {...options};
columns = [...columns];
let chart,
datatable;
const chartProxy = (chart) => {
const extras = {
setOption(name,value) {
options[name] = value;
chart.draw(datatable, options);
},
setOptions(newOptions) {
options = {...newOptions};
chart.draw(datatable, options);
}
};
return new Proxy(chart,{
get(target,property) {
let value = extras[property];
if(value!==undefined) return value;
value = target[property];
if(value!==undefined) return Reflect.get(target,property);
value = datatable[property];
if(typeof(value)==="function") {
if(["add","insert","remove","set"].some((prefix) => property.startsWith(prefix))) {
return (...args) => { value.call(datatable,...args); chart.draw(datatable,options); };
};
return value.bind(datatable);
};
}
});
};
const target = self.getElementById("target"),
resizeObserver = new ResizeObserver(entries => {
for (let entry of entries) {
if(entry.contentBoxSize) {
// Firefox implements `contentBoxSize` as a single content rect, rather than an array
const contentBoxSize = Array.isArray(entry.contentBoxSize) ? entry.contentBoxSize[0] : entry.contentBoxSize;
if(options.width !== contentBoxSize.inlineSize) {
options.width = contentBoxSize.inlineSize;
chart.draw(datatable, options);
}
} else {
if(options.width !== entry.contentRect.width) {
options.width = entry.contentRect.width;
chart.draw(datatable, options);
}
}
}
}),
callback = (textNode, oldValue, newValue) => {
datatable = new google.visualization.DataTable();
try {
const config = JSON5.parse(newValue.trim());
if(config.options) Object.assign(options,config.options);
if(config.columns) columns=config.columns;
if(config.rows) rows=config.rows;
columns.forEach((column) => {
datatable.addColumn(column);
});
if(optionsTransform) options = optionsTransform(options);
if(rowTransform) rows = rows.map((row,index) => rowTransform(row,index,options));
datatable.addRows(rows);
const {selectedStyle,style} = options;
rows.forEach((row,index) => {
if(selectedStyle) datatable.setRowProperty(index,"selectedStyle",selectedStyle);
if(style) datatable.setRowProperty(index,"style",style);
});
chart.draw(datatable, options);
} catch (e) {
console.error(e + newValue);
target.innerText = e + newValue;
}
};
self.firstChild.innerText = "Loading ...";
self.variables({type: "string", title: "string", style: "string"}, {observed:true});
if(self.hasAttribute("style")) target.setAttribute("style",self.getAttribute("style"));
self.init = () => {
if(!options.title && self.hasAttribute("title")) options.title = self.getAttribute("title");
self.chart = chart = chartProxy(new google.visualization[type||self.getAttribute("type")](target));
addEventListener("change",({target,value}) => {
if (target === "type") {
chart = new google.visualization[type](target);
} else if (target === "title") {
options.title = value;
} else if(target === "style") {
target.setAttribute("style",value);
}
chart.draw(datatable, options);
});
const node = self.firstChild;
callback(node, node.textContent, node.textContent);
// Will be used by the Lightview global observer
node.characterDataMutationCallback = callback;
// resized charts if window resizes
resizeObserver.observe(document.body);
self.dispatchEvent(new Event("initialized"));
};
self.addEventListener("mounted", ({target}) => {
const gscript = document.createElement("script");
gscript.setAttribute("src","https://www.gstatic.com/charts/loader.js");
gscript.onload = () => {
google.charts.load("current", {"packages":packages});
google.charts.setOnLoadCallback(self.init);
};
self.appendChild(gscript);
});
const jscript = document.createElement("script");
jscript.setAttribute("src","../javascript/json5.min.js");
document.head.appendChild(jscript);
}
export {chart};