Porovnat revize

...

19 Revize
master ... docs

Autor SHA1 Zpráva Datum
  Prateeksha Singh e8bbd2129f [docs] add configuration and navigation docs před 7 roky
  Prateeksha Singh 0a020a4709 [docs] chart-demo -> project-demo component před 7 roky
  Prateeksha Singh 1985d88208 [docs] numeric control, more docs před 7 roky
  Prateeksha Singh 6be7b6505c [docs] add aggregation/sliced charts před 7 roky
  Prateeksha Singh 95d08e006d [docs] complete annotations, mixed and stacked charts před 7 roky
  Prateeksha Singh d516ae4e9a [docs] complete trends_regions.md, regionFill -> areaFill před 7 roky
  Prateeksha Singh 3fe262c621 [docs] use Vue component demos in markdown itself před 7 roky
  Prateeksha Singh 0e7e91d428 [demoBuilder] add numeric toggle před 7 roky
  Prateeksha Singh 81a9a4e0e8 [docs] add more pages před 7 roky
  Prateeksha Singh fc874a76f1 [docs] update sidebar před 7 roky
  Prateeksha Singh 7dad65fd61 [docs] integrate search před 7 roky
  Prateeksha Singh c740ad9a85 [docs] add intro chart topics před 7 roky
  Prateeksha Singh 52d904da7d [docs][major] setup home and docsify page před 7 roky
  Prateeksha Singh 420206f749 [docs][major][init] setup docsify před 7 roky
  Prateeksha Singh bb596deb06 [fix] bar spaceRatio, overflow; add 2 more doc sections před 7 roky
  Prateeksha Singh c33473f52c [fixes] docs init, fix multi demos and axis override před 7 roky
  Prateeksha Singh a5f215eccc [docs] full migration of demo to docsBuilder před 7 roky
  Prateeksha Singh dc6ae93742 [docs] migrate more sections, demos and install před 7 roky
  Prateeksha Singh b4d098d1e8 [DOCS] Docs builder před 7 roky
55 změnil soubory, kde provedl 29085 přidání a 1502 odebrání
  1. +32
    -20
      dist/frappe-charts.esm.js
  2. +4330
    -1
      dist/frappe-charts.min.cjs.js
  3. +1
    -1
      dist/frappe-charts.min.cjs.js.map
  4. +4322
    -1
      dist/frappe-charts.min.esm.js
  5. +1
    -1
      dist/frappe-charts.min.esm.js.map
  6. +1
    -1
      dist/frappe-charts.min.iife.js
  7. +1
    -1
      dist/frappe-charts.min.iife.js.map
  8. +0
    -0
      docs/.nojekyll
  9. +136
    -0
      docs/README.md
  10. +28
    -0
      docs/_sidebar.md
  11. +27
    -10
      docs/assets/css/index.css
  12. +101
    -1
      docs/assets/js/data.js
  13. +436
    -54
      docs/assets/js/demoConfig.js
  14. +172
    -0
      docs/assets/js/docsBuilder.js
  15. +0
    -2
      docs/assets/js/frappe-charts.min.js
  16. +0
    -1
      docs/assets/js/frappe-charts.min.js.map
  17. +0
    -373
      docs/assets/js/index.js
  18. +0
    -672
      docs/assets/js/index.min.js
  19. +0
    -1
      docs/assets/js/index.min.js.map
  20. +86
    -0
      docs/basic/aggr_sliced_diags.md
  21. +108
    -0
      docs/basic/annotations.md
  22. +149
    -0
      docs/basic/basic_chart.md
  23. +70
    -0
      docs/basic/heatmap.md
  24. +95
    -0
      docs/basic/stacked_and_mixed.md
  25. +179
    -0
      docs/basic/trends_regions.md
  26. +15
    -0
      docs/contributing.md
  27. +321
    -0
      docs/data.js
  28. +250
    -0
      docs/demoBuilder.js
  29. +22
    -0
      docs/exporting/images.md
  30. +1
    -0
      docs/externals/docsify.min.js
  31. +10947
    -0
      docs/externals/vue.js
  32. +2
    -0
      docs/frappe-charts.min.iife.js
  33. +57
    -0
      docs/getting_started/quick_start.md
  34. +108
    -277
      docs/index.html
  35. +30
    -0
      docs/index.js
  36. +5653
    -0
      docs/index.min.js
  37. +57
    -0
      docs/reference/api.md
  38. +200
    -0
      docs/reference/configuration.md
  39. +15
    -0
      docs/style.css
  40. +60
    -0
      docs/update_state/modify_data.md
  41. +27
    -0
      docs/update_state/navigation.md
  42. +952
    -0
      docs/vuestyle.css
  43. +4
    -0
      docs/wrappers.md
  44. +4
    -5
      package.json
  45. +22
    -55
      rollup.config.js
  46. +1
    -1
      src/js/chart.js
  47. +2
    -3
      src/js/charts/AxisChart.js
  48. +2
    -1
      src/js/charts/BaseChart.js
  49. +1
    -1
      src/js/objects/ChartComponents.js
  50. +10
    -6
      src/js/utils/axis-chart-utils.js
  51. +12
    -3
      src/js/utils/constants.js
  52. +25
    -4
      src/js/utils/dom.js
  53. +1
    -1
      src/js/utils/draw.js
  54. +4
    -0
      src/js/utils/helpers.js
  55. +5
    -5
      yarn.lock

+ 32
- 20
dist/frappe-charts.esm.js Zobrazit soubor

@@ -18,6 +18,14 @@ $.create = (tag, o) => {
ref.parentNode.insertBefore(element, ref);
element.appendChild(ref);

} else if (i === "onClick" ) {
element.addEventListener('click', val);

} else if (i === "onInput" ) {
element.addEventListener('input', function(e) {
val(element.value);
});

} else if (i === "styles") {
if(typeof val === "object") {
Object.keys(val).map(prop => {
@@ -99,6 +107,7 @@ const BASE_MEASURES = {
},

baseHeight: 240,

titleHeight: 20,
legendHeight: 30,

@@ -130,13 +139,17 @@ function getExtraWidth(m) {
const INIT_CHART_UPDATE_TIMEOUT = 700;
const CHART_POST_ANIMATE_TIMEOUT = 400;

const DEFAULT_AXIS_CHART_TYPE = 'line';
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 MIN_BAR_PERCENT_HEIGHT = 0.01;
const BAR_CHART_SPACE_RATIO = 1;
const MIN_BAR_PERCENT_HEIGHT = 0.02;

const LINE_CHART_DOT_SIZE = 4;
const DOT_OVERLAY_SIZE_INCR = 4;
@@ -298,10 +311,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));
}
@@ -969,7 +978,7 @@ function getPaths(xList, yList, color, options={}, meta={}) {
};

// Region
if(options.regionFill) {
if(options.areaFill) {
let gradient_id_region = makeGradient(meta.svgDefs, color, true);

let pathStr = "M" + `${xList[0]},${meta.zeroLine}L` + pointsStr + `L${xList.slice(-1)[0]},${meta.zeroLine}`;
@@ -1358,7 +1367,7 @@ class BaseChart {
this.rawChartArgs = options;

this.title = options.title || '';
this.type = options.type || '';
this.type = options.type || 'line';

this.realData = this.prepareData(options.data);
this.data = this.prepareFirstData(this.realData);
@@ -1458,6 +1467,7 @@ class BaseChart {

if(this.independentWidth) {
args.styles = { width: this.independentWidth + 'px' };
this.parent.style.overflow = 'auto';
}

this.container = $.create('div', args);
@@ -2163,7 +2173,7 @@ let componentConfigs = {
c.color,
{
heatline: c.heatline,
regionFill: c.regionFill
areaFill: c.areaFill
},
{
svgDefs: c.svgDefs,
@@ -2995,6 +3005,11 @@ function dataPrep(data, type) {
}];
}

let overridingType;
if(AXIS_DATASET_CHART_TYPES.includes(type)) {
overridingType = type;
}

datasets.map(d=> {
// Set values
if(!d.values) {
@@ -3013,14 +3028,13 @@ function dataPrep(data, type) {
}

// Set labels
//

// Set type
if(!d.chartType ) {
if(!AXIS_DATASET_CHART_TYPES.includes(type)) type === DEFAULT_AXIS_CHART_TYPE;
d.chartType = type;
if(overridingType) {
d.chartType = overridingType;
} else if(!d.chartType) {
d.chartType = AXIS_CHART_DEFAULT_TYPE;
}

});

// Markers
@@ -3110,7 +3124,6 @@ class AxisChart extends BaseChart {
this.barOptions = args.barOptions || {};
this.lineOptions = args.lineOptions || {};

this.type = args.type || 'line';
this.init = 1;

this.setup();
@@ -3343,7 +3356,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);
@@ -3389,7 +3402,7 @@ class AxisChart extends BaseChart {
color: this.colors[index],
svgDefs: this.svgDefs,
heatline: this.lineOptions.heatline,
regionFill: this.lineOptions.regionFill,
areaFill: this.lineOptions.areaFill,
hideDots: this.lineOptions.hideDots,
hideLine: this.lineOptions.hideLine,

@@ -3677,7 +3690,6 @@ class AxisChart extends BaseChart {
// removeDataPoint(index = 0) {}
}

// import MultiAxisChart from './charts/MultiAxisChart';
const chartTypes = {
bar: AxisChart,
line: AxisChart,
@@ -3689,7 +3701,7 @@ const chartTypes = {

function getChartByType(chartType = 'line', parent, options) {
if (chartType === 'axis-mixed') {
options.type = 'line';
// options.type = 'line';
return new AxisChart(parent, options);
}



+ 4330
- 1
dist/frappe-charts.min.cjs.js
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 1
- 1
dist/frappe-charts.min.cjs.js.map
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 4322
- 1
dist/frappe-charts.min.esm.js
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 1
- 1
dist/frappe-charts.min.esm.js.map
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 1
- 1
dist/frappe-charts.min.iife.js
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 1
- 1
dist/frappe-charts.min.iife.js.map
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


docs/docs.html → docs/.nojekyll Zobrazit soubor


+ 136
- 0
docs/README.md Zobrazit soubor

@@ -0,0 +1,136 @@
<div align="center">
<img src="https://github.com/frappe/design/blob/master/logos/charts-logo.svg" height="128">
<a href="https://frappe.github.io/charts">
<h2>Frappe Charts</h2>
</a>
<p align="center">
<p>GitHub-inspired modern, intuitive and responsive charts with zero dependencies</p>
<a href="https://frappe.github.io/charts">
<b>Explore Demos » </b>
</a>
<a href="https://codepen.io/pratu16x7/pen/wjKBoq">
<b> Edit at CodePen »</b>
</a>
</p>
</div>

<p align="center">
<a href="https://travis-ci.org/frappe/charts">
<img src="https://img.shields.io/travis/frappe/charts.svg?style=flat-square">
</a>
<a href="http://github.com/frappe/charts/tree/master/dist/js/frappe-charts.min.iife.js">
<img src="http://img.badgesize.io/frappe/charts/master/dist/frappe-charts.min.iife.js.svg?compression=gzip">
</a>
<a href="https://travis-ci.org/frappe/charts">
<img src="https://img.shields.io/travis/frappe/charts.svg?style=flat-square">
</a>
</p>
<!--
<p align="center">
<a href="https://frappe.github.io/charts">
<img src=".github/example.gif">
</a>
</p> -->

### Contents
* [Installation](#installation)
* [Usage](#usage)
* [Updates](#updates)
* [License](#license)

#### Installation
* Install via [`npm`](https://www.npmjs.com/get-npm):

```console
$ npm install frappe-charts
```

and include in your project:
```js
import { Chart } from "frappe-charts"
```

* ...or include within your HTML

```html
<script src="https://cdn.jsdelivr.net/npm/frappe-charts@1.1.0/dist/frappe-charts.min.iife.js"></script>
<!-- or -->
<script src="https://unpkg.com/frappe-charts@1.1.0/dist/frappe-charts.min.iife.js"></script>
```

#### Usage
```js
const data = {
labels: ["12am-3am", "3am-6pm", "6am-9am", "9am-12am",
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9am-12am"
],
datasets: [
{
name: "Some Data", type: "bar",
values: [25, 40, 30, 35, 8, 52, 17, -4]
},
{
name: "Another Set", type: "line",
values: [25, 50, -10, 15, 18, 32, 27, 14]
}
]
}

const chart = new frappe.Chart("#chart", { // or a DOM element,
// new Chart() in case of ES6 module with above usage
title: "My Awesome Chart",
data: data,
type: 'axis-mixed', // or 'bar', 'line', 'scatter', 'pie', 'percentage'
height: 250,
colors: ['#7cd6fd', '#743ee2']
})
```

If you want to contribute:

1. Clone this repo.
2. `cd` into project directory
3. `npm install`
4. `npm run dev`

#### Updates

##### v1.0.0
- Major rewrite out. Some new features include:
- Mixed type axis datasets
- Stacked bar charts
- Value over data points
- Y Markers and regions
- Dot size, Bar space size, and other options
- Legend for axis charts
- We would be looking to incorporate existing PRs and issues in the meantime.

##### Please read [#93](https://github.com/frappe/charts/issues/93) for v0.1.0 updates on rework and development.

##### v0.0.7
- [Custom color values](https://github.com/frappe/charts/pull/71) for charts as hex codes. The API now takes an array of colors for all charts instead of a color for each dataset.
- [@iamkdev's](https://github.com/iamkdev) blog on [usage with Angular](https://medium.com/@iamkdev/frappé-charts-with-angular-c9c5dd075d9f).

##### v0.0.5
- More [flexible Y values](https://github.com/frappe/charts/commit/3de049c451194dcd8e61ff91ceeb998ce131c709): independent from exponent, minimum Y axis point for line graphs.
- Customisable [Heatmap colors](https://github.com/frappe/charts/pull/53); check out the Halloween demo on the [website](https://frappe.github.io/charts) :D
- Tooltip values can be [formatted](https://github.com/frappe/charts/commit/e3d9ed0eae14b65044dca0542cdd4d12af3f2b44).

##### v0.0.4
- Build update: [Shipped](https://github.com/frappe/charts/pull/35) an ES6 module, along with the browser friendly IIFE.

##### v0.0.2
- We have an animated [Pie Chart](https://github.com/frappe/charts/issues/29)! Thanks [@sheweichun](https://github.com/sheweichun).
- [@tobiaslins](https://github.com/tobiaslins) contributed tweaks for his quest to make these easy to use with React. Check out his [repo](https://github.com/tobiaslins/frappe-charts-react-example) and updates at [#24](https://github.com/frappe/charts/issues/24) to learn more :)
- A new logo.

##### v0.0.1
- The very first version out, with animatable bars and lines, a percentage chart and a heatmap. GitHub-style.

#### License
This repository has been released under the [MIT License](LICENSE)

------------------
Project maintained by [Frappe](https://frappe.io).
Used in [ERPNext](https://erpnext.com). Read the [blog post](https://medium.com/@pratu16x7/so-we-decided-to-create-our-own-charts-a95cb5032c97).


+ 28
- 0
docs/_sidebar.md Zobrazit soubor

@@ -0,0 +1,28 @@
* Getting started
* [Quick start](getting_started/quick_start.md)

* Axis charts
* [A basic chart](basic/basic_chart.md)
* [Area and Trends Charts](basic/trends_regions.md)
* [Tooltips and Annotations](basic/annotations.md)
* [Stacked and Mixed Charts](basic/stacked_and_mixed.md)

* Pies and Percentages
* [Aggregation Charts](basic/aggr_sliced_diags.md)

* Update state
* [Modify data](update_state/modify_data.md)
* [Navigation](update_state/navigation.md)

* Heatmap
* [Day-based Month-wise data](basic/heatmap.md)

* Exporting
* [Image Files](exporting/images.md)

* Reference
* [Configuration](reference/configuration.md)
* [API](reference/api.md)

* [Wrappers](wrappers.md)
* [Contributing](contributing.md)

+ 27
- 10
docs/assets/css/index.css Zobrazit soubor

@@ -1,9 +1,8 @@
body {
/* container styles */
max-width: 720px;
margin: auto;
/* max-width: 720px;
margin: auto; */

font-family: "proxima-nova", sans-serif;
font-size: 15px;
color: #6c7680;
text-rendering: optimizeLegibility !important;
@@ -12,6 +11,10 @@ body {
-webkit-font-smoothing: antialiased;
}

#home-page {
font-family: "proxima-nova", sans-serif;
}

h1,
h2,
h3,
@@ -46,6 +49,16 @@ header .lead-text {
section {
margin: 4em 0; /* SAME 1 */
}
section figure {
border: 1px solid #ddd; /* SAME 3 */
border-radius: 3px;
}
.btn, .btn-group {
margin-bottom: 1rem;
}
.btn-group, .btn-action {
margin-right: 0.5rem;
}
h1 {
font-size: 3.5rem;
margin-bottom: 1.5rem;
@@ -53,6 +66,9 @@ h1 {
h1, h6 {
font-weight: 700;
}
p.new-context {
margin-top: 2rem;
}
.btn {
outline: none !important;
}
@@ -79,16 +95,22 @@ 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;
}
.hide {
display: none;
}


/* Moon images */
@@ -103,8 +125,3 @@ a, a:focus, a:hover {
margin-bottom: 5px;
font-size: 12px;
}


.text-center {
text-align: center;
}

+ 101
- 1
docs/assets/js/data.js Zobrazit soubor

@@ -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
// ================================================================================
@@ -128,6 +130,69 @@ export const typeData = {
]
};

let updateDataAllLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue",
"Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
"Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon"];

const baseLength = 10;
const fullLength = 30;

let getRandom = () => Math.floor(getRandomBias(-40, 60, 0.8, 1));
let updateDataAllValues = Array.from({length: fullLength}, getRandom);

// We're gonna be shuffling this
let updateDataAllIndices = updateDataAllLabels.map((d,i) => i);

let getUpdateArray = (sourceArray, length=10) => {
let indices = updateDataAllIndices.slice(0, length);
return indices.map((index) => sourceArray[index]);
};

let currentLastIndex = baseLength;

export function getUpdateData() {
shuffle(updateDataAllIndices);
let value = getRandom();
let start = getRandom();
let end = getRandom();
currentLastIndex = baseLength;

return {
labels: updateDataAllLabels.slice(0, baseLength),
datasets: [{
values: getUpdateArray(updateDataAllValues)
}],
yMarkers: [
{
label: "Altitude",
value: value,
type: 'dashed'
}
],
yRegions: [
{
label: "Range",
start: start,
end: end
},
],
};
}

export function getAddUpdateData() {
if(currentLastIndex >= fullLength) return;

// TODO: Fix update on removal
currentLastIndex++;
let c = currentLastIndex -1;

return [updateDataAllLabels[c], [updateDataAllValues[c]]];

// updateChart.addDataPoint(
// updateDataAllLabels[index], [updateDataAllValues[index]]
// );
}

export const trendsData = {
labels: [1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976,
1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986,
@@ -152,6 +217,16 @@ export const moonData = {
diameters: [5262.4, 4820.6, 3637.4, 3121.6],
};

export const eventsData = {
labels: ["Ganymede", "Callisto", "Io", "Europa"],
datasets: [
{
"values": moonData.distances,
"formatted": moonData.distances.map(d => d*1000 + " km")
}
]
};

// const jupiterMoons = {
// 'Ganymede': {
// mass: '14819000 x 10^16 kg',
@@ -177,3 +252,28 @@ 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
};

+ 436
- 54
docs/assets/js/demoConfig.js Zobrazit soubor

@@ -1,54 +1,436 @@
import { lineCompositeData, barCompositeData } from './data';

export default {
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
}
}
},

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
}
}
},

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',
}
}
}
}
import { lineCompositeData, barCompositeData, typeData, getUpdateData,
getAddUpdateData, trendsData, eventsData, moonData, heatmapData } from './data';

export const lineComposite = {
config: {
title: "Fireball/Bolide Events - Yearly (reported)",
data: lineCompositeData,
type: "line",
height: 190,
colors: ["green"],
isNavigable: 1,
valuesOverPoints: 1,

lineOptions: {
dotSize: 8
}
}
}

export const barComposite = {
config: {
data: barCompositeData,
type: "bar",
height: 210,
colors: ["violet", "light-blue", "#46a9f9"],
valuesOverPoints: 1,
axisOptions: {
xAxisMode: "tick"
},
barOptions: {
stacked: 1
}
}
}

export const demoSections = [
{
title: "Create a Chart",
name: "demo-main",
contentBlocks: [
{
type: "code",
lang: "html",
content: ` &lt!--HTML--&gt;
&lt;figure id="frost-chart"&gt;&lt;/figure&gt;`,
},
{
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',
}
},
options: [
{
name: "type",
path: ["type"],
type: "string",
states: {
"Mixed": 'axis-mixed',
"Line": 'line',
"Bar": 'bar',
"Pie Chart": 'pie',
"Percentage Chart": 'percentage',
},
activeState: "Mixed"
}
],
actions: [{ name: "Export ...", fn: "export", args: [] }],
}
]
},

{
title: "Update Values",
name: "updates-chart",
contentBlocks: [
{
type: "demo",
config: {
data: getUpdateData(),
type: 'line',
height: 300,
colors: ['#ff6c03'],
lineOptions: {
areaFill: 1
}
},
actions: [
{
name: "Random Data",
fn: "update",
args: [getUpdateData()]
},
{
name: "Add Value",
fn: "addDataPoint",
args: getAddUpdateData()
},
{
name: "Remove Value",
fn: "removeDataPoint",
args: []
},
{
name: "Export ...",
fn: "export",
args: []
}
]
}
]
},

{
title: "Plot Trends",
name: "trends-plot",
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', 'areaFill'],
states: {
"Line": [0, 1, 0, 0],
"Dots": [1, 0, 0, 0],
"HeatLine": [0, 1, 1, 0],
"Area": [0, 1, 0, 1]
},
activeState: "HeatLine"
}
],
actions: [{ name: "Export ...", fn: "export", args: [] }]
}
],
},

{
title: "Listen to state change",
name: "state-change",
contentBlocks: [
{
type: "demo",
config: {
title: "Jupiter's Moons: Semi-major Axis (1000 km)",
data: eventsData,
type: 'bar',
height: 330,
colors: ['grey'],
isNavigable: 1,
},
sideContent: `<div class="image-container border">
<img class="moon-image" src="./assets/img/europa.jpg">
</div>
<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>
<p>Diameter: <span class="diameter">3121.6</span> km</p>
</div>`,
postSetup: (chart, figure, row) => {
chart.parent.addEventListener('data-select', (e) => {
let i = e.index;
let name = moonData.names[i];
row.querySelector('.moon-name').innerHTML = name;
row.querySelector('.semi-major-axis').innerHTML = moonData.distances[i] * 1000;
row.querySelector('.mass').innerHTML = moonData.masses[i];
row.querySelector('.diameter').innerHTML = moonData.diameters[i];
row.querySelector('img').src = "./assets/img/" + name.toLowerCase() + ".jpg";
});
}
},
{
type: "code",
lang: "javascript",
content: ` ...
isNavigable: 1, // Navigate across data points; default 0
...

chart.parent.addEventListener('data-select', (e) => {
update_moon_data(e.index); // e contains index and value of current datapoint
});`,
}
]
},

{
title: "And a Month-wise Heatmap",
name: "heatmap",
contentBlocks: [
{
type: "demo",
config: {
title: "Monthly Distribution",
data: heatmapData,
type: 'heatmap',
discreteDomains: 1,
countLabel: 'Level',
colors: ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'],
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": ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'],
"GitHub's Halloween": ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c']
}
}
],
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']
});`,
}
],
},

{
title: "Demo",
name: "codepen",
contentBlocks: [
{
type: "custom",
html: `<p data-height="299" data-theme-id="light" data-slug-hash="wjKBoq" data-default-tab="js,result"
data-user="pratu16x7" data-embed-version="2" data-pen-title="Frappe Charts Demo" class="codepen">
See the Pen <a href="https://codepen.io/pratu16x7/pen/wjKBoq/">Frappe Charts Demo</a>
by Prateeksha Singh (<a href="https://codepen.io/pratu16x7">@pratu16x7</a>) on
<a href="https://codepen.io">CodePen</a>.
</p>`
}
]
},
{
title: "Available Options",
name: "options",
contentBlocks: [
{
type: "code",
lang: "javascript",
content: `
...
{
data: {
labels: [],
datasets: [],
yRegions: [],
yMarkers: []
}
title: '',
colors: [],
height: 200,

tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' pts',
}

// Axis charts
isNavigable: 1, // default: 0
valuesOverPoints: 1, // default: 0
barOptions: {
spaceRatio: 1 // default: 0.5
stacked: 1 // default: 0
}

lineOptions: {
dotSize: 6, // default: 4
hideLine: 0, // default: 0
hideDots: 1, // default: 0
heatline: 1, // default: 0
areaFill: 1 // default: 0
}

axisOptions: {
yAxisMode: 'span', // Axis lines, default
xAxisMode: 'tick', // No axis lines, only short ticks
xIsSeries: 1 // Allow skipping x values for space
// default: 0
},

// Pie/Percentage charts
maxLegendPoints: 6, // default: 20
maxSlices: 10, // default: 20

// Percentage chart
barOptions: {
height: 15 // default: 20
depth: 5 // default: 2
}

// Heatmap
discreteDomains: 1, // default: 1
}
...

// Updating values
chart.update(data);

// Axis charts:
chart.addDataPoint(label, valueFromEachDataset, index)
chart.removeDataPoint(index)
chart.updateDataset(datasetValues, index)

// Exporting
chart.export();

// Unbind window-resize events
chart.unbindWindowEvents();

`
}
]
},

{
title: "Install",
name: "installation",
contentBlocks: [
{ type: "text", content: 'Install via npm' },
{ type: "code", lang: "console", content: ` npm install frappe-charts` },

{ type: "text", content: 'And include it in your project' },
{ type: "code", lang: "javascript", content: ` import { Chart } from "frappe-charts` },

{ type: "text", content: 'Use as:' },
{
type: "code",
lang: "javascript",
content: ` new Chart(); // ES6 module
// or
new frappe.Chart(); // Browser`,
},

{ type: "text", content: '... or include it directly in your HTML' },
{
type: "code",
lang: "html",
content: ` &lt;script src="https://unpkg.com/frappe-charts@1.1.0"&gt;&lt;/script&gt;`,
},
]
}
]

+ 172
- 0
docs/assets/js/docsBuilder.js Zobrazit soubor

@@ -0,0 +1,172 @@
import { $ } from '../../../src/js/utils/dom';
import { toTitleCase } from '../../../src/js/utils/helpers';

export class docsBuilder {
constructor(LIB_OBJ) {
this.LIB_OBJ = LIB_OBJ;
}

makeSection(parent, sys) {
return new docSection(this.LIB_OBJ, parent, sys);
}
}

class docSection {
constructor(LIB_OBJ, parent, sys) {
this.LIB_OBJ = LIB_OBJ;
this.parent = parent; // should be preferably a section
this.sys = sys;
this.blockMap = {};
this.demos = [];

this.make();
}

make() {
// const section = document.querySelector(this.parent);
let s = this.sys;
if(s.title) {
$.create('h6', { inside: this.parent, innerHTML: s.title });
}

if(s.contentBlocks) {
s.contentBlocks.forEach((blockConf, index) => {
this.blockMap[index] = this.getBlock(blockConf);
});
} else {
// TODO:
this.blockMap['test'] = this.getDemo(s);
}
}

getBlock(blockConf) {
let fnName = 'get' + toTitleCase(blockConf.type);
if(this[fnName]) {
return this[fnName](blockConf);
} else {
throw new Error(`Unknown section block type '${blockConf.type}'.`);
}
}

getText(blockConf) {
return $.create('p', {
inside: this.parent,
className: 'new-context',
innerHTML: blockConf.content
});
}

getCode(blockConf) {
let pre = $.create('pre', { inside: this.parent });
let lang = blockConf.lang || 'javascript';
let code = $.create('code', {
inside: pre,
className: `hljs ${lang}`,
innerHTML: blockConf.content
});
}

getCustom(blockConf) {
this.parent.innerHTML += blockConf.html;
}

getDemo(blockConf) {
let bc = blockConf;
let args = bc.config;
let figure, row;
if(!bc.sideContent) {
figure = $.create('figure', { inside: this.parent });
} else {
row = $.create('div', {
inside: this.parent,
className: "row",
innerHTML: `<div class="col-sm-8"></div>
<div class="col-sm-4"></div>`,
});
figure = $.create('figure', { inside: row.querySelector('.col-sm-8') });
row.querySelector('.col-sm-4').innerHTML += bc.sideContent;
}

let libObj = new this.LIB_OBJ(figure, args);
let demoIndex = this.demos.length;
this.demos.push(libObj);

if(bc.postSetup) {
bc.postSetup(this.demos[demoIndex], figure, row);
}

this.getDemoOptions(demoIndex, bc.options, args, figure);
this.getDemoActions(demoIndex, bc.actions, args);
}

getDemoOptions(demoIndex, options=[], args={}, figure) {
options.forEach(o => {
const btnGroup = $.create('div', {
inside: this.parent,
className: `btn-group ${o.name}`
});
const mapKeys = o.mapKeys;

if(o.type === "number") {
let numOpts = o.numberOptions;

const inputGroup = $.create('input', {
inside: btnGroup,
className: `form-control`,
type: "range",
min: numOpts.min,
max: numOpts.max,
step: numOpts.step,
value: o.activeState ? o.activeState : 0,
// (max - min)/2
onInput: (value) => {
args[o.path[0]][o.path[1]] = value;

this.demos[demoIndex] = new this.LIB_OBJ(figure, args);
}
});

} else if(["map", "string"].includes(o.type)) {
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, string, number, object
args[o.path[0]] = state;
}
this.demos[demoIndex] = new this.LIB_OBJ(figure, args);
}
});

if(activeClass) { button.click(); }
});
}
});
}

getDemoActions(demoIndex, actions=[], args={}) {
actions.forEach(o => {
let args = o.args || [];
$.create('button', {
inside: this.parent,
className: `btn btn-action btn-sm btn-secondary`,
innerHTML: o.name,
onClick: () => {this.demos[demoIndex][o.fn](...args);}
});
});
}
}


+ 0
- 2
docs/assets/js/frappe-charts.min.js
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 0
- 1
docs/assets/js/frappe-charts.min.js.map
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 0
- 373
docs/assets/js/index.js Zobrazit soubor

@@ -1,373 +0,0 @@
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';
// ================================================================================

let Chart = frappe.Chart; // eslint-disable-line no-undef

let lc = demoConfig.lineComposite;
let lineCompositeChart = new Chart (lc.elementID, lc.options);

let bc = demoConfig.barComposite;
let barCompositeChart = new Chart (bc.elementID, bc.options);

lineCompositeChart.parent.addEventListener('data-select', (e) => {
let i = e.index;
barCompositeChart.updateDatasets([
fireballOver25[i], fireball_5_25[i], fireball_2_5[i]
]);
});

// ================================================================================

let customColors = ['purple', 'magenta', 'light-blue'];
let typeChartArgs = {
title: "My Awesome Chart",
data: typeData,
type: 'axis-mixed',
height: 300,
colors: customColors,

// maxLegendPoints: 6,
maxSlices: 10,

tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' pts',
}
};

let aggrChart = new Chart("#chart-aggr", typeChartArgs);

Array.prototype.slice.call(
document.querySelectorAll('.aggr-type-buttons button')
).map(el => {
el.addEventListener('click', (e) => {
let btn = e.target;
let type = btn.getAttribute('data-type');
typeChartArgs.type = type;
if(type !== 'axis-mixed') {
typeChartArgs.colors = undefined;
} else {
typeChartArgs.colors = customColors;
}

if(type !== 'percentage') {
typeChartArgs.height = 300;
} else {
typeChartArgs.height = undefined;
}

let newChart = new Chart("#chart-aggr", typeChartArgs);
if(newChart){
aggrChart = newChart;
}
Array.prototype.slice.call(
btn.parentNode.querySelectorAll('button')).map(el => {
el.classList.remove('active');
});
btn.classList.add('active');
});
});

document.querySelector('.export-aggr').addEventListener('click', () => {
aggrChart.export();
});

// Update values chart
// ================================================================================
let updateDataAllLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue",
"Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
"Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon"];

let getRandom = () => Math.floor(getRandomBias(-40, 60, 0.8, 1));
let updateDataAllValues = Array.from({length: 30}, getRandom);

// We're gonna be shuffling this
let updateDataAllIndices = updateDataAllLabels.map((d,i) => i);

let getUpdateData = (source_array, length=10) => {
let indices = updateDataAllIndices.slice(0, length);
return indices.map((index) => source_array[index]);
};

let updateData = {
labels: getUpdateData(updateDataAllLabels),
datasets: [{
"values": getUpdateData(updateDataAllValues)
}],
yMarkers: [
{
label: "Altitude",
value: 25,
type: 'dashed'
}
],
yRegions: [
{
label: "Range",
start: 10,
end: 45
},
],
};

let updateChart = new Chart("#chart-update", {
data: updateData,
type: 'line',
height: 300,
colors: ['#ff6c03'],
lineOptions: {
// hideLine: 1,
regionFill: 1
},
});

let chartUpdateButtons = document.querySelector('.chart-update-buttons');

chartUpdateButtons.querySelector('[data-update="random"]').addEventListener("click", () => {
shuffle(updateDataAllIndices);
let value = getRandom();
let start = getRandom();
let end = getRandom();
let data = {
labels: updateDataAllLabels.slice(0, 10),
datasets: [{values: getUpdateData(updateDataAllValues)}],
yMarkers: [
{
label: "Altitude",
value: value,
type: 'dashed'
}
],
yRegions: [
{
label: "Range",
start: start,
end: end
},
],
};
updateChart.update(data);
});

chartUpdateButtons.querySelector('[data-update="add"]').addEventListener("click", () => {
let index = updateChart.state.datasetLength; // last index to add
if(index >= updateDataAllIndices.length) return;
updateChart.addDataPoint(
updateDataAllLabels[index], [updateDataAllValues[index]]
);
});

chartUpdateButtons.querySelector('[data-update="remove"]').addEventListener("click", () => {
updateChart.removeDataPoint();
});

document.querySelector('.export-update').addEventListener('click', () => {
updateChart.export();
});

// 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 eventsData = {
labels: ["Ganymede", "Callisto", "Io", "Europa"],
datasets: [
{
"values": moonData.distances,
"formatted": moonData.distances.map(d => d*1000 + " km")
}
]
};

let eventsChart = new Chart("#chart-events", {
title: "Jupiter's Moons: Semi-major Axis (1000 km)",
data: eventsData,
type: 'bar',
height: 330,
colors: ['grey'],
isNavigable: 1,
});

let dataDiv = document.querySelector('.chart-events-data');

eventsChart.parent.addEventListener('data-select', (e) => {
let name = moonData.names[e.index];
dataDiv.querySelector('.moon-name').innerHTML = name;
dataDiv.querySelector('.semi-major-axis').innerHTML = moonData.distances[e.index] * 1000;
dataDiv.querySelector('.mass').innerHTML = moonData.masses[e.index];
dataDiv.querySelector('.diameter').innerHTML = moonData.diameters[e.index];
dataDiv.querySelector('img').src = "./assets/img/" + name.toLowerCase() + ".jpg";
});

// 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();
});

+ 0
- 672
docs/assets/js/index.min.js Zobrazit soubor

@@ -1,672 +0,0 @@
(function () {
'use strict';

function __$styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
var insertAt = ref.insertAt;

if (!css || typeof document === 'undefined') { return; }

var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';

if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}

if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}

// Fixed 5-color theme,
// More colors are difficult to parse visually









var HEATMAP_COLORS_BLUE = ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'];
var HEATMAP_COLORS_YELLOW = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'];



// Universal constants

/**
* Returns whether or not two given arrays are equal.
* @param {Array} arr1 First array
* @param {Array} arr2 Second array
*/


/**
* Shuffles array in place. ES6 version
* @param {Array} array An array containing the items.
*/
function shuffle(array) {
// Awesomeness: https://bost.ocks.org/mike/shuffle/
// https://stackoverflow.com/a/2450976/6495043
// https://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array?noredirect=1&lq=1

for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var _ref = [array[j], array[i]];
array[i] = _ref[0];
array[j] = _ref[1];
}

return array;
}

/**
* Fill an array with extra points
* @param {Array} array Array
* @param {Number} count number of filler elements
* @param {Object} element element to fill with
* @param {Boolean} start fill at start?
*/


/**
* Returns pixel width of string.
* @param {String} string
* @param {Number} charWidth Width of single char in pixels
*/




// https://stackoverflow.com/a/29325222
function getRandomBias(min, max, bias, influence) {
var range = max - min;
var biasValue = range * bias + min;
var rnd = Math.random() * range + min,
// random in range
mix = Math.random() * influence; // random mixer
return rnd * (1 - mix) + biasValue * mix; // mix full range and bias
}

// Playing around with dates




var NO_OF_MILLIS = 1000;
var SEC_IN_DAY = 86400;


var MONTH_NAMES_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];




// https://stackoverflow.com/a/11252167/6495043


function clone(date) {
return new Date(date.getTime());
}

function timestampSec(date) {
return date.getTime() / NO_OF_MILLIS;
}

function timestampToMidnight(timestamp) {
var roundAhead = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

var midnightTs = Math.floor(timestamp - timestamp % SEC_IN_DAY);
if (roundAhead) {
return midnightTs + SEC_IN_DAY;
}
return midnightTs;
}

// export function getMonthsBetween(startDate, endDate) {}











// mutates


// mutates
function addDays(date, numberOfDays) {
date.setDate(date.getDate() + numberOfDays);
}

var reportCountList = [152, 222, 199, 287, 534, 709, 1179, 1256, 1632, 1856, 1850];

var lineCompositeData = {
labels: ["2007", "2008", "2009", "2010", "2011", "2012", "2013", "2014", "2015", "2016", "2017"],

yMarkers: [{
label: "Average 100 reports/month",
value: 1200,
options: { labelPos: 'left' }
}],

datasets: [{
"name": "Events",
"values": reportCountList
}]
};

var fireball_5_25 = [[4, 0, 3, 1, 1, 2, 1, 1, 1, 0, 1, 1], [2, 3, 3, 2, 1, 3, 0, 1, 2, 7, 10, 4], [5, 6, 2, 4, 0, 1, 4, 3, 0, 2, 0, 1], [0, 2, 6, 2, 1, 1, 2, 3, 6, 3, 7, 8], [6, 8, 7, 7, 4, 5, 6, 5, 22, 12, 10, 11], [7, 10, 11, 7, 3, 2, 7, 7, 11, 15, 22, 20], [13, 16, 21, 18, 19, 17, 12, 17, 31, 28, 25, 29], [24, 14, 21, 14, 11, 15, 19, 21, 41, 22, 32, 18], [31, 20, 30, 22, 14, 17, 21, 35, 27, 50, 117, 24], [32, 24, 21, 27, 11, 27, 43, 37, 44, 40, 48, 32], [31, 38, 36, 26, 23, 23, 25, 29, 26, 47, 61, 50]];
var fireball_2_5 = [[22, 6, 6, 9, 7, 8, 6, 14, 19, 10, 8, 20], [11, 13, 12, 8, 9, 11, 9, 13, 10, 22, 40, 24], [20, 13, 13, 19, 13, 10, 14, 13, 20, 18, 5, 9], [7, 13, 16, 19, 12, 11, 21, 27, 27, 24, 33, 33], [38, 25, 28, 22, 31, 21, 35, 42, 37, 32, 46, 53], [50, 33, 36, 34, 35, 28, 27, 52, 58, 59, 75, 69], [54, 67, 67, 45, 66, 51, 38, 64, 90, 113, 116, 87], [84, 52, 56, 51, 55, 46, 50, 87, 114, 83, 152, 93], [73, 58, 59, 63, 56, 51, 83, 140, 103, 115, 265, 89], [106, 95, 94, 71, 77, 75, 99, 136, 129, 154, 168, 156], [81, 102, 95, 72, 58, 91, 89, 122, 124, 135, 183, 171]];
var fireballOver25 = [
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], [1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2], [3, 2, 1, 3, 2, 0, 2, 2, 2, 3, 0, 1], [2, 3, 5, 2, 1, 3, 0, 2, 3, 5, 1, 4], [7, 4, 6, 1, 9, 2, 2, 2, 20, 9, 4, 9], [5, 6, 1, 2, 5, 4, 5, 5, 16, 9, 14, 9], [5, 4, 7, 5, 1, 5, 3, 3, 5, 7, 22, 2], [5, 13, 11, 6, 1, 7, 9, 8, 14, 17, 16, 3], [8, 9, 8, 6, 4, 8, 5, 6, 14, 11, 21, 12]];

var barCompositeData = {
labels: MONTH_NAMES_SHORT,
datasets: [{
name: "Over 25 reports",
values: fireballOver25[9]
}, {
name: "5 to 25 reports",
values: fireball_5_25[9]
}, {
name: "2 to 5 reports",
values: fireball_2_5[9]
}]
};

// Demo Chart multitype Chart
// ================================================================================
var typeData = {
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm", "12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"],

yMarkers: [{
label: "Marker",
value: 43,
options: { labelPos: 'left'
// type: 'dashed'
} }],

yRegions: [{
label: "Region",
start: -10,
end: 50,
options: { labelPos: 'right' }
}],

datasets: [{
name: "Some Data",
values: [18, 40, 30, 35, 8, 52, 17, -4],
axisPosition: 'right',
chartType: 'bar'
}, {
name: "Another Set",
values: [30, 50, -10, 15, 18, 32, 27, 14],
axisPosition: 'right',
chartType: 'bar'
}, {
name: "Yet Another",
values: [15, 20, -3, -15, 58, 12, -17, 37],
chartType: 'line'
}]
};

var trendsData = {
labels: [1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016],
datasets: [{
values: [132.9, 150.0, 149.4, 148.0, 94.4, 97.6, 54.1, 49.2, 22.5, 18.4, 39.3, 131.0, 220.1, 218.9, 198.9, 162.4, 91.0, 60.5, 20.6, 14.8, 33.9, 123.0, 211.1, 191.8, 203.3, 133.0, 76.1, 44.9, 25.1, 11.6, 28.9, 88.3, 136.3, 173.9, 170.4, 163.6, 99.3, 65.3, 45.8, 24.7, 12.6, 4.2, 4.8, 24.9, 80.8, 84.5, 94.0, 113.3, 69.8, 39.8]
}]
};

var moonData = {
names: ["Ganymede", "Callisto", "Io", "Europa"],
masses: [14819000, 10759000, 8931900, 4800000],
distances: [1070.412, 1882.709, 421.700, 671.034],
diameters: [5262.4, 4820.6, 3637.4, 3121.6]
};

// const jupiterMoons = {
// 'Ganymede': {
// mass: '14819000 x 10^16 kg',
// 'semi-major-axis': '1070412 km',
// 'diameter': '5262.4 km'
// },
// 'Callisto': {
// mass: '10759000 x 10^16 kg',
// 'semi-major-axis': '1882709 km',
// 'diameter': '4820.6 km'
// },
// 'Io': {
// mass: '8931900 x 10^16 kg',
// 'semi-major-axis': '421700 km',
// 'diameter': '3637.4 km'
// },
// 'Europa': {
// mass: '4800000 x 10^16 kg',
// 'semi-major-axis': '671034 km',
// 'diameter': '3121.6 km'
// },
// };

// ================================================================================

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
}
}
},

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
}
}
},

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';
}
}
}
}
};

var Chart = frappe.Chart; // eslint-disable-line no-undef

var lc = demoConfig.lineComposite;
var lineCompositeChart = new Chart(lc.elementID, lc.options);

var bc = demoConfig.barComposite;
var barCompositeChart = new Chart(bc.elementID, bc.options);

lineCompositeChart.parent.addEventListener('data-select', function (e) {
var i = e.index;
barCompositeChart.updateDatasets([fireballOver25[i], fireball_5_25[i], fireball_2_5[i]]);
});

// ================================================================================

var customColors = ['purple', 'magenta', 'light-blue'];
var typeChartArgs = {
title: "My Awesome Chart",
data: typeData,
type: 'axis-mixed',
height: 300,
colors: customColors,

// maxLegendPoints: 6,
maxSlices: 10,

tooltipOptions: {
formatTooltipX: function formatTooltipX(d) {
return (d + '').toUpperCase();
},
formatTooltipY: function formatTooltipY(d) {
return d + ' pts';
}
}
};

var aggrChart = new Chart("#chart-aggr", typeChartArgs);

Array.prototype.slice.call(document.querySelectorAll('.aggr-type-buttons button')).map(function (el) {
el.addEventListener('click', function (e) {
var btn = e.target;
var type = btn.getAttribute('data-type');
typeChartArgs.type = type;
if (type !== 'axis-mixed') {
typeChartArgs.colors = undefined;
} else {
typeChartArgs.colors = customColors;
}

if (type !== 'percentage') {
typeChartArgs.height = 300;
} else {
typeChartArgs.height = undefined;
}

var newChart = new Chart("#chart-aggr", typeChartArgs);
if (newChart) {
aggrChart = newChart;
}
Array.prototype.slice.call(btn.parentNode.querySelectorAll('button')).map(function (el) {
el.classList.remove('active');
});
btn.classList.add('active');
});
});

document.querySelector('.export-aggr').addEventListener('click', function () {
aggrChart.export();
});

// Update values chart
// ================================================================================
var updateDataAllLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon"];

var getRandom = function getRandom() {
return Math.floor(getRandomBias(-40, 60, 0.8, 1));
};
var updateDataAllValues = Array.from({ length: 30 }, getRandom);

// We're gonna be shuffling this
var updateDataAllIndices = updateDataAllLabels.map(function (d, i) {
return i;
});

var getUpdateData = function getUpdateData(source_array) {
var length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10;

var indices = updateDataAllIndices.slice(0, length);
return indices.map(function (index) {
return source_array[index];
});
};

var updateData = {
labels: getUpdateData(updateDataAllLabels),
datasets: [{
"values": getUpdateData(updateDataAllValues)
}],
yMarkers: [{
label: "Altitude",
value: 25,
type: 'dashed'
}],
yRegions: [{
label: "Range",
start: 10,
end: 45
}]
};

var updateChart = new Chart("#chart-update", {
data: updateData,
type: 'line',
height: 300,
colors: ['#ff6c03'],
lineOptions: {
// hideLine: 1,
regionFill: 1
}
});

var chartUpdateButtons = document.querySelector('.chart-update-buttons');

chartUpdateButtons.querySelector('[data-update="random"]').addEventListener("click", function () {
shuffle(updateDataAllIndices);
var value = getRandom();
var start = getRandom();
var end = getRandom();
var data = {
labels: updateDataAllLabels.slice(0, 10),
datasets: [{ values: getUpdateData(updateDataAllValues) }],
yMarkers: [{
label: "Altitude",
value: value,
type: 'dashed'
}],
yRegions: [{
label: "Range",
start: start,
end: end
}]
};
updateChart.update(data);
});

chartUpdateButtons.querySelector('[data-update="add"]').addEventListener("click", function () {
var index = updateChart.state.datasetLength; // last index to add
if (index >= updateDataAllIndices.length) return;
updateChart.addDataPoint(updateDataAllLabels[index], [updateDataAllValues[index]]);
});

chartUpdateButtons.querySelector('[data-update="remove"]').addEventListener("click", function () {
updateChart.removeDataPoint();
});

document.querySelector('.export-update').addEventListener('click', function () {
updateChart.export();
});

// 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 eventsData = {
labels: ["Ganymede", "Callisto", "Io", "Europa"],
datasets: [{
"values": moonData.distances,
"formatted": moonData.distances.map(function (d) {
return d * 1000 + " km";
})
}]
};

var eventsChart = new Chart("#chart-events", {
title: "Jupiter's Moons: Semi-major Axis (1000 km)",
data: eventsData,
type: 'bar',
height: 330,
colors: ['grey'],
isNavigable: 1
});

var dataDiv = document.querySelector('.chart-events-data');

eventsChart.parent.addEventListener('data-select', function (e) {
var name = moonData.names[e.index];
dataDiv.querySelector('.moon-name').innerHTML = name;
dataDiv.querySelector('.semi-major-axis').innerHTML = moonData.distances[e.index] * 1000;
dataDiv.querySelector('.mass').innerHTML = moonData.masses[e.index];
dataDiv.querySelector('.diameter').innerHTML = moonData.diameters[e.index];
dataDiv.querySelector('img').src = "./assets/img/" + name.toLowerCase() + ".jpg";
});

// 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();
});

}());

+ 0
- 1
docs/assets/js/index.min.js.map
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 86
- 0
docs/basic/aggr_sliced_diags.md Zobrazit soubor

@@ -0,0 +1,86 @@
## Also called Sliced Diagrams
Another family of charts, the aggregation charts accumulate the value at a data point across the multiple datasets.

**The data format stays the same, with single or multi datasets.**

#### Pie chart
Perhaps the most well-known representation of data slices are Pie charts:

```js
type: 'pie'
```
<project-demo data="mixed-2" v-bind:config="{
type: 'pie',
height: 300
}">
</project-demo>

#### Percentage Charts FTW

Pies have received some [criticism]() for data perception; we are much better at parsing sizes in a single dimension rather than an area. That's why, the much leaner `percentage` chart can come in handy:

```js
type: 'percentage'
```
<project-demo data="mixed-2" v-bind:config="{
type: 'percentage',
height: 180,
}">
</project-demo>

#### Limiting the slices
When there are too many data values to show visually, it makes sense to bundle up the least of the values as a cumulated data point, rather than showing tiny slices. This can be done by defining the maximum number of slices to be shown.

```js
maxSlices: 7,
```
<project-demo data="mixed-2" v-bind:config="{
type: 'pie',
height: 300,
maxSlices: 7,
}"
v-bind:options="[
{
name: 'maxSlices',
path: ['maxSlices'],
type: 'number',
numberOptions: { min: 5, max: 8, step: 1 },
activeState: 7
}
]">
</project-demo>

#### Configuring percentage bars
Some attributes of a percentage bar can be redefined; like its height and the depth of it's shadow.

```js
barOptions: {
height: 15, // default: 20
depth: 5 // default: 2
}
```
<project-demo data="mixed-2" v-bind:config="{
type: 'percentage',
height: 200,
barOptions: {
height: 15,
depth: 5
}
}"
v-bind:options="[
{
name: 'barOptions',
path: ['barOptions', 'depth'],
type: 'number',
numberOptions: { min: 1, max: 10, step: 1 },
activeState: 5
},
{
name: 'barOptions',
path: ['barOptions', 'height'],
type: 'number',
numberOptions: { min: 11, max: 31, step: 2 },
activeState: 15
}
]">
</project-demo>

+ 108
- 0
docs/basic/annotations.md Zobrazit soubor

@@ -0,0 +1,108 @@
## Annotations
Special values (like range points) on a chart can be annotated for quick comparisions. As they are among the components of a graph that can be updated, they are defined within the `data` property itself. There are two kinds of annotations that can be used to mark the vertical axis values: **markers** and **regions**.

#### Markers

To highlight certain values on the Y axis, `yMarkers` can be set. They will shown as dashed lines on the graph.

```js
data = {
// labels: [],
// datasets: [],
yMarkers: [
{
label: "Threshold",
value: 650,
options: { labelPos: 'left' } // default: 'right'
}
]
}
```
<project-demo data="ymarkers"
v-bind:config="{
type: 'line',
height: 180,
colors: ['violet'],
axisOptions: {
yAxisMode: 'tick'
},
}">
</project-demo>

#### Regions

2D counterparts to markers, they have a `start` and `end` instead of value:

```js
yRegions: [
{
label: "Optimum Value",
start: 100,
end: 600,
options: { labelPos: 'right' }
}
],
```
Shown as a greyed-out area between the extremes.
<project-demo data="yregions"
v-bind:config="{
type: 'line',
height: 180,
colors: ['violet'],
axisOptions: {
yAxisMode: 'tick'
},
}">
</project-demo>

## Tooltips

Frappe Charts are known for their [awesome tooltips](https://twitter.com/Elijah_Meeks/status/934338534143488000). What's more, they are also customizable for the format of the label and value displayed on them.

```js
tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' pts',
}
```

<project-demo data="0"
v-bind:config="{
type: 'line',
height: 150,
colors: ['violet'],
axisOptions: {
yAxisMode: 'tick'
},
tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' pts',
}
}">
</project-demo>

For a non-web or static interface, where tooltips are absent, `valuesOverPoints` is a useful tweak to show value information at a glance.

```js
{
valuesOverPoints: 1 // default: 0
}
```
<project-demo data="1" v-bind:config="{
type: 'line',
height: 200,
colors:['violet', 'magenta'],
valuesOverPoints: 1
}"
v-bind:options="[
{
name: 'type',
path: ['type'],
type: 'String',
states: { 'Bar': 'bar', 'Line': 'line' },
activeState: 'Bar'
}
]">
</project-demo>

Next up we'll look at perhaps one the more exciting parts in axis charts: **Mixed Charts**.

+ 149
- 0
docs/basic/basic_chart.md Zobrazit soubor

@@ -0,0 +1,149 @@
## Axis chart: what is it

An axis chart is generally a 2D rendition of data, where a set of values corresponds to every point in a dataset. That's why, data is the most important component for a chart. For example, for some values across items, the data could look like:
```js
data = {
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
datasets: [
{ values: [18, 40, 30, 35, 8, 52, 17, -4] }
]
}
```

Rendering it doesn't require much more that that. Plug the data in with a [type]() `bar`, with an optional [color]() and [height]():

```js
new frappe.Chart( "#chart", {
data: data,
type: 'bar',
height: 140,
colors: ['red']
});
```
<project-demo
data="0"
v-bind:config="{ type: 'bar', height: 140, colors:['red'] }">
</project-demo>


And similarly, a `line` chart is data-wise homomorphic to a bar chart:

```js
type:'line'
```
<project-demo
data="0"
v-bind:config="{ type: 'line', height: 140, colors:['red'] }">
</project-demo>


## Adding more datasets

A chart can have multiple datasets. In an axis chart, every dataset is represented individually.

```js
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] }
]
}
```
Notice that this case demonstrates why the `colors` option is an array. We'll see more about it ahead.
<project-demo data="1" v-bind:config="{
type: 'line',
height: 200,
colors:['green', 'light-green']
}"
v-bind:options="[
{
name: 'type',
path: ['type'],
type: 'String',
states: { 'Line': 'line', 'Bar': 'bar' },
activeState: 'Mixed'
}
]">
</project-demo>


## Responsiveness

Frappe Charts are responsive, as they rerender all the data in the current available container width. To demonstrate, let's take the example of setting the [bar width]() for bar charts.

In order to set the bar width, instead of defining it and the space between the bars independently, we simply define the <b>ratio of the space</b> between bars to the bar width. The chart then adjusts the actual size proportional to the chart container.

```js
barOptions: {
spaceRatio: 0.2 // default: 1
},
```
Try resizing the window to see the effect, with different ratio values.

<project-demo data="2" v-bind:config="{
type: 'bar',
height: 140,
colors: ['orange'],
axisOptions: { xAxisMode: 'tick' },
barOptions: { spaceRatio: 0.2 },
}"
v-bind:options="[
{
name: 'spaceRatio',
path: ['barOptions', 'spaceRatio'],
type: 'number',
numberOptions: { min: 0.1, max: 1.9, step: 0.1 },
activeState: 0.2
}
]">
</project-demo>


## More Tweaks

Axis lines define a chart presentation. By default they are long `span`ning lines, but to give prominence to data points, X and/or Y axes can also be short `tick`s:

```js
axisOptions: {
xAxisMode: 'tick' // default: 'span'
},
```
<project-demo
data="2"
v-bind:config="{
type: 'bar',
height: 140,
colors:['blue'],
axisOptions: { xAxisMode: 'tick' }
}">
</project-demo>


Just like bar width, we can set the <b>dot size</b> on a line graph, with the [`dotSize`]() property in [`lineOptions`]().

```js
lineOptions: {
dotSize: 8 // default: 4
},
```
<project-demo data="2" v-bind:config="{
type: 'line',
height: 140,
colors:['orange'],
axisOptions: { xAxisMode: 'tick' },
lineOptions: { dotSize: 8 }
}"
v-bind:options="[
{
name: 'dotSize',
path: ['lineOptions', 'dotSize'],
type: 'number',
numberOptions: { min: 3, max: 10, step: 1 },
activeState: 8
}
]">
</project-demo>


These were some of the basic toggles to a chart; there are quite a few line options to go with, particularly to create [regions](). We'll look at those in next section.

+ 70
- 0
docs/basic/heatmap.md Zobrazit soubor

@@ -0,0 +1,70 @@
## Day-based Month-wise data

The heatmap is a representation of day-wise data (similar to [the GitHub Contribution Graph]()). It spaces out data values linearly, across 5 levels (zero data kept exclusive).

In this case, the data has three parts,

```js
let data = {
dataPoints: {
"1426744959": 20,
"1463673055": 113,
"1476892421": 57,
// ...
},
start: startDate, // a JS date object
end: endDate
}
```
(We are working on making the start date and end date implicit and optional).

The chart is rendered by the type `heatmap`:

```js
let chart = new Chart("#heatmap", {
type: 'heatmap',
data: data,
})
```
<project-demo data="heatmap-data" v-bind:config="{
title: 'Monthly Distribution',
type: 'heatmap',
}">
</project-demo>

Setting `discreteDomains` to `0` allows for a continous distribution of heat squares (as on GitHub), rather than showing the month-wise separation. A different set of colors can also be specified.

```js
discreteDomains: 0, // default 1
colors: ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'],
```

<project-demo data="heatmap-data" v-bind:config="{
title: 'Monthly Distribution',
type: 'heatmap',
height: 200,
discreteDomains: 1,
countLabel: 'Level',
colors: ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'],
}"
v-bind:options="[
{
name: 'Discrete domains',
path: ['discreteDomains'],
type: 'Boolean',
// boolNames: ['Continuous', 'Discrete'],
states: { 'Discrete': 1, 'Continuous': 0 }
},
{
name: 'Colors',
path: ['colors'],
type: 'Array',
states: {
'Green (Default)': [],
'Blue': ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'],
'Halloween': ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c']
}
}
]">
</project-demo>


+ 95
- 0
docs/basic/stacked_and_mixed.md Zobrazit soubor

@@ -0,0 +1,95 @@
#### Mixed Bar/Line Chart

As we have seen, chart can have [multiple datasets](/basic/basic_chart?id=adding-more-datasets). Each dataset can also have a different `chartType`, which if specified, should accompany the `type` property set to `axis-mixed`.

```js
data: {
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
datasets: [
{
name: "Dataset 1",
values: [18, 40, 30, 35, 8, 52, 17, -4],
chartType: 'bar'
},
{
name: "Dataset 2",
values: [30, 50, -10, 15, 18, 32, 27, 14],
chartType: 'line'
}
]
},

type: 'axis-mixed'
```
This allows for creation of mixed axis chart. It is recommended to list the bar datasets before the line ones to avoid overlapping.
<project-demo data="mixed-1" v-bind:config="{
type: 'axis-mixed',
height: 200,
colors:['light-green', 'green']
}">
</project-demo>

All the `lineOptions` and `barOptions` apply to mix and match datasets as well.

<project-demo data="mixed-2" v-bind:config="{
type: 'axis-mixed',
height: 240,
colors:['light-green', 'green', 'blue'],
lineOptions: {
dotSize: 4
},
barOptions: {
spaceRatio: 0.4
},
}"
v-bind:options="[
{
name: 'barOptions',
path: ['barOptions', 'spaceRatio'],
type: 'number',
numberOptions: { min: 0.1, max: 1.9, step: 0.1 },
activeState: 0.4
},
{
name: 'lineOptions',
path: ['lineOptions', 'dotSize'],
type: 'number',
numberOptions: { min: 3, max: 10, step: 1 },
activeState: 4
}
]">
</project-demo>

Infact, one of the bar options is actually dependent on multiple datasets.

#### Stacked Bar Chart

Unlike lines, bars have two ways to show multiple data point values: adjacent or stacked bars. Stacked bar charts are similar to area charts, being useful for comparisions of similar trends. The property [`stacked`]() in `barOptions` renders a stacked bar chart instead of the default adjacent bars:

```js
barOptions: {
stacked: 1 // default 0, i.e. adjacent
}
```
<project-demo data="bar-composite-data" v-bind:config="{
type: 'bar',
height: 240,
colors:['blue', 'green', 'light-green'],
barOptions: {
spaceRatio: 0.4,
stacked: 1
},
}"
v-bind:options="[
{
name: 'barOptions',
path: ['barOptions', 'stacked'],
type: 'Boolean',
states: { 'Stacked': 1, 'Adjacent': 0 },
activeState: 1
}
]">
</project-demo>


In [Aggregation Charts]() however, instead of being rendered individually, each data point in aggregated accross every dataset. We'll cover those next.

+ 179
- 0
docs/basic/trends_regions.md Zobrazit soubor

@@ -0,0 +1,179 @@
## Area Chart
An area chart is derived from a line chart, by marking the area between the X axis and the line plot. It is usually used to compare the areas under the curve for two or more different plots.

```js
lineOptions: {
areaFill: 1 // default: 0
},
```
<project-demo data="1"
v-bind:config="{
type: 'line',
height: 240,
colors: ['violet'],
lineOptions: {
areaFill: 1
},
}">
</project-demo>

## Plotting Trends
Line charts are great to show trends. One of the reasons they are interesting is because the data involved usually involves a large number of data points. For so many points, we'd really like to keep the plot as less detailed as we can, while also using the already present color to advantage. Let's see how we can change some properties of a default line chart can reduce clutter.

## Continuity
The X axis (often the time axis) is usually continuous. That means we can reduce the redundancy of rendering every X label by allowing for only a few periodic ones.


We can skip X labels by setting the `xIsSeries` property in `axisOptions` to `true`.



```js
axisOptions: {
xIsSeries: true // default: false
},
```
This results only some of the X ticks having a label.
<project-demo data="trends-data"
v-bind:config="{
type: 'line',
height: 180,
colors: ['violet'],
axisOptions: {
xAxisMode: 'tick',
xIsSeries: 1
}
}">
</project-demo>

The line plot in the above plot could still be simplified. For example, to maintain uniformity, we could opt out of showing the dots at all, with `hideDots`.
```js
lineOptions: {
hideDots: 1 // default: 0
},
```
<project-demo data="trends-data"
v-bind:config="{
type: 'line',
height: 180,
colors: ['violet'],
axisOptions: {
xAxisMode: 'tick',
xIsSeries: 1
},
lineOptions: {
hideDots: 1
},
}">
</project-demo>

Or you could just choose to show only the dots instead.
```js
lineOptions: {
hideLine: 1 // default: 0
},
```
<project-demo data="trends-data"
v-bind:config="{
type: 'line',
height: 180,
colors: ['violet'],
axisOptions: {
xAxisMode: 'tick',
xIsSeries: 1
},
lineOptions: {
hideLine: 1
},
}">
</project-demo>
Needless to say, turning both of them on would be too amusing to be of any use :)

A subtle way to show gradation of values is to render a change in color with the magnitude of the values. The property that does this is called `heatline`.
```js
lineOptions: {
heatline: 1 // default: 0
},
```
<project-demo data="trends-data"
v-bind:config="{
type: 'line',
height: 180,
colors: ['violet'],
axisOptions: {
xAxisMode: 'tick',
xIsSeries: 1
},
lineOptions: {
hideDots: 1,
heatline: 1
},
}">
</project-demo>

## Combinations
Here's a demo using different combinations of the line options.

<project-demo data="trends-data"
v-bind:config="{
type: 'line',
height: 200,
colors: ['violet'],
axisOptions: {
xAxisMode: 'tick',
xIsSeries: 1
}
}"x
v-bind:options="[
{
name: 'lineOptions',
path: ['lineOptions'],
type: 'Map',
mapKeys: ['hideLine', 'hideDots', 'heatline', 'areaFill'],
states: {
'Line': [0, 1, 0, 0],
'Dots': [1, 0, 0, 0],
'HeatLine': [0, 1, 1, 0],
'Area': [0, 1, 0, 1]
},
activeState: 'Area'
}
]">
</project-demo>

Next up, we'll start to annotate the data in charts.




































+ 15
- 0
docs/contributing.md Zobrazit soubor

@@ -0,0 +1,15 @@
# Contributing
If you wish to contribute to Frappe Charts:

1. Clone the git repo.
2. `cd` into project directory
3. `npm install`
4. `npm run dev`

All changes should be made in the code base contained in `src`.

To contribute to one of the chart types, there are individual js files specific to each chart type in `src/js/charts/`, with `BaseChart` being the root for any chart. All charts are broadly categorised as `AxisChart`, `AggregationCharts` (`PieChart` and `PercentageChart`) and `Heatmap`. Common behaviour to be in all children charts can be considered to be defined in the parent.

Most of the ground-level logic code is segregated into the utils modules `src/js/utils/`.

If you wish to use an arbitrary constant value for a specific measure, color, ratio etc., check `src/js/utils/constants.js` and register the value to be used.

+ 321
- 0
docs/data.js Zobrazit soubor

@@ -0,0 +1,321 @@
const fireball_5_25 = [
[4, 0, 3, 1, 1, 2, 1, 1, 1, 0, 1, 1],
[2, 3, 3, 2, 1, 3, 0, 1, 2, 7, 10, 4],
[5, 6, 2, 4, 0, 1, 4, 3, 0, 2, 0, 1],
[0, 2, 6, 2, 1, 1, 2, 3, 6, 3, 7, 8],
[6, 8, 7, 7, 4, 5, 6, 5, 22, 12, 10, 11],
[7, 10, 11, 7, 3, 2, 7, 7, 11, 15, 22, 20],
[13, 16, 21, 18, 19, 17, 12, 17, 31, 28, 25, 29],
[24, 14, 21, 14, 11, 15, 19, 21, 41, 22, 32, 18],
[31, 20, 30, 22, 14, 17, 21, 35, 27, 50, 117, 24],
[32, 24, 21, 27, 11, 27, 43, 37, 44, 40, 48, 32],
[31, 38, 36, 26, 23, 23, 25, 29, 26, 47, 61, 50],
];
const fireball_2_5 = [
[22, 6, 6, 9, 7, 8, 6, 14, 19, 10, 8, 20],
[11, 13, 12, 8, 9, 11, 9, 13, 10, 22, 40, 24],
[20, 13, 13, 19, 13, 10, 14, 13, 20, 18, 5, 9],
[7, 13, 16, 19, 12, 11, 21, 27, 27, 24, 33, 33],
[38, 25, 28, 22, 31, 21, 35, 42, 37, 32, 46, 53],
[50, 33, 36, 34, 35, 28, 27, 52, 58, 59, 75, 69],
[54, 67, 67, 45, 66, 51, 38, 64, 90, 113, 116, 87],
[84, 52, 56, 51, 55, 46, 50, 87, 114, 83, 152, 93],
[73, 58, 59, 63, 56, 51, 83, 140, 103, 115, 265, 89],
[106, 95, 94, 71, 77, 75, 99, 136, 129, 154, 168, 156],
[81, 102, 95, 72, 58, 91, 89, 122, 124, 135, 183, 171],
];
const fireballOver25 = [
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
[1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2],
[3, 2, 1, 3, 2, 0, 2, 2, 2, 3, 0, 1],
[2, 3, 5, 2, 1, 3, 0, 2, 3, 5, 1, 4],
[7, 4, 6, 1, 9, 2, 2, 2, 20, 9, 4, 9],
[5, 6, 1, 2, 5, 4, 5, 5, 16, 9, 14, 9],
[5, 4, 7, 5, 1, 5, 3, 3, 5, 7, 22, 2],
[5, 13, 11, 6, 1, 7, 9, 8, 14, 17, 16, 3],
[8, 9, 8, 6, 4, 8, 5, 6, 14, 11, 21, 12]
];

// https://stackoverflow.com/a/29325222
function getRandomBias(min, max, bias, influence) {
const range = max - min;
const biasValue = range * bias + min;
var rnd = Math.random() * range + min, // random in range
mix = Math.random() * influence; // random mixer
return rnd * (1 - mix) + biasValue * mix; // mix full range and bias
}

/**
* Shuffles array in place. ES6 version
* @param {Array} array An array containing the items.
*/
function shuffle(array) {
// Awesomeness: https://bost.ocks.org/mike/shuffle/
// https://stackoverflow.com/a/2450976/6495043
// https://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array?noredirect=1&lq=1

for (let i = array.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}

return array;
}

let updateDataAllLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue",
"Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
"Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon"];

const baseLength = 10;
const fullLength = 30;

let getRandom = () => Math.floor(getRandomBias(-40, 60, 0.8, 1));
let updateDataAllValues = Array.from({length: fullLength}, getRandom);

// We're gonna be shuffling this
let updateDataAllIndices = updateDataAllLabels.map((d,i) => i);

let getUpdateArray = (sourceArray, length=10) => {
let indices = updateDataAllIndices.slice(0, length);
return indices.map((index) => sourceArray[index]);
};

let currentLastIndex = baseLength;

function getUpdateData() {
shuffle(updateDataAllIndices);
let value = getRandom();
let start = getRandom();
let end = getRandom();
currentLastIndex = baseLength;

return {
labels: updateDataAllLabels.slice(0, baseLength),
datasets: [{
values: getUpdateArray(updateDataAllValues)
}],
yMarkers: [
{
label: "Altitude",
value: value,
type: 'dashed'
}
],
yRegions: [
{
label: "Range",
start: start,
end: end
},
],
};
}

function getAddUpdateData() {
if(currentLastIndex >= fullLength) return;

// TODO: Fix update on removal
currentLastIndex++;
let c = currentLastIndex -1;

return [updateDataAllLabels[c], [updateDataAllValues[c]]];

// updateChart.addDataPoint(
// updateDataAllLabels[index], [updateDataAllValues[index]]
// );
}

const NO_OF_MILLIS = 1000;
const SEC_IN_DAY = 86400;

function clone(date) {
return new Date(date.getTime());
}

function timestampToMidnight(timestamp, roundAhead = false) {
let midnightTs = Math.floor(timestamp - (timestamp % SEC_IN_DAY));
if(roundAhead) {
return midnightTs + SEC_IN_DAY;
}
return midnightTs;
}

function timestampSec(date) {
return date.getTime()/NO_OF_MILLIS;
}

function addDays(date, numberOfDays) {
let newDate = clone(date);
newDate.setDate(newDate.getDate() + numberOfDays);
return newDate;
}

function getHeatmapData() {
let today = new Date();
let start = clone(today);
start = 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;
}

return {
dataPoints: dataPoints,
start: start,
end: end
};
}


const sampleData = {
"0": {
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
datasets: [
{ values: [18, 40, 30, 35, 8, 52, 17, -4] }
]
},
"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] }
]
},
"trends-data": {
labels: [1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976,
1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986,
1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016] ,
datasets: [
{
values: [132.9, 150.0, 149.4, 148.0, 94.4, 97.6, 54.1, 49.2, 22.5, 18.4,
39.3, 131.0, 220.1, 218.9, 198.9, 162.4, 91.0, 60.5, 20.6, 14.8,
33.9, 123.0, 211.1, 191.8, 203.3, 133.0, 76.1, 44.9, 25.1, 11.6,
28.9, 88.3, 136.3, 173.9, 170.4, 163.6, 99.3, 65.3, 45.8, 24.7,
12.6, 4.2, 4.8, 24.9, 80.8, 84.5, 94.0, 113.3, 69.8, 39.8]
}
]
},
"ymarkers": {
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] }
],
yMarkers: [
{
label: "Threshold",
value: 650,
options: { labelPos: 'left' }
}
]
},

"yregions": {
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, 430, 630, 210] }
],
yRegions: [
{
label: "Optimum Value",
start: 100,
end: 600,
options: { labelPos: 'right' }
}
]
},

"mixed-1": {
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
datasets: [
{
name: "Dataset 1",
values: [18, 40, 30, 35, 8, 52, 17, -4],
chartType: 'bar'
},
{
name: "Dataset 2",
values: [30, 50, -10, 15, 18, 32, 27, 14],
chartType: 'line'
}
]
},

"mixed-2": {
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm",
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"],

datasets: [
{
name: "Some Data",
values: [18, 40, 30, 35, 8, 52, 17, -4],
chartType: 'bar'
},
{
name: "Another Set",
values: [30, 50, -10, 15, 18, 32, 27, 14],
chartType: 'bar'
},
{
name: "Yet Another",
values: [15, 20, -3, -15, 58, 12, -17, 37],
chartType: 'line'
}
]
},

"bar-composite-data": {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
datasets: [
{
name: "Over 25 reports",
values: fireballOver25[9],
},
{
name: "5 to 25 reports",
values: fireball_5_25[9],
},
{
name: "2 to 5 reports",
values: fireball_2_5[9]
}
]
},

"get-update-data": getUpdateData,

"heatmap-data": getHeatmapData
}

+ 250
- 0
docs/demoBuilder.js Zobrazit soubor

@@ -0,0 +1,250 @@
function $$(expr, con) {
return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
}

$$.create = (tag, o) => {
var element = document.createElement(tag);
let container = null;

if (o.withLabel) {
container = document.createElement('div');
container.classList.add('input-wrapper');
element.label = document.createElement('label');
element.label.innerHTML = o.withLabel;
container.appendChild(element.label);
container.appendChild(element);
}

for (var i in o) {
var val = o[i];

if(i === "inside") {
let child = container ? container : element;

$$(val).appendChild(child);

} 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 === "onInput" ) {
element.addEventListener('input', function(e) {
val(element.value);
});

} else if (i === "onChange" ) {
element.addEventListener('change', function(e) {
val(element.value);
});

} else if (i === "styles") {
if(typeof val === "object") {
Object.keys(val).map(prop => {
element.style[prop] = val[prop];
});
}
} else if (i in element ) {
element[i] = val;
}
else {
element.setAttribute(i, val);
}
}

return container ? container : element;
};

function toTitleCase(str) {
return str.replace(/\w*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
}

function scrub(text) {
return text.replace(/ /g, "_").toLowerCase();
};

// export class demoBuilder {
class demoBuilder {
constructor(LIB_OBJ) {
this.LIB_OBJ = LIB_OBJ;
}

makeSection(parent, sys) {
return new docSection(this.LIB_OBJ, parent, sys);
}
}

class docSection {
constructor(LIB_OBJ, parent, sys) {
this.LIB_OBJ = LIB_OBJ;
this.parent = parent;
this.sys = sys;
this.blockMap = {};
this.demos = [];

this.make();
}

make() {
// const section = document.querySelector(this.parent);
let s = this.sys;
if(s.title) {
$$.create('h6', { inside: this.parent, innerHTML: s.title });
}

if(s.contentBlocks) {
s.contentBlocks.forEach((blockConf, index) => {
this.blockMap[index] = this.getBlock(blockConf);
});
} else {
// TODO:
this.blockMap['test'] = this.getDemo(s);
}
}

getBlock(blockConf) {
let fnName = 'get' + toTitleCase(blockConf.type);
if(this[fnName]) {
return this[fnName](blockConf);
} else {
throw new Error(`Unknown section block type '${blockConf.type}'.`);
}
}

getText(blockConf) {
return $$.create('p', {
inside: this.parent,
className: 'new-context',
innerHTML: blockConf.content
});
}

getCode(blockConf) {
let pre = $$.create('pre', { inside: this.parent });
let lang = blockConf.lang || 'javascript';
let code = $$.create('code', {
inside: pre,
className: `hljs ${lang}`,
innerHTML: blockConf.content
});
}

getCustom(blockConf) {
this.parent.innerHTML += blockConf.html;
}

getDemo(blockConf) {
let bc = blockConf;
let args = bc.config;

let figure, row;
if(!bc.sideContent) {
figure = $$.create('figure', { inside: this.parent });
} else {
row = $$.create('div', {
inside: this.parent,
className: "row",
innerHTML: `<div class="col-sm-8"></div>
<div class="col-sm-4"></div>`,
});
figure = $$.create('figure', { inside: row.querySelector('.col-sm-8') });
row.querySelector('.col-sm-4').innerHTML += bc.sideContent;
}

let libObj = new this.LIB_OBJ(figure, args);
let demoIndex = this.demos.length;
this.demos.push(libObj);

if(bc.postSetup) {
bc.postSetup(this.demos[demoIndex], figure, row);
}

this.getDemoOptions(demoIndex, bc.options, args, figure);
this.getDemoActions(demoIndex, bc.actions, args);
}

getDemoOptions(demoIndex, options=[], args={}, figure) {
options.forEach(o => {
const btnGroup = $$.create('div', {
inside: this.parent,
className: `btn-group ${scrub(o.name)}`
});
const mapKeys = o.mapKeys;

if(o.type === "number") {
let numOpts = o.numberOptions;
let activeState = o.activeState ? o.activeState : 0

const inputGroup = $$.create('input', {
inside: btnGroup,
withLabel: o.name + ': ' + '<b>' + activeState + '</b>',
className: `form-control`,
type: "range",
min: numOpts.min,
max: numOpts.max,
step: numOpts.step,
value: activeState,
// (max - min)/2
onInput: (value) => {
if(o.path[1]) {
args[o.path[0]][o.path[1]] = value;
} else {
args[o.path[0]] = value;
}

let label = inputGroup.querySelector('label');
if(label) {
label.innerHTML = o.name + ': ' + '<b>' + value + '</b>';
}

this.demos[demoIndex] = new this.LIB_OBJ(figure, args);
}
});

} else if(["Map", "String", "Boolean", "Array", "Object"].includes(o.type)) {
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, string, number, object
args[o.path[0]] = state;
}
this.demos[demoIndex] = new this.LIB_OBJ(figure, args);
}
});

if(activeClass) { button.click(); }
});
}
});
}

getDemoActions(demoIndex, actions=[], args={}) {
actions.forEach(o => {
let args = o.args || [];
$$.create('button', {
inside: this.parent,
className: `btn btn-action btn-sm btn-secondary`,
innerHTML: o.name,
onClick: () => {this.demos[demoIndex][o.fn](...args);}
});
});
}
}


+ 22
- 0
docs/exporting/images.md Zobrazit soubor

@@ -0,0 +1,22 @@
## Exporting to images

Frappe charts are exportable to an SVG format, in which they are natively rendered.

```js
chart.export();
```

<project-demo data="get-update-data" v-bind:config="{
title: 'My Area Chart',
type: 'line',
height: 300,
lineOptions: { areaFill: 1 }
}"
v-bind:actions="[
{
name: 'Export',
fn: 'export',
args: []
}
]">
</project-demo>

+ 1
- 0
docs/externals/docsify.min.js
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 10947
- 0
docs/externals/vue.js
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 2
- 0
docs/frappe-charts.min.iife.js
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 57
- 0
docs/getting_started/quick_start.md Zobrazit soubor

@@ -0,0 +1,57 @@
## Installation
* Install via [`npm`](https://www.npmjs.com/get-npm):

```console
$ npm install frappe-charts
```

and include in your project:
```js
import { Chart } from "frappe-charts"
```

* ...or include within your HTML

```html
<script src="https://cdn.jsdelivr.net/npm/frappe-charts@1.1.0/dist/frappe-charts.min.iife.js"></script>
<!-- or -->
<script src="https://unpkg.com/frappe-charts@1.1.0/dist/frappe-charts.min.iife.js"></script>
```

## Usage
```js
const data = {
labels: ["12am-3am", "3am-6pm", "6am-9am", "9am-12am",
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9am-12am"
],
datasets: [
{
name: "Some Data", type: "bar",
values: [25, 40, 30, 35, 8, 52, 17, -4]
},
{
name: "Another Set", type: "line",
values: [25, 50, -10, 15, 18, 32, 27, 14]
}
]
}

const chart = new frappe.Chart("#chart", { // or a DOM element,
// new Chart() in case of ES6 module with above usage
title: "My Awesome Chart",
data: data,
type: 'axis-mixed', // or 'bar', 'line', 'scatter', 'pie', 'percentage'
height: 250,
colors: ['#7cd6fd', '#743ee2']
})
```

## Demo
Here's a demo to try out yourself:
<p data-height="299" data-theme-id="light" data-slug-hash="wjKBoq" data-default-tab="js,result"
data-user="pratu16x7" data-embed-version="2" data-pen-title="Frappe Charts Demo" class="codepen">
See the Pen <a href="https://codepen.io/pratu16x7/pen/wjKBoq/">Frappe Charts Demo</a>
by Prateeksha Singh (<a href="https://codepen.io/pratu16x7">@pratu16x7</a>) on
<a href="https://codepen.io">CodePen</a>.
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

+ 108
- 277
docs/index.html Zobrazit soubor

@@ -1,291 +1,55 @@
<!DOCTYPE html>
<html>
<head>
<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="description" content="A simple, responsive, modern charts library for the web.">
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Frappe Charts</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="https://frappe.github.io/charts">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

<link rel="stylesheet" type="text/css" href="assets/css/reset.css" media="screen">
<link rel="stylesheet" type="text/css" href="assets/css/bootstrap.min.css" media="screen">
<link rel="stylesheet" type="text/css" href="assets/css/index.css" media="screen">
<link rel="stylesheet" type="text/css" href="assets/css/hljs.css" media="screen">
<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.">

<script src="assets/js/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>

<link rel="shortcut icon" href="https://frappe.github.io/frappe/assets/img/favicon.png" type="image/x-icon">
<link rel="icon" href="https://frappe.github.io/frappe/assets/img/favicon.png" type="image/x-icon">
<link rel="stylesheet" type="text/css" href="assets/css/reset.css" media="screen">
<link rel="stylesheet" type="text/css" href="assets/css/bootstrap.min.css" media="screen">
<link rel="stylesheet" type="text/css" href="assets/css/index.css" media="screen">
<link rel="stylesheet" type="text/css" href="assets/css/hljs.css" media="screen">

<script async defer src="https://buttons.github.io/buttons.js"></script>
</head>
<link rel="stylesheet" type="text/css" href="vuestyle.css" media="screen">
<link rel="stylesheet" type="text/css" href="style.css" media="screen">

<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="demo-tip">Click or use arrow keys to navigate data points</p>
<div id="chart-composite-2" class="border"></div>
</header>

<section>
<h6>Create a chart</h6>
<pre><code class="hljs html"> &lt!--HTML--&gt;
&lt;div id="chart"&gt;&lt;/div&gt;</code></pre>
<pre><code class="hljs javascript"> // Javascript
let chart = new frappe.Chart( "#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' }}]
},
<script src="assets/js/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>

title: "My Awesome Chart",
type: 'axis-mixed', // or 'bar', 'line', 'pie', 'percentage'
height: 300,
colors: ['purple', '#ffa3ef', 'light-blue'],
<link rel="shortcut icon" href="https://frappe.github.io/frappe/assets/img/favicon.png" type="image/x-icon">
<link rel="icon" href="https://frappe.github.io/frappe/assets/img/favicon.png" type="image/x-icon">

tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' pts',
}
});
<script async defer src="https://buttons.github.io/buttons.js"></script>

chart.export();
</code></pre>

<div id="chart-aggr" class="border"></div>
<div class="btn-group aggr-type-buttons margin-top 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>
</section>

<section>
<h6>Update Values</h6>
<div id="chart-update" class="border"></div>

<div class="chart-update-buttons mt-1 mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary" data-update="random">Random Data</button>
<button type="button" class="btn btn-sm btn-secondary" data-update="add">Add Value</button>
<button type="button" class="btn btn-sm btn-secondary" data-update="remove">Remove Value</button>
<button type="button" class="btn btn-sm btn-secondary export-update">Export ...</button>
</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>
</head>
<body>
<div id="home-page" class="hide">

<section>
<h6>Listen to state change</h6>
<div class="row">
<div class="col-sm-8">
<div id="chart-events" class="border"></div>
</div>
<div class="col-sm-4 chart-events-data">
<div class="image-container border">
<img class="moon-image" src="./assets/img/europa.jpg">
</div>
<div class="content-data margin-top">
<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>
<p>Diameter: <span class="diameter">3121.6</span> km</p>
</div>
</div>
</div>
<pre><code class="hljs javascript margin-top"> ...
isNavigable: 1, // Navigate across data points; default 0
...

chart.parent.addEventListener('data-select', (e) => {
update_moon_data(e.index); // e contains index and value of current datapoint
});</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>
<h6>Demo</h6>
<p data-height="299" data-theme-id="light" data-slug-hash="wjKBoq" data-default-tab="js,result"
data-user="pratu16x7" data-embed-version="2" data-pen-title="Frappe Charts Demo" class="codepen">
See the Pen <a href="https://codepen.io/pratu16x7/pen/wjKBoq/">Frappe Charts Demo</a>
by Prateeksha Singh (<a href="https://codepen.io/pratu16x7">@pratu16x7</a>) on
<a href="https://codepen.io">CodePen</a>.
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
</section>

<section>
<h6>Available options</h6>
<pre><code class="hljs javascript">
...
{
data: {
labels: [],
datasets: [],
yRegions: [],
yMarkers: []
}
title: '',
colors: [],
height: 200,

tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' pts',
}

// Axis charts
isNavigable: 1, // default: 0
valuesOverPoints: 1, // default: 0
barOptions: {
spaceRatio: 1 // default: 0.5
stacked: 1 // default: 0
}

lineOptions: {
dotSize: 6, // default: 4
hideLine: 0, // default: 0
hideDots: 1, // default: 0
heatline: 1, // default: 0
regionFill: 1 // default: 0
}

axisOptions: {
yAxisMode: 'span', // Axis lines, default
xAxisMode: 'tick', // No axis lines, only short ticks
xIsSeries: 1 // Allow skipping x values for space
// default: 0
},

// Pie/Percentage charts
maxLegendPoints: 6, // default: 20
maxSlices: 10, // default: 20

// Percentage chart
barOptions: {
height: 15 // default: 20
depth: 5 // default: 2
}

// Heatmap
discreteDomains: 1, // default: 1
}
...

// Updating values
chart.update(data);

// Axis charts:
chart.addDataPoint(label, valueFromEachDataset, index)
chart.removeDataPoint(index)
chart.updateDataset(datasetValues, index)

// Exporting
chart.export();

// Unbind window-resize events
chart.unbindWindowEvents();

</code></pre>
</section>
<header>
<h1>Frappe Charts</h1>
<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>
<figure id="bar-composite-1" class="border"></figure>
</header>

<section>
<h6>Install</h6>
<p>Install via npm</p>
<pre><code class="hljs console"> npm install frappe-charts</code></pre>
<p>And include it in your project</p>
<pre><code class="hljs javascript"> import { Chart } from "frappe-charts"</code></pre>
<p>... or include it directly in your HTML</p>
<pre><code class="hljs html"> &lt;script src="https://unpkg.com/frappe-charts@1.1.0"&gt;&lt;/script&gt;</code></pre>
<p>Use as:</p>
<pre><code class="hljs javascript"> new Chart(); // ES6 module
// or
new frappe.Chart(); // Browser</code></pre>
</section>
<!-- Generated content goes here -->

<section class="text-center">
<!-- Closing -->
<section class="closing text-center">
<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;">
<!-- <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;">
<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 style="mt1: 3rem; margin-bottom: 1.5rem;">
<a href="#" id="docs-link" style="margin-right: 1rem;">Documentation</a>
<a href="https://github.com/frappe/charts" target="_blank">GitHub</a>
</p>
<p><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>
</section>

@@ -311,7 +75,74 @@
</svg>
</a>

<script src="assets/js/frappe-charts.min.js"></script>
<script src="assets/js/index.min.js"></script>
</body>
</div>

<div id="app"></div>

<!-- SCRIPTS -->

<!-- Home page script -->
<script src="index.min.js"></script>

<!-- Docs section script -->
<script src="data.js"></script>
<script src="demoBuilder.js"></script>
<script src="frappe-charts.min.iife.js"></script>
<!-- <script src="//unpkg.com/vue/dist/vue.js"></script> -->
<script src="/externals/vue.js"></script>
<script>

let dbd = new demoBuilder(frappe.Chart);

Vue.component('project-demo', {
template: '<div class="project-demo"></div>',
props: ['data', 'config', 'options', 'actions', 'sideContent'],
mounted: function() {
let config = this.config;
config.data = sampleData[this.data];
if(typeof sampleData[this.data] === "function") {
config.data = sampleData[this.data]();
}

var demoConfig = {
config: config,
options: this.options,
actions: this.actions,
sideContent: this.sideContent,
};

dbd.makeSection(this.$el, demoConfig);
}
});

Vue.mixin({
methods: {
getAddUpdateData: getAddUpdateData,
getUpdateData: getUpdateData
}
})

new Vue({
el: '#app',
});

window.$docsify = {
name: 'frappe-charts',
// repo: 'https://github.com/frappe/charts',
loadSidebar: true,
subMaxLevel: 5,
executeScript: true,
search: {
placeholder: 'Search Docs ...',
noData: 'No Results',
depth: 2
}
};
</script>

<!-- <script src="//unpkg.com/docsify/lib/docsify.min.js"></script> -->
<script src="/externals/docsify.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/external-script.min.js"></script>
</body>
</html>

+ 30
- 0
docs/index.js Zobrazit soubor

@@ -0,0 +1,30 @@
import { docsBuilder } from './assets/js/docsBuilder';
import { Chart } from "../dist/frappe-charts.min.esm";

import { $, insertAfter } from '../src/js/utils/dom';
import { fireballOver25, fireball_2_5, fireball_5_25 } from './assets/js/data';
import { lineComposite, barComposite, demoSections} from './assets/js/demoConfig';

let dbd = new docsBuilder(Chart);
let currentElement = document.querySelector('header');

if(document.querySelectorAll('#line-composite-1').length
&& !document.querySelector('#home-page').classList.contains("hide")) {

let lineCompositeChart = new Chart("#line-composite-1", lineComposite.config);
let barCompositeChart = new Chart("#bar-composite-1", barComposite.config);

lineCompositeChart.parent.addEventListener('data-select', (e) => {
let i = e.index;
barCompositeChart.updateDatasets([
fireballOver25[i], fireball_5_25[i], fireball_2_5[i]
]);
});

demoSections.forEach(sectionConf => {
let sectionEl = $.create('section', { className: sectionConf.name || sectionConf.title });
insertAfter(sectionEl, currentElement);
currentElement = sectionEl;
dbd.makeSection(sectionEl, sectionConf);
});
}

+ 5653
- 0
docs/index.min.js
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 57
- 0
docs/reference/api.md Zobrazit soubor

@@ -0,0 +1,57 @@
# API

## Modifying Data
There are two ways to update data in a chart: either in adding and removing individual points, or updating the existing data with an entirely new set of data points.

### Updating individual data points

#### addDataPoint
Add a data point to the chart, increasing the length of the dataset.

```js
addDataPoint(label: String, valueFromEachDataset: Array, index: Number): void

// Usage
let label = 'Wed';
let valueFromEachDataset = [30, 17];

chart.addDataPoint(label, valueFromEachDataset); // by default adds at end
chart.addDataPoint(label, valueFromEachDataset, 6);
```

#### removeDataPoint
Remove a data point from the chart, reducing the length of the dataset.

```js
removeDataPoint(index: Number): void

// Usage
chart.removeDataPoint(); // by default removes from end
chart.removeDataPoint(10);
```

### Updating full data

#### update

Update the entire data, including annotations, by passing the entire new `data` object to `update`.

```js
update(data: Object): void

// Usage
chart.update(data);
```

## Exporting

#### export

Frappe charts are exportable to an SVG format, in which they are natively rendered.

```js
export(): void

// Usage
chart.export();
```

+ 200
- 0
docs/reference/configuration.md Zobrazit soubor

@@ -0,0 +1,200 @@
# Configuration

With all the customizable features of Frappe Charts, this section is dedicated to enabling / disabling existing functionality.

## Container

The first parameter required by the `Chart` constructor is the container element. You can pass in a CSS Selector or a DOM Object.

```javascript
const chart = new Chart('#chart', options);
// or
const container = document.querySelector('#chart');
const chart = new Chart(container, options);
```

## Options

The second parameter required by the `Chart` constructor is the options object. The minimum required configuration is to pass `data` values, which itself requires an array of `labels` and an array of `datasets`.

```javascript
const options = {
data: {
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm", "12pm-3pm"],

datasets: [
{
name: "Some Data", values: [25, 40, 30, 35, 8]
},
{
name: "Another Set", values: [25, 50, -10, 15, 18]
}
]
}
}

const chart = new Chart(container, options);
```

### data
- Type: `Object`
- Required Properties: `labels`, `datasets`
- Optional Properties: `yMarkers`, `yRegions`

Contains an array of `labels` and an array of `datasets`, each a value for the 2-dimensional data points.

May also have [annotation]() parameters, for example those for `yMarkers` and `yRegions`. This is because all properties defined inside data are meant to be animatable.
```javascript
data: {
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm", "12pm-3pm"],

datasets: [
{ name: "Some Data", values: [25, 40, 30, 35, 8] },
{ name: "Another Set", values: [25, 50, -10, 15, 18] }
],

yMarkers: [{ label: "Marker", value: 70 }],

yRegions: [{ label: "Region", start: -10, end: 50 }]
}
```

Other configurable options are listed as follows:

### title
- Type: `String`
- Default: `''`

Add a title to the Chart.

---

### type
- Type: `String`
- Values: `line | bar | axis-mixed | pie | percentage | heatmap`
- Default: `line`

Let the chart know what type to render.

#### type: 'axis-mixed'

Mixed axis chart. For this to work, you must pass the `chartType` value for each dataset.

```javascript

const data = {
labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],

datasets: [
{
name: "Some Data",
values: [18, 40, 30, 35, 8, 52, 17],
chartType: 'bar'
},
{
name: "Yet Another",
values: [15, 20, -3, -15, 58, 12, -17],
chartType: 'line'
}
]
}

const chart = new Chart('#chart', {
data: data
});

```

---

### colors
- Type: `Array`
- Default: `['light-blue', 'blue', 'violet', 'red', 'orange',
'yellow', 'green', 'light-green', 'purple', 'magenta', 'light-grey', 'dark-grey']`

Set the colors to be used for each individual unit type, depending on the chart type.

---

### height
- Type: `Number`
- Default: `240`

Set the height of the chart in pixels.

---

### axisOptions
- Type: `Object`
- Default: `{}`

#### xAxisMode and yAxisMode
- Type: `String`
- Values: `span | tick`
- Default: `span`

Display axis points as short ticks or long spanning lines.

#### xIsSeries
- Type: `Boolean`
- Default: `0`

The X axis (often the time axis) is usually continuous. That means we can reduce the redundancy of rendering every X label by setting `xIsSeries` to `1` and allowing only a few periodic ones.

---

### TooltipOptions
- Type: `Object`
- Default: `{}`

Customizing options for the format of the label and value displayed on hover tooltips.

####
- Type: `function`
- Default: `{}`

---

### barOptions
- Type: `Object`
- Default: `{}`

Can be used to set various properties on bar plots.

#### spaceRatio
- Type: `Number`
- Min: `0`
- Max: `2`
- Default: `0.5`

In order to set the bar width, instead of defining it and the space between the bars independently, we simply define the <b>ratio of the space</b> between bars to the bar width. The chart then adjusts the actual size proportional to the chart container.

#### stacked
- Type: `Boolean`
- Default: `0`

Renders multiple bar datasets in a stacked configuration, rather than the default adjacent.

---

### lineOptions
- Type: `Object`
- Default: `{}`

Can be used to set various properties on line plots, turn them into Area Charts and so on. Explore in details on the [Trends]() page.

---

### isNavigable
- Type: `Boolean`
- Default: `0`

Makes the chart interactive with arrow keys and highlights the current active data point.

---

### valuesOverPoints
- Type: `Boolean`
- Default: `0`

To display data values over bars or dots in an axis graph.

+ 15
- 0
docs/style.css Zobrazit soubor

@@ -0,0 +1,15 @@
input[type="range"] {
padding: 0;
}

.input-wrapper {
display: flex;
margin-right: 15px;
}

.input-wrapper label {
margin-right: 10px;
margin-top: 5px;
font-size: 0.8em;
flex-shrink: 0;
}

+ 60
- 0
docs/update_state/modify_data.md Zobrazit soubor

@@ -0,0 +1,60 @@
# Modifying Data

There are two ways to update data in a chart: either in adding and removing individual points, or updating the existing data with an entirely new set of data points.

### Updating individual data points

```js
let label = 'Wed';
let valueFromEachDataset = [30];
let index = 10; // default for adding/removing values: last index

chart.addDataPoint(label, valueFromEachDataset); // by default adds at end
chart.addDataPoint(label, valueFromEachDataset, index);
```

```js
let index = 10;
chart.removeDataPoint();
chart.removeDataPoint(index);
```

<project-demo data="get-update-data" v-bind:config="{
type: 'line',
height: 200
}"
v-bind:actions="[
{
name: 'Add Value',
fn: 'addDataPoint',
args: getAddUpdateData()
},
{
name: 'Remove Value',
fn: 'removeDataPoint',
args: []
}
]">
</project-demo>

### Updating full data

Another way is to simply update the entire data, including annotations, by passing the entire new `data` object to `update`.

```js
chart.update(data);
```

<project-demo data="get-update-data" v-bind:config="{
type: 'line',
height: 200
}"
v-bind:actions="[
{
name: 'Random Data',
fn: 'update',
args: [getUpdateData()]
}
]">
</project-demo>


+ 27
- 0
docs/update_state/navigation.md Zobrazit soubor

@@ -0,0 +1,27 @@
# Navigation

In order to analyse a data individually, it helps if the chart can activate a given point on the plot. This is where `isNavigable` comes in handy, which makes the chart interactive with arrow keys and highlights the current active data point.

```js
isNavigable: true // default: false
```

Try and traverse this chart with arrow-keys.

<project-demo data="2" v-bind:config="{
type: 'bar',
height: 140,
isNavigable: 1,
colors: ['light-blue'],
axisOptions: { xAxisMode: 'tick' },
barOptions: { spaceRatio: 0.2 },
}">
</project-demo>

Each time a data point is activated, a new `data-select` event is triggered that contains all the label and value information specific to the point This can then be used to reflect in other parts of the webpage.

```js
chart.parent.addEventListener('data-select', (e) => {
update_moon_data(e.index); // e contains index and value of current datapoint
});
```

+ 952
- 0
docs/vuestyle.css Zobrazit soubor

@@ -0,0 +1,952 @@
@import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600");
* {
-webkit-font-smoothing: antialiased;
-webkit-overflow-scrolling: touch;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-text-size-adjust: none;
-webkit-touch-callout: none;
box-sizing: border-box
}

body:not(.ready) {
overflow: hidden
}

body:not(.ready) .app-nav,
body:not(.ready)>nav,
body:not(.ready) [data-cloak] {
display: none
}

div#app {
font-size: 30px;
font-weight: lighter;
margin: 40vh auto;
text-align: center
}

div#app:empty:before {
content: "Loading..."
}

.emoji {
height: 1.2rem;
vertical-align: middle
}

.progress {
background-color: var(--theme-color, #7b85f2);
height: 2px;
left: 0;
position: fixed;
right: 0;
top: 0;
transition: width .2s, opacity .4s;
width: 0;
z-index: 5
}

.search .search-keyword,
.search a:hover {
color: var(--theme-color, #7b85f2)
}

.search .search-keyword {
font-style: normal;
font-weight: 700
}

body,
html {
height: 100%
}

body {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
color: #34495e;
font-family: Source Sans Pro, Helvetica Neue, Arial, sans-serif;
font-size: 15px;
letter-spacing: 0;
margin: 0;
overflow-x: hidden
}

img {
max-width: 100%
}

a[disabled] {
cursor: not-allowed;
opacity: .6
}

kbd {
border: 1px solid #ccc;
border-radius: 3px;
display: inline-block;
font-size: 12px !important;
line-height: 12px;
margin-bottom: 3px;
padding: 3px 5px;
vertical-align: middle
}

.task-list-item {
list-style-type: none
}

li input[type=checkbox] {
margin: 0 .2em .25em -1.6em;
vertical-align: middle
}

.app-nav {
margin: 25px 60px 0 0;
position: absolute;
right: 0;
text-align: right;
z-index: 2
}

.app-nav.no-badge {
margin-right: 25px
}

.app-nav p {
margin: 0
}

.app-nav>a {
margin: 0 1rem;
padding: 5px 0
}

.app-nav li,
.app-nav ul {
display: inline-block;
list-style: none;
margin: 0
}

.app-nav a {
color: inherit;
font-size: 16px;
text-decoration: none;
transition: color .3s
}

.app-nav a.active,
.app-nav a:hover {
color: var(--theme-color, #7b85f2)
}

.app-nav a.active {
border-bottom: 2px solid var(--theme-color, #7b85f2)
}

.app-nav li {
display: inline-block;
margin: 0 1rem;
padding: 5px 0;
position: relative
}

.app-nav li ul {
background-color: #fff;
border: 1px solid #ddd;
border-bottom-color: #ccc;
border-radius: 4px;
box-sizing: border-box;
display: none;
max-height: calc(100vh - 61px);
overflow-y: auto;
padding: 10px 0;
position: absolute;
right: -15px;
text-align: left;
top: 100%;
white-space: nowrap
}

.app-nav li ul li {
display: block;
font-size: 14px;
line-height: 1rem;
margin: 0;
margin: 8px 14px;
white-space: nowrap
}

.app-nav li ul a {
display: block;
font-size: inherit;
margin: 0;
padding: 0
}

.app-nav li ul a.active {
border-bottom: 0
}

.app-nav li:hover ul {
display: block
}

.github-corner {
border-bottom: 0;
position: fixed;
right: 0;
text-decoration: none;
top: 0;
z-index: 1
}

.github-corner:hover .octo-arm {
animation: a .56s ease-in-out
}

.github-corner svg {
color: #fff;
fill: var(--theme-color, #7b85f2);
height: 80px;
width: 80px
}

main {
display: block;
position: relative;
width: 100vw;
height: 100%;
z-index: 0
}

main.hidden {
display: none
}

.anchor {
display: inline-block;
text-decoration: none;
transition: all .3s
}

.anchor span {
color: #34495e
}

.anchor:hover {
text-decoration: underline
}

.sidebar {
border-right: 1px solid rgba(0, 0, 0, .07);
overflow-y: auto;
padding: 40px 0 0;
position: absolute;
top: 0;
bottom: 0;
left: 0;
transition: transform .25s ease-out;
width: 300px;
z-index: 3
}

.sidebar>h1 {
margin: 0 auto 1rem;
font-size: 1.5rem;
font-weight: 300;
text-align: center
}

.sidebar>h1 a {
color: inherit;
text-decoration: none
}

.sidebar>h1 .app-nav {
display: block;
position: static
}

.sidebar .sidebar-nav {
line-height: 2em;
padding-bottom: 40px
}

.sidebar li.collapse .app-sub-sidebar {
display: none
}

.sidebar ul {
margin: 0;
padding: 0
}

.sidebar li>p {
font-weight: 700;
margin: 0
}

.sidebar ul,
.sidebar ul li {
list-style: none
}

.sidebar ul li a {
border-bottom: none;
display: block
}

.sidebar ul li ul {
padding-left: 20px
}

.sidebar::-webkit-scrollbar {
width: 4px
}

.sidebar::-webkit-scrollbar-thumb {
background: transparent;
border-radius: 4px
}

.sidebar:hover::-webkit-scrollbar-thumb {
background: hsla(0, 0%, 53%, .4)
}

.sidebar:hover::-webkit-scrollbar-track {
background: hsla(0, 0%, 53%, .1)
}

.sidebar-toggle {
background-color: transparent;
background-color: hsla(0, 0%, 100%, .8);
border: 0;
outline: none;
padding: 10px;
position: absolute;
bottom: 0;
left: 0;
text-align: center;
transition: opacity .3s;
width: 284px;
z-index: 4
}

.sidebar-toggle .sidebar-toggle-button:hover {
opacity: .4
}

.sidebar-toggle span {
background-color: var(--theme-color, #7b85f2);
display: block;
margin-bottom: 4px;
width: 16px;
height: 2px
}

body.sticky .sidebar,
body.sticky .sidebar-toggle {
position: fixed
}

.content {
padding-top: 60px;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 300px;
transition: left .25s ease
}

.markdown-section {
margin: 0 auto;
max-width: 800px;
padding: 30px 15px 40px;
position: relative
}

.markdown-section>* {
box-sizing: border-box;
font-size: inherit
}

.markdown-section>:first-child {
margin-top: 0 !important
}

.markdown-section hr {
border: none;
border-bottom: 1px solid #eee;
margin: 2em 0
}

.markdown-section iframe {
border: 1px solid #eee
}

.markdown-section table {
border-collapse: collapse;
border-spacing: 0;
display: block;
margin-bottom: 1rem;
overflow: auto;
width: 100%
}

.markdown-section th {
font-weight: 700
}

.markdown-section td,
.markdown-section th {
border: 1px solid #ddd;
padding: 6px 13px
}

.markdown-section tr {
border-top: 1px solid #ccc
}

.markdown-section p.tip,
.markdown-section tr:nth-child(2n) {
background-color: #f8f8f8
}

.markdown-section p.tip {
border-bottom-right-radius: 2px;
border-left: 4px solid #f66;
border-top-right-radius: 2px;
margin: 2em 0;
padding: 12px 24px 12px 30px;
position: relative
}

.markdown-section p.tip:before {
background-color: #f66;
border-radius: 100%;
color: #fff;
content: "!";
font-family: Dosis, Source Sans Pro, Helvetica Neue, Arial, sans-serif;
font-size: 14px;
font-weight: 700;
left: -12px;
line-height: 20px;
position: absolute;
height: 20px;
width: 20px;
text-align: center;
top: 14px
}

.markdown-section p.tip code {
background-color: #efefef
}

.markdown-section p.tip em {
color: #34495e
}

.markdown-section p.warn {
background: rgba(66, 185, 131, .1);
border-radius: 2px;
padding: 1rem
}

body.close .sidebar {
transform: translateX(-300px)
}

body.close .sidebar-toggle {
width: auto
}

body.close .content {
left: 0
}

@media print {
.app-nav,
.github-corner,
.sidebar,
.sidebar-toggle {
display: none
}
}

@media screen and (max-width:768px) {
.github-corner,
.sidebar,
.sidebar-toggle {
position: fixed
}
.app-nav {
margin-top: 16px
}
.app-nav li ul {
top: 30px
}
main {
height: auto;
overflow-x: hidden
}
.sidebar {
left: -300px;
transition: transform .25s ease-out
}
.content {
left: 0;
max-width: 100vw;
position: static;
padding-top: 20px;
transition: transform .25s ease
}
.app-nav,
.github-corner {
transition: transform .25s ease-out
}
.sidebar-toggle {
background-color: transparent;
width: auto;
padding: 30px 30px 10px 10px
}
body.close .sidebar {
transform: translateX(300px)
}
body.close .sidebar-toggle {
background-color: hsla(0, 0%, 100%, .8);
transition: background-color 1s;
width: 284px;
padding: 10px
}
body.close .content {
transform: translateX(300px)
}
body.close .app-nav,
body.close .github-corner {
display: none
}
.github-corner:hover .octo-arm {
animation: none
}
.github-corner .octo-arm {
animation: a .56s ease-in-out
}
}

@keyframes a {
0%,
to {
transform: rotate(0)
}
20%,
60% {
transform: rotate(-25deg)
}
40%,
80% {
transform: rotate(10deg)
}
}

section.cover {
-ms-flex-align: center;
align-items: center;
background-position: 50%;
background-repeat: no-repeat;
background-size: cover;
height: 100vh;
display: none
}

section.cover.show {
display: -ms-flexbox;
display: flex
}

section.cover.has-mask .mask {
background-color: #fff;
opacity: .8;
position: absolute;
top: 0;
height: 100%;
width: 100%
}

section.cover .cover-main {
-ms-flex: 1;
flex: 1;
margin: -20px 16px 0;
text-align: center;
z-index: 1
}

section.cover a {
color: inherit
}

section.cover a,
section.cover a:hover {
text-decoration: none
}

section.cover p {
line-height: 1.5rem;
margin: 1em 0
}

section.cover h1 {
color: inherit;
font-size: 2.5rem;
font-weight: 300;
margin: .625rem 0 2.5rem;
position: relative;
text-align: center
}

section.cover h1 a {
display: block
}

section.cover h1 small {
bottom: -.4375rem;
font-size: 1rem;
position: absolute
}

section.cover blockquote {
font-size: 1.5rem;
text-align: center
}

section.cover ul {
line-height: 1.8;
list-style-type: none;
margin: 1em auto;
max-width: 500px;
padding: 0
}

section.cover .cover-main>p:last-child a {
border: 1px solid var(--theme-color, #7b85f2);
border-radius: 2rem;
box-sizing: border-box;
color: var(--theme-color, #7b85f2);
display: inline-block;
font-size: 1.05rem;
letter-spacing: .1rem;
margin: .5rem 1rem;
padding: .75em 2rem;
text-decoration: none;
transition: all .15s ease
}

section.cover .cover-main>p:last-child a:last-child {
background-color: var(--theme-color, #7b85f2);
color: #fff
}

section.cover .cover-main>p:last-child a:last-child:hover {
color: inherit;
opacity: .8
}

section.cover .cover-main>p:last-child a:hover {
color: inherit
}

section.cover blockquote>p>a {
border-bottom: 2px solid var(--theme-color, #7b85f2);
transition: color .3s
}

section.cover blockquote>p>a:hover {
color: var(--theme-color, #7b85f2)
}

.sidebar,
body {
background-color: #fff
}

.sidebar {
color: #364149
}

.sidebar li {
margin: 6px 0 6px 15px
}

.sidebar ul li a {
color: #505d6b;
font-size: 14px;
font-weight: 400;
overflow: hidden;
text-decoration: none;
text-overflow: ellipsis;
white-space: nowrap
}

.sidebar ul li a:hover {
text-decoration: underline
}

.sidebar ul li ul {
padding: 0
}

.sidebar ul li.active>a {
border-right: 2px solid;
color: var(--theme-color, #7b85f2);
font-weight: 600
}

.app-sub-sidebar li:before {
content: "-";
padding-right: 4px;
float: left
}

.markdown-section h1,
.markdown-section h2,
.markdown-section h3,
.markdown-section h4,
.markdown-section strong {
color: #2c3e50;
font-weight: 600
}

.markdown-section a {
color: var(--theme-color, #7b85f2);
font-weight: 600
}

.markdown-section h1 {
font-size: 2rem;
margin: 0 0 1rem
}

.markdown-section h2 {
font-size: 1.75rem;
margin: 45px 0 .8rem
}

.markdown-section h3 {
font-size: 1.5rem;
margin: 40px 0 .6rem
}

.markdown-section h4 {
font-size: 1.25rem
}

.markdown-section h5 {
font-size: 1rem
}

.markdown-section h6 {
color: #777;
font-size: 1rem
}

.markdown-section figure,
.markdown-section p {
margin: 1.2em 0
}

.markdown-section ol,
.markdown-section p,
.markdown-section ul {
line-height: 1.6rem;
word-spacing: .05rem
}

.markdown-section ol,
.markdown-section ul {
padding-left: 1.5rem
}

.markdown-section blockquote {
border-left: 4px solid var(--theme-color, #7b85f2);
color: #858585;
margin: 2em 0;
padding-left: 20px
}

.markdown-section blockquote p {
font-weight: 600;
margin-left: 0
}

.markdown-section iframe {
margin: 1em 0
}

.markdown-section em {
color: #7f8c8d
}

.markdown-section code {
border-radius: 2px;
color: #e96900;
font-size: .8rem;
margin: 0 2px;
padding: 3px 5px;
white-space: pre-wrap
}

.markdown-section code,
.markdown-section pre {
background-color: #f8f8f8;
font-family: Roboto Mono, Monaco, courier, monospace
}

.markdown-section pre {
-moz-osx-font-smoothing: initial;
-webkit-font-smoothing: initial;
line-height: 1.5rem;
margin: 1.2em 0;
overflow: auto;
padding: 0 1.4rem;
position: relative;
word-wrap: normal
}

.token.cdata,
.token.comment,
.token.doctype,
.token.prolog {
color: #8e908c
}

.token.namespace {
opacity: .7
}

.token.boolean,
.token.number {
color: #c76b29
}

.token.punctuation {
color: #525252
}

.token.property {
color: #c08b30
}

.token.tag {
color: #2973b7
}

.token.string {
color: var(--theme-color, #7b85f2)
}

.token.selector {
color: #6679cc
}

.token.attr-name {
color: #2973b7
}

.language-css .token.string,
.style .token.string,
.token.entity,
.token.url {
color: #22a2c9
}

.token.attr-value,
.token.control,
.token.directive,
.token.unit {
color: var(--theme-color, #7b85f2)
}

.token.keyword {
color: #e96900
}

.token.atrule,
.token.regex,
.token.statement {
color: #22a2c9
}

.token.placeholder,
.token.variable {
color: #3d8fd1
}

.token.deleted {
text-decoration: line-through
}

.token.inserted {
border-bottom: 1px dotted #202746;
text-decoration: none
}

.token.italic {
font-style: italic
}

.token.bold,
.token.important {
font-weight: 700
}

.token.important {
color: #c94922
}

.token.entity {
cursor: help
}

.markdown-section pre>code {
-moz-osx-font-smoothing: initial;
-webkit-font-smoothing: initial;
background-color: #f8f8f8;
border-radius: 2px;
color: #525252;
display: block;
font-family: Roboto Mono, Monaco, courier, monospace;
font-size: .8rem;
line-height: inherit;
margin: 0 2px;
max-width: inherit;
overflow: inherit;
padding: 2.2em 5px;
white-space: inherit
}

.markdown-section code:after,
.markdown-section code:before {
letter-spacing: .05rem
}

code .token {
-moz-osx-font-smoothing: initial;
-webkit-font-smoothing: initial;
min-height: 1.5rem
}

pre:after {
color: #ccc;
content: attr(data-lang);
font-size: .6rem;
font-weight: 600;
height: 15px;
line-height: 15px;
padding: 5px 10px 0;
position: absolute;
right: 0;
text-align: right;
top: 0
}

+ 4
- 0
docs/wrappers.md Zobrazit soubor

@@ -0,0 +1,4 @@
- [@tobiaslins](https://github.com/tobiaslins) contributed tweaks for his quest to make these easy to use with React. Check out his [repo]
- [@iamkdev's](https://github.com/iamkdev) blog on [usage with Angular](https://medium.com/@iamkdev/frappé-charts-with-angular-c9c5dd075d9f).
- A [Ruby Gem](https://github.com/pacuna/frappe_charts).


+ 4
- 5
package.json Zobrazit soubor

@@ -39,19 +39,19 @@
"babel-plugin-istanbul": "^4.1.5",
"babel-preset-env": "^1.6.1",
"babel-preset-latest": "^6.24.1",
"clean-css": "^4.1.11",
"babel-register": "^6.26.0",
"clean-css": "^4.1.11",
"coveralls": "^3.0.0",
"cross-env": "^5.1.4",
"cssnano": "^3.10.0",
"eslint": "^4.18.2",
"fs": "0.0.1-security",
"livereload": "^0.6.3",
"livereload": "^0.7.0",
"mocha": "^5.0.5",
"node-sass": "^4.7.2",
"npm-run-all": "^4.1.1",
"postcss": "^6.0.21",
"nyc": "^11.6.0",
"postcss": "^6.0.21",
"postcss-cssnext": "^3.0.2",
"postcss-nested": "^2.1.2",
"precss": "^3.1.2",
@@ -65,6 +65,5 @@
"rollup-plugin-uglify-es": "0.0.1",
"rollup-watch": "^4.3.1"
},
"dependencies": {
}
"dependencies": {}
}

+ 22
- 55
rollup.config.js Zobrazit soubor

@@ -42,10 +42,6 @@ export default [
input: 'src/js/index.js',
sourcemap: true,
output: [
{
file: 'docs/assets/js/frappe-charts.min.js',
format: 'iife',
},
{
file: pkg.browser,
format: 'iife',
@@ -81,43 +77,8 @@ export default [
uglify()
]
},
{
input: 'docs/assets/js/index.js',
sourcemap: true,
output: [
{
file: 'docs/assets/js/index.min.js',
format: 'iife',
}
],
name: 'frappe',
plugins: [
postcssPlugin({
preprocessor: (content, id) => new Promise((resolve, reject) => {
const result = sass.renderSync({ file: id })
resolve({ code: result.css.toString() })
}),
extensions: [ '.scss' ],
plugins: [
nested(),
cssnext({ warnForDuplicates: false }),
cssnano()
]
}),
eslint({
exclude: [
'src/css/**'
]
}),
babel({
exclude: 'node_modules/**'
}),
replace({
exclude: 'node_modules/**',
ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
})
]
},


{
input: 'src/js/chart.js',
sourcemap: true,
@@ -152,13 +113,28 @@ export default [
babel({
exclude: 'node_modules/**',
}),
replace({
exclude: 'node_modules/**',
ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
}),
uglify()
// TODO:
// uglify()
],
},


{
input: 'docs/index.js',
output: [
{
file: 'docs/index.min.js',
format: 'iife',
}
],
plugins: [
babel({
exclude: 'node_modules/**'
})
]
},


{
input: 'src/js/chart.js',
output: [
@@ -181,15 +157,6 @@ export default [
cssnano()
]
}),
eslint({
exclude: [
'src/css/**',
]
}),
replace({
exclude: 'node_modules/**',
ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
})
],
}
];

+ 1
- 1
src/js/chart.js Zobrazit soubor

@@ -17,7 +17,7 @@ const chartTypes = {

function getChartByType(chartType = 'line', parent, options) {
if (chartType === 'axis-mixed') {
options.type = 'line';
// options.type = 'line';
return new AxisChart(parent, options);
}



+ 2
- 3
src/js/charts/AxisChart.js Zobrazit soubor

@@ -16,7 +16,6 @@ export default class AxisChart extends BaseChart {
this.barOptions = args.barOptions || {};
this.lineOptions = args.lineOptions || {};

this.type = args.type || 'line';
this.init = 1;

this.setup();
@@ -249,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);
@@ -295,7 +294,7 @@ export default class AxisChart extends BaseChart {
color: this.colors[index],
svgDefs: this.svgDefs,
heatline: this.lineOptions.heatline,
regionFill: this.lineOptions.regionFill,
areaFill: this.lineOptions.areaFill,
hideDots: this.lineOptions.hideDots,
hideLine: this.lineOptions.hideLine,



+ 2
- 1
src/js/charts/BaseChart.js Zobrazit soubor

@@ -23,7 +23,7 @@ export default class BaseChart {
this.rawChartArgs = options;

this.title = options.title || '';
this.type = options.type || '';
this.type = options.type || 'line';

this.realData = this.prepareData(options.data);
this.data = this.prepareFirstData(this.realData);
@@ -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);


+ 1
- 1
src/js/objects/ChartComponents.js Zobrazit soubor

@@ -354,7 +354,7 @@ let componentConfigs = {
c.color,
{
heatline: c.heatline,
regionFill: c.regionFill
areaFill: c.areaFill
},
{
svgDefs: c.svgDefs,


+ 10
- 6
src/js/utils/axis-chart-utils.js Zobrazit soubor

@@ -1,5 +1,5 @@
import { fillArray } from '../utils/helpers';
import { DEFAULT_AXIS_CHART_TYPE, AXIS_DATASET_CHART_TYPES, DEFAULT_CHAR_WIDTH } from '../utils/constants';
import { AXIS_CHART_DEFAULT_TYPE, AXIS_CHART_MIXED_TYPE, AXIS_DATASET_CHART_TYPES, DEFAULT_CHAR_WIDTH } from '../utils/constants';

export function dataPrep(data, type) {
data.labels = data.labels || [];
@@ -16,6 +16,11 @@ export function dataPrep(data, type) {
}];
}

let overridingType;
if(AXIS_DATASET_CHART_TYPES.includes(type)) {
overridingType = type;
};

datasets.map(d=> {
// Set values
if(!d.values) {
@@ -34,14 +39,13 @@ export function dataPrep(data, type) {
}

// Set labels
//

// Set type
if(!d.chartType ) {
if(!AXIS_DATASET_CHART_TYPES.includes(type)) type === DEFAULT_AXIS_CHART_TYPE;
d.chartType = type;
if(overridingType) {
d.chartType = overridingType;
} else if(!d.chartType) {
d.chartType = AXIS_CHART_DEFAULT_TYPE;
}

});

// Markers


+ 12
- 3
src/js/utils/constants.js Zobrazit soubor

@@ -31,6 +31,7 @@ export const BASE_MEASURES = {
},

baseHeight: 240,

titleHeight: 20,
legendHeight: 30,

@@ -62,13 +63,21 @@ export function getExtraWidth(m) {
export const INIT_CHART_UPDATE_TIMEOUT = 700;
export const CHART_POST_ANIMATE_TIMEOUT = 400;

export const DEFAULT_AXIS_CHART_TYPE = 'line';
export const AXIS_CHART_DEFAULT_TYPE = 'line';
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 MIN_BAR_PERCENT_HEIGHT = 0.01;
export const BAR_CHART_SPACE_RATIO = 1;
export const MIN_BAR_PERCENT_HEIGHT = 0.02;

export const LINE_CHART_DOT_SIZE = 4;
export const DOT_OVERLAY_SIZE_INCR = 4;


+ 25
- 4
src/js/utils/dom.js Zobrazit soubor

@@ -26,6 +26,19 @@ $.create = (tag, o) => {
ref.parentNode.insertBefore(element, ref);
element.appendChild(ref);

} else if (i === "onClick" ) {
element.addEventListener('click', val);

} else if (i === "onInput" ) {
element.addEventListener('input', function(e) {
val(element.value);
});

} else if (i === "onChange" ) {
element.addEventListener('change', function(e) {
val(element.value);
});

} else if (i === "styles") {
if(typeof val === "object") {
Object.keys(val).map(prop => {
@@ -118,13 +131,21 @@ 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}`);

forEachNode($children, (node, i) => {
if (typeof $child === 'string') {
$child = $parent.querySelector($child);
}

this.forEachNode($children, (node, i) => {
if(index >= 0 && i <= index) return;
node.classList.remove(activeClass);
});
})

$child.classList.add(activeClass);
}

export function insertAfter(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

+ 1
- 1
src/js/utils/draw.js Zobrazit soubor

@@ -551,7 +551,7 @@ export function getPaths(xList, yList, color, options={}, meta={}) {
};

// Region
if(options.regionFill) {
if(options.areaFill) {
let gradient_id_region = makeGradient(meta.svgDefs, color, true);

let pathStr = "M" + `${xList[0]},${meta.zeroLine}L` + pointsStr + `L${xList.slice(-1)[0]},${meta.zeroLine}`;


+ 4
- 0
src/js/utils/helpers.js Zobrazit soubor

@@ -92,3 +92,7 @@ export function getPositionByAngle(angle, radius) {
y: Math.cos(angle * ANGLE_RATIO) * radius,
};
}

export function toTitleCase(str) {
return str.replace(/\w*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
}

+ 5
- 5
yarn.lock Zobrazit soubor

@@ -2720,13 +2720,13 @@ levn@^0.3.0, levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"

livereload@^0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/livereload/-/livereload-0.6.3.tgz#d97f6b133db6c70eff575abc7460f10cd35f6f76"
livereload@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/livereload/-/livereload-0.7.0.tgz#38238dd155ffb251191697f737b6b13f471da115"
dependencies:
chokidar "^1.7.0"
opts ">= 1.2.0"
ws "^1.1.1"
ws "^1.1.5"

load-json-file@^1.0.0:
version "1.1.0"
@@ -5200,7 +5200,7 @@ write@^0.2.1:
dependencies:
mkdirp "^0.5.1"

ws@^1.1.1:
ws@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51"
dependencies:


Načítá se…
Zrušit
Uložit