@@ -18,6 +18,9 @@ $.create = (tag, o) => { | |||||
ref.parentNode.insertBefore(element, ref); | ref.parentNode.insertBefore(element, ref); | ||||
element.appendChild(ref); | element.appendChild(ref); | ||||
} else if (i === "onClick" ) { | |||||
element.addEventListener('click', val); | |||||
} else if (i === "styles") { | } else if (i === "styles") { | ||||
if(typeof val === "object") { | if(typeof val === "object") { | ||||
Object.keys(val).map(prop => { | 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) { | function floatTwo(d) { | ||||
return parseFloat(d.toFixed(2)); | return parseFloat(d.toFixed(2)); | ||||
} | } | ||||
@@ -3677,7 +3676,6 @@ class AxisChart extends BaseChart { | |||||
// removeDataPoint(index = 0) {} | // removeDataPoint(index = 0) {} | ||||
} | } | ||||
// import MultiAxisChart from './charts/MultiAxisChart'; | |||||
const chartTypes = { | const chartTypes = { | ||||
bar: AxisChart, | bar: AxisChart, | ||||
line: AxisChart, | line: AxisChart, | ||||
@@ -46,6 +46,14 @@ header .lead-text { | |||||
section { | section { | ||||
margin: 4em 0; /* SAME 1 */ | 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 { | h1 { | ||||
font-size: 3.5rem; | font-size: 3.5rem; | ||||
margin-bottom: 1.5rem; | margin-bottom: 1.5rem; | ||||
@@ -79,16 +87,19 @@ a, a:focus, a:hover { | |||||
/* BaseCSS */ | /* BaseCSS */ | ||||
.margin-top { | |||||
.mt1 { | |||||
margin-top: 1rem; /* SAME 2 */ | margin-top: 1rem; /* SAME 2 */ | ||||
} | } | ||||
.mv1 { | .mv1 { | ||||
margin: 2em 0 1em 0; | margin: 2em 0 1em 0; | ||||
} | } | ||||
.border { | .border { | ||||
border: 1px solid #ddd; | |||||
border: 1px solid #ddd; /* SAME 3 */ | |||||
border-radius: 3px; | border-radius: 3px; | ||||
} | } | ||||
.text-center { | |||||
text-align: center; | |||||
} | |||||
/* Moon images */ | /* Moon images */ | ||||
@@ -103,8 +114,3 @@ a, a:focus, a:hover { | |||||
margin-bottom: 5px; | margin-bottom: 5px; | ||||
font-size: 12px; | 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 | // 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 { | export default { | ||||
lineComposite: { | lineComposite: { | ||||
elementID: "#chart-composite-1", | |||||
options: { | |||||
config: { | |||||
title: "Fireball/Bolide Events - Yearly (reported)", | title: "Fireball/Bolide Events - Yearly (reported)", | ||||
data: lineCompositeData, | data: lineCompositeData, | ||||
type: "line", | type: "line", | ||||
@@ -19,8 +19,7 @@ export default { | |||||
}, | }, | ||||
barComposite: { | barComposite: { | ||||
elementID: "#chart-composite-2", | |||||
options: { | |||||
config: { | |||||
data: barCompositeData, | data: barCompositeData, | ||||
type: "bar", | type: "bar", | ||||
height: 210, | 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 { 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, | import { fireballOver25, fireball_2_5, fireball_5_25, lineCompositeData, | ||||
barCompositeData, typeData, trendsData, moonData } from './data'; | 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 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; | let i = e.index; | ||||
barCompositeChart.updateDatasets([ | |||||
barComposite.updateDatasets([ | |||||
fireballOver25[i], fireball_5_25[i], fireball_2_5[i] | fireballOver25[i], fireball_5_25[i], fireball_2_5[i] | ||||
]); | ]); | ||||
}); | }); | ||||
@@ -31,6 +27,7 @@ let typeChartArgs = { | |||||
type: 'axis-mixed', | type: 'axis-mixed', | ||||
height: 300, | height: 300, | ||||
colors: customColors, | colors: customColors, | ||||
valuesOverPoints: 1, | |||||
// maxLegendPoints: 6, | // maxLegendPoints: 6, | ||||
maxSlices: 10, | maxSlices: 10, | ||||
@@ -174,59 +171,10 @@ document.querySelector('.export-update').addEventListener('click', () => { | |||||
// Trends Chart | // 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 = { | let eventsData = { | ||||
@@ -262,112 +210,7 @@ eventsChart.parent.addEventListener('data-select', (e) => { | |||||
// Heatmap | // 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, | // Fixed 5-color theme, | ||||
// More colors are difficult to parse visually | // 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; | 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', | type: 'axis-mixed', | ||||
height: 300, | height: 300, | ||||
colors: customColors, | colors: customColors, | ||||
valuesOverPoints: 1, | |||||
// maxLegendPoints: 6, | // maxLegendPoints: 6, | ||||
maxSlices: 10, | maxSlices: 10, | ||||
@@ -486,55 +920,10 @@ document.querySelector('.export-update').addEventListener('click', function () { | |||||
// Trends Chart | // 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 = { | var eventsData = { | ||||
labels: ["Ganymede", "Callisto", "Io", "Europa"], | labels: ["Ganymede", "Callisto", "Io", "Europa"], | ||||
@@ -569,104 +958,9 @@ eventsChart.parent.addEventListener('data-select', function (e) { | |||||
// Heatmap | // 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"> | <meta charset="UTF-8"> | ||||
<title>Frappe Charts</title> | <title>Frappe Charts</title> | ||||
<meta name="viewport" content="width=device-width, initial-scale=1"> | <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."> | <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"> | <link rel="stylesheet" type="text/css" href="assets/css/reset.css" media="screen"> | ||||
@@ -24,18 +25,20 @@ | |||||
<body> | <body> | ||||
<header> | <header> | ||||
<h1>Frappe Charts</h1> | <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> | <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> | </header> | ||||
<section> | <section> | ||||
<h6>Create a chart</h6> | <h6>Create a chart</h6> | ||||
<p>Click or use arrow keys to navigate data points</p> | |||||
<pre><code class="hljs html"> <!--HTML--> | <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 | <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: { | data: { | ||||
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm", | labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm", | ||||
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"], | "12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"], | ||||
@@ -76,14 +79,13 @@ | |||||
</code></pre> | </code></pre> | ||||
<div id="chart-aggr" class="border"></div> | <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 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='pie'>Pie Chart</button> | ||||
<button type="button" class="btn btn-sm btn-secondary" data-type='percentage'>Percentage Chart</button> | <button type="button" class="btn btn-sm btn-secondary" data-type='percentage'>Percentage Chart</button> | ||||
</div> | </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> | ||||
<section> | <section> | ||||
@@ -98,20 +100,7 @@ | |||||
</div> | </div> | ||||
</section> | </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> | <section> | ||||
<h6>Listen to state change</h6> | <h6>Listen to state change</h6> | ||||
@@ -123,7 +112,7 @@ | |||||
<div class="image-container border"> | <div class="image-container border"> | ||||
<img class="moon-image" src="./assets/img/europa.jpg"> | <img class="moon-image" src="./assets/img/europa.jpg"> | ||||
</div> | </div> | ||||
<div class="content-data margin-top"> | |||||
<div class="content-data mt1"> | |||||
<h6 class="moon-name">Europa</h6> | <h6 class="moon-name">Europa</h6> | ||||
<p>Semi-major-axis: <span class="semi-major-axis">671034</span> km</p> | <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> | <p>Mass: <span class="mass">4800000</span> x 10^16 kg</p> | ||||
@@ -131,7 +120,7 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<pre><code class="hljs javascript margin-top"> ... | |||||
<pre><code class="hljs javascript mt1"> ... | |||||
isNavigable: 1, // Navigate across data points; default 0 | isNavigable: 1, // Navigate across data points; default 0 | ||||
... | ... | ||||
@@ -140,41 +129,7 @@ | |||||
});</code></pre> | });</code></pre> | ||||
</section> | </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> | <section> | ||||
<h6>Demo</h6> | <h6>Demo</h6> | ||||
@@ -279,11 +234,11 @@ | |||||
<section class="text-center"> | <section class="text-center"> | ||||
<!-- Closing --> | <!-- Closing --> | ||||
<a href="https://github.com/frappe/charts/archive/master.zip"><button class="large blue button btn">Download</button></a> | <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="docs.html" style="margin-right: 1rem;" target="_blank">Documentation</a> --> | ||||
<a href="https://github.com/frappe/charts" target="_blank">View on GitHub</a> | <a href="https://github.com/frappe/charts" target="_blank">View on GitHub</a> | ||||
</p> | </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> | <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> | ||||
<p>License: MIT</p> | <p>License: MIT</p> | ||||
@@ -26,6 +26,9 @@ $.create = (tag, o) => { | |||||
ref.parentNode.insertBefore(element, ref); | ref.parentNode.insertBefore(element, ref); | ||||
element.appendChild(ref); | element.appendChild(ref); | ||||
} else if (i === "onClick" ) { | |||||
element.addEventListener('click', val); | |||||
} else if (i === "styles") { | } else if (i === "styles") { | ||||
if(typeof val === "object") { | if(typeof val === "object") { | ||||
Object.keys(val).map(prop => { | 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; | if(index >= 0 && i <= index) return; | ||||
node.classList.remove(activeClass); | node.classList.remove(activeClass); | ||||
}); | |||||
}) | |||||
$child.classList.add(activeClass); | $child.classList.add(activeClass); | ||||
} | } |