Compare commits

...

97 Commits

Author SHA1 Message Date
Soham Kulkarni
d8ae43fac6
fix: rollup to generate css file with proper name (#427) 2025-03-27 20:05:28 +05:30
Faris Ansari
0ee7f9a30f v2.0.0-rc25 2025-03-26 14:08:59 +05:30
Faris Ansari
4967fc9e07 chore: update scss plugin 2025-03-26 14:04:57 +05:30
Soham Kulkarni
8cc3b45c18
chore: add correct build step (#426) 2025-03-26 13:58:07 +05:30
Soham Kulkarni
bd77462d01
chore: add build step in ci (#425) 2025-03-26 13:24:04 +05:30
Faris Ansari
17994abb92 chore: there are no tests 2025-03-25 20:05:18 +05:30
Faris Ansari
77cc7fde6c chore: add publish workflow 2025-03-25 20:04:06 +05:30
Soham Kulkarni
dc6ef83a7b
fix: make series label space ratio configurable (#424) 2025-03-25 19:55:03 +05:30
Arjun
f5fc2c1bf7
Merge pull request #390 from kimsreng/v2-beta
Fixed: Unrecognized falsy value of truncateLegends
2022-11-15 16:55:22 +05:30
Shivam Mishra
b6403b83c3
chore: update rc version 2022-11-14 12:47:46 +05:30
Shivam Mishra
2e3011c267
feat: allow more attributes in formatY (#401) 2022-11-14 12:33:03 +05:30
kimsreng
2aab8dd315
Fixed: Unrecognized falsy value of truncateLegends 2022-07-22 16:46:00 +07:00
Suraj Shetty
ea95aece5a chore: Bump version to fix faulty publish 2022-07-18 14:22:08 +05:30
Suraj Shetty
f2d2eb1e9e chore: bump version 2022-07-18 14:21:41 +05:30
Ankush Menat
2b455e95a6
Merge pull request #388 from frappe/custom_number_shortner
feat: custom number formatter function
2022-07-18 11:06:07 +05:30
Ankush Menat
624cf70f03 feat: custom number formatter function
You can now pass `numberFormatter` in `axisOptions` to customize
number shortening behaviour.

The interface for this function is pretty simple

```javascript
(value) => {
    // format value
    return value
};
```
2022-07-15 16:35:29 +05:30
Ankush Menat
5ea1d33fdf chore: add editorconfig 2022-07-15 16:28:30 +05:30
Shivam Mishra
46191e7a53 chore: upgrade can I use 2021-09-21 05:59:22 +00:00
Shivam Mishra
95a19f09a3 chore: bump version 2021-09-21 05:57:59 +00:00
Shivam Mishra
8bc8231b21 fix: imports 2021-09-21 05:56:27 +00:00
Shivam Mishra
c18c076adc chore: bump to rc19 2021-06-16 10:53:17 +00:00
Shivam Mishra
a765508bbd chore: bump to rc18 2021-06-16 10:49:01 +00:00
Shivam Mishra
cdf5fbe33b feat: better regionFill gradients 2021-06-16 10:48:38 +00:00
Shivam Mishra
a26a81c866 fix: style issue with dots 2021-06-03 09:39:49 +00:00
Shivam Mishra
f19d15f112 chore: bump version 2021-06-03 09:24:12 +00:00
Shivam Mishra
07597ebe87 feat: add trailingDot option 2021-06-03 09:08:57 +00:00
Shivam Mishra
9c0ecc89be chore: bump to rc15 2021-05-07 09:43:05 +00:00
Shivam Mishra
3d6a349425 fix: range clipping logic 2021-05-07 09:42:45 +00:00
Shivam Mishra
ce4126b3b1 chore: bump to rc14 2021-05-07 08:49:14 +00:00
Shivam Mishra
f145d6bbe9 fix: allow option to disable entry animation 2021-05-07 08:47:33 +00:00
Shivam Mishra
b7f20aab15 feat: allow clipping yAxis range 2021-05-07 08:34:50 +00:00
Shivam Mishra
7c9cf65385 refactor: remove space before shortened number 2021-05-07 08:31:08 +00:00
T3cH_W1z4rD
61717aee95 Fixed XSS (#339) 2021-05-07 08:27:54 +00:00
Shivam Mishra
304d23502a chore: bump to rc13 2021-04-18 11:47:31 +00:00
Shivam Mishra
db12dcf27c fix: path building error 2021-04-18 11:35:44 +00:00
Shivam Mishra
1b4e206a1e fix: chart labels spacing issue 2021-04-18 11:10:36 +00:00
Shivam Mishra
8d8096869f chore: bump to rc12 2021-04-18 10:39:44 +00:00
Shivam Mishra
fa559cc8bd fix: donut chart, single data point bug 2021-04-18 10:39:21 +00:00
Shivam Mishra
ed8f97efd5 feat: add resize observer 2021-04-18 10:28:18 +00:00
Suraj Shetty
8d68d9933e chore: Bump version to v2.0.0-rc11 2021-03-19 14:15:42 +05:30
prssanna
72d5507c6f chore: bump to rc10 2021-03-09 16:56:18 +05:30
prssanna
d6ab5b952e fix: name.replace exception 2021-03-09 14:03:02 +05:30
Shivam Mishra
4854591a89 chore: bump to rc9 2021-02-24 10:20:50 +00:00
Shivam Mishra
a0265677a2 fix: clone in update 2021-02-24 10:19:59 +00:00
Shivam Mishra
ba0d3703f5 chore: bump to rc8 2021-02-22 03:23:51 +00:00
Shivam Mishra
bbe91840f7 chore: update export 2021-02-22 03:20:59 +00:00
Shivam Mishra
94a7e02d75 chore: bump to rc7 2021-02-22 03:18:51 +00:00
Shivam Mishra
d8984ec5ae feat: allow setting lineType for yMarker 2021-02-22 03:18:14 +00:00
Shivam Mishra
067f5ea7f8 feat: allow hiding legends 2021-02-22 03:17:07 +00:00
Shivam Mishra
263f38c9ec chore: bump to rc6 2021-02-18 10:55:43 +00:00
Shivam Mishra
7e13f81063 feat: clone options before building 2021-02-18 10:54:33 +00:00
Suraj Shetty
9cc7bde398 chore: Bump version to rc5 2021-02-02 12:30:29 +05:30
prssanna
ce64f01a8b fix: import round function 2021-01-28 16:24:47 +05:30
Shivam Mishra
583d82a96e chore: build rc3 2020-12-15 16:38:44 +05:30
Shivam Mishra
8308b9fd90 feat: default to css vars in makeText 2020-12-15 16:37:13 +05:30
Shivam Mishra
f413c75932 chore: build rc2 for v2 2020-12-15 16:08:28 +05:30
Shivam Mishra
86bbb6d2aa chore: remove base font-fill 2020-12-15 16:07:49 +05:30
Shivam Mishra
d386d21e2f chore: build rc1 for v2 2020-12-14 16:36:40 +05:30
Shivam Mishra
8101b1822e fix: remove duplicate function 2020-12-14 15:32:42 +05:30
Shivam Mishra
cff7ce4c27 feat: add deepsource 2020-12-14 15:25:39 +05:30
Shivam Mishra
690a7f4467 refactor: validate y 2020-12-14 15:25:39 +05:30
Shivam Mishra
03f6436be4 feat: update variables 2020-12-14 15:25:39 +05:30
Shivam Mishra
8524e6cbd6 feat: allow custom yRegion colors 2020-12-14 15:25:39 +05:30
Shivam Mishra
1181660ed1 chore: remove console.log 2020-12-14 15:25:39 +05:30
Shivam Mishra
26671b143b chore: format codebase 2020-12-14 15:25:39 +05:30
Shivam Mishra
5d2c141f14 fix: floating point rounding fixes 2020-12-14 15:25:39 +05:30
Shivam Mishra
e2d7ce8b21 feat: allow stroke color for yMarker 2020-12-14 15:25:39 +05:30
Shivam Mishra
73f1d9b1e3 feat: DonutChart extends PieChart 2020-12-14 15:25:39 +05:30
Shivam Mishra
dc00b46a7a chore: format donut chart and pie chart 2020-12-14 15:25:39 +05:30
Shivam Mishra
fd28107795 chore: remove unused import 2020-12-14 15:25:39 +05:30
Shivam Mishra
7cfa35a418 feat: new legends
* merge legendBar and legendDots
* use BaseChart to render legends
2020-12-14 15:25:20 +05:30
Shivam Mishra
d84614cb65 feat: update legendBar 2020-12-14 15:25:20 +05:30
Shivam Mishra
610cfb1f6d feat: update main in package.json 2020-12-14 15:25:20 +05:30
Shivam Mishra
767a905967 feat: remove deprecated MultiAxis 2020-12-14 15:25:20 +05:30
Shivam Mishra
56a7374277 chore: formatting improvements 2020-12-14 15:25:20 +05:30
Shivam Mishra
562a9cba55 chore: update tooltip styles
* max-width for tooltip label
* remove ellipsis
* use normal white-space wrapping
2020-12-14 15:25:20 +05:30
Shivam Mishra
4f4dd4d36f chore: remove dist 2020-12-14 15:25:20 +05:30
Shivam Mishra
0257bc370e feat: ignore dist 2020-12-14 15:25:08 +05:30
Shivam Mishra
7dde276477 feat: generate es 2020-12-14 15:25:08 +05:30
Shivam Mishra
b12b916584 chore: update build 2020-12-14 15:25:08 +05:30
Shivam Mishra
a7b06bb027 feat: change axis line colors 2020-12-14 15:25:08 +05:30
Shivam Mishra
9dd24aa7a7 feat: don't override axis line colors 2020-12-14 15:25:08 +05:30
Shivam Mishra
4d8321e9be feat: always show last label when xIsSeries is toggled 2020-12-14 15:25:08 +05:30
Shivam Mishra
399ff37b6a feat: add space ratio option for x-axis series labels 2020-12-14 15:25:08 +05:30
Shivam Mishra
dc49b29d39 feat: [breaking] hide dots by default 2020-12-14 15:25:08 +05:30
Shivam Mishra
51a6ed33a5 feat: update opacity for light gradient 2020-12-14 15:25:08 +05:30
Shivam Mishra
f8c3f9d7b4 chore: reset space ratio 2020-12-14 15:25:08 +05:30
Shivam Mishra
d3909d49c1 feat: added function for rounded top rect 2020-12-14 15:25:08 +05:30
Shivam Mishra
255e806533 chore: cleanup rounded bar utility 2020-12-14 15:25:08 +05:30
Shivam Mishra
6cb9bf6bd3 chore: update build 2020-12-14 15:25:08 +05:30
Shivam Mishra
5e17dea6de feat: tune spacing for legends 2020-12-14 15:25:08 +05:30
Shivam Mishra
89fc842330 feat: update build 2020-12-14 15:25:08 +05:30
Shivam Mishra
63e0a0bdf4 feat: generate sourcemaps inn build 2020-12-14 15:25:08 +05:30
Shivam Mishra
d2dd27dfab feat: added helper function for rounded edges 2020-12-14 15:25:08 +05:30
Shivam Mishra
846a21ae6a feat: remove depth for percentage chart 2020-12-14 15:25:08 +05:30
Shivam Mishra
5b00da4974 chore: remove docs folder 2020-12-14 15:25:08 +05:30
Shivam Mishra
069a5f7451 feat: show bundle size 2020-12-14 15:24:41 +05:30
56 changed files with 1738 additions and 13804 deletions

9
.deepsource.toml Normal file
View File

@ -0,0 +1,9 @@
version = 1
[[analyzers]]
name = "javascript"
enabled = true
[analyzers.meta]
environment = ["browser"]
style_guide = "standard"

14
.editorconfig Normal file
View File

@ -0,0 +1,14 @@
# Root editor config file
root = true
# Common settings
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
# indentation settings
[{*.js,*.css,*.html}]
indent_style = tab
indent_size = 4

19
.github/workflows/publish.yml vendored Normal file
View File

@ -0,0 +1,19 @@
name: Publish on NPM
on:
push:
branches: [ v2-beta ]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: 20
- run: npm install
- run: npm run build
- uses: JS-DevTools/npm-publish@v3
with:
token: ${{ secrets.NPM_TOKEN }}
tag: next

3
.gitignore vendored
View File

@ -60,4 +60,7 @@ typings/
# next.js build output
.next
# npm build output
dist
.DS_Store

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,104 +0,0 @@
.chart-container {
position: relative;
/* for absolutely positioned tooltip */
/* https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/ */
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; }
.chart-container .axis, .chart-container .chart-label {
fill: #313B44; }
.chart-container .axis line, .chart-container .chart-label line {
stroke: #E2E6E9; }
.chart-container .dataset-units circle {
stroke: #fff;
stroke-width: 2; }
.chart-container .dataset-units path {
fill: none;
stroke-opacity: 1;
stroke-width: 2px; }
.chart-container .dataset-path {
stroke-width: 2px; }
.chart-container .path-group path {
fill: none;
stroke-opacity: 1;
stroke-width: 2px; }
.chart-container line.dashed {
stroke-dasharray: 5, 3; }
.chart-container .axis-line .specific-value {
text-anchor: start; }
.chart-container .axis-line .y-line {
text-anchor: end; }
.chart-container .axis-line .x-line {
text-anchor: middle; }
.chart-container .legend-dataset-text {
fill: #6c7680;
font-weight: 600; }
.graph-svg-tip {
position: absolute;
z-index: 99999;
padding: 10px;
font-size: 12px;
text-align: center;
background: #FFFFFF;
box-shadow: 0px 1px 4px rgba(17, 43, 66, 0.1), 0px 2px 6px rgba(17, 43, 66, 0.08), 0px 40px 30px -30px rgba(17, 43, 66, 0.1);
border-radius: 6px; }
.graph-svg-tip ul {
padding-left: 0;
display: flex; }
.graph-svg-tip ol {
padding-left: 0;
display: flex; }
.graph-svg-tip ul.data-point-list li {
min-width: 90px;
font-weight: 600; }
.graph-svg-tip .svg-pointer {
position: absolute;
height: 12px;
width: 12px;
border-radius: 2px;
background: white;
transform: rotate(45deg);
margin-top: -7px;
margin-left: -6px; }
.graph-svg-tip.comparison {
text-align: left;
padding: 0px;
pointer-events: none; }
.graph-svg-tip.comparison .title {
display: block;
padding: 16px;
margin: 0;
color: #313B44;
font-weight: 600;
line-height: 1;
pointer-events: none;
text-transform: uppercase; }
.graph-svg-tip.comparison ul {
margin: 0;
white-space: nowrap;
list-style: none; }
.graph-svg-tip.comparison ul.tooltip-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 5px; }
.graph-svg-tip.comparison li {
display: inline-block;
display: flex;
flex-direction: row;
font-weight: 600;
line-height: 1;
padding: 5px 15px 15px 15px; }
.graph-svg-tip.comparison li .tooltip-legend {
height: 12px;
width: 12px;
margin-right: 8px;
border-radius: 2px; }
.graph-svg-tip.comparison li .tooltip-label {
margin-top: 4px;
font-size: 11px;
max-width: 100px;
color: #313B44;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; }
.graph-svg-tip.comparison li .tooltip-value {
color: #192734; }

File diff suppressed because one or more lines are too long

View File

@ -1,2 +0,0 @@
plugins:
- jekyll-redirect-from

File diff suppressed because one or more lines are too long

View File

@ -1,99 +0,0 @@
/*
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
*/
.hljs {
display: block;
color: #36414c;
overflow-x: auto;
padding: 0.5em;
background: #F8F8F9;
border-radius: 3px;
}
.hljs-comment,
.hljs-quote {
color: #998;
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-subst {
color: #333;
font-weight: bold;
}
.hljs-number,
.hljs-literal,
.hljs-variable,
.hljs-template-variable,
.hljs-tag .hljs-attr {
color: #008080;
}
.hljs-string,
.hljs-doctag {
color: #d14;
}
.hljs-title,
.hljs-section,
.hljs-selector-id {
color: #900;
font-weight: bold;
}
.hljs-subst {
font-weight: normal;
}
.hljs-type,
.hljs-class .hljs-title {
color: #458;
font-weight: bold;
}
.hljs-tag,
.hljs-name,
.hljs-attribute {
color: #000080;
font-weight: normal;
}
.hljs-regexp,
.hljs-link {
color: #009926;
}
.hljs-symbol,
.hljs-bullet {
color: #990073;
}
.hljs-built_in,
.hljs-builtin-name {
color: #0086b3;
}
.hljs-meta {
color: #999;
font-weight: bold;
}
.hljs-deletion {
background: #fdd;
}
.hljs-addition {
background: #dfd;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@ -1,110 +0,0 @@
body {
/* container styles */
max-width: 720px;
margin: auto;
font-family: "proxima-nova", sans-serif;
font-size: 15px;
color: #6c7680;
text-rendering: optimizeLegibility !important;
line-height: 1.5em;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
}
h1,
h2,
h3,
h4,
h5,
h6,
.lead,
.page-sidebar,
.breadcrumb,
.label,
.h6,
.sans,
blockquote {
font-family: "proxima-nova", sans-serif;
color: #36414C;
}
header {
margin: 4rem 0; /* SAME 1 */
font-size: 1.6em;
font-weight: 300;
text-align: center;
}
header .lead-text {
line-height: 3rem;
margin: 2rem 0;
}
.demo-tip {
margin-top: 1rem; /* SAME 2 */
font-size: 1rem;
}
section {
margin: 4em 0; /* SAME 1 */
}
h1 {
font-size: 3.5rem;
margin-bottom: 1.5rem;
}
h1, h6 {
font-weight: 700;
}
.btn {
outline: none !important;
}
.blue.button {
color: #fff;
background: #7575ff;
border: 0px;
border-bottom: 3px solid rgba(0, 0, 0, 0.2);
}
.blue.button:hover {
background: #5b5be5;
}
.large.button {
font-size: 1.33em;
padding: 12px 24px 10px;
border-bottom: 3px solid rgba(0, 0, 0, 0.2);
}
a {
color: #5E64FF;
}
a, a:focus, a:hover {
transition: color 0.3s, border 0.3s, background-color 0.3s;
}
/* BaseCSS */
.margin-top {
margin-top: 1rem; /* SAME 2 */
}
.mv1 {
margin: 2em 0 1em 0;
}
.border {
border: 1px solid #ddd;
border-radius: 3px;
}
/* Moon images */
.image-container {
padding: 3px;
}
.image-container img{
display: block;
width: 100%;
}
.content-data p {
margin-bottom: 5px;
font-size: 12px;
}
.text-center {
text-align: center;
}

View File

@ -1,353 +0,0 @@
/*!
*this reset is a copy of bootstrap's reboot.css which is inturn a fork of normalise*
* Bootstrap Reboot v4.0.0-beta.3 (https://getbootstrap.com)
* Copyright 2011-2017 The Bootstrap Authors
* Copyright 2011-2017 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-family: sans-serif;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-ms-overflow-style: scrollbar;
-webkit-tap-highlight-color: transparent;
--line-height: 3;
line-height: calc(((var(--line-height) * var(--capital-height)) - var(--valign)) * 1px);
}
@-ms-viewport {
width: device-width;
}
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
display: block;
}
body {
margin: 0;
font-size: 1em;
font-weight: 400;
/* line-height: 1.5; */
text-align: left;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, Noto, Oxygen-Sans, "Noto Sans", Ubuntu,Cantarell, sans-serif, "Apple Color Emoji", "Noto Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
color: #36414c;
font-weight:normal;
-webkit-text-size-adjust: 100%;
-webkit-font-feature-settings: "kern" 1;
-moz-font-feature-settings: "kern" 1;
-o-font-feature-settings: "kern" 1;
font-feature-settings: "kern" 1;
font-kerning: normal;
text-rendering: optimizeLegibility;
}
[tabindex="-1"]:focus {
outline: 0 !important;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 1.6rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-original-title] {
text-decoration: underline;
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
border-bottom: 0;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: .5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
dfn {
font-style: italic;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 80%;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}
a {
color: #007bff;
text-decoration: none;
background-color: transparent;
-webkit-text-decoration-skip: objects;
}
a:hover {
color: #0056b3;
text-decoration: underline;
}
a:not([href]):not([tabindex]) {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus, a:not([href]):not([tabindex]):hover {
color: inherit;
text-decoration: none;
}
a:not([href]):not([tabindex]):focus {
outline: 0;
}
pre,
code,
kbd,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
pre {
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
-ms-overflow-style: scrollbar;
}
figure {
margin: 0 0 1rem;
}
img {
vertical-align: middle;
border-style: none;
}
svg:not(:root) {
overflow: hidden;
}
a,
area,
button,
[role="button"],
input:not([type="range"]),
label,
select,
summary,
textarea {
-ms-touch-action: manipulation;
touch-action: manipulation;
}
table {
border-collapse: collapse;
}
caption {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
color: #6c757d;
text-align: left;
caption-side: bottom;
}
th {
text-align: inherit;
}
label {
display: inline-block;
margin-bottom: .5rem;
}
button {
border-radius: 0;
}
button:focus {
outline: 1px dotted;
outline: 5px auto -webkit-focus-ring-color;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html [type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
padding: 0;
border-style: none;
}
input[type="radio"],
input[type="checkbox"] {
box-sizing: border-box;
padding: 0;
}
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"] {
-webkit-appearance: listbox;
}
textarea {
overflow: auto;
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
display: block;
width: 100%;
max-width: 100%;
padding: 0;
margin-bottom: .5rem;
font-size: 1.5rem;
line-height: inherit;
color: inherit;
white-space: normal;
}
progress {
vertical-align: baseline;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
outline-offset: -2px;
-webkit-appearance: none;
}
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
summary {
display: list-item;
cursor: pointer;
}
template {
display: none;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,278 +0,0 @@
import { MONTH_NAMES_SHORT } from "../../../src/js/utils/date-utils";
// Composite Chart
// ================================================================================
const reportCountList = [
152,
222,
199,
287,
534,
709,
1179,
1256,
1632,
1856,
1850,
];
export const lineCompositeData = {
labels: [
"2007",
"2008",
"2009",
"2010",
"2011",
"2012",
"2013",
"2014",
"2015",
"2016",
"2017",
],
yMarkers: [
{
label: "Average 100 reports/month",
value: 1200,
options: { labelPos: "left" },
},
],
datasets: [
{
name: "Events",
values: reportCountList,
},
],
};
export const fireball_5_25 = [
[4, 0, 3, 1, 1, 2, 1, 1, 1, 0, 1, 1],
[2, 3, 3, 2, 1, 3, 0, 1, 2, 7, 10, 4],
[5, 6, 2, 4, 0, 1, 4, 3, 0, 2, 0, 1],
[0, 2, 6, 2, 1, 1, 2, 3, 6, 3, 7, 8],
[6, 8, 7, 7, 4, 5, 6, 5, 22, 12, 10, 11],
[7, 10, 11, 7, 3, 2, 7, 7, 11, 15, 22, 20],
[13, 16, 21, 18, 19, 17, 12, 17, 31, 28, 25, 29],
[24, 14, 21, 14, 11, 15, 19, 21, 41, 22, 32, 18],
[31, 20, 30, 22, 14, 17, 21, 35, 27, 50, 117, 24],
[32, 24, 21, 27, 11, 27, 43, 37, 44, 40, 48, 32],
[31, 38, 36, 26, 23, 23, 25, 29, 26, 47, 61, 50],
];
export const fireball_2_5 = [
[22, 6, 6, 9, 7, 8, 6, 14, 19, 10, 8, 20],
[11, 13, 12, 8, 9, 11, 9, 13, 10, 22, 40, 24],
[20, 13, 13, 19, 13, 10, 14, 13, 20, 18, 5, 9],
[7, 13, 16, 19, 12, 11, 21, 27, 27, 24, 33, 33],
[38, 25, 28, 22, 31, 21, 35, 42, 37, 32, 46, 53],
[50, 33, 36, 34, 35, 28, 27, 52, 58, 59, 75, 69],
[54, 67, 67, 45, 66, 51, 38, 64, 90, 113, 116, 87],
[84, 52, 56, 51, 55, 46, 50, 87, 114, 83, 152, 93],
[73, 58, 59, 63, 56, 51, 83, 140, 103, 115, 265, 89],
[106, 95, 94, 71, 77, 75, 99, 136, 129, 154, 168, 156],
[81, 102, 95, 72, 58, 91, 89, 122, 124, 135, 183, 171],
];
export const fireballOver25 = [
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
[1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2],
[3, 2, 1, 3, 2, 0, 2, 2, 2, 3, 0, 1],
[2, 3, 5, 2, 1, 3, 0, 2, 3, 5, 1, 4],
[7, 4, 6, 1, 9, 2, 2, 2, 20, 9, 4, 9],
[5, 6, 1, 2, 5, 4, 5, 5, 16, 9, 14, 9],
[5, 4, 7, 5, 1, 5, 3, 3, 5, 7, 22, 2],
[5, 13, 11, 6, 1, 7, 9, 8, 14, 17, 16, 3],
[8, 9, 8, 6, 4, 8, 5, 6, 14, 11, 21, 12],
];
export const barCompositeData = {
labels: MONTH_NAMES_SHORT,
datasets: [
{
name: "Over 25 reports",
values: fireballOver25[9],
},
{
name: "5 to 25 reports",
values: fireball_5_25[9],
},
{
name: "2 to 5 reports",
values: fireball_2_5[9],
},
],
};
// Demo Chart multitype Chart
// ================================================================================
export const typeData = {
labels: [
"12am-3am",
"3am-6am",
"6am-9am",
"9am-12pm",
"12pm-3pm",
"3pm-6pm",
"6pm-9pm",
"9pm-12am",
],
yMarkers: [
{
label: "Marker",
value: 43,
options: { labelPos: "left" },
// type: 'dashed'
},
],
yRegions: [
{
label: "Region",
start: -10,
end: 50,
options: { labelPos: "right" },
},
],
datasets: [
{
name: "Some Data",
values: [18, 40, 30, 35, 8, 52, 17, -4],
axisPosition: "right",
chartType: "bar",
},
{
name: "Another Set",
values: [30, 50, -10, 15, 18, 32, 27, 14],
axisPosition: "right",
chartType: "bar",
},
{
name: "Yet Another",
values: [15, 20, -3, -15, 58, 12, -17, 37],
chartType: "line",
},
],
};
export const trendsData = {
labels: [
1967,
1968,
1969,
1970,
1971,
1972,
1973,
1974,
1975,
1976,
1977,
1978,
1979,
1980,
1981,
1982,
1983,
1984,
1985,
1986,
1987,
1988,
1989,
1990,
1991,
1992,
1993,
1994,
1995,
1996,
1997,
1998,
1999,
2000,
2001,
2002,
2003,
2004,
2005,
2006,
2007,
2008,
2009,
2010,
2011,
2012,
2013,
2014,
2015,
2016,
],
datasets: [
{
values: [
132.9,
150.0,
149.4,
148.0,
94.4,
97.6,
54.1,
49.2,
22.5,
18.4,
39.3,
131.0,
220.1,
218.9,
198.9,
162.4,
91.0,
60.5,
20.6,
14.8,
33.9,
123.0,
211.1,
191.8,
203.3,
133.0,
76.1,
44.9,
25.1,
11.6,
28.9,
88.3,
136.3,
173.9,
170.4,
163.6,
99.3,
65.3,
45.8,
24.7,
12.6,
4.2,
4.8,
24.9,
80.8,
84.5,
94.0,
113.3,
69.8,
39.8,
],
},
],
};
export const moonData = {
names: ["Ganymede", "Callisto", "Io", "Europa"],
masses: [14819000, 10759000, 8931900, 4800000],
distances: [1070.412, 1882.709, 421.7, 671.034],
diameters: [5262.4, 4820.6, 3637.4, 3121.6],
};

View File

@ -1,55 +0,0 @@
import { lineCompositeData, barCompositeData } from './data';
export default {
lineComposite: {
elementID: "#chart-composite-1",
options: {
title: "Fireball/Bolide Events - Yearly (reported)",
data: lineCompositeData,
type: "line",
height: 190,
colors: ["green"],
isNavigable: 1,
valuesOverPoints: 1,
lineOptions: {
dotSize: 8
}
}
},
barComposite: {
elementID: "#chart-composite-2",
options: {
data: barCompositeData,
type: "bar",
height: 210,
colors: ["violet", "light-blue", "#46a9f9"],
valuesOverPoints: 1,
axisOptions: {
xAxisMode: "tick",
shortenYAxisNumbers: true
},
barOptions: {
stacked: 1
}
}
},
demoMain: {
elementID: "",
options: {
title: "My Awesome Chart",
data: "typeData",
type: "axis-mixed",
height: 300,
colors: ["purple", "magenta", "light-blue"],
maxSlices: 10,
tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' pts',
}
}
}
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,375 +0,0 @@
import { shuffle, getRandomBias } from '../../../src/js/utils/helpers';
import { HEATMAP_COLORS_YELLOW, HEATMAP_COLORS_BLUE } from '../../../src/js/utils/constants';
import { SEC_IN_DAY, clone, timestampToMidnight, timestampSec, addDays } from '../../../src/js/utils/date-utils';
/* eslint-disable no-unused-vars */
import { fireballOver25, fireball_2_5, fireball_5_25, lineCompositeData,
barCompositeData, typeData, trendsData, moonData } from './data';
/* eslint-enable no-unused-vars */
import demoConfig from './demoConfig';
// import { lineComposite, barComposite } from './demoConfig';
// ================================================================================
let Chart = frappe.Chart; // eslint-disable-line no-undef
let lc = demoConfig.lineComposite;
let lineCompositeChart = new Chart (lc.elementID, lc.options);
let bc = demoConfig.barComposite;
let barCompositeChart = new Chart (bc.elementID, bc.options);
lineCompositeChart.parent.addEventListener('data-select', (e) => {
let i = e.index;
barCompositeChart.updateDatasets([
fireballOver25[i], fireball_5_25[i], fireball_2_5[i]
]);
});
// ================================================================================
let customColors = ['purple', 'magenta', 'light-blue'];
let typeChartArgs = {
title: "My Awesome Chart",
data: typeData,
type: 'axis-mixed',
height: 300,
colors: customColors,
// maxLegendPoints: 6,
maxSlices: 10,
tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' pts',
}
};
let aggrChart = new Chart("#chart-aggr", typeChartArgs);
Array.prototype.slice.call(
document.querySelectorAll('.aggr-type-buttons button')
).map(el => {
el.addEventListener('click', (e) => {
let btn = e.target;
let type = btn.getAttribute('data-type');
typeChartArgs.type = type;
if(type !== 'axis-mixed') {
typeChartArgs.colors = undefined;
} else {
typeChartArgs.colors = customColors;
}
if(type !== 'percentage') {
typeChartArgs.height = 300;
} else {
typeChartArgs.height = undefined;
}
let newChart = new Chart("#chart-aggr", typeChartArgs);
if(newChart){
aggrChart = newChart;
}
Array.prototype.slice.call(
btn.parentNode.querySelectorAll('button')).map(el => {
el.classList.remove('active');
});
btn.classList.add('active');
});
});
document.querySelector('.export-aggr').addEventListener('click', () => {
aggrChart.export();
});
// Update values chart
// ================================================================================
let updateDataAllLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue",
"Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
"Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon"];
let getRandom = () => Math.floor(getRandomBias(-40, 60, 0.8, 1));
let updateDataAllValues = Array.from({length: 30}, getRandom);
// We're gonna be shuffling this
let updateDataAllIndices = updateDataAllLabels.map((d,i) => i);
let getUpdateData = (source_array, length=10) => {
let indices = updateDataAllIndices.slice(0, length);
return indices.map((index) => source_array[index]);
};
let updateData = {
labels: getUpdateData(updateDataAllLabels),
datasets: [{
"values": getUpdateData(updateDataAllValues)
}],
yMarkers: [
{
label: "Altitude",
value: 25,
type: 'dashed'
}
],
yRegions: [
{
label: "Range",
start: 10,
end: 45
},
],
};
let updateChart = new Chart("#chart-update", {
data: updateData,
type: 'line',
height: 300,
colors: ['#ff6c03'],
lineOptions: {
// hideLine: 1,
regionFill: 1
},
});
let chartUpdateButtons = document.querySelector('.chart-update-buttons');
chartUpdateButtons.querySelector('[data-update="random"]').addEventListener("click", () => {
shuffle(updateDataAllIndices);
let value = getRandom();
let start = getRandom();
let end = getRandom();
let data = {
labels: updateDataAllLabels.slice(0, 10),
datasets: [{values: getUpdateData(updateDataAllValues)}],
yMarkers: [
{
label: "Altitude",
value: value,
type: 'dashed'
}
],
yRegions: [
{
label: "Range",
start: start,
end: end
},
],
};
updateChart.update(data);
});
chartUpdateButtons.querySelector('[data-update="add"]').addEventListener("click", () => {
let index = updateChart.state.datasetLength; // last index to add
if(index >= updateDataAllIndices.length) return;
updateChart.addDataPoint(
updateDataAllLabels[index], [updateDataAllValues[index]]
);
});
chartUpdateButtons.querySelector('[data-update="remove"]').addEventListener("click", () => {
updateChart.removeDataPoint();
});
document.querySelector('.export-update').addEventListener('click', () => {
updateChart.export();
});
// Trends Chart
// ================================================================================
let plotChartArgs = {
title: "Mean Total Sunspot Count - Yearly",
data: trendsData,
type: 'line',
height: 300,
colors: ['#238e38'],
lineOptions: {
hideDots: 1,
heatline: 1,
},
axisOptions: {
xAxisMode: 'tick',
yAxisMode: 'span',
xIsSeries: 1
}
};
let trendsChart = new Chart("#chart-trends", plotChartArgs);
Array.prototype.slice.call(
document.querySelectorAll('.chart-plot-buttons button')
).map(el => {
el.addEventListener('click', (e) => {
let btn = e.target;
let type = btn.getAttribute('data-type');
let config = {};
config[type] = 1;
if(['regionFill', 'heatline'].includes(type)) {
config.hideDots = 1;
}
// plotChartArgs.init = false;
plotChartArgs.lineOptions = config;
new Chart("#chart-trends", plotChartArgs);
Array.prototype.slice.call(
btn.parentNode.querySelectorAll('button')).map(el => {
el.classList.remove('active');
});
btn.classList.add('active');
});
});
document.querySelector('.export-trends').addEventListener('click', () => {
trendsChart.export();
});
// Event chart
// ================================================================================
let eventsData = {
labels: ["Ganymede", "Callisto", "Io", "Europa"],
datasets: [
{
"values": moonData.distances,
"formatted": moonData.distances.map(d => d*1000 + " km")
}
]
};
let eventsChart = new Chart("#chart-events", {
title: "Jupiter's Moons: Semi-major Axis (1000 km)",
data: eventsData,
type: 'bar',
height: 330,
colors: ['grey'],
isNavigable: 1,
});
let dataDiv = document.querySelector('.chart-events-data');
eventsChart.parent.addEventListener('data-select', (e) => {
let name = moonData.names[e.index];
dataDiv.querySelector('.moon-name').innerHTML = name;
dataDiv.querySelector('.semi-major-axis').innerHTML = moonData.distances[e.index] * 1000;
dataDiv.querySelector('.mass').innerHTML = moonData.masses[e.index];
dataDiv.querySelector('.diameter').innerHTML = moonData.diameters[e.index];
dataDiv.querySelector('img').src = "./assets/img/" + name.toLowerCase() + ".jpg";
});
// Heatmap
// ================================================================================
let today = new Date();
let start = clone(today);
addDays(start, 4);
let end = clone(start);
start.setFullYear( start.getFullYear() - 2 );
end.setFullYear( end.getFullYear() - 1 );
let dataPoints = {};
let startTs = timestampSec(start);
let endTs = timestampSec(end);
startTs = timestampToMidnight(startTs);
endTs = timestampToMidnight(endTs, true);
while (startTs < endTs) {
dataPoints[parseInt(startTs)] = Math.floor(getRandomBias(0, 5, 0.2, 1));
startTs += SEC_IN_DAY;
}
const heatmapData = {
dataPoints: dataPoints,
start: start,
end: end
};
let heatmapArgs = {
title: "Monthly Distribution",
data: heatmapData,
type: 'heatmap',
discreteDomains: 1,
countLabel: 'Level',
colors: HEATMAP_COLORS_BLUE,
legendScale: [0, 1, 2, 4, 5]
};
let heatmapChart = new Chart("#chart-heatmap", heatmapArgs);
Array.prototype.slice.call(
document.querySelectorAll('.heatmap-mode-buttons button')
).map(el => {
el.addEventListener('click', (e) => {
let btn = e.target;
let mode = btn.getAttribute('data-mode');
let discreteDomains = 0;
if(mode === 'discrete') {
discreteDomains = 1;
}
let colors = [];
let colors_mode = document
.querySelector('.heatmap-color-buttons .active')
.getAttribute('data-color');
if(colors_mode === 'halloween') {
colors = HEATMAP_COLORS_YELLOW;
} else if (colors_mode === 'blue') {
colors = HEATMAP_COLORS_BLUE;
}
heatmapArgs.discreteDomains = discreteDomains;
heatmapArgs.colors = colors;
new Chart("#chart-heatmap", heatmapArgs);
Array.prototype.slice.call(
btn.parentNode.querySelectorAll('button')).map(el => {
el.classList.remove('active');
});
btn.classList.add('active');
});
});
Array.prototype.slice.call(
document.querySelectorAll('.heatmap-color-buttons button')
).map(el => {
el.addEventListener('click', (e) => {
let btn = e.target;
let colors_mode = btn.getAttribute('data-color');
let colors = [];
if(colors_mode === 'halloween') {
colors = HEATMAP_COLORS_YELLOW;
} else if (colors_mode === 'blue') {
colors = HEATMAP_COLORS_BLUE;
}
let discreteDomains = 1;
let view_mode = document
.querySelector('.heatmap-mode-buttons .active')
.getAttribute('data-mode');
if(view_mode === 'continuous') {
discreteDomains = 0;
}
heatmapArgs.discreteDomains = discreteDomains;
heatmapArgs.colors = colors;
new Chart("#chart-heatmap", heatmapArgs);
Array.prototype.slice.call(
btn.parentNode.querySelectorAll('button')).map(el => {
el.classList.remove('active');
});
btn.classList.add('active');
});
});
document.querySelector('.export-heatmap').addEventListener('click', () => {
heatmapChart.export();
});

View File

@ -1,648 +0,0 @@
(function () {
'use strict';
// Fixed 5-color theme,
// More colors are difficult to parse visually
var HEATMAP_COLORS_BLUE = ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'];
var HEATMAP_COLORS_YELLOW = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'];
// Universal constants
/**
* Returns the value of a number upto 2 decimal places.
* @param {Number} d Any number
*/
/**
* Returns whether or not two given arrays are equal.
* @param {Array} arr1 First array
* @param {Array} arr2 Second array
*/
/**
* Shuffles array in place. ES6 version
* @param {Array} array An array containing the items.
*/
function shuffle(array) {
// Awesomeness: https://bost.ocks.org/mike/shuffle/
// https://stackoverflow.com/a/2450976/6495043
// https://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array?noredirect=1&lq=1
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var _ref = [array[j], array[i]];
array[i] = _ref[0];
array[j] = _ref[1];
}
return array;
}
/**
* Fill an array with extra points
* @param {Array} array Array
* @param {Number} count number of filler elements
* @param {Object} element element to fill with
* @param {Boolean} start fill at start?
*/
/**
* Returns pixel width of string.
* @param {String} string
* @param {Number} charWidth Width of single char in pixels
*/
// https://stackoverflow.com/a/29325222
function getRandomBias(min, max, bias, influence) {
var range = max - min;
var biasValue = range * bias + min;
var rnd = Math.random() * range + min,
// random in range
mix = Math.random() * influence; // random mixer
return rnd * (1 - mix) + biasValue * mix; // mix full range and bias
}
/**
* Check if a number is valid for svg attributes
* @param {object} candidate Candidate to test
* @param {Boolean} nonNegative flag to treat negative number as invalid
*/
/**
* Round a number to the closes precision, max max precision 4
* @param {Number} d Any Number
*/
// Playing around with dates
var NO_OF_MILLIS = 1000;
var SEC_IN_DAY = 86400;
var MONTH_NAMES_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
function clone(date) {
return new Date(date.getTime());
}
function timestampSec(date) {
return date.getTime() / NO_OF_MILLIS;
}
function timestampToMidnight(timestamp) {
var roundAhead = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var midnightTs = Math.floor(timestamp - timestamp % SEC_IN_DAY);
if (roundAhead) {
return midnightTs + SEC_IN_DAY;
}
return midnightTs;
}
// export function getMonthsBetween(startDate, endDate) {}
// mutates
// mutates
function addDays(date, numberOfDays) {
date.setDate(date.getDate() + numberOfDays);
}
// Composite Chart
// ================================================================================
var reportCountList = [152, 222, 199, 287, 534, 709, 1179, 1256, 1632, 1856, 1850];
var lineCompositeData = {
labels: ["2007", "2008", "2009", "2010", "2011", "2012", "2013", "2014", "2015", "2016", "2017"],
yMarkers: [{
label: "Average 100 reports/month",
value: 1200,
options: { labelPos: "left" }
}],
datasets: [{
name: "Events",
values: reportCountList
}]
};
var fireball_5_25 = [[4, 0, 3, 1, 1, 2, 1, 1, 1, 0, 1, 1], [2, 3, 3, 2, 1, 3, 0, 1, 2, 7, 10, 4], [5, 6, 2, 4, 0, 1, 4, 3, 0, 2, 0, 1], [0, 2, 6, 2, 1, 1, 2, 3, 6, 3, 7, 8], [6, 8, 7, 7, 4, 5, 6, 5, 22, 12, 10, 11], [7, 10, 11, 7, 3, 2, 7, 7, 11, 15, 22, 20], [13, 16, 21, 18, 19, 17, 12, 17, 31, 28, 25, 29], [24, 14, 21, 14, 11, 15, 19, 21, 41, 22, 32, 18], [31, 20, 30, 22, 14, 17, 21, 35, 27, 50, 117, 24], [32, 24, 21, 27, 11, 27, 43, 37, 44, 40, 48, 32], [31, 38, 36, 26, 23, 23, 25, 29, 26, 47, 61, 50]];
var fireball_2_5 = [[22, 6, 6, 9, 7, 8, 6, 14, 19, 10, 8, 20], [11, 13, 12, 8, 9, 11, 9, 13, 10, 22, 40, 24], [20, 13, 13, 19, 13, 10, 14, 13, 20, 18, 5, 9], [7, 13, 16, 19, 12, 11, 21, 27, 27, 24, 33, 33], [38, 25, 28, 22, 31, 21, 35, 42, 37, 32, 46, 53], [50, 33, 36, 34, 35, 28, 27, 52, 58, 59, 75, 69], [54, 67, 67, 45, 66, 51, 38, 64, 90, 113, 116, 87], [84, 52, 56, 51, 55, 46, 50, 87, 114, 83, 152, 93], [73, 58, 59, 63, 56, 51, 83, 140, 103, 115, 265, 89], [106, 95, 94, 71, 77, 75, 99, 136, 129, 154, 168, 156], [81, 102, 95, 72, 58, 91, 89, 122, 124, 135, 183, 171]];
var fireballOver25 = [
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], [1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2], [3, 2, 1, 3, 2, 0, 2, 2, 2, 3, 0, 1], [2, 3, 5, 2, 1, 3, 0, 2, 3, 5, 1, 4], [7, 4, 6, 1, 9, 2, 2, 2, 20, 9, 4, 9], [5, 6, 1, 2, 5, 4, 5, 5, 16, 9, 14, 9], [5, 4, 7, 5, 1, 5, 3, 3, 5, 7, 22, 2], [5, 13, 11, 6, 1, 7, 9, 8, 14, 17, 16, 3], [8, 9, 8, 6, 4, 8, 5, 6, 14, 11, 21, 12]];
var barCompositeData = {
labels: MONTH_NAMES_SHORT,
datasets: [{
name: "Over 25 reports",
values: fireballOver25[9]
}, {
name: "5 to 25 reports",
values: fireball_5_25[9]
}, {
name: "2 to 5 reports",
values: fireball_2_5[9]
}]
};
// Demo Chart multitype Chart
// ================================================================================
var typeData = {
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm", "12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"],
yMarkers: [{
label: "Marker",
value: 43,
options: { labelPos: "left" }
// type: 'dashed'
}],
yRegions: [{
label: "Region",
start: -10,
end: 50,
options: { labelPos: "right" }
}],
datasets: [{
name: "Some Data",
values: [18, 40, 30, 35, 8, 52, 17, -4],
axisPosition: "right",
chartType: "bar"
}, {
name: "Another Set",
values: [30, 50, -10, 15, 18, 32, 27, 14],
axisPosition: "right",
chartType: "bar"
}, {
name: "Yet Another",
values: [15, 20, -3, -15, 58, 12, -17, 37],
chartType: "line"
}]
};
var trendsData = {
labels: [1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016],
datasets: [{
values: [132.9, 150.0, 149.4, 148.0, 94.4, 97.6, 54.1, 49.2, 22.5, 18.4, 39.3, 131.0, 220.1, 218.9, 198.9, 162.4, 91.0, 60.5, 20.6, 14.8, 33.9, 123.0, 211.1, 191.8, 203.3, 133.0, 76.1, 44.9, 25.1, 11.6, 28.9, 88.3, 136.3, 173.9, 170.4, 163.6, 99.3, 65.3, 45.8, 24.7, 12.6, 4.2, 4.8, 24.9, 80.8, 84.5, 94.0, 113.3, 69.8, 39.8]
}]
};
var moonData = {
names: ["Ganymede", "Callisto", "Io", "Europa"],
masses: [14819000, 10759000, 8931900, 4800000],
distances: [1070.412, 1882.709, 421.7, 671.034],
diameters: [5262.4, 4820.6, 3637.4, 3121.6]
};
var demoConfig = {
lineComposite: {
elementID: "#chart-composite-1",
options: {
title: "Fireball/Bolide Events - Yearly (reported)",
data: lineCompositeData,
type: "line",
height: 190,
colors: ["green"],
isNavigable: 1,
valuesOverPoints: 1,
lineOptions: {
dotSize: 8
}
}
},
barComposite: {
elementID: "#chart-composite-2",
options: {
data: barCompositeData,
type: "bar",
height: 210,
colors: ["violet", "light-blue", "#46a9f9"],
valuesOverPoints: 1,
axisOptions: {
xAxisMode: "tick",
shortenYAxisNumbers: true
},
barOptions: {
stacked: 1
}
}
},
demoMain: {
elementID: "",
options: {
title: "My Awesome Chart",
data: "typeData",
type: "axis-mixed",
height: 300,
colors: ["purple", "magenta", "light-blue"],
maxSlices: 10,
tooltipOptions: {
formatTooltipX: function formatTooltipX(d) {
return (d + '').toUpperCase();
},
formatTooltipY: function formatTooltipY(d) {
return d + ' pts';
}
}
}
}
};
/* eslint-disable no-unused-vars */
/* eslint-enable no-unused-vars */
// import { lineComposite, barComposite } from './demoConfig';
// ================================================================================
var Chart = frappe.Chart; // eslint-disable-line no-undef
var lc = demoConfig.lineComposite;
var lineCompositeChart = new Chart(lc.elementID, lc.options);
var bc = demoConfig.barComposite;
var barCompositeChart = new Chart(bc.elementID, bc.options);
lineCompositeChart.parent.addEventListener('data-select', function (e) {
var i = e.index;
barCompositeChart.updateDatasets([fireballOver25[i], fireball_5_25[i], fireball_2_5[i]]);
});
// ================================================================================
var customColors = ['purple', 'magenta', 'light-blue'];
var typeChartArgs = {
title: "My Awesome Chart",
data: typeData,
type: 'axis-mixed',
height: 300,
colors: customColors,
// maxLegendPoints: 6,
maxSlices: 10,
tooltipOptions: {
formatTooltipX: function formatTooltipX(d) {
return (d + '').toUpperCase();
},
formatTooltipY: function formatTooltipY(d) {
return d + ' pts';
}
}
};
var aggrChart = new Chart("#chart-aggr", typeChartArgs);
Array.prototype.slice.call(document.querySelectorAll('.aggr-type-buttons button')).map(function (el) {
el.addEventListener('click', function (e) {
var btn = e.target;
var type = btn.getAttribute('data-type');
typeChartArgs.type = type;
if (type !== 'axis-mixed') {
typeChartArgs.colors = undefined;
} else {
typeChartArgs.colors = customColors;
}
if (type !== 'percentage') {
typeChartArgs.height = 300;
} else {
typeChartArgs.height = undefined;
}
var newChart = new Chart("#chart-aggr", typeChartArgs);
if (newChart) {
aggrChart = newChart;
}
Array.prototype.slice.call(btn.parentNode.querySelectorAll('button')).map(function (el) {
el.classList.remove('active');
});
btn.classList.add('active');
});
});
document.querySelector('.export-aggr').addEventListener('click', function () {
aggrChart.export();
});
// Update values chart
// ================================================================================
var updateDataAllLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "Mon"];
var getRandom = function getRandom() {
return Math.floor(getRandomBias(-40, 60, 0.8, 1));
};
var updateDataAllValues = Array.from({ length: 30 }, getRandom);
// We're gonna be shuffling this
var updateDataAllIndices = updateDataAllLabels.map(function (d, i) {
return i;
});
var getUpdateData = function getUpdateData(source_array) {
var length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10;
var indices = updateDataAllIndices.slice(0, length);
return indices.map(function (index) {
return source_array[index];
});
};
var updateData = {
labels: getUpdateData(updateDataAllLabels),
datasets: [{
"values": getUpdateData(updateDataAllValues)
}],
yMarkers: [{
label: "Altitude",
value: 25,
type: 'dashed'
}],
yRegions: [{
label: "Range",
start: 10,
end: 45
}]
};
var updateChart = new Chart("#chart-update", {
data: updateData,
type: 'line',
height: 300,
colors: ['#ff6c03'],
lineOptions: {
// hideLine: 1,
regionFill: 1
}
});
var chartUpdateButtons = document.querySelector('.chart-update-buttons');
chartUpdateButtons.querySelector('[data-update="random"]').addEventListener("click", function () {
shuffle(updateDataAllIndices);
var value = getRandom();
var start = getRandom();
var end = getRandom();
var data = {
labels: updateDataAllLabels.slice(0, 10),
datasets: [{ values: getUpdateData(updateDataAllValues) }],
yMarkers: [{
label: "Altitude",
value: value,
type: 'dashed'
}],
yRegions: [{
label: "Range",
start: start,
end: end
}]
};
updateChart.update(data);
});
chartUpdateButtons.querySelector('[data-update="add"]').addEventListener("click", function () {
var index = updateChart.state.datasetLength; // last index to add
if (index >= updateDataAllIndices.length) return;
updateChart.addDataPoint(updateDataAllLabels[index], [updateDataAllValues[index]]);
});
chartUpdateButtons.querySelector('[data-update="remove"]').addEventListener("click", function () {
updateChart.removeDataPoint();
});
document.querySelector('.export-update').addEventListener('click', function () {
updateChart.export();
});
// Trends Chart
// ================================================================================
var plotChartArgs = {
title: "Mean Total Sunspot Count - Yearly",
data: trendsData,
type: 'line',
height: 300,
colors: ['#238e38'],
lineOptions: {
hideDots: 1,
heatline: 1
},
axisOptions: {
xAxisMode: 'tick',
yAxisMode: 'span',
xIsSeries: 1
}
};
var trendsChart = new Chart("#chart-trends", plotChartArgs);
Array.prototype.slice.call(document.querySelectorAll('.chart-plot-buttons button')).map(function (el) {
el.addEventListener('click', function (e) {
var btn = e.target;
var type = btn.getAttribute('data-type');
var config = {};
config[type] = 1;
if (['regionFill', 'heatline'].includes(type)) {
config.hideDots = 1;
}
// plotChartArgs.init = false;
plotChartArgs.lineOptions = config;
new Chart("#chart-trends", plotChartArgs);
Array.prototype.slice.call(btn.parentNode.querySelectorAll('button')).map(function (el) {
el.classList.remove('active');
});
btn.classList.add('active');
});
});
document.querySelector('.export-trends').addEventListener('click', function () {
trendsChart.export();
});
// Event chart
// ================================================================================
var eventsData = {
labels: ["Ganymede", "Callisto", "Io", "Europa"],
datasets: [{
"values": moonData.distances,
"formatted": moonData.distances.map(function (d) {
return d * 1000 + " km";
})
}]
};
var eventsChart = new Chart("#chart-events", {
title: "Jupiter's Moons: Semi-major Axis (1000 km)",
data: eventsData,
type: 'bar',
height: 330,
colors: ['grey'],
isNavigable: 1
});
var dataDiv = document.querySelector('.chart-events-data');
eventsChart.parent.addEventListener('data-select', function (e) {
var name = moonData.names[e.index];
dataDiv.querySelector('.moon-name').innerHTML = name;
dataDiv.querySelector('.semi-major-axis').innerHTML = moonData.distances[e.index] * 1000;
dataDiv.querySelector('.mass').innerHTML = moonData.masses[e.index];
dataDiv.querySelector('.diameter').innerHTML = moonData.diameters[e.index];
dataDiv.querySelector('img').src = "./assets/img/" + name.toLowerCase() + ".jpg";
});
// Heatmap
// ================================================================================
var today = new Date();
var start = clone(today);
addDays(start, 4);
var end = clone(start);
start.setFullYear(start.getFullYear() - 2);
end.setFullYear(end.getFullYear() - 1);
var dataPoints = {};
var startTs = timestampSec(start);
var endTs = timestampSec(end);
startTs = timestampToMidnight(startTs);
endTs = timestampToMidnight(endTs, true);
while (startTs < endTs) {
dataPoints[parseInt(startTs)] = Math.floor(getRandomBias(0, 5, 0.2, 1));
startTs += SEC_IN_DAY;
}
var heatmapData = {
dataPoints: dataPoints,
start: start,
end: end
};
var heatmapArgs = {
title: "Monthly Distribution",
data: heatmapData,
type: 'heatmap',
discreteDomains: 1,
countLabel: 'Level',
colors: HEATMAP_COLORS_BLUE,
legendScale: [0, 1, 2, 4, 5]
};
var heatmapChart = new Chart("#chart-heatmap", heatmapArgs);
Array.prototype.slice.call(document.querySelectorAll('.heatmap-mode-buttons button')).map(function (el) {
el.addEventListener('click', function (e) {
var btn = e.target;
var mode = btn.getAttribute('data-mode');
var discreteDomains = 0;
if (mode === 'discrete') {
discreteDomains = 1;
}
var colors = [];
var colors_mode = document.querySelector('.heatmap-color-buttons .active').getAttribute('data-color');
if (colors_mode === 'halloween') {
colors = HEATMAP_COLORS_YELLOW;
} else if (colors_mode === 'blue') {
colors = HEATMAP_COLORS_BLUE;
}
heatmapArgs.discreteDomains = discreteDomains;
heatmapArgs.colors = colors;
new Chart("#chart-heatmap", heatmapArgs);
Array.prototype.slice.call(btn.parentNode.querySelectorAll('button')).map(function (el) {
el.classList.remove('active');
});
btn.classList.add('active');
});
});
Array.prototype.slice.call(document.querySelectorAll('.heatmap-color-buttons button')).map(function (el) {
el.addEventListener('click', function (e) {
var btn = e.target;
var colors_mode = btn.getAttribute('data-color');
var colors = [];
if (colors_mode === 'halloween') {
colors = HEATMAP_COLORS_YELLOW;
} else if (colors_mode === 'blue') {
colors = HEATMAP_COLORS_BLUE;
}
var discreteDomains = 1;
var view_mode = document.querySelector('.heatmap-mode-buttons .active').getAttribute('data-mode');
if (view_mode === 'continuous') {
discreteDomains = 0;
}
heatmapArgs.discreteDomains = discreteDomains;
heatmapArgs.colors = colors;
new Chart("#chart-heatmap", heatmapArgs);
Array.prototype.slice.call(btn.parentNode.querySelectorAll('button')).map(function (el) {
el.classList.remove('active');
});
btn.classList.add('active');
});
});
document.querySelector('.export-heatmap').addEventListener('click', function () {
heatmapChart.export();
});
}());
//# sourceMappingURL=index.min.js.map

File diff suppressed because one or more lines are too long

View File

View File

@ -1,323 +0,0 @@
---
redirect_to: "https://frappe.io/charts"
---
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Frappe Charts</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="keywords" content="open source javascript js charts library svg zero-dependency interactive data visualization beautiful drag resize">
<meta name="description" content="A simple, responsive, modern charts library for the web.">
<link rel="stylesheet" type="text/css" href="assets/css/reset.css" media="screen">
<link rel="stylesheet" type="text/css" href="assets/css/bootstrap.min.css" media="screen">
<link rel="stylesheet" type="text/css" href="assets/css/index.css" media="screen">
<link rel="stylesheet" type="text/css" href="assets/css/hljs.css" media="screen">
<script src="assets/js/highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<link rel="shortcut icon" href="https://frappe.github.io/frappe/assets/img/favicon.png" type="image/x-icon">
<link rel="icon" href="https://frappe.github.io/frappe/assets/img/favicon.png" type="image/x-icon">
<script async defer src="https://buttons.github.io/buttons.js"></script>
</head>
<body>
<header>
<h1>Frappe Charts</h1>
<p class="lead-text">GitHub-inspired simple and modern SVG charts for the web<br>with zero dependencies.</p>
<div id="chart-composite-1" class="border"></div>
<p class="demo-tip">Click or use arrow keys to navigate data points</p>
<div id="chart-composite-2" class="border"></div>
</header>
<section>
<h6>Create a chart</h6>
<pre><code class="hljs html"> &lt!--HTML--&gt;
&lt;div id="chart"&gt;&lt;/div&gt;</code></pre>
<pre><code class="hljs javascript"> // Javascript
let chart = new frappe.Chart( "#chart", { // or DOM element
data: {
labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm",
"12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"],
datasets: [
{
name: "Some Data", chartType: 'bar',
values: [25, 40, 30, 35, 8, 52, 17, -4]
},
{
name: "Another Set", chartType: 'bar',
values: [25, 50, -10, 15, 18, 32, 27, 14]
},
{
name: "Yet Another", chartType: 'line',
values: [15, 20, -3, -15, 58, 12, -17, 37]
}
],
yMarkers: [{ label: "Marker", value: 70,
options: { labelPos: 'left' }}],
yRegions: [{ label: "Region", start: -10, end: 50,
options: { labelPos: 'right' }}]
},
title: "My Awesome Chart",
type: 'axis-mixed', // or 'bar', 'line', 'pie', 'percentage', 'donut'
height: 300,
colors: ['purple', '#ffa3ef', 'light-blue'],
tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' pts',
}
});
chart.export();
</code></pre>
<div id="chart-aggr" class="border"></div>
<div class="btn-group aggr-type-buttons margin-top mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary active" data-type='axis-mixed'>Mixed</button>
<button type="button" class="btn btn-sm btn-secondary" data-type='pie'>Pie Chart</button>
<button type="button" class="btn btn-sm btn-secondary" data-type='donut'>Donut Chart</button>
<button type="button" class="btn btn-sm btn-secondary" data-type='percentage'>Percentage Chart</button>
</div>
<div class="btn-group export-buttons margin-top mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary export-aggr">Export ...</button>
</div>
</section>
<section>
<h6>Update Values</h6>
<div id="chart-update" class="border"></div>
<div class="chart-update-buttons mt-1 mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary" data-update="random">Random Data</button>
<button type="button" class="btn btn-sm btn-secondary" data-update="add">Add Value</button>
<button type="button" class="btn btn-sm btn-secondary" data-update="remove">Remove Value</button>
<button type="button" class="btn btn-sm btn-secondary export-update">Export ...</button>
</div>
</section>
<section>
<h6>Plot Trends</h6>
<div id="chart-trends" class="border"></div>
<div class="btn-group chart-plot-buttons mt-1 mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary" data-type="hideDots">Line</button>
<button type="button" class="btn btn-sm btn-secondary" data-type="hideLine">Dots</button>
<button type="button" class="btn btn-sm btn-secondary active" data-type="heatline">HeatLine</button>
<button type="button" class="btn btn-sm btn-secondary" data-type="regionFill">Region</button>
</div>
<div class="btn-group export-buttons mt-1 mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary export-trends">Export ...</button>
</div>
</section>
<section>
<h6>Listen to state change</h6>
<div class="row">
<div class="col-sm-8">
<div id="chart-events" class="border"></div>
</div>
<div class="col-sm-4 chart-events-data">
<div class="image-container border">
<img class="moon-image" src="./assets/img/europa.jpg">
</div>
<div class="content-data margin-top">
<h6 class="moon-name">Europa</h6>
<p>Semi-major-axis: <span class="semi-major-axis">671034</span> km</p>
<p>Mass: <span class="mass">4800000</span> x 10^16 kg</p>
<p>Diameter: <span class="diameter">3121.6</span> km</p>
</div>
</div>
</div>
<pre><code class="hljs javascript margin-top"> ...
isNavigable: 1, // Navigate across data points; default 0
...
chart.parent.addEventListener('data-select', (e) => {
update_moon_data(e.index); // e contains index and value of current datapoint
});</code></pre>
</section>
<section>
<h6>
And a Month-wise Heatmap
</h6>
<div id="chart-heatmap" class="border"
style="overflow: scroll;"></div>
<div class="heatmap-mode-buttons btn-group mt-1 mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary active" data-mode="discrete">Discrete</button>
<button type="button" class="btn btn-sm btn-secondary" data-mode="continuous">Continuous</button>
</div>
<div class="heatmap-color-buttons btn-group mt-1 mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary" data-color="default">Green (Default)</button>
<button type="button" class="btn btn-sm btn-secondary active" data-color="blue">Blue</button>
<button type="button" class="btn btn-sm btn-secondary" data-color="halloween">GitHub's Halloween</button>
</div>
<div class="btn-group export-buttons mt-1 mx-auto" role="group">
<button type="button" class="btn btn-sm btn-secondary export-heatmap">Export ...</button>
</div>
<pre><code class="hljs javascript margin-top"> let heatmap = new frappe.Chart("#heatmap", {
type: 'heatmap',
title: "Monthly Distribution",
data: {
dataPoints: {'1524064033': 8, /* ... */},
// object with timestamp-value pairs
start: startDate
end: endDate // Date objects
},
countLabel: 'Level',
discreteDomains: 0 // default: 1
colors: ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'],
// Set of five incremental colors,
// preferably with a low-saturation color for zero data;
// def: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127']
});</code></pre>
</section>
<section>
<h6>Demo</h6>
<p data-height="299" data-theme-id="light" data-slug-hash="wjKBoq" data-default-tab="js,result"
data-user="pratu16x7" data-embed-version="2" data-pen-title="Frappe Charts Demo" class="codepen">
See the Pen <a href="https://codepen.io/pratu16x7/pen/wjKBoq/">Frappe Charts Demo</a>
by Prateeksha Singh (<a href="https://codepen.io/pratu16x7">@pratu16x7</a>) on
<a href="https://codepen.io">CodePen</a>.
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
</section>
<section>
<h6>Available options</h6>
<pre><code class="hljs javascript">
...
{
data: {
labels: [],
datasets: [],
yRegions: [],
yMarkers: []
}
title: '',
colors: [],
height: 200,
tooltipOptions: {
formatTooltipX: d => (d + '').toUpperCase(),
formatTooltipY: d => d + ' pts',
}
// Axis charts
isNavigable: 1, // default: 0
valuesOverPoints: 1, // default: 0
barOptions: {
spaceRatio: 1 // default: 0.5
stacked: 1 // default: 0
}
lineOptions: {
dotSize: 6, // default: 4
hideLine: 0, // default: 0
hideDots: 1, // default: 0
heatline: 1, // default: 0
regionFill: 1 // default: 0
}
axisOptions: {
yAxisMode: 'span', // Axis lines, default
xAxisMode: 'tick', // No axis lines, only short ticks
xIsSeries: 1 // Allow skipping x values for space
// default: 0
},
// Pie/Percentage/Donut charts
maxLegendPoints: 6, // default: 20
maxSlices: 10, // default: 20
// Percentage chart
barOptions: {
height: 15 // default: 20
depth: 5 // default: 2
}
// Heatmap
discreteDomains: 1, // default: 1
}
...
// Updating values
chart.update(data);
// Axis charts:
chart.addDataPoint(label, valueFromEachDataset, index)
chart.removeDataPoint(index)
chart.updateDataset(datasetValues, index)
// Exporting
chart.export();
// Unbind window-resize events
chart.destroy();
</code></pre>
</section>
<section>
<h6>Install</h6>
<p>Install via npm</p>
<pre><code class="hljs console"> npm install frappe-charts</code></pre>
<p>And include it in your project</p>
<pre><code class="hljs javascript"> import { Chart } from "frappe-charts"</code></pre>
<p>(for ES6+ import the ESModule from the dist folder)</p>
<pre><code class="hljs javascript"> import { Chart } from "frappe-charts/dist/frappe-charts.esm.js"</code></pre>
<p>... or include it directly in your HTML</p>
<pre><code class="hljs html"> &lt;script src="https://unpkg.com/frappe-charts@1.1.0"&gt;&lt;/script&gt;</code></pre>
<p>Use as:</p>
<pre><code class="hljs javascript"> new Chart(); // ES6 module
// or
new frappe.Chart(); // Browser</code></pre>
</section>
<section class="text-center">
<!-- Closing -->
<a href="https://github.com/frappe/charts/archive/master.zip"><button class="large blue button btn">Download</button></a>
<p style="margin-top: 3rem;margin-bottom: 1.5rem;">
<!-- <a href="docs.html" style="margin-right: 1rem;" target="_blank">Documentation</a> -->
<a href="https://github.com/frappe/charts" target="_blank">View on GitHub</a>
</p>
<p style="margin-top: 1rem;">
<a class="github-button" href="https://github.com/frappe/charts" data-icon="octicon-star" data-show-count="true" aria-label="Star frappe/charts on GitHub">Star</a>
</p>
<p>License: MIT</p>
</section>
<footer class="built-with-frappe text-center">
<img style="padding: 5px; width: 40px; background: #fff" class="frappe-bird" src="./assets/img/frappe-bird.png">
<p style="margin: 24px 0 0px 0; font-size: 15px">
Project maintained by <a href="https://frappe.io" target="_blank">Frappe</a>.
Used in <a href="https://erpnext.com" target="_blank">ERPNext</a>.
Read the <a href="https://medium.com/@pratu16x7/so-we-decided-to-create-our-own-charts-a95cb5032c97" target="_blank">blog post</a>.
</p>
<p style="margin: 24px 0 80px 0; font-size: 12px">
Data from the <a href="https://www.amsmeteors.org" target="_blank">American Meteor Society</a>,
<a href="http://www.sidc.be/silso" target="_blank">SILSO</a> and
<a href="https://api.nasa.gov/index.html" target="_blank">NASA Open APIs</a>
</p>
</footer>
<a href="https://github.com/frappe/charts" target="_blank" class="github-corner" aria-label="View source on Github">
<svg width="80" height="80" viewBox="0 0 250 250" style="fill:#9a9a9a; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path>
</svg>
</a>
<script src="assets/js/frappe-charts.min.js"></script>
<script src="assets/js/index.min.js"></script>
</body>
</html>

View File

@ -1,11 +1,12 @@
{
"name": "frappe-charts",
"version": "1.5.2",
"main": "dist/frappe-charts.cjs.js",
"common": "dist/frappe-charts.cjs.js",
"version": "2.0.0-rc26",
"main": "dist/frappe-charts.esm.js",
"module": "dist/frappe-charts.esm.js",
"browser": "dist/frappe-charts.umd.js",
"unpkg": "dist/frappe-charts.umd.js",
"common": "dist/frappe-charts.cjs.js",
"unnpkg": "dist/frappe-charts.umd.js",
"type": "module",
"description": "https://frappe.github.io/charts",
"directories": {
"doc": "docs"
@ -39,10 +40,12 @@
"@babel/preset-env": "^7.10.4",
"rollup": "^2.21.0",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-bundle-size": "^1.0.3",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-eslint": "^7.0.0",
"rollup-plugin-postcss": "^3.1.3",
"rollup-plugin-scss": "^2.5.0",
"rollup-plugin-terser": "^6.1.0"
"rollup-plugin-scss": "^4.0.1",
"rollup-plugin-terser": "^6.1.0",
"sass": "^1.86.0"
}
}

View File

@ -4,6 +4,7 @@ import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
import postcss from 'rollup-plugin-postcss';
import scss from 'rollup-plugin-scss';
import bundleSize from 'rollup-plugin-bundle-size';
import { terser } from 'rollup-plugin-terser';
@ -12,6 +13,7 @@ export default [
{
input: 'src/js/index.js',
output: {
sourcemap: true,
name: 'frappe-charts',
file: pkg.browser,
format: 'umd'
@ -22,7 +24,8 @@ export default [
exclude: ['node_modules/**']
}),
terser(),
scss({ output: 'dist/frappe-charts.min.css' })
scss({ fileName: 'frappe-charts.min.css' }),
bundleSize()
]
},
@ -30,14 +33,16 @@ export default [
{
input: 'src/js/chart.js',
output: [
{ file: pkg.common, format: 'cjs' },
{ file: pkg.module, format: 'es' }
{ file: pkg.common, format: 'cjs', sourcemap: true },
{ file: pkg.module, format: 'es', sourcemap: true },
],
plugins: [
babel({
exclude: ['node_modules/**']
}),
postcss()
terser(),
postcss(),
bundleSize()
]
}
];

View File

@ -1,54 +1,58 @@
:root {
--fr-label-color: #313b44;
--fr-axis-line-color: #E2E6E9;
--charts-label-color: #313b44;
--charts-axis-line-color: #f4f5f6;
--fr-stroke-width: 2px;
--fr-dataset-circle-stroke: #FFFFFF;
--fr-dataset-circle-stroke-width: var(--fr-stroke-width);
--charts-tooltip-title: var(--charts-label-color);
--charts-tooltip-label: var(--charts-label-color);
--charts-tooltip-value: #192734;
--charts-tooltip-bg: #ffffff;
--fr-tooltip-title: var(--fr-label-color);
--fr-tooltip-label: var(--fr-label-color);
--fr-tooltip-value: #192734;
--fr-tooltip-bg: #FFFFFF;
--charts-stroke-width: 2px;
--charts-dataset-circle-stroke: #ffffff;
--charts-dataset-circle-stroke-width: var(--charts-stroke-width);
--charts-legend-label: var(--charts-label-color);
--charts-legend-value: var(--charts-label-color);
}
.chart-container {
position: relative; /* for absolutely positioned tooltip */
font-family: -apple-system, BlinkMacSystemFont,
'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell',
'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
"Helvetica Neue", sans-serif;
.axis, .chart-label {
fill: var(--fr-label-color);
.axis,
.chart-label {
fill: var(--charts-label-color);
line {
stroke: var(--fr-axis-line-color);
stroke: var(--charts-axis-line-color);
}
}
.dataset-units {
circle {
stroke: var(--fr-dataset-circle-stroke);
stroke-width: var(--fr-dataset-circle-stroke-width);
stroke: var(--charts-dataset-circle-stroke);
stroke-width: var(--charts-dataset-circle-stroke-width);
}
path {
fill: none;
stroke-opacity: 1;
stroke-width: var(--fr-stroke-width);
stroke-width: var(--charts-stroke-width);
}
}
.dataset-path {
stroke-width: var(--fr-stroke-width);
stroke-width: var(--charts-stroke-width);
}
.path-group {
path {
fill: none;
stroke-opacity: 1;
stroke-width: var(--fr-stroke-width);
stroke-width: var(--charts-stroke-width);
}
}
@ -69,12 +73,12 @@
}
.legend-dataset-label {
fill: var(--fr-tooltip-label);
fill: var(--charts-legend-label);
font-weight: 600;
}
.legend-dataset-value {
fill: var(--fr-tooltip-value);
fill: var(--charts-legend-value);
}
}
@ -84,8 +88,10 @@
padding: 10px;
font-size: 12px;
text-align: center;
background: var(--fr-tooltip-bg);
box-shadow: 0px 1px 4px rgba(17, 43, 66, 0.1), 0px 2px 6px rgba(17, 43, 66, 0.08), 0px 40px 30px -30px rgba(17, 43, 66, 0.1);
background: var(--charts-tooltip-bg);
box-shadow: 0px 1px 4px rgba(17, 43, 66, 0.1),
0px 2px 6px rgba(17, 43, 66, 0.08),
0px 40px 30px -30px rgba(17, 43, 66, 0.1);
border-radius: 6px;
ul {
@ -110,7 +116,7 @@
height: 12px;
width: 12px;
border-radius: 2px;
background: var(--fr-tooltip-bg);
background: var(--charts-tooltip-bg);
transform: rotate(45deg);
margin-top: -7px;
margin-left: -6px;
@ -125,11 +131,15 @@
display: block;
padding: 16px;
margin: 0;
color: var(--fr-tooltip-title);
color: var(--charts-tooltip-title);
font-weight: 600;
line-height: 1;
pointer-events: none;
text-transform: uppercase;
strong {
color: var(--charts-tooltip-value);
}
}
ul {
@ -163,16 +173,15 @@
.tooltip-label {
margin-top: 4px;
font-size: 11px;
max-width: 100px;
line-height: 1.25;
max-width: 150px;
white-space: normal;
color: var(--fr-tooltip-label);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--charts-tooltip-label);
}
.tooltip-value {
color: var(--fr-tooltip-value);
color: var(--charts-tooltip-value);
}
}
}

View File

@ -1,6 +1,5 @@
import '../css/charts.scss';
// import MultiAxisChart from './charts/MultiAxisChart';
import PercentageChart from './charts/PercentageChart';
import PieChart from './charts/PieChart';
import Heatmap from './charts/Heatmap';
@ -10,7 +9,6 @@ import DonutChart from './charts/DonutChart';
const chartTypes = {
bar: AxisChart,
line: AxisChart,
// multiaxis: MultiAxisChart,
percentage: PercentageChart,
heatmap: Heatmap,
pie: PieChart,

View File

@ -1,8 +1,6 @@
import BaseChart from './BaseChart';
import { truncateString } from '../utils/draw-utils';
import { legendDot } from '../utils/draw';
import { round } from '../utils/helpers';
import { getExtraWidth } from '../utils/constants';
export default class AggregationChart extends BaseChart {
constructor(parent, args) {
@ -15,6 +13,7 @@ export default class AggregationChart extends BaseChart {
this.config.formatTooltipY = (args.tooltipOptions || {}).formatTooltipY;
this.config.maxSlices = args.maxSlices || 20;
this.config.maxLegendPoints = args.maxLegendPoints || 20;
this.config.legendRowHeight = 60;
}
calc() {
@ -62,36 +61,22 @@ export default class AggregationChart extends BaseChart {
let s = this.state;
this.legendArea.textContent = '';
this.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints);
super.renderLegend(this.legendTotals);
}
let count = 0;
let y = 0;
this.legendTotals.map((d, i) => {
let barWidth = 150;
let divisor = Math.floor(
(this.width - getExtraWidth(this.measures))/barWidth
makeLegend(data, index, x_pos, y_pos) {
let formatted = this.config.formatTooltipY ? this.config.formatTooltipY(data) : data;
return legendDot(
x_pos,
y_pos,
12, // size
3, // dot radius
this.colors[index], // fill
this.state.labels[index], // label
formatted, // value
null, // base_font_size
this.config.truncateLegends // truncate_legends
);
if (this.legendTotals.length < divisor) {
barWidth = this.width/this.legendTotals.length;
}
if(count > divisor) {
count = 0;
y += 60;
}
let x = barWidth * count + 5;
let label = this.config.truncateLegends ? truncateString(s.labels[i], barWidth/10) : s.labels[i];
let formatted = this.config.formatTooltipY ? this.config.formatTooltipY(d) : d;
let dot = legendDot(
x,
y,
12,
3,
this.colors[i],
`${label}: ${formatted}`,
d,
false
);
this.legendArea.appendChild(dot);
count++;
});
}
}

View File

@ -1,13 +1,14 @@
import BaseChart from './BaseChart';
import { dataPrep, zeroDataPrep, getShortenedLabels } from '../utils/axis-chart-utils';
import { AXIS_LEGEND_BAR_SIZE } from '../utils/constants';
import { getComponent } from '../objects/ChartComponents';
import { getOffset, fire } from '../utils/dom';
import { calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex, scale, getClosestInArray } from '../utils/intervals';
import { floatTwo } from '../utils/helpers';
import { makeOverlay, updateOverlay, legendBar } from '../utils/draw';
import { getTopOffset, getLeftOffset, MIN_BAR_PERCENT_HEIGHT, BAR_CHART_SPACE_RATIO,
LINE_CHART_DOT_SIZE } from '../utils/constants';
import { makeOverlay, updateOverlay, legendDot } from '../utils/draw';
import {
getTopOffset, getLeftOffset, MIN_BAR_PERCENT_HEIGHT, BAR_CHART_SPACE_RATIO,
LINE_CHART_DOT_SIZE
} from '../utils/constants';
export default class AxisChart extends BaseChart {
constructor(parent, args) {
@ -39,11 +40,16 @@ export default class AxisChart extends BaseChart {
this.config.yAxisMode = options.axisOptions.yAxisMode || 'span';
this.config.xIsSeries = options.axisOptions.xIsSeries || 0;
this.config.shortenYAxisNumbers = options.axisOptions.shortenYAxisNumbers || 0;
this.config.numberFormatter = options.axisOptions.numberFormatter;
this.config.seriesLabelSpaceRatio = options.axisOptions.seriesLabelSpaceRatio
this.config.yAxisRange = options.axisOptions.yAxisRange || {},
this.config.formatTooltipX = options.tooltipOptions.formatTooltipX;
this.config.formatTooltipY = options.tooltipOptions.formatTooltipY;
this.config.valuesOverPoints = options.valuesOverPoints;
this.config.legendRowHeight = 30;
}
prepareData(data = this.data) {
@ -84,7 +90,7 @@ export default class AxisChart extends BaseChart {
}
calcYAxisParameters(dataValues, withMinimum = 'false') {
const yPts = calcChartIntervals(dataValues, withMinimum);
const yPts = calcChartIntervals(dataValues, withMinimum, this.config.yAxisRange);
const scaleMultiplier = this.height / getValueRange(yPts);
const intervalHeight = getIntervalSize(yPts) * scaleMultiplier;
const zeroLine = this.height - (getZeroIndex(yPts) * intervalHeight);
@ -110,7 +116,7 @@ export default class AxisChart extends BaseChart {
let values = d.values;
let cumulativeYs = d.cumulativeYs || [];
return {
name: d.name.replace(/<|>|&/g, (char) => char == '&' ? '&amp;' : char == '<' ? '&lt;' : '&gt;'),
name: d.name && d.name.replace(/<|>|&/g, (char) => char == '&' ? '&amp;' : char == '<' ? '&lt;' : '&gt;'),
index: i,
chartType: d.chartType,
@ -193,8 +199,8 @@ export default class AxisChart extends BaseChart {
{
mode: this.config.yAxisMode,
width: this.width,
shortenNumbers: this.config.shortenYAxisNumbers
// pos: 'right'
shortenNumbers: this.config.shortenYAxisNumbers,
numberFormatter: this.config.numberFormatter,
},
function () {
return this.state.yAxis;
@ -211,7 +217,7 @@ export default class AxisChart extends BaseChart {
function () {
let s = this.state;
s.xAxis.calcLabels = getShortenedLabels(this.width,
s.xAxis.labels, this.config.xIsSeries);
s.xAxis.labels, this.config.xIsSeries,this.config.seriesLabelSpaceRatio);
return s.xAxis;
}.bind(this)
@ -299,7 +305,9 @@ export default class AxisChart extends BaseChart {
heatline: this.lineOptions.heatline,
regionFill: this.lineOptions.regionFill,
spline: this.lineOptions.spline,
hideDots: this.lineOptions.hideDots,
showDots: this.lineOptions.showDots,
trailingDot: this.lineOptions.trailingDot,
hideDotBorder: this.lineOptions.hideDotBorder,
hideLine: this.lineOptions.hideLine,
// same for all datasets
@ -369,7 +377,11 @@ export default class AxisChart extends BaseChart {
value: value,
yPos: set.yPositions[index],
color: this.colors[i],
formatted: formatY ? formatY(value) : value,
formatted: formatY ? formatY(value, {
name: set.name,
index: set.index,
values: set.values
}) : value,
};
});
@ -423,25 +435,23 @@ export default class AxisChart extends BaseChart {
renderLegend() {
let s = this.data;
if (s.datasets.length > 1) {
this.legendArea.textContent = '';
s.datasets.map((d, i) => {
let barWidth = AXIS_LEGEND_BAR_SIZE;
// let rightEndPoint = this.baseWidth - this.measures.margins.left - this.measures.margins.right;
// let multiplier = s.datasets.length - i;
let rect = legendBar(
// rightEndPoint - multiplier * barWidth, // To right align
barWidth * i,
'0',
barWidth,
this.colors[i],
d.name,
this.config.truncateLegends);
this.legendArea.appendChild(rect);
});
super.renderLegend(s.datasets);
}
}
makeLegend(data, index, x_pos, y_pos) {
return legendDot(
x_pos,
y_pos + 5, // Extra offset
12, // size
3, // dot radius
this.colors[index], // fill
data.name, //label
null, // value
8.75, // base_font_size
this.config.truncateLegends // truncate legends
);
}
// Overlay
makeOverlay() {

View File

@ -1,14 +1,19 @@
import SvgTip from '../objects/SvgTip';
import { $, isElementInViewport, getElementContentWidth, isHidden } from '../utils/dom';
import { makeSVGContainer, makeSVGDefs, makeSVGGroup, makeText } from '../utils/draw';
import { BASE_MEASURES, getExtraHeight, getExtraWidth, getTopOffset, getLeftOffset,
INIT_CHART_UPDATE_TIMEOUT, CHART_POST_ANIMATE_TIMEOUT, DEFAULT_COLORS} from '../utils/constants';
import { LEGEND_ITEM_WIDTH } from '../utils/constants';
import {
BASE_MEASURES, getExtraHeight, getExtraWidth, getTopOffset, getLeftOffset,
INIT_CHART_UPDATE_TIMEOUT, CHART_POST_ANIMATE_TIMEOUT, DEFAULT_COLORS
} from '../utils/constants';
import { getColor, isValidColor } from '../utils/colors';
import { runSMILAnimation } from '../utils/animation';
import { downloadFile, prepareForExport } from '../utils/export';
import { deepClone } from '../utils/helpers';
export default class BaseChart {
constructor(parent, options) {
options = deepClone(options);
this.parent = typeof parent === 'string'
? document.querySelector(parent)
@ -30,10 +35,11 @@ export default class BaseChart {
this.config = {
showTooltip: 1, // calculate
showLegend: 1, // calculate
showLegend: (typeof options.showLegend !== 'undefined') ? options.showLegend : 1,
isNavigable: options.isNavigable || 0,
animate: (typeof options.animate !== 'undefined') ? options.animate : 1,
truncateLegends: options.truncateLegends || 1
disableEntryAnimation: options.disableEntryAnimation || 0,
truncateLegends: (typeof options.truncateLegends !== 'undefined') ? options.truncateLegends : 1
};
this.measures = JSON.parse(JSON.stringify(BASE_MEASURES));
@ -89,11 +95,16 @@ export default class BaseChart {
// Bind window events
this.boundDrawFn = () => this.draw(true);
if (ResizeObserver) {
this.resizeObserver = new ResizeObserver(this.boundDrawFn);
this.resizeObserver.observe(this.parent);
}
window.addEventListener('resize', this.boundDrawFn);
window.addEventListener('orientationchange', this.boundDrawFn);
}
destroy() {
if (this.resizeObserver) this.resizeObserver.disconnect();
window.removeEventListener('resize', this.boundDrawFn);
window.removeEventListener('orientationchange', this.boundDrawFn);
}
@ -150,10 +161,12 @@ export default class BaseChart {
if (init) {
this.data = this.realData;
setTimeout(() => {this.update(this.data);}, this.initTimeout);
setTimeout(() => { this.update(this.data, true); }, this.initTimeout);
}
if (this.config.showLegend) {
this.renderLegend();
}
this.setupNavigation(init);
}
@ -223,13 +236,14 @@ export default class BaseChart {
setupComponents() { this.components = new Map(); }
update(data) {
if(!data) {
console.error('No data to update.');
}
update(data, drawing = false) {
if (!data) console.error('No data to update.');
if (!drawing) data = deepClone(data);
const animate = drawing ? !this.config.disableEntryAnimation : this.config.animate;
this.data = this.prepareData(data);
this.calc(); // builds state
this.render(this.components, this.config.animate);
this.render(this.components, animate);
}
render(components = this.components, animate = true) {
@ -262,7 +276,26 @@ export default class BaseChart {
}
}
renderLegend() {}
renderLegend(dataset) {
this.legendArea.textContent = '';
let count = 0;
let y = 0;
dataset.map((data, index) => {
let divisor = Math.floor(this.width / LEGEND_ITEM_WIDTH);
if (count > divisor) {
count = 0;
y += this.config.legendRowHeight;
}
let x = LEGEND_ITEM_WIDTH * count;
let dot = this.makeLegend(data, index, x, y);
this.legendArea.appendChild(dot);
count++;
});
}
makeLegend() { }
setupNavigation(init = false) {
if (!this.config.isNavigable) return;

View File

@ -1,86 +1,35 @@
import AggregationChart from './AggregationChart';
import PieChart from './PieChart';
import { getComponent } from '../objects/ChartComponents';
import { getOffset } from '../utils/dom';
import { getPositionByAngle } from '../utils/helpers';
import { makeArcStrokePathStr, makeStrokeCircleStr } from '../utils/draw';
import { lightenDarkenColor } from '../utils/colors';
import { transform } from '../utils/animation';
import { FULL_ANGLE } from '../utils/constants';
export default class DonutChart extends AggregationChart {
export default class DonutChart extends PieChart {
constructor(parent, args) {
super(parent, args);
this.type = 'donut';
this.initTimeout = 0;
this.init = 1;
this.setup();
}
configure(args) {
super.configure(args);
this.mouseMove = this.mouseMove.bind(this);
this.mouseLeave = this.mouseLeave.bind(this);
this.hoverRadio = args.hoverRadio || 0.1;
this.config.startAngle = args.startAngle || 0;
this.type = 'donut';
this.sliceName = 'donutSlices';
this.arcFunc = makeArcStrokePathStr;
this.shapeFunc = makeStrokeCircleStr;
this.clockWise = args.clockWise || false;
this.strokeWidth = args.strokeWidth || 30;
}
calc() {
super.calc();
let s = this.state;
this.radius =
this.height > this.width
getRadius() {
return this.height > this.width
? this.center.x - this.strokeWidth / 2
: this.center.y - this.strokeWidth / 2;
const { radius, clockWise } = this;
const prevSlicesProperties = s.slicesProperties || [];
s.sliceStrings = [];
s.slicesProperties = [];
let curAngle = 180 - this.config.startAngle;
s.sliceTotals.map((total, i) => {
const startAngle = curAngle;
const originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;
const largeArc = originDiffAngle > 180 ? 1: 0;
const diffAngle = clockWise ? -originDiffAngle : originDiffAngle;
const endAngle = curAngle = curAngle + diffAngle;
const startPosition = getPositionByAngle(startAngle, radius);
const endPosition = getPositionByAngle(endAngle, radius);
const prevProperty = this.init && prevSlicesProperties[i];
let curStart,curEnd;
if(this.init) {
curStart = prevProperty ? prevProperty.startPosition : startPosition;
curEnd = prevProperty ? prevProperty.endPosition : startPosition;
} else {
curStart = startPosition;
curEnd = endPosition;
}
const curPath =
originDiffAngle === 360
? makeStrokeCircleStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc)
: makeArcStrokePathStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc);
s.sliceStrings.push(curPath);
s.slicesProperties.push({
startPosition,
endPosition,
value: total,
total: s.grandTotal,
startAngle,
endAngle,
angle: diffAngle
});
});
this.init = 0;
resetHover(path, color) {
transform(path,'translate3d(0,0,0)');
this.tip.hideTip();
path.style.stroke = color;
}
setupComponents() {
@ -88,7 +37,7 @@ export default class DonutChart extends AggregationChart {
let componentConfigs = [
[
'donutSlices',
this.sliceName,
{},
function () {
return {
@ -106,56 +55,4 @@ export default class DonutChart extends AggregationChart {
return [args[0], component];
}));
}
calTranslateByAngle(property){
const{ radius, hoverRadio } = this;
const position = getPositionByAngle(property.startAngle+(property.angle / 2),radius);
return `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;
}
hoverSlice(path,i,flag,e){
if(!path) return;
const color = this.colors[i];
if(flag) {
transform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));
path.style.stroke = lightenDarkenColor(color, 50);
let g_off = getOffset(this.svg);
let x = e.pageX - g_off.left + 10;
let y = e.pageY - g_off.top - 10;
let title = (this.formatted_labels && this.formatted_labels.length > 0
? this.formatted_labels[i] : this.state.labels[i]) + ': ';
let percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);
this.tip.setValues(x, y, {name: title, value: percent + "%"});
this.tip.showTip();
} else {
transform(path,'translate3d(0,0,0)');
this.tip.hideTip();
path.style.stroke = color;
}
}
bindTooltip() {
this.container.addEventListener('mousemove', this.mouseMove);
this.container.addEventListener('mouseleave', this.mouseLeave);
}
mouseMove(e){
const target = e.target;
let slices = this.components.get('donutSlices').store;
let prevIndex = this.curActiveSliceIndex;
let prevAcitve = this.curActiveSlice;
if(slices.includes(target)) {
let i = slices.indexOf(target);
this.hoverSlice(prevAcitve, prevIndex,false);
this.curActiveSlice = target;
this.curActiveSliceIndex = i;
this.hoverSlice(target, i, true, e);
} else {
this.mouseLeave();
}
}
mouseLeave(){
this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);
}
}

View File

@ -1,11 +1,15 @@
import BaseChart from './BaseChart';
import { getComponent } from '../objects/ChartComponents';
import { makeText, heatSquare } from '../utils/draw';
import { DAY_NAMES_SHORT, addDays, areInSameMonth, getLastDateInMonth, setDayToSunday, getYyyyMmDd, getWeeksBetween, getMonthName, clone,
NO_OF_MILLIS, NO_OF_YEAR_MONTHS, NO_OF_DAYS_IN_WEEK } from '../utils/date-utils';
import {
DAY_NAMES_SHORT, addDays, areInSameMonth, getLastDateInMonth, setDayToSunday, getYyyyMmDd, getWeeksBetween, getMonthName, clone,
NO_OF_MILLIS, NO_OF_YEAR_MONTHS, NO_OF_DAYS_IN_WEEK
} from '../utils/date-utils';
import { calcDistribution, getMaxCheckpoint } from '../utils/intervals';
import { getExtraHeight, getExtraWidth, HEATMAP_DISTRIBUTION_SIZE, HEATMAP_SQUARE_SIZE,
HEATMAP_GUTTER_SIZE } from '../utils/constants';
import {
getExtraHeight, getExtraWidth, HEATMAP_DISTRIBUTION_SIZE, HEATMAP_SQUARE_SIZE,
HEATMAP_GUTTER_SIZE
} from '../utils/constants';
const COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE;
const ROW_HEIGHT = COL_WIDTH;

View File

@ -1,173 +0,0 @@
import AxisChart from './AxisChart';
import { Y_AXIS_MARGIN } from '../utils/constants';
// import { ChartComponent } from '../objects/ChartComponents';
import { floatTwo } from '../utils/helpers';
export default class MultiAxisChart extends AxisChart {
constructor(args) {
super(args);
// this.unitType = args.unitType || 'line';
// this.setup();
}
preSetup() {
this.type = 'multiaxis';
}
setMeasures() {
super.setMeasures();
let noOfLeftAxes = this.data.datasets.filter(d => d.axisPosition === 'left').length;
this.measures.margins.left = (noOfLeftAxes) * Y_AXIS_MARGIN || Y_AXIS_MARGIN;
this.measures.margins.right = (this.data.datasets.length - noOfLeftAxes) * Y_AXIS_MARGIN || Y_AXIS_MARGIN;
}
prepareYAxis() { }
prepareData(data) {
super.prepareData(data);
let sets = this.state.datasets;
// let axesLeft = sets.filter(d => d.axisPosition === 'left');
// let axesRight = sets.filter(d => d.axisPosition === 'right');
// let axesNone = sets.filter(d => !d.axisPosition ||
// !['left', 'right'].includes(d.axisPosition));
let leftCount = 0, rightCount = 0;
sets.forEach((d, i) => {
d.yAxis = {
position: d.axisPosition,
index: d.axisPosition === 'left' ? leftCount++ : rightCount++
};
});
}
configure(args) {
super.configure(args);
this.config.xAxisMode = args.xAxisMode || 'tick';
this.config.yAxisMode = args.yAxisMode || 'span';
}
// setUnitWidthAndXOffset() {
// this.state.unitWidth = this.width/(this.state.datasetLength);
// this.state.xOffset = this.state.unitWidth/2;
// }
configUnits() {
this.unitArgs = {
type: 'bar',
args: {
spaceWidth: this.state.unitWidth/2,
}
};
}
setYAxis() {
this.state.datasets.map(d => {
this.calcYAxisParameters(d.yAxis, d.values, this.unitType === 'line');
});
}
calcYUnits() {
this.state.datasets.map(d => {
d.positions = d.values.map(val => floatTwo(d.yAxis.zeroLine - val * d.yAxis.scaleMultiplier));
});
}
// TODO: function doesn't exist, handle with components
renderConstants() {
this.state.datasets.map(d => {
let guidePos = d.yAxis.position === 'left'
? -1 * d.yAxis.index * Y_AXIS_MARGIN
: this.width + d.yAxis.index * Y_AXIS_MARGIN;
this.renderer.xLine(guidePos, '', {
pos:'top',
mode: 'span',
stroke: this.colors[i],
className: 'y-axis-guide'
})
});
}
getYAxesComponents() {
return this.data.datasets.map((e, i) => {
return new ChartComponent({
layerClass: 'y axis y-axis-' + i,
make: () => {
let yAxis = this.state.datasets[i].yAxis;
this.renderer.setZeroline(yAxis.zeroline);
let options = {
pos: yAxis.position,
mode: 'tick',
offset: yAxis.index * Y_AXIS_MARGIN,
stroke: this.colors[i]
};
return yAxis.positions.map((position, j) =>
this.renderer.yLine(position, yAxis.labels[j], options)
);
},
animate: () => {}
});
});
}
// TODO remove renderer zeroline from above and below
getChartComponents() {
return this.data.datasets.map((d, index) => {
return new ChartComponent({
layerClass: 'dataset-units dataset-' + index,
make: () => {
let d = this.state.datasets[index];
let unitType = this.unitArgs;
// the only difference, should be tied to datasets or default
this.renderer.setZeroline(d.yAxis.zeroLine);
return d.positions.map((y, j) => {
return this.renderer[unitType.type](
this.state.xAxisPositions[j],
y,
unitType.args,
this.colors[index],
j,
index,
this.state.datasetLength
);
});
},
animate: (svgUnits) => {
let d = this.state.datasets[index];
let unitType = this.unitArgs.type;
// have been updated in axis render;
let newX = this.state.xAxisPositions;
let newY = this.state.datasets[index].positions;
let lastUnit = svgUnits[svgUnits.length - 1];
let parentNode = lastUnit.parentNode;
if(this.oldState.xExtra > 0) {
for(var i = 0; i<this.oldState.xExtra; i++) {
let unit = lastUnit.cloneNode(true);
parentNode.appendChild(unit);
svgUnits.push(unit);
}
}
this.renderer.setZeroline(d.yAxis.zeroLine);
svgUnits.map((unit, i) => {
if(newX[i] === undefined || newY[i] === undefined) return;
this.elementsToAnimate.push(this.renderer['animate' + unitType](
unit, // unit, with info to replace where it came from in the data
newX[i],
newY[i],
index,
this.state.noOfDatasets
));
});
}
});
});
}
}

View File

@ -1,7 +1,7 @@
import AggregationChart from './AggregationChart';
import { getOffset } from '../utils/dom';
import { getComponent } from '../objects/ChartComponents';
import { PERCENTAGE_BAR_DEFAULT_HEIGHT, PERCENTAGE_BAR_DEFAULT_DEPTH } from '../utils/constants';
import { PERCENTAGE_BAR_DEFAULT_HEIGHT, getExtraHeight } from '../utils/constants';
export default class PercentageChart extends AggregationChart {
constructor(parent, args) {
@ -16,11 +16,13 @@ export default class PercentageChart extends AggregationChart {
let b = this.barOptions;
b.height = b.height || PERCENTAGE_BAR_DEFAULT_HEIGHT;
b.depth = b.depth || PERCENTAGE_BAR_DEFAULT_DEPTH;
m.paddings.right = 30;
m.legendHeight = 60;
m.baseHeight = (b.height + b.depth * 0.5) * 8;
m.paddings.top = 60;
m.paddings.bottom = 0;
m.legendHeight = 80;
m.baseHeight = (b.height) * 8 + getExtraHeight(m);
}
setupComponents() {
@ -31,7 +33,6 @@ export default class PercentageChart extends AggregationChart {
'percentageBars',
{
barHeight: this.barOptions.height,
barDepth: this.barOptions.depth,
},
function () {
return {
@ -74,11 +75,12 @@ export default class PercentageChart extends AggregationChart {
let bars = this.components.get('percentageBars').store;
let bar = e.target;
if (bars.includes(bar)) {
let i = bars.indexOf(bar);
let gOff = getOffset(this.container), pOff = getOffset(bar);
let x = pOff.left - gOff.left + parseInt(bar.getAttribute('width'))/2;
let width = bar.getAttribute('width') || bar.getBoundingClientRect().width;
let x = pOff.left - gOff.left + parseInt(width) / 2;
let y = pOff.top - gOff.top;
let title = (this.formattedLabels && this.formattedLabels.length > 0
? this.formattedLabels[i] : this.state.labels[i]) + ': ';

View File

@ -3,14 +3,12 @@ import { getComponent } from '../objects/ChartComponents';
import { getOffset } from '../utils/dom';
import { getPositionByAngle } from '../utils/helpers';
import { makeArcPathStr, makeCircleStr } from '../utils/draw';
import { lightenDarkenColor } from '../utils/colors';
import { transform } from '../utils/animation';
import { FULL_ANGLE } from '../utils/constants';
export default class PieChart extends AggregationChart {
constructor(parent, args) {
super(parent, args);
this.type = 'pie';
this.initTimeout = 0;
this.init = 1;
@ -25,13 +23,23 @@ export default class PieChart extends AggregationChart {
this.hoverRadio = args.hoverRadio || 0.1;
this.config.startAngle = args.startAngle || 0;
this.type = 'pie';
this.sliceName = 'pieSlices';
this.arcFunc = makeArcPathStr;
this.shapeFunc = makeCircleStr;
this.clockWise = args.clockWise || false;
}
getRadius() {
return this.height > this.width ? this.center.x : this.center.y;
}
calc() {
super.calc();
let s = this.state;
this.radius = (this.height > this.width ? this.center.x : this.center.y);
this.radius = this.getRadius();
const { radius, clockWise } = this;
@ -60,8 +68,8 @@ export default class PieChart extends AggregationChart {
}
const curPath =
originDiffAngle === 360
? makeCircleStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc)
: makeArcPathStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc);
? this.shapeFunc(curStart, curEnd, this.center, this.radius, clockWise, largeArc)
: this.arcFunc(curStart, curEnd, this.center, this.radius, clockWise, largeArc);
s.sliceStrings.push(curPath);
s.slicesProperties.push({
@ -112,7 +120,8 @@ export default class PieChart extends AggregationChart {
const color = this.colors[i];
if (flag) {
transform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));
path.style.fill = lightenDarkenColor(color, 50);
// path.style.fill = lightenDarkenColor(color, 50);
// path.style.stroke = lightenDarkenColor(color, 50);
let g_off = getOffset(this.svg);
let x = e.pageX - g_off.left + 10;
let y = e.pageY - g_off.top - 10;
@ -122,11 +131,15 @@ export default class PieChart extends AggregationChart {
this.tip.setValues(x, y, { name: title, value: percent + "%" });
this.tip.showTip();
} else {
this.resetHover(path, color)
}
}
resetHover(path, color) {
transform(path, 'translate3d(0,0,0)');
this.tip.hideTip();
path.style.fill = color;
}
}
bindTooltip() {
this.container.addEventListener('mousemove', this.mouseMove);
@ -135,12 +148,12 @@ export default class PieChart extends AggregationChart {
mouseMove(e) {
const target = e.target;
let slices = this.components.get('pieSlices').store;
let slices = this.components.get(this.sliceName).store;
let prevIndex = this.curActiveSliceIndex;
let prevAcitve = this.curActiveSlice;
let prevActive = this.curActiveSlice;
if (slices.includes(target)) {
let i = slices.indexOf(target);
this.hoverSlice(prevAcitve, prevIndex,false);
this.hoverSlice(prevActive, prevIndex, false);
this.curActiveSlice = target;
this.curActiveSliceIndex = i;
this.hoverSlice(target, i, true, e);

View File

@ -3,7 +3,7 @@ import * as Charts from './chart';
let frappe = { };
frappe.NAME = 'Frappe Charts';
frappe.VERSION = '1.5.5';
frappe.VERSION = '2.0.0-rc22';
frappe = Object.assign({ }, frappe, Charts);

View File

@ -1,8 +1,10 @@
import { makeSVGGroup } from '../utils/draw';
import { makeText, makePath, xLine, yLine, yMarker, yRegion, datasetBar, datasetDot, percentageBar, getPaths, heatSquare } from '../utils/draw';
import { equilizeNoOfElements } from '../utils/draw-utils';
import { translateHoriLine, translateVertLine, animateRegion, animateBar,
animateDot, animatePath, animatePathStr } from '../utils/animate';
import {
translateHoriLine, translateVertLine, animateRegion, animateBar,
animateDot, animatePath, animatePathStr
} from '../utils/animate';
import { getMonthName } from '../utils/date-utils';
class ChartComponent {
@ -102,10 +104,14 @@ let componentConfigs = {
percentageBars: {
layerClass: 'percentage-bars',
makeElements(data) {
const numberOfPoints = data.xPositions.length;
return data.xPositions.map((x, i) => {
let y = 0;
let bar = percentageBar(x, y, data.widths[i],
this.constants.barHeight, this.constants.barDepth, data.colors[i]);
let isLast = i == numberOfPoints - 1;
let isFirst = i == 0;
let bar = percentageBar(x, y, data.widths[i], this.constants.barHeight, isFirst, isLast, data.colors[i]);
return bar;
});
},
@ -119,7 +125,12 @@ let componentConfigs = {
makeElements(data) {
return data.positions.map((position, i) =>
yLine(position, data.labels[i], this.constants.width,
{mode: this.constants.mode, pos: this.constants.pos, shortenNumbers: this.constants.shortenNumbers})
{
mode: this.constants.mode,
pos: this.constants.pos,
shortenNumbers: this.constants.shortenNumbers,
numberFormatter: this.constants.numberFormatter
})
);
},
@ -181,7 +192,7 @@ let componentConfigs = {
makeElements(data) {
return data.map(m =>
yMarker(m.position, m.label, this.constants.width,
{labelPos: m.options.labelPos, mode: 'span', lineType: 'dashed'})
{ labelPos: m.options.labelPos, stroke: m.options.stroke, mode: 'span', lineType: m.options.lineType })
);
},
animateElements(newData) {
@ -214,7 +225,7 @@ let componentConfigs = {
makeElements(data) {
return data.map(r =>
yRegion(r.startPos, r.endPos, this.constants.width,
r.label, {labelPos: r.options.labelPos})
r.label, { labelPos: r.options.labelPos, stroke: r.options.stroke, fill: r.options.fill })
);
},
animateElements(newData) {
@ -379,7 +390,7 @@ let componentConfigs = {
}
this.units = [];
if(!c.hideDots) {
if (c.showDots) {
this.units = data.yPositions.map((y, j) => {
return datasetDot(
data.xPositions[j],
@ -387,11 +398,27 @@ let componentConfigs = {
data.radius,
c.color,
(c.valuesOverPoints ? data.values[j] : ''),
j
j,
c.hideDotBorder
);
});
}
if (c.trailingDot && !c.showDots) {
const lastIndex = data.yPositions.length - 1;
const dot = datasetDot(
data.xPositions[lastIndex],
data.yPositions[lastIndex],
data.radius,
c.color,
(c.valuesOverPoints ? data.values[lastIndex] : ''),
lastIndex,
c.hideDotBorder
);
this.units.push(dot);
}
return Object.values(this.paths).concat(this.units);
},
animateElements(newData) {

View File

@ -1,5 +1,8 @@
import { fillArray } from '../utils/helpers';
import { DEFAULT_AXIS_CHART_TYPE, AXIS_DATASET_CHART_TYPES, DEFAULT_CHAR_WIDTH } from '../utils/constants';
import {
DEFAULT_AXIS_CHART_TYPE, AXIS_DATASET_CHART_TYPES, DEFAULT_CHAR_WIDTH,
SERIES_LABEL_SPACE_RATIO
} from '../utils/constants';
export function dataPrep(data, type) {
data.labels = data.labels || [];
@ -31,11 +34,9 @@ export function dataPrep(data, type) {
} else {
vals = fillArray(vals, datasetLength - vals.length, 0);
}
d.values = vals;
}
// Set labels
//
// Set type
if (!d.chartType) {
if (!AXIS_DATASET_CHART_TYPES.includes(type)) type === DEFAULT_AXIS_CHART_TYPE;
@ -96,8 +97,8 @@ export function zeroDataPrep(realData) {
return zeroData;
}
export function getShortenedLabels(chartWidth, labels=[], isSeries=true) {
let allowedSpace = chartWidth / labels.length;
export function getShortenedLabels(chartWidth, labels = [], isSeries = true, seriesLabelSpaceRatio) {
let allowedSpace = (chartWidth / labels.length) * (seriesLabelSpaceRatio || SERIES_LABEL_SPACE_RATIO);
if (allowedSpace <= 0) allowedSpace = 1;
let allowedLetters = allowedSpace / DEFAULT_CHAR_WIDTH;
@ -120,8 +121,14 @@ export function getShortenedLabels(chartWidth, labels=[], isSeries=true) {
}
} else {
if (i % seriesMultiple !== 0) {
if (i !== (labels.length - 1)) {
label = "";
}
} else {
if (i > (labels.length - (seriesMultiple / 2))) {
label = "";
}
}
}
}
return label;

View File

@ -65,16 +65,16 @@ export const CHART_POST_ANIMATE_TIMEOUT = 400;
export const DEFAULT_AXIS_CHART_TYPE = 'line';
export const AXIS_DATASET_CHART_TYPES = ['line', 'bar'];
export const AXIS_LEGEND_BAR_SIZE = 100;
export const LEGEND_ITEM_WIDTH = 150;
export const SERIES_LABEL_SPACE_RATIO = 0.6;
export const BAR_CHART_SPACE_RATIO = 0.8;
export const BAR_CHART_SPACE_RATIO = 0.5;
export const MIN_BAR_PERCENT_HEIGHT = 0.00;
export const LINE_CHART_DOT_SIZE = 4;
export const DOT_OVERLAY_SIZE_INCR = 4;
export const PERCENTAGE_BAR_DEFAULT_HEIGHT = 20;
export const PERCENTAGE_BAR_DEFAULT_DEPTH = 2;
export const PERCENTAGE_BAR_DEFAULT_HEIGHT = 16;
// Fixed 5-color theme,
// More colors are difficult to parse visually

View File

@ -2,8 +2,7 @@ export function $(expr, con) {
return typeof expr === "string" ? (con || document).querySelector(expr) : expr || null;
}
export function findNodeIndex(node)
{
export function findNodeIndex(node) {
var i = 0;
while (node.previousSibling) {
node = node.previousSibling;

View File

@ -51,13 +51,15 @@ export function shortenLargeNumber(label) {
let shortened = (Math.pow(10, p - l * 3) * +(number / Math.pow(10, p)).toFixed(1));
// Correct for floating point error upto 2 decimal places
return Math.round(shortened*100)/100 + ' ' + ['', 'K', 'M', 'B', 'T'][l];
return Math.round(shortened * 100) / 100 + ['', 'K', 'M', 'B', 'T'][l];
}
// cubic bezier curve calculation (from example by François Romain)
export function getSplineCurvePointsStr(xList, yList) {
let points = [];
const length = Math.min(xList.length, yList.length);
for (let i = 0; i < xList.length; i++) {
points.push([xList[i], yList[i]]);
}

View File

@ -1,14 +1,12 @@
import { getBarHeightAndYAttr, truncateString, shortenLargeNumber, getSplineCurvePointsStr } from './draw-utils';
import { getStringWidth, isValidNumber } from './helpers';
import { DOT_OVERLAY_SIZE_INCR, PERCENTAGE_BAR_DEFAULT_DEPTH } from './constants';
import { lightenDarkenColor } from './colors';
import { getStringWidth, isValidNumber, round } from './helpers';
import { DOT_OVERLAY_SIZE_INCR } from './constants';
export const AXIS_TICK_LENGTH = 6;
const LABEL_MARGIN = 4;
const LABEL_MAX_CHARS = 15;
const LABEL_MAX_CHARS = 18;
export const FONT_SIZE = 10;
const BASE_LINE_COLOR = '#E2E6E9';
const FONT_FILL = '#313B44';
function $(expr, con) {
return typeof expr === "string" ? (con || document).querySelector(expr) : expr || null;
@ -158,7 +156,7 @@ export function makeGradient(svgDefElem, color, lighter = false) {
let gradientDef = renderVerticalGradient(svgDefElem, gradientId);
let opacities = [1, 0.6, 0.2];
if (lighter) {
opacities = [0.4, 0.2, 0];
opacities = [0.15, 0.05, 0];
}
setGradientStop(gradientDef, "0%", color, opacities[0]);
@ -168,8 +166,31 @@ export function makeGradient(svgDefElem, color, lighter = false) {
return gradientId;
}
export function percentageBar(x, y, width, height,
depth=PERCENTAGE_BAR_DEFAULT_DEPTH, fill='none') {
export function rightRoundedBar(x, width, height) {
// https://medium.com/@dennismphil/one-side-rounded-rectangle-using-svg-fb31cf318d90
let radius = height / 2;
let xOffset = width - radius;
return `M${x},0 h${xOffset} q${radius},0 ${radius},${radius} q0,${radius} -${radius},${radius} h-${xOffset} v${height}z`;
}
export function leftRoundedBar(x, width, height) {
let radius = height / 2;
let xOffset = width - radius;
return `M${x + radius},0 h${xOffset} v${height} h-${xOffset} q-${radius}, 0 -${radius},-${radius} q0,-${radius} ${radius},-${radius}z`;
}
export function percentageBar(x, y, width, height, isFirst, isLast, fill = 'none') {
if (isLast) {
let pathStr = rightRoundedBar(x, width, height);
return makePath(pathStr, 'percentage-bar', null, fill);
}
if (isFirst) {
let pathStr = leftRoundedBar(x, width, height);
return makePath(pathStr, 'percentage-bar', null, fill);
}
let args = {
className: 'percentage-bar',
@ -177,14 +198,7 @@ export function percentageBar(x, y, width, height,
y: y,
width: width,
height: height,
fill: fill,
styles: {
'stroke': lightenDarkenColor(fill, -25),
// Diabolically good: https://stackoverflow.com/a/9000859
// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray
'stroke-dasharray': `0, ${height + width}, ${width}, ${height}`,
'stroke-width': depth
},
fill: fill
};
return createSVG("rect", args);
@ -208,39 +222,9 @@ export function heatSquare(className, x, y, size, radius, fill='none', data={})
return createSVG("rect", args);
}
export function legendBar(x, y, size, fill='none', label, truncate=false) {
label = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;
let args = {
className: 'legend-bar',
x: 0,
y: 0,
width: size,
height: '2px',
fill: fill
};
let text = createSVG('text', {
className: 'legend-dataset-text',
x: 0,
y: 0,
dy: (FONT_SIZE * 2) + 'px',
'font-size': (FONT_SIZE * 1.2) + 'px',
'text-anchor': 'start',
fill: FONT_FILL,
innerHTML: label
});
let group = createSVG('g', {
transform: `translate(${x}, ${y})`
});
group.appendChild(createSVG("rect", args));
group.appendChild(text);
return group;
}
export function legendDot(x, y, size, radius, fill='none', label, value, truncate=false) {
export function legendDot(x, y, size, radius, fill = 'none', label, value, font_size = null, truncate = false) {
label = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;
if (!font_size) font_size = FONT_SIZE;
let args = {
className: 'legend-dot',
@ -256,15 +240,16 @@ export function legendDot(x, y, size, radius, fill='none', label, value, truncat
className: 'legend-dataset-label',
x: size,
y: 0,
dx: (FONT_SIZE) + 'px',
dy: (FONT_SIZE/3) + 'px',
'font-size': (FONT_SIZE * 1.6) + 'px',
dx: (font_size) + 'px',
dy: (font_size / 3) + 'px',
'font-size': (font_size * 1.6) + 'px',
'text-anchor': 'start',
fill: FONT_FILL,
innerHTML: label
});
let textValue = createSVG('text', {
let textValue = null;
if (value) {
textValue = createSVG('text', {
className: 'legend-dataset-value',
x: size,
y: FONT_SIZE + 10,
@ -272,16 +257,19 @@ export function legendDot(x, y, size, radius, fill='none', label, value, truncat
dy: (FONT_SIZE / 3) + 'px',
'font-size': (FONT_SIZE * 1.2) + 'px',
'text-anchor': 'start',
fill: FONT_FILL,
innerHTML: value
});
}
let group = createSVG('g', {
transform: `translate(${x}, ${y})`
});
group.appendChild(createSVG("rect", args));
group.appendChild(textLabel);
if (value && textValue) {
group.appendChild(textValue);
}
return group;
}
@ -289,7 +277,7 @@ export function legendDot(x, y, size, radius, fill='none', label, value, truncat
export function makeText(className, x, y, content, options = {}) {
let fontSize = options.fontSize || FONT_SIZE;
let dy = options.dy !== undefined ? options.dy : (fontSize / 2);
let fill = options.fill || FONT_FILL;
let fill = options.fill || "var(--charts-label-color)";
let textAnchor = options.textAnchor || 'start';
return createSVG('text', {
className: className,
@ -304,7 +292,6 @@ export function makeText(className, x, y, content, options = {}) {
}
function makeVertLine(x, label, y1, y2, options = {}) {
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
let l = createSVG('line', {
className: 'line-vertical ' + options.className,
x1: 0,
@ -336,9 +323,14 @@ function makeVertLine(x, label, y1, y2, options={}) {
}
function makeHoriLine(y, label, x1, x2, options = {}) {
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
if (!options.lineType) options.lineType = '';
if (options.shortenNumbers) label = shortenLargeNumber(label);
if (options.shortenNumbers) {
if (options.numberFormatter) {
label = options.numberFormatter(label);
} else {
label = shortenLargeNumber(label);
}
}
let className = 'line-horizontal ' + options.className +
(options.lineType === "dashed" ? "dashed" : "");
@ -400,11 +392,13 @@ export function yLine(y, label, width, options={}) {
x1 += options.offset;
x2 += options.offset;
if (typeof label === "number") label = round(label);
return makeHoriLine(y, label, x1, x2, {
stroke: options.stroke,
className: options.className,
lineType: options.lineType,
shortenNumbers: options.shortenNumbers
shortenNumbers: options.shortenNumbers,
numberFormatter: options.numberFormatter,
});
}
@ -414,7 +408,6 @@ export function xLine(x, label, height, options={}) {
if (!options.pos) options.pos = 'bottom';
if (!options.offset) options.offset = 0;
if (!options.mode) options.mode = 'span';
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
if (!options.className) options.className = '';
// Draw X axis line in span/tick mode with optional label
@ -438,14 +431,16 @@ export function xLine(x, label, height, options={}) {
}
return makeVertLine(x, label, y1, y2, {
stroke: options.stroke,
className: options.className,
lineType: options.lineType
});
}
export function yMarker(y, label, width, options = {}) {
if (!isValidNumber(y)) y = 0;
if (!options.labelPos) options.labelPos = 'right';
if (!options.lineType) options.lineType = 'dashed';
let x = options.labelPos === 'left' ? LABEL_MARGIN
: width - getStringWidth(label, 5) - LABEL_MARGIN;
@ -477,8 +472,8 @@ export function yRegion(y1, y2, width, label, options={}) {
let rect = createSVG('rect', {
className: `bar mini`, // remove class
styles: {
fill: `rgba(228, 234, 239, 0.49)`,
stroke: BASE_LINE_COLOR,
fill: options.fill || `rgba(228, 234, 239, 0.49)`,
stroke: options.stroke || BASE_LINE_COLOR,
'stroke-dasharray': `${width}, ${height}`
},
// 'data-point-index': index,
@ -527,6 +522,26 @@ export function datasetBar(x, yTop, width, color, label='', index=0, offset=0, m
if (!isValidNumber(height, true)) height = 0;
if (!isValidNumber(width, true)) width = 0;
// x y h w
// M{x},{y+r}
// q0,-{r} {r},-{r}
// q{r},0 {r},{r}
// v{h-r}
// h-{w}z
// let radius = width/2;
// let pathStr = `M${x},${y+radius} q0,-${radius} ${radius},-${radius} q${radius},0 ${radius},${radius} v${height-radius} h-${width}z`
// let rect = createSVG('path', {
// className: 'bar mini',
// d: pathStr,
// styles: { fill: color },
// x: x,
// y: y,
// 'data-point-index': index,
// });
let rect = createSVG('rect', {
className: `bar mini`,
style: `fill: ${color}`,
@ -565,9 +580,9 @@ export function datasetBar(x, yTop, width, color, label='', index=0, offset=0, m
}
}
export function datasetDot(x, y, radius, color, label='', index=0) {
export function datasetDot(x, y, radius, color, label = '', index = 0, hideDotBorder = false) {
let dot = createSVG('circle', {
style: `fill: ${color}`,
style: `fill: ${color}; ${hideDotBorder ? `stroke: ${color}`: ''}`,
'data-point-index': index,
cx: x,
cy: y,

View File

@ -115,3 +115,29 @@ export function round(d) {
// https://www.jacklmoore.com/notes/rounding-in-javascript/
return Number(Math.round(d + 'e4') + 'e-4');
}
/**
* Creates a deep clone of an object
* @param {Object} candidate Any Object
*/
export function deepClone(candidate) {
let cloned, value, key;
if (candidate instanceof Date) {
return new Date(candidate.getTime());
}
if (typeof candidate !== "object" || candidate === null) {
return candidate;
}
cloned = Array.isArray(candidate) ? [] : {};
for (key in candidate) {
value = candidate[key];
cloned[key] = deepClone(value);
}
return cloned;
}

View File

@ -73,7 +73,7 @@ function getChartIntervals(maxValue, minValue=0) {
return intervals;
}
export function calcChartIntervals(values, withMinimum=false) {
export function calcChartIntervals(values, withMinimum = false, range = {}) {
//*** Where the magic happens ***
// Calculates best-fit y intervals from given values
@ -82,6 +82,14 @@ export function calcChartIntervals(values, withMinimum=false) {
let maxValue = Math.max(...values);
let minValue = Math.min(...values);
if (range.max !== undefined) {
maxValue = maxValue > range.max ? maxValue : range.max;
}
if (range.min !== undefined) {
minValue = minValue < range.min ? minValue : range.min;
}
// Exponent to be used for pretty print
let exponent = 0, intervals = []; // eslint-disable-line no-unused-vars

2622
yarn.lock

File diff suppressed because it is too large Load Diff