Compare commits
121 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c55b2c129c | ||
|
|
8fc2d3da72 | ||
|
|
5087de37c2 | ||
|
|
6519231aec | ||
|
|
1498251710 | ||
|
|
0271b06be5 | ||
|
|
b7810e430c | ||
|
|
beb5b4a811 | ||
|
|
80b4f459ac | ||
|
|
5cc6c20dff | ||
|
|
ff06309b9f | ||
|
|
2282680ab6 | ||
|
|
63c727ca58 | ||
|
|
8ae511b859 | ||
|
|
5cbd88a2a5 | ||
|
|
0de4a2f283 | ||
|
|
6b538f1a64 | ||
|
|
761831d86f | ||
|
|
e2ee06153f | ||
|
|
3d7ffb50cc | ||
|
|
3857a194b1 | ||
|
|
2cede5f625 | ||
|
|
f12dbc4b34 | ||
|
|
c3cbd0b128 | ||
|
|
4e36bbaea3 | ||
|
|
c066006520 | ||
|
|
f11d63d089 | ||
|
|
e5d1561bcd | ||
|
|
1c2b5dc55b | ||
|
|
6bdf532ea5 | ||
|
|
2ef08e5a52 | ||
|
|
bcd7d6e033 | ||
|
|
1f677569eb | ||
|
|
1b32910002 | ||
|
|
07efd722dc | ||
|
|
6076b7df0a | ||
|
|
7de3e2c1ea | ||
|
|
affc137ec5 | ||
|
|
61cf4540c4 | ||
|
|
4d59882e05 | ||
|
|
4a636bc7fb | ||
|
|
f74f60c03a | ||
|
|
8ad40d1b0d | ||
|
|
2d83da5a2c | ||
|
|
05a607422f | ||
|
|
8916ee643b | ||
|
|
fd1dac175f | ||
|
|
9ea1f7c25f | ||
|
|
e18c3a8de4 | ||
|
|
aae0102760 | ||
|
|
e9a2e1ebc8 | ||
|
|
0fc6f9f48c | ||
|
|
b25cd55ebe | ||
|
|
e9a37a72b7 | ||
|
|
cab09315ed | ||
|
|
ea8ec8b42d | ||
|
|
ff5ebec38d | ||
|
|
4f3f7624c1 | ||
|
|
6d16f02e64 | ||
|
|
1ec4ebf894 | ||
|
|
2bac3e247e | ||
|
|
1677380432 | ||
|
|
673c45393e | ||
|
|
7002534868 | ||
|
|
73969076b4 | ||
|
|
320ddd8e6b | ||
|
|
228e381cf5 | ||
|
|
a57988fc4e | ||
|
|
4ab6e685ca | ||
|
|
b747ec7776 | ||
|
|
d083f37826 | ||
|
|
7ee0734162 | ||
|
|
bc34bf9103 | ||
|
|
6ab3c22a98 | ||
|
|
4c3a23b565 | ||
|
|
719f86188d | ||
|
|
401731c99b | ||
|
|
a9ff5c0922 | ||
|
|
391d2f2629 | ||
|
|
539563005d | ||
|
|
986dbb4a5a | ||
|
|
a257c2af5f | ||
|
|
80307097aa | ||
|
|
f4dcc65509 | ||
|
|
99d4ad15a0 | ||
|
|
d12e272cf5 | ||
|
|
40e109bd44 | ||
|
|
099ab6aa03 | ||
|
|
0cb7b76fee | ||
|
|
beabb2793a | ||
|
|
c034ae3eb0 | ||
|
|
a5f41ce1b1 | ||
|
|
4d30c3777e | ||
|
|
eda1288230 | ||
|
|
4453299f43 | ||
|
|
7365c04ede | ||
|
|
8de8679ed6 | ||
|
|
719192297c | ||
|
|
691153aac4 | ||
|
|
ef0429ac68 | ||
|
|
e8e61a7281 | ||
|
|
13982b066f | ||
|
|
1a6775868a | ||
|
|
3265b26292 | ||
|
|
833beaeb85 | ||
|
|
36f7e7de84 | ||
|
|
ffddd25c8e | ||
|
|
a724ac54ee | ||
|
|
796992d0f8 | ||
|
|
34595901cd | ||
|
|
bfdc8f2617 | ||
|
|
e38aa2757d | ||
|
|
d424619b44 | ||
|
|
b4a16f05f2 | ||
|
|
1b08948d34 | ||
|
|
4cc5c4d029 | ||
|
|
2dca902d79 | ||
|
|
537ec25d55 | ||
|
|
3ccd3653f6 | ||
|
|
1f2f0a9a1c | ||
|
|
2e3685ca06 |
1
.doclets.yml
Normal file
1
.doclets.yml
Normal file
@ -0,0 +1 @@
|
||||
dir: src/scripts
|
||||
@ -1,6 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- '0.10'
|
||||
- '5.5.0'
|
||||
before_script:
|
||||
- 'npm install -g bower grunt-cli'
|
||||
- 'bower install'
|
||||
|
||||
65
CHANGELOG.md
65
CHANGELOG.md
@ -1,21 +1,62 @@
|
||||
v0.11.0 - 11 Apr 2017
|
||||
- Added CSP compatibility by using CSSOM instead of style attributes (Francisco Silva)
|
||||
- Added feature to render pie / donut chart as solid shape, allowing outlines (Sergey Kovalyov, Chris Carson)
|
||||
- Fixed XMLNS for foreignObjet content (Alfredo Matos)
|
||||
|
||||
v0.10.0 - 23 Oct 2016
|
||||
---------------------
|
||||
|
||||
- Added dominant-baseline styles for pie and donut charts (Gion Kunz)
|
||||
- Added public getNode on SVG api (Gion Kunz)
|
||||
- Added support for bar charts to have auto narrowing on AutoScaleAxis by overriding referenceValue (Jonathan Dumaine)
|
||||
- Added amdModuleId for better integration into webpack (Chris)
|
||||
- Added grid background to line and bar chart (hansmaad)
|
||||
- Added new LTS node version and included NPM run scripts (Gion Kunz)
|
||||
- Added correct meta data emission in events (Gion Kunz)
|
||||
- Fixed rounding issues where raw value was added instead of rounded (Gion Kunz)
|
||||
- Fixed step axis issue with axis stretch and series count 0 (Gion Kunz)
|
||||
- Fixed label position of single series pie / donut charts to be centered (Gion Kunz)
|
||||
- Fixed order or drawing pie and donut slices (Gion Kunz)
|
||||
- Fixed calculations of stepLength to only stretch ticksLength if > 1 (Alexander van Eck)
|
||||
- Fixed better handling of axisOptions.position and fallback to 'end' position (Alexander van Eck)
|
||||
- Fixed handling of holes in interpolation for multi-value series (James Watmuff)
|
||||
- Fixed function StepAxis() returning NaN (Joao Milton)
|
||||
- Fixed NaN issues in SVG when rendering Pie chart with only 0s (Alexander van Eck)
|
||||
- Fixed infinite loop in getBounds with a more robust increment (hansmaad)
|
||||
- Fixed performance of Chartist.extend (cheese83)
|
||||
- Fixed license reference issues in package.json (Jacob Quant)
|
||||
- Cleanup of data normalization changes and allows Date objects and booleans as values (Gion Kunz)
|
||||
- Cleanup refactoring for data management and normalization (Gion Kunz)
|
||||
|
||||
v0.9.8 - 22 Jun 2016
|
||||
--------------------
|
||||
- Added monotone cubic interpolation which is now the default interpolation for line charts (James Watmuff)
|
||||
- Update zoom plugin to 0.2.1 (hansmaad)
|
||||
- Bugfix: Prevent infinite loop in getBounds if bounds.valueRange is very small, fixes #643 (hansmaad)
|
||||
- Bugfix: Correct update events during media changes (Rory Hunter)
|
||||
- Bugfix: prevent negative value for foreignObject width attribute (Jose Ignacio)
|
||||
- Fixed example line chart in getting started documentation (Robin Edbom)
|
||||
- Updated development pipeline dependencies (Gion Kunz)
|
||||
- Updated chartist tooltip plugin and example styles (Gion Kunz)
|
||||
- Fixed WTFPL License issue (Gion Kunz)
|
||||
|
||||
v0.9.7 - 23 Feb 2016
|
||||
--------------------
|
||||
- Fixed bug with label and grid rendering on axis, fixes #621
|
||||
|
||||
v0.9.6 - 22 Feb 2016
|
||||
--------------------
|
||||
- Added dual licensing WTFPL and MIT, built new version <Gion Kunz>
|
||||
- Adding unminified CSS to dist output, fixes #506 <Gion Kunz>
|
||||
- Refactored namespaced attribute handling, fixes #584 <Gion Kunz>
|
||||
- Allow charts to be created without data and labels, fixes #598, fixes #588, fixes #537, fixes #425 <Gion Kunz> <Carlos Morales>
|
||||
- Removed onlyInteger setting from default bar chart settings, fixes #423 <Gion Kunz>
|
||||
- Removed serialization of values on line chart areas, fixes #424 <Gion Kunz>
|
||||
- Removed workaround and fallback for SVG element width and height calculations, fixes #592 <Gion Kunz>
|
||||
- Render 0 in ct:value attribute for line graphs <Paul Salaets>
|
||||
- Allow empty pie chart values to be ignored <Stephen>
|
||||
- Fix #527 Pie render issue with small angles. <hansmaad>
|
||||
- Small fix for stacked bars with 'holes' in the data <medzes>
|
||||
|
||||
- Added dual licensing WTFPL and MIT, built new version (Gion Kunz)
|
||||
- Adding unminified CSS to dist output, fixes #506 (Gion Kunz)
|
||||
- Refactored namespaced attribute handling, fixes #584 (Gion Kunz)
|
||||
- Allow charts to be created without data and labels, fixes #598, fixes #588, fixes #537, fixes #425 (Gion Kunz> <Carlos Morales)
|
||||
- Removed onlyInteger setting from default bar chart settings, fixes #423 (Gion Kunz)
|
||||
- Removed serialization of values on line chart areas, fixes #424 (Gion Kunz)
|
||||
- Removed workaround and fallback for SVG element width and height calculations, fixes #592 (Gion Kunz)
|
||||
- Render 0 in ct:value attribute for line graphs (Paul Salaets)
|
||||
- Allow empty pie chart values to be ignored (Stephen)
|
||||
- Fix #527 Pie render issue with small angles. (hansmaad)
|
||||
- Small fix for stacked bars with 'holes' in the data (medzes)
|
||||
|
||||
v0.9.5 - 14 Nov 2015
|
||||
--------------------
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (c) 2013 Gion Kunz <gion.kunz@gmail.com>
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
|
||||
13
bower.json
13
bower.json
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "chartist",
|
||||
"main": [
|
||||
"./dist/chartist.min.js",
|
||||
"./dist/chartist.min.css"
|
||||
"./dist/chartist.js",
|
||||
"./dist/chartist.css"
|
||||
],
|
||||
"devDependencies": {
|
||||
"snap.svg": "~0.3.0",
|
||||
@ -12,14 +12,15 @@
|
||||
"codemirror": "~4.12.0",
|
||||
"base64": "~0.3.0",
|
||||
"chartist-plugin-pointlabels": "~0.0.4",
|
||||
"chartist-plugin-sketchy": "~0.0.2",
|
||||
"chartist-plugin-accessibility": "~0.0.2",
|
||||
"chartist-plugin-tooltip": "~0.0.8",
|
||||
"chartist-plugin-tooltip": "~0.0.12",
|
||||
"chartist-plugin-axistitle": "~0.0.1",
|
||||
"chartist-plugin-threshold": "~0.0.1",
|
||||
"chartist-plugin-fill-donut": "~0.0.1",
|
||||
"chartist-plugin-zoom": "~0.0.1",
|
||||
"matchMedia": "~0.2.0"
|
||||
"chartist-plugin-zoom": "~0.2.1",
|
||||
"chartist-plugin-targetline": "~1.0.0",
|
||||
"matchMedia": "~0.2.0",
|
||||
"moment": "^2.14.1"
|
||||
},
|
||||
"ignore": [
|
||||
".*",
|
||||
|
||||
55
dist/chartist.css
vendored
55
dist/chartist.css
vendored
@ -4,7 +4,8 @@
|
||||
font-size: 0.75rem;
|
||||
line-height: 1; }
|
||||
|
||||
.ct-chart-line .ct-label, .ct-chart-bar .ct-label {
|
||||
.ct-chart-line .ct-label,
|
||||
.ct-chart-bar .ct-label {
|
||||
display: block;
|
||||
display: -webkit-box;
|
||||
display: -moz-box;
|
||||
@ -12,6 +13,10 @@
|
||||
display: -webkit-flex;
|
||||
display: flex; }
|
||||
|
||||
.ct-chart-pie .ct-label,
|
||||
.ct-chart-donut .ct-label {
|
||||
dominant-baseline: central; }
|
||||
|
||||
.ct-label.ct-horizontal.ct-start {
|
||||
-webkit-box-align: flex-end;
|
||||
-webkit-align-items: flex-end;
|
||||
@ -137,6 +142,9 @@
|
||||
stroke-width: 1px;
|
||||
stroke-dasharray: 2px; }
|
||||
|
||||
.ct-grid-background {
|
||||
fill: none; }
|
||||
|
||||
.ct-point {
|
||||
stroke-width: 10px;
|
||||
stroke-linecap: round; }
|
||||
@ -159,77 +167,92 @@
|
||||
|
||||
.ct-series-a .ct-point, .ct-series-a .ct-line, .ct-series-a .ct-bar, .ct-series-a .ct-slice-donut {
|
||||
stroke: #d70206; }
|
||||
.ct-series-a .ct-slice-pie, .ct-series-a .ct-area {
|
||||
|
||||
.ct-series-a .ct-slice-pie, .ct-series-a .ct-slice-donut-solid, .ct-series-a .ct-area {
|
||||
fill: #d70206; }
|
||||
|
||||
.ct-series-b .ct-point, .ct-series-b .ct-line, .ct-series-b .ct-bar, .ct-series-b .ct-slice-donut {
|
||||
stroke: #f05b4f; }
|
||||
.ct-series-b .ct-slice-pie, .ct-series-b .ct-area {
|
||||
|
||||
.ct-series-b .ct-slice-pie, .ct-series-b .ct-slice-donut-solid, .ct-series-b .ct-area {
|
||||
fill: #f05b4f; }
|
||||
|
||||
.ct-series-c .ct-point, .ct-series-c .ct-line, .ct-series-c .ct-bar, .ct-series-c .ct-slice-donut {
|
||||
stroke: #f4c63d; }
|
||||
.ct-series-c .ct-slice-pie, .ct-series-c .ct-area {
|
||||
|
||||
.ct-series-c .ct-slice-pie, .ct-series-c .ct-slice-donut-solid, .ct-series-c .ct-area {
|
||||
fill: #f4c63d; }
|
||||
|
||||
.ct-series-d .ct-point, .ct-series-d .ct-line, .ct-series-d .ct-bar, .ct-series-d .ct-slice-donut {
|
||||
stroke: #d17905; }
|
||||
.ct-series-d .ct-slice-pie, .ct-series-d .ct-area {
|
||||
|
||||
.ct-series-d .ct-slice-pie, .ct-series-d .ct-slice-donut-solid, .ct-series-d .ct-area {
|
||||
fill: #d17905; }
|
||||
|
||||
.ct-series-e .ct-point, .ct-series-e .ct-line, .ct-series-e .ct-bar, .ct-series-e .ct-slice-donut {
|
||||
stroke: #453d3f; }
|
||||
.ct-series-e .ct-slice-pie, .ct-series-e .ct-area {
|
||||
|
||||
.ct-series-e .ct-slice-pie, .ct-series-e .ct-slice-donut-solid, .ct-series-e .ct-area {
|
||||
fill: #453d3f; }
|
||||
|
||||
.ct-series-f .ct-point, .ct-series-f .ct-line, .ct-series-f .ct-bar, .ct-series-f .ct-slice-donut {
|
||||
stroke: #59922b; }
|
||||
.ct-series-f .ct-slice-pie, .ct-series-f .ct-area {
|
||||
|
||||
.ct-series-f .ct-slice-pie, .ct-series-f .ct-slice-donut-solid, .ct-series-f .ct-area {
|
||||
fill: #59922b; }
|
||||
|
||||
.ct-series-g .ct-point, .ct-series-g .ct-line, .ct-series-g .ct-bar, .ct-series-g .ct-slice-donut {
|
||||
stroke: #0544d3; }
|
||||
.ct-series-g .ct-slice-pie, .ct-series-g .ct-area {
|
||||
|
||||
.ct-series-g .ct-slice-pie, .ct-series-g .ct-slice-donut-solid, .ct-series-g .ct-area {
|
||||
fill: #0544d3; }
|
||||
|
||||
.ct-series-h .ct-point, .ct-series-h .ct-line, .ct-series-h .ct-bar, .ct-series-h .ct-slice-donut {
|
||||
stroke: #6b0392; }
|
||||
.ct-series-h .ct-slice-pie, .ct-series-h .ct-area {
|
||||
|
||||
.ct-series-h .ct-slice-pie, .ct-series-h .ct-slice-donut-solid, .ct-series-h .ct-area {
|
||||
fill: #6b0392; }
|
||||
|
||||
.ct-series-i .ct-point, .ct-series-i .ct-line, .ct-series-i .ct-bar, .ct-series-i .ct-slice-donut {
|
||||
stroke: #f05b4f; }
|
||||
.ct-series-i .ct-slice-pie, .ct-series-i .ct-area {
|
||||
|
||||
.ct-series-i .ct-slice-pie, .ct-series-i .ct-slice-donut-solid, .ct-series-i .ct-area {
|
||||
fill: #f05b4f; }
|
||||
|
||||
.ct-series-j .ct-point, .ct-series-j .ct-line, .ct-series-j .ct-bar, .ct-series-j .ct-slice-donut {
|
||||
stroke: #dda458; }
|
||||
.ct-series-j .ct-slice-pie, .ct-series-j .ct-area {
|
||||
|
||||
.ct-series-j .ct-slice-pie, .ct-series-j .ct-slice-donut-solid, .ct-series-j .ct-area {
|
||||
fill: #dda458; }
|
||||
|
||||
.ct-series-k .ct-point, .ct-series-k .ct-line, .ct-series-k .ct-bar, .ct-series-k .ct-slice-donut {
|
||||
stroke: #eacf7d; }
|
||||
.ct-series-k .ct-slice-pie, .ct-series-k .ct-area {
|
||||
|
||||
.ct-series-k .ct-slice-pie, .ct-series-k .ct-slice-donut-solid, .ct-series-k .ct-area {
|
||||
fill: #eacf7d; }
|
||||
|
||||
.ct-series-l .ct-point, .ct-series-l .ct-line, .ct-series-l .ct-bar, .ct-series-l .ct-slice-donut {
|
||||
stroke: #86797d; }
|
||||
.ct-series-l .ct-slice-pie, .ct-series-l .ct-area {
|
||||
|
||||
.ct-series-l .ct-slice-pie, .ct-series-l .ct-slice-donut-solid, .ct-series-l .ct-area {
|
||||
fill: #86797d; }
|
||||
|
||||
.ct-series-m .ct-point, .ct-series-m .ct-line, .ct-series-m .ct-bar, .ct-series-m .ct-slice-donut {
|
||||
stroke: #b2c326; }
|
||||
.ct-series-m .ct-slice-pie, .ct-series-m .ct-area {
|
||||
|
||||
.ct-series-m .ct-slice-pie, .ct-series-m .ct-slice-donut-solid, .ct-series-m .ct-area {
|
||||
fill: #b2c326; }
|
||||
|
||||
.ct-series-n .ct-point, .ct-series-n .ct-line, .ct-series-n .ct-bar, .ct-series-n .ct-slice-donut {
|
||||
stroke: #6188e2; }
|
||||
.ct-series-n .ct-slice-pie, .ct-series-n .ct-area {
|
||||
|
||||
.ct-series-n .ct-slice-pie, .ct-series-n .ct-slice-donut-solid, .ct-series-n .ct-area {
|
||||
fill: #6188e2; }
|
||||
|
||||
.ct-series-o .ct-point, .ct-series-o .ct-line, .ct-series-o .ct-bar, .ct-series-o .ct-slice-donut {
|
||||
stroke: #a748ca; }
|
||||
.ct-series-o .ct-slice-pie, .ct-series-o .ct-area {
|
||||
|
||||
.ct-series-o .ct-slice-pie, .ct-series-o .ct-slice-donut-solid, .ct-series-o .ct-area {
|
||||
fill: #a748ca; }
|
||||
|
||||
.ct-square {
|
||||
|
||||
7
dist/chartist.css.map
vendored
7
dist/chartist.css.map
vendored
File diff suppressed because one or more lines are too long
847
dist/chartist.js
vendored
847
dist/chartist.js
vendored
File diff suppressed because it is too large
Load Diff
2
dist/chartist.min.css
vendored
2
dist/chartist.min.css
vendored
File diff suppressed because one or more lines are too long
8
dist/chartist.min.js
vendored
8
dist/chartist.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/chartist.min.js.map
vendored
2
dist/chartist.min.js.map
vendored
File diff suppressed because one or more lines are too long
11
dist/scss/chartist.scss
vendored
11
dist/scss/chartist.scss
vendored
@ -107,7 +107,7 @@
|
||||
stroke: $color;
|
||||
}
|
||||
|
||||
.#{$ct-class-slice-pie}, .#{$ct-class-area} {
|
||||
.#{$ct-class-slice-pie}, .#{$ct-class-slice-donut-solid}, .#{$ct-class-area} {
|
||||
fill: $color;
|
||||
}
|
||||
}
|
||||
@ -123,6 +123,11 @@
|
||||
@include ct-flex();
|
||||
}
|
||||
|
||||
.#{$ct-class-chart-pie} .#{$ct-class-label},
|
||||
.#{$ct-class-chart-donut} .#{$ct-class-label} {
|
||||
dominant-baseline: central;
|
||||
}
|
||||
|
||||
.#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} {
|
||||
@include ct-align-justify(flex-end, flex-start);
|
||||
// Fallback for browsers that don't support foreignObjects
|
||||
@ -188,6 +193,10 @@
|
||||
@include ct-chart-grid($ct-grid-color, $ct-grid-width, $ct-grid-dasharray);
|
||||
}
|
||||
|
||||
.#{$ct-class-grid-background} {
|
||||
fill: $ct-grid-background-fill;
|
||||
}
|
||||
|
||||
.#{$ct-class-point} {
|
||||
@include ct-chart-point($ct-point-size, $ct-point-shape);
|
||||
}
|
||||
|
||||
3
dist/scss/settings/_chartist-settings.scss
vendored
3
dist/scss/settings/_chartist-settings.scss
vendored
@ -17,7 +17,9 @@ $ct-class-area: ct-area !default;
|
||||
$ct-class-bar: ct-bar !default;
|
||||
$ct-class-slice-pie: ct-slice-pie !default;
|
||||
$ct-class-slice-donut: ct-slice-donut !default;
|
||||
$ct-class-slice-donut-solid: ct-slice-donut-solid !default;
|
||||
$ct-class-grid: ct-grid !default;
|
||||
$ct-class-grid-background: ct-grid-background !default;
|
||||
$ct-class-vertical: ct-vertical !default;
|
||||
$ct-class-horizontal: ct-horizontal !default;
|
||||
$ct-class-start: ct-start !default;
|
||||
@ -37,6 +39,7 @@ $ct-text-line-height: 1;
|
||||
$ct-grid-color: rgba(0, 0, 0, 0.2) !default;
|
||||
$ct-grid-dasharray: 2px !default;
|
||||
$ct-grid-width: 1px !default;
|
||||
$ct-grid-background-fill: none !default;
|
||||
|
||||
// Line chart properties
|
||||
$ct-line-width: 4px !default;
|
||||
|
||||
11001
package-lock.json
generated
Normal file
11001
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
64
package.json
64
package.json
@ -2,7 +2,7 @@
|
||||
"name": "chartist",
|
||||
"title": "Chartist.js",
|
||||
"description": "Simple, responsive charts",
|
||||
"version": "0.9.7",
|
||||
"version": "0.11.4",
|
||||
"author": "Gion Kunz",
|
||||
"homepage": "https://gionkunz.github.io/chartist-js",
|
||||
"repository": {
|
||||
@ -23,11 +23,13 @@
|
||||
"LICENSE-WTFPL",
|
||||
"LICENSE-MIT",
|
||||
"package.json",
|
||||
"README.md"
|
||||
"README.md",
|
||||
"rescue-campaign.js"
|
||||
],
|
||||
"style": "dist/chartist.min.css",
|
||||
"main": "dist/chartist.js",
|
||||
"browser": "dist/chartist.js",
|
||||
"license": "MIT OR WTFPL",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "WTFPL",
|
||||
@ -40,41 +42,47 @@
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"assemble": "~0.4.42",
|
||||
"assemble-dox": "0.0.2",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-concurrent": "^1.0.0",
|
||||
"grunt-contrib-clean": "^0.6.0",
|
||||
"grunt-contrib-concat": "^0.5.0",
|
||||
"grunt-contrib-connect": "~0.9.0",
|
||||
"grunt-contrib-copy": "^0.7.0",
|
||||
"grunt-contrib-cssmin": "^0.12.1",
|
||||
"grunt-contrib-htmlmin": "~0.4.0",
|
||||
"grunt": "^1.0.1",
|
||||
"grunt-assemble": "^0.4.0",
|
||||
"grunt-concurrent": "^2.3.0",
|
||||
"grunt-contrib-clean": "^1.0.0",
|
||||
"grunt-contrib-concat": "^1.0.1",
|
||||
"grunt-contrib-connect": "^1.0.2",
|
||||
"grunt-contrib-copy": "^1.0.0",
|
||||
"grunt-contrib-cssmin": "^1.0.1",
|
||||
"grunt-contrib-htmlmin": "^1.4.0",
|
||||
"grunt-contrib-imagemin": "^1.0.0",
|
||||
"grunt-contrib-jasmine": "~0.8.2",
|
||||
"grunt-contrib-jshint": "~0.11.0",
|
||||
"grunt-contrib-uglify": "^0.7.0",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"grunt-critical": "0.1.1",
|
||||
"grunt-contrib-jasmine": "^1.0.3",
|
||||
"grunt-contrib-jshint": "^1.0.0",
|
||||
"grunt-contrib-uglify": "^1.0.1",
|
||||
"grunt-contrib-watch": "^1.0.0",
|
||||
"grunt-critical": "^0.2.1",
|
||||
"grunt-newer": "^1.1.0",
|
||||
"grunt-sass": "^0.18.0",
|
||||
"grunt-svgmin": "~2.0.0",
|
||||
"grunt-sass": "^1.1.0",
|
||||
"grunt-svgmin": "^3.2.0",
|
||||
"grunt-template": "^0.2.3",
|
||||
"grunt-umd": "~2.3.1",
|
||||
"grunt-usemin": "~3.0.0",
|
||||
"handlebars-helpers": "~0.5.8",
|
||||
"jasmine-jquery": "~2.0.6",
|
||||
"jshint-stylish": "~1.0.0",
|
||||
"load-grunt-config": "^0.16.0",
|
||||
"lodash": "~2.4.1",
|
||||
"seed-random": "~2.2.0",
|
||||
"grunt-umd": "^2.3.1",
|
||||
"grunt-usemin": "^3.1.1",
|
||||
"handlebars-helpers": "^0.6.1",
|
||||
"jasmine-jquery": "^2.1.1",
|
||||
"jquery": "^3.0.0",
|
||||
"jshint-stylish": "^2.2.0",
|
||||
"load-grunt-config": "^0.19.2",
|
||||
"lodash": "^4.13.1",
|
||||
"seed-random": "^2.2.0",
|
||||
"time-grunt": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
"node": ">=4.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test"
|
||||
"start": "./node_modules/.bin/grunt",
|
||||
"test": "./node_modules/.bin/grunt test",
|
||||
"dev": "./node_modules/.bin/grunt dev",
|
||||
"build": "./node_modules/.bin/grunt build",
|
||||
"preview": "./node_modules/.bin/grunt preview",
|
||||
"public": "./node_modules/.bin/grunt public"
|
||||
},
|
||||
"config": {
|
||||
"banner": "/* Chartist.js <%= pkg.version %>\n * Copyright © <%= year %> Gion Kunz\n * Free to use under either the WTFPL license or the MIT license.\n * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL\n * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-MIT\n */\n",
|
||||
|
||||
@ -17,4 +17,4 @@ var options = {
|
||||
// Create a new line chart object where as first parameter we pass in a selector
|
||||
// that is resolving to our chart container element. The Second parameter
|
||||
// is the actual data object. As a third parameter we pass in our custom options.
|
||||
new Chartist.Bar('.ct-chart', data, options);
|
||||
new Chartist.Line('.ct-chart', data, options);
|
||||
|
||||
@ -121,6 +121,16 @@ sections:
|
||||
<code>showArea</code> and even the smoothing function can be overriden per series! And guess what?
|
||||
You can even override those series settings in the responsive configuration! Check the example code
|
||||
for more details.
|
||||
- type: live-example
|
||||
data:
|
||||
title: Time Series with Moment.js
|
||||
level: 4
|
||||
id: example-timeseries-moment
|
||||
classes: ct-golden-section
|
||||
intro: >
|
||||
This example uses <a href="http://momentjs.com/">Moment.js</a> in the label interpolation function
|
||||
to format a date object. The fixed axis ensures that there is correct spacing between the data points,
|
||||
and the number of labels is determined by the divisor.
|
||||
- title: Bar chart examples
|
||||
level: 3
|
||||
items:
|
||||
@ -246,3 +256,19 @@ sections:
|
||||
intro: >
|
||||
Although it'd be also possible to achieve this animation with CSS, with some minor suboptimal
|
||||
things, here's an example of how to animate donut charts using Chartist.Svg.animate and SMIL.
|
||||
|
||||
- type: live-example
|
||||
data:
|
||||
title: Donut chart using fill rather than stroke
|
||||
level: 4
|
||||
id: example-donut-solid-chart
|
||||
classes: ct-golden-section ct-negative-labels
|
||||
intro: This pie chart uses donut and donutSolid to draw a donut chart.
|
||||
|
||||
- type: live-example
|
||||
data:
|
||||
title: Gauge chart using fill rather than stroke
|
||||
level: 4
|
||||
id: example-gauge-donut-solid-chart
|
||||
classes: ct-golden-section ct-negative-labels
|
||||
intro: This pie chart uses total, startAngle, donut and donutSolid to draw a gauge chart.
|
||||
|
||||
@ -430,8 +430,8 @@ sections:
|
||||
- type: text
|
||||
data:
|
||||
text: >
|
||||
Chartist generates predefined classes for series by default. Those class names are alpha
|
||||
numerated and always start with <code>ct-series-a</code>, where the letter a will be iterated
|
||||
Chartist generates predefined classes for series by default. Those class names are alphabetically
|
||||
ordered and always start with <code>ct-series-a</code>, where the letter a will be iterated
|
||||
with each series count (a, b, c, d etc.). To address a specific series in styling, you’ll
|
||||
need to create some styles for the corresponding series class name.
|
||||
|
||||
|
||||
@ -1,3 +1,19 @@
|
||||
affiliate-projects:
|
||||
- title: Material Dashboard Pro
|
||||
link: https://www.creative-tim.com/product/material-dashboard-pro?ref=chartist.io
|
||||
image:
|
||||
src: https://s3.amazonaws.com/creativetim_bucket/products/51/original/opt_mdp_thumbnail.jpg
|
||||
alt: Material Dashboard Pro
|
||||
- title: Material Dashboard Pro Angular
|
||||
link: https://www.creative-tim.com/product/material-dashboard-pro-angular2?ref=chartist.io
|
||||
image:
|
||||
src: https://s3.amazonaws.com/creativetim_bucket/products/55/original/opt_mdp_angular_thumbnail.jpg
|
||||
alt: Material Dashboard Pro Angular
|
||||
- title: Light Bootstrap Dashboard PRO React
|
||||
link: https://www.creative-tim.com/product/light-bootstrap-dashboard-pro-react?ref=chartist.io
|
||||
image:
|
||||
src: https://s3.amazonaws.com/creativetim_bucket/products/66/original/opt_lbdp_react_thumbnail.jpg
|
||||
alt: Light Bootstrap Dashboard PRO React
|
||||
gallery-examples:
|
||||
- id: example-gallery-one
|
||||
classes: ct-golden-section
|
||||
@ -240,6 +256,12 @@ sections:
|
||||
-
|
||||
- '<a href="https://github.com/hatemalimam/ChartistJSF" target="_blank">ChartistJSF</a>'
|
||||
- Java Server Faces (Prime Faces) Component
|
||||
-
|
||||
-'<a href="https://github.com/Yopadd/vue-chartist" target="_blank">vue-chartist</a>'
|
||||
- Vue plugin
|
||||
-
|
||||
-'<a href="https://github.com/eriklieben/aurelia-chartist" target="_blank">aurelia-chartist</a>'
|
||||
- Aurelia plugin
|
||||
- title: Chart CSS animation example
|
||||
level: 3
|
||||
items:
|
||||
@ -296,4 +318,4 @@ sections:
|
||||
side-notes:
|
||||
- type: text
|
||||
data:
|
||||
text: With the clear separation of concerns within Chartist.js you're able to style your charts with CSS in @media queries. However, sometimes it requires to also control the behaviour of your charts depending on the media. For this purpose Chartist.js provides you with a simple configuration override mechanism based on media queries.
|
||||
text: With the clear separation of concerns within Chartist.js, you're able to style your charts with CSS in @media queries. However, sometimes you also need to conditionally control the behavior of your charts. For this purpose, Chartist.js provides you with a simple configuration override mechanism based on media queries.
|
||||
|
||||
@ -153,32 +153,6 @@ sections:
|
||||
- '<strong>Link:</strong>'
|
||||
- '<a href="https://github.com/gionkunz/chartist-plugin-pointlabels" target="_blank">chartist-plugin-pointlabels</a>'
|
||||
|
||||
- type: sub-section
|
||||
data:
|
||||
title: Sketchy Plugin
|
||||
level: 4
|
||||
items:
|
||||
- type: text
|
||||
data:
|
||||
text: >
|
||||
The sketchy plugin makes your charts look like they have been drawn by hand. This plugin makes use
|
||||
of SVG filters and works on IE10+, Safari 7+ and Android 4.4+. Also note that SVG filters are not
|
||||
very performant and they will eat your users mobile battery quickly for sure.
|
||||
- type: live-example
|
||||
data:
|
||||
id: example-plugin-sketchy
|
||||
classes: ct-golden-section
|
||||
intro: >
|
||||
Create beautiful hand drawn charts using the Chartist Sketchy plugin.
|
||||
- type: table
|
||||
data:
|
||||
rows:
|
||||
-
|
||||
- '<strong>Author:</strong>'
|
||||
- Gion Kunz
|
||||
-
|
||||
- '<strong>Link:</strong>'
|
||||
- '<a href="https://github.com/gionkunz/chartist-plugin-sketchy" target="_blank">chartist-plugin-sketchy</a>'
|
||||
- type: sub-section
|
||||
data:
|
||||
title: Axis Title Plugin
|
||||
@ -278,6 +252,30 @@ sections:
|
||||
-
|
||||
- '<strong>Link:</strong>'
|
||||
- '<a href="https://github.com/hansmaad/chartist-plugin-zoom" target="_blank">chartist-plugin-zoom</a>'
|
||||
- type: sub-section
|
||||
data:
|
||||
title: Target Line Plugin
|
||||
level: 4
|
||||
items:
|
||||
- type: text
|
||||
data:
|
||||
text: >
|
||||
The target line plugin allows you to draw a target line on your chart.
|
||||
- type: live-example
|
||||
data:
|
||||
id: example-plugin-targetline
|
||||
classes: ct-golden-section
|
||||
intro: >
|
||||
Pass a value to the plugin to draw a target line on the chart.
|
||||
- type: table
|
||||
data:
|
||||
rows:
|
||||
-
|
||||
- '<strong>Author:</strong>'
|
||||
- Harry Twyford
|
||||
-
|
||||
- '<strong>Link:</strong>'
|
||||
- '<a href="https://github.com/htwyford/chartist-plugin-targetline" target="_blank">chartist-plugin-targetline</a>'
|
||||
- title: Develop a plugin
|
||||
level: 3
|
||||
items:
|
||||
|
||||
9
site/examples/example-donut-solid-chart.js
Normal file
9
site/examples/example-donut-solid-chart.js
Normal file
@ -0,0 +1,9 @@
|
||||
new Chartist.Pie('.ct-chart', {
|
||||
series: [20, 10, 30, 40]
|
||||
}, {
|
||||
donut: true,
|
||||
donutWidth: 60,
|
||||
donutSolid: true,
|
||||
startAngle: 270,
|
||||
showLabel: true
|
||||
});
|
||||
10
site/examples/example-gauge-donut-solid-chart.js
Normal file
10
site/examples/example-gauge-donut-solid-chart.js
Normal file
@ -0,0 +1,10 @@
|
||||
new Chartist.Pie('.ct-chart', {
|
||||
series: [20, 10, 30, 40]
|
||||
}, {
|
||||
donut: true,
|
||||
donutWidth: 60,
|
||||
donutSolid: true,
|
||||
startAngle: 270,
|
||||
total: 200,
|
||||
showLabel: true
|
||||
});
|
||||
@ -3,7 +3,8 @@ var chart = new Chartist.Line('.ct-chart', {
|
||||
series: [
|
||||
[5, 5, 10, 8, 7, 5, 4, null, null, null, 10, 10, 7, 8, 6, 9],
|
||||
[10, 15, null, 12, null, 10, 12, 15, null, null, 12, null, 14, null, null, null],
|
||||
[null, null, null, null, 3, 4, 1, 3, 4, 6, 7, 9, 5, null, null, null]
|
||||
[null, null, null, null, 3, 4, 1, 3, 4, 6, 7, 9, 5, null, null, null],
|
||||
[{x:3, y: 3},{x: 4, y: 3}, {x: 5, y: undefined}, {x: 6, y: 4}, {x: 7, y: null}, {x: 8, y: 4}, {x: 9, y: 4}]
|
||||
]
|
||||
}, {
|
||||
fullWidth: true,
|
||||
|
||||
@ -3,7 +3,8 @@ var chart = new Chartist.Line('.ct-chart', {
|
||||
series: [
|
||||
[5, 5, 10, 8, 7, 5, 4, null, null, null, 10, 10, 7, 8, 6, 9],
|
||||
[10, 15, null, 12, null, 10, 12, 15, null, null, 12, null, 14, null, null, null],
|
||||
[null, null, null, null, 3, 4, 1, 3, 4, 6, 7, 9, 5, null, null, null]
|
||||
[null, null, null, null, 3, 4, 1, 3, 4, 6, 7, 9, 5, null, null, null],
|
||||
[{x:3, y: 3},{x: 4, y: 3}, {x: 5, y: undefined}, {x: 6, y: 4}, {x: 7, y: null}, {x: 8, y: 4}, {x: 9, y: 4}]
|
||||
]
|
||||
}, {
|
||||
fullWidth: true,
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
new Chartist.Bar('.ct-chart', {
|
||||
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
|
||||
series: [
|
||||
[800000, 1200000, 1400000, 1300000],
|
||||
[200000, 400000, 500000, 300000],
|
||||
[100000, 200000, 400000, 600000]
|
||||
]
|
||||
}, {
|
||||
plugins: [
|
||||
Chartist.plugins.ctSketchy({
|
||||
overrides: {
|
||||
grid: {
|
||||
baseFrequency: 0.2,
|
||||
scale: 5,
|
||||
numOctaves: 1
|
||||
},
|
||||
bar: {
|
||||
baseFrequency: 0.02,
|
||||
scale: 10
|
||||
},
|
||||
label: false
|
||||
}
|
||||
})
|
||||
],
|
||||
stackBars: true,
|
||||
axisY: {
|
||||
labelInterpolationFnc: function(value) {
|
||||
return (value / 1000) + 'k';
|
||||
}
|
||||
}
|
||||
}).on('draw', function(data) {
|
||||
if(data.type === 'bar') {
|
||||
data.element.attr({
|
||||
style: 'stroke-width: 30px'
|
||||
});
|
||||
}
|
||||
});
|
||||
12
site/examples/example-plugin-targetline.js
Normal file
12
site/examples/example-plugin-targetline.js
Normal file
@ -0,0 +1,12 @@
|
||||
new Chartist.Line('.ct-chart', {
|
||||
labels: ['M', 'T', 'W', 'T', 'F'],
|
||||
series: [
|
||||
[5, 11, 2, 5, 7]
|
||||
]
|
||||
}, {
|
||||
plugins: [
|
||||
Chartist.plugins.ctTargetLine({
|
||||
value: 6
|
||||
})
|
||||
]
|
||||
});
|
||||
37
site/examples/example-timeseries-moment.js
Normal file
37
site/examples/example-timeseries-moment.js
Normal file
@ -0,0 +1,37 @@
|
||||
// Requires Moment.js
|
||||
|
||||
var chart = new Chartist.Line('.ct-chart', {
|
||||
series: [
|
||||
{
|
||||
name: 'series-1',
|
||||
data: [
|
||||
{x: new Date(143134652600), y: 53},
|
||||
{x: new Date(143234652600), y: 40},
|
||||
{x: new Date(143340052600), y: 45},
|
||||
{x: new Date(143366652600), y: 40},
|
||||
{x: new Date(143410652600), y: 20},
|
||||
{x: new Date(143508652600), y: 32},
|
||||
{x: new Date(143569652600), y: 18},
|
||||
{x: new Date(143579652600), y: 11}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'series-2',
|
||||
data: [
|
||||
{x: new Date(143134652600), y: 53},
|
||||
{x: new Date(143234652600), y: 35},
|
||||
{x: new Date(143334652600), y: 30},
|
||||
{x: new Date(143384652600), y: 30},
|
||||
{x: new Date(143568652600), y: 10}
|
||||
]
|
||||
}
|
||||
]
|
||||
}, {
|
||||
axisX: {
|
||||
type: Chartist.FixedScaleAxis,
|
||||
divisor: 5,
|
||||
labelInterpolationFnc: function(value) {
|
||||
return moment(value).format('MMM D');
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -38,6 +38,7 @@
|
||||
|
||||
<!-- build:js({site,src}) scripts/all.js -->
|
||||
<!-- Vendor scripts-->
|
||||
<script src="bower_components/moment/moment.js"></script>
|
||||
<script src="bower_components/modernizr/modernizr.js"></script>
|
||||
<script src="bower_components/jquery/dist/jquery.js"></script>
|
||||
<script src="bower_components/snap.svg/dist/snap.svg-min.js"></script>
|
||||
@ -70,13 +71,13 @@
|
||||
|
||||
<!-- Chartist plugins -->
|
||||
<script src="bower_components/chartist-plugin-pointlabels/dist/chartist-plugin-pointlabels.js"></script>
|
||||
<script src="bower_components/chartist-plugin-sketchy/dist/chartist-plugin-sketchy.js"></script>
|
||||
<script src="bower_components/chartist-plugin-accessibility/dist/chartist-plugin-accessibility.js"></script>
|
||||
<script src="bower_components/chartist-plugin-tooltip/dist/chartist-plugin-tooltip.js"></script>
|
||||
<script src="bower_components/chartist-plugin-axistitle/dist/chartist-plugin-axistitle.js"></script>
|
||||
<script src="bower_components/chartist-plugin-threshold/dist/chartist-plugin-threshold.js"></script>
|
||||
<script src="bower_components/chartist-plugin-fill-donut/dist/chartist-plugin-fill-donut.js"></script>
|
||||
<script src="bower_components/chartist-plugin-zoom/dist/chartist-plugin-zoom.js"></script>
|
||||
<script src="bower_components/chartist-plugin-targetline/chartist-plugin-targetline.js"></script>
|
||||
|
||||
<!-- Chartist site scripts -->
|
||||
<script src="scripts/main.js"></script>
|
||||
|
||||
5
site/partials/affiliate-project.hbs
Normal file
5
site/partials/affiliate-project.hbs
Normal file
@ -0,0 +1,5 @@
|
||||
<a href="{{link}}" target="_blank" class="affiliate-project">
|
||||
<div class="affiliate-project__title">{{title}}</div>
|
||||
<img src="{{image.src}}" alt="{{image.alt}}" class="affiliate-project__image">
|
||||
<div class="button">Get this Template</div>
|
||||
</a>
|
||||
31
site/styles/_affiliate-project.scss
Normal file
31
site/styles/_affiliate-project.scss
Normal file
@ -0,0 +1,31 @@
|
||||
.affiliate-projects {
|
||||
display: flex;
|
||||
margin: 0 -10px;
|
||||
}
|
||||
|
||||
.affiliate-project {
|
||||
display: block;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.affiliate-project__title {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.affiliate-project__image {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 640px) {
|
||||
.affiliate-projects {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.affiliate-project {
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
@ -108,3 +108,37 @@
|
||||
stroke: red;
|
||||
}
|
||||
}
|
||||
#example-plugin-tooltip {
|
||||
.chart {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.chartist-tooltip {
|
||||
position: absolute;
|
||||
display: block;
|
||||
min-width: 5em;
|
||||
padding: .5em;
|
||||
background: #F4C63D;
|
||||
color: #453D3F;
|
||||
font-family: Oxygen,Helvetica,Arial,sans-serif;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
-webkit-transition: opacity .2s linear;
|
||||
-moz-transition: opacity .2s linear;
|
||||
-o-transition: opacity .2s linear;
|
||||
transition: opacity .2s linear; }
|
||||
.chartist-tooltip:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-left: -15px;
|
||||
border: 15px solid transparent;
|
||||
border-top-color: #F4C63D; }
|
||||
.chartist-tooltip.tooltip-show {
|
||||
opacity: 1; }
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
line-height: 0.5;
|
||||
margin-top: 2rem;
|
||||
|
||||
@include text-shadow(1px 1px mix(black, $color-yellow, 15%), 2px 2px mix(black, $color-yellow, 15%), 3px 3px mix(black, $color-yellow, 15%));
|
||||
text-shadow: 1px 1px mix(black, $color-yellow, 15%), 2px 2px mix(black, $color-yellow, 15%), 3px 3px mix(black, $color-yellow, 15%);
|
||||
|
||||
@media #{$medium-up} {
|
||||
font-size: rem-calc(nth($modular-scale, 10));
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
@import "api-doc";
|
||||
@import "live-example";
|
||||
@import "example-charts";
|
||||
@import "affiliate-project";
|
||||
|
||||
.button {
|
||||
text-transform: uppercase;
|
||||
|
||||
@ -10,6 +10,14 @@ a community that was disappointed about the abilities provided by other charting
|
||||
of other great charting libraries but after using them there were always tweaks you would have wished for that were not
|
||||
included.</p>
|
||||
|
||||
<h3>Get awesome Dashboard Templates by Creative Tim</h3>
|
||||
<p>Are you planning to use Chartist to create a nice Dashboard or Admin UI? Don't loose any time and kickstart your development using the awesome templates by Creative Tim. They include Chartist and come with awesome chart styles!</p>
|
||||
<div class="affiliate-projects">
|
||||
{{#each page.affiliate-projects}}
|
||||
{{> affiliate-project }}
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
<h3>Highly customizable responsive charts</h3>
|
||||
<ul class="example-gallery">
|
||||
{{#each page.gallery-examples}}
|
||||
|
||||
@ -20,12 +20,15 @@
|
||||
* @module Chartist.AutoScaleAxis
|
||||
*/
|
||||
/* global Chartist */
|
||||
(function (window, document, Chartist) {
|
||||
(function (globalRoot, Chartist) {
|
||||
'use strict';
|
||||
|
||||
var window = globalRoot.window;
|
||||
var document = globalRoot.document;
|
||||
|
||||
function AutoScaleAxis(axisUnit, data, chartRect, options) {
|
||||
// Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options
|
||||
var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos);
|
||||
var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos);
|
||||
this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.onlyInteger);
|
||||
this.range = {
|
||||
min: this.bounds.min,
|
||||
@ -48,4 +51,4 @@
|
||||
projectValue: projectValue
|
||||
});
|
||||
|
||||
}(window, document, Chartist));
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
/* global Chartist */
|
||||
(function (window, document, Chartist) {
|
||||
(function (globalRoot, Chartist) {
|
||||
'use strict';
|
||||
|
||||
var window = globalRoot.window;
|
||||
var document = globalRoot.document;
|
||||
|
||||
var axisUnits = {
|
||||
x: {
|
||||
pos: 'x',
|
||||
@ -97,7 +100,7 @@
|
||||
Chartist.createLabel(projectedValue, labelLength, index, labelValues, this, axisOptions.offset, labelOffset, labelGroup, [
|
||||
chartOptions.classNames.label,
|
||||
chartOptions.classNames[this.units.dir],
|
||||
chartOptions.classNames[axisOptions.position]
|
||||
(axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames['end'])
|
||||
], useForeignObject, eventEmitter);
|
||||
}
|
||||
}.bind(this));
|
||||
@ -113,4 +116,4 @@
|
||||
|
||||
Chartist.Axis.units = axisUnits;
|
||||
|
||||
}(window, document, Chartist));
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -18,11 +18,14 @@
|
||||
* @module Chartist.FixedScaleAxis
|
||||
*/
|
||||
/* global Chartist */
|
||||
(function (window, document, Chartist) {
|
||||
(function (globalRoot, Chartist) {
|
||||
'use strict';
|
||||
|
||||
var window = globalRoot.window;
|
||||
var document = globalRoot.document;
|
||||
|
||||
function FixedScaleAxis(axisUnit, data, chartRect, options) {
|
||||
var highLow = options.highLow || Chartist.getHighLow(data.normalized, options, axisUnit.pos);
|
||||
var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos);
|
||||
this.divisor = options.divisor || 1;
|
||||
this.ticks = options.ticks || Chartist.times(this.divisor).map(function(value, index) {
|
||||
return highLow.low + (highLow.high - highLow.low) / this.divisor * index;
|
||||
@ -53,4 +56,4 @@
|
||||
projectValue: projectValue
|
||||
});
|
||||
|
||||
}(window, document, Chartist));
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -14,9 +14,12 @@
|
||||
* @module Chartist.StepAxis
|
||||
*/
|
||||
/* global Chartist */
|
||||
(function (window, document, Chartist) {
|
||||
(function (globalRoot, Chartist) {
|
||||
'use strict';
|
||||
|
||||
var window = globalRoot.window;
|
||||
var document = globalRoot.document;
|
||||
|
||||
function StepAxis(axisUnit, data, chartRect, options) {
|
||||
Chartist.StepAxis.super.constructor.call(this,
|
||||
axisUnit,
|
||||
@ -24,7 +27,8 @@
|
||||
options.ticks,
|
||||
options);
|
||||
|
||||
this.stepLength = this.axisLength / (options.ticks.length - (options.stretch ? 1 : 0));
|
||||
var calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0));
|
||||
this.stepLength = this.axisLength / calc;
|
||||
}
|
||||
|
||||
function projectValue(value, index) {
|
||||
@ -36,4 +40,4 @@
|
||||
projectValue: projectValue
|
||||
});
|
||||
|
||||
}(window, document, Chartist));
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -4,9 +4,11 @@
|
||||
* @module Chartist.Base
|
||||
*/
|
||||
/* global Chartist */
|
||||
(function(window, document, Chartist) {
|
||||
(function(globalRoot, Chartist) {
|
||||
'use strict';
|
||||
|
||||
var window = globalRoot.window;
|
||||
|
||||
// TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance.
|
||||
// This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not
|
||||
// work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage.
|
||||
@ -23,7 +25,9 @@
|
||||
*/
|
||||
function update(data, options, override) {
|
||||
if(data) {
|
||||
this.data = data;
|
||||
this.data = data || {};
|
||||
this.data.labels = this.data.labels || [];
|
||||
this.data.series = this.data.series || [];
|
||||
// Event for data transformation that allows to manipulate the data before it gets rendered in the charts
|
||||
this.eventEmitter.emit('data', {
|
||||
type: 'update',
|
||||
@ -143,7 +147,9 @@
|
||||
*/
|
||||
function Base(query, data, defaultOptions, options, responsiveOptions) {
|
||||
this.container = Chartist.querySelector(query);
|
||||
this.data = data;
|
||||
this.data = data || {};
|
||||
this.data.labels = this.data.labels || [];
|
||||
this.data.series = this.data.series || [];
|
||||
this.defaultOptions = defaultOptions;
|
||||
this.options = options;
|
||||
this.responsiveOptions = responsiveOptions;
|
||||
@ -186,4 +192,4 @@
|
||||
supportsForeignObject: false
|
||||
});
|
||||
|
||||
}(window, document, Chartist));
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -4,9 +4,12 @@
|
||||
* @module Chartist.Bar
|
||||
*/
|
||||
/* global Chartist */
|
||||
(function(window, document, Chartist){
|
||||
(function(globalRoot, Chartist){
|
||||
'use strict';
|
||||
|
||||
var window = globalRoot.window;
|
||||
var document = globalRoot.document;
|
||||
|
||||
/**
|
||||
* Default options in bar charts. Expand the code view to see a detailed list of options with comments.
|
||||
*
|
||||
@ -65,6 +68,8 @@
|
||||
high: undefined,
|
||||
// Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value
|
||||
low: undefined,
|
||||
// Unless low/high are explicitly set, bar chart will be centered at zero by default. Set referenceValue to null to auto scale.
|
||||
referenceValue: 0,
|
||||
// Padding of the chart drawing area to the container element and labels as a number or padding object {top: 5, right: 5, bottom: 5, left: 5}
|
||||
chartPadding: {
|
||||
top: 15,
|
||||
@ -85,6 +90,8 @@
|
||||
distributeSeries: false,
|
||||
// If true the whole data is reversed including labels, the series order as well as the whole series data arrays.
|
||||
reverseData: false,
|
||||
// If the bar chart should add a background fill to the .ct-grids group.
|
||||
showGridBackground: false,
|
||||
// Override the class names that get used to generate the SVG structure of the chart
|
||||
classNames: {
|
||||
chart: 'ct-chart-bar',
|
||||
@ -95,6 +102,7 @@
|
||||
bar: 'ct-bar',
|
||||
grid: 'ct-grid',
|
||||
gridGroup: 'ct-grids',
|
||||
gridBackground: 'ct-grid-background',
|
||||
vertical: 'ct-vertical',
|
||||
horizontal: 'ct-horizontal',
|
||||
start: 'ct-start',
|
||||
@ -107,16 +115,18 @@
|
||||
*
|
||||
*/
|
||||
function createChart(options) {
|
||||
this.data = Chartist.normalizeData(this.data);
|
||||
var data = {
|
||||
raw: this.data,
|
||||
normalized: options.distributeSeries ? Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y').map(function(value) {
|
||||
return [value];
|
||||
}) : Chartist.getDataArray(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y')
|
||||
};
|
||||
|
||||
var data;
|
||||
var highLow;
|
||||
|
||||
if(options.distributeSeries) {
|
||||
data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y');
|
||||
data.normalized.series = data.normalized.series.map(function(value) {
|
||||
return [value];
|
||||
});
|
||||
} else {
|
||||
data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y');
|
||||
}
|
||||
|
||||
// Create new svg element
|
||||
this.svg = Chartist.createSvg(
|
||||
this.container,
|
||||
@ -130,9 +140,10 @@
|
||||
var seriesGroup = this.svg.elem('g');
|
||||
var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup);
|
||||
|
||||
if(options.stackBars && data.normalized.length !== 0) {
|
||||
if(options.stackBars && data.normalized.series.length !== 0) {
|
||||
|
||||
// If stacked bars we need to calculate the high low from stacked values from each series
|
||||
var serialSums = Chartist.serialMap(data.normalized, function serialSums() {
|
||||
var serialSums = Chartist.serialMap(data.normalized.series, function serialSums() {
|
||||
return Array.prototype.slice.call(arguments).map(function(value) {
|
||||
return value;
|
||||
}).reduce(function(prev, curr) {
|
||||
@ -143,14 +154,13 @@
|
||||
}, {x: 0, y: 0});
|
||||
});
|
||||
|
||||
highLow = Chartist.getHighLow([serialSums], Chartist.extend({}, options, {
|
||||
referenceValue: 0
|
||||
}), options.horizontalBars ? 'x' : 'y');
|
||||
highLow = Chartist.getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y');
|
||||
|
||||
} else {
|
||||
highLow = Chartist.getHighLow(data.normalized, Chartist.extend({}, options, {
|
||||
referenceValue: 0
|
||||
}), options.horizontalBars ? 'x' : 'y');
|
||||
|
||||
highLow = Chartist.getHighLow(data.normalized.series, options, options.horizontalBars ? 'x' : 'y');
|
||||
}
|
||||
|
||||
// Overrides of high / low from settings
|
||||
highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high);
|
||||
highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low);
|
||||
@ -167,51 +177,51 @@
|
||||
if(options.distributeSeries && options.stackBars) {
|
||||
// If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore should
|
||||
// use only the first label for the step axis
|
||||
labelAxisTicks = data.raw.labels.slice(0, 1);
|
||||
labelAxisTicks = data.normalized.labels.slice(0, 1);
|
||||
} else {
|
||||
// If distributed series are enabled but stacked bars aren't, we should use the series labels
|
||||
// If we are drawing a regular bar chart with two dimensional series data, we just use the labels array
|
||||
// as the bars are normalized
|
||||
labelAxisTicks = data.raw.labels;
|
||||
labelAxisTicks = data.normalized.labels;
|
||||
}
|
||||
|
||||
// Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary.
|
||||
if(options.horizontalBars) {
|
||||
if(options.axisX.type === undefined) {
|
||||
valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, {
|
||||
valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, {
|
||||
highLow: highLow,
|
||||
referenceValue: 0
|
||||
}));
|
||||
} else {
|
||||
valueAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, {
|
||||
valueAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, {
|
||||
highLow: highLow,
|
||||
referenceValue: 0
|
||||
}));
|
||||
}
|
||||
|
||||
if(options.axisY.type === undefined) {
|
||||
labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data, chartRect, {
|
||||
labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, {
|
||||
ticks: labelAxisTicks
|
||||
});
|
||||
} else {
|
||||
labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);
|
||||
labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY);
|
||||
}
|
||||
} else {
|
||||
if(options.axisX.type === undefined) {
|
||||
labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, {
|
||||
labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, {
|
||||
ticks: labelAxisTicks
|
||||
});
|
||||
} else {
|
||||
labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);
|
||||
labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX);
|
||||
}
|
||||
|
||||
if(options.axisY.type === undefined) {
|
||||
valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {
|
||||
valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, {
|
||||
highLow: highLow,
|
||||
referenceValue: 0
|
||||
}));
|
||||
} else {
|
||||
valueAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {
|
||||
valueAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, {
|
||||
highLow: highLow,
|
||||
referenceValue: 0
|
||||
}));
|
||||
@ -226,6 +236,10 @@
|
||||
labelAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);
|
||||
valueAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);
|
||||
|
||||
if (options.showGridBackground) {
|
||||
Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter);
|
||||
}
|
||||
|
||||
// Draw the series
|
||||
data.raw.series.forEach(function(series, seriesIndex) {
|
||||
// Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc.
|
||||
@ -239,14 +253,14 @@
|
||||
if(options.distributeSeries && !options.stackBars) {
|
||||
// If distributed series are enabled but stacked bars aren't, we need to use the length of the normaizedData array
|
||||
// which is the series count and divide by 2
|
||||
periodHalfLength = labelAxis.axisLength / data.normalized.length / 2;
|
||||
periodHalfLength = labelAxis.axisLength / data.normalized.series.length / 2;
|
||||
} else if(options.distributeSeries && options.stackBars) {
|
||||
// If distributed series and stacked bars are enabled we'll only get one bar so we should just divide the axis
|
||||
// length by 2
|
||||
periodHalfLength = labelAxis.axisLength / 2;
|
||||
} else {
|
||||
// On regular bar charts we should just use the series length
|
||||
periodHalfLength = labelAxis.axisLength / data.normalized[seriesIndex].length / 2;
|
||||
periodHalfLength = labelAxis.axisLength / data.normalized.series[seriesIndex].length / 2;
|
||||
}
|
||||
|
||||
// Adding the series group to the series element
|
||||
@ -264,7 +278,7 @@
|
||||
(series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))
|
||||
].join(' '));
|
||||
|
||||
data.normalized[seriesIndex].forEach(function(value, valueIndex) {
|
||||
data.normalized.series[seriesIndex].forEach(function(value, valueIndex) {
|
||||
var projected,
|
||||
bar,
|
||||
previousStack,
|
||||
@ -287,13 +301,13 @@
|
||||
// We need to transform coordinates differently based on the chart layout
|
||||
if(options.horizontalBars) {
|
||||
projected = {
|
||||
x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized[seriesIndex]),
|
||||
y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized[seriesIndex])
|
||||
x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized.series[seriesIndex]),
|
||||
y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized.series[seriesIndex])
|
||||
};
|
||||
} else {
|
||||
projected = {
|
||||
x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized[seriesIndex]),
|
||||
y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized[seriesIndex])
|
||||
x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]),
|
||||
y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized.series[seriesIndex])
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,17 +357,19 @@
|
||||
positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1);
|
||||
positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1);
|
||||
|
||||
var metaData = Chartist.getMetaData(series, valueIndex);
|
||||
|
||||
// Create bar element
|
||||
bar = seriesElement.elem('line', positions, options.classNames.bar).attr({
|
||||
'ct:value': [value.x, value.y].filter(Chartist.isNum).join(','),
|
||||
'ct:meta': Chartist.getMetaData(series, valueIndex)
|
||||
'ct:value': [value.x, value.y].filter(Chartist.isNumeric).join(','),
|
||||
'ct:meta': Chartist.serialize(metaData)
|
||||
});
|
||||
|
||||
this.eventEmitter.emit('draw', Chartist.extend({
|
||||
type: 'bar',
|
||||
value: value,
|
||||
index: valueIndex,
|
||||
meta: Chartist.getMetaData(series, valueIndex),
|
||||
meta: metaData,
|
||||
series: series,
|
||||
seriesIndex: seriesIndex,
|
||||
axisX: axisX,
|
||||
@ -427,4 +443,4 @@
|
||||
createChart: createChart
|
||||
});
|
||||
|
||||
}(window, document, Chartist));
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -6,9 +6,12 @@
|
||||
* @module Chartist.Line
|
||||
*/
|
||||
/* global Chartist */
|
||||
(function(window, document, Chartist){
|
||||
(function(globalRoot, Chartist){
|
||||
'use strict';
|
||||
|
||||
var window = globalRoot.window;
|
||||
var document = globalRoot.document;
|
||||
|
||||
/**
|
||||
* Default options in line charts. Expand the code view to see a detailed list of options with comments.
|
||||
*
|
||||
@ -73,6 +76,8 @@
|
||||
areaBase: 0,
|
||||
// Specify if the lines should be smoothed. This value can be true or false where true will result in smoothing using the default smoothing interpolation function Chartist.Interpolation.cardinal and false results in Chartist.Interpolation.none. You can also choose other smoothing / interpolation functions available in the Chartist.Interpolation module, or write your own interpolation function. Check the examples for a brief description.
|
||||
lineSmooth: true,
|
||||
// If the line chart should add a background fill to the .ct-grids group.
|
||||
showGridBackground: false,
|
||||
// Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value
|
||||
low: undefined,
|
||||
// Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value
|
||||
@ -99,6 +104,7 @@
|
||||
area: 'ct-area',
|
||||
grid: 'ct-grid',
|
||||
gridGroup: 'ct-grids',
|
||||
gridBackground: 'ct-grid-background',
|
||||
vertical: 'ct-vertical',
|
||||
horizontal: 'ct-horizontal',
|
||||
start: 'ct-start',
|
||||
@ -111,11 +117,7 @@
|
||||
*
|
||||
*/
|
||||
function createChart(options) {
|
||||
this.data = Chartist.normalizeData(this.data);
|
||||
var data = {
|
||||
raw: this.data,
|
||||
normalized: Chartist.getDataArray(this.data, options.reverseData, true)
|
||||
};
|
||||
var data = Chartist.normalizeData(this.data, options.reverseData, true);
|
||||
|
||||
// Create new svg object
|
||||
this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);
|
||||
@ -128,26 +130,30 @@
|
||||
var axisX, axisY;
|
||||
|
||||
if(options.axisX.type === undefined) {
|
||||
axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data, chartRect, Chartist.extend({}, options.axisX, {
|
||||
ticks: data.raw.labels,
|
||||
axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, {
|
||||
ticks: data.normalized.labels,
|
||||
stretch: options.fullWidth
|
||||
}));
|
||||
} else {
|
||||
axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data, chartRect, options.axisX);
|
||||
axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX);
|
||||
}
|
||||
|
||||
if(options.axisY.type === undefined) {
|
||||
axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data, chartRect, Chartist.extend({}, options.axisY, {
|
||||
high: Chartist.isNum(options.high) ? options.high : options.axisY.high,
|
||||
low: Chartist.isNum(options.low) ? options.low : options.axisY.low
|
||||
axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, {
|
||||
high: Chartist.isNumeric(options.high) ? options.high : options.axisY.high,
|
||||
low: Chartist.isNumeric(options.low) ? options.low : options.axisY.low
|
||||
}));
|
||||
} else {
|
||||
axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data, chartRect, options.axisY);
|
||||
axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY);
|
||||
}
|
||||
|
||||
axisX.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);
|
||||
axisY.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);
|
||||
|
||||
if (options.showGridBackground) {
|
||||
Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter);
|
||||
}
|
||||
|
||||
// Draw the series
|
||||
data.raw.series.forEach(function(series, seriesIndex) {
|
||||
var seriesElement = seriesGroup.elem('g');
|
||||
@ -167,10 +173,10 @@
|
||||
var pathCoordinates = [],
|
||||
pathData = [];
|
||||
|
||||
data.normalized[seriesIndex].forEach(function(value, valueIndex) {
|
||||
data.normalized.series[seriesIndex].forEach(function(value, valueIndex) {
|
||||
var p = {
|
||||
x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized[seriesIndex]),
|
||||
y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized[seriesIndex])
|
||||
x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized.series[seriesIndex]),
|
||||
y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized.series[seriesIndex])
|
||||
};
|
||||
pathCoordinates.push(p.x, p.y);
|
||||
pathData.push({
|
||||
@ -189,7 +195,7 @@
|
||||
};
|
||||
|
||||
var smoothing = typeof seriesOptions.lineSmooth === 'function' ?
|
||||
seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.cardinal() : Chartist.Interpolation.none());
|
||||
seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.monotoneCubic() : Chartist.Interpolation.none());
|
||||
// Interpolating path where pathData will be used to annotate each path element so we can trace back the original
|
||||
// index, value and meta data
|
||||
var path = smoothing(pathCoordinates, pathData);
|
||||
@ -206,8 +212,8 @@
|
||||
x2: pathElement.x + 0.01,
|
||||
y2: pathElement.y
|
||||
}, options.classNames.point).attr({
|
||||
'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNum).join(','),
|
||||
'ct:meta': pathElement.data.meta
|
||||
'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNumeric).join(','),
|
||||
'ct:meta': Chartist.serialize(pathElement.data.meta)
|
||||
});
|
||||
|
||||
this.eventEmitter.emit('draw', {
|
||||
@ -234,12 +240,13 @@
|
||||
|
||||
this.eventEmitter.emit('draw', {
|
||||
type: 'line',
|
||||
values: data.normalized[seriesIndex],
|
||||
values: data.normalized.series[seriesIndex],
|
||||
path: path.clone(),
|
||||
chartRect: chartRect,
|
||||
index: seriesIndex,
|
||||
series: series,
|
||||
seriesIndex: seriesIndex,
|
||||
seriesMeta: series.meta,
|
||||
axisX: axisX,
|
||||
axisY: axisY,
|
||||
group: seriesElement,
|
||||
@ -287,7 +294,7 @@
|
||||
// Emit an event for each area that was drawn
|
||||
this.eventEmitter.emit('draw', {
|
||||
type: 'area',
|
||||
values: data.normalized[seriesIndex],
|
||||
values: data.normalized.series[seriesIndex],
|
||||
path: areaPath.clone(),
|
||||
series: series,
|
||||
seriesIndex: seriesIndex,
|
||||
@ -408,4 +415,4 @@
|
||||
createChart: createChart
|
||||
});
|
||||
|
||||
}(window, document, Chartist));
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -4,9 +4,12 @@
|
||||
* @module Chartist.Pie
|
||||
*/
|
||||
/* global Chartist */
|
||||
(function(window, document, Chartist) {
|
||||
(function(globalRoot, Chartist) {
|
||||
'use strict';
|
||||
|
||||
var window = globalRoot.window;
|
||||
var document = globalRoot.document;
|
||||
|
||||
/**
|
||||
* Default options in line charts. Expand the code view to see a detailed list of options with comments.
|
||||
*
|
||||
@ -26,6 +29,7 @@
|
||||
series: 'ct-series',
|
||||
slicePie: 'ct-slice-pie',
|
||||
sliceDonut: 'ct-slice-donut',
|
||||
sliceDonutSolid: 'ct-slice-donut-solid',
|
||||
label: 'ct-label'
|
||||
},
|
||||
// The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise.
|
||||
@ -34,6 +38,8 @@
|
||||
total: undefined,
|
||||
// If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices.
|
||||
donut: false,
|
||||
// If specified the donut segments will be drawn as shapes instead of strokes.
|
||||
donutSolid: false,
|
||||
// Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future.
|
||||
// This option can be set as number or string to specify a relative width (i.e. 100 or '30%').
|
||||
donutWidth: 60,
|
||||
@ -81,15 +87,14 @@
|
||||
* @param options
|
||||
*/
|
||||
function createChart(options) {
|
||||
this.data = Chartist.normalizeData(this.data);
|
||||
var data = Chartist.normalizeData(this.data);
|
||||
var seriesGroups = [],
|
||||
labelsGroup,
|
||||
chartRect,
|
||||
radius,
|
||||
labelRadius,
|
||||
totalDataSum,
|
||||
startAngle = options.startAngle,
|
||||
dataArray = Chartist.getDataArray(this.data, options.reverseData);
|
||||
startAngle = options.startAngle;
|
||||
|
||||
// Create SVG.js draw
|
||||
this.svg = Chartist.createSvg(this.container, options.width, options.height,options.donut ? options.classNames.chartDonut : options.classNames.chartPie);
|
||||
@ -98,7 +103,7 @@
|
||||
// Get biggest circle radius possible within chartRect
|
||||
radius = Math.min(chartRect.width() / 2, chartRect.height() / 2);
|
||||
// Calculate total of all series to get reference value or use total reference from optional options
|
||||
totalDataSum = options.total || dataArray.reduce(function(previousValue, currentValue) {
|
||||
totalDataSum = options.total || data.normalized.series.reduce(function(previousValue, currentValue) {
|
||||
return previousValue + currentValue;
|
||||
}, 0);
|
||||
|
||||
@ -110,15 +115,17 @@
|
||||
// If this is a donut chart we need to adjust our radius to enable strokes to be drawn inside
|
||||
// Unfortunately this is not possible with the current SVG Spec
|
||||
// See this proposal for more details: http://lists.w3.org/Archives/Public/www-svg/2003Oct/0000.html
|
||||
radius -= options.donut ? donutWidth.value / 2 : 0;
|
||||
radius -= options.donut && !options.donutSolid ? donutWidth.value / 2 : 0;
|
||||
|
||||
// If labelPosition is set to `outside` or a donut chart is drawn then the label position is at the radius,
|
||||
// if regular pie chart it's half of the radius
|
||||
if(options.labelPosition === 'outside' || options.donut) {
|
||||
if(options.labelPosition === 'outside' || options.donut && !options.donutSolid) {
|
||||
labelRadius = radius;
|
||||
} else if(options.labelPosition === 'center') {
|
||||
// If labelPosition is center we start with 0 and will later wait for the labelOffset
|
||||
labelRadius = 0;
|
||||
} else if(options.donutSolid) {
|
||||
labelRadius = radius - donutWidth.value / 2;
|
||||
} else {
|
||||
// Default option is 'inside' where we use half the radius so the label will be placed in the center of the pie
|
||||
// slice
|
||||
@ -134,39 +141,41 @@
|
||||
};
|
||||
|
||||
// Check if there is only one non-zero value in the series array.
|
||||
var hasSingleValInSeries = this.data.series.filter(function(val) {
|
||||
var hasSingleValInSeries = data.raw.series.filter(function(val) {
|
||||
return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;
|
||||
}).length === 1;
|
||||
|
||||
// Creating the series groups
|
||||
data.raw.series.forEach(function(series, index) {
|
||||
seriesGroups[index] = this.svg.elem('g', null, null);
|
||||
}.bind(this));
|
||||
//if we need to show labels we create the label group now
|
||||
if(options.showLabel) {
|
||||
labelsGroup = this.svg.elem('g', null, null, true);
|
||||
labelsGroup = this.svg.elem('g', null, null);
|
||||
}
|
||||
|
||||
// Draw the series
|
||||
// initialize series groups
|
||||
for (var i = 0; i < this.data.series.length; i++) {
|
||||
data.raw.series.forEach(function(series, index) {
|
||||
// If current value is zero and we are ignoring empty values then skip to next value
|
||||
if (dataArray[i] === 0 && options.ignoreEmptyValues) continue;
|
||||
|
||||
var series = this.data.series[i];
|
||||
seriesGroups[i] = this.svg.elem('g', null, null, true);
|
||||
if (data.normalized.series[index] === 0 && options.ignoreEmptyValues) return;
|
||||
|
||||
// If the series is an object and contains a name or meta data we add a custom attribute
|
||||
seriesGroups[i].attr({
|
||||
seriesGroups[index].attr({
|
||||
'ct:series-name': series.name
|
||||
});
|
||||
|
||||
// Use series class from series data or if not set generate one
|
||||
seriesGroups[i].addClass([
|
||||
seriesGroups[index].addClass([
|
||||
options.classNames.series,
|
||||
(series.className || options.classNames.series + '-' + Chartist.alphaNumerate(i))
|
||||
(series.className || options.classNames.series + '-' + Chartist.alphaNumerate(index))
|
||||
].join(' '));
|
||||
|
||||
var endAngle = startAngle + dataArray[i] / totalDataSum * 360;
|
||||
// If the whole dataset is 0 endAngle should be zero. Can't divide by 0.
|
||||
var endAngle = (totalDataSum > 0 ? startAngle + data.normalized.series[index] / totalDataSum * 360 : 0);
|
||||
|
||||
// Use slight offset so there are no transparent hairline issues
|
||||
var overlappigStartAngle = Math.max(0, startAngle - (i === 0 || hasSingleValInSeries ? 0 : 0.2));
|
||||
var overlappigStartAngle = Math.max(0, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2));
|
||||
|
||||
// If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle
|
||||
// with Z and use 359.99 degrees
|
||||
@ -177,44 +186,59 @@
|
||||
var start = Chartist.polarToCartesian(center.x, center.y, radius, overlappigStartAngle),
|
||||
end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle);
|
||||
|
||||
var innerStart,
|
||||
innerEnd,
|
||||
donutSolidRadius;
|
||||
|
||||
// Create a new path element for the pie chart. If this isn't a donut chart we should close the path for a correct stroke
|
||||
var path = new Chartist.Svg.Path(!options.donut)
|
||||
var path = new Chartist.Svg.Path(!options.donut || options.donutSolid)
|
||||
.move(end.x, end.y)
|
||||
.arc(radius, radius, 0, endAngle - startAngle > 180, 0, start.x, start.y);
|
||||
|
||||
// If regular pie chart (no donut) we add a line to the center of the circle for completing the pie
|
||||
if(!options.donut) {
|
||||
path.line(center.x, center.y);
|
||||
} else if (options.donutSolid) {
|
||||
donutSolidRadius = radius - donutWidth.value;
|
||||
innerStart = Chartist.polarToCartesian(center.x, center.y, donutSolidRadius, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2));
|
||||
innerEnd = Chartist.polarToCartesian(center.x, center.y, donutSolidRadius, endAngle);
|
||||
path.line(innerStart.x, innerStart.y);
|
||||
path.arc(donutSolidRadius, donutSolidRadius, 0, endAngle - startAngle > 180, 1, innerEnd.x, innerEnd.y);
|
||||
}
|
||||
|
||||
// Create the SVG path
|
||||
// If this is a donut chart we add the donut class, otherwise just a regular slice
|
||||
var pathElement = seriesGroups[i].elem('path', {
|
||||
var pathClassName = options.classNames.slicePie;
|
||||
if (options.donut) {
|
||||
pathClassName = options.classNames.sliceDonut;
|
||||
if (options.donutSolid) {
|
||||
pathClassName = options.classNames.sliceDonutSolid;
|
||||
}
|
||||
}
|
||||
var pathElement = seriesGroups[index].elem('path', {
|
||||
d: path.stringify()
|
||||
}, options.donut ? options.classNames.sliceDonut : options.classNames.slicePie);
|
||||
}, pathClassName);
|
||||
|
||||
// Adding the pie series value to the path
|
||||
pathElement.attr({
|
||||
'ct:value': dataArray[i],
|
||||
'ct:value': data.normalized.series[index],
|
||||
'ct:meta': Chartist.serialize(series.meta)
|
||||
});
|
||||
|
||||
// If this is a donut, we add the stroke-width as style attribute
|
||||
if(options.donut) {
|
||||
pathElement.attr({
|
||||
'style': 'stroke-width: ' + donutWidth.value + 'px'
|
||||
});
|
||||
if(options.donut && !options.donutSolid) {
|
||||
pathElement._node.style.strokeWidth = donutWidth.value + 'px';
|
||||
}
|
||||
|
||||
// Fire off draw event
|
||||
this.eventEmitter.emit('draw', {
|
||||
type: 'slice',
|
||||
value: dataArray[i],
|
||||
value: data.normalized.series[index],
|
||||
totalDataSum: totalDataSum,
|
||||
index: i,
|
||||
index: index,
|
||||
meta: series.meta,
|
||||
series: series,
|
||||
group: seriesGroups[i],
|
||||
group: seriesGroups[index],
|
||||
element: pathElement,
|
||||
path: path.clone(),
|
||||
center: center,
|
||||
@ -225,9 +249,31 @@
|
||||
|
||||
// If we need to show labels we need to add the label for this slice now
|
||||
if(options.showLabel) {
|
||||
// Position at the labelRadius distance from center and between start and end angle
|
||||
var labelPosition = Chartist.polarToCartesian(center.x, center.y, labelRadius, startAngle + (endAngle - startAngle) / 2),
|
||||
interpolatedValue = options.labelInterpolationFnc(this.data.labels && !Chartist.isFalseyButZero(this.data.labels[i]) ? this.data.labels[i] : dataArray[i], i);
|
||||
var labelPosition;
|
||||
if(data.raw.series.length === 1) {
|
||||
// If we have only 1 series, we can position the label in the center of the pie
|
||||
labelPosition = {
|
||||
x: center.x,
|
||||
y: center.y
|
||||
};
|
||||
} else {
|
||||
// Position at the labelRadius distance from center and between start and end angle
|
||||
labelPosition = Chartist.polarToCartesian(
|
||||
center.x,
|
||||
center.y,
|
||||
labelRadius,
|
||||
startAngle + (endAngle - startAngle) / 2
|
||||
);
|
||||
}
|
||||
|
||||
var rawValue;
|
||||
if(data.normalized.labels && !Chartist.isFalseyButZero(data.normalized.labels[index])) {
|
||||
rawValue = data.normalized.labels[index];
|
||||
} else {
|
||||
rawValue = data.normalized.series[index];
|
||||
}
|
||||
|
||||
var interpolatedValue = options.labelInterpolationFnc(rawValue, index);
|
||||
|
||||
if(interpolatedValue || interpolatedValue === 0) {
|
||||
var labelElement = labelsGroup.elem('text', {
|
||||
@ -239,7 +285,7 @@
|
||||
// Fire off draw event
|
||||
this.eventEmitter.emit('draw', {
|
||||
type: 'label',
|
||||
index: i,
|
||||
index: index,
|
||||
group: labelsGroup,
|
||||
element: labelElement,
|
||||
text: '' + interpolatedValue,
|
||||
@ -252,7 +298,7 @@
|
||||
// Set next startAngle to current endAngle.
|
||||
// (except for last slice)
|
||||
startAngle = endAngle;
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.eventEmitter.emit('created', {
|
||||
chartRect: chartRect,
|
||||
@ -345,4 +391,4 @@
|
||||
determineAnchorPosition: determineAnchorPosition
|
||||
});
|
||||
|
||||
}(window, document, Chartist));
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* @module Chartist.Class
|
||||
*/
|
||||
/* global Chartist */
|
||||
(function(window, document, Chartist) {
|
||||
(function(globalRoot, Chartist) {
|
||||
'use strict';
|
||||
|
||||
function listToArray(list) {
|
||||
@ -108,4 +108,4 @@
|
||||
cloneDefinitions: cloneDefinitions
|
||||
};
|
||||
|
||||
}(window, document, Chartist));
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -7,9 +7,12 @@ var Chartist = {
|
||||
version: '<%= pkg.version %>'
|
||||
};
|
||||
|
||||
(function (window, document, Chartist) {
|
||||
(function (globalRoot, Chartist) {
|
||||
'use strict';
|
||||
|
||||
var window = globalRoot.window;
|
||||
var document = globalRoot.document;
|
||||
|
||||
/**
|
||||
* This object contains all namespaces used within Chartist.
|
||||
*
|
||||
@ -56,18 +59,20 @@ var Chartist = {
|
||||
* @return {Object} An object that has the same reference as target but is extended and merged with the properties of source
|
||||
*/
|
||||
Chartist.extend = function (target) {
|
||||
var i, source, sourceProp;
|
||||
target = target || {};
|
||||
|
||||
var sources = Array.prototype.slice.call(arguments, 1);
|
||||
sources.forEach(function(source) {
|
||||
for (i = 1; i < arguments.length; i++) {
|
||||
source = arguments[i];
|
||||
for (var prop in source) {
|
||||
if (typeof source[prop] === 'object' && source[prop] !== null && !(source[prop] instanceof Array)) {
|
||||
target[prop] = Chartist.extend({}, target[prop], source[prop]);
|
||||
sourceProp = source[prop];
|
||||
if (typeof sourceProp === 'object' && sourceProp !== null && !(sourceProp instanceof Array)) {
|
||||
target[prop] = Chartist.extend(target[prop], sourceProp);
|
||||
} else {
|
||||
target[prop] = source[prop];
|
||||
target[prop] = sourceProp;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return target;
|
||||
};
|
||||
@ -313,9 +318,10 @@ var Chartist = {
|
||||
svg = new Chartist.Svg('svg').attr({
|
||||
width: width,
|
||||
height: height
|
||||
}).addClass(className).attr({
|
||||
style: 'width: ' + width + '; height: ' + height + ';'
|
||||
});
|
||||
}).addClass(className);
|
||||
|
||||
svg._node.style.width = width;
|
||||
svg._node.style.height = height;
|
||||
|
||||
// Add the DOM node to our container
|
||||
container.appendChild(svg._node);
|
||||
@ -329,37 +335,71 @@ var Chartist = {
|
||||
* @param {Object} data The data object that is passed as second argument to the charts
|
||||
* @return {Object} The normalized data object
|
||||
*/
|
||||
Chartist.normalizeData = function(data) {
|
||||
// Ensure data is present otherwise enforce
|
||||
data = data || {series: [], labels: []};
|
||||
data.series = data.series || [];
|
||||
data.labels = data.labels || [];
|
||||
Chartist.normalizeData = function(data, reverse, multi) {
|
||||
var labelCount;
|
||||
var output = {
|
||||
raw: data,
|
||||
normalized: {}
|
||||
};
|
||||
|
||||
// Check if we should generate some labels based on existing series data
|
||||
if (data.series.length > 0 && data.labels.length === 0) {
|
||||
var normalized = Chartist.getDataArray(data),
|
||||
labelCount;
|
||||
output.normalized.series = Chartist.getDataArray({
|
||||
series: data.series || []
|
||||
}, reverse, multi);
|
||||
|
||||
// If all elements of the normalized data array are arrays we're dealing with
|
||||
// data from Bar or Line charts and we need to find the largest series if they are un-even
|
||||
if (normalized.every(function(value) {
|
||||
// If all elements of the normalized data array are arrays we're dealing with
|
||||
// multi series data and we need to find the largest series if they are un-even
|
||||
if (output.normalized.series.every(function(value) {
|
||||
return value instanceof Array;
|
||||
})) {
|
||||
// Getting the series with the the most elements
|
||||
labelCount = Math.max.apply(null, normalized.map(function(series) {
|
||||
return series.length;
|
||||
}));
|
||||
} else {
|
||||
// We're dealing with Pie data so we just take the normalized array length
|
||||
labelCount = normalized.length;
|
||||
}
|
||||
|
||||
// Setting labels to an array with emptry strings using our labelCount estimated above
|
||||
data.labels = Chartist.times(labelCount).map(function() {
|
||||
return '';
|
||||
});
|
||||
// Getting the series with the the most elements
|
||||
labelCount = Math.max.apply(null, output.normalized.series.map(function(series) {
|
||||
return series.length;
|
||||
}));
|
||||
} else {
|
||||
// We're dealing with Pie data so we just take the normalized array length
|
||||
labelCount = output.normalized.series.length;
|
||||
}
|
||||
return data;
|
||||
|
||||
output.normalized.labels = (data.labels || []).slice();
|
||||
// Padding the labels to labelCount with empty strings
|
||||
Array.prototype.push.apply(
|
||||
output.normalized.labels,
|
||||
Chartist.times(Math.max(0, labelCount - output.normalized.labels.length)).map(function() {
|
||||
return '';
|
||||
})
|
||||
);
|
||||
|
||||
if(reverse) {
|
||||
Chartist.reverseData(output.normalized);
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
/**
|
||||
* This function safely checks if an objects has an owned property.
|
||||
*
|
||||
* @param {Object} object The object where to check for a property
|
||||
* @param {string} property The property name
|
||||
* @returns {boolean} Returns true if the object owns the specified property
|
||||
*/
|
||||
Chartist.safeHasProperty = function(object, property) {
|
||||
return object !== null &&
|
||||
typeof object === 'object' &&
|
||||
object.hasOwnProperty(property);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a value is considered a hole in the data series.
|
||||
*
|
||||
* @param {*} value
|
||||
* @returns {boolean} True if the value is considered a data hole
|
||||
*/
|
||||
Chartist.isDataHoleValue = function(value) {
|
||||
return value === null ||
|
||||
value === undefined ||
|
||||
(typeof value === 'number' && isNaN(value));
|
||||
};
|
||||
|
||||
/**
|
||||
@ -385,30 +425,29 @@ var Chartist = {
|
||||
*
|
||||
* @memberof Chartist.Core
|
||||
* @param {Object} data The series object that contains the data to be visualized in the chart
|
||||
* @param {Boolean} reverse If true the whole data is reversed by the getDataArray call. This will modify the data object passed as first parameter. The labels as well as the series order is reversed. The whole series data arrays are reversed too.
|
||||
* @param {Boolean} multi Create a multi dimensional array from a series data array where a value object with `x` and `y` values will be created.
|
||||
* @param {Boolean} [reverse] If true the whole data is reversed by the getDataArray call. This will modify the data object passed as first parameter. The labels as well as the series order is reversed. The whole series data arrays are reversed too.
|
||||
* @param {Boolean} [multi] Create a multi dimensional array from a series data array where a value object with `x` and `y` values will be created.
|
||||
* @return {Array} A plain array that contains the data to be visualized in the chart
|
||||
*/
|
||||
Chartist.getDataArray = function (data, reverse, multi) {
|
||||
// If the data should be reversed but isn't we need to reverse it
|
||||
// If it's reversed but it shouldn't we need to reverse it back
|
||||
// That's required to handle data updates correctly and to reflect the responsive configurations
|
||||
if(reverse && !data.reversed || !reverse && data.reversed) {
|
||||
Chartist.reverseData(data);
|
||||
data.reversed = !data.reversed;
|
||||
}
|
||||
|
||||
Chartist.getDataArray = function(data, reverse, multi) {
|
||||
// Recursively walks through nested arrays and convert string values to numbers and objects with value properties
|
||||
// to values. Check the tests in data core -> data normalization for a detailed specification of expected values
|
||||
function recursiveConvert(value) {
|
||||
if(Chartist.isFalseyButZero(value)) {
|
||||
// This is a hole in data and we should return undefined
|
||||
return undefined;
|
||||
} else if((value.data || value) instanceof Array) {
|
||||
return (value.data || value).map(recursiveConvert);
|
||||
} else if(value.hasOwnProperty('value')) {
|
||||
if(Chartist.safeHasProperty(value, 'value')) {
|
||||
// We are dealing with value object notation so we need to recurse on value property
|
||||
return recursiveConvert(value.value);
|
||||
} else if(Chartist.safeHasProperty(value, 'data')) {
|
||||
// We are dealing with series object notation so we need to recurse on data property
|
||||
return recursiveConvert(value.data);
|
||||
} else if(value instanceof Array) {
|
||||
// Data is of type array so we need to recurse on the series
|
||||
return value.map(recursiveConvert);
|
||||
} else if(Chartist.isDataHoleValue(value)) {
|
||||
// We're dealing with a hole in the data and therefore need to return undefined
|
||||
// We're also returning undefined for multi value output
|
||||
return undefined;
|
||||
} else {
|
||||
// We need to prepare multi value output (x and y data)
|
||||
if(multi) {
|
||||
var multiValue = {};
|
||||
|
||||
@ -427,6 +466,7 @@ var Chartist = {
|
||||
return multiValue;
|
||||
|
||||
} else {
|
||||
// We can return simple data
|
||||
return Chartist.getNumberOrUndefined(value);
|
||||
}
|
||||
}
|
||||
@ -461,7 +501,7 @@ var Chartist = {
|
||||
|
||||
Chartist.getMetaData = function(series, index) {
|
||||
var value = series.data ? series.data[index] : series[index];
|
||||
return value ? Chartist.serialize(value.meta) : undefined;
|
||||
return value ? value.meta : undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -577,14 +617,14 @@ var Chartist = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the value is a valid number or string with a number.
|
||||
* Checks if a value can be safely coerced to a number. This includes all values except null which result in finite numbers when coerced. This excludes NaN, since it's not finite.
|
||||
*
|
||||
* @memberof Chartist.Core
|
||||
* @param value
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
Chartist.isNum = function(value) {
|
||||
return !isNaN(value) && isFinite(value);
|
||||
Chartist.isNumeric = function(value) {
|
||||
return value === null ? false : isFinite(value);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -606,23 +646,33 @@ var Chartist = {
|
||||
* @returns {*}
|
||||
*/
|
||||
Chartist.getNumberOrUndefined = function(value) {
|
||||
return isNaN(+value) ? undefined : +value;
|
||||
return Chartist.isNumeric(value) ? +value : undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a value from a dimension `value.x` or `value.y` while returning value directly if it's a valid numeric value. If the value is not numeric and it's falsey this function will return undefined.
|
||||
* Checks if provided value object is multi value (contains x or y properties)
|
||||
*
|
||||
* @memberof Chartist.Core
|
||||
* @param value
|
||||
*/
|
||||
Chartist.isMultiValue = function(value) {
|
||||
return typeof value === 'object' && ('x' in value || 'y' in value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a value from a dimension `value.x` or `value.y` while returning value directly if it's a valid numeric value. If the value is not numeric and it's falsey this function will return `defaultValue`.
|
||||
*
|
||||
* @memberof Chartist.Core
|
||||
* @param value
|
||||
* @param dimension
|
||||
* @param defaultValue
|
||||
* @returns {*}
|
||||
*/
|
||||
Chartist.getMultiValue = function(value, dimension) {
|
||||
if(Chartist.isNum(value)) {
|
||||
return +value;
|
||||
} else if(value) {
|
||||
return value[dimension || 'y'] || 0;
|
||||
if(Chartist.isMultiValue(value)) {
|
||||
return Chartist.getNumberOrUndefined(value[dimension || 'y']);
|
||||
} else {
|
||||
return 0;
|
||||
return Chartist.getNumberOrUndefined(value);
|
||||
}
|
||||
};
|
||||
|
||||
@ -727,24 +777,37 @@ var Chartist = {
|
||||
}
|
||||
}
|
||||
|
||||
var EPSILON = 2.221E-16;
|
||||
bounds.step = Math.max(bounds.step, EPSILON);
|
||||
function safeIncrement(value, increment) {
|
||||
// If increment is too small use *= (1+EPSILON) as a simple nextafter
|
||||
if (value === (value += increment)) {
|
||||
value *= (1 + (increment > 0 ? EPSILON : -EPSILON));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Narrow min and max based on new step
|
||||
newMin = bounds.min;
|
||||
newMax = bounds.max;
|
||||
while(newMin + bounds.step <= bounds.low) {
|
||||
newMin += bounds.step;
|
||||
while (newMin + bounds.step <= bounds.low) {
|
||||
newMin = safeIncrement(newMin, bounds.step);
|
||||
}
|
||||
while(newMax - bounds.step >= bounds.high) {
|
||||
newMax -= bounds.step;
|
||||
while (newMax - bounds.step >= bounds.high) {
|
||||
newMax = safeIncrement(newMax, -bounds.step);
|
||||
}
|
||||
bounds.min = newMin;
|
||||
bounds.max = newMax;
|
||||
bounds.range = bounds.max - bounds.min;
|
||||
|
||||
bounds.values = [];
|
||||
for (i = bounds.min; i <= bounds.max; i += bounds.step) {
|
||||
bounds.values.push(Chartist.roundWithPrecision(i));
|
||||
var values = [];
|
||||
for (i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) {
|
||||
var value = Chartist.roundWithPrecision(i);
|
||||
if (value !== values[values.length - 1]) {
|
||||
values.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
bounds.values = values;
|
||||
return bounds;
|
||||
};
|
||||
|
||||
@ -859,6 +922,31 @@ var Chartist = {
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a grid background rect and emits the draw event.
|
||||
*
|
||||
* @memberof Chartist.Core
|
||||
* @param gridGroup
|
||||
* @param chartRect
|
||||
* @param className
|
||||
* @param eventEmitter
|
||||
*/
|
||||
Chartist.createGridBackground = function (gridGroup, chartRect, className, eventEmitter) {
|
||||
var gridBackground = gridGroup.elem('rect', {
|
||||
x: chartRect.x1,
|
||||
y: chartRect.y2,
|
||||
width: chartRect.width(),
|
||||
height: chartRect.height(),
|
||||
}, className, true);
|
||||
|
||||
// Event for grid background draw
|
||||
eventEmitter.emit('draw', {
|
||||
type: 'gridBackground',
|
||||
group: gridGroup,
|
||||
element: gridBackground
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a label based on a projected value and an axis.
|
||||
*
|
||||
@ -882,15 +970,17 @@ var Chartist = {
|
||||
positionalData[axis.units.pos] = position + labelOffset[axis.units.pos];
|
||||
positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];
|
||||
positionalData[axis.units.len] = length;
|
||||
positionalData[axis.counterUnits.len] = axisOffset - 10;
|
||||
positionalData[axis.counterUnits.len] = Math.max(0, axisOffset - 10);
|
||||
|
||||
if(useForeignObject) {
|
||||
// We need to set width and height explicitly to px as span will not expand with width and height being
|
||||
// 100% in all browsers
|
||||
var content = '<span class="' + classes.join(' ') + '" style="' +
|
||||
axis.units.len + ': ' + Math.round(positionalData[axis.units.len]) + 'px; ' +
|
||||
axis.counterUnits.len + ': ' + Math.round(positionalData[axis.counterUnits.len]) + 'px">' +
|
||||
labels[index] + '</span>';
|
||||
var content = document.createElement('span');
|
||||
content.className = classes.join(' ');
|
||||
content.setAttribute('xmlns', Chartist.namespaces.xhtml);
|
||||
content.innerText = labels[index];
|
||||
content.style[axis.units.len] = Math.round(positionalData[axis.units.len]) + 'px';
|
||||
content.style[axis.counterUnits.len] = Math.round(positionalData[axis.counterUnits.len]) + 'px';
|
||||
|
||||
labelElement = group.foreignObject(content, Chartist.extend({
|
||||
style: 'overflow: visible;'
|
||||
@ -942,7 +1032,7 @@ var Chartist = {
|
||||
mediaQueryListeners = [],
|
||||
i;
|
||||
|
||||
function updateCurrentOptions(preventChangedEvent) {
|
||||
function updateCurrentOptions(mediaEvent) {
|
||||
var previousOptions = currentOptions;
|
||||
currentOptions = Chartist.extend({}, baseOptions);
|
||||
|
||||
@ -955,7 +1045,7 @@ var Chartist = {
|
||||
}
|
||||
}
|
||||
|
||||
if(eventEmitter && !preventChangedEvent) {
|
||||
if(eventEmitter && mediaEvent) {
|
||||
eventEmitter.emit('optionsChanged', {
|
||||
previousOptions: previousOptions,
|
||||
currentOptions: currentOptions
|
||||
@ -979,8 +1069,8 @@ var Chartist = {
|
||||
mediaQueryListeners.push(mql);
|
||||
}
|
||||
}
|
||||
// Execute initially so we get the correct options
|
||||
updateCurrentOptions(true);
|
||||
// Execute initially without an event argument so we get the correct options
|
||||
updateCurrentOptions();
|
||||
|
||||
return {
|
||||
removeMediaQueryListeners: removeMediaQueryListeners,
|
||||
@ -990,4 +1080,72 @@ var Chartist = {
|
||||
};
|
||||
};
|
||||
|
||||
}(window, document, Chartist));
|
||||
|
||||
/**
|
||||
* Splits a list of coordinates and associated values into segments. Each returned segment contains a pathCoordinates
|
||||
* valueData property describing the segment.
|
||||
*
|
||||
* With the default options, segments consist of contiguous sets of points that do not have an undefined value. Any
|
||||
* points with undefined values are discarded.
|
||||
*
|
||||
* **Options**
|
||||
* The following options are used to determine how segments are formed
|
||||
* ```javascript
|
||||
* var options = {
|
||||
* // If fillHoles is true, undefined values are simply discarded without creating a new segment. Assuming other options are default, this returns single segment.
|
||||
* fillHoles: false,
|
||||
* // If increasingX is true, the coordinates in all segments have strictly increasing x-values.
|
||||
* increasingX: false
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @memberof Chartist.Core
|
||||
* @param {Array} pathCoordinates List of point coordinates to be split in the form [x1, y1, x2, y2 ... xn, yn]
|
||||
* @param {Array} values List of associated point values in the form [v1, v2 .. vn]
|
||||
* @param {Object} options Options set by user
|
||||
* @return {Array} List of segments, each containing a pathCoordinates and valueData property.
|
||||
*/
|
||||
Chartist.splitIntoSegments = function(pathCoordinates, valueData, options) {
|
||||
var defaultOptions = {
|
||||
increasingX: false,
|
||||
fillHoles: false
|
||||
};
|
||||
|
||||
options = Chartist.extend({}, defaultOptions, options);
|
||||
|
||||
var segments = [];
|
||||
var hole = true;
|
||||
|
||||
for(var i = 0; i < pathCoordinates.length; i += 2) {
|
||||
// If this value is a "hole" we set the hole flag
|
||||
if(Chartist.getMultiValue(valueData[i / 2].value) === undefined) {
|
||||
// if(valueData[i / 2].value === undefined) {
|
||||
if(!options.fillHoles) {
|
||||
hole = true;
|
||||
}
|
||||
} else {
|
||||
if(options.increasingX && i >= 2 && pathCoordinates[i] <= pathCoordinates[i-2]) {
|
||||
// X is not increasing, so we need to make sure we start a new segment
|
||||
hole = true;
|
||||
}
|
||||
|
||||
|
||||
// If it's a valid value we need to check if we're coming out of a hole and create a new empty segment
|
||||
if(hole) {
|
||||
segments.push({
|
||||
pathCoordinates: [],
|
||||
valueData: []
|
||||
});
|
||||
// As we have a valid value now, we are not in a "hole" anymore
|
||||
hole = false;
|
||||
}
|
||||
|
||||
// Add to the segment pathCoordinates and valueData
|
||||
segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]);
|
||||
segments[segments.length - 1].valueData.push(valueData[i / 2]);
|
||||
}
|
||||
}
|
||||
|
||||
return segments;
|
||||
};
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* @module Chartist.Event
|
||||
*/
|
||||
/* global Chartist */
|
||||
(function (window, document, Chartist) {
|
||||
(function (globalRoot, Chartist) {
|
||||
'use strict';
|
||||
|
||||
Chartist.EventEmitter = function () {
|
||||
@ -75,4 +75,4 @@
|
||||
};
|
||||
};
|
||||
|
||||
}(window, document, Chartist));
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* @module Chartist.Interpolation
|
||||
*/
|
||||
/* global Chartist */
|
||||
(function(window, document, Chartist) {
|
||||
(function(globalRoot, Chartist) {
|
||||
'use strict';
|
||||
|
||||
Chartist.Interpolation = {};
|
||||
@ -40,7 +40,7 @@
|
||||
var currY = pathCoordinates[i + 1];
|
||||
var currData = valueData[i / 2];
|
||||
|
||||
if(currData.value !== undefined) {
|
||||
if(Chartist.getMultiValue(currData.value) !== undefined) {
|
||||
|
||||
if(hole) {
|
||||
path.move(currX, currY, false, currData);
|
||||
@ -162,43 +162,12 @@
|
||||
var t = Math.min(1, Math.max(0, options.tension)),
|
||||
c = 1 - t;
|
||||
|
||||
// This function will help us to split pathCoordinates and valueData into segments that also contain pathCoordinates
|
||||
// and valueData. This way the existing functions can be reused and the segment paths can be joined afterwards.
|
||||
// This functionality is necessary to treat "holes" in the line charts
|
||||
function splitIntoSegments(pathCoordinates, valueData) {
|
||||
var segments = [];
|
||||
var hole = true;
|
||||
|
||||
for(var i = 0; i < pathCoordinates.length; i += 2) {
|
||||
// If this value is a "hole" we set the hole flag
|
||||
if(valueData[i / 2].value === undefined) {
|
||||
if(!options.fillHoles) {
|
||||
hole = true;
|
||||
}
|
||||
} else {
|
||||
// If it's a valid value we need to check if we're coming out of a hole and create a new empty segment
|
||||
if(hole) {
|
||||
segments.push({
|
||||
pathCoordinates: [],
|
||||
valueData: []
|
||||
});
|
||||
// As we have a valid value now, we are not in a "hole" anymore
|
||||
hole = false;
|
||||
}
|
||||
|
||||
// Add to the segment pathCoordinates and valueData
|
||||
segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]);
|
||||
segments[segments.length - 1].valueData.push(valueData[i / 2]);
|
||||
}
|
||||
}
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
return function cardinal(pathCoordinates, valueData) {
|
||||
// First we try to split the coordinates into segments
|
||||
// This is necessary to treat "holes" in line charts
|
||||
var segments = splitIntoSegments(pathCoordinates, valueData);
|
||||
var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, {
|
||||
fillHoles: options.fillHoles
|
||||
});
|
||||
|
||||
if(!segments.length) {
|
||||
// If there were no segments return 'Chartist.Interpolation.none'
|
||||
@ -268,6 +237,137 @@
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Monotone Cubic spline interpolation produces a smooth curve which preserves monotonicity. Unlike cardinal splines, the curve will not extend beyond the range of y-values of the original data points.
|
||||
*
|
||||
* Monotone Cubic splines can only be created if there are more than two data points. If this is not the case this smoothing will fallback to `Chartist.Smoothing.none`.
|
||||
*
|
||||
* The x-values of subsequent points must be increasing to fit a Monotone Cubic spline. If this condition is not met for a pair of adjacent points, then there will be a break in the curve between those data points.
|
||||
*
|
||||
* All smoothing functions within Chartist are factory functions that accept an options parameter.
|
||||
*
|
||||
* @example
|
||||
* var chart = new Chartist.Line('.ct-chart', {
|
||||
* labels: [1, 2, 3, 4, 5],
|
||||
* series: [[1, 2, 8, 1, 7]]
|
||||
* }, {
|
||||
* lineSmooth: Chartist.Interpolation.monotoneCubic({
|
||||
* fillHoles: false
|
||||
* })
|
||||
* });
|
||||
*
|
||||
* @memberof Chartist.Interpolation
|
||||
* @param {Object} options The options of the monotoneCubic factory function.
|
||||
* @return {Function}
|
||||
*/
|
||||
Chartist.Interpolation.monotoneCubic = function(options) {
|
||||
var defaultOptions = {
|
||||
fillHoles: false
|
||||
};
|
||||
|
||||
options = Chartist.extend({}, defaultOptions, options);
|
||||
|
||||
return function monotoneCubic(pathCoordinates, valueData) {
|
||||
// First we try to split the coordinates into segments
|
||||
// This is necessary to treat "holes" in line charts
|
||||
var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, {
|
||||
fillHoles: options.fillHoles,
|
||||
increasingX: true
|
||||
});
|
||||
|
||||
if(!segments.length) {
|
||||
// If there were no segments return 'Chartist.Interpolation.none'
|
||||
return Chartist.Interpolation.none()([]);
|
||||
} else if(segments.length > 1) {
|
||||
// If the split resulted in more that one segment we need to interpolate each segment individually and join them
|
||||
// afterwards together into a single path.
|
||||
var paths = [];
|
||||
// For each segment we will recurse the monotoneCubic fn function
|
||||
segments.forEach(function(segment) {
|
||||
paths.push(monotoneCubic(segment.pathCoordinates, segment.valueData));
|
||||
});
|
||||
// Join the segment path data into a single path and return
|
||||
return Chartist.Svg.Path.join(paths);
|
||||
} else {
|
||||
// If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first
|
||||
// segment
|
||||
pathCoordinates = segments[0].pathCoordinates;
|
||||
valueData = segments[0].valueData;
|
||||
|
||||
// If less than three points we need to fallback to no smoothing
|
||||
if(pathCoordinates.length <= 4) {
|
||||
return Chartist.Interpolation.none()(pathCoordinates, valueData);
|
||||
}
|
||||
|
||||
var xs = [],
|
||||
ys = [],
|
||||
i,
|
||||
n = pathCoordinates.length / 2,
|
||||
ms = [],
|
||||
ds = [], dys = [], dxs = [],
|
||||
path;
|
||||
|
||||
// Populate x and y coordinates into separate arrays, for readability
|
||||
|
||||
for(i = 0; i < n; i++) {
|
||||
xs[i] = pathCoordinates[i * 2];
|
||||
ys[i] = pathCoordinates[i * 2 + 1];
|
||||
}
|
||||
|
||||
// Calculate deltas and derivative
|
||||
|
||||
for(i = 0; i < n - 1; i++) {
|
||||
dys[i] = ys[i + 1] - ys[i];
|
||||
dxs[i] = xs[i + 1] - xs[i];
|
||||
ds[i] = dys[i] / dxs[i];
|
||||
}
|
||||
|
||||
// Determine desired slope (m) at each point using Fritsch-Carlson method
|
||||
// See: http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation
|
||||
|
||||
ms[0] = ds[0];
|
||||
ms[n - 1] = ds[n - 2];
|
||||
|
||||
for(i = 1; i < n - 1; i++) {
|
||||
if(ds[i] === 0 || ds[i - 1] === 0 || (ds[i - 1] > 0) !== (ds[i] > 0)) {
|
||||
ms[i] = 0;
|
||||
} else {
|
||||
ms[i] = 3 * (dxs[i - 1] + dxs[i]) / (
|
||||
(2 * dxs[i] + dxs[i - 1]) / ds[i - 1] +
|
||||
(dxs[i] + 2 * dxs[i - 1]) / ds[i]);
|
||||
|
||||
if(!isFinite(ms[i])) {
|
||||
ms[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now build a path from the slopes
|
||||
|
||||
path = new Chartist.Svg.Path().move(xs[0], ys[0], false, valueData[0]);
|
||||
|
||||
for(i = 0; i < n - 1; i++) {
|
||||
path.curve(
|
||||
// First control point
|
||||
xs[i] + dxs[i] / 3,
|
||||
ys[i] + ms[i] * dxs[i] / 3,
|
||||
// Second control point
|
||||
xs[i + 1] - dxs[i] / 3,
|
||||
ys[i + 1] - ms[i + 1] * dxs[i] / 3,
|
||||
// End point
|
||||
xs[i + 1],
|
||||
ys[i + 1],
|
||||
|
||||
false,
|
||||
valueData[i + 1]
|
||||
);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Step interpolation will cause the line chart to move in steps rather than diagonal or smoothed lines. This interpolation will create additional points that will also be drawn when the `showPoint` option is enabled.
|
||||
*
|
||||
@ -334,4 +434,4 @@
|
||||
};
|
||||
};
|
||||
|
||||
}(window, document, Chartist));
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* @module Chartist.Svg.Path
|
||||
*/
|
||||
/* global Chartist */
|
||||
(function(window, document, Chartist) {
|
||||
(function(globalRoot, Chartist) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
@ -382,4 +382,4 @@
|
||||
|
||||
Chartist.Svg.Path.elementDescriptions = elementDescriptions;
|
||||
Chartist.Svg.Path.join = join;
|
||||
}(window, document, Chartist));
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -4,9 +4,11 @@
|
||||
* @module Chartist.Svg
|
||||
*/
|
||||
/* global Chartist */
|
||||
(function(window, document, Chartist) {
|
||||
(function(globalRoot, Chartist) {
|
||||
'use strict';
|
||||
|
||||
var document = globalRoot.document;
|
||||
|
||||
/**
|
||||
* Chartist.Svg creates a new SVG object wrapper with a starting element. You can use the wrapper to fluently create sub-elements and modify them.
|
||||
*
|
||||
@ -55,7 +57,7 @@
|
||||
*
|
||||
* @memberof Chartist.Svg
|
||||
* @param {Object|String} attributes An object with properties that will be added as attributes to the SVG element that is created. Attributes with undefined values will not be added. If this parameter is a String then the function is used as a getter and will return the attribute value.
|
||||
* @param {String} ns If specified, the attribute will be obtained using getAttributeNs. In order to write namepsaced attributes you can use the namespace:attribute notation within the attributes object.
|
||||
* @param {String} [ns] If specified, the attribute will be obtained using getAttributeNs. In order to write namepsaced attributes you can use the namespace:attribute notation within the attributes object.
|
||||
* @return {Object|String} The current wrapper object will be returned so it can be used for chaining or the attribute value if used as getter function.
|
||||
*/
|
||||
function attr(attributes, ns) {
|
||||
@ -146,6 +148,16 @@
|
||||
return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying SVG node for the current element.
|
||||
*
|
||||
* @memberof Chartist.Svg
|
||||
* @returns {Node}
|
||||
*/
|
||||
function getNode() {
|
||||
return this._node;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a foreignObject (see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject) that allows to embed HTML content into a SVG graphic. With the help of foreignObjects you can enable the usage of regular HTML elements inside of SVG where they are subject for SVG positioning and transformation but the Browser will use the HTML rendering capabilities for the containing DOM.
|
||||
*
|
||||
@ -483,6 +495,7 @@
|
||||
root: root,
|
||||
querySelector: querySelector,
|
||||
querySelectorAll: querySelectorAll,
|
||||
getNode: getNode,
|
||||
foreignObject: foreignObject,
|
||||
text: text,
|
||||
empty: empty,
|
||||
@ -584,4 +597,4 @@
|
||||
Chartist.Svg.List = Chartist.Class.extend({
|
||||
constructor: SvgList
|
||||
});
|
||||
}(window, document, Chartist));
|
||||
}(this || global, Chartist));
|
||||
|
||||
@ -107,7 +107,7 @@
|
||||
stroke: $color;
|
||||
}
|
||||
|
||||
.#{$ct-class-slice-pie}, .#{$ct-class-area} {
|
||||
.#{$ct-class-slice-pie}, .#{$ct-class-slice-donut-solid}, .#{$ct-class-area} {
|
||||
fill: $color;
|
||||
}
|
||||
}
|
||||
@ -123,6 +123,11 @@
|
||||
@include ct-flex();
|
||||
}
|
||||
|
||||
.#{$ct-class-chart-pie} .#{$ct-class-label},
|
||||
.#{$ct-class-chart-donut} .#{$ct-class-label} {
|
||||
dominant-baseline: central;
|
||||
}
|
||||
|
||||
.#{$ct-class-label}.#{$ct-class-horizontal}.#{$ct-class-start} {
|
||||
@include ct-align-justify(flex-end, flex-start);
|
||||
// Fallback for browsers that don't support foreignObjects
|
||||
@ -188,6 +193,10 @@
|
||||
@include ct-chart-grid($ct-grid-color, $ct-grid-width, $ct-grid-dasharray);
|
||||
}
|
||||
|
||||
.#{$ct-class-grid-background} {
|
||||
fill: $ct-grid-background-fill;
|
||||
}
|
||||
|
||||
.#{$ct-class-point} {
|
||||
@include ct-chart-point($ct-point-size, $ct-point-shape);
|
||||
}
|
||||
|
||||
@ -17,7 +17,9 @@ $ct-class-area: ct-area !default;
|
||||
$ct-class-bar: ct-bar !default;
|
||||
$ct-class-slice-pie: ct-slice-pie !default;
|
||||
$ct-class-slice-donut: ct-slice-donut !default;
|
||||
$ct-class-slice-donut-solid: ct-slice-donut-solid !default;
|
||||
$ct-class-grid: ct-grid !default;
|
||||
$ct-class-grid-background: ct-grid-background !default;
|
||||
$ct-class-vertical: ct-vertical !default;
|
||||
$ct-class-horizontal: ct-horizontal !default;
|
||||
$ct-class-start: ct-start !default;
|
||||
@ -37,6 +39,7 @@ $ct-text-line-height: 1;
|
||||
$ct-grid-color: rgba(0, 0, 0, 0.2) !default;
|
||||
$ct-grid-dasharray: 2px !default;
|
||||
$ct-grid-width: 1px !default;
|
||||
$ct-grid-background-fill: none !default;
|
||||
|
||||
// Line chart properties
|
||||
$ct-line-width: 4px !default;
|
||||
|
||||
@ -16,7 +16,7 @@ module.exports = function (grunt) {
|
||||
{
|
||||
expand: true,
|
||||
cwd: '<%= pkg.config.site %>/images',
|
||||
src: '{,*/}*.{png,jpg,jpeg,gif}',
|
||||
src: '{,*/}*.{png,jpg,jpeg}',
|
||||
dest: '<%= pkg.config.public %>/images'
|
||||
}
|
||||
]
|
||||
|
||||
@ -29,10 +29,11 @@ module.exports = function (grunt) {
|
||||
'<%= pkg.config.src %>/scripts/charts/pie.js'
|
||||
],
|
||||
options: {
|
||||
summary: true,
|
||||
specs: '<%= pkg.config.test %>/spec/**/spec-*.js',
|
||||
helpers: '<%= pkg.config.test %>/spec/**/helper-*.js',
|
||||
vendor: [
|
||||
'node_modules/jasmine-jquery/vendor/jquery/jquery.js',
|
||||
vendor: [
|
||||
'node_modules/jquery/dist/jquery.js',
|
||||
'node_modules/jasmine-jquery/lib/jasmine-jquery.js'
|
||||
],
|
||||
styles: [
|
||||
|
||||
@ -15,7 +15,8 @@ module.exports = function (grunt) {
|
||||
src: '<%= pkg.config.dist %>/chartist.js',
|
||||
objectToExport: 'Chartist',
|
||||
globalAlias: 'Chartist',
|
||||
indent: ' '
|
||||
amdModuleId: 'Chartist',
|
||||
indent: 2
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,6 +1,32 @@
|
||||
describe('Axes tests', function() {
|
||||
'use strict';
|
||||
|
||||
describe('StepAxis projectValue should not return NaN', function() {
|
||||
it('should return 0 if options.ticks.length == 1', function() {
|
||||
var ticks = [1],
|
||||
axisUnit = {
|
||||
'pos':'y',
|
||||
'len':'height',
|
||||
'dir':'vertical',
|
||||
'rectStart':'y2',
|
||||
'rectEnd':'y1',
|
||||
'rectOffset':'x1'
|
||||
},
|
||||
data = [[1]],
|
||||
chartRect = {
|
||||
'y2':0,
|
||||
'y1':15,
|
||||
'x1':50,
|
||||
'x2':100
|
||||
},
|
||||
options = {
|
||||
'ticks': ticks
|
||||
},
|
||||
stepAxis = new Chartist.StepAxis(axisUnit, data, chartRect, options);
|
||||
expect(stepAxis.stepLength).toEqual(15);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fixed scale axis', function () {
|
||||
it('should order the tick array', function() {
|
||||
|
||||
@ -13,12 +39,7 @@ describe('Axes tests', function() {
|
||||
'rectEnd':'y1',
|
||||
'rectOffset':'x1'
|
||||
},
|
||||
data = {
|
||||
'raw': {
|
||||
'series':[[ {x: 1, y: 10}, {x: 2, y: 5}, {x: 3, y: -5} ]]
|
||||
},
|
||||
'normalized':[[ {'y':10,'x':1},{'y':5,'x':2},{'y':-5,'x':3} ]]
|
||||
},
|
||||
data = [[ {x: 1, y: 10}, {x: 2, y: 5}, {x: 3, y: -5} ]],
|
||||
chartRect = {
|
||||
'padding':{'top':15,'right':15,'bottom':5,'left':10},
|
||||
'y2':15,
|
||||
|
||||
@ -9,6 +9,71 @@ describe('Bar chart tests', function() {
|
||||
|
||||
});
|
||||
|
||||
describe('grids', function() {
|
||||
|
||||
var chart;
|
||||
var options;
|
||||
var data;
|
||||
|
||||
beforeEach(function() {
|
||||
data = {
|
||||
series: [[
|
||||
{ x: 1, y: 1 },
|
||||
{ x: 3, y: 5 }
|
||||
]]
|
||||
};
|
||||
options = {
|
||||
axisX: {
|
||||
type: Chartist.AutoScaleAxis,
|
||||
onlyInteger: true
|
||||
},
|
||||
axisY: {
|
||||
type: Chartist.AutoScaleAxis,
|
||||
onlyInteger: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function onCreated(fn) {
|
||||
jasmine.getFixtures().set('<div class="ct-chart ct-golden-section"></div>');
|
||||
chart = new Chartist.Bar('.ct-chart', data, options);
|
||||
chart.on('created', fn);
|
||||
}
|
||||
|
||||
it('should contain ct-grids group', function(done) {
|
||||
onCreated(function () {
|
||||
expect($('g.ct-grids').length).toBe(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should draw grid lines', function(done) {
|
||||
onCreated(function () {
|
||||
expect($('g.ct-grids line.ct-grid.ct-horizontal').length).toBe(3);
|
||||
expect($('g.ct-grids line.ct-grid.ct-vertical').length).toBe(6);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should draw grid background', function(done) {
|
||||
options.showGridBackground = true;
|
||||
onCreated(function () {
|
||||
expect($('g.ct-grids rect.ct-grid-background').length).toBe(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not draw grid background if option set to false', function(done) {
|
||||
options.showGridBackground = false;
|
||||
onCreated(function () {
|
||||
expect($('g.ct-grids rect.ct-grid-background').length).toBe(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('ct:value attribute', function() {
|
||||
it('should contain x and y value for each bar', function(done) {
|
||||
jasmine.getFixtures().set('<div class="ct-chart ct-golden-section"></div>');
|
||||
|
||||
@ -214,6 +214,26 @@ describe('Chartist core', function() {
|
||||
]]
|
||||
);
|
||||
});
|
||||
|
||||
it('should normalize boolean series correctly', function() {
|
||||
var data = {
|
||||
series: [true, false, false, true]
|
||||
};
|
||||
|
||||
expect(Chartist.getDataArray(data)).toEqual(
|
||||
[1, 0, 0, 1]
|
||||
);
|
||||
});
|
||||
|
||||
it('should normalize date series correctly', function() {
|
||||
var data = {
|
||||
series: [new Date(0), new Date(1), new Date(2), new Date(3)]
|
||||
};
|
||||
|
||||
expect(Chartist.getDataArray(data)).toEqual(
|
||||
[0, 1, 2, 3]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('padding normalization tests', function () {
|
||||
@ -279,9 +299,9 @@ describe('Chartist core', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('quantity', function() {
|
||||
|
||||
|
||||
it('should return value for numbers', function() {
|
||||
expect(Chartist.quantity(100)).toEqual({ value: 100 });
|
||||
expect(Chartist.quantity(0)).toEqual({ value: 0 });
|
||||
@ -289,17 +309,289 @@ describe('Chartist core', function() {
|
||||
expect(Chartist.quantity(null)).toEqual({ value: null });
|
||||
expect(Chartist.quantity(undefined)).toEqual({ value: undefined });
|
||||
});
|
||||
|
||||
|
||||
it('should return value without unit from string', function() {
|
||||
expect(Chartist.quantity('100')).toEqual({ value: 100, unit : undefined });
|
||||
expect(Chartist.quantity('0')).toEqual({ value: 0, unit : undefined });
|
||||
});
|
||||
|
||||
|
||||
it('should return value and unit from string', function() {
|
||||
expect(Chartist.quantity('100%')).toEqual({ value: 100, unit :'%' });
|
||||
expect(Chartist.quantity('100 %')).toEqual({ value: 100, unit :'%' });
|
||||
expect(Chartist.quantity('0px')).toEqual({ value: 0, unit: 'px' });
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('getBounds', function() {
|
||||
|
||||
it('should return 10 steps', function() {
|
||||
var bounds = Chartist.getBounds(100, { high: 10, low: 1 }, 10, false);
|
||||
expect(bounds.min).toBe(1);
|
||||
expect(bounds.max).toBe(10);
|
||||
expect(bounds.values).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
||||
});
|
||||
|
||||
it('should return 5 steps', function() {
|
||||
var bounds = Chartist.getBounds(100, { high: 10, low: 1 }, 20, false);
|
||||
expect(bounds.min).toBe(1);
|
||||
expect(bounds.max).toBe(10);
|
||||
expect(bounds.values).toEqual([1, 3, 5, 7, 9]);
|
||||
// Is this correct behaviour? Should it include 10?
|
||||
});
|
||||
|
||||
it('should return non integer steps', function() {
|
||||
var bounds = Chartist.getBounds(100, { high: 2, low: 1 }, 20, false);
|
||||
expect(bounds.min).toBe(1);
|
||||
expect(bounds.max).toBe(2);
|
||||
expect(bounds.values).toEqual([ 1, 1.25, 1.5, 1.75, 2 ]);
|
||||
});
|
||||
|
||||
it('should return integer steps only', function() {
|
||||
var bounds = Chartist.getBounds(100, { high: 3, low: 1 }, 20, true);
|
||||
expect(bounds.min).toBe(1);
|
||||
expect(bounds.max).toBe(3);
|
||||
expect(bounds.values).toEqual([ 1, 2, 3 ]);
|
||||
});
|
||||
|
||||
it('should return single integer step', function() {
|
||||
var bounds = Chartist.getBounds(100, { high: 2, low: 1 }, 20, true);
|
||||
expect(bounds.min).toBe(1);
|
||||
expect(bounds.max).toBe(2);
|
||||
expect(bounds.values).toEqual([ 1, 2,]);
|
||||
});
|
||||
|
||||
it('should floor/ceil min/max', function() {
|
||||
var bounds = Chartist.getBounds(100, { high: 9.9, low: 1.01 }, 20, false);
|
||||
expect(bounds.min).toBe(1);
|
||||
expect(bounds.max).toBe(10);
|
||||
expect(bounds.values).toEqual([1, 3, 5, 7, 9]);
|
||||
// Is this correct behaviour? Should it include 10?
|
||||
});
|
||||
|
||||
it('should floor/ceil min/max for non integers', function() {
|
||||
var bounds = Chartist.getBounds(100, { high: 2.9, low: 1.01 }, 20, false);
|
||||
expect(bounds.min).toBe(1);
|
||||
expect(bounds.max).toBe(3);
|
||||
expect(bounds.values).toEqual([1, 1.5, 2, 2.5, 3]);
|
||||
});
|
||||
|
||||
it('should floor/ceil min/max if integers only', function() {
|
||||
var bounds = Chartist.getBounds(100, { high: 2.9, low: 1.01 }, 20, true);
|
||||
expect(bounds.min).toBe(1);
|
||||
expect(bounds.max).toBe(3);
|
||||
expect(bounds.values).toEqual([1, 2, 3]);
|
||||
});
|
||||
|
||||
it('should return neg and pos values', function() {
|
||||
var bounds = Chartist.getBounds(100, { high: 1.9, low: -0.9 }, 20, false);
|
||||
expect(bounds.min).toBe(-1);
|
||||
expect(bounds.max).toBe(2);
|
||||
expect(bounds.values).toEqual([-1, 0, 1, 2]);
|
||||
});
|
||||
|
||||
it('should return two steps if no space', function() {
|
||||
var bounds = Chartist.getBounds(100, { high: 5, low: 0 }, 45, false);
|
||||
expect(bounds.min).toBe(0);
|
||||
expect(bounds.max).toBe(5);
|
||||
expect(bounds.values).toEqual([0, 4]);
|
||||
// Is this correct behaviour? Should it be [0, 5]?
|
||||
});
|
||||
|
||||
it('should return single step if no space', function() {
|
||||
var bounds = Chartist.getBounds(100, { high: 5, low: 0 }, 80, false);
|
||||
expect(bounds.min).toBe(0);
|
||||
expect(bounds.max).toBe(5);
|
||||
expect(bounds.values).toEqual([0]);
|
||||
// Is this correct behaviour? Should it be [0, 5]?
|
||||
});
|
||||
|
||||
it('should return single step if range is less than epsilon', function() {
|
||||
var bounds = Chartist.getBounds(100, { high: 1.0000000000000002, low: 1 }, 20, false);
|
||||
expect(bounds.min).toBe(1);
|
||||
expect(bounds.max).toBe(1.0000000000000002);
|
||||
expect(bounds.low).toBe(1);
|
||||
expect(bounds.high).toBe(1.0000000000000002);
|
||||
expect(bounds.values).toEqual([1]);
|
||||
});
|
||||
|
||||
it('should return single step if range is less than smallest increment', function() {
|
||||
var bounds = Chartist.getBounds(613.234375, { high: 1000.0000000000001, low: 999.9999999999997 }, 50, false);
|
||||
expect(bounds.min).toBe(999.9999999999999);
|
||||
expect(bounds.max).toBe(1000);
|
||||
expect(bounds.low).toBe(999.9999999999997);
|
||||
expect(bounds.high).toBe(1000.0000000000001);
|
||||
expect(bounds.values).toEqual([Chartist.roundWithPrecision(999.9999999999999)]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('splitIntoSegments', function() {
|
||||
|
||||
function makeValues(arr) {
|
||||
return arr.map(function(x) {
|
||||
return { value: x };
|
||||
});
|
||||
}
|
||||
|
||||
it('should return empty array for empty input', function() {
|
||||
expect(Chartist.splitIntoSegments([],[])).toEqual([]);
|
||||
});
|
||||
|
||||
it('should remove undefined values', function() {
|
||||
var coords = [1,2,3,4,5,6,7,8,9,10,11,12];
|
||||
var values = makeValues([1,undefined,undefined,4,undefined,6]);
|
||||
|
||||
expect(Chartist.splitIntoSegments(coords, values)).toEqual([{
|
||||
pathCoordinates: [1,2],
|
||||
valueData: makeValues([1])
|
||||
}, {
|
||||
pathCoordinates: [7, 8],
|
||||
valueData: makeValues([4])
|
||||
}, {
|
||||
pathCoordinates: [11, 12],
|
||||
valueData: makeValues([6])
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should respect fillHoles option', function() {
|
||||
var coords = [1,2,3,4,5,6,7,8,9,10,11,12];
|
||||
var values = makeValues([1,undefined,undefined,4,undefined,6]);
|
||||
var options = {
|
||||
fillHoles: true
|
||||
};
|
||||
|
||||
expect(Chartist.splitIntoSegments(coords, values, options)).toEqual([{
|
||||
pathCoordinates: [1,2,7,8,11,12],
|
||||
valueData: makeValues([1,4,6])
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should respect increasingX option', function() {
|
||||
var coords = [1,2,3,4,5,6,5,6,7,8,1,2];
|
||||
var values = makeValues([1,2,3,4,5,6]);
|
||||
var options = {
|
||||
increasingX: true
|
||||
};
|
||||
|
||||
expect(Chartist.splitIntoSegments(coords, values, options)).toEqual([{
|
||||
pathCoordinates: [1,2,3,4,5,6],
|
||||
valueData: makeValues([1,2,3])
|
||||
}, {
|
||||
pathCoordinates: [5,6,7,8],
|
||||
valueData: makeValues([4,5])
|
||||
}, {
|
||||
pathCoordinates: [1,2],
|
||||
valueData: makeValues([6])
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createGrid', function() {
|
||||
var group, axis, classes, eventEmitter, position, length, offset;
|
||||
|
||||
beforeEach(function() {
|
||||
eventEmitter = Chartist.EventEmitter();
|
||||
group = new Chartist.Svg('g');
|
||||
axis = {
|
||||
units: {
|
||||
pos : 'x'
|
||||
},
|
||||
counterUnits: {
|
||||
pos : 'y'
|
||||
}
|
||||
};
|
||||
classes = [];
|
||||
position = 10;
|
||||
length = 100;
|
||||
offset = 20;
|
||||
});
|
||||
|
||||
function onCreated(fn, done) {
|
||||
eventEmitter.addEventHandler('draw', function(grid) {
|
||||
fn(grid);
|
||||
done();
|
||||
});
|
||||
Chartist.createGrid(position, 1, axis, offset, length, group, classes, eventEmitter);
|
||||
}
|
||||
|
||||
it('should add single grid line to group', function(done) {
|
||||
onCreated(function() {
|
||||
expect(group.querySelectorAll('line').svgElements.length).toBe(1);
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should draw line', function(done) {
|
||||
onCreated(function() {
|
||||
var line = group.querySelector('line');
|
||||
expect(line.attr('x1')).toBe('10');
|
||||
expect(line.attr('x2')).toBe('10');
|
||||
expect(line.attr('y1')).toBe('20');
|
||||
expect(line.attr('y2')).toBe('120');
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should draw horizontal line', function(done) {
|
||||
axis.units.pos = 'y';
|
||||
axis.counterUnits.pos = 'x';
|
||||
onCreated(function() {
|
||||
var line = group.querySelector('line');
|
||||
expect(line.attr('y1')).toBe('10');
|
||||
expect(line.attr('y2')).toBe('10');
|
||||
expect(line.attr('x1')).toBe('20');
|
||||
expect(line.attr('x2')).toBe('120');
|
||||
}, done);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('createGridBackground', function() {
|
||||
var group, chartRect, className, eventEmitter;
|
||||
|
||||
beforeEach(function() {
|
||||
eventEmitter = Chartist.EventEmitter();
|
||||
group = new Chartist.Svg('g');
|
||||
className = 'ct-test';
|
||||
chartRect = {
|
||||
x1 : 5,
|
||||
y2 : 10,
|
||||
_width : 100,
|
||||
_height : 50,
|
||||
width : function() { return this._width; },
|
||||
height : function() { return this._height; },
|
||||
};
|
||||
});
|
||||
|
||||
function onCreated(fn, done) {
|
||||
eventEmitter.addEventHandler('draw', function(data) {
|
||||
fn(data);
|
||||
done();
|
||||
});
|
||||
Chartist.createGridBackground(group, chartRect, className, eventEmitter);
|
||||
}
|
||||
|
||||
it('should add rect', function(done) {
|
||||
onCreated(function() {
|
||||
var rects = group.querySelectorAll('rect').svgElements;
|
||||
expect(rects.length).toBe(1);
|
||||
var rect = rects[0];
|
||||
expect(rect.attr('x')).toBe('5');
|
||||
expect(rect.attr('y')).toBe('10');
|
||||
expect(rect.attr('width')).toBe('100');
|
||||
expect(rect.attr('height')).toBe('50');
|
||||
expect(rect.classes()).toEqual(['ct-test']);
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should pass grid to event', function(done) {
|
||||
onCreated(function(data) {
|
||||
expect(data.type).toBe('gridBackground');
|
||||
var rect = data.element;
|
||||
expect(rect.attr('x')).toBe('5');
|
||||
expect(rect.attr('y')).toBe('10');
|
||||
}, done);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@ -9,6 +9,119 @@ describe('Line chart tests', function () {
|
||||
|
||||
});
|
||||
|
||||
describe('grids', function() {
|
||||
|
||||
var chart;
|
||||
var options;
|
||||
var data;
|
||||
|
||||
beforeEach(function() {
|
||||
data = {
|
||||
series: [[
|
||||
{ x: 1, y: 1 },
|
||||
{ x: 3, y: 5 }
|
||||
]]
|
||||
};
|
||||
options = {
|
||||
axisX: {
|
||||
type: Chartist.AutoScaleAxis,
|
||||
onlyInteger: true
|
||||
},
|
||||
axisY: {
|
||||
type: Chartist.AutoScaleAxis,
|
||||
onlyInteger: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function onCreated(fn) {
|
||||
jasmine.getFixtures().set('<div class="ct-chart ct-golden-section"></div>');
|
||||
chart = new Chartist.Line('.ct-chart', data, options);
|
||||
chart.on('created', fn);
|
||||
}
|
||||
|
||||
it('should contain ct-grids group', function(done) {
|
||||
onCreated(function () {
|
||||
expect($('g.ct-grids').length).toBe(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should draw grid lines', function(done) {
|
||||
onCreated(function () {
|
||||
expect($('g.ct-grids line.ct-grid.ct-horizontal').length).toBe(3);
|
||||
expect($('g.ct-grids line.ct-grid.ct-vertical').length).toBe(5);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should draw grid background', function(done) {
|
||||
options.showGridBackground = true;
|
||||
onCreated(function () {
|
||||
expect($('g.ct-grids rect.ct-grid-background').length).toBe(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not draw grid background if option set to false', function(done) {
|
||||
options.showGridBackground = false;
|
||||
onCreated(function () {
|
||||
expect($('g.ct-grids rect.ct-grid-background').length).toBe(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('AxisY position tests', function() {
|
||||
var options;
|
||||
var data;
|
||||
|
||||
beforeEach(function() {
|
||||
data = {
|
||||
series: [[
|
||||
{ x: 1, y: 1 },
|
||||
{ x: 3, y: 5 }
|
||||
]]
|
||||
};
|
||||
options = {};
|
||||
});
|
||||
|
||||
function onCreated(callback) {
|
||||
jasmine.getFixtures().set('<div class="ct-chart ct-golden-section"></div>');
|
||||
var chart = new Chartist.Line('.ct-chart', data, options);
|
||||
chart.on('created', callback);
|
||||
}
|
||||
|
||||
it('class should be ct-start if position start', function(done) {
|
||||
options = {
|
||||
axisY: {
|
||||
position: 'start'
|
||||
}
|
||||
};
|
||||
onCreated(function() {
|
||||
$('.ct-label.ct-vertical').each(function() {
|
||||
expect($(this).attr('class')).toBe('ct-label ct-vertical ct-start');
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('class should be ct-end if position is any other value than start', function(done) {
|
||||
options = {
|
||||
axisY: {
|
||||
position: 'right'
|
||||
}
|
||||
};
|
||||
onCreated(function() {
|
||||
$('.ct-label.ct-vertical').each(function() {
|
||||
expect($(this).attr('class')).toBe('ct-label ct-vertical ct-end');
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ct:value attribute', function () {
|
||||
it('should contain x and y value for each datapoint', function (done) {
|
||||
jasmine.getFixtures().set('<div class="ct-chart ct-golden-section"></div>');
|
||||
@ -209,6 +322,40 @@ describe('Line chart tests', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should render correctly with Interpolation.monotoneCubic and holes everywhere', function (done) {
|
||||
jasmine.getFixtures().set('<div class="ct-chart ct-golden-section"></div>');
|
||||
|
||||
var chart = new Chartist.Line('.ct-chart', {
|
||||
labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
series: [
|
||||
[NaN, 15, 0, null, 2, 3, 4, undefined, {value: 1, meta: 'meta data'}, null]
|
||||
]
|
||||
}, {
|
||||
lineSmooth: Chartist.Interpolation.monotoneCubic()
|
||||
});
|
||||
|
||||
chart.on('draw', function (context) {
|
||||
if (context.type === 'line') {
|
||||
expect(context.path.pathElements.map(function (pathElement) {
|
||||
return {
|
||||
command: pathElement.command,
|
||||
data: pathElement.data
|
||||
};
|
||||
})).toEqual([
|
||||
{command: 'M', data: {valueIndex: 1, value: {x: undefined, y: 15}, meta: undefined}},
|
||||
// Monotone cubic should create Line path segment if only one connection
|
||||
{command: 'L', data: {valueIndex: 2, value: {x: undefined, y: 0}, meta: undefined}},
|
||||
{command: 'M', data: {valueIndex: 4, value: {x: undefined, y: 2}, meta: undefined}},
|
||||
// Monotone cubic should create Curve path segment for 2 or more connections
|
||||
{command: 'C', data: {valueIndex: 5, value: {x: undefined, y: 3}, meta: undefined}},
|
||||
{command: 'C', data: {valueIndex: 6, value: {x: undefined, y: 4}, meta: undefined}},
|
||||
{command: 'M', data: {valueIndex: 8, value: {x: undefined, y: 1}, meta: 'meta data'}}
|
||||
]);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should render correctly with Interpolation.simple and holes everywhere', function (done) {
|
||||
jasmine.getFixtures().set('<div class="ct-chart ct-golden-section"></div>');
|
||||
|
||||
@ -314,6 +461,32 @@ describe('Line chart tests', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Single value data tests', function() {
|
||||
var data;
|
||||
|
||||
beforeEach(function() {
|
||||
data = {
|
||||
labels: [1],
|
||||
series: [[1]]
|
||||
};
|
||||
});
|
||||
|
||||
function onCreated(callback) {
|
||||
jasmine.getFixtures().set('<div class="ct-chart ct-golden-section"></div>');
|
||||
var chart = new Chartist.Line('.ct-chart', data);
|
||||
chart.on('created', callback);
|
||||
}
|
||||
|
||||
it('should render without NaN values and points', function(done) {
|
||||
onCreated(function() {
|
||||
expect($('.ct-line').eq(0).attr('d')).toBe('M50,15');
|
||||
expect($('.ct-point').eq(0).attr('x1')).toBe('50');
|
||||
expect($('.ct-point').eq(0).attr('x2')).toBe('50.01');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Empty data tests', function () {
|
||||
it('should render empty grid with no data', function (done) {
|
||||
jasmine.getFixtures().set('<div class="ct-chart ct-golden-section"></div>');
|
||||
@ -403,4 +576,24 @@ describe('Line chart tests', function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('x1 and x2 attribute', function () {
|
||||
it('should contain just a datapoint', function (done) {
|
||||
jasmine.getFixtures().set('<div class="ct-chart ct-golden-section"></div>');
|
||||
|
||||
var chart = new Chartist.Line('.ct-chart', {
|
||||
series: [[
|
||||
{x: 1, y: 2}
|
||||
]]
|
||||
}, {
|
||||
fullWidth: true
|
||||
});
|
||||
|
||||
chart.on('created', function () {
|
||||
expect($('.ct-point').eq(0).attr('x1')).not.toBe('NaN');
|
||||
expect($('.ct-point').eq(0).attr('x2')).not.toBe('NaN');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -39,8 +39,9 @@ describe('Pie chart tests', function() {
|
||||
|
||||
var num = '\\d+(\\.\\d*)?';
|
||||
var data, options;
|
||||
|
||||
|
||||
beforeEach(function() {
|
||||
var sum = function(a, b) { return a + b; };
|
||||
data = {
|
||||
series: [5, 3, 4]
|
||||
};
|
||||
@ -52,9 +53,8 @@ describe('Pie chart tests', function() {
|
||||
return Math.round(value / data.series.reduce(sum) * 100) + '%';
|
||||
}
|
||||
};
|
||||
var sum = function(a, b) { return a + b; };
|
||||
});
|
||||
|
||||
|
||||
function onCreated(callback) {
|
||||
jasmine.getFixtures().set('<div class="ct-chart ct-golden-section"></div>');
|
||||
var chart = new Chartist.Pie('.ct-chart', data, options);
|
||||
@ -71,9 +71,9 @@ describe('Pie chart tests', function() {
|
||||
it('should set value attribute', function(done) {
|
||||
onCreated(function() {
|
||||
var slices = $('.ct-slice-pie');
|
||||
expect(slices.eq(2).attr('ct:value')).toBe('5');
|
||||
expect(slices.eq(0).attr('ct:value')).toBe('5');
|
||||
expect(slices.eq(1).attr('ct:value')).toBe('3');
|
||||
expect(slices.eq(0).attr('ct:value')).toBe('4');
|
||||
expect(slices.eq(2).attr('ct:value')).toBe('4');
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -101,7 +101,7 @@ describe('Pie chart tests', function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should overlap slices', function(done) {
|
||||
data = {
|
||||
series: [1, 1]
|
||||
@ -110,8 +110,8 @@ describe('Pie chart tests', function() {
|
||||
var slice1 = $('.ct-slice-pie').eq(0);
|
||||
var slice2 = $('.ct-slice-pie').eq(1);
|
||||
|
||||
expect(slice1.attr('d')).toMatch(/^M50,10A40,40,0,0,0,50.\d+,90L50,50Z/);
|
||||
expect(slice2.attr('d')).toMatch(/^M50,90A40,40,0,0,0,50,10L50,50Z/);
|
||||
expect(slice1.attr('d')).toMatch(/^M50,90A40,40,0,0,0,50,10L50,50Z/);
|
||||
expect(slice2.attr('d')).toMatch(/^M50,10A40,40,0,0,0,50.\d+,90L50,50Z/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -121,7 +121,7 @@ describe('Pie chart tests', function() {
|
||||
series: [1, 2]
|
||||
};
|
||||
onCreated(function() {
|
||||
var slice1 = $('.ct-slice-pie').eq(0);
|
||||
var slice1 = $('.ct-slice-pie').eq(1);
|
||||
expect(slice1.attr('d')).toMatch(/^M50,10A40,40,0,1,0/);
|
||||
done();
|
||||
}, data);
|
||||
@ -137,7 +137,7 @@ describe('Pie chart tests', function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should draw complete circle with startAngle', function(done) {
|
||||
data.series = [100];
|
||||
options.startAngle = 90;
|
||||
@ -147,7 +147,7 @@ describe('Pie chart tests', function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should draw complete circle if values are 0', function(done) {
|
||||
data = {
|
||||
series: [0, 1, 0]
|
||||
@ -171,8 +171,8 @@ describe('Pie chart tests', function() {
|
||||
options = {
|
||||
width: 100,
|
||||
height: 100,
|
||||
chartPadding: 0,
|
||||
};
|
||||
chartPadding: 0
|
||||
};
|
||||
});
|
||||
|
||||
function onCreated(callback) {
|
||||
@ -182,42 +182,42 @@ describe('Pie chart tests', function() {
|
||||
}
|
||||
|
||||
it('Pie should render correctly with very small slices', function(done) {
|
||||
onCreated(function() {
|
||||
onCreated(function() {
|
||||
var slice1 = $('.ct-slice-pie').eq(0);
|
||||
var slice2 = $('.ct-slice-pie').eq(1);
|
||||
|
||||
expect(slice1.attr('d')).toMatch(/^M49.9\d*,0A50,50,0,1,0,50,0/);
|
||||
expect(slice2.attr('d')).toMatch(/^M50.1\d+,0A50,50,0,0,0,50,0/);
|
||||
expect(slice1.attr('d')).toMatch(/^M50.1\d+,0A50,50,0,0,0,50,0/);
|
||||
expect(slice2.attr('d')).toMatch(/^M49.9\d*,0A50,50,0,1,0,50,0/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('Pie should render correctly with very small slices on startAngle', function(done) {
|
||||
options.startAngle = 90;
|
||||
onCreated(function() {
|
||||
onCreated(function() {
|
||||
var slice1 = $('.ct-slice-pie').eq(0);
|
||||
var slice2 = $('.ct-slice-pie').eq(1);
|
||||
|
||||
expect(slice1.attr('d')).toMatch(/^M100,49.97\d*A50,50,0,1,0,100,49.98\d*/);
|
||||
expect(slice2.attr('d')).toMatch(/^M100,50.1\d*A50,50,0,0,0,100,50/);
|
||||
expect(slice1.attr('d')).toMatch(/^M100,50.1\d*A50,50,0,0,0,100,50/);
|
||||
expect(slice2.attr('d')).toMatch(/^M100,49.97\d*A50,50,0,1,0,100,49.98\d*/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Donut should render correctly with very small slices', function(done) {
|
||||
options.donut = true;
|
||||
onCreated(function() {
|
||||
onCreated(function() {
|
||||
var slice1 = $('.ct-slice-donut').eq(0);
|
||||
var slice2 = $('.ct-slice-donut').eq(1);
|
||||
|
||||
expect(slice1.attr('d')).toMatch(/^M49.9\d*,30A20,20,0,1,0,50,30/);
|
||||
expect(slice2.attr('d')).toMatch(/^M50.\d+,30A20,20,0,0,0,50,30/);
|
||||
expect(slice1.attr('d')).toMatch(/^M50.\d+,30A20,20,0,0,0,50,30/);
|
||||
expect(slice2.attr('d')).toMatch(/^M49.9\d*,30A20,20,0,1,0,50,30/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('Pie with some empty values configured to be ignored', function() {
|
||||
var data, options;
|
||||
|
||||
@ -239,19 +239,52 @@ describe('Pie chart tests', function() {
|
||||
}
|
||||
|
||||
it('Pie should not render empty slices', function(done) {
|
||||
onCreated(function() {
|
||||
onCreated(function() {
|
||||
var slices = $('.ct-slice-pie');
|
||||
|
||||
|
||||
expect(slices.length).toBe(3);
|
||||
|
||||
expect(slices.eq(2).attr('ct:value')).toBe('1');
|
||||
|
||||
expect(slices.eq(0).attr('ct:value')).toBe('1');
|
||||
expect(slices.eq(1).attr('ct:value')).toBe('2');
|
||||
expect(slices.eq(0).attr('ct:value')).toBe('4');
|
||||
expect(slices.eq(2).attr('ct:value')).toBe('4');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('Pie with empty values', function() {
|
||||
var data;
|
||||
|
||||
beforeEach(function() {
|
||||
data = {
|
||||
series: [0, 0, 0]
|
||||
};
|
||||
});
|
||||
|
||||
function onCreated(callback) {
|
||||
jasmine.getFixtures().set('<div class="ct-chart ct-golden-section"></div>');
|
||||
var chart = new Chartist.Pie('.ct-chart', data, {});
|
||||
chart.on('created', callback);
|
||||
}
|
||||
|
||||
it('Pie should render without NaN values and points', function(done) {
|
||||
onCreated(function() {
|
||||
var slices = $('.ct-slice-pie');
|
||||
|
||||
expect(slices.length).toBe(3);
|
||||
|
||||
expect(slices.eq(0).attr('ct:value')).toBe('0');
|
||||
expect(slices.eq(1).attr('ct:value')).toBe('0');
|
||||
expect(slices.eq(2).attr('ct:value')).toBe('0');
|
||||
|
||||
expect(slices.eq(0).attr('d')).toBe('M200,5A118.609,118.609,0,0,0,200,5L200,123.609Z');
|
||||
expect(slices.eq(1).attr('d')).toBe('M200,5A118.609,118.609,0,0,0,200,5L200,123.609Z');
|
||||
expect(slices.eq(2).attr('d')).toBe('M200,5A118.609,118.609,0,0,0,200,5L200,123.609Z');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Pie with some empty values configured not to be ignored', function() {
|
||||
var data, options;
|
||||
|
||||
@ -263,7 +296,7 @@ describe('Pie chart tests', function() {
|
||||
width: 100,
|
||||
height: 100,
|
||||
ignoreEmptyValues: false
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
function onCreated(callback) {
|
||||
@ -273,15 +306,15 @@ describe('Pie chart tests', function() {
|
||||
}
|
||||
|
||||
it('Pie should render empty slices', function(done) {
|
||||
onCreated(function() {
|
||||
onCreated(function() {
|
||||
var slices = $('.ct-slice-pie');
|
||||
|
||||
|
||||
expect(slices.length).toBe(4);
|
||||
|
||||
expect(slices.eq(3).attr('ct:value')).toBe('1');
|
||||
expect(slices.eq(2).attr('ct:value')).toBe('2');
|
||||
expect(slices.eq(1).attr('ct:value')).toBe('0');
|
||||
expect(slices.eq(0).attr('ct:value')).toBe('4');
|
||||
|
||||
expect(slices.eq(0).attr('ct:value')).toBe('1');
|
||||
expect(slices.eq(1).attr('ct:value')).toBe('2');
|
||||
expect(slices.eq(2).attr('ct:value')).toBe('0');
|
||||
expect(slices.eq(3).attr('ct:value')).toBe('4');
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -319,10 +352,10 @@ describe('Pie chart tests', function() {
|
||||
it('should set value attribute', function(done) {
|
||||
onCreated(function() {
|
||||
var slices = $('.ct-slice-donut');
|
||||
expect(slices.eq(3).attr('ct:value')).toBe('20');
|
||||
expect(slices.eq(2).attr('ct:value')).toBe('10');
|
||||
expect(slices.eq(1).attr('ct:value')).toBe('30');
|
||||
expect(slices.eq(0).attr('ct:value')).toBe('40');
|
||||
expect(slices.eq(0).attr('ct:value')).toBe('20');
|
||||
expect(slices.eq(1).attr('ct:value')).toBe('10');
|
||||
expect(slices.eq(2).attr('ct:value')).toBe('30');
|
||||
expect(slices.eq(3).attr('ct:value')).toBe('40');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user