@@ -18,6 +18,9 @@ $.create = (tag, o) => { | |||
ref.parentNode.insertBefore(element, ref); | |||
element.appendChild(ref); | |||
} else if (i === "onClick" ) { | |||
element.addEventListener('click', val); | |||
} else if (i === "styles") { | |||
if(typeof val === "object") { | |||
Object.keys(val).map(prop => { | |||
@@ -298,10 +301,6 @@ class SvgTip { | |||
} | |||
} | |||
/** | |||
* Returns the value of a number upto 2 decimal places. | |||
* @param {Number} d Any number | |||
*/ | |||
function floatTwo(d) { | |||
return parseFloat(d.toFixed(2)); | |||
} | |||
@@ -3677,7 +3676,6 @@ class AxisChart extends BaseChart { | |||
// removeDataPoint(index = 0) {} | |||
} | |||
// import MultiAxisChart from './charts/MultiAxisChart'; | |||
const chartTypes = { | |||
bar: AxisChart, | |||
line: AxisChart, | |||
@@ -46,6 +46,14 @@ header .lead-text { | |||
section { | |||
margin: 4em 0; /* SAME 1 */ | |||
} | |||
section figure { | |||
border: 1px solid #ddd; /* SAME 3 */ | |||
border-radius: 3px; | |||
overflow: auto; | |||
} | |||
section code { | |||
margin-top: 1rem; /* SAME 2 */ | |||
} | |||
h1 { | |||
font-size: 3.5rem; | |||
margin-bottom: 1.5rem; | |||
@@ -79,16 +87,19 @@ a, a:focus, a:hover { | |||
/* BaseCSS */ | |||
.margin-top { | |||
.mt1 { | |||
margin-top: 1rem; /* SAME 2 */ | |||
} | |||
.mv1 { | |||
margin: 2em 0 1em 0; | |||
} | |||
.border { | |||
border: 1px solid #ddd; | |||
border: 1px solid #ddd; /* SAME 3 */ | |||
border-radius: 3px; | |||
} | |||
.text-center { | |||
text-align: center; | |||
} | |||
/* Moon images */ | |||
@@ -103,8 +114,3 @@ a, a:focus, a:hover { | |||
margin-bottom: 5px; | |||
font-size: 12px; | |||
} | |||
.text-center { | |||
text-align: center; | |||
} |
@@ -1,4 +1,6 @@ | |||
import { MONTH_NAMES_SHORT } from '../../../src/js/utils/date-utils'; | |||
import { MONTH_NAMES_SHORT, SEC_IN_DAY, clone, timestampToMidnight, | |||
timestampSec, addDays } from '../../../src/js/utils/date-utils'; | |||
import { shuffle, getRandomBias } from '../../../src/js/utils/helpers'; | |||
// Composite Chart | |||
// ================================================================================ | |||
@@ -177,3 +179,29 @@ export const moonData = { | |||
// ================================================================================ | |||
let today = new Date(); | |||
let start = clone(today); | |||
addDays(start, 4); | |||
let end = clone(start); | |||
start.setFullYear( start.getFullYear() - 2 ); | |||
end.setFullYear( end.getFullYear() - 1 ); | |||
let dataPoints = {}; | |||
let startTs = timestampSec(start); | |||
let endTs = timestampSec(end); | |||
startTs = timestampToMidnight(startTs); | |||
endTs = timestampToMidnight(endTs, true); | |||
while (startTs < endTs) { | |||
dataPoints[parseInt(startTs)] = Math.floor(getRandomBias(0, 5, 0.2, 1)); | |||
startTs += SEC_IN_DAY; | |||
} | |||
export const heatmapData = { | |||
dataPoints: dataPoints, | |||
start: start, | |||
end: end | |||
}; | |||
@@ -1,9 +1,9 @@ | |||
import { lineCompositeData, barCompositeData } from './data'; | |||
import { lineCompositeData, barCompositeData, trendsData, heatmapData } from './data'; | |||
import { HEATMAP_COLORS_YELLOW, HEATMAP_COLORS_BLUE } from '../../../src/js/utils/constants'; | |||
export default { | |||
lineComposite: { | |||
elementID: "#chart-composite-1", | |||
options: { | |||
config: { | |||
title: "Fireball/Bolide Events - Yearly (reported)", | |||
data: lineCompositeData, | |||
type: "line", | |||
@@ -19,8 +19,7 @@ export default { | |||
}, | |||
barComposite: { | |||
elementID: "#chart-composite-2", | |||
options: { | |||
config: { | |||
data: barCompositeData, | |||
type: "bar", | |||
height: 210, | |||
@@ -35,20 +34,195 @@ export default { | |||
} | |||
}, | |||
demoMain: { | |||
elementID: "", | |||
options: { | |||
title: "My Awesome Chart", | |||
data: "typeData", | |||
type: "axis-mixed", | |||
height: 300, | |||
colors: ["purple", "magenta", "light-blue"], | |||
maxSlices: 10, | |||
tooltipOptions: { | |||
formatTooltipX: d => (d + '').toUpperCase(), | |||
formatTooltipY: d => d + ' pts', | |||
} | |||
} | |||
} | |||
} | |||
demoMain: { | |||
title: "Creating a Chart", | |||
contentBlocks: [ | |||
{ | |||
type: "text", | |||
content: `Booga wooga wooga Booga Booga wooga`, | |||
}, | |||
{ | |||
type: "code", | |||
lang: "html", | |||
content: ` <!--HTML--> | |||
<figure id="frost-chart"></figure>`, | |||
}, | |||
{ | |||
type: "code", | |||
lang: "javascript", | |||
content: ` // Javascript | |||
let chart = new frappe.Chart( "#frost-chart", { // or DOM element | |||
data: { | |||
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm", | |||
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"], | |||
datasets: [ | |||
{ | |||
name: "Some Data", chartType: 'bar', | |||
values: [25, 40, 30, 35, 8, 52, 17, -4] | |||
}, | |||
{ | |||
name: "Another Set", chartType: 'bar', | |||
values: [25, 50, -10, 15, 18, 32, 27, 14] | |||
}, | |||
{ | |||
name: "Yet Another", chartType: 'line', | |||
values: [15, 20, -3, -15, 58, 12, -17, 37] | |||
} | |||
], | |||
yMarkers: [{ label: "Marker", value: 70, | |||
options: { labelPos: 'left' }}], | |||
yRegions: [{ label: "Region", start: -10, end: 50, | |||
options: { labelPos: 'right' }}] | |||
}, | |||
title: "My Awesome Chart", | |||
type: 'axis-mixed', // or 'bar', 'line', 'pie', 'percentage' | |||
height: 300, | |||
colors: ['purple', '#ffa3ef', 'light-blue'], | |||
tooltipOptions: { | |||
formatTooltipX: d => (d + '').toUpperCase(), | |||
formatTooltipY: d => d + ' pts', | |||
} | |||
}); | |||
chart.export();`, | |||
}, | |||
{ | |||
type: "demo", | |||
config: { | |||
title: "My Awesome Chart", | |||
data: "typeData", | |||
type: "axis-mixed", | |||
height: 300, | |||
colors: ["purple", "magenta", "light-blue"], | |||
maxSlices: 10, | |||
tooltipOptions: { | |||
formatTooltipX: d => (d + '').toUpperCase(), | |||
formatTooltipY: d => d + ' pts', | |||
} | |||
}, | |||
sideContent: {}, | |||
options: [ | |||
{ | |||
name: "lineOptions", | |||
path: ["lineOptions"], | |||
type: "map", | |||
mapKeys: ['hideLine', 'hideDots', 'heatline', 'regionFill'], | |||
states: { | |||
"Line": [0, 1, 0, 0], | |||
"Dots": [1, 0, 0, 0], | |||
"HeatLine": [0, 1, 1, 0], | |||
"Region": [0, 1, 0, 1] | |||
}, | |||
activeState: "HeatLine" | |||
} | |||
], | |||
actions: [{ name: "Export ...", fn: "export", args: [] }], | |||
} | |||
] | |||
}, | |||
updateValues: { }, | |||
trendsPlot: { | |||
title: "Plot Trends", | |||
contentBlocks: [ | |||
{ | |||
type: "demo", | |||
config: { | |||
title: "Mean Total Sunspot Count - Yearly", | |||
data: trendsData, | |||
type: 'line', | |||
height: 300, | |||
colors: ['#238e38'], | |||
axisOptions: { | |||
xAxisMode: 'tick', | |||
yAxisMode: 'span', | |||
xIsSeries: 1 | |||
} | |||
}, | |||
options: [ | |||
{ | |||
name: "lineOptions", | |||
path: ["lineOptions"], | |||
type: "map", | |||
mapKeys: ['hideLine', 'hideDots', 'heatline', 'regionFill'], | |||
states: { | |||
"Line": [0, 1, 0, 0], | |||
"Dots": [1, 0, 0, 0], | |||
"HeatLine": [0, 1, 1, 0], | |||
"Region": [0, 1, 0, 1] | |||
}, | |||
activeState: "HeatLine" | |||
} | |||
], | |||
actions: [{ name: "Export ...", fn: "export", args: [] }] | |||
} | |||
], | |||
}, | |||
stateChange: {}, | |||
heatmap: { | |||
title: "And a Month-wise Heatmap", | |||
contentBlocks: [ | |||
{ | |||
type: "demo", | |||
config: { | |||
title: "Monthly Distribution", | |||
data: heatmapData, | |||
type: 'heatmap', | |||
discreteDomains: 1, | |||
countLabel: 'Level', | |||
colors: HEATMAP_COLORS_BLUE, | |||
legendScale: [0, 1, 2, 4, 5] | |||
}, | |||
options: [ | |||
{ | |||
name: "Discrete domains", | |||
path: ["discreteDomains"], | |||
type: 'boolean', | |||
// boolNames: ["Continuous", "Discrete"], | |||
states: { "Discrete": 1, "Continuous": 0 } | |||
}, | |||
{ | |||
name: "Colors", | |||
path: ["colors"], | |||
type: "object", | |||
states: { | |||
"Green (Default)": [], | |||
"Blue": HEATMAP_COLORS_BLUE, | |||
"GitHub's Halloween": HEATMAP_COLORS_YELLOW | |||
} | |||
} | |||
], | |||
actions: [{ name: "Export ...", fn: "export", args: [] }] | |||
}, | |||
{ | |||
type: "code", | |||
lang: "javascript", | |||
content: ` let heatmap = new frappe.Chart("#heatmap", { | |||
type: 'heatmap', | |||
title: "Monthly Distribution", | |||
data: { | |||
dataPoints: {'1524064033': 8, /* ... */}, | |||
// object with timestamp-value pairs | |||
start: startDate | |||
end: endDate // Date objects | |||
}, | |||
countLabel: 'Level', | |||
discreteDomains: 0 // default: 1 | |||
colors: ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'], | |||
// Set of five incremental colors, | |||
// preferably with a low-saturation color for zero data; | |||
// def: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'] | |||
});`, | |||
} | |||
], | |||
} | |||
} |
@@ -0,0 +1,108 @@ | |||
import { $ } from '../../../src/js/utils/dom'; | |||
export class docSectionBuilder { | |||
constructor(LIB_OBJ) { | |||
this.LIB_OBJ = LIB_OBJ; | |||
} | |||
setParent(parent) { | |||
// this.parent = parent; | |||
this.section = parent; | |||
} | |||
setSys(sys) { | |||
this.sys = sys; | |||
this.blockMap = {}; | |||
} | |||
make() { | |||
// const section = document.querySelector(this.section); | |||
let s = this.sys; | |||
$.create('h6', { inside: this.section, innerHTML: s.title }); | |||
s.contentBlocks.forEach((blockConf, index) => { | |||
this.blockMap[index] = this.getBlock(blockConf); | |||
}); | |||
} | |||
getBlock(blockConf) { | |||
let block; | |||
let type = blockConf.type; | |||
if(type === "text") { | |||
block = this.getText(blockConf); | |||
} else if(type === "code") { | |||
block = this.getCode(blockConf); | |||
} else { | |||
block = this.getDemo(blockConf); | |||
} | |||
} | |||
getText(blockConf) {} | |||
getCode(blockConf) { | |||
let pre = $.create('pre', { inside: this.section }); | |||
let code = $.create('code', { | |||
inside: pre, | |||
className: `hljs ${blockConf.lang}`, | |||
innerHTML: blockConf.content | |||
}); | |||
} | |||
getDemo(blockConf) { | |||
let args = blockConf.config; | |||
let figure = $.create('figure', { inside: this.section }); | |||
this.libObj = new this.LIB_OBJ(figure, args); | |||
this.getDemoOptions(blockConf.options, args, figure); | |||
this.getDemoActions(blockConf.actions, args); | |||
} | |||
getDemoOptions(options, args, figure) { | |||
options.forEach(o => { | |||
const btnGroup = $.create('div', { | |||
inside: this.section, | |||
className: `btn-group ${o.name}` | |||
}); | |||
const mapKeys = o.mapKeys; | |||
if(o.type === "map") { | |||
args[o.path[0]] = {}; | |||
} | |||
Object.keys(o.states).forEach(key => { | |||
let state = o.states[key]; | |||
let activeClass = key === o.activeState ? 'active' : ''; | |||
let button = $.create('button', { | |||
inside: btnGroup, | |||
className: `btn btn-sm btn-secondary ${activeClass}`, | |||
innerHTML: key, | |||
onClick: (e) => { | |||
// map | |||
if(o.type === "map") { | |||
mapKeys.forEach((attr, i) => { | |||
args[o.path[0]][attr] = state[i]; | |||
}) | |||
} else { | |||
// boolean, number, object | |||
args[o.path[0]] = state; | |||
} | |||
this.libObj = new this.LIB_OBJ(figure, args); | |||
} | |||
}); | |||
if(activeClass) { button.click(); } | |||
}); | |||
}); | |||
} | |||
getDemoActions(actions, args) { | |||
actions.forEach(o => { | |||
let args = o.args || []; | |||
$.create('button', { | |||
inside: this.section, | |||
className: `btn btn-sm btn-secondary`, | |||
innerHTML: o.name, | |||
onClick: () => {this.libObj[o.fn](...o.args);} | |||
}); | |||
}); | |||
} | |||
} | |||
@@ -1,23 +1,19 @@ | |||
import { $ } from '../../../src/js/utils/dom'; | |||
import { shuffle, getRandomBias } from '../../../src/js/utils/helpers'; | |||
import { HEATMAP_COLORS_YELLOW, HEATMAP_COLORS_BLUE } from '../../../src/js/utils/constants'; | |||
import { SEC_IN_DAY, clone, timestampToMidnight, timestampSec, addDays } from '../../../src/js/utils/date-utils'; | |||
import { fireballOver25, fireball_2_5, fireball_5_25, lineCompositeData, | |||
barCompositeData, typeData, trendsData, moonData } from './data'; | |||
import demoConfig from './demoConfig'; | |||
// import { lineComposite, barComposite } from './demoConfig'; | |||
// ================================================================================ | |||
import dc from './demoConfig'; | |||
import { docSectionBuilder } from './docSectionBuilder'; | |||
let Chart = frappe.Chart; // eslint-disable-line no-undef | |||
let dcb = new docSectionBuilder(Chart); | |||
let lc = demoConfig.lineComposite; | |||
let lineCompositeChart = new Chart (lc.elementID, lc.options); | |||
let bc = demoConfig.barComposite; | |||
let barCompositeChart = new Chart (bc.elementID, bc.options); | |||
let lineComposite = new Chart("#line-composite-1", dc.lineComposite.config); | |||
let barComposite = new Chart("#bar-composite-1", dc.barComposite.config); | |||
lineCompositeChart.parent.addEventListener('data-select', (e) => { | |||
lineComposite.parent.addEventListener('data-select', (e) => { | |||
let i = e.index; | |||
barCompositeChart.updateDatasets([ | |||
barComposite.updateDatasets([ | |||
fireballOver25[i], fireball_5_25[i], fireball_2_5[i] | |||
]); | |||
}); | |||
@@ -31,6 +27,7 @@ let typeChartArgs = { | |||
type: 'axis-mixed', | |||
height: 300, | |||
colors: customColors, | |||
valuesOverPoints: 1, | |||
// maxLegendPoints: 6, | |||
maxSlices: 10, | |||
@@ -174,59 +171,10 @@ document.querySelector('.export-update').addEventListener('click', () => { | |||
// Trends Chart | |||
// ================================================================================ | |||
let plotChartArgs = { | |||
title: "Mean Total Sunspot Count - Yearly", | |||
data: trendsData, | |||
type: 'line', | |||
height: 300, | |||
colors: ['#238e38'], | |||
lineOptions: { | |||
hideDots: 1, | |||
heatline: 1, | |||
}, | |||
axisOptions: { | |||
xAxisMode: 'tick', | |||
yAxisMode: 'span', | |||
xIsSeries: 1 | |||
} | |||
}; | |||
let trendsChart = new Chart("#chart-trends", plotChartArgs); | |||
Array.prototype.slice.call( | |||
document.querySelectorAll('.chart-plot-buttons button') | |||
).map(el => { | |||
el.addEventListener('click', (e) => { | |||
let btn = e.target; | |||
let type = btn.getAttribute('data-type'); | |||
let config = {}; | |||
config[type] = 1; | |||
if(['regionFill', 'heatline'].includes(type)) { | |||
config.hideDots = 1; | |||
} | |||
// plotChartArgs.init = false; | |||
plotChartArgs.lineOptions = config; | |||
new Chart("#chart-trends", plotChartArgs); | |||
Array.prototype.slice.call( | |||
btn.parentNode.querySelectorAll('button')).map(el => { | |||
el.classList.remove('active'); | |||
}); | |||
btn.classList.add('active'); | |||
}); | |||
}); | |||
document.querySelector('.export-trends').addEventListener('click', () => { | |||
trendsChart.export(); | |||
}); | |||
// Event chart | |||
// ================================================================================ | |||
let section = document.querySelector('.trends-plot'); | |||
dcb.setParent(section); | |||
dcb.setSys(dc.trendsPlot); | |||
dcb.make(); | |||
let eventsData = { | |||
@@ -262,112 +210,7 @@ eventsChart.parent.addEventListener('data-select', (e) => { | |||
// Heatmap | |||
// ================================================================================ | |||
let today = new Date(); | |||
let start = clone(today); | |||
addDays(start, 4); | |||
let end = clone(start); | |||
start.setFullYear( start.getFullYear() - 2 ); | |||
end.setFullYear( end.getFullYear() - 1 ); | |||
let dataPoints = {}; | |||
let startTs = timestampSec(start); | |||
let endTs = timestampSec(end); | |||
startTs = timestampToMidnight(startTs); | |||
endTs = timestampToMidnight(endTs, true); | |||
while (startTs < endTs) { | |||
dataPoints[parseInt(startTs)] = Math.floor(getRandomBias(0, 5, 0.2, 1)); | |||
startTs += SEC_IN_DAY; | |||
} | |||
const heatmapData = { | |||
dataPoints: dataPoints, | |||
start: start, | |||
end: end | |||
}; | |||
let heatmapArgs = { | |||
title: "Monthly Distribution", | |||
data: heatmapData, | |||
type: 'heatmap', | |||
discreteDomains: 1, | |||
countLabel: 'Level', | |||
colors: HEATMAP_COLORS_BLUE, | |||
legendScale: [0, 1, 2, 4, 5] | |||
}; | |||
let heatmapChart = new Chart("#chart-heatmap", heatmapArgs); | |||
Array.prototype.slice.call( | |||
document.querySelectorAll('.heatmap-mode-buttons button') | |||
).map(el => { | |||
el.addEventListener('click', (e) => { | |||
let btn = e.target; | |||
let mode = btn.getAttribute('data-mode'); | |||
let discreteDomains = 0; | |||
if(mode === 'discrete') { | |||
discreteDomains = 1; | |||
} | |||
let colors = []; | |||
let colors_mode = document | |||
.querySelector('.heatmap-color-buttons .active') | |||
.getAttribute('data-color'); | |||
if(colors_mode === 'halloween') { | |||
colors = HEATMAP_COLORS_YELLOW; | |||
} else if (colors_mode === 'blue') { | |||
colors = HEATMAP_COLORS_BLUE; | |||
} | |||
heatmapArgs.discreteDomains = discreteDomains; | |||
heatmapArgs.colors = colors; | |||
new Chart("#chart-heatmap", heatmapArgs); | |||
Array.prototype.slice.call( | |||
btn.parentNode.querySelectorAll('button')).map(el => { | |||
el.classList.remove('active'); | |||
}); | |||
btn.classList.add('active'); | |||
}); | |||
}); | |||
Array.prototype.slice.call( | |||
document.querySelectorAll('.heatmap-color-buttons button') | |||
).map(el => { | |||
el.addEventListener('click', (e) => { | |||
let btn = e.target; | |||
let colors_mode = btn.getAttribute('data-color'); | |||
let colors = []; | |||
if(colors_mode === 'halloween') { | |||
colors = HEATMAP_COLORS_YELLOW; | |||
} else if (colors_mode === 'blue') { | |||
colors = HEATMAP_COLORS_BLUE; | |||
} | |||
let discreteDomains = 1; | |||
let view_mode = document | |||
.querySelector('.heatmap-mode-buttons .active') | |||
.getAttribute('data-mode'); | |||
if(view_mode === 'continuous') { | |||
discreteDomains = 0; | |||
} | |||
heatmapArgs.discreteDomains = discreteDomains; | |||
heatmapArgs.colors = colors; | |||
new Chart("#chart-heatmap", heatmapArgs); | |||
Array.prototype.slice.call( | |||
btn.parentNode.querySelectorAll('button')).map(el => { | |||
el.classList.remove('active'); | |||
}); | |||
btn.classList.add('active'); | |||
}); | |||
}); | |||
document.querySelector('.export-heatmap').addEventListener('click', () => { | |||
heatmapChart.export(); | |||
}); | |||
section = document.querySelector('.heatmap'); | |||
dcb.setParent(section); | |||
dcb.setSys(dc.heatmap); | |||
dcb.make(); |
@@ -28,6 +28,171 @@ function __$styleInject(css, ref) { | |||
} | |||
} | |||
var asyncGenerator = function () { | |||
function AwaitValue(value) { | |||
this.value = value; | |||
} | |||
function AsyncGenerator(gen) { | |||
var front, back; | |||
function send(key, arg) { | |||
return new Promise(function (resolve, reject) { | |||
var request = { | |||
key: key, | |||
arg: arg, | |||
resolve: resolve, | |||
reject: reject, | |||
next: null | |||
}; | |||
if (back) { | |||
back = back.next = request; | |||
} else { | |||
front = back = request; | |||
resume(key, arg); | |||
} | |||
}); | |||
} | |||
function resume(key, arg) { | |||
try { | |||
var result = gen[key](arg); | |||
var value = result.value; | |||
if (value instanceof AwaitValue) { | |||
Promise.resolve(value.value).then(function (arg) { | |||
resume("next", arg); | |||
}, function (arg) { | |||
resume("throw", arg); | |||
}); | |||
} else { | |||
settle(result.done ? "return" : "normal", result.value); | |||
} | |||
} catch (err) { | |||
settle("throw", err); | |||
} | |||
} | |||
function settle(type, value) { | |||
switch (type) { | |||
case "return": | |||
front.resolve({ | |||
value: value, | |||
done: true | |||
}); | |||
break; | |||
case "throw": | |||
front.reject(value); | |||
break; | |||
default: | |||
front.resolve({ | |||
value: value, | |||
done: false | |||
}); | |||
break; | |||
} | |||
front = front.next; | |||
if (front) { | |||
resume(front.key, front.arg); | |||
} else { | |||
back = null; | |||
} | |||
} | |||
this._invoke = send; | |||
if (typeof gen.return !== "function") { | |||
this.return = undefined; | |||
} | |||
} | |||
if (typeof Symbol === "function" && Symbol.asyncIterator) { | |||
AsyncGenerator.prototype[Symbol.asyncIterator] = function () { | |||
return this; | |||
}; | |||
} | |||
AsyncGenerator.prototype.next = function (arg) { | |||
return this._invoke("next", arg); | |||
}; | |||
AsyncGenerator.prototype.throw = function (arg) { | |||
return this._invoke("throw", arg); | |||
}; | |||
AsyncGenerator.prototype.return = function (arg) { | |||
return this._invoke("return", arg); | |||
}; | |||
return { | |||
wrap: function (fn) { | |||
return function () { | |||
return new AsyncGenerator(fn.apply(this, arguments)); | |||
}; | |||
}, | |||
await: function (value) { | |||
return new AwaitValue(value); | |||
} | |||
}; | |||
}(); | |||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | |||
function $(expr, con) { | |||
return typeof expr === "string" ? (con || document).querySelector(expr) : expr || null; | |||
} | |||
$.create = function (tag, o) { | |||
var element = document.createElement(tag); | |||
for (var i in o) { | |||
var val = o[i]; | |||
if (i === "inside") { | |||
$(val).appendChild(element); | |||
} else if (i === "around") { | |||
var ref = $(val); | |||
ref.parentNode.insertBefore(element, ref); | |||
element.appendChild(ref); | |||
} else if (i === "onClick") { | |||
element.addEventListener('click', val); | |||
} else if (i === "styles") { | |||
if ((typeof val === "undefined" ? "undefined" : _typeof(val)) === "object") { | |||
Object.keys(val).map(function (prop) { | |||
element.style[prop] = val[prop]; | |||
}); | |||
} | |||
} else if (i in element) { | |||
element[i] = val; | |||
} else { | |||
element.setAttribute(i, val); | |||
} | |||
} | |||
return element; | |||
}; | |||
// https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/ | |||
// Fixed 5-color theme, | |||
// More colors are difficult to parse visually | |||
@@ -267,74 +432,342 @@ var moonData = { | |||
// ================================================================================ | |||
var demoConfig = { | |||
lineComposite: { | |||
elementID: "#chart-composite-1", | |||
options: { | |||
title: "Fireball/Bolide Events - Yearly (reported)", | |||
data: lineCompositeData, | |||
type: "line", | |||
height: 190, | |||
colors: ["green"], | |||
isNavigable: 1, | |||
valuesOverPoints: 1, | |||
lineOptions: { | |||
dotSize: 8 | |||
} | |||
var today = new Date(); | |||
var start = clone(today); | |||
addDays(start, 4); | |||
var end = clone(start); | |||
start.setFullYear(start.getFullYear() - 2); | |||
end.setFullYear(end.getFullYear() - 1); | |||
var dataPoints = {}; | |||
var startTs = timestampSec(start); | |||
var endTs = timestampSec(end); | |||
startTs = timestampToMidnight(startTs); | |||
endTs = timestampToMidnight(endTs, true); | |||
while (startTs < endTs) { | |||
dataPoints[parseInt(startTs)] = Math.floor(getRandomBias(0, 5, 0.2, 1)); | |||
startTs += SEC_IN_DAY; | |||
} | |||
var heatmapData = { | |||
dataPoints: dataPoints, | |||
start: start, | |||
end: end | |||
}; | |||
var dc = { | |||
lineComposite: { | |||
config: { | |||
title: "Fireball/Bolide Events - Yearly (reported)", | |||
data: lineCompositeData, | |||
type: "line", | |||
height: 190, | |||
colors: ["green"], | |||
isNavigable: 1, | |||
valuesOverPoints: 1, | |||
lineOptions: { | |||
dotSize: 8 | |||
} | |||
} | |||
}, | |||
barComposite: { | |||
config: { | |||
data: barCompositeData, | |||
type: "bar", | |||
height: 210, | |||
colors: ["violet", "light-blue", "#46a9f9"], | |||
valuesOverPoints: 1, | |||
axisOptions: { | |||
xAxisMode: "tick" | |||
}, | |||
barOptions: { | |||
stacked: 1 | |||
} | |||
} | |||
}, | |||
demoMain: { | |||
title: "Creating a Chart", | |||
contentBlocks: [{ | |||
type: "text", | |||
content: 'Booga wooga wooga Booga Booga wooga' | |||
}, { | |||
type: "code", | |||
lang: "html", | |||
content: ' <!--HTML-->\n <figure id="frost-chart"></figure>' | |||
}, { | |||
type: "code", | |||
lang: "javascript", | |||
content: ' // Javascript\n let chart = new frappe.Chart( "#frost-chart", { // or DOM element\n data: {\n labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm",\n "12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"],\n\n datasets: [\n {\n name: "Some Data", chartType: \'bar\',\n values: [25, 40, 30, 35, 8, 52, 17, -4]\n },\n {\n name: "Another Set", chartType: \'bar\',\n values: [25, 50, -10, 15, 18, 32, 27, 14]\n },\n {\n name: "Yet Another", chartType: \'line\',\n values: [15, 20, -3, -15, 58, 12, -17, 37]\n }\n ],\n\n yMarkers: [{ label: "Marker", value: 70,\n options: { labelPos: \'left\' }}],\n yRegions: [{ label: "Region", start: -10, end: 50,\n options: { labelPos: \'right\' }}]\n },\n\n title: "My Awesome Chart",\n type: \'axis-mixed\', // or \'bar\', \'line\', \'pie\', \'percentage\'\n height: 300,\n colors: [\'purple\', \'#ffa3ef\', \'light-blue\'],\n\n tooltipOptions: {\n formatTooltipX: d => (d + \'\').toUpperCase(),\n formatTooltipY: d => d + \' pts\',\n }\n });\n\n chart.export();' | |||
}, { | |||
type: "demo", | |||
config: { | |||
title: "My Awesome Chart", | |||
data: "typeData", | |||
type: "axis-mixed", | |||
height: 300, | |||
colors: ["purple", "magenta", "light-blue"], | |||
maxSlices: 10, | |||
tooltipOptions: { | |||
formatTooltipX: function formatTooltipX(d) { | |||
return (d + '').toUpperCase(); | |||
}, | |||
formatTooltipY: function formatTooltipY(d) { | |||
return d + ' pts'; | |||
} | |||
} | |||
}, | |||
sideContent: {}, | |||
options: [{ | |||
name: "lineOptions", | |||
path: ["lineOptions"], | |||
type: "map", | |||
mapKeys: ['hideLine', 'hideDots', 'heatline', 'regionFill'], | |||
states: { | |||
"Line": [0, 1, 0, 0], | |||
"Dots": [1, 0, 0, 0], | |||
"HeatLine": [0, 1, 1, 0], | |||
"Region": [0, 1, 0, 1] | |||
}, | |||
activeState: "HeatLine" | |||
}], | |||
actions: [{ name: "Export ...", fn: "export", args: [] }] | |||
}] | |||
}, | |||
updateValues: {}, | |||
trendsPlot: { | |||
title: "Plot Trends", | |||
contentBlocks: [{ | |||
type: "demo", | |||
config: { | |||
title: "Mean Total Sunspot Count - Yearly", | |||
data: trendsData, | |||
type: 'line', | |||
height: 300, | |||
colors: ['#238e38'], | |||
axisOptions: { | |||
xAxisMode: 'tick', | |||
yAxisMode: 'span', | |||
xIsSeries: 1 | |||
} | |||
}, | |||
options: [{ | |||
name: "lineOptions", | |||
path: ["lineOptions"], | |||
type: "map", | |||
mapKeys: ['hideLine', 'hideDots', 'heatline', 'regionFill'], | |||
states: { | |||
"Line": [0, 1, 0, 0], | |||
"Dots": [1, 0, 0, 0], | |||
"HeatLine": [0, 1, 1, 0], | |||
"Region": [0, 1, 0, 1] | |||
}, | |||
activeState: "HeatLine" | |||
}], | |||
actions: [{ name: "Export ...", fn: "export", args: [] }] | |||
}] | |||
}, | |||
stateChange: {}, | |||
heatmap: { | |||
title: "And a Month-wise Heatmap", | |||
contentBlocks: [{ | |||
type: "demo", | |||
config: { | |||
title: "Monthly Distribution", | |||
data: heatmapData, | |||
type: 'heatmap', | |||
discreteDomains: 1, | |||
countLabel: 'Level', | |||
colors: HEATMAP_COLORS_BLUE, | |||
legendScale: [0, 1, 2, 4, 5] | |||
}, | |||
options: [{ | |||
name: "Discrete domains", | |||
path: ["discreteDomains"], | |||
type: 'boolean', | |||
// boolNames: ["Continuous", "Discrete"], | |||
states: { "Discrete": 1, "Continuous": 0 } | |||
}, { | |||
name: "Colors", | |||
path: ["colors"], | |||
type: "object", | |||
states: { | |||
"Green (Default)": [], | |||
"Blue": HEATMAP_COLORS_BLUE, | |||
"GitHub's Halloween": HEATMAP_COLORS_YELLOW | |||
} | |||
}], | |||
actions: [{ name: "Export ...", fn: "export", args: [] }] | |||
}, { | |||
type: "code", | |||
lang: "javascript", | |||
content: ' let heatmap = new frappe.Chart("#heatmap", {\n type: \'heatmap\',\n title: "Monthly Distribution",\n data: {\n dataPoints: {\'1524064033\': 8, /* ... */},\n // object with timestamp-value pairs\n start: startDate\n end: endDate // Date objects\n },\n countLabel: \'Level\',\n discreteDomains: 0 // default: 1\n colors: [\'#ebedf0\', \'#c0ddf9\', \'#73b3f3\', \'#3886e1\', \'#17459e\'],\n // Set of five incremental colors,\n // preferably with a low-saturation color for zero data;\n // def: [\'#ebedf0\', \'#c6e48b\', \'#7bc96f\', \'#239a3b\', \'#196127\']\n });' | |||
}] | |||
} | |||
}; | |||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | |||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | |||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | |||
var docSectionBuilder = function () { | |||
function docSectionBuilder(LIB_OBJ) { | |||
_classCallCheck(this, docSectionBuilder); | |||
this.LIB_OBJ = LIB_OBJ; | |||
} | |||
_createClass(docSectionBuilder, [{ | |||
key: 'setParent', | |||
value: function setParent(parent) { | |||
// this.parent = parent; | |||
this.section = parent; | |||
} | |||
}, | |||
barComposite: { | |||
elementID: "#chart-composite-2", | |||
options: { | |||
data: barCompositeData, | |||
type: "bar", | |||
height: 210, | |||
colors: ["violet", "light-blue", "#46a9f9"], | |||
valuesOverPoints: 1, | |||
axisOptions: { | |||
xAxisMode: "tick" | |||
}, | |||
barOptions: { | |||
stacked: 1 | |||
}, { | |||
key: 'setSys', | |||
value: function setSys(sys) { | |||
this.sys = sys; | |||
this.blockMap = {}; | |||
} | |||
}, { | |||
key: 'make', | |||
value: function make() { | |||
var _this = this; | |||
// const section = document.querySelector(this.section); | |||
var s = this.sys; | |||
$.create('h6', { inside: this.section, innerHTML: s.title }); | |||
s.contentBlocks.forEach(function (blockConf, index) { | |||
_this.blockMap[index] = _this.getBlock(blockConf); | |||
}); | |||
} | |||
}, { | |||
key: 'getBlock', | |||
value: function getBlock(blockConf) { | |||
var block = void 0; | |||
var type = blockConf.type; | |||
if (type === "text") { | |||
block = this.getText(blockConf); | |||
} else if (type === "code") { | |||
block = this.getCode(blockConf); | |||
} else { | |||
block = this.getDemo(blockConf); | |||
} | |||
} | |||
}, | |||
demoMain: { | |||
elementID: "", | |||
options: { | |||
title: "My Awesome Chart", | |||
data: "typeData", | |||
type: "axis-mixed", | |||
height: 300, | |||
colors: ["purple", "magenta", "light-blue"], | |||
maxSlices: 10, | |||
tooltipOptions: { | |||
formatTooltipX: function formatTooltipX(d) { | |||
return (d + '').toUpperCase(); | |||
}, | |||
formatTooltipY: function formatTooltipY(d) { | |||
return d + ' pts'; | |||
}, { | |||
key: 'getText', | |||
value: function getText(blockConf) {} | |||
}, { | |||
key: 'getCode', | |||
value: function getCode(blockConf) { | |||
var pre = $.create('pre', { inside: this.section }); | |||
var code = $.create('code', { | |||
inside: pre, | |||
className: 'hljs ' + blockConf.lang, | |||
innerHTML: blockConf.content | |||
}); | |||
} | |||
}, { | |||
key: 'getDemo', | |||
value: function getDemo(blockConf) { | |||
var args = blockConf.config; | |||
var figure = $.create('figure', { inside: this.section }); | |||
this.libObj = new this.LIB_OBJ(figure, args); | |||
this.getDemoOptions(blockConf.options, args, figure); | |||
this.getDemoActions(blockConf.actions, args); | |||
} | |||
}, { | |||
key: 'getDemoOptions', | |||
value: function getDemoOptions(options, args, figure) { | |||
var _this2 = this; | |||
options.forEach(function (o) { | |||
var btnGroup = $.create('div', { | |||
inside: _this2.section, | |||
className: 'btn-group ' + o.name | |||
}); | |||
var mapKeys = o.mapKeys; | |||
if (o.type === "map") { | |||
args[o.path[0]] = {}; | |||
} | |||
} | |||
Object.keys(o.states).forEach(function (key) { | |||
var state = o.states[key]; | |||
var activeClass = key === o.activeState ? 'active' : ''; | |||
var button = $.create('button', { | |||
inside: btnGroup, | |||
className: 'btn btn-sm btn-secondary ' + activeClass, | |||
innerHTML: key, | |||
onClick: function onClick(e) { | |||
// map | |||
if (o.type === "map") { | |||
mapKeys.forEach(function (attr, i) { | |||
args[o.path[0]][attr] = state[i]; | |||
}); | |||
} else { | |||
// boolean, number, object | |||
args[o.path[0]] = state; | |||
} | |||
_this2.libObj = new _this2.LIB_OBJ(figure, args); | |||
} | |||
}); | |||
if (activeClass) { | |||
button.click(); | |||
} | |||
}); | |||
}); | |||
} | |||
} | |||
}; | |||
}, { | |||
key: 'getDemoActions', | |||
value: function getDemoActions(actions, args) { | |||
var _this3 = this; | |||
actions.forEach(function (o) { | |||
$.create('button', { | |||
inside: _this3.section, | |||
className: 'btn btn-sm btn-secondary', | |||
innerHTML: o.name, | |||
onClick: function onClick() { | |||
var _libObj; | |||
(_libObj = _this3.libObj)[o.fn].apply(_libObj, _toConsumableArray(o.args)); | |||
} | |||
}); | |||
}); | |||
} | |||
}]); | |||
var Chart = frappe.Chart; // eslint-disable-line no-undef | |||
return docSectionBuilder; | |||
}(); | |||
var lc = demoConfig.lineComposite; | |||
var lineCompositeChart = new Chart(lc.elementID, lc.options); | |||
var Chart = frappe.Chart; // eslint-disable-line no-undef | |||
var dcb = new docSectionBuilder(Chart); | |||
var bc = demoConfig.barComposite; | |||
var barCompositeChart = new Chart(bc.elementID, bc.options); | |||
var lineComposite = new Chart("#line-composite-1", dc.lineComposite.config); | |||
var barComposite = new Chart("#bar-composite-1", dc.barComposite.config); | |||
lineCompositeChart.parent.addEventListener('data-select', function (e) { | |||
lineComposite.parent.addEventListener('data-select', function (e) { | |||
var i = e.index; | |||
barCompositeChart.updateDatasets([fireballOver25[i], fireball_5_25[i], fireball_2_5[i]]); | |||
barComposite.updateDatasets([fireballOver25[i], fireball_5_25[i], fireball_2_5[i]]); | |||
}); | |||
// ================================================================================ | |||
@@ -346,6 +779,7 @@ var typeChartArgs = { | |||
type: 'axis-mixed', | |||
height: 300, | |||
colors: customColors, | |||
valuesOverPoints: 1, | |||
// maxLegendPoints: 6, | |||
maxSlices: 10, | |||
@@ -486,55 +920,10 @@ document.querySelector('.export-update').addEventListener('click', function () { | |||
// Trends Chart | |||
// ================================================================================ | |||
var plotChartArgs = { | |||
title: "Mean Total Sunspot Count - Yearly", | |||
data: trendsData, | |||
type: 'line', | |||
height: 300, | |||
colors: ['#238e38'], | |||
lineOptions: { | |||
hideDots: 1, | |||
heatline: 1 | |||
}, | |||
axisOptions: { | |||
xAxisMode: 'tick', | |||
yAxisMode: 'span', | |||
xIsSeries: 1 | |||
} | |||
}; | |||
var trendsChart = new Chart("#chart-trends", plotChartArgs); | |||
Array.prototype.slice.call(document.querySelectorAll('.chart-plot-buttons button')).map(function (el) { | |||
el.addEventListener('click', function (e) { | |||
var btn = e.target; | |||
var type = btn.getAttribute('data-type'); | |||
var config = {}; | |||
config[type] = 1; | |||
if (['regionFill', 'heatline'].includes(type)) { | |||
config.hideDots = 1; | |||
} | |||
// plotChartArgs.init = false; | |||
plotChartArgs.lineOptions = config; | |||
new Chart("#chart-trends", plotChartArgs); | |||
Array.prototype.slice.call(btn.parentNode.querySelectorAll('button')).map(function (el) { | |||
el.classList.remove('active'); | |||
}); | |||
btn.classList.add('active'); | |||
}); | |||
}); | |||
document.querySelector('.export-trends').addEventListener('click', function () { | |||
trendsChart.export(); | |||
}); | |||
// Event chart | |||
// ================================================================================ | |||
var section = document.querySelector('.trends-plot'); | |||
dcb.setParent(section); | |||
dcb.setSys(dc.trendsPlot); | |||
dcb.make(); | |||
var eventsData = { | |||
labels: ["Ganymede", "Callisto", "Io", "Europa"], | |||
@@ -569,104 +958,9 @@ eventsChart.parent.addEventListener('data-select', function (e) { | |||
// Heatmap | |||
// ================================================================================ | |||
var today = new Date(); | |||
var start = clone(today); | |||
addDays(start, 4); | |||
var end = clone(start); | |||
start.setFullYear(start.getFullYear() - 2); | |||
end.setFullYear(end.getFullYear() - 1); | |||
var dataPoints = {}; | |||
var startTs = timestampSec(start); | |||
var endTs = timestampSec(end); | |||
startTs = timestampToMidnight(startTs); | |||
endTs = timestampToMidnight(endTs, true); | |||
while (startTs < endTs) { | |||
dataPoints[parseInt(startTs)] = Math.floor(getRandomBias(0, 5, 0.2, 1)); | |||
startTs += SEC_IN_DAY; | |||
} | |||
var heatmapData = { | |||
dataPoints: dataPoints, | |||
start: start, | |||
end: end | |||
}; | |||
var heatmapArgs = { | |||
title: "Monthly Distribution", | |||
data: heatmapData, | |||
type: 'heatmap', | |||
discreteDomains: 1, | |||
countLabel: 'Level', | |||
colors: HEATMAP_COLORS_BLUE, | |||
legendScale: [0, 1, 2, 4, 5] | |||
}; | |||
var heatmapChart = new Chart("#chart-heatmap", heatmapArgs); | |||
Array.prototype.slice.call(document.querySelectorAll('.heatmap-mode-buttons button')).map(function (el) { | |||
el.addEventListener('click', function (e) { | |||
var btn = e.target; | |||
var mode = btn.getAttribute('data-mode'); | |||
var discreteDomains = 0; | |||
if (mode === 'discrete') { | |||
discreteDomains = 1; | |||
} | |||
var colors = []; | |||
var colors_mode = document.querySelector('.heatmap-color-buttons .active').getAttribute('data-color'); | |||
if (colors_mode === 'halloween') { | |||
colors = HEATMAP_COLORS_YELLOW; | |||
} else if (colors_mode === 'blue') { | |||
colors = HEATMAP_COLORS_BLUE; | |||
} | |||
heatmapArgs.discreteDomains = discreteDomains; | |||
heatmapArgs.colors = colors; | |||
new Chart("#chart-heatmap", heatmapArgs); | |||
Array.prototype.slice.call(btn.parentNode.querySelectorAll('button')).map(function (el) { | |||
el.classList.remove('active'); | |||
}); | |||
btn.classList.add('active'); | |||
}); | |||
}); | |||
Array.prototype.slice.call(document.querySelectorAll('.heatmap-color-buttons button')).map(function (el) { | |||
el.addEventListener('click', function (e) { | |||
var btn = e.target; | |||
var colors_mode = btn.getAttribute('data-color'); | |||
var colors = []; | |||
if (colors_mode === 'halloween') { | |||
colors = HEATMAP_COLORS_YELLOW; | |||
} else if (colors_mode === 'blue') { | |||
colors = HEATMAP_COLORS_BLUE; | |||
} | |||
var discreteDomains = 1; | |||
var view_mode = document.querySelector('.heatmap-mode-buttons .active').getAttribute('data-mode'); | |||
if (view_mode === 'continuous') { | |||
discreteDomains = 0; | |||
} | |||
heatmapArgs.discreteDomains = discreteDomains; | |||
heatmapArgs.colors = colors; | |||
new Chart("#chart-heatmap", heatmapArgs); | |||
Array.prototype.slice.call(btn.parentNode.querySelectorAll('button')).map(function (el) { | |||
el.classList.remove('active'); | |||
}); | |||
btn.classList.add('active'); | |||
}); | |||
}); | |||
document.querySelector('.export-heatmap').addEventListener('click', function () { | |||
heatmapChart.export(); | |||
}); | |||
section = document.querySelector('.heatmap'); | |||
dcb.setParent(section); | |||
dcb.setSys(dc.heatmap); | |||
dcb.make(); | |||
}()); |
@@ -4,7 +4,8 @@ | |||
<meta charset="UTF-8"> | |||
<title>Frappe Charts</title> | |||
<meta name="viewport" content="width=device-width, initial-scale=1"> | |||
<meta name="keywords" content="open source javascript js charts library svg zero-dependency interactive data visualization beautiful drag resize"> | |||
<meta name="keywords" content="open source javascript js charts library svg zero-dependency | |||
interactive data visualization beautiful drag resize"> | |||
<meta name="description" content="A simple, responsive, modern charts library for the web."> | |||
<link rel="stylesheet" type="text/css" href="assets/css/reset.css" media="screen"> | |||
@@ -24,18 +25,20 @@ | |||
<body> | |||
<header> | |||
<h1>Frappe Charts</h1> | |||
<p class="lead-text">GitHub-inspired simple and modern SVG charts for the web<br>with zero dependencies.</p> | |||
<div id="chart-composite-1" class="border"></div> | |||
<p class="lead-text">GitHub-inspired simple and modern SVG charts for the web | |||
<br>with zero dependencies.</p> | |||
<figure id="line-composite-1" class="border"></figure> | |||
<p class="demo-tip">Click or use arrow keys to navigate data points</p> | |||
<div id="chart-composite-2" class="border"></div> | |||
<figure id="bar-composite-1" class="border"></figure> | |||
</header> | |||
<section> | |||
<h6>Create a chart</h6> | |||
<p>Click or use arrow keys to navigate data points</p> | |||
<pre><code class="hljs html"> <!--HTML--> | |||
<div id="chart"></div></code></pre> | |||
<figure id="frost-chart"></figure></code></pre> | |||
<pre><code class="hljs javascript"> // Javascript | |||
let chart = new frappe.Chart( "#chart", { // or DOM element | |||
let chart = new frappe.Chart( "#frost-chart", { // or DOM element | |||
data: { | |||
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm", | |||
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"], | |||
@@ -76,14 +79,13 @@ | |||
</code></pre> | |||
<div id="chart-aggr" class="border"></div> | |||
<div class="btn-group aggr-type-buttons margin-top mx-auto" role="group"> | |||
<div class="btn-group aggr-type-buttons mt1 mx-auto" role="group"> | |||
<button type="button" class="btn btn-sm btn-secondary active" data-type='axis-mixed'>Mixed</button> | |||
<button type="button" class="btn btn-sm btn-secondary" data-type='pie'>Pie Chart</button> | |||
<button type="button" class="btn btn-sm btn-secondary" data-type='percentage'>Percentage Chart</button> | |||
</div> | |||
<div class="btn-group export-buttons margin-top mx-auto" role="group"> | |||
<button type="button" class="btn btn-sm btn-secondary export-aggr">Export ...</button> | |||
</div> | |||
<button type="button" class="btn btn-sm btn-secondary export-aggr mt1">Export ...</button> | |||
</section> | |||
<section> | |||
@@ -98,20 +100,7 @@ | |||
</div> | |||
</section> | |||
<section> | |||
<h6>Plot Trends</h6> | |||
<div id="chart-trends" class="border"></div> | |||
<div class="btn-group chart-plot-buttons mt-1 mx-auto" role="group"> | |||
<button type="button" class="btn btn-sm btn-secondary" data-type="hideDots">Line</button> | |||
<button type="button" class="btn btn-sm btn-secondary" data-type="hideLine">Dots</button> | |||
<button type="button" class="btn btn-sm btn-secondary active" data-type="heatline">HeatLine</button> | |||
<button type="button" class="btn btn-sm btn-secondary" data-type="regionFill">Region</button> | |||
</div> | |||
<div class="btn-group export-buttons mt-1 mx-auto" role="group"> | |||
<button type="button" class="btn btn-sm btn-secondary export-trends">Export ...</button> | |||
</div> | |||
</section> | |||
<section class="trends-plot"></section> | |||
<section> | |||
<h6>Listen to state change</h6> | |||
@@ -123,7 +112,7 @@ | |||
<div class="image-container border"> | |||
<img class="moon-image" src="./assets/img/europa.jpg"> | |||
</div> | |||
<div class="content-data margin-top"> | |||
<div class="content-data mt1"> | |||
<h6 class="moon-name">Europa</h6> | |||
<p>Semi-major-axis: <span class="semi-major-axis">671034</span> km</p> | |||
<p>Mass: <span class="mass">4800000</span> x 10^16 kg</p> | |||
@@ -131,7 +120,7 @@ | |||
</div> | |||
</div> | |||
</div> | |||
<pre><code class="hljs javascript margin-top"> ... | |||
<pre><code class="hljs javascript mt1"> ... | |||
isNavigable: 1, // Navigate across data points; default 0 | |||
... | |||
@@ -140,41 +129,7 @@ | |||
});</code></pre> | |||
</section> | |||
<section> | |||
<h6> | |||
And a Month-wise Heatmap | |||
</h6> | |||
<div id="chart-heatmap" class="border" | |||
style="overflow: scroll;"></div> | |||
<div class="heatmap-mode-buttons btn-group mt-1 mx-auto" role="group"> | |||
<button type="button" class="btn btn-sm btn-secondary active" data-mode="discrete">Discrete</button> | |||
<button type="button" class="btn btn-sm btn-secondary" data-mode="continuous">Continuous</button> | |||
</div> | |||
<div class="heatmap-color-buttons btn-group mt-1 mx-auto" role="group"> | |||
<button type="button" class="btn btn-sm btn-secondary" data-color="default">Green (Default)</button> | |||
<button type="button" class="btn btn-sm btn-secondary active" data-color="blue">Blue</button> | |||
<button type="button" class="btn btn-sm btn-secondary" data-color="halloween">GitHub's Halloween</button> | |||
</div> | |||
<div class="btn-group export-buttons mt-1 mx-auto" role="group"> | |||
<button type="button" class="btn btn-sm btn-secondary export-heatmap">Export ...</button> | |||
</div> | |||
<pre><code class="hljs javascript margin-top"> let heatmap = new frappe.Chart("#heatmap", { | |||
type: 'heatmap', | |||
title: "Monthly Distribution", | |||
data: { | |||
dataPoints: {'1524064033': 8, /* ... */}, | |||
// object with timestamp-value pairs | |||
start: startDate | |||
end: endDate // Date objects | |||
}, | |||
countLabel: 'Level', | |||
discreteDomains: 0 // default: 1 | |||
colors: ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'], | |||
// Set of five incremental colors, | |||
// preferably with a low-saturation color for zero data; | |||
// def: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'] | |||
});</code></pre> | |||
</section> | |||
<section class="heatmap"></section> | |||
<section> | |||
<h6>Demo</h6> | |||
@@ -279,11 +234,11 @@ | |||
<section class="text-center"> | |||
<!-- Closing --> | |||
<a href="https://github.com/frappe/charts/archive/master.zip"><button class="large blue button btn">Download</button></a> | |||
<p style="margin-top: 3rem;margin-bottom: 1.5rem;"> | |||
<p style="mt1: 3rem;margin-bottom: 1.5rem;"> | |||
<!-- <a href="docs.html" style="margin-right: 1rem;" target="_blank">Documentation</a> --> | |||
<a href="https://github.com/frappe/charts" target="_blank">View on GitHub</a> | |||
</p> | |||
<p style="margin-top: 1rem;"> | |||
<p style="mt1: 1rem;"> | |||
<a class="github-button" href="https://github.com/frappe/charts" data-icon="octicon-star" data-show-count="true" aria-label="Star frappe/charts on GitHub">Star</a> | |||
</p> | |||
<p>License: MIT</p> | |||
@@ -26,6 +26,9 @@ $.create = (tag, o) => { | |||
ref.parentNode.insertBefore(element, ref); | |||
element.appendChild(ref); | |||
} else if (i === "onClick" ) { | |||
element.addEventListener('click', val); | |||
} else if (i === "styles") { | |||
if(typeof val === "object") { | |||
Object.keys(val).map(prop => { | |||
@@ -118,13 +121,17 @@ export function forEachNode(nodeList, callback, scope) { | |||
} | |||
} | |||
export function activate($parent, $child, commonClass, activeClass='active', index = -1) { | |||
let $children = $parent.querySelectorAll(`.${commonClass}.${activeClass}`); | |||
export function activate($parent, $child, commonSelector, activeClass='active', index = -1) { | |||
let $children = $parent.querySelectorAll(`${commonSelector}.${activeClass}`); | |||
if (typeof $child === 'string') { | |||
$child = $parent.querySelector($child); | |||
} | |||
forEachNode($children, (node, i) => { | |||
this.forEachNode($children, (node, i) => { | |||
if(index >= 0 && i <= index) return; | |||
node.classList.remove(activeClass); | |||
}); | |||
}) | |||
$child.classList.add(activeClass); | |||
} |