@@ -139,9 +139,11 @@ const AXIS_CHART_DEFAULT_TYPE = 'line'; | |||
const AXIS_DATASET_CHART_TYPES = ['line', 'bar']; | |||
const AXIS_LEGEND_BAR_SIZE = 100; | |||
const BAR_CHART_SPACE_RATIO = 0.5; | |||
const BAR_CHART_SPACE_RATIO = 1; | |||
const MIN_BAR_PERCENT_HEIGHT = 0.01; | |||
const LINE_CHART_DOT_SIZE = 4; | |||
@@ -304,10 +306,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)); | |||
} | |||
@@ -1464,6 +1462,7 @@ class BaseChart { | |||
if(this.independentWidth) { | |||
args.styles = { width: this.independentWidth + 'px' }; | |||
this.parent.style.overflow = 'auto'; | |||
} | |||
this.container = $.create('div', args); | |||
@@ -3352,7 +3351,7 @@ class AxisChart extends BaseChart { | |||
let stacked = this.barOptions.stacked; | |||
let spaceRatio = this.barOptions.spaceRatio || BAR_CHART_SPACE_RATIO; | |||
let barsWidth = s.unitWidth * (1 - spaceRatio); | |||
let barsWidth = s.unitWidth/2 * (2 - spaceRatio); | |||
let barWidth = barsWidth/(stacked ? 1 : barDatasets.length); | |||
let xPositions = s.xAxis.positions.map(x => x - barsWidth/2); | |||
@@ -3686,7 +3685,6 @@ class AxisChart extends BaseChart { | |||
// removeDataPoint(index = 0) {} | |||
} | |||
// import MultiAxisChart from './charts/MultiAxisChart'; | |||
const chartTypes = { | |||
bar: AxisChart, | |||
line: AxisChart, | |||
@@ -49,7 +49,6 @@ section { | |||
section figure { | |||
border: 1px solid #ddd; /* SAME 3 */ | |||
border-radius: 3px; | |||
overflow: auto; | |||
} | |||
.btn, .btn-group { | |||
margin-bottom: 1rem; | |||
@@ -64,6 +63,9 @@ h1 { | |||
h1, h6 { | |||
font-weight: 700; | |||
} | |||
p.new-context { | |||
margin-top: 2rem; | |||
} | |||
.btn { | |||
outline: none !important; | |||
} | |||
@@ -291,5 +291,19 @@ export const sampleData = { | |||
{ name: "Dataset 1", values: [18, 40, 30, 35, 8, 52, 17, -4] }, | |||
{ name: "Dataset 2", values: [30, 50, -10, 15, 18, 32, 27, 14] } | |||
] | |||
}, | |||
2: { | |||
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon"], | |||
datasets: [ | |||
{ values: [300, 250, 720, 560, 370, 610, 690, 410, | |||
370, 480, 620, 260, 170, 510, 630, 710] } | |||
] | |||
}, | |||
3: { | |||
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], | |||
datasets: [ | |||
{ values: [300, 250, 720, 560, 370, 610, 690, 410, | |||
370, 480, 620, 260, 170, 510, 630, 710, 560, 370, 610, 260, 170] } | |||
] | |||
} | |||
} |
@@ -46,6 +46,7 @@ class docSection { | |||
getText(blockConf) { | |||
return $.create('p', { | |||
inside: this.parent, | |||
className: 'new-context', | |||
innerHTML: blockConf.content | |||
}); | |||
} | |||
@@ -1,13 +1,14 @@ | |||
import { sampleData } from './data'; | |||
import { sampleData, trendsData } from './data'; | |||
export const docSections = [ | |||
{ | |||
name: "start", | |||
contentBlocks: [ | |||
// Intro | |||
{ | |||
type: "text", | |||
content: `A chart is generally a 2D rendition of data. For example, f | |||
or a set of values across items, the data could look like:` | |||
content: `A chart is generally a 2D rendition of data. For example, | |||
for a set of values across items, the data could look like:` | |||
}, | |||
{ | |||
type: "code", | |||
@@ -18,9 +19,11 @@ export const docSections = [ | |||
] | |||
}` | |||
}, | |||
// type: 'bar' | |||
{ | |||
type: "text", | |||
content: `Plug that in with a type 'bar', a color and height:` | |||
content: `Plug that in with a type <b>bar</b>, a color and height:` | |||
}, | |||
{ | |||
type: "code", | |||
@@ -35,29 +38,198 @@ export const docSections = [ | |||
type: "demo", | |||
config: { | |||
data: sampleData[0], | |||
type: 'line', | |||
type: 'bar', | |||
height: 140, | |||
colors: ['red'], | |||
}, | |||
}, | |||
// type: 'line' | |||
{ | |||
type: "text", | |||
content: `Similar is a 'line' chart:` | |||
content: `And similarly, a <b>line</b> chart:` | |||
}, | |||
{ | |||
type: "code", | |||
content: ` ... | |||
type: 'line', | |||
...` | |||
content: ` ... | |||
type: 'line', | |||
...` | |||
}, | |||
{ | |||
type: "demo", | |||
config: { | |||
data: sampleData[0], | |||
type: 'line', | |||
height: 140, | |||
colors: ['red'], | |||
}, | |||
}, | |||
// Axes lines: | |||
{ | |||
type: "text", | |||
content: `Axes lines are configurable. By default they are long | |||
<b>span</b>ning lines, but can also be short <b>tick</b>s:` | |||
}, | |||
{ | |||
type: "code", | |||
content: ` ... | |||
axisOptions: { | |||
xAxisMode: 'tick' // default: 'span' | |||
}, | |||
...` | |||
}, | |||
{ | |||
type: "demo", | |||
config: { | |||
data: sampleData[2], | |||
type: 'bar', | |||
height: 140, | |||
colors: ['blue'], | |||
colors: ['blue'], | |||
axisOptions: { | |||
xAxisMode: "tick", | |||
}, | |||
}, | |||
}, | |||
// Bar width: | |||
{ | |||
type: "text", | |||
content: `The bar <b>width</b> can be set by defining the <b>ratio of the space</b> | |||
between bars to the bar width.` | |||
}, | |||
{ | |||
type: "code", | |||
content: ` ... | |||
barOptions: { | |||
spaceRatio: 0.2 // default: 1 | |||
}, | |||
...` | |||
}, | |||
{ | |||
type: "demo", | |||
config: { | |||
data: sampleData[3], | |||
type: 'bar', | |||
height: 140, | |||
colors: ['orange'], | |||
axisOptions: { | |||
xAxisMode: "tick" | |||
}, | |||
barOptions: { | |||
spaceRatio: 0.2 | |||
}, | |||
}, | |||
options: [ | |||
{ | |||
name: "barOptions", | |||
path: ["barOptions"], | |||
type: "map", | |||
mapKeys: ['spaceRatio'], | |||
states: { | |||
"0.2": [0.2], | |||
"0.5": [0.5], | |||
"1": [1], | |||
"1.5": [1.5] | |||
}, | |||
activeState: "0.2" | |||
} | |||
] | |||
}, | |||
// Dot radius: | |||
{ | |||
type: "text", | |||
content: 'So can the <b>dot size</b> on a line graph, with the `dotSize` property in `lineOptions`.' | |||
}, | |||
{ | |||
type: "code", | |||
content: ` ... | |||
lineOptions: { | |||
dotRadius: 8 // default: 4 | |||
}, | |||
...` | |||
}, | |||
{ | |||
type: "demo", | |||
config: { | |||
data: sampleData[2], | |||
type: 'line', | |||
height: 140, | |||
colors: ['orange'], | |||
axisOptions: { | |||
xAxisMode: "tick" | |||
}, | |||
lineOptions: { | |||
dotSize: 8 | |||
} | |||
}, | |||
options: [ | |||
{ | |||
name: "lineOptions", | |||
path: ["lineOptions"], | |||
type: "map", | |||
mapKeys: ['dotSize'], | |||
states: { | |||
"3": [3], | |||
"4": [4], | |||
"8": [8], | |||
"10": [10], | |||
}, | |||
activeState: "8" | |||
} | |||
] | |||
}, | |||
] | |||
}, | |||
{ | |||
title: "Trends and region charts", | |||
name: "trends-and-region", | |||
contentBlocks: [ | |||
{ | |||
type: "text", | |||
content: 'lineOptions` have a bunch of other properties too. Region charts are' | |||
}, | |||
{ | |||
type: "code", | |||
content: ` ... | |||
data: { | |||
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], | |||
datasets: [ | |||
{ name: "Dataset 1", values: [18, 40, 30, 35, 8, 52, 17, -4] }, | |||
{ name: "Dataset 2", values: [30, 50, -10, 15, 18, 32, 27, 14] } | |||
] | |||
}, | |||
...` | |||
}, | |||
{ | |||
type: "demo", | |||
config: { | |||
data: trendsData, | |||
type: 'line', | |||
height: 180, | |||
colors: ['violet'], | |||
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" | |||
} | |||
] | |||
} | |||
] | |||
}, | |||
@@ -67,7 +239,19 @@ export const docSections = [ | |||
contentBlocks: [ | |||
{ | |||
type: "text", | |||
content: `Having more datasets, as in an axis chart, every dataset is represented individually.` | |||
content: `A chart can have multiple datasets. In an axis chart, every dataset is represented individually.` | |||
}, | |||
{ | |||
type: "code", | |||
content: ` ... | |||
data: { | |||
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], | |||
datasets: [ | |||
{ name: "Dataset 1", values: [18, 40, 30, 35, 8, 52, 17, -4] }, | |||
{ name: "Dataset 2", values: [30, 50, -10, 15, 18, 32, 27, 14] } | |||
] | |||
}, | |||
...` | |||
}, | |||
{ | |||
type: "demo", | |||
@@ -75,8 +259,20 @@ export const docSections = [ | |||
data: sampleData[1], | |||
type: 'line', | |||
height: 200, | |||
colors: ['yellow', 'light-green'], | |||
colors: ['green', 'light-green'], | |||
}, | |||
options: [ | |||
{ | |||
name: "type", | |||
path: ["type"], | |||
type: "string", | |||
states: { | |||
"Line": 'line', | |||
"Bar": 'bar', | |||
}, | |||
activeState: "Mixed" | |||
} | |||
], | |||
} | |||
] | |||
} |
@@ -214,6 +214,7 @@ var MONTH_NAMES_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", | |||
// https://stackoverflow.com/a/11252167/6495043 | |||
function clone(date) { | |||
@@ -272,12 +273,6 @@ var HEATMAP_COLORS_YELLOW = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001 | |||
// Universal constants | |||
/** | |||
* Returns the value of a number upto 2 decimal places. | |||
* @param {Number} d Any number | |||
*/ | |||
/** | |||
* Returns whether or not two given arrays are equal. | |||
* @param {Array} arr1 First array | |||
@@ -340,8 +335,6 @@ function toTitleCase(str) { | |||
}); | |||
} | |||
// Composite Chart | |||
// ================================================================================ | |||
var reportCountList = [152, 222, 199, 287, 534, 709, 1179, 1256, 1632, 1856, 1850]; | |||
var lineCompositeData = { | |||
@@ -563,6 +556,14 @@ var sampleData = { | |||
1: { | |||
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], | |||
datasets: [{ name: "Dataset 1", values: [18, 40, 30, 35, 8, 52, 17, -4] }, { name: "Dataset 2", values: [30, 50, -10, 15, 18, 32, 27, 14] }] | |||
}, | |||
2: { | |||
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon"], | |||
datasets: [{ values: [300, 250, 720, 560, 370, 610, 690, 410, 370, 480, 620, 260, 170, 510, 630, 710] }] | |||
}, | |||
3: { | |||
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], | |||
datasets: [{ values: [300, 250, 720, 560, 370, 610, 690, 410, 370, 480, 620, 260, 170, 510, 630, 710, 560, 370, 610, 260, 170] }] | |||
} | |||
}; | |||
@@ -804,15 +805,20 @@ var demoSections = [{ | |||
var docSections = [{ | |||
name: "start", | |||
contentBlocks: [{ | |||
contentBlocks: [ | |||
// Intro | |||
{ | |||
type: "text", | |||
content: "A chart is generally a 2D rendition of data. For example, f\n\t\t\t\t\tor a set of values across items, the data could look like:" | |||
content: "A chart is generally a 2D rendition of data. For example,\n\t\t\t\t\tfor a set of values across items, the data could look like:" | |||
}, { | |||
type: "code", | |||
content: " data = {\n labels: [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"],\n datasets: [\n\t { values: [18, 40, 30, 35, 8, 52, 17, -4] }\n ]\n }" | |||
}, { | |||
}, | |||
// type: 'bar' | |||
{ | |||
type: "text", | |||
content: "Plug that in with a type 'bar', a color and height:" | |||
content: "Plug that in with a type <b>bar</b>, a color and height:" | |||
}, { | |||
type: "code", | |||
content: " new frappe.Chart( \"#chart\", {\n data: data,\n type: 'bar',\n height: 140,\n colors: ['red']\n });" | |||
@@ -820,39 +826,183 @@ var docSections = [{ | |||
type: "demo", | |||
config: { | |||
data: sampleData[0], | |||
type: 'line', | |||
type: 'bar', | |||
height: 140, | |||
colors: ['red'] | |||
} | |||
}, { | |||
}, | |||
// type: 'line' | |||
{ | |||
type: "text", | |||
content: "Similar is a 'line' chart:" | |||
content: "And similarly, a <b>line</b> chart:" | |||
}, { | |||
type: "code", | |||
content: " ...\n type: 'line',\n ..." | |||
content: " ...\n type: 'line',\n ..." | |||
}, { | |||
type: "demo", | |||
config: { | |||
data: sampleData[0], | |||
type: 'line', | |||
height: 140, | |||
colors: ['red'] | |||
} | |||
}, | |||
// Axes lines: | |||
{ | |||
type: "text", | |||
content: "Axes lines are configurable. By default they are long\n\t\t\t\t\t<b>span</b>ning lines, but can also be short <b>tick</b>s:" | |||
}, { | |||
type: "code", | |||
content: " ...\n axisOptions: {\n xAxisMode: 'tick' // default: 'span'\n },\n ..." | |||
}, { | |||
type: "demo", | |||
config: { | |||
data: sampleData[2], | |||
type: 'bar', | |||
height: 140, | |||
colors: ['blue'] | |||
colors: ['blue'], | |||
axisOptions: { | |||
xAxisMode: "tick" | |||
} | |||
} | |||
}, | |||
// Bar width: | |||
{ | |||
type: "text", | |||
content: "The bar <b>width</b> can be set by defining the <b>ratio of the space</b>\n\t\t\t\t\tbetween bars to the bar width." | |||
}, { | |||
type: "code", | |||
content: " ...\n barOptions: {\n spaceRatio: 0.2 // default: 1\n },\n ..." | |||
}, { | |||
type: "demo", | |||
config: { | |||
data: sampleData[3], | |||
type: 'bar', | |||
height: 140, | |||
colors: ['orange'], | |||
axisOptions: { | |||
xAxisMode: "tick" | |||
}, | |||
barOptions: { | |||
spaceRatio: 0.2 | |||
} | |||
}, | |||
options: [{ | |||
name: "barOptions", | |||
path: ["barOptions"], | |||
type: "map", | |||
mapKeys: ['spaceRatio'], | |||
states: { | |||
"0.2": [0.2], | |||
"0.5": [0.5], | |||
"1": [1], | |||
"1.5": [1.5] | |||
}, | |||
activeState: "0.2" | |||
}] | |||
}, | |||
// Dot radius: | |||
{ | |||
type: "text", | |||
content: 'So can the <b>dot size</b> on a line graph, with the `dotSize` property in `lineOptions`.' | |||
}, { | |||
type: "code", | |||
content: " ...\n lineOptions: {\n dotRadius: 8 // default: 4\n },\n ..." | |||
}, { | |||
type: "demo", | |||
config: { | |||
data: sampleData[2], | |||
type: 'line', | |||
height: 140, | |||
colors: ['orange'], | |||
axisOptions: { | |||
xAxisMode: "tick" | |||
}, | |||
lineOptions: { | |||
dotSize: 8 | |||
} | |||
}, | |||
options: [{ | |||
name: "lineOptions", | |||
path: ["lineOptions"], | |||
type: "map", | |||
mapKeys: ['dotSize'], | |||
states: { | |||
"3": [3], | |||
"4": [4], | |||
"8": [8], | |||
"10": [10] | |||
}, | |||
activeState: "8" | |||
}] | |||
}] | |||
}, { | |||
title: "Trends and region charts", | |||
name: "trends-and-region", | |||
contentBlocks: [{ | |||
type: "text", | |||
content: 'lineOptions` have a bunch of other properties too. Region charts are' | |||
}, { | |||
type: "code", | |||
content: " ...\n data: {\n labels: [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"],\n datasets: [\n { name: \"Dataset 1\", values: [18, 40, 30, 35, 8, 52, 17, -4] },\n { name: \"Dataset 2\", values: [30, 50, -10, 15, 18, 32, 27, 14] }\n ]\n },\n ..." | |||
}, { | |||
type: "demo", | |||
config: { | |||
data: trendsData, | |||
type: 'line', | |||
height: 180, | |||
colors: ['violet'], | |||
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" | |||
}] | |||
}] | |||
}, { | |||
title: "Adding more datasets", | |||
name: "multi-dataset", | |||
contentBlocks: [{ | |||
type: "text", | |||
content: "Having more datasets, as in an axis chart, every dataset is represented individually." | |||
content: "A chart can have multiple datasets. In an axis chart, every dataset is represented individually." | |||
}, { | |||
type: "code", | |||
content: " ...\n data: {\n labels: [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"],\n datasets: [\n { name: \"Dataset 1\", values: [18, 40, 30, 35, 8, 52, 17, -4] },\n { name: \"Dataset 2\", values: [30, 50, -10, 15, 18, 32, 27, 14] }\n ]\n },\n ..." | |||
}, { | |||
type: "demo", | |||
config: { | |||
data: sampleData[1], | |||
type: 'line', | |||
height: 200, | |||
colors: ['yellow', 'light-green'] | |||
} | |||
colors: ['green', 'light-green'] | |||
}, | |||
options: [{ | |||
name: "type", | |||
path: ["type"], | |||
type: "string", | |||
states: { | |||
"Line": 'line', | |||
"Bar": 'bar' | |||
}, | |||
activeState: "Mixed" | |||
}] | |||
}] | |||
}]; | |||
@@ -922,6 +1072,7 @@ var docSection = function () { | |||
value: function getText(blockConf) { | |||
return $.create('p', { | |||
inside: this.parent, | |||
className: 'new-context', | |||
innerHTML: blockConf.content | |||
}); | |||
} | |||
@@ -32,16 +32,11 @@ | |||
<footer class="built-with-frappe text-center"> | |||
<img style="padding: 5px; width: 40px; background: #fff" class="frappe-bird" src="./assets/img/frappe-bird.png"> | |||
<p style="margin: 24px 0 0px 0; font-size: 15px"> | |||
<p style="margin: 24px 0 80px 0; font-size: 15px"> | |||
Project maintained by <a href="https://frappe.io" target="_blank">Frappe</a>. | |||
Used in <a href="https://erpnext.com" target="_blank">ERPNext</a>. | |||
Read the <a href="https://medium.com/@pratu16x7/so-we-decided-to-create-our-own-charts-a95cb5032c97" target="_blank">blog post</a>. | |||
</p> | |||
<p style="margin: 24px 0 80px 0; font-size: 12px"> | |||
Data from the <a href="https://www.amsmeteors.org" target="_blank">American Meteor Society</a>, | |||
<a href="http://www.sidc.be/silso" target="_blank">SILSO</a> and | |||
<a href="https://api.nasa.gov/index.html" target="_blank">NASA Open APIs</a> | |||
</p> | |||
</footer> | |||
<!-- <a href="https://github.com/frappe/charts" target="_blank" class="github-corner" aria-label="View source on Github"> | |||
@@ -248,7 +248,7 @@ export default class AxisChart extends BaseChart { | |||
let stacked = this.barOptions.stacked; | |||
let spaceRatio = this.barOptions.spaceRatio || BAR_CHART_SPACE_RATIO; | |||
let barsWidth = s.unitWidth * (1 - spaceRatio); | |||
let barsWidth = s.unitWidth/2 * (2 - spaceRatio); | |||
let barWidth = barsWidth/(stacked ? 1 : barDatasets.length); | |||
let xPositions = s.xAxis.positions.map(x => x - barsWidth/2); | |||
@@ -123,6 +123,7 @@ export default class BaseChart { | |||
if(this.independentWidth) { | |||
args.styles = { width: this.independentWidth + 'px' }; | |||
this.parent.style.overflow = 'auto'; | |||
} | |||
this.container = $.create('div', args); | |||
@@ -68,9 +68,15 @@ export const AXIS_CHART_MIXED_TYPE = 'axis-mixed'; | |||
export const AXIS_CHART_TYPES = ['line', 'bar', 'axis-mixed']; | |||
export const AXIS_DATASET_CHART_TYPES = ['line', 'bar']; | |||
export const AXIS_CHART_OPTIONS = { | |||
barOptions: { | |||
spaceRatio: 1, | |||
} | |||
} | |||
export const AXIS_LEGEND_BAR_SIZE = 100; | |||
export const BAR_CHART_SPACE_RATIO = 0.5; | |||
export const BAR_CHART_SPACE_RATIO = 1; | |||
export const MIN_BAR_PERCENT_HEIGHT = 0.01; | |||
export const LINE_CHART_DOT_SIZE = 4; | |||