Compare commits
97 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8ae43fac6 | ||
|
|
0ee7f9a30f | ||
|
|
4967fc9e07 | ||
|
|
8cc3b45c18 | ||
|
|
bd77462d01 | ||
|
|
17994abb92 | ||
|
|
77cc7fde6c | ||
|
|
dc6ef83a7b | ||
|
|
f5fc2c1bf7 | ||
|
|
b6403b83c3 | ||
|
|
2e3011c267 | ||
|
|
2aab8dd315 | ||
|
|
ea95aece5a | ||
|
|
f2d2eb1e9e | ||
|
|
2b455e95a6 | ||
|
|
624cf70f03 | ||
|
|
5ea1d33fdf | ||
|
|
46191e7a53 | ||
|
|
95a19f09a3 | ||
|
|
8bc8231b21 | ||
|
|
c18c076adc | ||
|
|
a765508bbd | ||
|
|
cdf5fbe33b | ||
|
|
a26a81c866 | ||
|
|
f19d15f112 | ||
|
|
07597ebe87 | ||
|
|
9c0ecc89be | ||
|
|
3d6a349425 | ||
|
|
ce4126b3b1 | ||
|
|
f145d6bbe9 | ||
|
|
b7f20aab15 | ||
|
|
7c9cf65385 | ||
|
|
61717aee95 | ||
|
|
304d23502a | ||
|
|
db12dcf27c | ||
|
|
1b4e206a1e | ||
|
|
8d8096869f | ||
|
|
fa559cc8bd | ||
|
|
ed8f97efd5 | ||
|
|
8d68d9933e | ||
|
|
72d5507c6f | ||
|
|
d6ab5b952e | ||
|
|
4854591a89 | ||
|
|
a0265677a2 | ||
|
|
ba0d3703f5 | ||
|
|
bbe91840f7 | ||
|
|
94a7e02d75 | ||
|
|
d8984ec5ae | ||
|
|
067f5ea7f8 | ||
|
|
263f38c9ec | ||
|
|
7e13f81063 | ||
|
|
9cc7bde398 | ||
|
|
ce64f01a8b | ||
|
|
583d82a96e | ||
|
|
8308b9fd90 | ||
|
|
f413c75932 | ||
|
|
86bbb6d2aa | ||
|
|
d386d21e2f | ||
|
|
8101b1822e | ||
|
|
cff7ce4c27 | ||
|
|
690a7f4467 | ||
|
|
03f6436be4 | ||
|
|
8524e6cbd6 | ||
|
|
1181660ed1 | ||
|
|
26671b143b | ||
|
|
5d2c141f14 | ||
|
|
e2d7ce8b21 | ||
|
|
73f1d9b1e3 | ||
|
|
dc00b46a7a | ||
|
|
fd28107795 | ||
|
|
7cfa35a418 | ||
|
|
d84614cb65 | ||
|
|
610cfb1f6d | ||
|
|
767a905967 | ||
|
|
56a7374277 | ||
|
|
562a9cba55 | ||
|
|
4f4dd4d36f | ||
|
|
0257bc370e | ||
|
|
7dde276477 | ||
|
|
b12b916584 | ||
|
|
a7b06bb027 | ||
|
|
9dd24aa7a7 | ||
|
|
4d8321e9be | ||
|
|
399ff37b6a | ||
|
|
dc49b29d39 | ||
|
|
51a6ed33a5 | ||
|
|
f8c3f9d7b4 | ||
|
|
d3909d49c1 | ||
|
|
255e806533 | ||
|
|
6cb9bf6bd3 | ||
|
|
5e17dea6de | ||
|
|
89fc842330 | ||
|
|
63e0a0bdf4 | ||
|
|
d2dd27dfab | ||
|
|
846a21ae6a | ||
|
|
5b00da4974 | ||
|
|
069a5f7451 |
9
.deepsource.toml
Normal file
9
.deepsource.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
version = 1
|
||||||
|
|
||||||
|
[[analyzers]]
|
||||||
|
name = "javascript"
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[analyzers.meta]
|
||||||
|
environment = ["browser"]
|
||||||
|
style_guide = "standard"
|
||||||
14
.editorconfig
Normal file
14
.editorconfig
Normal 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
19
.github/workflows/publish.yml
vendored
Normal 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
3
.gitignore
vendored
@ -60,4 +60,7 @@ typings/
|
|||||||
# next.js build output
|
# next.js build output
|
||||||
.next
|
.next
|
||||||
|
|
||||||
|
# npm build output
|
||||||
|
dist
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
4459
dist/frappe-charts.cjs.js
vendored
4459
dist/frappe-charts.cjs.js
vendored
File diff suppressed because it is too large
Load Diff
4467
dist/frappe-charts.esm.js
vendored
4467
dist/frappe-charts.esm.js
vendored
File diff suppressed because it is too large
Load Diff
104
dist/frappe-charts.min.css
vendored
104
dist/frappe-charts.min.css
vendored
@ -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; }
|
|
||||||
1
dist/frappe-charts.umd.js
vendored
1
dist/frappe-charts.umd.js
vendored
File diff suppressed because one or more lines are too long
@ -1,2 +0,0 @@
|
|||||||
plugins:
|
|
||||||
- jekyll-redirect-from
|
|
||||||
7
docs/assets/css/bootstrap.min.css
vendored
7
docs/assets/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
@ -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;
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
@ -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 |
@ -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],
|
|
||||||
};
|
|
||||||
@ -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',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
2
docs/assets/js/frappe-charts.min.js
vendored
2
docs/assets/js/frappe-charts.min.js
vendored
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
@ -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();
|
|
||||||
});
|
|
||||||
648
docs/assets/js/index.min.js
vendored
648
docs/assets/js/index.min.js
vendored
@ -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
323
docs/index.html
323
docs/index.html
@ -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"> <!--HTML-->
|
|
||||||
<div id="chart"></div></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"> <script src="https://unpkg.com/frappe-charts@1.1.0"></script></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>
|
|
||||||
15
package.json
15
package.json
@ -1,11 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "frappe-charts",
|
"name": "frappe-charts",
|
||||||
"version": "1.5.2",
|
"version": "2.0.0-rc26",
|
||||||
"main": "dist/frappe-charts.cjs.js",
|
"main": "dist/frappe-charts.esm.js",
|
||||||
"common": "dist/frappe-charts.cjs.js",
|
|
||||||
"module": "dist/frappe-charts.esm.js",
|
"module": "dist/frappe-charts.esm.js",
|
||||||
"browser": "dist/frappe-charts.umd.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",
|
"description": "https://frappe.github.io/charts",
|
||||||
"directories": {
|
"directories": {
|
||||||
"doc": "docs"
|
"doc": "docs"
|
||||||
@ -39,10 +40,12 @@
|
|||||||
"@babel/preset-env": "^7.10.4",
|
"@babel/preset-env": "^7.10.4",
|
||||||
"rollup": "^2.21.0",
|
"rollup": "^2.21.0",
|
||||||
"rollup-plugin-babel": "^4.4.0",
|
"rollup-plugin-babel": "^4.4.0",
|
||||||
|
"rollup-plugin-bundle-size": "^1.0.3",
|
||||||
"rollup-plugin-commonjs": "^10.1.0",
|
"rollup-plugin-commonjs": "^10.1.0",
|
||||||
"rollup-plugin-eslint": "^7.0.0",
|
"rollup-plugin-eslint": "^7.0.0",
|
||||||
"rollup-plugin-postcss": "^3.1.3",
|
"rollup-plugin-postcss": "^3.1.3",
|
||||||
"rollup-plugin-scss": "^2.5.0",
|
"rollup-plugin-scss": "^4.0.1",
|
||||||
"rollup-plugin-terser": "^6.1.0"
|
"rollup-plugin-terser": "^6.1.0",
|
||||||
|
"sass": "^1.86.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,6 +4,7 @@ import commonjs from 'rollup-plugin-commonjs';
|
|||||||
import babel from 'rollup-plugin-babel';
|
import babel from 'rollup-plugin-babel';
|
||||||
import postcss from 'rollup-plugin-postcss';
|
import postcss from 'rollup-plugin-postcss';
|
||||||
import scss from 'rollup-plugin-scss';
|
import scss from 'rollup-plugin-scss';
|
||||||
|
import bundleSize from 'rollup-plugin-bundle-size';
|
||||||
import { terser } from 'rollup-plugin-terser';
|
import { terser } from 'rollup-plugin-terser';
|
||||||
|
|
||||||
|
|
||||||
@ -12,6 +13,7 @@ export default [
|
|||||||
{
|
{
|
||||||
input: 'src/js/index.js',
|
input: 'src/js/index.js',
|
||||||
output: {
|
output: {
|
||||||
|
sourcemap: true,
|
||||||
name: 'frappe-charts',
|
name: 'frappe-charts',
|
||||||
file: pkg.browser,
|
file: pkg.browser,
|
||||||
format: 'umd'
|
format: 'umd'
|
||||||
@ -22,7 +24,8 @@ export default [
|
|||||||
exclude: ['node_modules/**']
|
exclude: ['node_modules/**']
|
||||||
}),
|
}),
|
||||||
terser(),
|
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',
|
input: 'src/js/chart.js',
|
||||||
output: [
|
output: [
|
||||||
{ file: pkg.common, format: 'cjs' },
|
{ file: pkg.common, format: 'cjs', sourcemap: true },
|
||||||
{ file: pkg.module, format: 'es' }
|
{ file: pkg.module, format: 'es', sourcemap: true },
|
||||||
],
|
],
|
||||||
plugins: [
|
plugins: [
|
||||||
babel({
|
babel({
|
||||||
exclude: ['node_modules/**']
|
exclude: ['node_modules/**']
|
||||||
}),
|
}),
|
||||||
postcss()
|
terser(),
|
||||||
|
postcss(),
|
||||||
|
bundleSize()
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@ -1,54 +1,58 @@
|
|||||||
:root {
|
:root {
|
||||||
--fr-label-color: #313b44;
|
--charts-label-color: #313b44;
|
||||||
--fr-axis-line-color: #E2E6E9;
|
--charts-axis-line-color: #f4f5f6;
|
||||||
|
|
||||||
--fr-stroke-width: 2px;
|
--charts-tooltip-title: var(--charts-label-color);
|
||||||
--fr-dataset-circle-stroke: #FFFFFF;
|
--charts-tooltip-label: var(--charts-label-color);
|
||||||
--fr-dataset-circle-stroke-width: var(--fr-stroke-width);
|
--charts-tooltip-value: #192734;
|
||||||
|
--charts-tooltip-bg: #ffffff;
|
||||||
|
|
||||||
--fr-tooltip-title: var(--fr-label-color);
|
--charts-stroke-width: 2px;
|
||||||
--fr-tooltip-label: var(--fr-label-color);
|
--charts-dataset-circle-stroke: #ffffff;
|
||||||
--fr-tooltip-value: #192734;
|
--charts-dataset-circle-stroke-width: var(--charts-stroke-width);
|
||||||
--fr-tooltip-bg: #FFFFFF;
|
|
||||||
|
--charts-legend-label: var(--charts-label-color);
|
||||||
|
--charts-legend-value: var(--charts-label-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-container {
|
.chart-container {
|
||||||
position: relative; /* for absolutely positioned tooltip */
|
position: relative; /* for absolutely positioned tooltip */
|
||||||
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont,
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
||||||
'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell',
|
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
|
||||||
'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
"Helvetica Neue", sans-serif;
|
||||||
|
|
||||||
.axis, .chart-label {
|
.axis,
|
||||||
fill: var(--fr-label-color);
|
.chart-label {
|
||||||
|
fill: var(--charts-label-color);
|
||||||
|
|
||||||
line {
|
line {
|
||||||
stroke: var(--fr-axis-line-color);
|
stroke: var(--charts-axis-line-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dataset-units {
|
.dataset-units {
|
||||||
circle {
|
circle {
|
||||||
stroke: var(--fr-dataset-circle-stroke);
|
stroke: var(--charts-dataset-circle-stroke);
|
||||||
stroke-width: var(--fr-dataset-circle-stroke-width);
|
stroke-width: var(--charts-dataset-circle-stroke-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
path {
|
path {
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke-opacity: 1;
|
stroke-opacity: 1;
|
||||||
stroke-width: var(--fr-stroke-width);
|
stroke-width: var(--charts-stroke-width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dataset-path {
|
.dataset-path {
|
||||||
stroke-width: var(--fr-stroke-width);
|
stroke-width: var(--charts-stroke-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
.path-group {
|
.path-group {
|
||||||
path {
|
path {
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke-opacity: 1;
|
stroke-opacity: 1;
|
||||||
stroke-width: var(--fr-stroke-width);
|
stroke-width: var(--charts-stroke-width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,12 +73,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.legend-dataset-label {
|
.legend-dataset-label {
|
||||||
fill: var(--fr-tooltip-label);
|
fill: var(--charts-legend-label);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.legend-dataset-value {
|
.legend-dataset-value {
|
||||||
fill: var(--fr-tooltip-value);
|
fill: var(--charts-legend-value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,8 +88,10 @@
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: var(--fr-tooltip-bg);
|
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);
|
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;
|
border-radius: 6px;
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
@ -110,7 +116,7 @@
|
|||||||
height: 12px;
|
height: 12px;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background: var(--fr-tooltip-bg);
|
background: var(--charts-tooltip-bg);
|
||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
margin-top: -7px;
|
margin-top: -7px;
|
||||||
margin-left: -6px;
|
margin-left: -6px;
|
||||||
@ -125,11 +131,15 @@
|
|||||||
display: block;
|
display: block;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--fr-tooltip-title);
|
color: var(--charts-tooltip-title);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: var(--charts-tooltip-value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
@ -163,16 +173,15 @@
|
|||||||
.tooltip-label {
|
.tooltip-label {
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
max-width: 100px;
|
line-height: 1.25;
|
||||||
|
max-width: 150px;
|
||||||
|
white-space: normal;
|
||||||
|
|
||||||
color: var(--fr-tooltip-label);
|
color: var(--charts-tooltip-label);
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip-value {
|
.tooltip-value {
|
||||||
color: var(--fr-tooltip-value);
|
color: var(--charts-tooltip-value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import '../css/charts.scss';
|
import '../css/charts.scss';
|
||||||
|
|
||||||
// import MultiAxisChart from './charts/MultiAxisChart';
|
|
||||||
import PercentageChart from './charts/PercentageChart';
|
import PercentageChart from './charts/PercentageChart';
|
||||||
import PieChart from './charts/PieChart';
|
import PieChart from './charts/PieChart';
|
||||||
import Heatmap from './charts/Heatmap';
|
import Heatmap from './charts/Heatmap';
|
||||||
@ -10,7 +9,6 @@ import DonutChart from './charts/DonutChart';
|
|||||||
const chartTypes = {
|
const chartTypes = {
|
||||||
bar: AxisChart,
|
bar: AxisChart,
|
||||||
line: AxisChart,
|
line: AxisChart,
|
||||||
// multiaxis: MultiAxisChart,
|
|
||||||
percentage: PercentageChart,
|
percentage: PercentageChart,
|
||||||
heatmap: Heatmap,
|
heatmap: Heatmap,
|
||||||
pie: PieChart,
|
pie: PieChart,
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
import BaseChart from './BaseChart';
|
import BaseChart from './BaseChart';
|
||||||
import { truncateString } from '../utils/draw-utils';
|
|
||||||
import { legendDot } from '../utils/draw';
|
import { legendDot } from '../utils/draw';
|
||||||
import { round } from '../utils/helpers';
|
import { round } from '../utils/helpers';
|
||||||
import { getExtraWidth } from '../utils/constants';
|
|
||||||
|
|
||||||
export default class AggregationChart extends BaseChart {
|
export default class AggregationChart extends BaseChart {
|
||||||
constructor(parent, args) {
|
constructor(parent, args) {
|
||||||
@ -15,6 +13,7 @@ export default class AggregationChart extends BaseChart {
|
|||||||
this.config.formatTooltipY = (args.tooltipOptions || {}).formatTooltipY;
|
this.config.formatTooltipY = (args.tooltipOptions || {}).formatTooltipY;
|
||||||
this.config.maxSlices = args.maxSlices || 20;
|
this.config.maxSlices = args.maxSlices || 20;
|
||||||
this.config.maxLegendPoints = args.maxLegendPoints || 20;
|
this.config.maxLegendPoints = args.maxLegendPoints || 20;
|
||||||
|
this.config.legendRowHeight = 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
calc() {
|
calc() {
|
||||||
@ -31,17 +30,17 @@ export default class AggregationChart extends BaseChart {
|
|||||||
}).filter(d => { return d[0] >= 0; }); // keep only positive results
|
}).filter(d => { return d[0] >= 0; }); // keep only positive results
|
||||||
|
|
||||||
let totals = allTotals;
|
let totals = allTotals;
|
||||||
if(allTotals.length > maxSlices) {
|
if (allTotals.length > maxSlices) {
|
||||||
// Prune and keep a grey area for rest as per maxSlices
|
// Prune and keep a grey area for rest as per maxSlices
|
||||||
allTotals.sort((a, b) => { return b[0] - a[0]; });
|
allTotals.sort((a, b) => { return b[0] - a[0]; });
|
||||||
|
|
||||||
totals = allTotals.slice(0, maxSlices-1);
|
totals = allTotals.slice(0, maxSlices - 1);
|
||||||
let remaining = allTotals.slice(maxSlices-1);
|
let remaining = allTotals.slice(maxSlices - 1);
|
||||||
|
|
||||||
let sumOfRemaining = 0;
|
let sumOfRemaining = 0;
|
||||||
remaining.map(d => {sumOfRemaining += d[0];});
|
remaining.map(d => { sumOfRemaining += d[0]; });
|
||||||
totals.push([sumOfRemaining, 'Rest']);
|
totals.push([sumOfRemaining, 'Rest']);
|
||||||
this.colors[maxSlices-1] = 'grey';
|
this.colors[maxSlices - 1] = 'grey';
|
||||||
}
|
}
|
||||||
|
|
||||||
s.labels = [];
|
s.labels = [];
|
||||||
@ -62,36 +61,22 @@ export default class AggregationChart extends BaseChart {
|
|||||||
let s = this.state;
|
let s = this.state;
|
||||||
this.legendArea.textContent = '';
|
this.legendArea.textContent = '';
|
||||||
this.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints);
|
this.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints);
|
||||||
|
super.renderLegend(this.legendTotals);
|
||||||
|
}
|
||||||
|
|
||||||
let count = 0;
|
makeLegend(data, index, x_pos, y_pos) {
|
||||||
let y = 0;
|
let formatted = this.config.formatTooltipY ? this.config.formatTooltipY(data) : data;
|
||||||
this.legendTotals.map((d, i) => {
|
|
||||||
let barWidth = 150;
|
return legendDot(
|
||||||
let divisor = Math.floor(
|
x_pos,
|
||||||
(this.width - getExtraWidth(this.measures))/barWidth
|
y_pos,
|
||||||
);
|
12, // size
|
||||||
if (this.legendTotals.length < divisor) {
|
3, // dot radius
|
||||||
barWidth = this.width/this.legendTotals.length;
|
this.colors[index], // fill
|
||||||
}
|
this.state.labels[index], // label
|
||||||
if(count > divisor) {
|
formatted, // value
|
||||||
count = 0;
|
null, // base_font_size
|
||||||
y += 60;
|
this.config.truncateLegends // truncate_legends
|
||||||
}
|
);
|
||||||
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++;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
import BaseChart from './BaseChart';
|
import BaseChart from './BaseChart';
|
||||||
import { dataPrep, zeroDataPrep, getShortenedLabels } from '../utils/axis-chart-utils';
|
import { dataPrep, zeroDataPrep, getShortenedLabels } from '../utils/axis-chart-utils';
|
||||||
import { AXIS_LEGEND_BAR_SIZE } from '../utils/constants';
|
|
||||||
import { getComponent } from '../objects/ChartComponents';
|
import { getComponent } from '../objects/ChartComponents';
|
||||||
import { getOffset, fire } from '../utils/dom';
|
import { getOffset, fire } from '../utils/dom';
|
||||||
import { calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex, scale, getClosestInArray } from '../utils/intervals';
|
import { calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex, scale, getClosestInArray } from '../utils/intervals';
|
||||||
import { floatTwo } from '../utils/helpers';
|
import { floatTwo } from '../utils/helpers';
|
||||||
import { makeOverlay, updateOverlay, legendBar } from '../utils/draw';
|
import { makeOverlay, updateOverlay, legendDot } from '../utils/draw';
|
||||||
import { getTopOffset, getLeftOffset, MIN_BAR_PERCENT_HEIGHT, BAR_CHART_SPACE_RATIO,
|
import {
|
||||||
LINE_CHART_DOT_SIZE } from '../utils/constants';
|
getTopOffset, getLeftOffset, MIN_BAR_PERCENT_HEIGHT, BAR_CHART_SPACE_RATIO,
|
||||||
|
LINE_CHART_DOT_SIZE
|
||||||
|
} from '../utils/constants';
|
||||||
|
|
||||||
export default class AxisChart extends BaseChart {
|
export default class AxisChart extends BaseChart {
|
||||||
constructor(parent, args) {
|
constructor(parent, args) {
|
||||||
@ -23,7 +24,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setMeasures() {
|
setMeasures() {
|
||||||
if(this.data.datasets.length <= 1) {
|
if (this.data.datasets.length <= 1) {
|
||||||
this.config.showLegend = 0;
|
this.config.showLegend = 0;
|
||||||
this.measures.paddings.bottom = 30;
|
this.measures.paddings.bottom = 30;
|
||||||
}
|
}
|
||||||
@ -39,24 +40,29 @@ export default class AxisChart extends BaseChart {
|
|||||||
this.config.yAxisMode = options.axisOptions.yAxisMode || 'span';
|
this.config.yAxisMode = options.axisOptions.yAxisMode || 'span';
|
||||||
this.config.xIsSeries = options.axisOptions.xIsSeries || 0;
|
this.config.xIsSeries = options.axisOptions.xIsSeries || 0;
|
||||||
this.config.shortenYAxisNumbers = options.axisOptions.shortenYAxisNumbers || 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.formatTooltipX = options.tooltipOptions.formatTooltipX;
|
||||||
this.config.formatTooltipY = options.tooltipOptions.formatTooltipY;
|
this.config.formatTooltipY = options.tooltipOptions.formatTooltipY;
|
||||||
|
|
||||||
this.config.valuesOverPoints = options.valuesOverPoints;
|
this.config.valuesOverPoints = options.valuesOverPoints;
|
||||||
|
this.config.legendRowHeight = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareData(data=this.data) {
|
prepareData(data = this.data) {
|
||||||
return dataPrep(data, this.type);
|
return dataPrep(data, this.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareFirstData(data=this.data) {
|
prepareFirstData(data = this.data) {
|
||||||
return zeroDataPrep(data);
|
return zeroDataPrep(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
calc(onlyWidthChange = false) {
|
calc(onlyWidthChange = false) {
|
||||||
this.calcXPositions();
|
this.calcXPositions();
|
||||||
if(!onlyWidthChange) {
|
if (!onlyWidthChange) {
|
||||||
this.calcYAxisParameters(this.getAllYValues(), this.type === 'line');
|
this.calcYAxisParameters(this.getAllYValues(), this.type === 'line');
|
||||||
}
|
}
|
||||||
this.makeDataByIndex();
|
this.makeDataByIndex();
|
||||||
@ -67,9 +73,9 @@ export default class AxisChart extends BaseChart {
|
|||||||
let labels = this.data.labels;
|
let labels = this.data.labels;
|
||||||
s.datasetLength = labels.length;
|
s.datasetLength = labels.length;
|
||||||
|
|
||||||
s.unitWidth = this.width/(s.datasetLength);
|
s.unitWidth = this.width / (s.datasetLength);
|
||||||
// Default, as per bar, and mixed. Only line will be a special case
|
// Default, as per bar, and mixed. Only line will be a special case
|
||||||
s.xOffset = s.unitWidth/2;
|
s.xOffset = s.unitWidth / 2;
|
||||||
|
|
||||||
// // For a pure Line Chart
|
// // For a pure Line Chart
|
||||||
// s.unitWidth = this.width/(s.datasetLength - 1);
|
// s.unitWidth = this.width/(s.datasetLength - 1);
|
||||||
@ -84,7 +90,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
calcYAxisParameters(dataValues, withMinimum = 'false') {
|
calcYAxisParameters(dataValues, withMinimum = 'false') {
|
||||||
const yPts = calcChartIntervals(dataValues, withMinimum);
|
const yPts = calcChartIntervals(dataValues, withMinimum, this.config.yAxisRange);
|
||||||
const scaleMultiplier = this.height / getValueRange(yPts);
|
const scaleMultiplier = this.height / getValueRange(yPts);
|
||||||
const intervalHeight = getIntervalSize(yPts) * scaleMultiplier;
|
const intervalHeight = getIntervalSize(yPts) * scaleMultiplier;
|
||||||
const zeroLine = this.height - (getZeroIndex(yPts) * intervalHeight);
|
const zeroLine = this.height - (getZeroIndex(yPts) * intervalHeight);
|
||||||
@ -110,7 +116,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
let values = d.values;
|
let values = d.values;
|
||||||
let cumulativeYs = d.cumulativeYs || [];
|
let cumulativeYs = d.cumulativeYs || [];
|
||||||
return {
|
return {
|
||||||
name: d.name.replace(/<|>|&/g, (char) => char == '&' ? '&' : char == '<' ? '<' : '>'),
|
name: d.name && d.name.replace(/<|>|&/g, (char) => char == '&' ? '&' : char == '<' ? '<' : '>'),
|
||||||
index: i,
|
index: i,
|
||||||
chartType: d.chartType,
|
chartType: d.chartType,
|
||||||
|
|
||||||
@ -125,14 +131,14 @@ export default class AxisChart extends BaseChart {
|
|||||||
|
|
||||||
calcYExtremes() {
|
calcYExtremes() {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
if(this.barOptions.stacked) {
|
if (this.barOptions.stacked) {
|
||||||
s.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos;
|
s.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s.yExtremes = new Array(s.datasetLength).fill(9999);
|
s.yExtremes = new Array(s.datasetLength).fill(9999);
|
||||||
s.datasets.map(d => {
|
s.datasets.map(d => {
|
||||||
d.yPositions.map((pos, j) => {
|
d.yPositions.map((pos, j) => {
|
||||||
if(pos < s.yExtremes[j]) {
|
if (pos < s.yExtremes[j]) {
|
||||||
s.yExtremes[j] = pos;
|
s.yExtremes[j] = pos;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -141,21 +147,21 @@ export default class AxisChart extends BaseChart {
|
|||||||
|
|
||||||
calcYRegions() {
|
calcYRegions() {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
if(this.data.yMarkers) {
|
if (this.data.yMarkers) {
|
||||||
this.state.yMarkers = this.data.yMarkers.map(d => {
|
this.state.yMarkers = this.data.yMarkers.map(d => {
|
||||||
d.position = scale(d.value, s.yAxis);
|
d.position = scale(d.value, s.yAxis);
|
||||||
if(!d.options) d.options = {};
|
if (!d.options) d.options = {};
|
||||||
// if(!d.label.includes(':')) {
|
// if(!d.label.includes(':')) {
|
||||||
// d.label += ': ' + d.value;
|
// d.label += ': ' + d.value;
|
||||||
// }
|
// }
|
||||||
return d;
|
return d;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if(this.data.yRegions) {
|
if (this.data.yRegions) {
|
||||||
this.state.yRegions = this.data.yRegions.map(d => {
|
this.state.yRegions = this.data.yRegions.map(d => {
|
||||||
d.startPos = scale(d.start, s.yAxis);
|
d.startPos = scale(d.start, s.yAxis);
|
||||||
d.endPos = scale(d.end, s.yAxis);
|
d.endPos = scale(d.end, s.yAxis);
|
||||||
if(!d.options) d.options = {};
|
if (!d.options) d.options = {};
|
||||||
return d;
|
return d;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -164,7 +170,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
getAllYValues() {
|
getAllYValues() {
|
||||||
let key = 'values';
|
let key = 'values';
|
||||||
|
|
||||||
if(this.barOptions.stacked) {
|
if (this.barOptions.stacked) {
|
||||||
key = 'cumulativeYs';
|
key = 'cumulativeYs';
|
||||||
let cumulative = new Array(this.state.datasetLength).fill(0);
|
let cumulative = new Array(this.state.datasetLength).fill(0);
|
||||||
this.data.datasets.map((d, i) => {
|
this.data.datasets.map((d, i) => {
|
||||||
@ -174,10 +180,10 @@ export default class AxisChart extends BaseChart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let allValueLists = this.data.datasets.map(d => d[key]);
|
let allValueLists = this.data.datasets.map(d => d[key]);
|
||||||
if(this.data.yMarkers) {
|
if (this.data.yMarkers) {
|
||||||
allValueLists.push(this.data.yMarkers.map(d => d.value));
|
allValueLists.push(this.data.yMarkers.map(d => d.value));
|
||||||
}
|
}
|
||||||
if(this.data.yRegions) {
|
if (this.data.yRegions) {
|
||||||
this.data.yRegions.map(d => {
|
this.data.yRegions.map(d => {
|
||||||
allValueLists.push([d.end, d.start]);
|
allValueLists.push([d.end, d.start]);
|
||||||
});
|
});
|
||||||
@ -193,10 +199,10 @@ export default class AxisChart extends BaseChart {
|
|||||||
{
|
{
|
||||||
mode: this.config.yAxisMode,
|
mode: this.config.yAxisMode,
|
||||||
width: this.width,
|
width: this.width,
|
||||||
shortenNumbers: this.config.shortenYAxisNumbers
|
shortenNumbers: this.config.shortenYAxisNumbers,
|
||||||
// pos: 'right'
|
numberFormatter: this.config.numberFormatter,
|
||||||
},
|
},
|
||||||
function() {
|
function () {
|
||||||
return this.state.yAxis;
|
return this.state.yAxis;
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
],
|
],
|
||||||
@ -208,10 +214,10 @@ export default class AxisChart extends BaseChart {
|
|||||||
height: this.height,
|
height: this.height,
|
||||||
// pos: 'right'
|
// pos: 'right'
|
||||||
},
|
},
|
||||||
function() {
|
function () {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
s.xAxis.calcLabels = getShortenedLabels(this.width,
|
s.xAxis.calcLabels = getShortenedLabels(this.width,
|
||||||
s.xAxis.labels, this.config.xIsSeries);
|
s.xAxis.labels, this.config.xIsSeries,this.config.seriesLabelSpaceRatio);
|
||||||
|
|
||||||
return s.xAxis;
|
return s.xAxis;
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
@ -223,7 +229,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
width: this.width,
|
width: this.width,
|
||||||
pos: 'right'
|
pos: 'right'
|
||||||
},
|
},
|
||||||
function() {
|
function () {
|
||||||
return this.state.yRegions;
|
return this.state.yRegions;
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
],
|
],
|
||||||
@ -245,23 +251,23 @@ export default class AxisChart extends BaseChart {
|
|||||||
valuesOverPoints: this.config.valuesOverPoints,
|
valuesOverPoints: this.config.valuesOverPoints,
|
||||||
minHeight: this.height * MIN_BAR_PERCENT_HEIGHT,
|
minHeight: this.height * MIN_BAR_PERCENT_HEIGHT,
|
||||||
},
|
},
|
||||||
function() {
|
function () {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
let d = s.datasets[index];
|
let d = s.datasets[index];
|
||||||
let stacked = this.barOptions.stacked;
|
let stacked = this.barOptions.stacked;
|
||||||
|
|
||||||
let spaceRatio = this.barOptions.spaceRatio || BAR_CHART_SPACE_RATIO;
|
let spaceRatio = this.barOptions.spaceRatio || BAR_CHART_SPACE_RATIO;
|
||||||
let barsWidth = s.unitWidth * (1 - spaceRatio);
|
let barsWidth = s.unitWidth * (1 - spaceRatio);
|
||||||
let barWidth = barsWidth/(stacked ? 1 : barDatasets.length);
|
let barWidth = barsWidth / (stacked ? 1 : barDatasets.length);
|
||||||
|
|
||||||
let xPositions = s.xAxis.positions.map(x => x - barsWidth/2);
|
let xPositions = s.xAxis.positions.map(x => x - barsWidth / 2);
|
||||||
if(!stacked) {
|
if (!stacked) {
|
||||||
xPositions = xPositions.map(p => p + barWidth * index);
|
xPositions = xPositions.map(p => p + barWidth * index);
|
||||||
}
|
}
|
||||||
|
|
||||||
let labels = new Array(s.datasetLength).fill('');
|
let labels = new Array(s.datasetLength).fill('');
|
||||||
if(this.config.valuesOverPoints) {
|
if (this.config.valuesOverPoints) {
|
||||||
if(stacked && d.index === s.datasets.length - 1) {
|
if (stacked && d.index === s.datasets.length - 1) {
|
||||||
labels = d.cumulativeYs;
|
labels = d.cumulativeYs;
|
||||||
} else {
|
} else {
|
||||||
labels = d.values;
|
labels = d.values;
|
||||||
@ -269,7 +275,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let offsets = new Array(s.datasetLength).fill(0);
|
let offsets = new Array(s.datasetLength).fill(0);
|
||||||
if(stacked) {
|
if (stacked) {
|
||||||
offsets = d.yPositions.map((y, j) => y - d.cumulativeYPos[j]);
|
offsets = d.yPositions.map((y, j) => y - d.cumulativeYPos[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,13 +305,15 @@ export default class AxisChart extends BaseChart {
|
|||||||
heatline: this.lineOptions.heatline,
|
heatline: this.lineOptions.heatline,
|
||||||
regionFill: this.lineOptions.regionFill,
|
regionFill: this.lineOptions.regionFill,
|
||||||
spline: this.lineOptions.spline,
|
spline: this.lineOptions.spline,
|
||||||
hideDots: this.lineOptions.hideDots,
|
showDots: this.lineOptions.showDots,
|
||||||
|
trailingDot: this.lineOptions.trailingDot,
|
||||||
|
hideDotBorder: this.lineOptions.hideDotBorder,
|
||||||
hideLine: this.lineOptions.hideLine,
|
hideLine: this.lineOptions.hideLine,
|
||||||
|
|
||||||
// same for all datasets
|
// same for all datasets
|
||||||
valuesOverPoints: this.config.valuesOverPoints,
|
valuesOverPoints: this.config.valuesOverPoints,
|
||||||
},
|
},
|
||||||
function() {
|
function () {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
let d = s.datasets[index];
|
let d = s.datasets[index];
|
||||||
let minLine = s.yAxis.positions[0] < s.yAxis.zeroLine
|
let minLine = s.yAxis.positions[0] < s.yAxis.zeroLine
|
||||||
@ -331,7 +339,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
width: this.width,
|
width: this.width,
|
||||||
pos: 'right'
|
pos: 'right'
|
||||||
},
|
},
|
||||||
function() {
|
function () {
|
||||||
return this.state.yMarkers;
|
return this.state.yMarkers;
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
]
|
]
|
||||||
@ -346,7 +354,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
.filter(args => !optionals.includes(args[0]) || this.state[args[0]])
|
.filter(args => !optionals.includes(args[0]) || this.state[args[0]])
|
||||||
.map(args => {
|
.map(args => {
|
||||||
let component = getComponent(...args);
|
let component = getComponent(...args);
|
||||||
if(args[0].includes('lineGraph') || args[0].includes('barGraph')) {
|
if (args[0].includes('lineGraph') || args[0].includes('barGraph')) {
|
||||||
this.dataUnitComponents.push(component);
|
this.dataUnitComponents.push(component);
|
||||||
}
|
}
|
||||||
return [args[0], component];
|
return [args[0], component];
|
||||||
@ -369,7 +377,11 @@ export default class AxisChart extends BaseChart {
|
|||||||
value: value,
|
value: value,
|
||||||
yPos: set.yPositions[index],
|
yPos: set.yPositions[index],
|
||||||
color: this.colors[i],
|
color: this.colors[i],
|
||||||
formatted: formatY ? formatY(value) : value,
|
formatted: formatY ? formatY(value, {
|
||||||
|
name: set.name,
|
||||||
|
index: set.index,
|
||||||
|
values: set.values
|
||||||
|
}) : value,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -391,8 +403,8 @@ export default class AxisChart extends BaseChart {
|
|||||||
let relX = e.pageX - o.left - getLeftOffset(m);
|
let relX = e.pageX - o.left - getLeftOffset(m);
|
||||||
let relY = e.pageY - o.top;
|
let relY = e.pageY - o.top;
|
||||||
|
|
||||||
if(relY < this.height + getTopOffset(m)
|
if (relY < this.height + getTopOffset(m)
|
||||||
&& relY > getTopOffset(m)) {
|
&& relY > getTopOffset(m)) {
|
||||||
this.mapTooltipXPosition(relX);
|
this.mapTooltipXPosition(relX);
|
||||||
} else {
|
} else {
|
||||||
this.tip.hideTip();
|
this.tip.hideTip();
|
||||||
@ -402,7 +414,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
|
|
||||||
mapTooltipXPosition(relX) {
|
mapTooltipXPosition(relX) {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
if(!s.yExtremes) return;
|
if (!s.yExtremes) return;
|
||||||
|
|
||||||
let index = getClosestInArray(relX, s.xAxis.positions, true);
|
let index = getClosestInArray(relX, s.xAxis.positions, true);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
@ -411,7 +423,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
this.tip.setValues(
|
this.tip.setValues(
|
||||||
dbi.xPos + this.tip.offset.x,
|
dbi.xPos + this.tip.offset.x,
|
||||||
dbi.yExtreme + this.tip.offset.y,
|
dbi.yExtreme + this.tip.offset.y,
|
||||||
{name: dbi.formattedLabel, value: ''},
|
{ name: dbi.formattedLabel, value: '' },
|
||||||
dbi.values,
|
dbi.values,
|
||||||
index
|
index
|
||||||
);
|
);
|
||||||
@ -422,34 +434,32 @@ export default class AxisChart extends BaseChart {
|
|||||||
|
|
||||||
renderLegend() {
|
renderLegend() {
|
||||||
let s = this.data;
|
let s = this.data;
|
||||||
if(s.datasets.length > 1) {
|
if (s.datasets.length > 1) {
|
||||||
this.legendArea.textContent = '';
|
super.renderLegend(s.datasets);
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// Overlay
|
||||||
makeOverlay() {
|
makeOverlay() {
|
||||||
if(this.init) {
|
if (this.init) {
|
||||||
this.init = 0;
|
this.init = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(this.overlayGuides) {
|
if (this.overlayGuides) {
|
||||||
this.overlayGuides.forEach(g => {
|
this.overlayGuides.forEach(g => {
|
||||||
let o = g.overlay;
|
let o = g.overlay;
|
||||||
o.parentNode.removeChild(o);
|
o.parentNode.removeChild(o);
|
||||||
@ -464,7 +474,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
if(this.state.currentIndex === undefined) {
|
if (this.state.currentIndex === undefined) {
|
||||||
this.state.currentIndex = this.state.datasetLength - 1;
|
this.state.currentIndex = this.state.datasetLength - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,7 +488,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateOverlayGuides() {
|
updateOverlayGuides() {
|
||||||
if(this.overlayGuides) {
|
if (this.overlayGuides) {
|
||||||
this.overlayGuides.forEach(g => {
|
this.overlayGuides.forEach(g => {
|
||||||
let o = g.overlay;
|
let o = g.overlay;
|
||||||
o.parentNode.removeChild(o);
|
o.parentNode.removeChild(o);
|
||||||
@ -524,7 +534,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
this.setCurrentDataPoint(this.state.currentIndex + 1);
|
this.setCurrentDataPoint(this.state.currentIndex + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDataPoint(index=this.state.currentIndex) {
|
getDataPoint(index = this.state.currentIndex) {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
let data_point = {
|
let data_point = {
|
||||||
index: index,
|
index: index,
|
||||||
@ -537,9 +547,9 @@ export default class AxisChart extends BaseChart {
|
|||||||
setCurrentDataPoint(index) {
|
setCurrentDataPoint(index) {
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
index = parseInt(index);
|
index = parseInt(index);
|
||||||
if(index < 0) index = 0;
|
if (index < 0) index = 0;
|
||||||
if(index >= s.xAxis.labels.length) index = s.xAxis.labels.length - 1;
|
if (index >= s.xAxis.labels.length) index = s.xAxis.labels.length - 1;
|
||||||
if(index === s.currentIndex) return;
|
if (index === s.currentIndex) return;
|
||||||
s.currentIndex = index;
|
s.currentIndex = index;
|
||||||
fire(this.parent, "data-select", this.getDataPoint());
|
fire(this.parent, "data-select", this.getDataPoint());
|
||||||
}
|
}
|
||||||
@ -547,7 +557,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
|
|
||||||
|
|
||||||
// API
|
// API
|
||||||
addDataPoint(label, datasetValues, index=this.state.datasetLength) {
|
addDataPoint(label, datasetValues, index = this.state.datasetLength) {
|
||||||
super.addDataPoint(label, datasetValues, index);
|
super.addDataPoint(label, datasetValues, index);
|
||||||
this.data.labels.splice(index, 0, label);
|
this.data.labels.splice(index, 0, label);
|
||||||
this.data.datasets.map((d, i) => {
|
this.data.datasets.map((d, i) => {
|
||||||
@ -556,7 +566,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
this.update(this.data);
|
this.update(this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeDataPoint(index = this.state.datasetLength-1) {
|
removeDataPoint(index = this.state.datasetLength - 1) {
|
||||||
if (this.data.labels.length <= 1) {
|
if (this.data.labels.length <= 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -568,7 +578,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
this.update(this.data);
|
this.update(this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDataset(datasetValues, index=0) {
|
updateDataset(datasetValues, index = 0) {
|
||||||
this.data.datasets[index].values = datasetValues;
|
this.data.datasets[index].values = datasetValues;
|
||||||
this.update(this.data);
|
this.update(this.data);
|
||||||
}
|
}
|
||||||
@ -577,7 +587,7 @@ export default class AxisChart extends BaseChart {
|
|||||||
|
|
||||||
updateDatasets(datasets) {
|
updateDatasets(datasets) {
|
||||||
this.data.datasets.map((d, i) => {
|
this.data.datasets.map((d, i) => {
|
||||||
if(datasets[i]) {
|
if (datasets[i]) {
|
||||||
d.values = datasets[i];
|
d.values = datasets[i];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,14 +1,19 @@
|
|||||||
import SvgTip from '../objects/SvgTip';
|
import SvgTip from '../objects/SvgTip';
|
||||||
import { $, isElementInViewport, getElementContentWidth, isHidden } from '../utils/dom';
|
import { $, isElementInViewport, getElementContentWidth, isHidden } from '../utils/dom';
|
||||||
import { makeSVGContainer, makeSVGDefs, makeSVGGroup, makeText } from '../utils/draw';
|
import { makeSVGContainer, makeSVGDefs, makeSVGGroup, makeText } from '../utils/draw';
|
||||||
import { BASE_MEASURES, getExtraHeight, getExtraWidth, getTopOffset, getLeftOffset,
|
import { LEGEND_ITEM_WIDTH } from '../utils/constants';
|
||||||
INIT_CHART_UPDATE_TIMEOUT, CHART_POST_ANIMATE_TIMEOUT, DEFAULT_COLORS} 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 { getColor, isValidColor } from '../utils/colors';
|
||||||
import { runSMILAnimation } from '../utils/animation';
|
import { runSMILAnimation } from '../utils/animation';
|
||||||
import { downloadFile, prepareForExport } from '../utils/export';
|
import { downloadFile, prepareForExport } from '../utils/export';
|
||||||
|
import { deepClone } from '../utils/helpers';
|
||||||
|
|
||||||
export default class BaseChart {
|
export default class BaseChart {
|
||||||
constructor(parent, options) {
|
constructor(parent, options) {
|
||||||
|
options = deepClone(options);
|
||||||
|
|
||||||
this.parent = typeof parent === 'string'
|
this.parent = typeof parent === 'string'
|
||||||
? document.querySelector(parent)
|
? document.querySelector(parent)
|
||||||
@ -30,17 +35,18 @@ export default class BaseChart {
|
|||||||
|
|
||||||
this.config = {
|
this.config = {
|
||||||
showTooltip: 1, // calculate
|
showTooltip: 1, // calculate
|
||||||
showLegend: 1, // calculate
|
showLegend: (typeof options.showLegend !== 'undefined') ? options.showLegend : 1,
|
||||||
isNavigable: options.isNavigable || 0,
|
isNavigable: options.isNavigable || 0,
|
||||||
animate: (typeof options.animate !== 'undefined') ? options.animate : 1,
|
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));
|
this.measures = JSON.parse(JSON.stringify(BASE_MEASURES));
|
||||||
let m = this.measures;
|
let m = this.measures;
|
||||||
this.setMeasures(options);
|
this.setMeasures(options);
|
||||||
if(!this.title.length) { m.titleHeight = 0; }
|
if (!this.title.length) { m.titleHeight = 0; }
|
||||||
if(!this.config.showLegend) m.legendHeight = 0;
|
if (!this.config.showLegend) m.legendHeight = 0;
|
||||||
this.argHeight = options.height || m.baseHeight;
|
this.argHeight = options.height || m.baseHeight;
|
||||||
|
|
||||||
this.state = {};
|
this.state = {};
|
||||||
@ -48,7 +54,7 @@ export default class BaseChart {
|
|||||||
|
|
||||||
this.initTimeout = INIT_CHART_UPDATE_TIMEOUT;
|
this.initTimeout = INIT_CHART_UPDATE_TIMEOUT;
|
||||||
|
|
||||||
if(this.config.isNavigable) {
|
if (this.config.isNavigable) {
|
||||||
this.overlays = [];
|
this.overlays = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +74,7 @@ export default class BaseChart {
|
|||||||
colors = (colors || []).concat(DEFAULT_COLORS[type]);
|
colors = (colors || []).concat(DEFAULT_COLORS[type]);
|
||||||
colors.forEach((string) => {
|
colors.forEach((string) => {
|
||||||
const color = getColor(string);
|
const color = getColor(string);
|
||||||
if(!isValidColor(color)) {
|
if (!isValidColor(color)) {
|
||||||
console.warn('"' + string + '" is not a valid color.');
|
console.warn('"' + string + '" is not a valid color.');
|
||||||
} else {
|
} else {
|
||||||
validColors.push(color);
|
validColors.push(color);
|
||||||
@ -89,11 +95,16 @@ export default class BaseChart {
|
|||||||
|
|
||||||
// Bind window events
|
// Bind window events
|
||||||
this.boundDrawFn = () => this.draw(true);
|
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('resize', this.boundDrawFn);
|
||||||
window.addEventListener('orientationchange', this.boundDrawFn);
|
window.addEventListener('orientationchange', this.boundDrawFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
|
if (this.resizeObserver) this.resizeObserver.disconnect();
|
||||||
window.removeEventListener('resize', this.boundDrawFn);
|
window.removeEventListener('resize', this.boundDrawFn);
|
||||||
window.removeEventListener('orientationchange', this.boundDrawFn);
|
window.removeEventListener('orientationchange', this.boundDrawFn);
|
||||||
}
|
}
|
||||||
@ -116,7 +127,7 @@ export default class BaseChart {
|
|||||||
className: 'chart-container'
|
className: 'chart-container'
|
||||||
};
|
};
|
||||||
|
|
||||||
if(this.independentWidth) {
|
if (this.independentWidth) {
|
||||||
args.styles = { width: this.independentWidth + 'px' };
|
args.styles = { width: this.independentWidth + 'px' };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,9 +142,9 @@ export default class BaseChart {
|
|||||||
this.bindTooltip();
|
this.bindTooltip();
|
||||||
}
|
}
|
||||||
|
|
||||||
bindTooltip() {}
|
bindTooltip() { }
|
||||||
|
|
||||||
draw(onlyWidthChange=false, init=false) {
|
draw(onlyWidthChange = false, init = false) {
|
||||||
if (onlyWidthChange && isHidden(this.parent)) {
|
if (onlyWidthChange && isHidden(this.parent)) {
|
||||||
// Don't update anything if the chart is hidden
|
// Don't update anything if the chart is hidden
|
||||||
return;
|
return;
|
||||||
@ -148,17 +159,19 @@ export default class BaseChart {
|
|||||||
// this.components.forEach(c => c.make());
|
// this.components.forEach(c => c.make());
|
||||||
this.render(this.components, false);
|
this.render(this.components, false);
|
||||||
|
|
||||||
if(init) {
|
if (init) {
|
||||||
this.data = this.realData;
|
this.data = this.realData;
|
||||||
setTimeout(() => {this.update(this.data);}, this.initTimeout);
|
setTimeout(() => { this.update(this.data, true); }, this.initTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.renderLegend();
|
if (this.config.showLegend) {
|
||||||
|
this.renderLegend();
|
||||||
|
}
|
||||||
|
|
||||||
this.setupNavigation(init);
|
this.setupNavigation(init);
|
||||||
}
|
}
|
||||||
|
|
||||||
calc() {} // builds state
|
calc() { } // builds state
|
||||||
|
|
||||||
updateWidth() {
|
updateWidth() {
|
||||||
this.baseWidth = getElementContentWidth(this.parent);
|
this.baseWidth = getElementContentWidth(this.parent);
|
||||||
@ -166,7 +179,7 @@ export default class BaseChart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
makeChartArea() {
|
makeChartArea() {
|
||||||
if(this.svg) {
|
if (this.svg) {
|
||||||
this.container.removeChild(this.svg);
|
this.container.removeChild(this.svg);
|
||||||
}
|
}
|
||||||
let m = this.measures;
|
let m = this.measures;
|
||||||
@ -179,7 +192,7 @@ export default class BaseChart {
|
|||||||
);
|
);
|
||||||
this.svgDefs = makeSVGDefs(this.svg);
|
this.svgDefs = makeSVGDefs(this.svg);
|
||||||
|
|
||||||
if(this.title.length) {
|
if (this.title.length) {
|
||||||
this.titleEL = makeText(
|
this.titleEL = makeText(
|
||||||
'title',
|
'title',
|
||||||
m.margins.left,
|
m.margins.left,
|
||||||
@ -199,7 +212,7 @@ export default class BaseChart {
|
|||||||
`translate(${getLeftOffset(m)}, ${top})`
|
`translate(${getLeftOffset(m)}, ${top})`
|
||||||
);
|
);
|
||||||
|
|
||||||
if(this.config.showLegend) {
|
if (this.config.showLegend) {
|
||||||
top += this.height + m.paddings.bottom;
|
top += this.height + m.paddings.bottom;
|
||||||
this.legendArea = makeSVGGroup(
|
this.legendArea = makeSVGGroup(
|
||||||
'chart-legend',
|
'chart-legend',
|
||||||
@ -207,9 +220,9 @@ export default class BaseChart {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.title.length) { this.svg.appendChild(this.titleEL); }
|
if (this.title.length) { this.svg.appendChild(this.titleEL); }
|
||||||
this.svg.appendChild(this.drawArea);
|
this.svg.appendChild(this.drawArea);
|
||||||
if(this.config.showLegend) { this.svg.appendChild(this.legendArea); }
|
if (this.config.showLegend) { this.svg.appendChild(this.legendArea); }
|
||||||
|
|
||||||
this.updateTipOffset(getLeftOffset(m), getTopOffset(m));
|
this.updateTipOffset(getLeftOffset(m), getTopOffset(m));
|
||||||
}
|
}
|
||||||
@ -223,17 +236,18 @@ export default class BaseChart {
|
|||||||
|
|
||||||
setupComponents() { this.components = new Map(); }
|
setupComponents() { this.components = new Map(); }
|
||||||
|
|
||||||
update(data) {
|
update(data, drawing = false) {
|
||||||
if(!data) {
|
if (!data) console.error('No data to update.');
|
||||||
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.data = this.prepareData(data);
|
||||||
this.calc(); // builds state
|
this.calc(); // builds state
|
||||||
this.render(this.components, this.config.animate);
|
this.render(this.components, animate);
|
||||||
}
|
}
|
||||||
|
|
||||||
render(components=this.components, animate=true) {
|
render(components = this.components, animate = true) {
|
||||||
if(this.config.isNavigable) {
|
if (this.config.isNavigable) {
|
||||||
// Remove all existing overlays
|
// Remove all existing overlays
|
||||||
this.overlays.map(o => o.parentNode.removeChild(o));
|
this.overlays.map(o => o.parentNode.removeChild(o));
|
||||||
// ref.parentNode.insertBefore(element, ref);
|
// ref.parentNode.insertBefore(element, ref);
|
||||||
@ -243,7 +257,7 @@ export default class BaseChart {
|
|||||||
components.forEach(c => {
|
components.forEach(c => {
|
||||||
elementsToAnimate = elementsToAnimate.concat(c.update(animate));
|
elementsToAnimate = elementsToAnimate.concat(c.update(animate));
|
||||||
});
|
});
|
||||||
if(elementsToAnimate.length > 0) {
|
if (elementsToAnimate.length > 0) {
|
||||||
runSMILAnimation(this.container, this.svg, elementsToAnimate);
|
runSMILAnimation(this.container, this.svg, elementsToAnimate);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
components.forEach(c => c.make());
|
components.forEach(c => c.make());
|
||||||
@ -256,18 +270,37 @@ export default class BaseChart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateNav() {
|
updateNav() {
|
||||||
if(this.config.isNavigable) {
|
if (this.config.isNavigable) {
|
||||||
this.makeOverlay();
|
this.makeOverlay();
|
||||||
this.bindUnits();
|
this.bindUnits();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLegend() {}
|
renderLegend(dataset) {
|
||||||
|
this.legendArea.textContent = '';
|
||||||
|
let count = 0;
|
||||||
|
let y = 0;
|
||||||
|
|
||||||
setupNavigation(init=false) {
|
dataset.map((data, index) => {
|
||||||
if(!this.config.isNavigable) return;
|
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++;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if(init) {
|
makeLegend() { }
|
||||||
|
|
||||||
|
|
||||||
|
setupNavigation(init = false) {
|
||||||
|
if (!this.config.isNavigable) return;
|
||||||
|
|
||||||
|
if (init) {
|
||||||
this.bindOverlay();
|
this.bindOverlay();
|
||||||
|
|
||||||
this.keyActions = {
|
this.keyActions = {
|
||||||
@ -279,9 +312,9 @@ export default class BaseChart {
|
|||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener('keydown', (e) => {
|
document.addEventListener('keydown', (e) => {
|
||||||
if(isElementInViewport(this.container)) {
|
if (isElementInViewport(this.container)) {
|
||||||
e = e || window.event;
|
e = e || window.event;
|
||||||
if(this.keyActions[e.keyCode]) {
|
if (this.keyActions[e.keyCode]) {
|
||||||
this.keyActions[e.keyCode]();
|
this.keyActions[e.keyCode]();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,24 +322,24 @@ export default class BaseChart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
makeOverlay() {}
|
makeOverlay() { }
|
||||||
updateOverlay() {}
|
updateOverlay() { }
|
||||||
bindOverlay() {}
|
bindOverlay() { }
|
||||||
bindUnits() {}
|
bindUnits() { }
|
||||||
|
|
||||||
onLeftArrow() {}
|
onLeftArrow() { }
|
||||||
onRightArrow() {}
|
onRightArrow() { }
|
||||||
onUpArrow() {}
|
onUpArrow() { }
|
||||||
onDownArrow() {}
|
onDownArrow() { }
|
||||||
onEnterKey() {}
|
onEnterKey() { }
|
||||||
|
|
||||||
addDataPoint() {}
|
addDataPoint() { }
|
||||||
removeDataPoint() {}
|
removeDataPoint() { }
|
||||||
|
|
||||||
getDataPoint() {}
|
getDataPoint() { }
|
||||||
setCurrentDataPoint() {}
|
setCurrentDataPoint() { }
|
||||||
|
|
||||||
updateDataset() {}
|
updateDataset() { }
|
||||||
|
|
||||||
export() {
|
export() {
|
||||||
let chartSvg = prepareForExport(this.svg);
|
let chartSvg = prepareForExport(this.svg);
|
||||||
|
|||||||
@ -1,86 +1,35 @@
|
|||||||
import AggregationChart from './AggregationChart';
|
import PieChart from './PieChart';
|
||||||
import { getComponent } from '../objects/ChartComponents';
|
import { getComponent } from '../objects/ChartComponents';
|
||||||
import { getOffset } from '../utils/dom';
|
|
||||||
import { getPositionByAngle } from '../utils/helpers';
|
|
||||||
import { makeArcStrokePathStr, makeStrokeCircleStr } from '../utils/draw';
|
import { makeArcStrokePathStr, makeStrokeCircleStr } from '../utils/draw';
|
||||||
import { lightenDarkenColor } from '../utils/colors';
|
|
||||||
import { transform } from '../utils/animation';
|
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) {
|
constructor(parent, args) {
|
||||||
super(parent, args);
|
super(parent, args);
|
||||||
this.type = 'donut';
|
|
||||||
this.initTimeout = 0;
|
|
||||||
this.init = 1;
|
|
||||||
|
|
||||||
this.setup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configure(args) {
|
configure(args) {
|
||||||
super.configure(args);
|
super.configure(args);
|
||||||
this.mouseMove = this.mouseMove.bind(this);
|
|
||||||
this.mouseLeave = this.mouseLeave.bind(this);
|
|
||||||
|
|
||||||
this.hoverRadio = args.hoverRadio || 0.1;
|
this.type = 'donut';
|
||||||
this.config.startAngle = args.startAngle || 0;
|
this.sliceName = 'donutSlices';
|
||||||
|
|
||||||
|
this.arcFunc = makeArcStrokePathStr;
|
||||||
|
this.shapeFunc = makeStrokeCircleStr;
|
||||||
|
|
||||||
this.clockWise = args.clockWise || false;
|
|
||||||
this.strokeWidth = args.strokeWidth || 30;
|
this.strokeWidth = args.strokeWidth || 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
calc() {
|
getRadius() {
|
||||||
super.calc();
|
return this.height > this.width
|
||||||
let s = this.state;
|
? this.center.x - this.strokeWidth / 2
|
||||||
this.radius =
|
: this.center.y - this.strokeWidth / 2;
|
||||||
this.height > this.width
|
}
|
||||||
? this.center.x - this.strokeWidth / 2
|
|
||||||
: this.center.y - this.strokeWidth / 2;
|
|
||||||
|
|
||||||
const { radius, clockWise } = this;
|
resetHover(path, color) {
|
||||||
|
transform(path,'translate3d(0,0,0)');
|
||||||
const prevSlicesProperties = s.slicesProperties || [];
|
this.tip.hideTip();
|
||||||
s.sliceStrings = [];
|
path.style.stroke = color;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setupComponents() {
|
setupComponents() {
|
||||||
@ -88,9 +37,9 @@ export default class DonutChart extends AggregationChart {
|
|||||||
|
|
||||||
let componentConfigs = [
|
let componentConfigs = [
|
||||||
[
|
[
|
||||||
'donutSlices',
|
this.sliceName,
|
||||||
{ },
|
{},
|
||||||
function() {
|
function () {
|
||||||
return {
|
return {
|
||||||
sliceStrings: s.sliceStrings,
|
sliceStrings: s.sliceStrings,
|
||||||
colors: this.colors,
|
colors: this.colors,
|
||||||
@ -106,56 +55,4 @@ export default class DonutChart extends AggregationChart {
|
|||||||
return [args[0], component];
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
import BaseChart from './BaseChart';
|
import BaseChart from './BaseChart';
|
||||||
import { getComponent } from '../objects/ChartComponents';
|
import { getComponent } from '../objects/ChartComponents';
|
||||||
import { makeText, heatSquare } from '../utils/draw';
|
import { makeText, heatSquare } from '../utils/draw';
|
||||||
import { DAY_NAMES_SHORT, addDays, areInSameMonth, getLastDateInMonth, setDayToSunday, getYyyyMmDd, getWeeksBetween, getMonthName, clone,
|
import {
|
||||||
NO_OF_MILLIS, NO_OF_YEAR_MONTHS, NO_OF_DAYS_IN_WEEK } from '../utils/date-utils';
|
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 { calcDistribution, getMaxCheckpoint } from '../utils/intervals';
|
||||||
import { getExtraHeight, getExtraWidth, HEATMAP_DISTRIBUTION_SIZE, HEATMAP_SQUARE_SIZE,
|
import {
|
||||||
HEATMAP_GUTTER_SIZE } from '../utils/constants';
|
getExtraHeight, getExtraWidth, HEATMAP_DISTRIBUTION_SIZE, HEATMAP_SQUARE_SIZE,
|
||||||
|
HEATMAP_GUTTER_SIZE
|
||||||
|
} from '../utils/constants';
|
||||||
|
|
||||||
const COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE;
|
const COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE;
|
||||||
const ROW_HEIGHT = COL_WIDTH;
|
const ROW_HEIGHT = COL_WIDTH;
|
||||||
@ -49,19 +53,19 @@ export default class Heatmap extends BaseChart {
|
|||||||
+ getExtraWidth(this.measures);
|
+ getExtraWidth(this.measures);
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareData(data=this.data) {
|
prepareData(data = this.data) {
|
||||||
if(data.start && data.end && data.start > data.end) {
|
if (data.start && data.end && data.start > data.end) {
|
||||||
throw new Error('Start date cannot be greater than end date.');
|
throw new Error('Start date cannot be greater than end date.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!data.start) {
|
if (!data.start) {
|
||||||
data.start = new Date();
|
data.start = new Date();
|
||||||
data.start.setFullYear( data.start.getFullYear() - 1 );
|
data.start.setFullYear(data.start.getFullYear() - 1);
|
||||||
}
|
}
|
||||||
if(!data.end) { data.end = new Date(); }
|
if (!data.end) { data.end = new Date(); }
|
||||||
data.dataPoints = data.dataPoints || {};
|
data.dataPoints = data.dataPoints || {};
|
||||||
|
|
||||||
if(parseInt(Object.keys(data.dataPoints)[0]) > 100000) {
|
if (parseInt(Object.keys(data.dataPoints)[0]) > 100000) {
|
||||||
let points = {};
|
let points = {};
|
||||||
Object.keys(data.dataPoints).forEach(timestampSec => {
|
Object.keys(data.dataPoints).forEach(timestampSec => {
|
||||||
let date = new Date(timestampSec * NO_OF_MILLIS);
|
let date = new Date(timestampSec * NO_OF_MILLIS);
|
||||||
@ -105,7 +109,7 @@ export default class Heatmap extends BaseChart {
|
|||||||
.reduce((a, b) => a + b, 0)
|
.reduce((a, b) => a + b, 0)
|
||||||
* COL_WIDTH
|
* COL_WIDTH
|
||||||
},
|
},
|
||||||
function() {
|
function () {
|
||||||
return s.domainConfigs[i];
|
return s.domainConfigs[i];
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
|
|
||||||
@ -120,8 +124,8 @@ export default class Heatmap extends BaseChart {
|
|||||||
|
|
||||||
let y = 0;
|
let y = 0;
|
||||||
DAY_NAMES_SHORT.forEach((dayName, i) => {
|
DAY_NAMES_SHORT.forEach((dayName, i) => {
|
||||||
if([1, 3, 5].includes(i)) {
|
if ([1, 3, 5].includes(i)) {
|
||||||
let dayText = makeText('subdomain-name', -COL_WIDTH/2, y, dayName,
|
let dayText = makeText('subdomain-name', -COL_WIDTH / 2, y, dayName,
|
||||||
{
|
{
|
||||||
fontSize: HEATMAP_SQUARE_SIZE,
|
fontSize: HEATMAP_SQUARE_SIZE,
|
||||||
dy: 8,
|
dy: 8,
|
||||||
@ -135,7 +139,7 @@ export default class Heatmap extends BaseChart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update(data) {
|
update(data) {
|
||||||
if(!data) {
|
if (!data) {
|
||||||
console.error('No data to update.');
|
console.error('No data to update.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,22 +153,22 @@ export default class Heatmap extends BaseChart {
|
|||||||
this.components.forEach(comp => {
|
this.components.forEach(comp => {
|
||||||
let daySquares = comp.store;
|
let daySquares = comp.store;
|
||||||
let daySquare = e.target;
|
let daySquare = e.target;
|
||||||
if(daySquares.includes(daySquare)) {
|
if (daySquares.includes(daySquare)) {
|
||||||
|
|
||||||
let count = daySquare.getAttribute('data-value');
|
let count = daySquare.getAttribute('data-value');
|
||||||
let dateParts = daySquare.getAttribute('data-date').split('-');
|
let dateParts = daySquare.getAttribute('data-date').split('-');
|
||||||
|
|
||||||
let month = getMonthName(parseInt(dateParts[1])-1, true);
|
let month = getMonthName(parseInt(dateParts[1]) - 1, true);
|
||||||
|
|
||||||
let gOff = this.container.getBoundingClientRect(), pOff = daySquare.getBoundingClientRect();
|
let gOff = this.container.getBoundingClientRect(), pOff = daySquare.getBoundingClientRect();
|
||||||
|
|
||||||
let width = parseInt(e.target.getAttribute('width'));
|
let width = parseInt(e.target.getAttribute('width'));
|
||||||
let x = pOff.left - gOff.left + width/2;
|
let x = pOff.left - gOff.left + width / 2;
|
||||||
let y = pOff.top - gOff.top;
|
let y = pOff.top - gOff.top;
|
||||||
let value = count + ' ' + this.countLabel;
|
let value = count + ' ' + this.countLabel;
|
||||||
let name = ' on ' + month + ' ' + dateParts[0] + ', ' + dateParts[2];
|
let name = ' on ' + month + ' ' + dateParts[0] + ', ' + dateParts[2];
|
||||||
|
|
||||||
this.tip.setValues(x, y, {name: name, value: value, valueFirst: 1}, []);
|
this.tip.setValues(x, y, { name: name, value: value, valueFirst: 1 }, []);
|
||||||
this.tip.showTip();
|
this.tip.showTip();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -183,7 +187,7 @@ export default class Heatmap extends BaseChart {
|
|||||||
dy: 9
|
dy: 9
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
x = (COL_WIDTH * 2) + COL_WIDTH/2;
|
x = (COL_WIDTH * 2) + COL_WIDTH / 2;
|
||||||
this.legendArea.appendChild(lessText);
|
this.legendArea.appendChild(lessText);
|
||||||
|
|
||||||
this.colors.slice(0, HEATMAP_DISTRIBUTION_SIZE).map((color, i) => {
|
this.colors.slice(0, HEATMAP_DISTRIBUTION_SIZE).map((color, i) => {
|
||||||
@ -192,7 +196,7 @@ export default class Heatmap extends BaseChart {
|
|||||||
this.legendArea.appendChild(square);
|
this.legendArea.appendChild(square);
|
||||||
});
|
});
|
||||||
|
|
||||||
let moreTextX = x + HEATMAP_DISTRIBUTION_SIZE * (COL_WIDTH + 3) + COL_WIDTH/4;
|
let moreTextX = x + HEATMAP_DISTRIBUTION_SIZE * (COL_WIDTH + 3) + COL_WIDTH / 4;
|
||||||
let moreText = makeText('subdomain-name', moreTextX, y, 'More',
|
let moreText = makeText('subdomain-name', moreTextX, y, 'More',
|
||||||
{
|
{
|
||||||
fontSize: HEATMAP_SQUARE_SIZE + 1,
|
fontSize: HEATMAP_SQUARE_SIZE + 1,
|
||||||
@ -212,9 +216,9 @@ export default class Heatmap extends BaseChart {
|
|||||||
let domainConfigs = [];
|
let domainConfigs = [];
|
||||||
|
|
||||||
let startOfMonth = clone(s.start);
|
let startOfMonth = clone(s.start);
|
||||||
for(var i = 0; i < noOfMonths; i++) {
|
for (var i = 0; i < noOfMonths; i++) {
|
||||||
let endDate = s.end;
|
let endDate = s.end;
|
||||||
if(!areInSameMonth(startOfMonth, s.end)) {
|
if (!areInSameMonth(startOfMonth, s.end)) {
|
||||||
let [month, year] = [startOfMonth.getMonth(), startOfMonth.getFullYear()];
|
let [month, year] = [startOfMonth.getMonth(), startOfMonth.getFullYear()];
|
||||||
endDate = getLastDateInMonth(month, year);
|
endDate = getLastDateInMonth(month, year);
|
||||||
}
|
}
|
||||||
@ -227,7 +231,7 @@ export default class Heatmap extends BaseChart {
|
|||||||
return domainConfigs;
|
return domainConfigs;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDomainConfig(startDate, endDate='') {
|
getDomainConfig(startDate, endDate = '') {
|
||||||
let [month, year] = [startDate.getMonth(), startDate.getFullYear()];
|
let [month, year] = [startDate.getMonth(), startDate.getFullYear()];
|
||||||
let startOfWeek = setDayToSunday(startDate); // TODO: Monday as well
|
let startOfWeek = setDayToSunday(startDate); // TODO: Monday as well
|
||||||
endDate = clone(endDate) || getLastDateInMonth(month, year);
|
endDate = clone(endDate) || getLastDateInMonth(month, year);
|
||||||
@ -241,7 +245,7 @@ export default class Heatmap extends BaseChart {
|
|||||||
let noOfMonthWeeks = getWeeksBetween(startOfWeek, endDate);
|
let noOfMonthWeeks = getWeeksBetween(startOfWeek, endDate);
|
||||||
|
|
||||||
let cols = [], col;
|
let cols = [], col;
|
||||||
for(var i = 0; i < noOfMonthWeeks; i++) {
|
for (var i = 0; i < noOfMonthWeeks; i++) {
|
||||||
col = this.getCol(startOfWeek, month);
|
col = this.getCol(startOfWeek, month);
|
||||||
cols.push(col);
|
cols.push(col);
|
||||||
|
|
||||||
@ -249,7 +253,7 @@ export default class Heatmap extends BaseChart {
|
|||||||
addDays(startOfWeek, 1);
|
addDays(startOfWeek, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(col[NO_OF_DAYS_IN_WEEK - 1].dataValue !== undefined) {
|
if (col[NO_OF_DAYS_IN_WEEK - 1].dataValue !== undefined) {
|
||||||
addDays(startOfWeek, 1);
|
addDays(startOfWeek, 1);
|
||||||
cols.push(this.getCol(startOfWeek, month, true));
|
cols.push(this.getCol(startOfWeek, month, true));
|
||||||
}
|
}
|
||||||
@ -266,13 +270,13 @@ export default class Heatmap extends BaseChart {
|
|||||||
let currentDate = clone(startDate);
|
let currentDate = clone(startDate);
|
||||||
let col = [];
|
let col = [];
|
||||||
|
|
||||||
for(var i = 0; i < NO_OF_DAYS_IN_WEEK; i++, addDays(currentDate, 1)) {
|
for (var i = 0; i < NO_OF_DAYS_IN_WEEK; i++, addDays(currentDate, 1)) {
|
||||||
let config = {};
|
let config = {};
|
||||||
|
|
||||||
// Non-generic adjustment for entire heatmap, needs state
|
// Non-generic adjustment for entire heatmap, needs state
|
||||||
let currentDateWithinData = currentDate >= s.start && currentDate <= s.end;
|
let currentDateWithinData = currentDate >= s.start && currentDate <= s.end;
|
||||||
|
|
||||||
if(empty || currentDate.getMonth() !== month || !currentDateWithinData) {
|
if (empty || currentDate.getMonth() !== month || !currentDateWithinData) {
|
||||||
config.yyyyMmDd = getYyyyMmDd(currentDate);
|
config.yyyyMmDd = getYyyyMmDd(currentDate);
|
||||||
} else {
|
} else {
|
||||||
config = this.getSubDomainConfig(currentDate);
|
config = this.getSubDomainConfig(currentDate);
|
||||||
|
|||||||
@ -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
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import AggregationChart from './AggregationChart';
|
import AggregationChart from './AggregationChart';
|
||||||
import { getOffset } from '../utils/dom';
|
import { getOffset } from '../utils/dom';
|
||||||
import { getComponent } from '../objects/ChartComponents';
|
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 {
|
export default class PercentageChart extends AggregationChart {
|
||||||
constructor(parent, args) {
|
constructor(parent, args) {
|
||||||
@ -16,11 +16,13 @@ export default class PercentageChart extends AggregationChart {
|
|||||||
|
|
||||||
let b = this.barOptions;
|
let b = this.barOptions;
|
||||||
b.height = b.height || PERCENTAGE_BAR_DEFAULT_HEIGHT;
|
b.height = b.height || PERCENTAGE_BAR_DEFAULT_HEIGHT;
|
||||||
b.depth = b.depth || PERCENTAGE_BAR_DEFAULT_DEPTH;
|
|
||||||
|
|
||||||
m.paddings.right = 30;
|
m.paddings.right = 30;
|
||||||
m.legendHeight = 60;
|
m.paddings.top = 60;
|
||||||
m.baseHeight = (b.height + b.depth * 0.5) * 8;
|
m.paddings.bottom = 0;
|
||||||
|
|
||||||
|
m.legendHeight = 80;
|
||||||
|
m.baseHeight = (b.height) * 8 + getExtraHeight(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
setupComponents() {
|
setupComponents() {
|
||||||
@ -31,9 +33,8 @@ export default class PercentageChart extends AggregationChart {
|
|||||||
'percentageBars',
|
'percentageBars',
|
||||||
{
|
{
|
||||||
barHeight: this.barOptions.height,
|
barHeight: this.barOptions.height,
|
||||||
barDepth: this.barOptions.depth,
|
|
||||||
},
|
},
|
||||||
function() {
|
function () {
|
||||||
return {
|
return {
|
||||||
xPositions: s.xPositions,
|
xPositions: s.xPositions,
|
||||||
widths: s.widths,
|
widths: s.widths,
|
||||||
@ -73,18 +74,19 @@ export default class PercentageChart extends AggregationChart {
|
|||||||
this.container.addEventListener('mousemove', (e) => {
|
this.container.addEventListener('mousemove', (e) => {
|
||||||
let bars = this.components.get('percentageBars').store;
|
let bars = this.components.get('percentageBars').store;
|
||||||
let bar = e.target;
|
let bar = e.target;
|
||||||
if(bars.includes(bar)) {
|
if (bars.includes(bar)) {
|
||||||
|
|
||||||
let i = bars.indexOf(bar);
|
let i = bars.indexOf(bar);
|
||||||
let gOff = getOffset(this.container), pOff = getOffset(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 y = pOff.top - gOff.top;
|
|
||||||
let title = (this.formattedLabels && this.formattedLabels.length>0
|
|
||||||
? this.formattedLabels[i] : this.state.labels[i]) + ': ';
|
|
||||||
let fraction = s.sliceTotals[i]/s.grandTotal;
|
|
||||||
|
|
||||||
this.tip.setValues(x, y, {name: title, value: (fraction*100).toFixed(1) + "%"});
|
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]) + ': ';
|
||||||
|
let fraction = s.sliceTotals[i] / s.grandTotal;
|
||||||
|
|
||||||
|
this.tip.setValues(x, y, { name: title, value: (fraction * 100).toFixed(1) + "%" });
|
||||||
this.tip.showTip();
|
this.tip.showTip();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3,14 +3,12 @@ import { getComponent } from '../objects/ChartComponents';
|
|||||||
import { getOffset } from '../utils/dom';
|
import { getOffset } from '../utils/dom';
|
||||||
import { getPositionByAngle } from '../utils/helpers';
|
import { getPositionByAngle } from '../utils/helpers';
|
||||||
import { makeArcPathStr, makeCircleStr } from '../utils/draw';
|
import { makeArcPathStr, makeCircleStr } from '../utils/draw';
|
||||||
import { lightenDarkenColor } from '../utils/colors';
|
|
||||||
import { transform } from '../utils/animation';
|
import { transform } from '../utils/animation';
|
||||||
import { FULL_ANGLE } from '../utils/constants';
|
import { FULL_ANGLE } from '../utils/constants';
|
||||||
|
|
||||||
export default class PieChart extends AggregationChart {
|
export default class PieChart extends AggregationChart {
|
||||||
constructor(parent, args) {
|
constructor(parent, args) {
|
||||||
super(parent, args);
|
super(parent, args);
|
||||||
this.type = 'pie';
|
|
||||||
this.initTimeout = 0;
|
this.initTimeout = 0;
|
||||||
this.init = 1;
|
this.init = 1;
|
||||||
|
|
||||||
@ -25,13 +23,23 @@ export default class PieChart extends AggregationChart {
|
|||||||
this.hoverRadio = args.hoverRadio || 0.1;
|
this.hoverRadio = args.hoverRadio || 0.1;
|
||||||
this.config.startAngle = args.startAngle || 0;
|
this.config.startAngle = args.startAngle || 0;
|
||||||
|
|
||||||
|
this.type = 'pie';
|
||||||
|
this.sliceName = 'pieSlices';
|
||||||
|
|
||||||
|
this.arcFunc = makeArcPathStr;
|
||||||
|
this.shapeFunc = makeCircleStr;
|
||||||
|
|
||||||
this.clockWise = args.clockWise || false;
|
this.clockWise = args.clockWise || false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRadius() {
|
||||||
|
return this.height > this.width ? this.center.x : this.center.y;
|
||||||
|
}
|
||||||
|
|
||||||
calc() {
|
calc() {
|
||||||
super.calc();
|
super.calc();
|
||||||
let s = this.state;
|
let s = this.state;
|
||||||
this.radius = (this.height > this.width ? this.center.x : this.center.y);
|
this.radius = this.getRadius();
|
||||||
|
|
||||||
const { radius, clockWise } = this;
|
const { radius, clockWise } = this;
|
||||||
|
|
||||||
@ -42,7 +50,7 @@ export default class PieChart extends AggregationChart {
|
|||||||
s.sliceTotals.map((total, i) => {
|
s.sliceTotals.map((total, i) => {
|
||||||
const startAngle = curAngle;
|
const startAngle = curAngle;
|
||||||
const originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;
|
const originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;
|
||||||
const largeArc = originDiffAngle > 180 ? 1: 0;
|
const largeArc = originDiffAngle > 180 ? 1 : 0;
|
||||||
const diffAngle = clockWise ? -originDiffAngle : originDiffAngle;
|
const diffAngle = clockWise ? -originDiffAngle : originDiffAngle;
|
||||||
const endAngle = curAngle = curAngle + diffAngle;
|
const endAngle = curAngle = curAngle + diffAngle;
|
||||||
const startPosition = getPositionByAngle(startAngle, radius);
|
const startPosition = getPositionByAngle(startAngle, radius);
|
||||||
@ -50,8 +58,8 @@ export default class PieChart extends AggregationChart {
|
|||||||
|
|
||||||
const prevProperty = this.init && prevSlicesProperties[i];
|
const prevProperty = this.init && prevSlicesProperties[i];
|
||||||
|
|
||||||
let curStart,curEnd;
|
let curStart, curEnd;
|
||||||
if(this.init) {
|
if (this.init) {
|
||||||
curStart = prevProperty ? prevProperty.startPosition : startPosition;
|
curStart = prevProperty ? prevProperty.startPosition : startPosition;
|
||||||
curEnd = prevProperty ? prevProperty.endPosition : startPosition;
|
curEnd = prevProperty ? prevProperty.endPosition : startPosition;
|
||||||
} else {
|
} else {
|
||||||
@ -60,8 +68,8 @@ export default class PieChart extends AggregationChart {
|
|||||||
}
|
}
|
||||||
const curPath =
|
const curPath =
|
||||||
originDiffAngle === 360
|
originDiffAngle === 360
|
||||||
? makeCircleStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc)
|
? this.shapeFunc(curStart, curEnd, this.center, this.radius, clockWise, largeArc)
|
||||||
: makeArcPathStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc);
|
: this.arcFunc(curStart, curEnd, this.center, this.radius, clockWise, largeArc);
|
||||||
|
|
||||||
s.sliceStrings.push(curPath);
|
s.sliceStrings.push(curPath);
|
||||||
s.slicesProperties.push({
|
s.slicesProperties.push({
|
||||||
@ -84,8 +92,8 @@ export default class PieChart extends AggregationChart {
|
|||||||
let componentConfigs = [
|
let componentConfigs = [
|
||||||
[
|
[
|
||||||
'pieSlices',
|
'pieSlices',
|
||||||
{ },
|
{},
|
||||||
function() {
|
function () {
|
||||||
return {
|
return {
|
||||||
sliceStrings: s.sliceStrings,
|
sliceStrings: s.sliceStrings,
|
||||||
colors: this.colors
|
colors: this.colors
|
||||||
@ -101,46 +109,51 @@ export default class PieChart extends AggregationChart {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
calTranslateByAngle(property){
|
calTranslateByAngle(property) {
|
||||||
const{radius,hoverRadio} = this;
|
const { radius, hoverRadio } = this;
|
||||||
const position = getPositionByAngle(property.startAngle+(property.angle / 2),radius);
|
const position = getPositionByAngle(property.startAngle + (property.angle / 2), radius);
|
||||||
return `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;
|
return `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
hoverSlice(path,i,flag,e){
|
hoverSlice(path, i, flag, e) {
|
||||||
if(!path) return;
|
if (!path) return;
|
||||||
const color = this.colors[i];
|
const color = this.colors[i];
|
||||||
if(flag) {
|
if (flag) {
|
||||||
transform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));
|
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 g_off = getOffset(this.svg);
|
||||||
let x = e.pageX - g_off.left + 10;
|
let x = e.pageX - g_off.left + 10;
|
||||||
let y = e.pageY - g_off.top - 10;
|
let y = e.pageY - g_off.top - 10;
|
||||||
let title = (this.formatted_labels && this.formatted_labels.length > 0
|
let title = (this.formatted_labels && this.formatted_labels.length > 0
|
||||||
? this.formatted_labels[i] : this.state.labels[i]) + ': ';
|
? this.formatted_labels[i] : this.state.labels[i]) + ': ';
|
||||||
let percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);
|
let percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);
|
||||||
this.tip.setValues(x, y, {name: title, value: percent + "%"});
|
this.tip.setValues(x, y, { name: title, value: percent + "%" });
|
||||||
this.tip.showTip();
|
this.tip.showTip();
|
||||||
} else {
|
} else {
|
||||||
transform(path,'translate3d(0,0,0)');
|
this.resetHover(path, color)
|
||||||
this.tip.hideTip();
|
|
||||||
path.style.fill = color;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetHover(path, color) {
|
||||||
|
transform(path, 'translate3d(0,0,0)');
|
||||||
|
this.tip.hideTip();
|
||||||
|
path.style.fill = color;
|
||||||
|
}
|
||||||
|
|
||||||
bindTooltip() {
|
bindTooltip() {
|
||||||
this.container.addEventListener('mousemove', this.mouseMove);
|
this.container.addEventListener('mousemove', this.mouseMove);
|
||||||
this.container.addEventListener('mouseleave', this.mouseLeave);
|
this.container.addEventListener('mouseleave', this.mouseLeave);
|
||||||
}
|
}
|
||||||
|
|
||||||
mouseMove(e){
|
mouseMove(e) {
|
||||||
const target = e.target;
|
const target = e.target;
|
||||||
let slices = this.components.get('pieSlices').store;
|
let slices = this.components.get(this.sliceName).store;
|
||||||
let prevIndex = this.curActiveSliceIndex;
|
let prevIndex = this.curActiveSliceIndex;
|
||||||
let prevAcitve = this.curActiveSlice;
|
let prevActive = this.curActiveSlice;
|
||||||
if(slices.includes(target)) {
|
if (slices.includes(target)) {
|
||||||
let i = slices.indexOf(target);
|
let i = slices.indexOf(target);
|
||||||
this.hoverSlice(prevAcitve, prevIndex,false);
|
this.hoverSlice(prevActive, prevIndex, false);
|
||||||
this.curActiveSlice = target;
|
this.curActiveSlice = target;
|
||||||
this.curActiveSliceIndex = i;
|
this.curActiveSliceIndex = i;
|
||||||
this.hoverSlice(target, i, true, e);
|
this.hoverSlice(target, i, true, e);
|
||||||
@ -149,7 +162,7 @@ export default class PieChart extends AggregationChart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mouseLeave(){
|
mouseLeave() {
|
||||||
this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);
|
this.hoverSlice(this.curActiveSlice, this.curActiveSliceIndex, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import * as Charts from './chart';
|
|||||||
let frappe = { };
|
let frappe = { };
|
||||||
|
|
||||||
frappe.NAME = 'Frappe Charts';
|
frappe.NAME = 'Frappe Charts';
|
||||||
frappe.VERSION = '1.5.5';
|
frappe.VERSION = '2.0.0-rc22';
|
||||||
|
|
||||||
frappe = Object.assign({ }, frappe, Charts);
|
frappe = Object.assign({ }, frappe, Charts);
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { makeSVGGroup } from '../utils/draw';
|
import { makeSVGGroup } from '../utils/draw';
|
||||||
import { makeText, makePath, xLine, yLine, yMarker, yRegion, datasetBar, datasetDot, percentageBar, getPaths, heatSquare } 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 { equilizeNoOfElements } from '../utils/draw-utils';
|
||||||
import { translateHoriLine, translateVertLine, animateRegion, animateBar,
|
import {
|
||||||
animateDot, animatePath, animatePathStr } from '../utils/animate';
|
translateHoriLine, translateVertLine, animateRegion, animateBar,
|
||||||
|
animateDot, animatePath, animatePathStr
|
||||||
|
} from '../utils/animate';
|
||||||
import { getMonthName } from '../utils/date-utils';
|
import { getMonthName } from '../utils/date-utils';
|
||||||
|
|
||||||
class ChartComponent {
|
class ChartComponent {
|
||||||
@ -27,7 +29,7 @@ class ChartComponent {
|
|||||||
this.labels = [];
|
this.labels = [];
|
||||||
|
|
||||||
this.layerClass = layerClass;
|
this.layerClass = layerClass;
|
||||||
this.layerClass = typeof(this.layerClass) === 'function'
|
this.layerClass = typeof (this.layerClass) === 'function'
|
||||||
? this.layerClass() : this.layerClass;
|
? this.layerClass() : this.layerClass;
|
||||||
|
|
||||||
this.refresh();
|
this.refresh();
|
||||||
@ -61,7 +63,7 @@ class ChartComponent {
|
|||||||
update(animate = true) {
|
update(animate = true) {
|
||||||
this.refresh();
|
this.refresh();
|
||||||
let animateElements = [];
|
let animateElements = [];
|
||||||
if(animate) {
|
if (animate) {
|
||||||
animateElements = this.animateElements(this.data) || [];
|
animateElements = this.animateElements(this.data) || [];
|
||||||
}
|
}
|
||||||
return animateElements;
|
return animateElements;
|
||||||
@ -86,7 +88,7 @@ let componentConfigs = {
|
|||||||
pieSlices: {
|
pieSlices: {
|
||||||
layerClass: 'pie-slices',
|
layerClass: 'pie-slices',
|
||||||
makeElements(data) {
|
makeElements(data) {
|
||||||
return data.sliceStrings.map((s, i) =>{
|
return data.sliceStrings.map((s, i) => {
|
||||||
let slice = makePath(s, 'pie-path', 'none', data.colors[i]);
|
let slice = makePath(s, 'pie-path', 'none', data.colors[i]);
|
||||||
slice.style.transition = 'transform .3s;';
|
slice.style.transition = 'transform .3s;';
|
||||||
return slice;
|
return slice;
|
||||||
@ -102,16 +104,20 @@ let componentConfigs = {
|
|||||||
percentageBars: {
|
percentageBars: {
|
||||||
layerClass: 'percentage-bars',
|
layerClass: 'percentage-bars',
|
||||||
makeElements(data) {
|
makeElements(data) {
|
||||||
return data.xPositions.map((x, i) =>{
|
const numberOfPoints = data.xPositions.length;
|
||||||
|
return data.xPositions.map((x, i) => {
|
||||||
let y = 0;
|
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;
|
return bar;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
animateElements(newData) {
|
animateElements(newData) {
|
||||||
if(newData) return [];
|
if (newData) return [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
@ -119,7 +125,12 @@ let componentConfigs = {
|
|||||||
makeElements(data) {
|
makeElements(data) {
|
||||||
return data.positions.map((position, i) =>
|
return data.positions.map((position, i) =>
|
||||||
yLine(position, data.labels[i], this.constants.width,
|
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
|
||||||
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -150,7 +161,7 @@ let componentConfigs = {
|
|||||||
makeElements(data) {
|
makeElements(data) {
|
||||||
return data.positions.map((position, i) =>
|
return data.positions.map((position, i) =>
|
||||||
xLine(position, data.calcLabels[i], this.constants.height,
|
xLine(position, data.calcLabels[i], this.constants.height,
|
||||||
{mode: this.constants.mode, pos: this.constants.pos})
|
{ mode: this.constants.mode, pos: this.constants.pos })
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -181,7 +192,7 @@ let componentConfigs = {
|
|||||||
makeElements(data) {
|
makeElements(data) {
|
||||||
return data.map(m =>
|
return data.map(m =>
|
||||||
yMarker(m.position, m.label, this.constants.width,
|
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) {
|
animateElements(newData) {
|
||||||
@ -214,7 +225,7 @@ let componentConfigs = {
|
|||||||
makeElements(data) {
|
makeElements(data) {
|
||||||
return data.map(r =>
|
return data.map(r =>
|
||||||
yRegion(r.startPos, r.endPos, this.constants.width,
|
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) {
|
animateElements(newData) {
|
||||||
@ -250,16 +261,16 @@ let componentConfigs = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
heatDomain: {
|
heatDomain: {
|
||||||
layerClass: function() { return 'heat-domain domain-' + this.constants.index; },
|
layerClass: function () { return 'heat-domain domain-' + this.constants.index; },
|
||||||
makeElements(data) {
|
makeElements(data) {
|
||||||
let {index, colWidth, rowHeight, squareSize, radius, xTranslate} = this.constants;
|
let { index, colWidth, rowHeight, squareSize, radius, xTranslate } = this.constants;
|
||||||
let monthNameHeight = -12;
|
let monthNameHeight = -12;
|
||||||
let x = xTranslate, y = 0;
|
let x = xTranslate, y = 0;
|
||||||
|
|
||||||
this.serializedSubDomains = [];
|
this.serializedSubDomains = [];
|
||||||
|
|
||||||
data.cols.map((week, weekNo) => {
|
data.cols.map((week, weekNo) => {
|
||||||
if(weekNo === 1) {
|
if (weekNo === 1) {
|
||||||
this.labels.push(
|
this.labels.push(
|
||||||
makeText('domain-name', x, monthNameHeight, getMonthName(index, true).toUpperCase(),
|
makeText('domain-name', x, monthNameHeight, getMonthName(index, true).toUpperCase(),
|
||||||
{
|
{
|
||||||
@ -269,7 +280,7 @@ let componentConfigs = {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
week.map((day, i) => {
|
week.map((day, i) => {
|
||||||
if(day.fill) {
|
if (day.fill) {
|
||||||
let data = {
|
let data = {
|
||||||
'data-date': day.yyyyMmDd,
|
'data-date': day.yyyyMmDd,
|
||||||
'data-value': day.dataValue,
|
'data-value': day.dataValue,
|
||||||
@ -288,12 +299,12 @@ let componentConfigs = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
animateElements(newData) {
|
animateElements(newData) {
|
||||||
if(newData) return [];
|
if (newData) return [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
barGraph: {
|
barGraph: {
|
||||||
layerClass: function() { return 'dataset-units dataset-bars dataset-' + this.constants.index; },
|
layerClass: function () { return 'dataset-units dataset-bars dataset-' + this.constants.index; },
|
||||||
makeElements(data) {
|
makeElements(data) {
|
||||||
let c = this.constants;
|
let c = this.constants;
|
||||||
this.unitType = 'bar';
|
this.unitType = 'bar';
|
||||||
@ -347,7 +358,7 @@ let componentConfigs = {
|
|||||||
this.store.map((bar, i) => {
|
this.store.map((bar, i) => {
|
||||||
animateElements = animateElements.concat(animateBar(
|
animateElements = animateElements.concat(animateBar(
|
||||||
bar, newXPos[i], newYPos[i], newData.barWidth, newOffsets[i],
|
bar, newXPos[i], newYPos[i], newData.barWidth, newOffsets[i],
|
||||||
{zeroLine: newData.zeroLine}
|
{ zeroLine: newData.zeroLine }
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -356,12 +367,12 @@ let componentConfigs = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
lineGraph: {
|
lineGraph: {
|
||||||
layerClass: function() { return 'dataset-units dataset-line dataset-' + this.constants.index; },
|
layerClass: function () { return 'dataset-units dataset-line dataset-' + this.constants.index; },
|
||||||
makeElements(data) {
|
makeElements(data) {
|
||||||
let c = this.constants;
|
let c = this.constants;
|
||||||
this.unitType = 'dot';
|
this.unitType = 'dot';
|
||||||
this.paths = {};
|
this.paths = {};
|
||||||
if(!c.hideLine) {
|
if (!c.hideLine) {
|
||||||
this.paths = getPaths(
|
this.paths = getPaths(
|
||||||
data.xPositions,
|
data.xPositions,
|
||||||
data.yPositions,
|
data.yPositions,
|
||||||
@ -378,8 +389,8 @@ let componentConfigs = {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.units = [];
|
this.units = [];
|
||||||
if(!c.hideDots) {
|
if (c.showDots) {
|
||||||
this.units = data.yPositions.map((y, j) => {
|
this.units = data.yPositions.map((y, j) => {
|
||||||
return datasetDot(
|
return datasetDot(
|
||||||
data.xPositions[j],
|
data.xPositions[j],
|
||||||
@ -387,11 +398,27 @@ let componentConfigs = {
|
|||||||
data.radius,
|
data.radius,
|
||||||
c.color,
|
c.color,
|
||||||
(c.valuesOverPoints ? data.values[j] : ''),
|
(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);
|
return Object.values(this.paths).concat(this.units);
|
||||||
},
|
},
|
||||||
animateElements(newData) {
|
animateElements(newData) {
|
||||||
@ -418,12 +445,12 @@ let componentConfigs = {
|
|||||||
|
|
||||||
let animateElements = [];
|
let animateElements = [];
|
||||||
|
|
||||||
if(Object.keys(this.paths).length) {
|
if (Object.keys(this.paths).length) {
|
||||||
animateElements = animateElements.concat(animatePath(
|
animateElements = animateElements.concat(animatePath(
|
||||||
this.paths, newXPos, newYPos, newData.zeroLine, this.constants.spline));
|
this.paths, newXPos, newYPos, newData.zeroLine, this.constants.spline));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.units.length) {
|
if (this.units.length) {
|
||||||
this.units.map((dot, i) => {
|
this.units.map((dot, i) => {
|
||||||
animateElements = animateElements.concat(animateDot(
|
animateElements = animateElements.concat(animateDot(
|
||||||
dot, newXPos[i], newYPos[i]));
|
dot, newXPos[i], newYPos[i]));
|
||||||
|
|||||||
@ -52,10 +52,10 @@ export default class SvgTip {
|
|||||||
|
|
||||||
fill() {
|
fill() {
|
||||||
let title;
|
let title;
|
||||||
if(this.index) {
|
if (this.index) {
|
||||||
this.container.setAttribute('data-point-index', this.index);
|
this.container.setAttribute('data-point-index', this.index);
|
||||||
}
|
}
|
||||||
if(this.titleValueFirst) {
|
if (this.titleValueFirst) {
|
||||||
title = `<strong>${this.titleValue}</strong>${this.titleName}`;
|
title = `<strong>${this.titleValue}</strong>${this.titleName}`;
|
||||||
} else {
|
} else {
|
||||||
title = `${this.titleName}<strong>${this.titleValue}</strong>`;
|
title = `${this.titleName}<strong>${this.titleValue}</strong>`;
|
||||||
@ -76,8 +76,8 @@ export default class SvgTip {
|
|||||||
let li = $.create('li', {
|
let li = $.create('li', {
|
||||||
innerHTML: `<div class="tooltip-legend" style="background: ${color};"></div>
|
innerHTML: `<div class="tooltip-legend" style="background: ${color};"></div>
|
||||||
<div>
|
<div>
|
||||||
<div class="tooltip-value">${ value === 0 || value ? value : '' }</div>
|
<div class="tooltip-value">${value === 0 || value ? value : ''}</div>
|
||||||
<div class="tooltip-label">${set.title ? set.title : '' }</div>
|
<div class="tooltip-label">${set.title ? set.title : ''}</div>
|
||||||
</div>`
|
</div>`
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -90,15 +90,15 @@ export default class SvgTip {
|
|||||||
|
|
||||||
this.top = this.y - this.container.offsetHeight
|
this.top = this.y - this.container.offsetHeight
|
||||||
- TOOLTIP_POINTER_TRIANGLE_HEIGHT;
|
- TOOLTIP_POINTER_TRIANGLE_HEIGHT;
|
||||||
this.left = this.x - width/2;
|
this.left = this.x - width / 2;
|
||||||
let maxLeft = this.parent.offsetWidth - width;
|
let maxLeft = this.parent.offsetWidth - width;
|
||||||
|
|
||||||
let pointer = this.container.querySelector('.svg-pointer');
|
let pointer = this.container.querySelector('.svg-pointer');
|
||||||
|
|
||||||
if(this.left < 0) {
|
if (this.left < 0) {
|
||||||
pointer.style.left = `calc(50% - ${-1 * this.left}px)`;
|
pointer.style.left = `calc(50% - ${-1 * this.left}px)`;
|
||||||
this.left = 0;
|
this.left = 0;
|
||||||
} else if(this.left > maxLeft) {
|
} else if (this.left > maxLeft) {
|
||||||
let delta = this.left - maxLeft;
|
let delta = this.left - maxLeft;
|
||||||
let pointerOffset = `calc(50% + ${delta}px)`;
|
let pointerOffset = `calc(50% + ${delta}px)`;
|
||||||
pointer.style.left = pointerOffset;
|
pointer.style.left = pointerOffset;
|
||||||
|
|||||||
@ -11,11 +11,11 @@ export function translate(unit, oldCoord, newCoord, duration) {
|
|||||||
let old = typeof oldCoord === 'string' ? oldCoord : oldCoord.join(', ');
|
let old = typeof oldCoord === 'string' ? oldCoord : oldCoord.join(', ');
|
||||||
return [
|
return [
|
||||||
unit,
|
unit,
|
||||||
{transform: newCoord.join(', ')},
|
{ transform: newCoord.join(', ') },
|
||||||
duration,
|
duration,
|
||||||
STD_EASING,
|
STD_EASING,
|
||||||
"translate",
|
"translate",
|
||||||
{transform: old}
|
{ transform: old }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,14 +42,14 @@ export function animateRegion(rectGroup, newY1, newY2, oldY2) {
|
|||||||
return [rectAnim, groupAnim];
|
return [rectAnim, groupAnim];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function animateBar(bar, x, yTop, width, offset=0, meta={}) {
|
export function animateBar(bar, x, yTop, width, offset = 0, meta = {}) {
|
||||||
let [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);
|
let [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);
|
||||||
y -= offset;
|
y -= offset;
|
||||||
if(bar.nodeName !== 'rect') {
|
if (bar.nodeName !== 'rect') {
|
||||||
let rect = bar.childNodes[0];
|
let rect = bar.childNodes[0];
|
||||||
let rectAnim = [
|
let rectAnim = [
|
||||||
rect,
|
rect,
|
||||||
{width: width, height: height},
|
{ width: width, height: height },
|
||||||
UNIT_ANIM_DUR,
|
UNIT_ANIM_DUR,
|
||||||
STD_EASING
|
STD_EASING
|
||||||
];
|
];
|
||||||
@ -58,18 +58,18 @@ export function animateBar(bar, x, yTop, width, offset=0, meta={}) {
|
|||||||
let groupAnim = translate(bar, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);
|
let groupAnim = translate(bar, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);
|
||||||
return [rectAnim, groupAnim];
|
return [rectAnim, groupAnim];
|
||||||
} else {
|
} else {
|
||||||
return [[bar, {width: width, height: height, x: x, y: y}, UNIT_ANIM_DUR, STD_EASING]];
|
return [[bar, { width: width, height: height, x: x, y: y }, UNIT_ANIM_DUR, STD_EASING]];
|
||||||
}
|
}
|
||||||
// bar.animate({height: args.newHeight, y: yTop}, UNIT_ANIM_DUR, mina.easein);
|
// bar.animate({height: args.newHeight, y: yTop}, UNIT_ANIM_DUR, mina.easein);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function animateDot(dot, x, y) {
|
export function animateDot(dot, x, y) {
|
||||||
if(dot.nodeName !== 'circle') {
|
if (dot.nodeName !== 'circle') {
|
||||||
let oldCoordStr = dot.getAttribute("transform").split("(")[1].slice(0, -1);
|
let oldCoordStr = dot.getAttribute("transform").split("(")[1].slice(0, -1);
|
||||||
let groupAnim = translate(dot, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);
|
let groupAnim = translate(dot, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);
|
||||||
return [groupAnim];
|
return [groupAnim];
|
||||||
} else {
|
} else {
|
||||||
return [[dot, {cx: x, cy: y}, UNIT_ANIM_DUR, STD_EASING]];
|
return [[dot, { cx: x, cy: y }, UNIT_ANIM_DUR, STD_EASING]];
|
||||||
}
|
}
|
||||||
// dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein);
|
// dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein);
|
||||||
}
|
}
|
||||||
@ -81,16 +81,16 @@ export function animatePath(paths, newXList, newYList, zeroLine, spline) {
|
|||||||
if (spline)
|
if (spline)
|
||||||
pointsStr = getSplineCurvePointsStr(newXList, newYList);
|
pointsStr = getSplineCurvePointsStr(newXList, newYList);
|
||||||
|
|
||||||
const animPath = [paths.path, {d:"M" + pointsStr}, PATH_ANIM_DUR, STD_EASING];
|
const animPath = [paths.path, { d: "M" + pointsStr }, PATH_ANIM_DUR, STD_EASING];
|
||||||
pathComponents.push(animPath);
|
pathComponents.push(animPath);
|
||||||
|
|
||||||
if(paths.region) {
|
if (paths.region) {
|
||||||
let regStartPt = `${newXList[0]},${zeroLine}L`;
|
let regStartPt = `${newXList[0]},${zeroLine}L`;
|
||||||
let regEndPt = `L${newXList.slice(-1)[0]}, ${zeroLine}`;
|
let regEndPt = `L${newXList.slice(-1)[0]}, ${zeroLine}`;
|
||||||
|
|
||||||
const animRegion = [
|
const animRegion = [
|
||||||
paths.region,
|
paths.region,
|
||||||
{d:"M" + regStartPt + pointsStr + regEndPt},
|
{ d: "M" + regStartPt + pointsStr + regEndPt },
|
||||||
PATH_ANIM_DUR,
|
PATH_ANIM_DUR,
|
||||||
STD_EASING
|
STD_EASING
|
||||||
];
|
];
|
||||||
@ -101,5 +101,5 @@ export function animatePath(paths, newXList, newYList, zeroLine, spline) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function animatePathStr(oldPath, pathStr) {
|
export function animatePathStr(oldPath, pathStr) {
|
||||||
return [oldPath, {d: pathStr}, UNIT_ANIM_DUR, STD_EASING];
|
return [oldPath, { d: pathStr }, UNIT_ANIM_DUR, STD_EASING];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,14 +11,14 @@ const EASING = {
|
|||||||
easeinout: "0.42 0 0.58 1"
|
easeinout: "0.42 0 0.58 1"
|
||||||
};
|
};
|
||||||
|
|
||||||
function animateSVGElement(element, props, dur, easingType="linear", type=undefined, oldValues={}) {
|
function animateSVGElement(element, props, dur, easingType = "linear", type = undefined, oldValues = {}) {
|
||||||
|
|
||||||
let animElement = element.cloneNode(true);
|
let animElement = element.cloneNode(true);
|
||||||
let newElement = element.cloneNode(true);
|
let newElement = element.cloneNode(true);
|
||||||
|
|
||||||
for(var attributeName in props) {
|
for (var attributeName in props) {
|
||||||
let animateElement;
|
let animateElement;
|
||||||
if(attributeName === 'transform') {
|
if (attributeName === 'transform') {
|
||||||
animateElement = document.createElementNS("http://www.w3.org/2000/svg", "animateTransform");
|
animateElement = document.createElementNS("http://www.w3.org/2000/svg", "animateTransform");
|
||||||
} else {
|
} else {
|
||||||
animateElement = document.createElementNS("http://www.w3.org/2000/svg", "animate");
|
animateElement = document.createElementNS("http://www.w3.org/2000/svg", "animate");
|
||||||
@ -31,7 +31,7 @@ function animateSVGElement(element, props, dur, easingType="linear", type=undefi
|
|||||||
from: currentValue,
|
from: currentValue,
|
||||||
to: value,
|
to: value,
|
||||||
begin: "0s",
|
begin: "0s",
|
||||||
dur: dur/1000 + "s",
|
dur: dur / 1000 + "s",
|
||||||
values: currentValue + ";" + value,
|
values: currentValue + ";" + value,
|
||||||
keySplines: EASING[easingType],
|
keySplines: EASING[easingType],
|
||||||
keyTimes: "0;1",
|
keyTimes: "0;1",
|
||||||
@ -39,7 +39,7 @@ function animateSVGElement(element, props, dur, easingType="linear", type=undefi
|
|||||||
fill: 'freeze'
|
fill: 'freeze'
|
||||||
};
|
};
|
||||||
|
|
||||||
if(type) {
|
if (type) {
|
||||||
animAttr["type"] = type;
|
animAttr["type"] = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ function animateSVGElement(element, props, dur, easingType="linear", type=undefi
|
|||||||
|
|
||||||
animElement.appendChild(animateElement);
|
animElement.appendChild(animateElement);
|
||||||
|
|
||||||
if(type) {
|
if (type) {
|
||||||
newElement.setAttribute(attributeName, `translate(${value})`);
|
newElement.setAttribute(attributeName, `translate(${value})`);
|
||||||
} else {
|
} else {
|
||||||
newElement.setAttribute(attributeName, value);
|
newElement.setAttribute(attributeName, value);
|
||||||
@ -97,10 +97,10 @@ function animateSVG(svgContainer, elements) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function runSMILAnimation(parent, svgElement, elementsToAnimate) {
|
export function runSMILAnimation(parent, svgElement, elementsToAnimate) {
|
||||||
if(elementsToAnimate.length === 0) return;
|
if (elementsToAnimate.length === 0) return;
|
||||||
|
|
||||||
let animSvgElement = animateSVG(svgElement, elementsToAnimate);
|
let animSvgElement = animateSVG(svgElement, elementsToAnimate);
|
||||||
if(svgElement.parentNode == parent) {
|
if (svgElement.parentNode == parent) {
|
||||||
parent.removeChild(svgElement);
|
parent.removeChild(svgElement);
|
||||||
parent.appendChild(animSvgElement);
|
parent.appendChild(animSvgElement);
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ export function runSMILAnimation(parent, svgElement, elementsToAnimate) {
|
|||||||
|
|
||||||
// Replace the new svgElement (data has already been replaced)
|
// Replace the new svgElement (data has already been replaced)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if(animSvgElement.parentNode == parent) {
|
if (animSvgElement.parentNode == parent) {
|
||||||
parent.removeChild(animSvgElement);
|
parent.removeChild(animSvgElement);
|
||||||
parent.appendChild(svgElement);
|
parent.appendChild(svgElement);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
import { fillArray } from '../utils/helpers';
|
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) {
|
export function dataPrep(data, type) {
|
||||||
data.labels = data.labels || [];
|
data.labels = data.labels || [];
|
||||||
@ -9,16 +12,16 @@ export function dataPrep(data, type) {
|
|||||||
// Datasets
|
// Datasets
|
||||||
let datasets = data.datasets;
|
let datasets = data.datasets;
|
||||||
let zeroArray = new Array(datasetLength).fill(0);
|
let zeroArray = new Array(datasetLength).fill(0);
|
||||||
if(!datasets) {
|
if (!datasets) {
|
||||||
// default
|
// default
|
||||||
datasets = [{
|
datasets = [{
|
||||||
values: zeroArray
|
values: zeroArray
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
datasets.map(d=> {
|
datasets.map(d => {
|
||||||
// Set values
|
// Set values
|
||||||
if(!d.values) {
|
if (!d.values) {
|
||||||
d.values = zeroArray;
|
d.values = zeroArray;
|
||||||
} else {
|
} else {
|
||||||
// Check for non values
|
// Check for non values
|
||||||
@ -26,19 +29,17 @@ export function dataPrep(data, type) {
|
|||||||
vals = vals.map(val => (!isNaN(val) ? val : 0));
|
vals = vals.map(val => (!isNaN(val) ? val : 0));
|
||||||
|
|
||||||
// Trim or extend
|
// Trim or extend
|
||||||
if(vals.length > datasetLength) {
|
if (vals.length > datasetLength) {
|
||||||
vals = vals.slice(0, datasetLength);
|
vals = vals.slice(0, datasetLength);
|
||||||
} else {
|
} else {
|
||||||
vals = fillArray(vals, datasetLength - vals.length, 0);
|
vals = fillArray(vals, datasetLength - vals.length, 0);
|
||||||
}
|
}
|
||||||
|
d.values = vals;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set labels
|
|
||||||
//
|
|
||||||
|
|
||||||
// Set type
|
// Set type
|
||||||
if(!d.chartType ) {
|
if (!d.chartType) {
|
||||||
if(!AXIS_DATASET_CHART_TYPES.includes(type)) type === DEFAULT_AXIS_CHART_TYPE;
|
if (!AXIS_DATASET_CHART_TYPES.includes(type)) type === DEFAULT_AXIS_CHART_TYPE;
|
||||||
d.chartType = type;
|
d.chartType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,9 +49,9 @@ export function dataPrep(data, type) {
|
|||||||
|
|
||||||
// Regions
|
// Regions
|
||||||
// data.yRegions = data.yRegions || [];
|
// data.yRegions = data.yRegions || [];
|
||||||
if(data.yRegions) {
|
if (data.yRegions) {
|
||||||
data.yRegions.map(d => {
|
data.yRegions.map(d => {
|
||||||
if(d.end < d.start) {
|
if (d.end < d.start) {
|
||||||
[d.start, d.end] = [d.end, d.start];
|
[d.start, d.end] = [d.end, d.start];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -74,7 +75,7 @@ export function zeroDataPrep(realData) {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
if(realData.yMarkers) {
|
if (realData.yMarkers) {
|
||||||
zeroData.yMarkers = [
|
zeroData.yMarkers = [
|
||||||
{
|
{
|
||||||
value: 0,
|
value: 0,
|
||||||
@ -83,7 +84,7 @@ export function zeroDataPrep(realData) {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(realData.yRegions) {
|
if (realData.yRegions) {
|
||||||
zeroData.yRegions = [
|
zeroData.yRegions = [
|
||||||
{
|
{
|
||||||
start: 0,
|
start: 0,
|
||||||
@ -96,31 +97,37 @@ export function zeroDataPrep(realData) {
|
|||||||
return zeroData;
|
return zeroData;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getShortenedLabels(chartWidth, labels=[], isSeries=true) {
|
export function getShortenedLabels(chartWidth, labels = [], isSeries = true, seriesLabelSpaceRatio) {
|
||||||
let allowedSpace = chartWidth / labels.length;
|
let allowedSpace = (chartWidth / labels.length) * (seriesLabelSpaceRatio || SERIES_LABEL_SPACE_RATIO);
|
||||||
if(allowedSpace <= 0) allowedSpace = 1;
|
if (allowedSpace <= 0) allowedSpace = 1;
|
||||||
let allowedLetters = allowedSpace / DEFAULT_CHAR_WIDTH;
|
let allowedLetters = allowedSpace / DEFAULT_CHAR_WIDTH;
|
||||||
|
|
||||||
let seriesMultiple;
|
let seriesMultiple;
|
||||||
if(isSeries) {
|
if (isSeries) {
|
||||||
// Find the maximum label length for spacing calculations
|
// Find the maximum label length for spacing calculations
|
||||||
let maxLabelLength = Math.max(...labels.map(label => label.length));
|
let maxLabelLength = Math.max(...labels.map(label => label.length));
|
||||||
seriesMultiple = Math.ceil(maxLabelLength/allowedLetters);
|
seriesMultiple = Math.ceil(maxLabelLength / allowedLetters);
|
||||||
}
|
}
|
||||||
|
|
||||||
let calcLabels = labels.map((label, i) => {
|
let calcLabels = labels.map((label, i) => {
|
||||||
label += "";
|
label += "";
|
||||||
if(label.length > allowedLetters) {
|
if (label.length > allowedLetters) {
|
||||||
|
|
||||||
if(!isSeries) {
|
if (!isSeries) {
|
||||||
if(allowedLetters-3 > 0) {
|
if (allowedLetters - 3 > 0) {
|
||||||
label = label.slice(0, allowedLetters-3) + " ...";
|
label = label.slice(0, allowedLetters - 3) + " ...";
|
||||||
} else {
|
} else {
|
||||||
label = label.slice(0, allowedLetters) + '..';
|
label = label.slice(0, allowedLetters) + '..';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(i % seriesMultiple !== 0) {
|
if (i % seriesMultiple !== 0) {
|
||||||
label = "";
|
if (i !== (labels.length - 1)) {
|
||||||
|
label = "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (i > (labels.length - (seriesMultiple / 2))) {
|
||||||
|
label = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ const PRESET_COLOR_MAP = {
|
|||||||
'light-orange': '#FECDB8'
|
'light-orange': '#FECDB8'
|
||||||
};
|
};
|
||||||
|
|
||||||
function limitColor(r){
|
function limitColor(r) {
|
||||||
if (r > 255) return 255;
|
if (r > 255) return 255;
|
||||||
else if (r < 0) return 0;
|
else if (r < 0) return 0;
|
||||||
return r;
|
return r;
|
||||||
@ -34,11 +34,11 @@ export function lightenDarkenColor(color, amt) {
|
|||||||
col = col.slice(1);
|
col = col.slice(1);
|
||||||
usePound = true;
|
usePound = true;
|
||||||
}
|
}
|
||||||
let num = parseInt(col,16);
|
let num = parseInt(col, 16);
|
||||||
let r = limitColor((num >> 16) + amt);
|
let r = limitColor((num >> 16) + amt);
|
||||||
let b = limitColor(((num >> 8) & 0x00FF) + amt);
|
let b = limitColor(((num >> 8) & 0x00FF) + amt);
|
||||||
let g = limitColor((num & 0x0000FF) + amt);
|
let g = limitColor((num & 0x0000FF) + amt);
|
||||||
return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
|
return (usePound ? "#" : "") + (g | (b << 8) | (r << 16)).toString(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isValidColor(string) {
|
export function isValidColor(string) {
|
||||||
|
|||||||
@ -65,16 +65,16 @@ export const CHART_POST_ANIMATE_TIMEOUT = 400;
|
|||||||
export const DEFAULT_AXIS_CHART_TYPE = 'line';
|
export const DEFAULT_AXIS_CHART_TYPE = 'line';
|
||||||
export const AXIS_DATASET_CHART_TYPES = ['line', 'bar'];
|
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 MIN_BAR_PERCENT_HEIGHT = 0.00;
|
||||||
|
|
||||||
export const LINE_CHART_DOT_SIZE = 4;
|
export const LINE_CHART_DOT_SIZE = 4;
|
||||||
export const DOT_OVERLAY_SIZE_INCR = 4;
|
export const DOT_OVERLAY_SIZE_INCR = 4;
|
||||||
|
|
||||||
export const PERCENTAGE_BAR_DEFAULT_HEIGHT = 20;
|
export const PERCENTAGE_BAR_DEFAULT_HEIGHT = 16;
|
||||||
export const PERCENTAGE_BAR_DEFAULT_DEPTH = 2;
|
|
||||||
|
|
||||||
// Fixed 5-color theme,
|
// Fixed 5-color theme,
|
||||||
// More colors are difficult to parse visually
|
// More colors are difficult to parse visually
|
||||||
|
|||||||
@ -27,8 +27,8 @@ export function getYyyyMmDd(date) {
|
|||||||
let mm = date.getMonth() + 1; // getMonth() is zero-based
|
let mm = date.getMonth() + 1; // getMonth() is zero-based
|
||||||
return [
|
return [
|
||||||
date.getFullYear(),
|
date.getFullYear(),
|
||||||
(mm>9 ? '' : '0') + mm,
|
(mm > 9 ? '' : '0') + mm,
|
||||||
(dd>9 ? '' : '0') + dd
|
(dd > 9 ? '' : '0') + dd
|
||||||
].join('-');
|
].join('-');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,12 +37,12 @@ export function clone(date) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function timestampSec(date) {
|
export function timestampSec(date) {
|
||||||
return date.getTime()/NO_OF_MILLIS;
|
return date.getTime() / NO_OF_MILLIS;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function timestampToMidnight(timestamp, roundAhead = false) {
|
export function timestampToMidnight(timestamp, roundAhead = false) {
|
||||||
let midnightTs = Math.floor(timestamp - (timestamp % SEC_IN_DAY));
|
let midnightTs = Math.floor(timestamp - (timestamp % SEC_IN_DAY));
|
||||||
if(roundAhead) {
|
if (roundAhead) {
|
||||||
return midnightTs + SEC_IN_DAY;
|
return midnightTs + SEC_IN_DAY;
|
||||||
}
|
}
|
||||||
return midnightTs;
|
return midnightTs;
|
||||||
@ -65,12 +65,12 @@ export function areInSameMonth(startDate, endDate) {
|
|||||||
&& startDate.getFullYear() === endDate.getFullYear();
|
&& startDate.getFullYear() === endDate.getFullYear();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMonthName(i, short=false) {
|
export function getMonthName(i, short = false) {
|
||||||
let monthName = MONTH_NAMES[i];
|
let monthName = MONTH_NAMES[i];
|
||||||
return short ? monthName.slice(0, 3) : monthName;
|
return short ? monthName.slice(0, 3) : monthName;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLastDateInMonth (month, year) {
|
export function getLastDateInMonth(month, year) {
|
||||||
return new Date(year, month + 1, 0); // 0: last day in previous month
|
return new Date(year, month + 1, 0); // 0: last day in previous month
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ export function getLastDateInMonth (month, year) {
|
|||||||
export function setDayToSunday(date) {
|
export function setDayToSunday(date) {
|
||||||
let newDate = clone(date);
|
let newDate = clone(date);
|
||||||
const day = newDate.getDay();
|
const day = newDate.getDay();
|
||||||
if(day !== 0) {
|
if (day !== 0) {
|
||||||
addDays(newDate, (-1) * day);
|
addDays(newDate, (-1) * day);
|
||||||
}
|
}
|
||||||
return newDate;
|
return newDate;
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
export function $(expr, con) {
|
export function $(expr, con) {
|
||||||
return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
|
return typeof expr === "string" ? (con || document).querySelector(expr) : expr || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findNodeIndex(node)
|
export function findNodeIndex(node) {
|
||||||
{
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
while (node.previousSibling) {
|
while (node.previousSibling) {
|
||||||
node = node.previousSibling;
|
node = node.previousSibling;
|
||||||
@ -27,12 +26,12 @@ $.create = (tag, o) => {
|
|||||||
element.appendChild(ref);
|
element.appendChild(ref);
|
||||||
|
|
||||||
} else if (i === "styles") {
|
} else if (i === "styles") {
|
||||||
if(typeof val === "object") {
|
if (typeof val === "object") {
|
||||||
Object.keys(val).map(prop => {
|
Object.keys(val).map(prop => {
|
||||||
element.style[prop] = val[prop];
|
element.style[prop] = val[prop];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (i in element ) {
|
} else if (i in element) {
|
||||||
element[i] = val;
|
element[i] = val;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -67,9 +66,9 @@ export function isElementInViewport(el) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
rect.top >= 0 &&
|
rect.top >= 0 &&
|
||||||
rect.left >= 0 &&
|
rect.left >= 0 &&
|
||||||
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
|
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
|
||||||
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
|
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +80,7 @@ export function getElementContentWidth(element) {
|
|||||||
return element.clientWidth - padding;
|
return element.clientWidth - padding;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bind(element, o){
|
export function bind(element, o) {
|
||||||
if (element) {
|
if (element) {
|
||||||
for (var event in o) {
|
for (var event in o) {
|
||||||
var callback = o[event];
|
var callback = o[event];
|
||||||
@ -93,12 +92,12 @@ export function bind(element, o){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function unbind(element, o){
|
export function unbind(element, o) {
|
||||||
if (element) {
|
if (element) {
|
||||||
for (var event in o) {
|
for (var event in o) {
|
||||||
var callback = o[event];
|
var callback = o[event];
|
||||||
|
|
||||||
event.split(/\s+/).forEach(function(event) {
|
event.split(/\s+/).forEach(function (event) {
|
||||||
element.removeEventListener(event, callback);
|
element.removeEventListener(event, callback);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -108,7 +107,7 @@ export function unbind(element, o){
|
|||||||
export function fire(target, type, properties) {
|
export function fire(target, type, properties) {
|
||||||
var evt = document.createEvent("HTMLEvents");
|
var evt = document.createEvent("HTMLEvents");
|
||||||
|
|
||||||
evt.initEvent(type, true, true );
|
evt.initEvent(type, true, true);
|
||||||
|
|
||||||
for (var j in properties) {
|
for (var j in properties) {
|
||||||
evt[j] = properties[j];
|
evt[j] = properties[j];
|
||||||
@ -119,17 +118,17 @@ export function fire(target, type, properties) {
|
|||||||
|
|
||||||
// https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/
|
// https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/
|
||||||
export function forEachNode(nodeList, callback, scope) {
|
export function forEachNode(nodeList, callback, scope) {
|
||||||
if(!nodeList) return;
|
if (!nodeList) return;
|
||||||
for (var i = 0; i < nodeList.length; i++) {
|
for (var i = 0; i < nodeList.length; i++) {
|
||||||
callback.call(scope, nodeList[i], i);
|
callback.call(scope, nodeList[i], i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function activate($parent, $child, commonClass, activeClass='active', index = -1) {
|
export function activate($parent, $child, commonClass, activeClass = 'active', index = -1) {
|
||||||
let $children = $parent.querySelectorAll(`.${commonClass}.${activeClass}`);
|
let $children = $parent.querySelectorAll(`.${commonClass}.${activeClass}`);
|
||||||
|
|
||||||
forEachNode($children, (node, i) => {
|
forEachNode($children, (node, i) => {
|
||||||
if(index >= 0 && i <= index) return;
|
if (index >= 0 && i <= index) return;
|
||||||
node.classList.remove(activeClass);
|
node.classList.remove(activeClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ export function equilizeNoOfElements(array1, array2,
|
|||||||
extraCount = array2.length - array1.length) {
|
extraCount = array2.length - array1.length) {
|
||||||
|
|
||||||
// Doesn't work if either has zero elements.
|
// Doesn't work if either has zero elements.
|
||||||
if(extraCount > 0) {
|
if (extraCount > 0) {
|
||||||
array1 = fillArray(array1, extraCount);
|
array1 = fillArray(array1, extraCount);
|
||||||
} else {
|
} else {
|
||||||
array2 = fillArray(array2, extraCount);
|
array2 = fillArray(array2, extraCount);
|
||||||
@ -30,7 +30,7 @@ export function truncateString(txt, len) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (txt.length > len) {
|
if (txt.length > len) {
|
||||||
return txt.slice(0, len-3) + '...';
|
return txt.slice(0, len - 3) + '...';
|
||||||
} else {
|
} else {
|
||||||
return txt;
|
return txt;
|
||||||
}
|
}
|
||||||
@ -47,18 +47,20 @@ export function shortenLargeNumber(label) {
|
|||||||
// Using absolute since log wont work for negative numbers
|
// Using absolute since log wont work for negative numbers
|
||||||
let p = Math.floor(Math.log10(Math.abs(number)));
|
let p = Math.floor(Math.log10(Math.abs(number)));
|
||||||
if (p <= 2) return number; // Return as is for a 3 digit number of less
|
if (p <= 2) return number; // Return as is for a 3 digit number of less
|
||||||
let l = Math.floor(p / 3);
|
let l = Math.floor(p / 3);
|
||||||
let shortened = (Math.pow(10, p - l * 3) * +(number / Math.pow(10, p)).toFixed(1));
|
let shortened = (Math.pow(10, p - l * 3) * +(number / Math.pow(10, p)).toFixed(1));
|
||||||
|
|
||||||
// Correct for floating point error upto 2 decimal places
|
// 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)
|
// cubic bezier curve calculation (from example by François Romain)
|
||||||
export function getSplineCurvePointsStr(xList, yList) {
|
export function getSplineCurvePointsStr(xList, yList) {
|
||||||
|
|
||||||
let points=[];
|
let points = [];
|
||||||
for(let i=0;i<xList.length;i++){
|
const length = Math.min(xList.length, yList.length);
|
||||||
|
|
||||||
|
for (let i = 0; i < xList.length; i++) {
|
||||||
points.push([xList[i], yList[i]]);
|
points.push([xList[i], yList[i]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,15 @@
|
|||||||
import { getBarHeightAndYAttr, truncateString, shortenLargeNumber, getSplineCurvePointsStr } from './draw-utils';
|
import { getBarHeightAndYAttr, truncateString, shortenLargeNumber, getSplineCurvePointsStr } from './draw-utils';
|
||||||
import { getStringWidth, isValidNumber } from './helpers';
|
import { getStringWidth, isValidNumber, round } from './helpers';
|
||||||
import { DOT_OVERLAY_SIZE_INCR, PERCENTAGE_BAR_DEFAULT_DEPTH } from './constants';
|
import { DOT_OVERLAY_SIZE_INCR } from './constants';
|
||||||
import { lightenDarkenColor } from './colors';
|
|
||||||
|
|
||||||
export const AXIS_TICK_LENGTH = 6;
|
export const AXIS_TICK_LENGTH = 6;
|
||||||
const LABEL_MARGIN = 4;
|
const LABEL_MARGIN = 4;
|
||||||
const LABEL_MAX_CHARS = 15;
|
const LABEL_MAX_CHARS = 18;
|
||||||
export const FONT_SIZE = 10;
|
export const FONT_SIZE = 10;
|
||||||
const BASE_LINE_COLOR = '#E2E6E9';
|
const BASE_LINE_COLOR = '#E2E6E9';
|
||||||
const FONT_FILL = '#313B44';
|
|
||||||
|
|
||||||
function $(expr, con) {
|
function $(expr, con) {
|
||||||
return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
|
return typeof expr === "string" ? (con || document).querySelector(expr) : expr || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createSVG(tag, o) {
|
export function createSVG(tag, o) {
|
||||||
@ -29,14 +27,14 @@ export function createSVG(tag, o) {
|
|||||||
element.appendChild(ref);
|
element.appendChild(ref);
|
||||||
|
|
||||||
} else if (i === "styles") {
|
} else if (i === "styles") {
|
||||||
if(typeof val === "object") {
|
if (typeof val === "object") {
|
||||||
Object.keys(val).map(prop => {
|
Object.keys(val).map(prop => {
|
||||||
element.style[prop] = val[prop];
|
element.style[prop] = val[prop];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(i === "className") { i = "class"; }
|
if (i === "className") { i = "class"; }
|
||||||
if(i === "innerHTML") {
|
if (i === "innerHTML") {
|
||||||
element['textContent'] = val;
|
element['textContent'] = val;
|
||||||
} else {
|
} else {
|
||||||
element.setAttribute(i, val);
|
element.setAttribute(i, val);
|
||||||
@ -82,16 +80,16 @@ export function makeSVGDefs(svgContainer) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeSVGGroup(className, transform='', parent=undefined) {
|
export function makeSVGGroup(className, transform = '', parent = undefined) {
|
||||||
let args = {
|
let args = {
|
||||||
className: className,
|
className: className,
|
||||||
transform: transform
|
transform: transform
|
||||||
};
|
};
|
||||||
if(parent) args.inside = parent;
|
if (parent) args.inside = parent;
|
||||||
return createSVG('g', args);
|
return createSVG('g', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wrapInSVGGroup(elements, className='') {
|
export function wrapInSVGGroup(elements, className = '') {
|
||||||
let g = createSVG('g', {
|
let g = createSVG('g', {
|
||||||
className: className
|
className: className
|
||||||
});
|
});
|
||||||
@ -99,7 +97,7 @@ export function wrapInSVGGroup(elements, className='') {
|
|||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makePath(pathStr, className='', stroke='none', fill='none', strokeWidth=2) {
|
export function makePath(pathStr, className = '', stroke = 'none', fill = 'none', strokeWidth = 2) {
|
||||||
return createSVG('path', {
|
return createSVG('path', {
|
||||||
className: className,
|
className: className,
|
||||||
d: pathStr,
|
d: pathStr,
|
||||||
@ -111,7 +109,7 @@ export function makePath(pathStr, className='', stroke='none', fill='none', stro
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeArcPathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){
|
export function makeArcPathStr(startPosition, endPosition, center, radius, clockWise = 1, largeArc = 0) {
|
||||||
let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];
|
let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];
|
||||||
let [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];
|
let [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];
|
||||||
return `M${center.x} ${center.y}
|
return `M${center.x} ${center.y}
|
||||||
@ -120,7 +118,7 @@ export function makeArcPathStr(startPosition, endPosition, center, radius, clock
|
|||||||
${arcEndX} ${arcEndY} z`;
|
${arcEndX} ${arcEndY} z`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){
|
export function makeCircleStr(startPosition, endPosition, center, radius, clockWise = 1, largeArc = 0) {
|
||||||
let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];
|
let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];
|
||||||
let [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, center.y * 2, center.y + endPosition.y];
|
let [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, center.y * 2, center.y + endPosition.y];
|
||||||
return `M${center.x} ${center.y}
|
return `M${center.x} ${center.y}
|
||||||
@ -132,7 +130,7 @@ export function makeCircleStr(startPosition, endPosition, center, radius, clockW
|
|||||||
${arcEndX} ${arcEndY} z`;
|
${arcEndX} ${arcEndY} z`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeArcStrokePathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){
|
export function makeArcStrokePathStr(startPosition, endPosition, center, radius, clockWise = 1, largeArc = 0) {
|
||||||
let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];
|
let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];
|
||||||
let [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];
|
let [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];
|
||||||
|
|
||||||
@ -141,7 +139,7 @@ export function makeArcStrokePathStr(startPosition, endPosition, center, radius,
|
|||||||
${arcEndX} ${arcEndY}`;
|
${arcEndX} ${arcEndY}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeStrokeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){
|
export function makeStrokeCircleStr(startPosition, endPosition, center, radius, clockWise = 1, largeArc = 0) {
|
||||||
let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];
|
let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];
|
||||||
let [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, radius * 2 + arcStartY, center.y + startPosition.y];
|
let [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, radius * 2 + arcStartY, center.y + startPosition.y];
|
||||||
|
|
||||||
@ -154,11 +152,11 @@ export function makeStrokeCircleStr(startPosition, endPosition, center, radius,
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function makeGradient(svgDefElem, color, lighter = false) {
|
export function makeGradient(svgDefElem, color, lighter = false) {
|
||||||
let gradientId ='path-fill-gradient' + '-' + color + '-' +(lighter ? 'lighter' : 'default');
|
let gradientId = 'path-fill-gradient' + '-' + color + '-' + (lighter ? 'lighter' : 'default');
|
||||||
let gradientDef = renderVerticalGradient(svgDefElem, gradientId);
|
let gradientDef = renderVerticalGradient(svgDefElem, gradientId);
|
||||||
let opacities = [1, 0.6, 0.2];
|
let opacities = [1, 0.6, 0.2];
|
||||||
if(lighter) {
|
if (lighter) {
|
||||||
opacities = [0.4, 0.2, 0];
|
opacities = [0.15, 0.05, 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
setGradientStop(gradientDef, "0%", color, opacities[0]);
|
setGradientStop(gradientDef, "0%", color, opacities[0]);
|
||||||
@ -168,8 +166,31 @@ export function makeGradient(svgDefElem, color, lighter = false) {
|
|||||||
return gradientId;
|
return gradientId;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function percentageBar(x, y, width, height,
|
export function rightRoundedBar(x, width, height) {
|
||||||
depth=PERCENTAGE_BAR_DEFAULT_DEPTH, fill='none') {
|
// 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 = {
|
let args = {
|
||||||
className: 'percentage-bar',
|
className: 'percentage-bar',
|
||||||
@ -177,20 +198,13 @@ export function percentageBar(x, y, width, height,
|
|||||||
y: y,
|
y: y,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
fill: fill,
|
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
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return createSVG("rect", args);
|
return createSVG("rect", args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function heatSquare(className, x, y, size, radius, fill='none', data={}) {
|
export function heatSquare(className, x, y, size, radius, fill = 'none', data = {}) {
|
||||||
let args = {
|
let args = {
|
||||||
className: className,
|
className: className,
|
||||||
x: x,
|
x: x,
|
||||||
@ -208,39 +222,9 @@ export function heatSquare(className, x, y, size, radius, fill='none', data={})
|
|||||||
return createSVG("rect", args);
|
return createSVG("rect", args);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function legendBar(x, y, size, fill='none', label, 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;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
label = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;
|
label = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;
|
||||||
|
if (!font_size) font_size = FONT_SIZE;
|
||||||
|
|
||||||
let args = {
|
let args = {
|
||||||
className: 'legend-dot',
|
className: 'legend-dot',
|
||||||
@ -256,32 +240,36 @@ export function legendDot(x, y, size, radius, fill='none', label, value, truncat
|
|||||||
className: 'legend-dataset-label',
|
className: 'legend-dataset-label',
|
||||||
x: size,
|
x: size,
|
||||||
y: 0,
|
y: 0,
|
||||||
dx: (FONT_SIZE) + 'px',
|
dx: (font_size) + 'px',
|
||||||
dy: (FONT_SIZE/3) + 'px',
|
dy: (font_size / 3) + 'px',
|
||||||
'font-size': (FONT_SIZE * 1.6) + 'px',
|
'font-size': (font_size * 1.6) + 'px',
|
||||||
'text-anchor': 'start',
|
'text-anchor': 'start',
|
||||||
fill: FONT_FILL,
|
|
||||||
innerHTML: label
|
innerHTML: label
|
||||||
});
|
});
|
||||||
|
|
||||||
let textValue = createSVG('text', {
|
let textValue = null;
|
||||||
className: 'legend-dataset-value',
|
if (value) {
|
||||||
x: size,
|
textValue = createSVG('text', {
|
||||||
y: FONT_SIZE + 10,
|
className: 'legend-dataset-value',
|
||||||
dx: (FONT_SIZE) + 'px',
|
x: size,
|
||||||
dy: (FONT_SIZE/3) + 'px',
|
y: FONT_SIZE + 10,
|
||||||
'font-size': (FONT_SIZE * 1.2) + 'px',
|
dx: (FONT_SIZE) + 'px',
|
||||||
'text-anchor': 'start',
|
dy: (FONT_SIZE / 3) + 'px',
|
||||||
fill: FONT_FILL,
|
'font-size': (FONT_SIZE * 1.2) + 'px',
|
||||||
innerHTML: value
|
'text-anchor': 'start',
|
||||||
});
|
innerHTML: value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let group = createSVG('g', {
|
let group = createSVG('g', {
|
||||||
transform: `translate(${x}, ${y})`
|
transform: `translate(${x}, ${y})`
|
||||||
});
|
});
|
||||||
group.appendChild(createSVG("rect", args));
|
group.appendChild(createSVG("rect", args));
|
||||||
group.appendChild(textLabel);
|
group.appendChild(textLabel);
|
||||||
group.appendChild(textValue);
|
|
||||||
|
if (value && textValue) {
|
||||||
|
group.appendChild(textValue);
|
||||||
|
}
|
||||||
|
|
||||||
return group;
|
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 = {}) {
|
export function makeText(className, x, y, content, options = {}) {
|
||||||
let fontSize = options.fontSize || FONT_SIZE;
|
let fontSize = options.fontSize || FONT_SIZE;
|
||||||
let dy = options.dy !== undefined ? options.dy : (fontSize / 2);
|
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';
|
let textAnchor = options.textAnchor || 'start';
|
||||||
return createSVG('text', {
|
return createSVG('text', {
|
||||||
className: className,
|
className: className,
|
||||||
@ -303,8 +291,7 @@ export function makeText(className, x, y, content, options = {}) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeVertLine(x, label, y1, y2, options={}) {
|
function makeVertLine(x, label, y1, y2, options = {}) {
|
||||||
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
|
||||||
let l = createSVG('line', {
|
let l = createSVG('line', {
|
||||||
className: 'line-vertical ' + options.className,
|
className: 'line-vertical ' + options.className,
|
||||||
x1: 0,
|
x1: 0,
|
||||||
@ -326,7 +313,7 @@ function makeVertLine(x, label, y1, y2, options={}) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let line = createSVG('g', {
|
let line = createSVG('g', {
|
||||||
transform: `translate(${ x }, 0)`
|
transform: `translate(${x}, 0)`
|
||||||
});
|
});
|
||||||
|
|
||||||
line.appendChild(l);
|
line.appendChild(l);
|
||||||
@ -335,13 +322,18 @@ function makeVertLine(x, label, y1, y2, options={}) {
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeHoriLine(y, label, x1, x2, options={}) {
|
function makeHoriLine(y, label, x1, x2, options = {}) {
|
||||||
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
if (!options.lineType) options.lineType = '';
|
||||||
if(!options.lineType) options.lineType = '';
|
if (options.shortenNumbers) {
|
||||||
if (options.shortenNumbers) label = shortenLargeNumber(label);
|
if (options.numberFormatter) {
|
||||||
|
label = options.numberFormatter(label);
|
||||||
|
} else {
|
||||||
|
label = shortenLargeNumber(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let className = 'line-horizontal ' + options.className +
|
let className = 'line-horizontal ' + options.className +
|
||||||
(options.lineType === "dashed" ? "dashed": "");
|
(options.lineType === "dashed" ? "dashed" : "");
|
||||||
|
|
||||||
let l = createSVG('line', {
|
let l = createSVG('line', {
|
||||||
className: className,
|
className: className,
|
||||||
@ -360,7 +352,7 @@ function makeHoriLine(y, label, x1, x2, options={}) {
|
|||||||
dy: (FONT_SIZE / 2 - 2) + 'px',
|
dy: (FONT_SIZE / 2 - 2) + 'px',
|
||||||
'font-size': FONT_SIZE + 'px',
|
'font-size': FONT_SIZE + 'px',
|
||||||
'text-anchor': x1 < x2 ? 'end' : 'start',
|
'text-anchor': x1 < x2 ? 'end' : 'start',
|
||||||
innerHTML: label+""
|
innerHTML: label + ""
|
||||||
});
|
});
|
||||||
|
|
||||||
let line = createSVG('g', {
|
let line = createSVG('g', {
|
||||||
@ -368,7 +360,7 @@ function makeHoriLine(y, label, x1, x2, options={}) {
|
|||||||
'stroke-opacity': 1
|
'stroke-opacity': 1
|
||||||
});
|
});
|
||||||
|
|
||||||
if(text === 0 || text === '0') {
|
if (text === 0 || text === '0') {
|
||||||
line.style.stroke = "rgba(27, 31, 35, 0.6)";
|
line.style.stroke = "rgba(27, 31, 35, 0.6)";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,19 +370,19 @@ function makeHoriLine(y, label, x1, x2, options={}) {
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function yLine(y, label, width, options={}) {
|
export function yLine(y, label, width, options = {}) {
|
||||||
if (!isValidNumber(y)) y = 0;
|
if (!isValidNumber(y)) y = 0;
|
||||||
|
|
||||||
if(!options.pos) options.pos = 'left';
|
if (!options.pos) options.pos = 'left';
|
||||||
if(!options.offset) options.offset = 0;
|
if (!options.offset) options.offset = 0;
|
||||||
if(!options.mode) options.mode = 'span';
|
if (!options.mode) options.mode = 'span';
|
||||||
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
if (!options.stroke) options.stroke = BASE_LINE_COLOR;
|
||||||
if(!options.className) options.className = '';
|
if (!options.className) options.className = '';
|
||||||
|
|
||||||
let x1 = -1 * AXIS_TICK_LENGTH;
|
let x1 = -1 * AXIS_TICK_LENGTH;
|
||||||
let x2 = options.mode === 'span' ? width + AXIS_TICK_LENGTH : 0;
|
let x2 = options.mode === 'span' ? width + AXIS_TICK_LENGTH : 0;
|
||||||
|
|
||||||
if(options.mode === 'tick' && options.pos === 'right') {
|
if (options.mode === 'tick' && options.pos === 'right') {
|
||||||
x1 = width + AXIS_TICK_LENGTH;
|
x1 = width + AXIS_TICK_LENGTH;
|
||||||
x2 = width;
|
x2 = width;
|
||||||
}
|
}
|
||||||
@ -400,22 +392,23 @@ export function yLine(y, label, width, options={}) {
|
|||||||
x1 += options.offset;
|
x1 += options.offset;
|
||||||
x2 += options.offset;
|
x2 += options.offset;
|
||||||
|
|
||||||
|
if (typeof label === "number") label = round(label);
|
||||||
|
|
||||||
return makeHoriLine(y, label, x1, x2, {
|
return makeHoriLine(y, label, x1, x2, {
|
||||||
stroke: options.stroke,
|
|
||||||
className: options.className,
|
className: options.className,
|
||||||
lineType: options.lineType,
|
lineType: options.lineType,
|
||||||
shortenNumbers: options.shortenNumbers
|
shortenNumbers: options.shortenNumbers,
|
||||||
|
numberFormatter: options.numberFormatter,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function xLine(x, label, height, options={}) {
|
export function xLine(x, label, height, options = {}) {
|
||||||
if (!isValidNumber(x)) x = 0;
|
if (!isValidNumber(x)) x = 0;
|
||||||
|
|
||||||
if(!options.pos) options.pos = 'bottom';
|
if (!options.pos) options.pos = 'bottom';
|
||||||
if(!options.offset) options.offset = 0;
|
if (!options.offset) options.offset = 0;
|
||||||
if(!options.mode) options.mode = 'span';
|
if (!options.mode) options.mode = 'span';
|
||||||
if(!options.stroke) options.stroke = BASE_LINE_COLOR;
|
if (!options.className) options.className = '';
|
||||||
if(!options.className) options.className = '';
|
|
||||||
|
|
||||||
// Draw X axis line in span/tick mode with optional label
|
// Draw X axis line in span/tick mode with optional label
|
||||||
// y2(span)
|
// y2(span)
|
||||||
@ -431,21 +424,23 @@ export function xLine(x, label, height, options={}) {
|
|||||||
let y1 = height + AXIS_TICK_LENGTH;
|
let y1 = height + AXIS_TICK_LENGTH;
|
||||||
let y2 = options.mode === 'span' ? -1 * AXIS_TICK_LENGTH : height;
|
let y2 = options.mode === 'span' ? -1 * AXIS_TICK_LENGTH : height;
|
||||||
|
|
||||||
if(options.mode === 'tick' && options.pos === 'top') {
|
if (options.mode === 'tick' && options.pos === 'top') {
|
||||||
// top axis ticks
|
// top axis ticks
|
||||||
y1 = -1 * AXIS_TICK_LENGTH;
|
y1 = -1 * AXIS_TICK_LENGTH;
|
||||||
y2 = 0;
|
y2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return makeVertLine(x, label, y1, y2, {
|
return makeVertLine(x, label, y1, y2, {
|
||||||
stroke: options.stroke,
|
|
||||||
className: options.className,
|
className: options.className,
|
||||||
lineType: options.lineType
|
lineType: options.lineType
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function yMarker(y, label, width, options={}) {
|
export function yMarker(y, label, width, options = {}) {
|
||||||
if(!options.labelPos) options.labelPos = 'right';
|
if (!isValidNumber(y)) y = 0;
|
||||||
|
|
||||||
|
if (!options.labelPos) options.labelPos = 'right';
|
||||||
|
if (!options.lineType) options.lineType = 'dashed';
|
||||||
let x = options.labelPos === 'left' ? LABEL_MARGIN
|
let x = options.labelPos === 'left' ? LABEL_MARGIN
|
||||||
: width - getStringWidth(label, 5) - LABEL_MARGIN;
|
: width - getStringWidth(label, 5) - LABEL_MARGIN;
|
||||||
|
|
||||||
@ -456,7 +451,7 @@ export function yMarker(y, label, width, options={}) {
|
|||||||
dy: (FONT_SIZE / -2) + 'px',
|
dy: (FONT_SIZE / -2) + 'px',
|
||||||
'font-size': FONT_SIZE + 'px',
|
'font-size': FONT_SIZE + 'px',
|
||||||
'text-anchor': 'start',
|
'text-anchor': 'start',
|
||||||
innerHTML: label+""
|
innerHTML: label + ""
|
||||||
});
|
});
|
||||||
|
|
||||||
let line = makeHoriLine(y, '', 0, width, {
|
let line = makeHoriLine(y, '', 0, width, {
|
||||||
@ -470,15 +465,15 @@ export function yMarker(y, label, width, options={}) {
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function yRegion(y1, y2, width, label, options={}) {
|
export function yRegion(y1, y2, width, label, options = {}) {
|
||||||
// return a group
|
// return a group
|
||||||
let height = y1 - y2;
|
let height = y1 - y2;
|
||||||
|
|
||||||
let rect = createSVG('rect', {
|
let rect = createSVG('rect', {
|
||||||
className: `bar mini`, // remove class
|
className: `bar mini`, // remove class
|
||||||
styles: {
|
styles: {
|
||||||
fill: `rgba(228, 234, 239, 0.49)`,
|
fill: options.fill || `rgba(228, 234, 239, 0.49)`,
|
||||||
stroke: BASE_LINE_COLOR,
|
stroke: options.stroke || BASE_LINE_COLOR,
|
||||||
'stroke-dasharray': `${width}, ${height}`
|
'stroke-dasharray': `${width}, ${height}`
|
||||||
},
|
},
|
||||||
// 'data-point-index': index,
|
// 'data-point-index': index,
|
||||||
@ -488,9 +483,9 @@ export function yRegion(y1, y2, width, label, options={}) {
|
|||||||
height: height
|
height: height
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!options.labelPos) options.labelPos = 'right';
|
if (!options.labelPos) options.labelPos = 'right';
|
||||||
let x = options.labelPos === 'left' ? LABEL_MARGIN
|
let x = options.labelPos === 'left' ? LABEL_MARGIN
|
||||||
: width - getStringWidth(label+"", 4.5) - LABEL_MARGIN;
|
: width - getStringWidth(label + "", 4.5) - LABEL_MARGIN;
|
||||||
|
|
||||||
let labelSvg = createSVG('text', {
|
let labelSvg = createSVG('text', {
|
||||||
className: 'chart-label',
|
className: 'chart-label',
|
||||||
@ -499,7 +494,7 @@ export function yRegion(y1, y2, width, label, options={}) {
|
|||||||
dy: (FONT_SIZE / -2) + 'px',
|
dy: (FONT_SIZE / -2) + 'px',
|
||||||
'font-size': FONT_SIZE + 'px',
|
'font-size': FONT_SIZE + 'px',
|
||||||
'text-anchor': 'start',
|
'text-anchor': 'start',
|
||||||
innerHTML: label+""
|
innerHTML: label + ""
|
||||||
});
|
});
|
||||||
|
|
||||||
let region = createSVG('g', {
|
let region = createSVG('g', {
|
||||||
@ -512,11 +507,11 @@ export function yRegion(y1, y2, width, label, options={}) {
|
|||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={}) {
|
export function datasetBar(x, yTop, width, color, label = '', index = 0, offset = 0, meta = {}) {
|
||||||
let [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);
|
let [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);
|
||||||
y -= offset;
|
y -= offset;
|
||||||
|
|
||||||
if(height === 0) {
|
if (height === 0) {
|
||||||
height = meta.minHeight;
|
height = meta.minHeight;
|
||||||
y -= meta.minHeight;
|
y -= meta.minHeight;
|
||||||
}
|
}
|
||||||
@ -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(height, true)) height = 0;
|
||||||
if (!isValidNumber(width, true)) width = 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', {
|
let rect = createSVG('rect', {
|
||||||
className: `bar mini`,
|
className: `bar mini`,
|
||||||
style: `fill: ${color}`,
|
style: `fill: ${color}`,
|
||||||
@ -539,14 +554,14 @@ export function datasetBar(x, yTop, width, color, label='', index=0, offset=0, m
|
|||||||
|
|
||||||
label += "";
|
label += "";
|
||||||
|
|
||||||
if(!label && !label.length) {
|
if (!label && !label.length) {
|
||||||
return rect;
|
return rect;
|
||||||
} else {
|
} else {
|
||||||
rect.setAttribute('y', 0);
|
rect.setAttribute('y', 0);
|
||||||
rect.setAttribute('x', 0);
|
rect.setAttribute('x', 0);
|
||||||
let text = createSVG('text', {
|
let text = createSVG('text', {
|
||||||
className: 'data-point-value',
|
className: 'data-point-value',
|
||||||
x: width/2,
|
x: width / 2,
|
||||||
y: 0,
|
y: 0,
|
||||||
dy: (FONT_SIZE / 2 * -1) + 'px',
|
dy: (FONT_SIZE / 2 * -1) + 'px',
|
||||||
'font-size': FONT_SIZE + 'px',
|
'font-size': FONT_SIZE + 'px',
|
||||||
@ -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', {
|
let dot = createSVG('circle', {
|
||||||
style: `fill: ${color}`,
|
style: `fill: ${color}; ${hideDotBorder ? `stroke: ${color}`: ''}`,
|
||||||
'data-point-index': index,
|
'data-point-index': index,
|
||||||
cx: x,
|
cx: x,
|
||||||
cy: y,
|
cy: y,
|
||||||
@ -576,7 +591,7 @@ export function datasetDot(x, y, radius, color, label='', index=0) {
|
|||||||
|
|
||||||
label += "";
|
label += "";
|
||||||
|
|
||||||
if(!label && !label.length) {
|
if (!label && !label.length) {
|
||||||
return dot;
|
return dot;
|
||||||
} else {
|
} else {
|
||||||
dot.setAttribute('cy', 0);
|
dot.setAttribute('cy', 0);
|
||||||
@ -603,7 +618,7 @@ export function datasetDot(x, y, radius, color, label='', index=0) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPaths(xList, yList, color, options={}, meta={}) {
|
export function getPaths(xList, yList, color, options = {}, meta = {}) {
|
||||||
let pointsList = yList.map((y, i) => (xList[i] + ',' + y));
|
let pointsList = yList.map((y, i) => (xList[i] + ',' + y));
|
||||||
let pointsStr = pointsList.join("L");
|
let pointsStr = pointsList.join("L");
|
||||||
|
|
||||||
@ -611,10 +626,10 @@ export function getPaths(xList, yList, color, options={}, meta={}) {
|
|||||||
if (options.spline)
|
if (options.spline)
|
||||||
pointsStr = getSplineCurvePointsStr(xList, yList);
|
pointsStr = getSplineCurvePointsStr(xList, yList);
|
||||||
|
|
||||||
let path = makePath("M"+pointsStr, 'line-graph-path', color);
|
let path = makePath("M" + pointsStr, 'line-graph-path', color);
|
||||||
|
|
||||||
// HeatLine
|
// HeatLine
|
||||||
if(options.heatline) {
|
if (options.heatline) {
|
||||||
let gradient_id = makeGradient(meta.svgDefs, color);
|
let gradient_id = makeGradient(meta.svgDefs, color);
|
||||||
path.style.stroke = `url(#${gradient_id})`;
|
path.style.stroke = `url(#${gradient_id})`;
|
||||||
}
|
}
|
||||||
@ -624,7 +639,7 @@ export function getPaths(xList, yList, color, options={}, meta={}) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Region
|
// Region
|
||||||
if(options.regionFill) {
|
if (options.regionFill) {
|
||||||
let gradient_id_region = makeGradient(meta.svgDefs, color, true);
|
let gradient_id_region = makeGradient(meta.svgDefs, color, true);
|
||||||
|
|
||||||
let pathStr = "M" + `${xList[0]},${meta.zeroLine}L` + pointsStr + `L${xList.slice(-1)[0]},${meta.zeroLine}`;
|
let pathStr = "M" + `${xList[0]},${meta.zeroLine}L` + pointsStr + `L${xList.slice(-1)[0]},${meta.zeroLine}`;
|
||||||
@ -637,7 +652,7 @@ export function getPaths(xList, yList, color, options={}, meta={}) {
|
|||||||
export let makeOverlay = {
|
export let makeOverlay = {
|
||||||
'bar': (unit) => {
|
'bar': (unit) => {
|
||||||
let transformValue;
|
let transformValue;
|
||||||
if(unit.nodeName !== 'rect') {
|
if (unit.nodeName !== 'rect') {
|
||||||
transformValue = unit.getAttribute('transform');
|
transformValue = unit.getAttribute('transform');
|
||||||
unit = unit.childNodes[0];
|
unit = unit.childNodes[0];
|
||||||
}
|
}
|
||||||
@ -645,7 +660,7 @@ export let makeOverlay = {
|
|||||||
overlay.style.fill = '#000000';
|
overlay.style.fill = '#000000';
|
||||||
overlay.style.opacity = '0.4';
|
overlay.style.opacity = '0.4';
|
||||||
|
|
||||||
if(transformValue) {
|
if (transformValue) {
|
||||||
overlay.setAttribute('transform', transformValue);
|
overlay.setAttribute('transform', transformValue);
|
||||||
}
|
}
|
||||||
return overlay;
|
return overlay;
|
||||||
@ -653,7 +668,7 @@ export let makeOverlay = {
|
|||||||
|
|
||||||
'dot': (unit) => {
|
'dot': (unit) => {
|
||||||
let transformValue;
|
let transformValue;
|
||||||
if(unit.nodeName !== 'circle') {
|
if (unit.nodeName !== 'circle') {
|
||||||
transformValue = unit.getAttribute('transform');
|
transformValue = unit.getAttribute('transform');
|
||||||
unit = unit.childNodes[0];
|
unit = unit.childNodes[0];
|
||||||
}
|
}
|
||||||
@ -664,7 +679,7 @@ export let makeOverlay = {
|
|||||||
overlay.setAttribute('fill', fill);
|
overlay.setAttribute('fill', fill);
|
||||||
overlay.style.opacity = '0.6';
|
overlay.style.opacity = '0.6';
|
||||||
|
|
||||||
if(transformValue) {
|
if (transformValue) {
|
||||||
overlay.setAttribute('transform', transformValue);
|
overlay.setAttribute('transform', transformValue);
|
||||||
}
|
}
|
||||||
return overlay;
|
return overlay;
|
||||||
@ -672,7 +687,7 @@ export let makeOverlay = {
|
|||||||
|
|
||||||
'heat_square': (unit) => {
|
'heat_square': (unit) => {
|
||||||
let transformValue;
|
let transformValue;
|
||||||
if(unit.nodeName !== 'circle') {
|
if (unit.nodeName !== 'circle') {
|
||||||
transformValue = unit.getAttribute('transform');
|
transformValue = unit.getAttribute('transform');
|
||||||
unit = unit.childNodes[0];
|
unit = unit.childNodes[0];
|
||||||
}
|
}
|
||||||
@ -683,7 +698,7 @@ export let makeOverlay = {
|
|||||||
overlay.setAttribute('fill', fill);
|
overlay.setAttribute('fill', fill);
|
||||||
overlay.style.opacity = '0.6';
|
overlay.style.opacity = '0.6';
|
||||||
|
|
||||||
if(transformValue) {
|
if (transformValue) {
|
||||||
overlay.setAttribute('transform', transformValue);
|
overlay.setAttribute('transform', transformValue);
|
||||||
}
|
}
|
||||||
return overlay;
|
return overlay;
|
||||||
@ -693,7 +708,7 @@ export let makeOverlay = {
|
|||||||
export let updateOverlay = {
|
export let updateOverlay = {
|
||||||
'bar': (unit, overlay) => {
|
'bar': (unit, overlay) => {
|
||||||
let transformValue;
|
let transformValue;
|
||||||
if(unit.nodeName !== 'rect') {
|
if (unit.nodeName !== 'rect') {
|
||||||
transformValue = unit.getAttribute('transform');
|
transformValue = unit.getAttribute('transform');
|
||||||
unit = unit.childNodes[0];
|
unit = unit.childNodes[0];
|
||||||
}
|
}
|
||||||
@ -704,14 +719,14 @@ export let updateOverlay = {
|
|||||||
overlay.setAttribute(attr.name, attr.nodeValue);
|
overlay.setAttribute(attr.name, attr.nodeValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(transformValue) {
|
if (transformValue) {
|
||||||
overlay.setAttribute('transform', transformValue);
|
overlay.setAttribute('transform', transformValue);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
'dot': (unit, overlay) => {
|
'dot': (unit, overlay) => {
|
||||||
let transformValue;
|
let transformValue;
|
||||||
if(unit.nodeName !== 'circle') {
|
if (unit.nodeName !== 'circle') {
|
||||||
transformValue = unit.getAttribute('transform');
|
transformValue = unit.getAttribute('transform');
|
||||||
unit = unit.childNodes[0];
|
unit = unit.childNodes[0];
|
||||||
}
|
}
|
||||||
@ -722,14 +737,14 @@ export let updateOverlay = {
|
|||||||
overlay.setAttribute(attr.name, attr.nodeValue);
|
overlay.setAttribute(attr.name, attr.nodeValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(transformValue) {
|
if (transformValue) {
|
||||||
overlay.setAttribute('transform', transformValue);
|
overlay.setAttribute('transform', transformValue);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
'heat_square': (unit, overlay) => {
|
'heat_square': (unit, overlay) => {
|
||||||
let transformValue;
|
let transformValue;
|
||||||
if(unit.nodeName !== 'circle') {
|
if (unit.nodeName !== 'circle') {
|
||||||
transformValue = unit.getAttribute('transform');
|
transformValue = unit.getAttribute('transform');
|
||||||
unit = unit.childNodes[0];
|
unit = unit.childNodes[0];
|
||||||
}
|
}
|
||||||
@ -740,7 +755,7 @@ export let updateOverlay = {
|
|||||||
overlay.setAttribute(attr.name, attr.nodeValue);
|
overlay.setAttribute(attr.name, attr.nodeValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(transformValue) {
|
if (transformValue) {
|
||||||
overlay.setAttribute('transform', transformValue);
|
overlay.setAttribute('transform', transformValue);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -4,13 +4,13 @@ import { CSSTEXT } from '../../css/chartsCss';
|
|||||||
export function downloadFile(filename, data) {
|
export function downloadFile(filename, data) {
|
||||||
var a = document.createElement('a');
|
var a = document.createElement('a');
|
||||||
a.style = "display: none";
|
a.style = "display: none";
|
||||||
var blob = new Blob(data, {type: "image/svg+xml; charset=utf-8"});
|
var blob = new Blob(data, { type: "image/svg+xml; charset=utf-8" });
|
||||||
var url = window.URL.createObjectURL(blob);
|
var url = window.URL.createObjectURL(blob);
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = filename;
|
a.download = filename;
|
||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
a.click();
|
a.click();
|
||||||
setTimeout(function(){
|
setTimeout(function () {
|
||||||
document.body.removeChild(a);
|
document.body.removeChild(a);
|
||||||
window.URL.revokeObjectURL(url);
|
window.URL.revokeObjectURL(url);
|
||||||
}, 300);
|
}, 300);
|
||||||
|
|||||||
@ -115,3 +115,29 @@ export function round(d) {
|
|||||||
// https://www.jacklmoore.com/notes/rounding-in-javascript/
|
// https://www.jacklmoore.com/notes/rounding-in-javascript/
|
||||||
return Number(Math.round(d + 'e4') + 'e-4');
|
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;
|
||||||
|
}
|
||||||
@ -5,25 +5,25 @@ function normalize(x) {
|
|||||||
// Returns normalized number and exponent
|
// Returns normalized number and exponent
|
||||||
// https://stackoverflow.com/q/9383593/6495043
|
// https://stackoverflow.com/q/9383593/6495043
|
||||||
|
|
||||||
if(x===0) {
|
if (x === 0) {
|
||||||
return [0, 0];
|
return [0, 0];
|
||||||
}
|
}
|
||||||
if(isNaN(x)) {
|
if (isNaN(x)) {
|
||||||
return {mantissa: -6755399441055744, exponent: 972};
|
return { mantissa: -6755399441055744, exponent: 972 };
|
||||||
}
|
}
|
||||||
var sig = x > 0 ? 1 : -1;
|
var sig = x > 0 ? 1 : -1;
|
||||||
if(!isFinite(x)) {
|
if (!isFinite(x)) {
|
||||||
return {mantissa: sig * 4503599627370496, exponent: 972};
|
return { mantissa: sig * 4503599627370496, exponent: 972 };
|
||||||
}
|
}
|
||||||
|
|
||||||
x = Math.abs(x);
|
x = Math.abs(x);
|
||||||
var exp = Math.floor(Math.log10(x));
|
var exp = Math.floor(Math.log10(x));
|
||||||
var man = x/Math.pow(10, exp);
|
var man = x / Math.pow(10, exp);
|
||||||
|
|
||||||
return [sig * man, exp];
|
return [sig * man, exp];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getChartRangeIntervals(max, min=0) {
|
function getChartRangeIntervals(max, min = 0) {
|
||||||
let upperBound = Math.ceil(max);
|
let upperBound = Math.ceil(max);
|
||||||
let lowerBound = Math.floor(min);
|
let lowerBound = Math.floor(min);
|
||||||
let range = upperBound - lowerBound;
|
let range = upperBound - lowerBound;
|
||||||
@ -32,38 +32,38 @@ function getChartRangeIntervals(max, min=0) {
|
|||||||
let partSize = 1;
|
let partSize = 1;
|
||||||
|
|
||||||
// To avoid too many partitions
|
// To avoid too many partitions
|
||||||
if(range > 5) {
|
if (range > 5) {
|
||||||
if(range % 2 !== 0) {
|
if (range % 2 !== 0) {
|
||||||
upperBound++;
|
upperBound++;
|
||||||
// Recalc range
|
// Recalc range
|
||||||
range = upperBound - lowerBound;
|
range = upperBound - lowerBound;
|
||||||
}
|
}
|
||||||
noOfParts = range/2;
|
noOfParts = range / 2;
|
||||||
partSize = 2;
|
partSize = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case: 1 and 2
|
// Special case: 1 and 2
|
||||||
if(range <= 2) {
|
if (range <= 2) {
|
||||||
noOfParts = 4;
|
noOfParts = 4;
|
||||||
partSize = range/noOfParts;
|
partSize = range / noOfParts;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case: 0
|
// Special case: 0
|
||||||
if(range === 0) {
|
if (range === 0) {
|
||||||
noOfParts = 5;
|
noOfParts = 5;
|
||||||
partSize = 1;
|
partSize = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let intervals = [];
|
let intervals = [];
|
||||||
for(var i = 0; i <= noOfParts; i++){
|
for (var i = 0; i <= noOfParts; i++) {
|
||||||
intervals.push(lowerBound + partSize * i);
|
intervals.push(lowerBound + partSize * i);
|
||||||
}
|
}
|
||||||
return intervals;
|
return intervals;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getChartIntervals(maxValue, minValue=0) {
|
function getChartIntervals(maxValue, minValue = 0) {
|
||||||
let [normalMaxValue, exponent] = normalize(maxValue);
|
let [normalMaxValue, exponent] = normalize(maxValue);
|
||||||
let normalMinValue = minValue ? minValue/Math.pow(10, exponent): 0;
|
let normalMinValue = minValue ? minValue / Math.pow(10, exponent) : 0;
|
||||||
|
|
||||||
// Allow only 7 significant digits
|
// Allow only 7 significant digits
|
||||||
normalMaxValue = normalMaxValue.toFixed(6);
|
normalMaxValue = normalMaxValue.toFixed(6);
|
||||||
@ -73,7 +73,7 @@ function getChartIntervals(maxValue, minValue=0) {
|
|||||||
return intervals;
|
return intervals;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calcChartIntervals(values, withMinimum=false) {
|
export function calcChartIntervals(values, withMinimum = false, range = {}) {
|
||||||
//*** Where the magic happens ***
|
//*** Where the magic happens ***
|
||||||
|
|
||||||
// Calculates best-fit y intervals from given values
|
// Calculates best-fit y intervals from given values
|
||||||
@ -82,6 +82,14 @@ export function calcChartIntervals(values, withMinimum=false) {
|
|||||||
let maxValue = Math.max(...values);
|
let maxValue = Math.max(...values);
|
||||||
let minValue = Math.min(...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
|
// Exponent to be used for pretty print
|
||||||
let exponent = 0, intervals = []; // eslint-disable-line no-unused-vars
|
let exponent = 0, intervals = []; // eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
@ -92,7 +100,7 @@ export function calcChartIntervals(values, withMinimum=false) {
|
|||||||
|
|
||||||
// Then unshift the negative values
|
// Then unshift the negative values
|
||||||
let value = 0;
|
let value = 0;
|
||||||
for(var i = 1; value < absMinValue; i++) {
|
for (var i = 1; value < absMinValue; i++) {
|
||||||
value += intervalSize;
|
value += intervalSize;
|
||||||
intervals.unshift((-1) * value);
|
intervals.unshift((-1) * value);
|
||||||
}
|
}
|
||||||
@ -101,9 +109,9 @@ export function calcChartIntervals(values, withMinimum=false) {
|
|||||||
|
|
||||||
// CASE I: Both non-negative
|
// CASE I: Both non-negative
|
||||||
|
|
||||||
if(maxValue >= 0 && minValue >= 0) {
|
if (maxValue >= 0 && minValue >= 0) {
|
||||||
exponent = normalize(maxValue)[1];
|
exponent = normalize(maxValue)[1];
|
||||||
if(!withMinimum) {
|
if (!withMinimum) {
|
||||||
intervals = getChartIntervals(maxValue);
|
intervals = getChartIntervals(maxValue);
|
||||||
} else {
|
} else {
|
||||||
intervals = getChartIntervals(maxValue, minValue);
|
intervals = getChartIntervals(maxValue, minValue);
|
||||||
@ -112,7 +120,7 @@ export function calcChartIntervals(values, withMinimum=false) {
|
|||||||
|
|
||||||
// CASE II: Only minValue negative
|
// CASE II: Only minValue negative
|
||||||
|
|
||||||
else if(maxValue > 0 && minValue < 0) {
|
else if (maxValue > 0 && minValue < 0) {
|
||||||
// `withMinimum` irrelevant in this case,
|
// `withMinimum` irrelevant in this case,
|
||||||
// We'll be handling both sides of zero separately
|
// We'll be handling both sides of zero separately
|
||||||
// (both starting from zero)
|
// (both starting from zero)
|
||||||
@ -121,7 +129,7 @@ export function calcChartIntervals(values, withMinimum=false) {
|
|||||||
|
|
||||||
let absMinValue = Math.abs(minValue);
|
let absMinValue = Math.abs(minValue);
|
||||||
|
|
||||||
if(maxValue >= absMinValue) {
|
if (maxValue >= absMinValue) {
|
||||||
exponent = normalize(maxValue)[1];
|
exponent = normalize(maxValue)[1];
|
||||||
intervals = getPositiveFirstIntervals(maxValue, absMinValue);
|
intervals = getPositiveFirstIntervals(maxValue, absMinValue);
|
||||||
} else {
|
} else {
|
||||||
@ -135,7 +143,7 @@ export function calcChartIntervals(values, withMinimum=false) {
|
|||||||
|
|
||||||
// CASE III: Both non-positive
|
// CASE III: Both non-positive
|
||||||
|
|
||||||
else if(maxValue <= 0 && minValue <= 0) {
|
else if (maxValue <= 0 && minValue <= 0) {
|
||||||
// Mirrored Case I:
|
// Mirrored Case I:
|
||||||
// Work with positives, then reverse the sign and array
|
// Work with positives, then reverse the sign and array
|
||||||
|
|
||||||
@ -143,7 +151,7 @@ export function calcChartIntervals(values, withMinimum=false) {
|
|||||||
let pseudoMinValue = Math.abs(maxValue);
|
let pseudoMinValue = Math.abs(maxValue);
|
||||||
|
|
||||||
exponent = normalize(pseudoMaxValue)[1];
|
exponent = normalize(pseudoMaxValue)[1];
|
||||||
if(!withMinimum) {
|
if (!withMinimum) {
|
||||||
intervals = getChartIntervals(pseudoMaxValue);
|
intervals = getChartIntervals(pseudoMaxValue);
|
||||||
} else {
|
} else {
|
||||||
intervals = getChartIntervals(pseudoMaxValue, pseudoMinValue);
|
intervals = getChartIntervals(pseudoMaxValue, pseudoMinValue);
|
||||||
@ -158,11 +166,11 @@ export function calcChartIntervals(values, withMinimum=false) {
|
|||||||
export function getZeroIndex(yPts) {
|
export function getZeroIndex(yPts) {
|
||||||
let zeroIndex;
|
let zeroIndex;
|
||||||
let interval = getIntervalSize(yPts);
|
let interval = getIntervalSize(yPts);
|
||||||
if(yPts.indexOf(0) >= 0) {
|
if (yPts.indexOf(0) >= 0) {
|
||||||
// the range has a given zero
|
// the range has a given zero
|
||||||
// zero-line on the chart
|
// zero-line on the chart
|
||||||
zeroIndex = yPts.indexOf(0);
|
zeroIndex = yPts.indexOf(0);
|
||||||
} else if(yPts[0] > 0) {
|
} else if (yPts[0] > 0) {
|
||||||
// Minimum value is positive
|
// Minimum value is positive
|
||||||
// zero-line is off the chart: below
|
// zero-line is off the chart: below
|
||||||
let min = yPts[0];
|
let min = yPts[0];
|
||||||
@ -181,7 +189,7 @@ export function getRealIntervals(max, noOfIntervals, min = 0, asc = 1) {
|
|||||||
let part = range * 1.0 / noOfIntervals;
|
let part = range * 1.0 / noOfIntervals;
|
||||||
let intervals = [];
|
let intervals = [];
|
||||||
|
|
||||||
for(var i = 0; i <= noOfIntervals; i++) {
|
for (var i = 0; i <= noOfIntervals; i++) {
|
||||||
intervals.push(min + part * i);
|
intervals.push(min + part * i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +201,7 @@ export function getIntervalSize(orderedArray) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getValueRange(orderedArray) {
|
export function getValueRange(orderedArray) {
|
||||||
return orderedArray[orderedArray.length-1] - orderedArray[0];
|
return orderedArray[orderedArray.length - 1] - orderedArray[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function scale(val, yAxis) {
|
export function scale(val, yAxis) {
|
||||||
@ -210,7 +218,7 @@ export function isInRange2D(coord, minCoord, maxCoord) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getClosestInArray(goal, arr, index = false) {
|
export function getClosestInArray(goal, arr, index = false) {
|
||||||
let closest = arr.reduce(function(prev, curr) {
|
let closest = arr.reduce(function (prev, curr) {
|
||||||
return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
|
return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -226,7 +234,7 @@ export function calcDistribution(values, distributionSize) {
|
|||||||
let distributionStep = 1 / (distributionSize - 1);
|
let distributionStep = 1 / (distributionSize - 1);
|
||||||
let distribution = [];
|
let distribution = [];
|
||||||
|
|
||||||
for(var i = 0; i < distributionSize; i++) {
|
for (var i = 0; i < distributionSize; i++) {
|
||||||
let checkpoint = dataMaxValue * (distributionStep * i);
|
let checkpoint = dataMaxValue * (distributionStep * i);
|
||||||
distribution.push(checkpoint);
|
distribution.push(checkpoint);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user