Comparar commits
388 Commits
2.0.0-beta1
...
v2.0.0
| Autor | SHA1 | Data | |
|---|---|---|---|
| ebb8ca233d | |||
| 6ba2efe3a4 | |||
| d5fd737058 | |||
| 93a2e9fc55 | |||
| a7fede4f46 | |||
| 488826ace3 | |||
| 9ee70d6d48 | |||
| 95bd0a54dd | |||
| 2b361e1fee | |||
| 7875b0c68d | |||
| 5c1f242785 | |||
| 3350d5fb13 | |||
| b15b316e85 | |||
| b6d7ceba1c | |||
| be6b254d50 | |||
| 0b56ea452f | |||
| 37da19df78 | |||
| d8347039cf | |||
| f39fa53a7e | |||
| cefaef4707 | |||
| d4b6be5afe | |||
| 798f643fab | |||
| 60a429f5cb | |||
| f6cb3cf0ef | |||
| f3926198d9 | |||
| 79f38b49d8 | |||
| 9a0553a1b5 | |||
| 74fd697351 | |||
| e090691ef7 | |||
| 67bd2dae6d | |||
| 998c6939bf | |||
| 2ab86f5557 | |||
| 21a33f0e41 | |||
| 1157b19626 | |||
| 04f1e57459 | |||
| 1292558f7c | |||
| f09f32f59e | |||
| bf724abe8b | |||
| fffbc27db3 | |||
| e511fc2a1c | |||
| f64324e2a8 | |||
| 4fec7dfdbb | |||
| f5bb8e25d5 | |||
| 81e1448836 | |||
| 56611f550d | |||
| 72b0ef2df0 | |||
| 1fbbdd2d38 | |||
| 136efeaf4d | |||
| 5d2444a5ee | |||
| 9bcc3ca34c | |||
| a16093e51c | |||
| a87ebe0841 | |||
| c3f765857e | |||
| c99cf97ff6 | |||
| 9410eaabbf | |||
| fc46e25f23 | |||
| b69b388b31 | |||
| d5f837843e | |||
| a25c2c740c | |||
| 3d6b47b0d5 | |||
| 156f8f0be8 | |||
| 237d5dca5a | |||
| 185ea3939d | |||
| aba16b402f | |||
| 77971e6b99 | |||
| 8d5b3809f6 | |||
| 33a1fa928d | |||
| 04fe614800 | |||
| 2977c8eb9c | |||
| a4fa956ab4 | |||
| 13fc892114 | |||
| 94cd6a480c | |||
| 595464fc7e | |||
| 5602826aeb | |||
| 0985e6d564 | |||
| 680fa8a68e | |||
| e7233c2f61 | |||
| 72f59264e9 | |||
| 2513d5dd48 | |||
| 14fd5de460 | |||
| 0480f2e18d | |||
| f23b640c81 | |||
| 9d210d8a8c | |||
| c7845d124d | |||
| 428567d8cf | |||
| aa604af05b | |||
| 194c11c3d7 | |||
| cd52936473 | |||
| 48cb104f14 | |||
| a7b16464bf | |||
| 1f8709f88a | |||
| 87633f61e9 | |||
| dae599e16d | |||
| 4729b05cc1 | |||
| 521236bd92 | |||
| 431f930c15 | |||
| 04e6926961 | |||
| 1cc9184c47 | |||
| 96315dd3c9 | |||
| 5fe1914e17 | |||
| b812bcc8a5 | |||
| 6ad533ce2b | |||
| 0f6e329aaa | |||
| cfd3ebb77e | |||
| f5a2e394c8 | |||
| 1bebda87f6 | |||
| 86b9139617 | |||
| f572125820 | |||
| 50d0c98030 | |||
| ee81d4a804 | |||
| ac5be9bde2 | |||
| d31db87115 | |||
| c3149a9400 | |||
| 4c35bba639 | |||
| 2672efad63 | |||
| 309ab1f477 | |||
| 37b3fb5d6c | |||
| e589734cbb | |||
| 01b88f19df | |||
| 756208413b | |||
| a79d365b49 | |||
| 1dc943ddb4 | |||
| db2073139b | |||
| 172839af2c | |||
| 0732793b7e | |||
| 41f2b5707a | |||
| 58fcb37760 | |||
| d366f2b4d3 | |||
| 766b748a58 | |||
| 38b2925e6c | |||
| 489f7ce6f7 | |||
| 3226dfa495 | |||
| a84f9d9177 | |||
| 96551c20db | |||
| f6951816a0 | |||
| d9af94a715 | |||
| eb2b04a9ff | |||
| 2f5e0924ef | |||
| c5020c3e5a | |||
| eb01a0d6f8 | |||
| 999125c521 | |||
| 813d18bd78 | |||
| 007d029837 | |||
| f2780bb825 | |||
| 09783be8a9 | |||
| a3dea119e8 | |||
| 55f9b68b0c | |||
| e9c18f603d | |||
| eb7241cbc9 | |||
| 84ed07a84e | |||
| 7235d829ec | |||
| ee16c1edbc | |||
| 9cf31da4c9 | |||
| e931276003 | |||
| 61ca178e2b | |||
| ada4c8eca3 | |||
| 92bc1a04cf | |||
| 1692b977cd | |||
| 098b05f1b2 | |||
| 85de9fbe9c | |||
| 80ede9b9bb | |||
| 09721407d2 | |||
| 9a20381af4 | |||
| df218ead82 | |||
| ba6afa7257 | |||
| e7df265c7a | |||
| 73300e91c4 | |||
| dfaf786e1a | |||
| 25e787cbf0 | |||
| d16f4fc5ce | |||
| aafe21db7e | |||
| 9ed88599d2 | |||
| 0e8babf1d7 | |||
| 16dc9e6167 | |||
| 172c088c6b | |||
| f75116a91e | |||
| 1afe9f1a6e | |||
| 212b6d3992 | |||
| bfd6f5f78e | |||
| 0890c809aa | |||
| d0a0d57fe2 | |||
| 6aa2933ec5 | |||
| d0b67c603b | |||
| 68ab74a46d | |||
| 0ed39c9fd7 | |||
| c312835eb1 | |||
| 888379ec5c | |||
| 59e3ccb42a | |||
| 76ef7de646 | |||
| cfb06ed34d | |||
| c8ea3af32c | |||
| 3c614a5dfe | |||
| 2d4e2f9889 | |||
| 62988e9768 | |||
| b282a01ab6 | |||
| 8e681a606d | |||
| 33303d8d8a | |||
| 00913be944 | |||
| 1de0435feb | |||
| 2db334dbf6 | |||
| 655c1152eb | |||
| f6b18a5998 | |||
| c42cb148da | |||
| fa7baa1627 | |||
| 19613f531c | |||
| 4f6e86640f | |||
| 25d6c2f064 | |||
| b756507625 | |||
| 24e4a924c4 | |||
| 7735371f45 | |||
| 977d45a3e0 | |||
| 307d02bf48 | |||
| 88fc6ecc5c | |||
| ff94a54891 | |||
| 0ed27d4474 | |||
| 5070059ac1 | |||
| 956b1dd1e0 | |||
| 8c68f78ec3 | |||
| 1202c03535 | |||
| 6b28790223 | |||
| 46861c9f0b | |||
| d49b5b82c7 | |||
| 0e393a3122 | |||
| 8cfa60c04d | |||
| 46ca099265 | |||
| 203bbcec6c | |||
| 6f0d32fa8c | |||
| fe57c8728e | |||
| ebf695734c | |||
| f00517643e | |||
| 84a6eb4a3b | |||
| 6478f93ded | |||
| 1967bef9f6 | |||
| 310eada01a | |||
| 1e91cf816b | |||
| cd29ede572 | |||
| ae19cfd35f | |||
| 8dca052a16 | |||
| 579e322809 | |||
| 8487375730 | |||
| 2caff1f4fa | |||
| 4ac60956db | |||
| 97cc714c94 | |||
| a9a003c4c4 | |||
| f7c6ca544b | |||
| ac9fe08068 | |||
| d9cc1219ce | |||
| 824f5880fb | |||
| cea6934258 | |||
| d6a27d8eb3 | |||
| 081cf7ba07 | |||
| 0c534e1eb8 | |||
| 754268890b | |||
| f2899934db | |||
| 5a5d698b11 | |||
| e2206ab269 | |||
| ff11975648 | |||
| 421e610150 | |||
| 94a8c9a27f | |||
| a0c359ee80 | |||
| 31721a353c | |||
| bbc6f5aa5f | |||
| 968a11a631 | |||
| a1940caf91 | |||
| d9e1b2250e | |||
| ad67d1ecf8 | |||
| 2c178a5670 | |||
| f170fd1b8d | |||
| a423542775 | |||
| d5727d7bc0 | |||
| 1221d8311a | |||
| eb61f5c3fc | |||
| fd668086b2 | |||
| 8e7162ca91 | |||
| 923378e2af | |||
| 0437968a4e | |||
| d134394a1d | |||
| cd02434943 | |||
| c078ae15f0 | |||
| 86ca455cb6 | |||
| 477fc72693 | |||
| d7643bf865 | |||
| d26ab24e3c | |||
| fc3a3aedaf | |||
| 3577d959d0 | |||
| 63b14dc2a9 | |||
| 888a8dd797 | |||
| 7363c6fcbe | |||
| dec4a5f57a | |||
| d163122536 | |||
| bafd36b5ec | |||
| ae643d3d76 | |||
| 5f4e8a4c13 | |||
| 29770d3e67 | |||
| 421e294e2c | |||
| 23b2d991f7 | |||
| d295e49907 | |||
| d9363d637a | |||
| f7d3ea3841 | |||
| 283f1d7387 | |||
| c8d3831152 | |||
| 9aee15fe6c | |||
| 8efa577ef5 | |||
| 3ccf3fd249 | |||
| cddfba1676 | |||
| 274897fc24 | |||
| f51d7753bd | |||
| 3e3912973c | |||
| 6d490fbbbb | |||
| 968db4e783 | |||
| 1170ab5481 | |||
| c2ee14dec9 | |||
| 139cbe1c64 | |||
| 1854ea086c | |||
| 716e303230 | |||
| 47d04ced8f | |||
| 95332e39f5 | |||
| ae3025a2e1 | |||
| 39e5daaca8 | |||
| 4add69432f | |||
| 7825ee5ef2 | |||
| 4eed79ee52 | |||
| 571120d650 | |||
| 7999aab26a | |||
| d689e0fc47 | |||
| 819f865723 | |||
| 4f8f182d21 | |||
| a2e1a97382 | |||
| 60920cd75a | |||
| 59b7927994 | |||
| 8befbbe8f0 | |||
| b0f69a1092 | |||
| 3b750e7f27 | |||
| ffa2870b56 | |||
| 1cb7dde0d5 | |||
| 20b9395585 | |||
| 73e9ff44fe | |||
| bffbaf6b37 | |||
| eba2fce923 | |||
| 792ee587ae | |||
| eaf183352c | |||
| 7ab2a5ed9a | |||
| 28fc6841f3 | |||
| 5df23df291 | |||
| 52ae1f7d3c | |||
| 0c247dde28 | |||
| 784fa78267 | |||
| d21b3c6d7e | |||
| a1e35ade49 | |||
| 89da20354c | |||
| 2f1006c6de | |||
| 744e1429b9 | |||
| 59fb1696a8 | |||
| 38afefde25 | |||
| d905f19355 | |||
| d8704ee37d | |||
| 0b260d57cc | |||
| dcc06eb3bb | |||
| 0a92cf1b40 | |||
| 62bc4e42ec | |||
| 95a172df06 | |||
| 40c8289ce8 | |||
| b388a1e873 | |||
| 14c2cf56d1 | |||
| 164671ffeb | |||
| 05043d4771 | |||
| 25f061f340 | |||
| bf277473c6 | |||
| 6b3fd19fa9 | |||
| 37abe74d43 | |||
| ea15aaaec2 | |||
| 10d056a4d1 | |||
| 0d1f63e601 | |||
| afc6d9094b | |||
| 60c1609ba9 | |||
| 0a17edd1ae | |||
| 2efb974189 | |||
| 7b719e6432 | |||
| 2a9b3e5221 | |||
| 29002b2efb | |||
| e8f80ca211 | |||
| a1fb98c79f | |||
| 872b7b6161 | |||
| ab2c3ce4e9 | |||
| 2bc386ee81 | |||
| 15ff3f9edc | |||
| 9ab505caec | |||
| a91dba3e8a |
@@ -0,0 +1,19 @@
|
||||
---
|
||||
engines:
|
||||
duplication:
|
||||
enabled: true
|
||||
config:
|
||||
languages:
|
||||
- javascript
|
||||
eslint:
|
||||
enabled: true
|
||||
fixme:
|
||||
enabled: true
|
||||
ratings:
|
||||
paths:
|
||||
- "**.js"
|
||||
exclude_paths:
|
||||
- dist/
|
||||
- node_modules/
|
||||
- test/
|
||||
- coverage/
|
||||
@@ -0,0 +1 @@
|
||||
**/*{.,-}min.js
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
ecmaFeatures:
|
||||
modules: true
|
||||
jsx: true
|
||||
|
||||
env:
|
||||
amd: true
|
||||
browser: true
|
||||
es6: true
|
||||
jquery: true
|
||||
node: true
|
||||
|
||||
# http://eslint.org/docs/rules/
|
||||
rules:
|
||||
# Possible Errors
|
||||
comma-dangle: [2, never]
|
||||
no-cond-assign: 2
|
||||
no-console: 0
|
||||
no-constant-condition: 2
|
||||
no-control-regex: 2
|
||||
no-debugger: 2
|
||||
no-dupe-args: 2
|
||||
no-dupe-keys: 2
|
||||
no-duplicate-case: 2
|
||||
no-empty: 2
|
||||
no-empty-character-class: 2
|
||||
no-ex-assign: 2
|
||||
no-extra-boolean-cast: 2
|
||||
no-extra-parens: 0
|
||||
no-extra-semi: 2
|
||||
no-func-assign: 2
|
||||
no-inner-declarations: [2, functions]
|
||||
no-invalid-regexp: 2
|
||||
no-irregular-whitespace: 2
|
||||
no-negated-in-lhs: 2
|
||||
no-obj-calls: 2
|
||||
no-regex-spaces: 2
|
||||
no-sparse-arrays: 2
|
||||
no-unexpected-multiline: 2
|
||||
no-unreachable: 2
|
||||
use-isnan: 2
|
||||
valid-jsdoc: 0
|
||||
valid-typeof: 2
|
||||
|
||||
# Best Practices
|
||||
accessor-pairs: 2
|
||||
block-scoped-var: 0
|
||||
complexity: [2, 6]
|
||||
consistent-return: 0
|
||||
curly: 0
|
||||
default-case: 0
|
||||
dot-location: 0
|
||||
dot-notation: 0
|
||||
eqeqeq: 2
|
||||
guard-for-in: 2
|
||||
no-alert: 2
|
||||
no-caller: 2
|
||||
no-case-declarations: 2
|
||||
no-div-regex: 2
|
||||
no-else-return: 0
|
||||
no-empty-label: 2
|
||||
no-empty-pattern: 2
|
||||
no-eq-null: 2
|
||||
no-eval: 2
|
||||
no-extend-native: 2
|
||||
no-extra-bind: 2
|
||||
no-fallthrough: 2
|
||||
no-floating-decimal: 0
|
||||
no-implicit-coercion: 0
|
||||
no-implied-eval: 2
|
||||
no-invalid-this: 0
|
||||
no-iterator: 2
|
||||
no-labels: 0
|
||||
no-lone-blocks: 2
|
||||
no-loop-func: 2
|
||||
no-magic-number: 0
|
||||
no-multi-spaces: 0
|
||||
no-multi-str: 0
|
||||
no-native-reassign: 2
|
||||
no-new-func: 2
|
||||
no-new-wrappers: 2
|
||||
no-new: 2
|
||||
no-octal-escape: 2
|
||||
no-octal: 2
|
||||
no-proto: 2
|
||||
no-redeclare: 2
|
||||
no-return-assign: 2
|
||||
no-script-url: 2
|
||||
no-self-compare: 2
|
||||
no-sequences: 0
|
||||
no-throw-literal: 0
|
||||
no-unused-expressions: 2
|
||||
no-useless-call: 2
|
||||
no-useless-concat: 2
|
||||
no-void: 2
|
||||
no-warning-comments: 0
|
||||
no-with: 2
|
||||
radix: 2
|
||||
vars-on-top: 0
|
||||
wrap-iife: 2
|
||||
yoda: 0
|
||||
|
||||
# Strict
|
||||
strict: 0
|
||||
|
||||
# Variables
|
||||
init-declarations: 0
|
||||
no-catch-shadow: 2
|
||||
no-delete-var: 2
|
||||
no-label-var: 2
|
||||
no-shadow-restricted-names: 2
|
||||
no-shadow: 0
|
||||
no-undef-init: 2
|
||||
no-undef: 0
|
||||
no-undefined: 0
|
||||
no-unused-vars: 0
|
||||
no-use-before-define: 0
|
||||
|
||||
# Node.js and CommonJS
|
||||
callback-return: 2
|
||||
global-require: 2
|
||||
handle-callback-err: 2
|
||||
no-mixed-requires: 0
|
||||
no-new-require: 0
|
||||
no-path-concat: 2
|
||||
no-process-exit: 2
|
||||
no-restricted-modules: 0
|
||||
no-sync: 0
|
||||
|
||||
# Stylistic Issues
|
||||
array-bracket-spacing: 0
|
||||
block-spacing: 0
|
||||
brace-style: 0
|
||||
camelcase: 0
|
||||
comma-spacing: 0
|
||||
comma-style: 0
|
||||
computed-property-spacing: 0
|
||||
consistent-this: 0
|
||||
eol-last: 0
|
||||
func-names: 0
|
||||
func-style: 0
|
||||
id-length: 0
|
||||
id-match: 0
|
||||
indent: 0
|
||||
jsx-quotes: 0
|
||||
key-spacing: 0
|
||||
linebreak-style: 0
|
||||
lines-around-comment: 0
|
||||
max-depth: 0
|
||||
max-len: 0
|
||||
max-nested-callbacks: 0
|
||||
max-params: 0
|
||||
max-statements: [2, 30]
|
||||
new-cap: 0
|
||||
new-parens: 0
|
||||
newline-after-var: 0
|
||||
no-array-constructor: 0
|
||||
no-bitwise: 0
|
||||
no-continue: 0
|
||||
no-inline-comments: 0
|
||||
no-lonely-if: 0
|
||||
no-mixed-spaces-and-tabs: 0
|
||||
no-multiple-empty-lines: 0
|
||||
no-negated-condition: 0
|
||||
no-nested-ternary: 0
|
||||
no-new-object: 0
|
||||
no-plusplus: 0
|
||||
no-restricted-syntax: 0
|
||||
no-spaced-func: 0
|
||||
no-ternary: 0
|
||||
no-trailing-spaces: 0
|
||||
no-underscore-dangle: 0
|
||||
no-unneeded-ternary: 0
|
||||
object-curly-spacing: 0
|
||||
one-var: 0
|
||||
operator-assignment: 0
|
||||
operator-linebreak: 0
|
||||
padded-blocks: 0
|
||||
quote-props: 0
|
||||
quotes: 0
|
||||
require-jsdoc: 0
|
||||
semi-spacing: 0
|
||||
semi: 0
|
||||
sort-vars: 0
|
||||
space-after-keywords: 0
|
||||
space-before-blocks: 0
|
||||
space-before-function-paren: 0
|
||||
space-before-keywords: 0
|
||||
space-in-parens: 0
|
||||
space-infix-ops: 0
|
||||
space-return-throw-case: 0
|
||||
space-unary-ops: 0
|
||||
spaced-comment: 0
|
||||
wrap-regex: 0
|
||||
|
||||
# ECMAScript 6
|
||||
arrow-body-style: 0
|
||||
arrow-parens: 0
|
||||
arrow-spacing: 0
|
||||
constructor-super: 0
|
||||
generator-star-spacing: 0
|
||||
no-arrow-condition: 0
|
||||
no-class-assign: 0
|
||||
no-const-assign: 0
|
||||
no-dupe-class-members: 0
|
||||
no-this-before-super: 0
|
||||
no-var: 0
|
||||
object-shorthand: 0
|
||||
prefer-arrow-callback: 0
|
||||
prefer-const: 0
|
||||
prefer-reflect: 0
|
||||
prefer-spread: 0
|
||||
prefer-template: 0
|
||||
require-yield: 0
|
||||
@@ -9,3 +9,5 @@ docs/index.md
|
||||
bower_components/
|
||||
|
||||
coverage/*
|
||||
|
||||
nbproject/*
|
||||
|
||||
+13
-4
@@ -1,20 +1,29 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.11"
|
||||
- "0.10"
|
||||
- "5.6"
|
||||
- "4.3"
|
||||
|
||||
before_install:
|
||||
- "export CHROME_BIN=chromium-browser"
|
||||
- "export DISPLAY=:99.0"
|
||||
- "sh -e /etc/init.d/xvfb start"
|
||||
- "sudo apt-get update"
|
||||
- "sudo apt-get install -y libappindicator1 fonts-liberation"
|
||||
- "wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb"
|
||||
- "sudo dpkg -i google-chrome*.deb"
|
||||
- "export CHROME_BIN=/usr/bin/google-chrome"
|
||||
|
||||
before_script:
|
||||
- npm install
|
||||
|
||||
script:
|
||||
- gulp test
|
||||
- gulp coverage
|
||||
- cat ./coverage/lcov.info | ./node_modules/.bin/coveralls
|
||||
|
||||
notifications:
|
||||
slack: chartjs:pcfCZR6ugg5TEcaLtmIfQYuA
|
||||
|
||||
sudo: false
|
||||
sudo: required
|
||||
|
||||
addons:
|
||||
firefox: latest
|
||||
@@ -30,6 +30,12 @@ Guidlines for reporting bugs:
|
||||
Please provide any additional details associated with the bug, if it's browser or screen density specific, or only happens with a certain configuration or data.
|
||||
|
||||
|
||||
Local development
|
||||
-----------------
|
||||
|
||||
Run `npm install` to install all the libraries, then run `gulp dev --test` to build and run tests as you make changes.
|
||||
|
||||
|
||||
Pull requests
|
||||
-------------
|
||||
|
||||
|
||||
externo
-6590
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
-40
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+3
-2
@@ -1,13 +1,14 @@
|
||||
# Chart.js
|
||||
|
||||
[](https://travis-ci.org/nnnick/Chart.js) [](https://codeclimate.com/github/nnnick/Chart.js)
|
||||
[](https://travis-ci.org/nnnick/Chart.js) [](https://codeclimate.com/github/nnnick/Chart.js)[](https://coveralls.io/r/nnnick/Chart.js?branch=v2.0-dev)
|
||||
|
||||
|
||||
|
||||
*Simple HTML5 Charts using the canvas element* [chartjs.org](http://www.chartjs.org)
|
||||
|
||||
## v2.0 Beta
|
||||
|
||||
Current Release: [2.0.0-beta](https://github.com/nnnick/Chart.js/releases/tag/2.0.0-beta)
|
||||
Current Release: [2.0.0-beta2](https://github.com/nnnick/Chart.js/releases/tag/2.0.0-beta2)
|
||||
|
||||
The next generation and release of Chart.js has been well under way this year and we are very close to releasing some amazing new features including, but not limited to:
|
||||
- Rewritten, optimized, and unit-tested
|
||||
|
||||
+12
-12
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "Chart.js",
|
||||
"version": "2.0.0-beta",
|
||||
"description": "Simple HTML5 Charts using the canvas element",
|
||||
"homepage": "https://github.com/nnnick/Chart.js",
|
||||
"author": "nnnick",
|
||||
"main": [
|
||||
"Chart.js"
|
||||
],
|
||||
"devDependencies": {
|
||||
"jquery": "~2.1.4"
|
||||
}
|
||||
}
|
||||
"name": "Chart.js",
|
||||
"version": "2.0.0",
|
||||
"description": "Simple HTML5 Charts using the canvas element",
|
||||
"homepage": "https://github.com/nnnick/Chart.js",
|
||||
"author": "nnnick",
|
||||
"main": [
|
||||
"Chart.js"
|
||||
],
|
||||
"devDependencies": {
|
||||
"jquery": "~2.1.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "nnnick/chartjs",
|
||||
"type": "library",
|
||||
"description": "Simple HTML5 charts using the canvas element.",
|
||||
"keywords": [
|
||||
"chart",
|
||||
"js"
|
||||
],
|
||||
"homepage": "http://www.chartjs.org/",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "NICK DOWNIE",
|
||||
"email": "hello@nickdownie.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"release/2.0": "v2.0-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"node": true,
|
||||
"predef": [ "require", "module" ]
|
||||
}
|
||||
externo
+12749
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
externo
+15
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+9144
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
externo
+14
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+102
-53
@@ -3,40 +3,53 @@ title: Getting started
|
||||
anchor: getting-started
|
||||
---
|
||||
|
||||
###Include Chart.js
|
||||
### Download Chart.js
|
||||
|
||||
First we need to include the Chart.js library on the page. The library occupies a global variable of `Chart`.
|
||||
To download a zip, go to [Chart.js on Github](https://github.com/nnnick/Chart.js) and choose the version that is right for your application.
|
||||
* [Standard build](https://raw.githubusercontent.com/nnnick/Chart.js/v2.0-dev/dist/Chart.js) (~31kB gzipped)
|
||||
* [Bundled with Moment.js](https://raw.githubusercontent.com/nnnick/Chart.js/v2.0-dev/dist/Chart.bundle.js) (~45kB gzipped)
|
||||
* [CDN Versions](https://cdnjs.com/libraries/Chart.js)
|
||||
|
||||
```html
|
||||
<script src="Chart.js"></script>
|
||||
To install via npm / bower:
|
||||
|
||||
```bash
|
||||
npm install chart.js --save
|
||||
```
|
||||
|
||||
Alternatively, if you're using an AMD loader for JavaScript modules, that is also supported in the Chart.js core. Please note: the library will still occupy a global variable of `Chart`, even if it detects `define` and `define.amd`. If this is a problem, you can call `noConflict` to restore the global Chart variable to it's previous owner.
|
||||
|
||||
```javascript
|
||||
// Using requirejs
|
||||
require(['path/to/Chartjs'], function(Chart){
|
||||
// Use Chart.js as normal here.
|
||||
|
||||
// Chart.noConflict restores the Chart global variable to it's previous owner
|
||||
// The function returns what was previously Chart, allowing you to reassign.
|
||||
var Chartjs = Chart.noConflict();
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
You can also grab Chart.js using bower, npm, or CDN:
|
||||
|
||||
```bash
|
||||
bower install Chart.js --save
|
||||
```
|
||||
```bash
|
||||
npm install Chart.js --save
|
||||
|
||||
### Installation
|
||||
|
||||
To import Chart.js using an old-school script tag:
|
||||
|
||||
```html
|
||||
<script src="Chart.js"></script>
|
||||
<script>
|
||||
var myChart = new Chart({...})
|
||||
</script>
|
||||
```
|
||||
|
||||
https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.0.0-beta/Chart.js
|
||||
To import Chart.js using an awesome module loader:
|
||||
|
||||
###Creating a Chart
|
||||
```javascript
|
||||
|
||||
// Using CommonJS
|
||||
var Chart = require('src/chart.js')
|
||||
var myChart = new Chart({...})
|
||||
|
||||
// ES6
|
||||
import Chart from 'src/chart.js'
|
||||
let myChart = new Chart({...})
|
||||
|
||||
// Using requirejs
|
||||
require(['path/to/Chartjs'], function(Chart){
|
||||
var myChart = new Chart({...})
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
### Creating a Chart
|
||||
|
||||
To create a chart, we need to instantiate the `Chart` class. To do this, we need to pass in the node, jQuery instance, or 2d context of the canvas of where we want to draw the chart. Here's an example.
|
||||
|
||||
@@ -60,30 +73,30 @@ The following example instantiates a bar chart showing the number of votes for d
|
||||
<script>
|
||||
var ctx = document.getElementById("myChart");
|
||||
var myChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
|
||||
datasets: [{
|
||||
label: '# of Votes',
|
||||
data: [12, 19, 3, 5, 2, 3]
|
||||
}]
|
||||
},
|
||||
options:{
|
||||
scales:{
|
||||
yAxes:[{
|
||||
ticks:{
|
||||
beginAtZero:true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
|
||||
datasets: [{
|
||||
label: '# of Votes',
|
||||
data: [12, 19, 3, 5, 2, 3]
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero:true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
It's that easy to get started using Chart.js! From here you can explore the many options that can help you customise your charts with scales, tooltips, labels, colors, custom actions, and much more.
|
||||
|
||||
###Global chart configuration
|
||||
### Global chart configuration
|
||||
|
||||
This concept was introduced in Chart.js 1.0 to keep configuration DRY, and allow for changing options globally across chart types, avoiding the need to specify options for each instance, or the default for a particular chart type.
|
||||
|
||||
@@ -103,7 +116,42 @@ hover |-|-|-
|
||||
*hover*.animationDuration | Number | 400 | Duration in milliseconds it takes to animate hover style changes
|
||||
onClick | Function | null | Called if the event is of type 'mouseup' or 'click'. Called in the context of the chart and passed an array of active elements
|
||||
defaultColor | Color | 'rgba(0,0,0,0.1)' |
|
||||
legendCallback | Function | ` function (chart) { // the chart object to generate a legend from. }` | Function to generate a legend. Default implementation returns an HTML string.
|
||||
defaultFontColor | Color | '#666' | Default font color for all text
|
||||
defaultFontFamily | String | "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" | Default font family for all text
|
||||
defaultFontSize | Number | 12 | Default font size (in px) for text. Does not apply to radialLinear scale point labels
|
||||
defaultFontStyle | String | 'normal' | Default font style. Does not apply to tooltip title or footer. Does not apply to chart title
|
||||
legendCallback | Function | ` function (chart) { }` | Function to generate a legend. Receives the chart object to generate a legend from. Default implementation returns an HTML string.
|
||||
|
||||
The global options for the chart title is defined in `Chart.defaults.global.title`
|
||||
|
||||
Name | Type | Default | Description
|
||||
--- | --- | --- | ---
|
||||
display | Boolean | true | Show the title block
|
||||
position | String | 'top' | Position of the title. 'top' or 'bottom' are allowed
|
||||
fullWidth | Boolean | true | Marks that this box should take the full width of the canvas (pushing down other boxes)
|
||||
fontColor | Color | '#666' | Text color
|
||||
fontFamily | String | 'Helvetica Neue' |
|
||||
fontSize | Number | 12 |
|
||||
fontStyle | String | 'bold' |
|
||||
padding | Number | 10 | Number of pixels to add above and below the title text
|
||||
text | String | '' | Title text
|
||||
|
||||
The global options for the chart legend is defined in `Chart.defaults.global.legend`
|
||||
|
||||
Name | Type | Default | Description
|
||||
--- | --- | --- | ---
|
||||
display | Boolean | true | Is the legend displayed
|
||||
position | String | 'top' | Position of the legend. Options are 'top' or 'bottom'
|
||||
fullWidth | Boolean | true | Marks that this box should take the full width of the canvas (pushing down other boxes)
|
||||
onClick | Function | `function(event, legendItem) {}` | A callback that is called when a click is registered on top of a label item
|
||||
labels |-|-|-
|
||||
*labels*boxWidth | Number | 40 | Width of coloured box
|
||||
*labels*fontSize | Number | 12 | Font size
|
||||
*labels*fontStyle | String | "normal" |
|
||||
*labels*fontColor | Color | "#666" |
|
||||
*labels*fontFamily | String | "Helvetica Neue" |
|
||||
*labels*padding | Number | 10 | Padding between rows of colored boxes
|
||||
*labels*generateLabels: | Function | `function(data) { }` | Generates legend items for each thing in the legend. Default implementation returns the text + styling for the color box. Styles that can be returned are `fillStyle`, `strokeStyle`, `lineCap`, `lineDash`, `lineDashOffset`, `lineWidth`, `lineJoin`. Return a `hidden` attribute to indicate that the label refers to something that is not visible. A strikethrough style will be given to the text in this case.
|
||||
|
||||
The global options for tooltips are defined in `Chart.defaults.global.tooltips`.
|
||||
|
||||
@@ -111,7 +159,7 @@ Name | Type | Default | Description
|
||||
--- |:---:| --- | ---
|
||||
enabled | Boolean | true |
|
||||
custom | | null |
|
||||
mode | String | 'single' | Sets which elements appear in the tooltip. Acceptable options are `'single'` or `'label'`. `single` highlights the closest element. `label` highlights elements in all datasets at the same `X` value.
|
||||
mode | String | 'single' | Sets which elements appear in the tooltip. Acceptable options are `'single'` or `'label'`. `single` highlights the closest element. `label` highlights elements in all datasets at the same `X` value.
|
||||
backgroundColor | Color | 'rgba(0,0,0,0.8)' | Background color of the tooltip
|
||||
| | |
|
||||
Label | | | There are three labels you can control. `title`, `body`, `footer` the star (\*) represents one of these three. *(i.e. titleFontFamily, footerSpacing)*
|
||||
@@ -123,12 +171,11 @@ Label | | | There are three labels you can control. `title`, `body`, `footer` th
|
||||
\*Align | String | "left" | text alignment. See [MDN Canvas Documentation](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign)
|
||||
titleMarginBottom | Number | 6 | Margin to add on bottom of title section
|
||||
footerMarginTop | Number | 6 | Margin to add before drawing the footer
|
||||
xPadding | Number | 6 | Padding to add on top and bottom of tooltip
|
||||
yPadding | Number | 6 | Padding to add on left and right of tooltip
|
||||
xPadding | Number | 6 | Padding to add on left and right of tooltip
|
||||
yPadding | Number | 6 | Padding to add on top and bottom of tooltip
|
||||
caretSize | Number | 5 | Size, in px, of the tooltip arrow
|
||||
cornerRadius | Number | 6 | Radius of tooltip corner curves
|
||||
xOffset | Number | 10 |
|
||||
multiKeyBackground | Color | "#fff" |
|
||||
multiKeyBackground | Color | "#fff" | Color to draw behind the colored boxes when multiple items are in the tooltip
|
||||
| | |
|
||||
callbacks | - | - | V2.0 introduces callback functions as a replacement for the template engine in v1. The tooltip has the following callbacks for providing text. For all functions, 'this' will be the tooltip object create from the Chart.Tooltip constructor
|
||||
**Callback Functions** | | | All functions are called with the same arguments
|
||||
@@ -155,9 +202,9 @@ The global options for animations are defined in `Chart.defaults.global.animatio
|
||||
Name | Type | Default | Description
|
||||
--- |:---:| --- | ---
|
||||
duration | Number | 1000 | The number of milliseconds an animation takes.
|
||||
easing | String | "easeOutQuart" | Easing function to use.
|
||||
onProgress | Function | none |
|
||||
onComplete | Function |none |
|
||||
easing | String | "easeOutQuart" | Easing function to use.
|
||||
onProgress | Function | none | Callback called on each step of an animation. Passed a single argument, an object, containing the chart instance and an object with details of the animation.
|
||||
onComplete | Function | none | Callback called at the end of an animation. Passed the same arguments as `onProgress`
|
||||
|
||||
The global options for elements are defined in `Chart.defaults.global.elements`.
|
||||
|
||||
@@ -176,9 +223,10 @@ line | - | - | -
|
||||
*line*.borderDash | Array | `[]` | Default line dash. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash)
|
||||
*line*.borderDashOffset | Number | 0.0 | Default line dash offset. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)
|
||||
*line*.borderJoinStyle | String | 'miter' | Default line join style. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin)
|
||||
*line*.fill | Boolean | true |
|
||||
*line*.fill | Boolean | true |
|
||||
point | - | - | -
|
||||
*point*.radius | Number | 3 | Default point radius
|
||||
*point*.pointStyle | String | 'circle' | Default point style
|
||||
*point*.backgroundColor | Color | `Chart.defaults.global.defaultColor` | Default point fill color
|
||||
*point*.borderWidth | Number | 1 | Default point stroke width
|
||||
*point*.borderColor | Color | `Chart.defaults.global.defaultColor` | Default point stroke color
|
||||
@@ -189,6 +237,7 @@ rectangle | - | - | -
|
||||
*rectangle*.backgroundColor | Color | `Chart.defaults.global.defaultColor` | Default bar fill color
|
||||
*rectangle*.borderWidth | Number | 0 | Default bar stroke width
|
||||
*rectangle*.borderColor | Color | `Chart.defaults.global.defaultColor` | Default bar stroke color
|
||||
*rectangle*.borderSkipped | String | 'bottom' | Default skipped (excluded) border for rectangle. Can be one of `bottom`, `left`, `top`, `right`
|
||||
|
||||
If for example, you wanted all charts created to be responsive, and resize when the browser window does, the following setting can be changed:
|
||||
|
||||
|
||||
+60
-23
@@ -1,14 +1,13 @@
|
||||
---
|
||||
title: Getting started
|
||||
title: Scales
|
||||
anchor: scales
|
||||
---
|
||||
|
||||
###Scales
|
||||
|
||||
Scales in v2.0 of Chart.js are significantly more powerful, but also different than those of v1.0.
|
||||
- Multiple x & y axes are now supported.
|
||||
- A built-in label auto-skip feature now detects would-be overlapping ticks and labels and removes every nth label to keep things displaying normally.
|
||||
- Scale titles are now supported
|
||||
* Multiple x & y axes are now supported.
|
||||
* A built-in label auto-skip feature now detects would-be overlapping ticks and labels and removes every nth label to keep things displaying normally.
|
||||
* Scale titles are now supported
|
||||
* New scale types can be extended without writing an entirely new chart type
|
||||
|
||||
Every scale extends a core scale class with the following options:
|
||||
|
||||
@@ -16,6 +15,20 @@ Name | Type | Default | Description
|
||||
--- |:---:| --- | ---
|
||||
type | String | Chart specific. | Type of scale being employed. Custom scales can be created and registered with a string key. Options: ["category"](#scales-category-scale), ["linear"](#scales-linear-scale), ["logarithmic"](#scales-logarithmic-scale), ["time"](#scales-time-scale), ["radialLinear"](#scales-radial-linear-scale)
|
||||
display | Boolean | true | If true, show the scale including gridlines, ticks, and labels. Overrides *gridLines.display*, *scaleLabel.display*, and *ticks.display*.
|
||||
beforeUpdate | Function | undefined | Callback called before the update process starts. Passed a single argument, the scale instance.
|
||||
beforeSetDimensions | Function | undefined | Callback that runs before dimensions are set. Passed a single argument, the scale instance.
|
||||
afterSetDimensions | Function | undefined | Callback that runs after dimensions are set. Passed a single argument, the scale instance.
|
||||
beforeDataLimits | Function | undefined | Callback that runs before data limits are determined. Passed a single argument, the scale instance.
|
||||
afterDataLimits | Function | undefined | Callback that runs after data limits are determined. Passed a single argument, the scale instance.
|
||||
beforeBuildTicks | Function | undefined | Callback that runs before ticks are created. Passed a single argument, the scale instance.
|
||||
afterBuildTicks | Function | undefined | Callback that runs after ticks are created. Useful for filtering ticks. Passed a single argument, the scale instance.
|
||||
beforeTickToLabelConversion | Function | undefined | Callback that runs before ticks are converted into strings. Passed a single argument, the scale instance.
|
||||
afterTickToLabelConversion | Function | undefined | Callback that runs after ticks are converted into strings. Passed a single argument, the scale instance.
|
||||
beforeCalculateTickRotation | Function | undefined | Callback that runs before tick rotation is determined. Passed a single argument, the scale instance.
|
||||
afterCalculateTickRotation | Function | undefined | Callback that runs after tick rotation is determined. Passed a single argument, the scale instance.
|
||||
beforeFit | Function | undefined | Callback that runs before the scale fits to the canvas. Passed a single argument, the scale instance.
|
||||
afterFit | Function | undefined | Callback that runs after the scale fits to the canvas. Passed a single argument, the scale instance.
|
||||
afterUpdate | Function | undefined | Callback that runs at the end of the update process. Passed a single argument, the scale instance.
|
||||
**gridLines** | Array | - | Options for the grid lines that run perpendicular to the axis.
|
||||
*gridLines*.display | Boolean | true |
|
||||
*gridLines*.color | Color | "rgba(0, 0, 0, 0.1)" | Color of the grid lines.
|
||||
@@ -40,12 +53,16 @@ display | Boolean | true | If true, show the scale including gridlines, ticks, a
|
||||
*ticks*.fontStyle | String | "normal" | Font style for the tick labels, follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit).
|
||||
*ticks*.maxRotation | Number | 90 | Maximum rotation for tick labels when rotating to condense labels. Note: Rotation doesn't occur until necessary. *Note: Only applicable to horizontal scales.*
|
||||
*ticks*.minRotation | Number | 20 | *currently not-implemented* Minimum rotation for tick labels when condensing is necessary. *Note: Only applicable to horizontal scales.*
|
||||
*ticks*.maxTicksLimit | Number | 11 | Maximum number of ticks and gridlines to show. If not defined, it will limit to 11 ticks but will show all gridlines.
|
||||
*ticks*.padding | Number | 10 | Padding between the tick label and the axis. *Note: Only applicable to horizontal scales.*
|
||||
*ticks*.mirror | Boolean | false | Flips tick labels around axis, displaying the labels inside the chart instead of outside. *Note: Only applicable to vertical scales.*
|
||||
*ticks*.reverse | Boolean | false | Reverses order of tick labels.
|
||||
*ticks*.display | Boolean | true | If true, show the ticks.
|
||||
*ticks*.suggestedMin | Number | - | User defined minimum number for the scale, overrides minimum value *except for if* it is higher than the minimum value.
|
||||
*ticks*.suggestedMax | Number | - | User defined maximum number for the scale, overrides maximum value *except for if* it is lower than the maximum value.
|
||||
*ticks*.min | Number | - | User defined minimum number for the scale, overrides minimum value.
|
||||
*ticks*.max | Number | - | User defined minimum number for the scale, overrides maximum value
|
||||
*ticks*.autoSkip | Boolean | true | If true, automatically calculates how many labels that can be shown and hides labels accordingly. Turn it off to show all labels no matter what
|
||||
*ticks*.callback | Function | `function(value) { return '' + value; } ` | Returns the string representation of the tick value as it should be displayed on the chart.
|
||||
|
||||
The `callback` method may be used for advanced tick customization. The following callback would display every label in scientific notation
|
||||
@@ -65,7 +82,7 @@ The `callback` method may be used for advanced tick customization. The following
|
||||
}
|
||||
```
|
||||
|
||||
#### Category Scale
|
||||
### Category Scale
|
||||
The category scale will be familiar to those who have used v1.0. Labels are drawn in from the labels array included in the chart data.
|
||||
|
||||
The category scale extends the core scale class with the following tick template:
|
||||
@@ -76,7 +93,9 @@ The category scale extends the core scale class with the following tick template
|
||||
}
|
||||
```
|
||||
|
||||
#### Linear Scale
|
||||
The `ticks.min` and `ticks.max` attributes may be used with the category scale. Unlike other scales, the value of these attributes must simply be something that can be found in the `labels` array of the data object.
|
||||
|
||||
### Linear Scale
|
||||
The linear scale can be used to display numerical data. It can be placed on either the x or y axis. The scatter chart type automatically configures a line chart to use one of these scales for the x axis.
|
||||
|
||||
The linear scale extends the core scale class with the following tick template:
|
||||
@@ -113,7 +132,13 @@ The linear scale extends the core scale class with the following tick template:
|
||||
}
|
||||
```
|
||||
|
||||
#### Logarithmic Scale
|
||||
It also provides additional configuration options:
|
||||
|
||||
Name | Type | Default | Description
|
||||
--- |:---:| --- | ---
|
||||
*ticks*.stepSize | Number | - | User defined fixed step size for the scale. If set, the scale ticks will be enumerated by multiple of stepSize, having one tick per increment. If not set, the ticks are labeled automatically using the nice numbers algorithm.
|
||||
|
||||
### Logarithmic Scale
|
||||
The logarithmic scale is used to display logarithmic data of course. It can be placed on either the x or y axis.
|
||||
|
||||
The log scale extends the core scale class with the following tick template:
|
||||
@@ -135,7 +160,7 @@ The log scale extends the core scale class with the following tick template:
|
||||
}
|
||||
```
|
||||
|
||||
#### Time Scale
|
||||
### Time Scale
|
||||
The time scale is used to display times and dates. It can be placed on the x axis. When building its ticks, it will automatically calculate the most comfortable unit base on the size of the scale.
|
||||
|
||||
The time scale extends the core scale class with the following tick template:
|
||||
@@ -145,24 +170,31 @@ The time scale extends the core scale class with the following tick template:
|
||||
position: "bottom",
|
||||
time: {
|
||||
// string/callback - By default, date objects are expected. You may use a pattern string from http://momentjs.com/docs/#/parsing/string-format/ to parse a time string format, or use a callback function that is passed the label, and must return a moment() instance.
|
||||
format: false,
|
||||
parser: false,
|
||||
// string - By default, unit will automatically be detected. Override with 'week', 'month', 'year', etc. (see supported time measurements)
|
||||
unit: false,
|
||||
|
||||
// Number - The number of steps of the above unit between ticks
|
||||
unitStepSize: 1
|
||||
|
||||
// string - By default, no rounding is applied. To round, set to a supported time unit eg. 'week', 'month', 'year', etc.
|
||||
round: false,
|
||||
|
||||
// Moment js for each of the units. Replaces `displayFormat`
|
||||
// To override, use a pattern string from http://momentjs.com/docs/#/displaying/format/
|
||||
displayFormats: {
|
||||
'millisecond': 'SSS [ms]',
|
||||
'second': 'h:mm:ss a', // 11:20:01 AM
|
||||
'minute': 'h:mm:ss a', // 11:20:01 AM
|
||||
'hour': 'MMM D, hA', // Sept 4, 5PM
|
||||
'day': 'll', // Sep 4 2015
|
||||
'week': 'll', // Week 46, or maybe "[W]WW - YYYY" ?
|
||||
'month': 'MMM YYYY', // Sept 2015
|
||||
'quarter': '[Q]Q - YYYY', // Q3
|
||||
'year': 'YYYY', // 2015
|
||||
},
|
||||
'millisecond': 'SSS [ms]',
|
||||
'second': 'h:mm:ss a', // 11:20:01 AM
|
||||
'minute': 'h:mm:ss a', // 11:20:01 AM
|
||||
'hour': 'MMM D, hA', // Sept 4, 5PM
|
||||
'day': 'll', // Sep 4 2015
|
||||
'week': 'll', // Week 46, or maybe "[W]WW - YYYY" ?
|
||||
'month': 'MMM YYYY', // Sept 2015
|
||||
'quarter': '[Q]Q - YYYY', // Q3
|
||||
'year': 'YYYY', // 2015
|
||||
},
|
||||
// Sets the display format used in tooltip generation
|
||||
tooltipFormat: ''
|
||||
},
|
||||
}
|
||||
```
|
||||
@@ -210,7 +242,7 @@ The following time measurements are supported:
|
||||
}
|
||||
```
|
||||
|
||||
#### Radial Linear Scale
|
||||
### Radial Linear Scale
|
||||
The radial linear scale is used specifically for the radar chart type.
|
||||
|
||||
The radial linear scale extends the core scale class with the following tick template:
|
||||
@@ -241,7 +273,7 @@ The radial linear scale extends the core scale class with the following tick tem
|
||||
//Number - The backdrop padding to the side of the label in pixels
|
||||
backdropPaddingX: 2,
|
||||
|
||||
//Number - Limit the maximum number of ticks
|
||||
//Number - Limit the maximum number of ticks and gridlines
|
||||
maxTicksLimit: 11,
|
||||
},
|
||||
|
||||
@@ -257,6 +289,11 @@ The radial linear scale extends the core scale class with the following tick tem
|
||||
|
||||
//String - Point label font colour
|
||||
fontColor: "#666",
|
||||
|
||||
//Function - Used to determine point labels to show in scale
|
||||
callback: function(pointLabel) {
|
||||
return pointLabel;
|
||||
}
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
+12
-38
@@ -2,7 +2,7 @@
|
||||
title: Line Chart
|
||||
anchor: line-chart
|
||||
---
|
||||
###Introduction
|
||||
### Introduction
|
||||
A line chart is a way of plotting data points on a line.
|
||||
|
||||
Often, it is used to show trend data, and the comparison of two data sets.
|
||||
@@ -11,7 +11,7 @@ Often, it is used to show trend data, and the comparison of two data sets.
|
||||
<canvas width="250" height="125"></canvas>
|
||||
</div>
|
||||
|
||||
###Example usage
|
||||
### Example usage
|
||||
```javascript
|
||||
var myLineChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
@@ -27,7 +27,7 @@ var myLineChart = Chart.Line(ctx, {
|
||||
options: options
|
||||
});
|
||||
```
|
||||
###Data structure
|
||||
### Data structure
|
||||
|
||||
```javascript
|
||||
var data = {
|
||||
@@ -80,11 +80,14 @@ var data = {
|
||||
// Number or array - border width of point when hovered
|
||||
pointHoverBorderWidth: 2,
|
||||
|
||||
// Tension - bezier curve tension of the line. Set to 0 to draw straight Wlines connecting points
|
||||
tension: 0.1,
|
||||
|
||||
// The actual data
|
||||
data: [65, 59, 80, 81, 56, 55, 40],
|
||||
|
||||
// String - If specified, binds the dataset to a certain y-axis. If not specified, the first y-axis is used.
|
||||
yAxisID: "y-axis-1",
|
||||
// String - If specified, binds the dataset to a certain y-axis. If not specified, the first y-axis is used. First id is y-axis-0
|
||||
yAxisID: "y-axis-0",
|
||||
},
|
||||
{
|
||||
label: "My Second dataset",
|
||||
@@ -104,7 +107,7 @@ var data = {
|
||||
};
|
||||
```
|
||||
|
||||
The line chart requires an array of labels for each of the data points. This is shown on the X axis.
|
||||
The line chart requires an array of labels. This labels are shown on the X axis. There must be one label for each data point. More labels than datapoints are allowed, in which case the line ends at the last data point.
|
||||
The data for line charts is broken up into an array of datasets. Each dataset has a colour for the fill, a colour for the line and colours for the points and strokes of the points. These colours are strings just like CSS. You can use RGBA, RGB, HEX or HSL notation.
|
||||
|
||||
The label key on each dataset is optional, and can be used when generating a scale for the chart.
|
||||
@@ -117,6 +120,7 @@ The default options for line chart are defined in `Chart.defaults.Line`.
|
||||
|
||||
Name | Type | Default | Description
|
||||
--- | --- | --- | ---
|
||||
showLines | Boolean | true | If false, the lines between points are not drawn
|
||||
stacked | Boolean | false | If true, lines stack on top of each other along the y axis.
|
||||
*hover*.mode | String | "label" | Label's hover mode. "label" is used since the x axis displays data by the index in the dataset.
|
||||
scales | - | - | -
|
||||
@@ -145,37 +149,7 @@ new Chart(ctx, {
|
||||
}
|
||||
});
|
||||
// This will create a chart with all of the default options, merged from the global config,
|
||||
// and the Line chart defaults, but this particular instance will have `bezierCurve` set to false.
|
||||
// and the Line chart defaults, but this particular instance will have the x axis not displaying.
|
||||
```
|
||||
|
||||
We can also change these defaults values for each Line type that is created, this object is available at `Chart.defaults.Line`.
|
||||
|
||||
|
||||
### Prototype methods
|
||||
|
||||
#### .getElementsAtEvent( event )
|
||||
|
||||
Calling `getElementsAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the point elements that are at that the same position of that event.
|
||||
|
||||
```javascript
|
||||
canvas.onclick = function(evt){
|
||||
var activePoints = myLineChart.getElementsAtEvent(evt);
|
||||
// => activePoints is an array of points on the canvas that are at the same position as the click event.
|
||||
};
|
||||
```
|
||||
|
||||
This functionality may be useful for implementing DOM based tooltips, or triggering custom behaviour in your application.
|
||||
|
||||
#### .getElementAtEvent( event )
|
||||
Calling `getElementAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the single element at the event position. If there are multiple items within range, only the first is returned
|
||||
|
||||
#### .update( )
|
||||
|
||||
Calling `update()` on your Chart instance will re-render the chart with any updated values, allowing you to edit the value of multiple existing points, then render those in one animated render loop. You can safely call `update()` after changing the entire data object on the chart.
|
||||
|
||||
```javascript
|
||||
myLineChart.data.datasets[0].data[2] = 50;
|
||||
// Would update the first dataset's value of 'March' to be 50
|
||||
myLineChart.update();
|
||||
// Calling update now animates the position of March from 90 to 50.
|
||||
```
|
||||
We can also change these defaults values for each Line type that is created, this object is available at `Chart.defaults.line`.
|
||||
|
||||
+14
-42
@@ -14,7 +14,7 @@ It is sometimes used to show trend data, and the comparison of multiple data set
|
||||
|
||||
### Example usage
|
||||
```javascript
|
||||
var myBarChart = new Chart(ctx,{
|
||||
var myBarChart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: data,
|
||||
options: options
|
||||
@@ -50,7 +50,7 @@ var data = {
|
||||
data: [65, 59, 80, 81, 56, 55, 40],
|
||||
|
||||
// String - If specified, binds the dataset to a certain y-axis. If not specified, the first y-axis is used.
|
||||
yAxisID: "y-axis-1",
|
||||
yAxisID: "y-axis-0",
|
||||
},
|
||||
{
|
||||
label: "My Second dataset",
|
||||
@@ -108,13 +108,13 @@ You can override these for your `Chart` instance by passing a second argument in
|
||||
For example, we could have a bar chart without a stroke on each bar by doing the following:
|
||||
|
||||
```javascript
|
||||
new Chart(ctx,{
|
||||
type:"bar",
|
||||
new Chart(ctx, {
|
||||
type: "bar",
|
||||
data: data,
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
stacked: true,
|
||||
stacked: true
|
||||
}],
|
||||
yAxes: [{
|
||||
stacked: true
|
||||
@@ -137,47 +137,19 @@ The following shows the relationship between the bar percentage option and the c
|
||||
```text
|
||||
// categoryPercentage: 1.0
|
||||
// barPercentage: 1.0
|
||||
Bar: | 1.0 | 1.0 |
|
||||
Category: | 1.0 |
|
||||
Sample: |===========|
|
||||
Bar: | 1.0 | 1.0 |
|
||||
Category: | 1.0 |
|
||||
Sample: |===========|
|
||||
|
||||
// categoryPercentage: 1.0
|
||||
// barPercentage: 0.5
|
||||
Bar: |.5| |.5|
|
||||
Category: | 1.0 |
|
||||
Sample: |==============|
|
||||
Bar: |.5| |.5|
|
||||
Category: | 1.0 |
|
||||
Sample: |==============|
|
||||
|
||||
// categoryPercentage: 0.5
|
||||
// barPercentage: 1.0
|
||||
Bar: |1.||1.|
|
||||
Category: | .5 |
|
||||
Sample: |==============|
|
||||
```
|
||||
### Prototype methods
|
||||
|
||||
#### .getElementsAtEvent( event )
|
||||
|
||||
Calling `getElementsAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the point elements that are at that the same position of that event.
|
||||
|
||||
```javascript
|
||||
canvas.onclick = function(evt){
|
||||
var activePoints = myLineChart.getElementsAtEvent(evt);
|
||||
// => activePoints is an array of points on the canvas that are at the same position as the click event.
|
||||
};
|
||||
```
|
||||
|
||||
This functionality may be useful for implementing DOM based tooltips, or triggering custom behaviour in your application.
|
||||
|
||||
#### .getElementAtEvent( event )
|
||||
Calling `getElementAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the single element at the event position. If there are multiple items within range, only the first is returned
|
||||
|
||||
#### .update( )
|
||||
|
||||
Calling `update()` on your Chart instance will re-render the chart with any updated values, allowing you to edit the value of multiple existing points, then render those in one animated render loop.
|
||||
|
||||
```javascript
|
||||
myBarChart.data.datasets[0].data[2] = 50;
|
||||
// Would update the first dataset's value of 'March' to be 50
|
||||
myBarChart.update();
|
||||
// Calling update now animates the position of March from 90 to 50.
|
||||
Bar: |1.||1.|
|
||||
Category: | .5 |
|
||||
Sample: |==============|
|
||||
```
|
||||
+10
-56
@@ -3,7 +3,7 @@ title: Radar Chart
|
||||
anchor: radar-chart
|
||||
---
|
||||
|
||||
###Introduction
|
||||
### Introduction
|
||||
A radar chart is a way of showing multiple data points and the variation between them.
|
||||
|
||||
They are often useful for comparing the points of two or more different data sets.
|
||||
@@ -12,17 +12,17 @@ They are often useful for comparing the points of two or more different data set
|
||||
<canvas width="250" height="125"></canvas>
|
||||
</div>
|
||||
|
||||
###Example usage
|
||||
### Example usage
|
||||
|
||||
```javascript
|
||||
var myRadarChart = new Chart(ctx,{
|
||||
type:'radar',
|
||||
var myRadarChart = new Chart(ctx, {
|
||||
type: 'radar',
|
||||
data: data,
|
||||
options: options
|
||||
});
|
||||
```
|
||||
|
||||
###Data structure
|
||||
### Data structure
|
||||
```javascript
|
||||
var data = {
|
||||
labels: ["Eating", "Drinking", "Sleeping", "Designing", "Coding", "Cycling", "Running"],
|
||||
@@ -52,10 +52,10 @@ var data = {
|
||||
```
|
||||
For a radar chart, to provide context of what each point means, we include an array of strings that show around each point in the chart.
|
||||
For the radar chart data, we have an array of datasets. Each of these is an object, with a fill colour, a stroke colour, a colour for the fill of each point, and a colour for the stroke of each point. We also have an array of data values.
|
||||
|
||||
The label key on each dataset is optional, and can be used when generating a scale for the chart.
|
||||
|
||||
### Chart options
|
||||
|
||||
### Chart Options
|
||||
|
||||
These are the customisation options specific to Radar charts. These options are merged with the [global chart configuration options](#getting-started-global-chart-configuration), and form the options of the chart.
|
||||
|
||||
@@ -66,7 +66,7 @@ Name | Type | Default | Description
|
||||
scale | Array | [See Scales](#scales) and [Defaults for Radial Linear Scale](#scales-radial-linear-scale) | Options for the one scale used on the chart. Use this to style the ticks, labels, and grid lines.
|
||||
*scale*.type | String |"radialLinear" | As defined in ["Radial Linear"](#scales-radial-linear-scale).
|
||||
*elements*.line | Array | | Options for all line elements used on the chart, as defined in the global elements, duplicated here to show Radar chart specific defaults.
|
||||
*elements.line*.tension | Number | 0 | Tension exhibited by lines when calculating splineCurve.
|
||||
*elements.line*.tension | Number | 0 | Tension exhibited by lines when calculating splineCurve. Setting to 0 creates straight lines.
|
||||
|
||||
You can override these for your `Chart` instance by passing a second argument into the `Radar` method as an object with the keys you want to override.
|
||||
|
||||
@@ -74,7 +74,7 @@ For example, we could have a radar chart without a point for each on piece of da
|
||||
|
||||
```javascript
|
||||
new Chart(ctx, {
|
||||
type:"radar",
|
||||
type: "radar",
|
||||
data: data,
|
||||
options: {
|
||||
scale: {
|
||||
@@ -90,50 +90,4 @@ new Chart(ctx, {
|
||||
// well as the ticks beginning at zero.
|
||||
```
|
||||
|
||||
We can also change these defaults values for each Radar type that is created, this object is available at `Chart.defaults.Radar`.
|
||||
|
||||
|
||||
### Prototype methods
|
||||
|
||||
#### .getPointsAtEvent( event )
|
||||
|
||||
Calling `getPointsAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the point elements that are at that the same position of that event.
|
||||
|
||||
```javascript
|
||||
canvas.onclick = function(evt){
|
||||
var activePoints = myRadarChart.getPointsAtEvent(evt);
|
||||
// => activePoints is an array of points on the canvas that are at the same position as the click event.
|
||||
};
|
||||
```
|
||||
|
||||
This functionality may be useful for implementing DOM based tooltips, or triggering custom behaviour in your application.
|
||||
|
||||
#### .update( )
|
||||
|
||||
Calling `update()` on your Chart instance will re-render the chart with any updated values, allowing you to edit the value of multiple existing points, then render those in one animated render loop.
|
||||
|
||||
```javascript
|
||||
myRadarChart.datasets[0].points[2].value = 50;
|
||||
// Would update the first dataset's value of 'Sleeping' to be 50
|
||||
myRadarChart.update();
|
||||
// Calling update now animates the position of Sleeping from 90 to 50.
|
||||
```
|
||||
|
||||
#### .addData( valuesArray, label )
|
||||
|
||||
Calling `addData(valuesArray, label)` on your Chart instance passing an array of values for each dataset, along with a label for those points.
|
||||
|
||||
```javascript
|
||||
// The values array passed into addData should be one for each dataset in the chart
|
||||
myRadarChart.addData([40, 60], "Dancing");
|
||||
// The new data will now animate at the end of the chart.
|
||||
```
|
||||
|
||||
#### .removeData( )
|
||||
|
||||
Calling `removeData()` on your Chart instance will remove the first value for all datasets on the chart.
|
||||
|
||||
```javascript
|
||||
myRadarChart.removeData();
|
||||
// Other points will now animate to their correct positions.
|
||||
```
|
||||
We can also change these defaults values for each Radar type that is created, this object is available at `Chart.defaults.radar`.
|
||||
|
||||
@@ -14,45 +14,42 @@ This type of chart is often useful when we want to show a comparison data simila
|
||||
### Example usage
|
||||
|
||||
```javascript
|
||||
new Chart(ctx).PolarArea(data, options);
|
||||
new Chart(ctx, {
|
||||
data: data,
|
||||
type: 'polarArea',
|
||||
options: options
|
||||
});
|
||||
```
|
||||
|
||||
### Data structure
|
||||
|
||||
```javascript
|
||||
var data = [
|
||||
{
|
||||
value: 300,
|
||||
color:"#F7464A",
|
||||
highlight: "#FF5A5E",
|
||||
label: "Red"
|
||||
},
|
||||
{
|
||||
value: 50,
|
||||
color: "#46BFBD",
|
||||
highlight: "#5AD3D1",
|
||||
label: "Green"
|
||||
},
|
||||
{
|
||||
value: 100,
|
||||
color: "#FDB45C",
|
||||
highlight: "#FFC870",
|
||||
label: "Yellow"
|
||||
},
|
||||
{
|
||||
value: 40,
|
||||
color: "#949FB1",
|
||||
highlight: "#A8B3C5",
|
||||
label: "Grey"
|
||||
},
|
||||
{
|
||||
value: 120,
|
||||
color: "#4D5360",
|
||||
highlight: "#616774",
|
||||
label: "Dark Grey"
|
||||
}
|
||||
|
||||
];
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [
|
||||
10,
|
||||
32,
|
||||
53,
|
||||
14,
|
||||
22,
|
||||
],
|
||||
backgroundColor: [
|
||||
"#F7464A",
|
||||
"#46BFBD",
|
||||
"#FDB45C",
|
||||
"#949FB1",
|
||||
"#4D5360",
|
||||
],
|
||||
label: 'My dataset' // for legend
|
||||
}],
|
||||
labels: [
|
||||
"Red",
|
||||
"Green",
|
||||
"Yellow",
|
||||
"Grey",
|
||||
"Dark Grey"
|
||||
]
|
||||
};
|
||||
```
|
||||
As you can see, for the chart data you pass in an array of objects, with a value and a colour. The value attribute should be a number, while the color attribute should be a string. Similar to CSS, for this string you can use HEX notation, RGB, RGBA or HSL.
|
||||
|
||||
@@ -65,69 +62,30 @@ Name | Type | Default | Description
|
||||
scale | Array | [See Scales](#scales) and [Defaults for Radial Linear Scale](#getting-started-radial-linear-scale) | Options for the one scale used on the chart. Use this to style the ticks, labels, and grid.
|
||||
*scale*.type | String |"radialLinear" | As defined in ["Radial Linear"](#scales-radial-linear-scale).
|
||||
*scale*.lineArc | Boolean | true | When true, lines are circular.
|
||||
*animation*.animateRotate | Boolean |true | If true, will animate the rotation of the chart.
|
||||
*animation*.animateScale | Boolean | true | If true, will animate scaling the chart.
|
||||
animateRotate | Boolean |true | If true, will animate the rotation of the chart.
|
||||
animateScale | Boolean | true | If true, will animate scaling the chart.
|
||||
*legend*.*labels*.generateLabels | Function | `function(data) {} ` | Returns labels for each the legend
|
||||
*legend*.onClick | Function | function(event, legendItem) {} ` | Handles clicking an individual legend item
|
||||
legendCallback | Function | `function(chart) ` | Generates the HTML legend via calls to `generateLegend`
|
||||
|
||||
You can override these for your `Chart` instance by passing a second argument into the `PolarArea` method as an object with the keys you want to override.
|
||||
|
||||
For example, we could have a polar area chart with a black stroke on each segment like so:
|
||||
|
||||
```javascript
|
||||
new Chart(ctx).PolarArea(data, {
|
||||
segmentStrokeColor: "#000000"
|
||||
new Chart(ctx, {
|
||||
data: data,
|
||||
type: "polarArea",
|
||||
options: {
|
||||
elements: {
|
||||
arc: {
|
||||
borderColor: "#000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// This will create a chart with all of the default options, merged from the global config,
|
||||
// and the PolarArea chart defaults but this particular instance will have `segmentStrokeColor` set to `"#000000"`.
|
||||
// and the PolarArea chart defaults but this particular instance will have `elements.arc.borderColor` set to `"#000000"`.
|
||||
```
|
||||
|
||||
We can also change these defaults values for each PolarArea type that is created, this object is available at `Chart.defaults.PolarArea`.
|
||||
|
||||
### Prototype methods
|
||||
|
||||
#### .getSegmentsAtEvent( event )
|
||||
|
||||
Calling `getSegmentsAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the segment elements that are at that the same position of that event.
|
||||
|
||||
```javascript
|
||||
canvas.onclick = function(evt){
|
||||
var activePoints = myPolarAreaChart.getSegmentsAtEvent(evt);
|
||||
// => activePoints is an array of segments on the canvas that are at the same position as the click event.
|
||||
};
|
||||
```
|
||||
|
||||
This functionality may be useful for implementing DOM based tooltips, or triggering custom behaviour in your application.
|
||||
|
||||
#### .update( )
|
||||
|
||||
Calling `update()` on your Chart instance will re-render the chart with any updated values, allowing you to edit the value of multiple existing points, then render those in one animated render loop.
|
||||
|
||||
```javascript
|
||||
myPolarAreaChart.segments[1].value = 10;
|
||||
// Would update the first dataset's value of 'Green' to be 10
|
||||
myPolarAreaChart.update();
|
||||
// Calling update now animates the position of Green from 50 to 10.
|
||||
```
|
||||
|
||||
#### .addData( segmentData, index )
|
||||
|
||||
Calling `addData(segmentData, index)` on your Chart instance passing an object in the same format as in the constructor. There is an option second argument of 'index', this determines at what index the new segment should be inserted into the chart.
|
||||
|
||||
```javascript
|
||||
// An object in the same format as the original data source
|
||||
myPolarAreaChart.addData({
|
||||
value: 130,
|
||||
color: "#B48EAD",
|
||||
highlight: "#C69CBE",
|
||||
label: "Purple"
|
||||
});
|
||||
// The new segment will now animate in.
|
||||
```
|
||||
|
||||
#### .removeData( index )
|
||||
|
||||
Calling `removeData(index)` on your Chart instance will remove segment at that particular index. If none is provided, it will default to the last segment.
|
||||
|
||||
```javascript
|
||||
myPolarAreaChart.removeData();
|
||||
// Other segments will update to fill the empty space left.
|
||||
```
|
||||
We can also change these defaults values for each PolarArea type that is created, this object is available at `Chart.defaults.polarArea`.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Pie & Doughnut Charts
|
||||
anchor: doughnut-pie-chart
|
||||
---
|
||||
###Introduction
|
||||
### Introduction
|
||||
Pie and doughnut charts are probably the most commonly used chart there are. They are divided into segments, the arc of each segment shows the proportional value of each piece of data.
|
||||
|
||||
They are excellent at showing the relational proportions between data.
|
||||
@@ -78,6 +78,8 @@ scale | Array | [See Scales](#scales) and [Defaults for Radial Linear Scale](#ge
|
||||
*scale*.lineArc | Boolean | true | When true, lines are arced compared to straight when false.
|
||||
*animation*.animateRotate | Boolean |true | If true, will animate the rotation of the chart.
|
||||
*animation*.animateScale | Boolean | false | If true, will animate scaling the Doughnut from the centre.
|
||||
*legend*.*labels*.generateLabels | Function | `function(data) {} ` | Returns labels for each the legend
|
||||
*legend*.onClick | Function | function(event, legendItem) {} ` | Handles clicking an individual legend item
|
||||
|
||||
You can override these for your `Chart` instance by passing a second argument into the `Doughnut` method as an object with the keys you want to override.
|
||||
|
||||
@@ -94,55 +96,4 @@ new Chart(ctx,{
|
||||
// and the Doughnut chart defaults but this particular instance will have `animateScale` set to `true`.
|
||||
```
|
||||
|
||||
We can also change these default values for each Doughnut type that is created, this object is available at `Chart.defaults.Doughnut`. Pie charts also have a clone of these defaults available to change at `Chart.defaults.Pie`, with the only difference being `percentageInnerCutout` being set to 0.
|
||||
|
||||
### Prototype methods
|
||||
|
||||
#### .getSegmentsAtEvent( event )
|
||||
|
||||
Calling `getSegmentsAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the segment elements that are at the same position of that event.
|
||||
|
||||
```javascript
|
||||
canvas.onclick = function(evt){
|
||||
var activePoints = myDoughnutChart.getSegmentsAtEvent(evt);
|
||||
// => activePoints is an array of segments on the canvas that are at the same position as the click event.
|
||||
};
|
||||
```
|
||||
|
||||
This functionality may be useful for implementing DOM based tooltips, or triggering custom behaviour in your application.
|
||||
|
||||
#### .update( )
|
||||
|
||||
Calling `update()` on your Chart instance will re-render the chart with any updated values, allowing you to edit the value of multiple existing points, then render those in one animated render loop.
|
||||
|
||||
```javascript
|
||||
myDoughnutChart.segments[1].value = 10;
|
||||
// Would update the first dataset's value of 'Green' to be 10
|
||||
myDoughnutChart.update();
|
||||
// Calling update now animates the circumference of the segment 'Green' from 50 to 10.
|
||||
// and transitions other segment widths
|
||||
```
|
||||
|
||||
#### .addData( segmentData, index )
|
||||
|
||||
Calling `addData(segmentData, index)` on your Chart instance passing an object in the same format as in the constructor. There is an optional second argument of 'index', this determines at what index the new segment should be inserted into the chart.
|
||||
|
||||
```javascript
|
||||
// An object in the same format as the original data source
|
||||
myDoughnutChart.addData({
|
||||
value: 130,
|
||||
color: "#B48EAD",
|
||||
highlight: "#C69CBE",
|
||||
label: "Purple"
|
||||
});
|
||||
// The new segment will now animate in.
|
||||
```
|
||||
|
||||
#### .removeData( index )
|
||||
|
||||
Calling `removeData(index)` on your Chart instance will remove segment at that particular index. If none is provided, it will default to the last segment.
|
||||
|
||||
```javascript
|
||||
myDoughnutChart.removeData();
|
||||
// Other segments will update to fill the empty space left.
|
||||
```
|
||||
We can also change these default values for each Doughnut type that is created, this object is available at `Chart.defaults.doughnut`. Pie charts also have a clone of these defaults available to change at `Chart.defaults.pie`, with the only difference being `percentageInnerCutout` being set to 0.
|
||||
+286
-87
@@ -10,17 +10,38 @@ For each chart, there are a set of global prototype methods on the shared `Chart
|
||||
|
||||
```javascript
|
||||
// For example:
|
||||
var myLineChart = new Chart(ctx).Line(data);
|
||||
var myLineChart = new Chart(ctx, config);
|
||||
```
|
||||
|
||||
#### .clear()
|
||||
#### .destroy()
|
||||
|
||||
Will clear the chart canvas. Used extensively internally between animation frames, but you might find it useful.
|
||||
Use this to destroy any chart instances that are created. This will clean up any references stored to the chart object within Chart.js, along with any associated event listeners attached by Chart.js.
|
||||
This must be called before the canvas is reused for a new chart.
|
||||
|
||||
```javascript
|
||||
// Will clear the canvas that myLineChart is drawn on
|
||||
myLineChart.clear();
|
||||
// => returns 'this' for chainability
|
||||
// Destroys a specific chart instance
|
||||
myLineChart.destroy();
|
||||
```
|
||||
|
||||
#### .update(duration, lazy)
|
||||
|
||||
Triggers an update of the chart. This can be safely called after replacing the entire data object. This will update all scales, legends, and then re-render the chart.
|
||||
|
||||
```javascript
|
||||
// duration is the time for the animation of the redraw in miliseconds
|
||||
// lazy is a boolean. if true, the animation can be interupted by other animations
|
||||
myLineChart.data.datasets[0].data[2] = 50; // Would update the first dataset's value of 'March' to be 50
|
||||
myLineChart.update(); // Calling update now animates the position of March from 90 to 50.
|
||||
```
|
||||
|
||||
#### .render(duration, lazy)
|
||||
|
||||
Triggers a redraw of all chart elements. Note, this does not update elements for new data. Use `.update()` in that case.
|
||||
|
||||
```javascript
|
||||
// duration is the time for the animation of the redraw in miliseconds
|
||||
// lazy is a boolean. if true, the animation can be interupted by other animations
|
||||
myLineChart.render(duration, lazy);
|
||||
```
|
||||
|
||||
#### .stop()
|
||||
@@ -35,7 +56,7 @@ myLineChart.stop();
|
||||
|
||||
#### .resize()
|
||||
|
||||
Use this to manually resize the canvas element. This is run each time the browser is resized, but you can call this method manually if you change the size of the canvas nodes container element.
|
||||
Use this to manually resize the canvas element. This is run each time the canvas container is resized, but you can call this method manually if you change the size of the canvas nodes container element.
|
||||
|
||||
```javascript
|
||||
// Resizes & redraws to fill its container element
|
||||
@@ -43,13 +64,14 @@ myLineChart.resize();
|
||||
// => returns 'this' for chainability
|
||||
```
|
||||
|
||||
#### .destroy()
|
||||
#### .clear()
|
||||
|
||||
Use this to destroy any chart instances that are created. This will clean up any references stored to the chart object within Chart.js, along with any associated event listeners attached by Chart.js.
|
||||
Will clear the chart canvas. Used extensively internally between animation frames, but you might find it useful.
|
||||
|
||||
```javascript
|
||||
// Destroys a specific chart instance
|
||||
myLineChart.destroy();
|
||||
// Will clear the canvas that myLineChart is drawn on
|
||||
myLineChart.clear();
|
||||
// => returns 'this' for chainability
|
||||
```
|
||||
|
||||
#### .toBase64Image()
|
||||
@@ -63,109 +85,290 @@ myLineChart.toBase64Image();
|
||||
|
||||
#### .generateLegend()
|
||||
|
||||
Returns an HTML string of a legend for that chart. The template for this legend is at `legendTemplate` in the chart options.
|
||||
Returns an HTML string of a legend for that chart. The legend is generated from the `legendCallback` in the options.
|
||||
|
||||
```javascript
|
||||
myLineChart.generateLegend();
|
||||
// => returns HTML string of a legend for this chart
|
||||
```
|
||||
|
||||
#### .getElementAtEvent(e)
|
||||
|
||||
Calling `getElementAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the single element at the event position. If there are multiple items within range, only the first is returned
|
||||
|
||||
```javascript
|
||||
myLineChart.getElementAtEvent(e);
|
||||
// => returns the first element at the event point.
|
||||
```
|
||||
|
||||
#### .getElementsAtEvent(e)
|
||||
|
||||
Looks for the element under the event point, then returns all elements at the same data index. This is used internally for 'label' mode highlighting.
|
||||
|
||||
Calling `getElementsAtEvent(event)` on your Chart instance passing an argument of an event, or jQuery event, will return the point elements that are at that the same position of that event.
|
||||
|
||||
```javascript
|
||||
canvas.onclick = function(evt){
|
||||
var activePoints = myLineChart.getElementsAtEvent(evt);
|
||||
// => activePoints is an array of points on the canvas that are at the same position as the click event.
|
||||
};
|
||||
```
|
||||
|
||||
This functionality may be useful for implementing DOM based tooltips, or triggering custom behaviour in your application.
|
||||
|
||||
#### .getDatasetAtEvent(e)
|
||||
|
||||
Looks for the element under the event point, then returns all elements from that dataset. This is used internally for 'dataset' mode highlighting
|
||||
|
||||
```javascript
|
||||
myLineChart.getDatasetAtEvent(e);
|
||||
// => returns an array of elements
|
||||
```
|
||||
|
||||
### External Tooltips
|
||||
|
||||
You can enable custom tooltips in the global or chart configuration like so:
|
||||
|
||||
```javascript
|
||||
var myPieChart = new Chart(ctx).Pie(data, {
|
||||
customTooltips: function(tooltip) {
|
||||
var myPieChart = new Chart(ctx, {
|
||||
type: 'pie',
|
||||
data: data,
|
||||
options: {
|
||||
tooltips: {
|
||||
custom: function(tooltip) {
|
||||
// tooltip will be false if tooltip is not visible or should be hidden
|
||||
if (!tooltip) {
|
||||
return;
|
||||
}
|
||||
|
||||
// tooltip will be false if tooltip is not visible or should be hidden
|
||||
if (!tooltip) {
|
||||
return;
|
||||
}
|
||||
// Otherwise, tooltip will be an object with all tooltip properties like:
|
||||
|
||||
// Otherwise, tooltip will be an object with all tooltip properties like:
|
||||
|
||||
// tooltip.caretHeight
|
||||
// tooltip.caretPadding
|
||||
// tooltip.chart
|
||||
// tooltip.cornerRadius
|
||||
// tooltip.fillColor
|
||||
// tooltip.font...
|
||||
// tooltip.text
|
||||
// tooltip.x
|
||||
// tooltip.y
|
||||
// etc...
|
||||
|
||||
};
|
||||
// tooltip.caretHeight
|
||||
// tooltip.caretPadding
|
||||
// tooltip.chart
|
||||
// tooltip.cornerRadius
|
||||
// tooltip.fillColor
|
||||
// tooltip.font...
|
||||
// tooltip.text
|
||||
// tooltip.x
|
||||
// tooltip.y
|
||||
// etc...
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
See files `sample/pie-customTooltips.html` and `sample/line-customTooltips.html` for examples on how to get started.
|
||||
See `sample/line-customTooltips.html` for examples on how to get started.
|
||||
|
||||
### Writing new scale types
|
||||
|
||||
Starting with Chart.js 2.0 scales can be individually extended. Scales should always derive from Chart.Scale.
|
||||
|
||||
```javascript
|
||||
var MyScale = Chart.Scale.extend({
|
||||
/* extensions ... */
|
||||
});
|
||||
|
||||
// MyScale is now derived from Chart.Scale
|
||||
```
|
||||
|
||||
Once you have created your scale class, you need to register it with the global chart object so that it can be used. A default config for the scale may be provided when registering the constructor. The first parameter to the register function is a string key that is used later to identify which scale type to use for a chart.
|
||||
|
||||
```javascript
|
||||
Chart.scaleService.registerScaleType('myScale', MyScale, defaultConfigObject);
|
||||
```
|
||||
|
||||
To use the new scale, simply pass in the string key to the config when creating a chart.
|
||||
|
||||
```javascript
|
||||
var lineChart = new Chart(ctx, {
|
||||
data: data,
|
||||
type: 'line',
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
type: 'myScale' // this is the same key that was passed to the registerScaleType function
|
||||
}]
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
#### Scale Properties
|
||||
|
||||
Scale instances are given the following properties during the fitting process.
|
||||
|
||||
```javascript
|
||||
{
|
||||
left: Number, // left edge of the scale bounding box
|
||||
right: Number, // right edge of the bounding box'
|
||||
top: Number,
|
||||
bottom: Number,
|
||||
width: Number, // the same as right - left
|
||||
height: Number, // the same as bottom - top
|
||||
|
||||
// Margin on each side. Like css, this is outside the bounding box.
|
||||
margins: {
|
||||
left: Number,
|
||||
right: Number,
|
||||
top: Number,
|
||||
bottom: Number,
|
||||
},
|
||||
|
||||
// Amount of padding on the inside of the bounding box (like CSS)
|
||||
paddingLeft: Number,
|
||||
paddingRight: Number,
|
||||
paddingTop: Number,
|
||||
paddingBottom: Number,
|
||||
}
|
||||
```
|
||||
|
||||
#### Scale Interface
|
||||
To work with Chart.js, custom scale types must implement the following interface.
|
||||
|
||||
```javascript
|
||||
{
|
||||
// Determines the data limits. Should set this.min and this.max to be the data max/min
|
||||
determineDataLimits: function() {},
|
||||
|
||||
// Generate tick marks. this.chart is the chart instance. The data object can be accessed as this.chart.data
|
||||
// buildTicks() should create a ticks array on the scale instance, if you intend to use any of the implementations from the base class
|
||||
buildTicks: function() {},
|
||||
|
||||
// Get the value to show for the data at the given index of the the given dataset, ie this.chart.data.datasets[datasetIndex].data[index]
|
||||
getLabelForIndex: function(index, datasetIndex) {},
|
||||
|
||||
// Get the pixel (x coordinate for horizontal scale, y coordinate for vertical scales) for a given value
|
||||
// @param index: index into the ticks array
|
||||
// @param includeOffset: if true, get the pixel halway between the given tick and the next
|
||||
getPixelForTick: function(index, includeOffset) {},
|
||||
|
||||
// Get the pixel (x coordinate for horizontal scale, y coordinate for vertical scales) for a given value
|
||||
// @param value : the value to get the pixel for
|
||||
// @param index : index into the data array of the value
|
||||
// @param datasetIndex : index of the dataset the value comes from
|
||||
// @param includeOffset : if true, get the pixel halway between the given tick and the next
|
||||
getPixelForValue: function(value, index, datasetIndex, includeOffset) {}
|
||||
}
|
||||
```
|
||||
|
||||
Optionally, the following methods may also be overwritten, but an implementation is already provided by the `Chart.Scale` base class.
|
||||
|
||||
```javascript
|
||||
// Transform the ticks array of the scale instance into strings. The default implementation simply calls this.options.ticks.callback(numericalTick, index, ticks);
|
||||
convertTicksToLabels: function() {},
|
||||
|
||||
// Determine how much the labels will rotate by. The default implementation will only rotate labels if the scale is horizontal.
|
||||
calculateTickRotation: function() {},
|
||||
|
||||
// Fits the scale into the canvas.
|
||||
// this.maxWidth and this.maxHeight will tell you the maximum dimensions the scale instance can be. Scales should endeavour to be as efficient as possible with canvas space.
|
||||
// this.margins is the amount of space you have on either side of your scale that you may expand in to. This is used already for calculating the best label rotation
|
||||
// You must set this.minSize to be the size of your scale. It must be an object containing 2 properties: width and height.
|
||||
// You must set this.width to be the width and this.height to be the height of the scale
|
||||
fit: function() {},
|
||||
|
||||
// Draws the scale onto the canvas. this.(left|right|top|bottom) will have been populated to tell you the area on the canvas to draw in
|
||||
// @param chartArea : an object containing four properties: left, right, top, bottom. This is the rectangle that lines, bars, etc will be drawn in. It may be used, for example, to draw grid lines.
|
||||
draw: function(chartArea) {},
|
||||
```
|
||||
|
||||
The Core.Scale base class also has some utility functions that you may find useful.
|
||||
```javascript
|
||||
{
|
||||
// Returns true if the scale instance is horizontal
|
||||
isHorizontal: function() {},
|
||||
|
||||
// Get the correct value from the value from this.chart.data.datasets[x].data[]
|
||||
// If dataValue is an object, returns .x or .y depending on the return of isHorizontal()
|
||||
// If the value is undefined, returns NaN
|
||||
// Otherwise returns the value.
|
||||
// Note that in all cases, the returned value is not guaranteed to be a Number
|
||||
getRightValue: function(dataValue) {},
|
||||
}
|
||||
```
|
||||
|
||||
### Writing new chart types
|
||||
|
||||
Chart.js 1.0 has been rewritten to provide a platform for developers to create their own custom chart types, and be able to share and utilise them through the Chart.js API.
|
||||
|
||||
The format is relatively simple, there are a set of utility helper methods under `Chart.helpers`, including things such as looping over collections, requesting animation frames, and easing equations.
|
||||
|
||||
On top of this, there are also some simple base classes of Chart elements, these all extend from `Chart.Element`, and include things such as points, bars and scales.
|
||||
Chart.js 2.0 introduces the concept of controllers for each dataset. Like scales, new controllers can be written as needed.
|
||||
|
||||
```javascript
|
||||
Chart.Type.extend({
|
||||
// Passing in a name registers this chart in the Chart namespace
|
||||
name: "Scatter",
|
||||
// Providing a defaults will also register the deafults in the chart namespace
|
||||
defaults : {
|
||||
options: "Here",
|
||||
available: "at this.options"
|
||||
},
|
||||
// Initialize is fired when the chart is initialized - Data is passed in as a parameter
|
||||
// Config is automatically merged by the core of Chart.js, and is available at this.options
|
||||
initialize: function(data){
|
||||
this.chart.ctx // The drawing context for this chart
|
||||
this.chart.canvas // the canvas node for this chart
|
||||
},
|
||||
// Used to draw something on the canvas
|
||||
draw: function() {
|
||||
}
|
||||
Chart.controllers.MyType = Chart.DatasetController.extend({
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Now we can create a new instance of our chart, using the Chart.js API
|
||||
new Chart(ctx).Scatter(data);
|
||||
// initialize is now run
|
||||
new Chart(ctx, {
|
||||
// this is the string the constructor was registered at, ie Chart.controllers.MyType
|
||||
type: 'MyType',
|
||||
data: data,
|
||||
options: options
|
||||
});
|
||||
```
|
||||
|
||||
#### Dataset Controller Interface
|
||||
|
||||
Dataset controllers must implement the following interface.
|
||||
|
||||
```javascript
|
||||
{
|
||||
// Create elements for each piece of data in the dataset. Store elements in an array on the dataset as dataset.metaData
|
||||
addElements: function() {},
|
||||
|
||||
// Create a single element for the data at the given index and reset its state
|
||||
addElementAndReset: function(index) {},
|
||||
|
||||
// Draw the representation of the dataset
|
||||
// @param ease : if specified, this number represents how far to transition elements. See the implementation of draw() in any of the provided controllers to see how this should be used
|
||||
draw: function(ease) {},
|
||||
|
||||
// Remove hover styling from the given element
|
||||
removeHoverStyle: function(element) {},
|
||||
|
||||
// Add hover styling to the given element
|
||||
setHoverStyle: function(element) {},
|
||||
|
||||
// Update the elements in response to new data
|
||||
// @param reset : if true, put the elements into a reset state so they can animate to their final values
|
||||
update: function(reset) {},
|
||||
}
|
||||
```
|
||||
|
||||
The following methods may optionally be overridden by derived dataset controllers
|
||||
```javascript
|
||||
{
|
||||
// Initializes the controller
|
||||
initialize: function(chart, datasetIndex) {},
|
||||
|
||||
// Ensures that the dataset represented by this controller is linked to a scale. Overridden to helpers.noop in the polar area and doughnut controllers as these
|
||||
// chart types using a single scale
|
||||
linkScales: function() {},
|
||||
|
||||
// Called by the main chart controller when an update is triggered. The default implementation handles the number of data points changing and creating elements appropriately.
|
||||
buildOrUpdateElements: function() {}
|
||||
}
|
||||
```
|
||||
|
||||
### Extending existing chart types
|
||||
|
||||
We can also extend existing chart types, and expose them to the API in the same way. Let's say for example, we might want to run some more code when we initialize every Line chart.
|
||||
Extending or replacing an existing controller type is easy. Simply replace the constructor for one of the built in types with your own.
|
||||
|
||||
```javascript
|
||||
// Notice now we're extending the particular Line chart type, rather than the base class.
|
||||
Chart.types.Line.extend({
|
||||
// Passing in a name registers this chart in the Chart namespace in the same way
|
||||
name: "LineAlt",
|
||||
initialize: function(data){
|
||||
console.log('My Line chart extension');
|
||||
Chart.types.Line.prototype.initialize.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
The built in controller types are:
|
||||
* `Chart.controllers.line`
|
||||
* `Chart.controllers.bar`
|
||||
* `Chart.controllers.radar`
|
||||
* `Chart.controllers.doughnut`
|
||||
* `Chart.controllers.polarArea`
|
||||
* `Chart.controllers.bubble`
|
||||
|
||||
// Creates a line chart in the same way
|
||||
new Chart(ctx).LineAlt(data);
|
||||
// but this logs 'My Line chart extension' in the console.
|
||||
```
|
||||
#### Bar Controller
|
||||
The bar controller has a special property that you should be aware of. To correctly calculate the width of a bar, the controller must determine the number of datasets that map to bars. To do this, the bar controller attaches a property `bar` to the dataset during initialization. If you are creating a replacement or updated bar controller, you should do the same. This will ensure that charts with regular bars and your new derived bars will work seamlessly.
|
||||
|
||||
### Community extensions
|
||||
### Building Chart.js
|
||||
|
||||
- <a href="https://github.com/Regaddi/Chart.StackedBar.js" target="_blank">Stacked Bar Chart</a> by <a href="https://twitter.com/Regaddi" target="_blank">@Regaddi</a>
|
||||
- <a href="https://github.com/tannerlinsley/Chart.StackedArea.js" target="_blank">Stacked Bar Chart</a> by <a href="https://twitter.com/tannerlinsley" target="_blank">@tannerlinsley</a>
|
||||
- <a href="https://github.com/CAYdenberg/Chart.js" target="_blank">Error bars (bar and line charts)</a> by <a href="https://twitter.com/CAYdenberg" target="_blank">@CAYdenberg</a>
|
||||
- <a href="http://dima117.github.io/Chart.Scatter/" target="_blank">Scatter chart (number & date scales are supported)</a> by <a href="https://github.com/dima117" target="_blank">@dima117</a>
|
||||
|
||||
### Creating custom builds
|
||||
|
||||
Chart.js uses <a href="http://gulpjs.com/" target="_blank">gulp</a> to build the library into a single JavaScript file. We can use this same build script with custom parameters in order to build a custom version.
|
||||
Chart.js uses <a href="http://gulpjs.com/" target="_blank">gulp</a> to build the library into a single JavaScript file.
|
||||
|
||||
Firstly, we need to ensure development dependencies are installed. With node and npm installed, after cloning the Chart.js repo to a local directory, and navigating to that directory in the command line, we can run the following:
|
||||
|
||||
@@ -176,12 +379,8 @@ npm install -g gulp
|
||||
|
||||
This will install the local development dependencies for Chart.js, along with a CLI for the JavaScript task runner <a href="http://gulpjs.com/" target="_blank">gulp</a>.
|
||||
|
||||
Now, we can run the `gulp build` task, and pass in a comma seperated list of types as an argument to build a custom version of Chart.js with only specified chart types.
|
||||
|
||||
Here we will create a version of Chart.js with only Line, Radar and Bar charts included:
|
||||
Now, we can run the `gulp build` task.
|
||||
|
||||
```bash
|
||||
gulp build --types=Line,Radar,Bar
|
||||
gulp build
|
||||
```
|
||||
|
||||
This will output to the `/custom` directory, and write two files, Chart.js, and Chart.min.js with only those chart types included.
|
||||
|
||||
+118
-117
@@ -1,47 +1,35 @@
|
||||
var gulp = require('gulp'),
|
||||
concat = require('gulp-concat'),
|
||||
uglify = require('gulp-uglify'),
|
||||
util = require('gulp-util'),
|
||||
jshint = require('gulp-jshint'),
|
||||
size = require('gulp-size'),
|
||||
connect = require('gulp-connect'),
|
||||
replace = require('gulp-replace'),
|
||||
htmlv = require('gulp-html-validator'),
|
||||
inquirer = require('inquirer'),
|
||||
semver = require('semver'),
|
||||
exec = require('child_process').exec,
|
||||
fs = require('fs'),
|
||||
package = require('./package.json'),
|
||||
bower = require('./bower.json'),
|
||||
karma = require('gulp-karma');
|
||||
concat = require('gulp-concat'),
|
||||
uglify = require('gulp-uglify'),
|
||||
util = require('gulp-util'),
|
||||
jshint = require('gulp-jshint'),
|
||||
size = require('gulp-size'),
|
||||
connect = require('gulp-connect'),
|
||||
replace = require('gulp-replace'),
|
||||
htmlv = require('gulp-html-validator'),
|
||||
inquirer = require('inquirer'),
|
||||
semver = require('semver'),
|
||||
exec = require('child_process').exec,
|
||||
fs = require('fs'),
|
||||
package = require('./package.json'),
|
||||
bower = require('./bower.json'),
|
||||
karma = require('gulp-karma'),
|
||||
browserify = require('browserify'),
|
||||
streamify = require('gulp-streamify'),
|
||||
source = require('vinyl-source-stream'),
|
||||
merge = require('merge-stream');
|
||||
|
||||
var srcDir = './src/';
|
||||
var outDir = './dist/';
|
||||
var testDir = './test/';
|
||||
/*
|
||||
* Usage : gulp build --types=Bar,Line,Doughnut
|
||||
* Output: - A built Chart.js file with Core and types Bar, Line and Doughnut concatenated together
|
||||
* - A minified version of this code, in Chart.min.js
|
||||
*/
|
||||
|
||||
var srcFiles = [
|
||||
'./node_modules/color/dist/color.min.js',
|
||||
'./src/core/core.js',
|
||||
'./src/core/core.helpers.js',
|
||||
'./src/core/core.element.js',
|
||||
'./src/core/**',
|
||||
'./src/controllers/**',
|
||||
'./src/scales/**',
|
||||
'./src/elements/**',
|
||||
'./src/charts/**',
|
||||
];
|
||||
|
||||
var preTestFiles = [
|
||||
'./node_modules/moment/min/moment.min.js',
|
||||
'./node_modules/moment/min/moment.min.js',
|
||||
];
|
||||
|
||||
var testFiles = [
|
||||
'./test/mockContext.js',
|
||||
'./test/*.js'
|
||||
'./test/mockContext.js',
|
||||
'./test/*.js'
|
||||
];
|
||||
|
||||
gulp.task('build', buildTask);
|
||||
@@ -66,18 +54,30 @@ gulp.task('default', ['build', 'watch']);
|
||||
|
||||
function buildTask() {
|
||||
|
||||
var isCustom = !!(util.env.types),
|
||||
outputDir = (isCustom) ? 'custom' : '.';
|
||||
var bundled = browserify('./src/Chart.js')
|
||||
.bundle()
|
||||
.pipe(source('Chart.bundle.js'))
|
||||
.pipe(streamify(replace('{{ version }}', package.version)))
|
||||
.pipe(gulp.dest(outDir))
|
||||
.pipe(streamify(uglify({
|
||||
preserveComments: 'some'
|
||||
})))
|
||||
.pipe(streamify(concat('Chart.bundle.min.js')))
|
||||
.pipe(gulp.dest(outDir));
|
||||
|
||||
return gulp.src(srcFiles)
|
||||
.pipe(concat('Chart.js'))
|
||||
.pipe(replace('{{ version }}', package.version))
|
||||
.pipe(gulp.dest(outputDir))
|
||||
.pipe(uglify({
|
||||
preserveComments: 'some'
|
||||
}))
|
||||
.pipe(concat('Chart.min.js'))
|
||||
.pipe(gulp.dest(outputDir));
|
||||
var nonBundled = browserify('./src/Chart.js')
|
||||
.ignore('moment')
|
||||
.bundle()
|
||||
.pipe(source('Chart.js'))
|
||||
.pipe(streamify(replace('{{ version }}', package.version)))
|
||||
.pipe(gulp.dest(outDir))
|
||||
.pipe(streamify(uglify({
|
||||
preserveComments: 'some'
|
||||
})))
|
||||
.pipe(streamify(concat('Chart.min.js')))
|
||||
.pipe(gulp.dest(outDir));
|
||||
|
||||
return merge(bundled, nonBundled);
|
||||
|
||||
}
|
||||
|
||||
@@ -87,120 +87,121 @@ function buildTask() {
|
||||
* Output: - New version number written into package.json & bower.json
|
||||
*/
|
||||
function bumpTask(complete) {
|
||||
util.log('Current version:', util.colors.cyan(package.version));
|
||||
var choices = ['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'].map(function(versionType) {
|
||||
return versionType + ' (v' + semver.inc(package.version, versionType) + ')';
|
||||
});
|
||||
inquirer.prompt({
|
||||
type: 'list',
|
||||
name: 'version',
|
||||
message: 'What version update would you like?',
|
||||
choices: choices
|
||||
}, function(res) {
|
||||
var increment = res.version.split(' ')[0],
|
||||
newVersion = semver.inc(package.version, increment);
|
||||
util.log('Current version:', util.colors.cyan(package.version));
|
||||
var choices = ['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'].map(function(versionType) {
|
||||
return versionType + ' (v' + semver.inc(package.version, versionType) + ')';
|
||||
});
|
||||
inquirer.prompt({
|
||||
type: 'list',
|
||||
name: 'version',
|
||||
message: 'What version update would you like?',
|
||||
choices: choices
|
||||
}, function(res) {
|
||||
var increment = res.version.split(' ')[0],
|
||||
newVersion = semver.inc(package.version, increment);
|
||||
|
||||
// Set the new versions into the bower/package object
|
||||
package.version = newVersion;
|
||||
bower.version = newVersion;
|
||||
// Set the new versions into the bower/package object
|
||||
package.version = newVersion;
|
||||
bower.version = newVersion;
|
||||
|
||||
// Write these to their own files, then build the output
|
||||
fs.writeFileSync('package.json', JSON.stringify(package, null, 2));
|
||||
fs.writeFileSync('bower.json', JSON.stringify(bower, null, 2));
|
||||
// Write these to their own files, then build the output
|
||||
fs.writeFileSync('package.json', JSON.stringify(package, null, 2));
|
||||
fs.writeFileSync('bower.json', JSON.stringify(bower, null, 2));
|
||||
|
||||
complete();
|
||||
});
|
||||
complete();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function releaseTask() {
|
||||
exec('git tag -a v' + package.version);
|
||||
exec('git tag -a v' + package.version);
|
||||
}
|
||||
|
||||
|
||||
function jshintTask() {
|
||||
return gulp.src(srcDir + '**/*.js')
|
||||
.pipe(jshint())
|
||||
.pipe(jshint.reporter('default'));
|
||||
return gulp.src(srcDir + '**/*.js')
|
||||
.pipe(jshint('config.jshintrc'))
|
||||
.pipe(jshint.reporter('jshint-stylish'))
|
||||
.pipe(jshint.reporter('fail'));
|
||||
}
|
||||
|
||||
|
||||
function validHTMLTask() {
|
||||
return gulp.src('samples/*.html')
|
||||
.pipe(htmlv());
|
||||
return gulp.src('samples/*.html')
|
||||
.pipe(htmlv());
|
||||
}
|
||||
|
||||
|
||||
function unittestTask() {
|
||||
var files = srcFiles.slice();
|
||||
Array.prototype.unshift.apply(files, preTestFiles);
|
||||
Array.prototype.push.apply(files, testFiles);
|
||||
var files = ['./src/**/*.js'];
|
||||
Array.prototype.unshift.apply(files, preTestFiles);
|
||||
Array.prototype.push.apply(files, testFiles);
|
||||
|
||||
return gulp.src(files)
|
||||
.pipe(karma({
|
||||
configFile: 'karma.conf.ci.js',
|
||||
action: 'run'
|
||||
}));
|
||||
return gulp.src(files)
|
||||
.pipe(karma({
|
||||
configFile: 'karma.conf.ci.js',
|
||||
action: 'run'
|
||||
}));
|
||||
}
|
||||
|
||||
function unittestWatchTask() {
|
||||
var files = srcFiles.slice();
|
||||
Array.prototype.unshift.apply(files, preTestFiles);
|
||||
Array.prototype.push.apply(files, testFiles);
|
||||
var files = ['./src/**/*.js'];
|
||||
Array.prototype.unshift.apply(files, preTestFiles);
|
||||
Array.prototype.push.apply(files, testFiles);
|
||||
|
||||
return gulp.src(files)
|
||||
.pipe(karma({
|
||||
configFile: 'karma.conf.js',
|
||||
action: 'watch'
|
||||
}));
|
||||
return gulp.src(files)
|
||||
.pipe(karma({
|
||||
configFile: 'karma.conf.js',
|
||||
action: 'watch'
|
||||
}));
|
||||
}
|
||||
|
||||
function coverageTask() {
|
||||
var files = srcFiles.slice();
|
||||
Array.prototype.unshift.apply(files, preTestFiles);
|
||||
Array.prototype.push.apply(files, testFiles);
|
||||
var files = ['./src/**/*.js'];
|
||||
Array.prototype.unshift.apply(files, preTestFiles);
|
||||
Array.prototype.push.apply(files, testFiles);
|
||||
|
||||
return gulp.src(files)
|
||||
.pipe(karma({
|
||||
configFile: 'karma.coverage.conf.js',
|
||||
action: 'run'
|
||||
}));
|
||||
return gulp.src(files)
|
||||
.pipe(karma({
|
||||
configFile: 'karma.coverage.conf.js',
|
||||
action: 'run'
|
||||
}));
|
||||
}
|
||||
|
||||
function librarySizeTask() {
|
||||
return gulp.src('Chart.min.js')
|
||||
.pipe(size({
|
||||
gzip: true
|
||||
}));
|
||||
return gulp.src('dist/Chart.bundle.min.js')
|
||||
.pipe(size({
|
||||
gzip: true
|
||||
}));
|
||||
}
|
||||
|
||||
function moduleSizesTask() {
|
||||
return gulp.src(srcDir + '*.js')
|
||||
.pipe(uglify({
|
||||
preserveComments: 'some'
|
||||
}))
|
||||
.pipe(size({
|
||||
showFiles: true,
|
||||
gzip: true
|
||||
}));
|
||||
return gulp.src(srcDir + '**/*.js')
|
||||
.pipe(uglify({
|
||||
preserveComments: 'some'
|
||||
}))
|
||||
.pipe(size({
|
||||
showFiles: true,
|
||||
gzip: true
|
||||
}));
|
||||
}
|
||||
|
||||
function watchTask() {
|
||||
if (util.env.test) {
|
||||
return gulp.watch('./src/**', ['build', 'unittest', 'unittestWatch']);
|
||||
}
|
||||
return gulp.watch('./src/**', ['build']);
|
||||
if (util.env.test) {
|
||||
return gulp.watch('./src/**', ['build', 'unittest', 'unittestWatch']);
|
||||
}
|
||||
return gulp.watch('./src/**', ['build']);
|
||||
}
|
||||
|
||||
function serverTask() {
|
||||
connect.server({
|
||||
port: 8000
|
||||
});
|
||||
connect.server({
|
||||
port: 8000
|
||||
});
|
||||
}
|
||||
|
||||
// Convenience task for opening the project straight from the command line
|
||||
|
||||
function _openTask() {
|
||||
exec('open http://localhost:8000');
|
||||
exec('subl .');
|
||||
exec('open http://localhost:8000');
|
||||
exec('subl .');
|
||||
}
|
||||
|
||||
+7
-1
@@ -7,8 +7,14 @@ module.exports = function(config) {
|
||||
flags: ['--no-sandbox']
|
||||
}
|
||||
},
|
||||
frameworks: ['jasmine'],
|
||||
frameworks: ['browserify', 'jasmine'],
|
||||
reporters: ['progress', 'html'],
|
||||
preprocessors: {
|
||||
'src/**/*.js': ['browserify']
|
||||
},
|
||||
browserify: {
|
||||
debug: true
|
||||
}
|
||||
};
|
||||
|
||||
if (process.env.TRAVIS) {
|
||||
|
||||
+8
-1
@@ -1,7 +1,14 @@
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
browsers: ['Chrome', 'Firefox'],
|
||||
frameworks: ['jasmine'],
|
||||
frameworks: ['browserify', 'jasmine'],
|
||||
reporters: ['progress', 'html'],
|
||||
|
||||
preprocessors: {
|
||||
'src/**/*.js': ['browserify']
|
||||
},
|
||||
browserify: {
|
||||
debug: true
|
||||
}
|
||||
});
|
||||
};
|
||||
+35
-10
@@ -1,18 +1,43 @@
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
browsers: ['Chrome', 'Firefox'],
|
||||
var configuration = {
|
||||
browsers: ['Firefox'],
|
||||
|
||||
coverageReporter: {
|
||||
type: 'html',
|
||||
dir: 'coverage/'
|
||||
},
|
||||
|
||||
frameworks: ['jasmine'],
|
||||
frameworks: ['browserify', 'jasmine'],
|
||||
|
||||
preprocessors: {
|
||||
'src/**/*.js': ['coverage']
|
||||
'src/**/*.js': ['browserify']
|
||||
},
|
||||
browserify: {
|
||||
debug: true,
|
||||
transform: [['browserify-istanbul', {
|
||||
instrumenterConfig: {
|
||||
embed: true
|
||||
}
|
||||
}]]
|
||||
},
|
||||
|
||||
reporters: ['progress', 'coverage'],
|
||||
});
|
||||
coverageReporter: {
|
||||
dir: 'coverage/',
|
||||
reporters: [
|
||||
{ type: 'html', subdir: 'report-html' },
|
||||
{ type: 'lcovonly', subdir: '.', file: 'lcov.info' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// If on the CI, use the CI chrome launcher
|
||||
if (process.env.TRAVIS) {
|
||||
configuration.browsers.push('Chrome_travis_ci');
|
||||
configuration.customLaunchers = {
|
||||
Chrome_travis_ci: {
|
||||
base: 'Chrome',
|
||||
flags: ['--no-sandbox']
|
||||
}
|
||||
};
|
||||
} else {
|
||||
configuration.browsers.push('Chrome');
|
||||
}
|
||||
|
||||
config.set(configuration);
|
||||
};
|
||||
+16
-6
@@ -2,15 +2,17 @@
|
||||
"name": "chart.js",
|
||||
"homepage": "http://www.chartjs.org",
|
||||
"description": "Simple HTML5 charts using the canvas element.",
|
||||
"version": "2.0.0-beta",
|
||||
"main": "Chart.js",
|
||||
"version": "2.0.0",
|
||||
"main": "src/chart.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nnnick/Chart.js.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"color": "git://github.com/chartjs/color",
|
||||
"gulp": "3.5.x",
|
||||
"browserify": "^13.0.0",
|
||||
"browserify-istanbul": "^0.2.1",
|
||||
"coveralls": "^2.11.6",
|
||||
"gulp": "3.9.x",
|
||||
"gulp-concat": "~2.1.x",
|
||||
"gulp-connect": "~2.0.5",
|
||||
"gulp-html-validator": "^0.0.2",
|
||||
@@ -18,24 +20,32 @@
|
||||
"gulp-karma": "0.0.4",
|
||||
"gulp-replace": "^0.4.0",
|
||||
"gulp-size": "~0.4.0",
|
||||
"gulp-streamify": "^1.0.2",
|
||||
"gulp-uglify": "~0.2.x",
|
||||
"gulp-umd": "~0.2.0",
|
||||
"gulp-util": "~2.2.x",
|
||||
"inquirer": "^0.5.1",
|
||||
"jasmine": "^2.3.2",
|
||||
"jasmine-core": "^2.3.4",
|
||||
"jquery": "^2.1.4",
|
||||
"jshint-stylish": "~2.1.0",
|
||||
"karma": "^0.12.37",
|
||||
"karma-browserify": "^5.0.1",
|
||||
"karma-chrome-launcher": "^0.2.0",
|
||||
"karma-coverage": "^0.5.1",
|
||||
"karma-firefox-launcher": "^0.1.6",
|
||||
"karma-jasmine": "^0.3.6",
|
||||
"karma-jasmine-html-reporter": "^0.1.8",
|
||||
"semver": "^3.0.1"
|
||||
"merge-stream": "^1.0.0",
|
||||
"semver": "^3.0.1",
|
||||
"vinyl-source-stream": "^1.1.0",
|
||||
"watchify": "^3.7.0"
|
||||
},
|
||||
"spm": {
|
||||
"main": "Chart.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"chartjs-color": "^1.0.2",
|
||||
"moment": "^2.10.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title> Animation Callbacks </title>
|
||||
<script src="../../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width: 75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
<progress id="animationProgress" max="1" value="0" style="width: 100%"></progress>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addDataset">Add Dataset</button>
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<script>
|
||||
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
||||
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100);
|
||||
};
|
||||
var randomColorFactor = function() {
|
||||
return Math.round(Math.random() * 255);
|
||||
};
|
||||
var randomColor = function(opacity) {
|
||||
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
|
||||
};
|
||||
|
||||
var $progress = $('#animationProgress');
|
||||
|
||||
var config = {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [{
|
||||
label: "My First dataset ",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
fill: false,
|
||||
borderDash: [5, 5],
|
||||
}, {
|
||||
label: "My Second dataset ",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
title:{
|
||||
display:true,
|
||||
text:"Chart.js Line Chart - Animation Progress Bar"
|
||||
},
|
||||
animation: {
|
||||
duration: 2000,
|
||||
onProgress: function(animation) {
|
||||
$progress.attr({
|
||||
value: animation.animationObject.currentStep / animation.animationObject.numSteps,
|
||||
});
|
||||
},
|
||||
onComplete: function(animation) {
|
||||
window.setTimeout(function() {
|
||||
$progress.attr({
|
||||
value: 0
|
||||
});
|
||||
}, 2000);
|
||||
}
|
||||
},
|
||||
tooltips: {
|
||||
mode: 'label',
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
scaleLabel: {
|
||||
show: true,
|
||||
labelString: 'Month'
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
scaleLabel: {
|
||||
show: true,
|
||||
labelString: 'Value'
|
||||
},
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.borderColor = randomColor(0.4);
|
||||
dataset.backgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderColor = randomColor(0.7);
|
||||
dataset.pointBackgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
return randomScalingFactor();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
var newDataset = {
|
||||
label: 'Dataset ' + config.data.datasets.length,
|
||||
borderColor: randomColor(0.4),
|
||||
backgroundColor: randomColor(0.5),
|
||||
pointBorderColor: randomColor(0.7),
|
||||
pointBackgroundColor: randomColor(0.5),
|
||||
pointBorderWidth: 1,
|
||||
data: [],
|
||||
};
|
||||
|
||||
for (var index = 0; index < config.data.labels.length; ++index) {
|
||||
newDataset.data.push(randomScalingFactor());
|
||||
}
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
var month = MONTHS[config.data.labels.length % MONTHS.length];
|
||||
config.data.labels.push(month);
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data.push(randomScalingFactor());
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
config.data.labels.splice(-1, 1); // remove the label first
|
||||
|
||||
config.data.datasets.forEach(function(dataset, datasetIndex) {
|
||||
dataset.data.pop();
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -3,13 +3,20 @@
|
||||
|
||||
<head>
|
||||
<title>Bar Chart Multi Axis</title>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width: 50%">
|
||||
<canvas id="canvas" height="450" width="600"></canvas>
|
||||
<div style="width: 75%">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
@@ -52,6 +59,10 @@
|
||||
hoverMode: 'label',
|
||||
hoverAnimationDuration: 400,
|
||||
stacked: false,
|
||||
title:{
|
||||
display:true,
|
||||
text:"Chart.js Bar Chart - Multi Axis"
|
||||
},
|
||||
scales: {
|
||||
yAxes: [{
|
||||
type: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
|
||||
|
||||
@@ -3,13 +3,20 @@
|
||||
|
||||
<head>
|
||||
<title>Stacked Bar Chart</title>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width: 50%">
|
||||
<canvas id="canvas" height="450" width="600"></canvas>
|
||||
<div style="width: 75%">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
@@ -43,6 +50,10 @@
|
||||
type: 'bar',
|
||||
data: barChartData,
|
||||
options: {
|
||||
title:{
|
||||
display:true,
|
||||
text:"Chart.js Bar Chart - Stacked"
|
||||
},
|
||||
tooltips: {
|
||||
mode: 'label'
|
||||
},
|
||||
|
||||
+30
-31
@@ -3,31 +3,29 @@
|
||||
|
||||
<head>
|
||||
<title>Bar Chart</title>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../Chart.js"></script>
|
||||
<style type="text/css">
|
||||
canvas {
|
||||
border: 1px solid red;
|
||||
}
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container" style="width: 50%; height: 25%;">
|
||||
<canvas id="canvas" height="450" width="600"></canvas>
|
||||
<div id="container" style="width: 75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addDataset">Add Dataset</button>
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<button id="show">Show</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
||||
|
||||
var randomScalingFactor = function() {
|
||||
return (Math.random() > 0.5 ? 1.0 : -1.0) * Math.round(Math.random() * 100);
|
||||
};
|
||||
@@ -57,23 +55,32 @@
|
||||
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myBar.generateLegend());
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myBar = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: barChartData,
|
||||
options: {
|
||||
// Elements options apply to all of the options unless overridden in a dataset
|
||||
// In this case, we are setting the border of each bar to be 2px wide and green
|
||||
elements: {
|
||||
rectangle: {
|
||||
borderWidth: 2,
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderSkipped: 'bottom'
|
||||
}
|
||||
},
|
||||
responsive: true,
|
||||
legend: {
|
||||
position: 'top',
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Chart.js Bar Chart'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
@@ -86,7 +93,6 @@
|
||||
|
||||
});
|
||||
window.myBar.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
@@ -102,12 +108,12 @@
|
||||
|
||||
barChartData.datasets.push(newDataset);
|
||||
window.myBar.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (barChartData.datasets.length > 0) {
|
||||
barChartData.labels.push('data #' + barChartData.labels.length);
|
||||
var month = MONTHS[barChartData.labels.length % MONTHS.length];
|
||||
barChartData.labels.push(month);
|
||||
|
||||
for (var index = 0; index < barChartData.datasets.length; ++index) {
|
||||
//window.myBar.addData(randomScalingFactor(), index);
|
||||
@@ -115,14 +121,12 @@
|
||||
}
|
||||
|
||||
window.myBar.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
barChartData.datasets.splice(0, 1);
|
||||
window.myBar.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
@@ -133,11 +137,6 @@
|
||||
});
|
||||
|
||||
window.myBar.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#show').click(function() {
|
||||
document.getElementById('container').style.display = '';
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
+20
-34
@@ -2,18 +2,20 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Bar Chart</title>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../Chart.js"></script>
|
||||
<title>Bubble Chart</title>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<style type="text/css">
|
||||
canvas {
|
||||
border: 1px solid red;
|
||||
}
|
||||
canvas{
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container" style="width: 100%; height: 25%;">
|
||||
<div id="container" style="width: 75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
@@ -21,13 +23,11 @@
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<button id="show">Show</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var DEFAULT_DATASET_SIZE = 7;
|
||||
|
||||
var addedCount = 0;
|
||||
|
||||
var randomScalingFactor = function() {
|
||||
return (Math.random() > 0.5 ? 1.0 : -1.0) * Math.round(Math.random() * 100);
|
||||
};
|
||||
@@ -107,15 +107,8 @@
|
||||
r: Math.abs(randomScalingFactor()) / 5,
|
||||
}]
|
||||
}]
|
||||
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myChart.generateLegend());
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myChart = new Chart(ctx, {
|
||||
@@ -123,10 +116,12 @@
|
||||
data: bubbleChartData,
|
||||
options: {
|
||||
responsive: true,
|
||||
title:{
|
||||
display:true,
|
||||
text:'Chart.js Bubble Chart'
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
@@ -142,16 +137,17 @@
|
||||
});
|
||||
});
|
||||
window.myChart.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
++addedCount;
|
||||
var newDataset = {
|
||||
label: "My added dataset " + addedCount,
|
||||
backgroundColor: randomColor(),
|
||||
data: []
|
||||
};
|
||||
|
||||
for (var index = 0; index < bubbleChartData.datasets[0].data.length; ++index) {
|
||||
for (var index = 0; index < DEFAULT_DATASET_SIZE; ++index) {
|
||||
newDataset.data.push({
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
@@ -161,14 +157,11 @@
|
||||
|
||||
bubbleChartData.datasets.push(newDataset);
|
||||
window.myChart.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (bubbleChartData.datasets.length > 0) {
|
||||
|
||||
for (var index = 0; index < bubbleChartData.datasets.length; ++index) {
|
||||
//window.myChart.addData(randomScalingFactor(), index);
|
||||
bubbleChartData.datasets[index].data.push({
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
@@ -177,14 +170,12 @@
|
||||
}
|
||||
|
||||
window.myChart.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
bubbleChartData.datasets.splice(0, 1);
|
||||
window.myChart.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
@@ -194,11 +185,6 @@
|
||||
});
|
||||
|
||||
window.myChart.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#show').click(function() {
|
||||
document.getElementById('container').style.display = '';
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -3,13 +3,20 @@
|
||||
|
||||
<head>
|
||||
<title>Combo Bar-Line Chart</title>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width: 50%">
|
||||
<canvas id="canvas" height="450" width="600"></canvas>
|
||||
<div style="width: 75%">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
@@ -51,6 +58,10 @@
|
||||
data: barChartData,
|
||||
options: {
|
||||
responsive: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Chart.js Combo Bar Line Chart'
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Line Chart</title>
|
||||
<script src="../node_modules/moment/min/moment.min.js"></script>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-webkit-box-shadow: 0 0 20px 0 rgba(0, 0, 0, .5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:100%;">
|
||||
<canvas id="canvas" style="width:100%;height:100%"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addDataset">Add Dataset</button>
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100 * (Math.random() > 0.5 ? -1 : 1));
|
||||
};
|
||||
var randomColorFactor = function() {
|
||||
return Math.round(Math.random() * 255);
|
||||
};
|
||||
var randomColor = function(opacity) {
|
||||
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
|
||||
};
|
||||
var newDate = function(days) {
|
||||
var date = new Date();
|
||||
return date.setDate(date.getDate() + days);
|
||||
};
|
||||
var newTimestamp = function(days) {
|
||||
return Date.now() - days * 100000;
|
||||
};
|
||||
|
||||
var config = {
|
||||
type: 'bar',
|
||||
data: {
|
||||
//labels: [newTimestamp(0), newTimestamp(1), newTimestamp(2), newTimestamp(3), newTimestamp(4), newTimestamp(5), newTimestamp(6)], // unix timestamps
|
||||
// labels: [newDate(0), newDate(1), newDate(2), newDate(3), newDate(4), newDate(5), newDate(6)], // Date Objects
|
||||
labels: ["01/01/2015 20:00", "01/02/2015 20:00", "01/03/2015 22:00", "01/05/2015 23:00", "01/07/2015 03:00", "01/08/2015 10:00", "01/10/2015"], // Hours
|
||||
// labels: ["01/01/2015", "01/02/2015", "01/03/2015", "01/06/2015", "01/15/2015", "01/17/2015", "01/30/2015"], // Days
|
||||
// labels: ["12/25/2014", "01/08/2015", "01/15/2015", "01/22/2015", "01/29/2015", "02/05/2015", "02/12/2015"], // Weeks
|
||||
datasets: [{
|
||||
type: 'bar',
|
||||
label: 'Dataset 1',
|
||||
backgroundColor: "rgba(151,187,205,0.5)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
borderColor: 'white',
|
||||
borderWidth: 2
|
||||
}, {
|
||||
type: 'bar',
|
||||
label: 'Dataset 2',
|
||||
backgroundColor: "rgba(151,187,205,0.5)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
borderColor: 'white',
|
||||
borderWidth: 2
|
||||
}, {
|
||||
type: 'line',
|
||||
label: 'Dataset 3',
|
||||
backgroundColor: "rgba(220,220,220,0.5)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}, ]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: "time",
|
||||
display: true,
|
||||
time: {
|
||||
format: 'MM/DD/YYYY HH:mm',
|
||||
// round: 'day'
|
||||
}
|
||||
}, ],
|
||||
yAxes: [{
|
||||
display: true
|
||||
}]
|
||||
},
|
||||
elements: {
|
||||
line: {
|
||||
tension: 0.3
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.borderColor = randomColor(0.4);
|
||||
dataset.backgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderColor = randomColor(0.7);
|
||||
dataset.pointBackgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(config.data);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myLine.generateLegend());
|
||||
}
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
return randomScalingFactor();
|
||||
});
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
var newDataset = {
|
||||
label: 'Dataset ' + config.data.datasets.length,
|
||||
borderColor: randomColor(0.4),
|
||||
backgroundColor: randomColor(0.5),
|
||||
pointBorderColor: randomColor(0.7),
|
||||
pointBackgroundColor: randomColor(0.5),
|
||||
pointBorderWidth: 1,
|
||||
data: [],
|
||||
};
|
||||
|
||||
for (var index = 0; index < config.data.labels.length; ++index) {
|
||||
newDataset.data.push(randomScalingFactor());
|
||||
}
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
config.data.labels.push(
|
||||
myLine.scales['x-axis-0'].labelMoments[myLine.scales['x-axis-0'].labelMoments.length - 1].add(1, 'day')
|
||||
.format('MM/DD/YYYY')
|
||||
);
|
||||
|
||||
for (var index = 0; index < config.data.datasets.length; ++index) {
|
||||
config.data.datasets[index].data.push(randomScalingFactor());
|
||||
}
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
config.data.labels.splice(-1, 1); // remove the label first
|
||||
|
||||
config.data.datasets.forEach(function(dataset, datasetIndex) {
|
||||
config.data.datasets[datasetIndex].data.pop();
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+20
-31
@@ -3,22 +3,19 @@
|
||||
|
||||
<head>
|
||||
<title>Doughnut Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#canvas-holder {
|
||||
width: 30%;
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="canvas-holder" style="width:100%">
|
||||
<div id="canvas-holder" style="width:75%">
|
||||
<canvas id="chart-area" />
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
@@ -26,12 +23,6 @@
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100);
|
||||
@@ -44,6 +35,7 @@
|
||||
};
|
||||
|
||||
var config = {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [
|
||||
@@ -60,6 +52,7 @@
|
||||
"#949FB1",
|
||||
"#4D5360",
|
||||
],
|
||||
label: 'Dataset 1'
|
||||
}, {
|
||||
hidden: true,
|
||||
data: [
|
||||
@@ -76,6 +69,7 @@
|
||||
"#949FB1",
|
||||
"#4D5360",
|
||||
],
|
||||
label: 'Dataset 2'
|
||||
}, {
|
||||
data: [
|
||||
randomScalingFactor(),
|
||||
@@ -91,6 +85,7 @@
|
||||
"#949FB1",
|
||||
"#4D5360",
|
||||
],
|
||||
label: 'Dataset 3'
|
||||
}],
|
||||
labels: [
|
||||
"Red",
|
||||
@@ -101,22 +96,20 @@
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true
|
||||
responsive: true,
|
||||
legend: {
|
||||
position: 'top',
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Chart.js Doughnut Chart'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myDoughnut.generateLegend());
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("chart-area").getContext("2d");
|
||||
window.myDoughnut = Chart.Doughnut(ctx, config);
|
||||
console.log(window.myDoughnut);
|
||||
|
||||
updateLegend();
|
||||
window.myDoughnut = new Chart(ctx, config);
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
@@ -131,13 +124,13 @@
|
||||
});
|
||||
|
||||
window.myDoughnut.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
var newDataset = {
|
||||
backgroundColor: [],
|
||||
data: [],
|
||||
label: 'New dataset ' + config.data.datasets.length,
|
||||
};
|
||||
|
||||
for (var index = 0; index < config.data.labels.length; ++index) {
|
||||
@@ -147,7 +140,6 @@
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myDoughnut.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
@@ -160,14 +152,12 @@
|
||||
});
|
||||
|
||||
window.myDoughnut.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myDoughnut.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
@@ -179,7 +169,6 @@
|
||||
});
|
||||
|
||||
window.myDoughnut.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -3,19 +3,14 @@
|
||||
|
||||
<head>
|
||||
<title>Line Chart with Custom Tooltips</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
#canvas-holder1 {
|
||||
width: 300px;
|
||||
margin: 20px auto;
|
||||
canvas{
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
|
||||
#canvas-holder2 {
|
||||
width: 50%;
|
||||
margin: 20px 25%;
|
||||
}
|
||||
|
||||
#chartjs-tooltip {
|
||||
opacity: 1;
|
||||
position: absolute;
|
||||
@@ -38,16 +33,14 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="canvas-holder1">
|
||||
<canvas id="chart1" width="300" height="100" />
|
||||
<div id="canvas-holder1" style="width:75%;">
|
||||
<canvas id="chart1"/>
|
||||
</div>
|
||||
<script>
|
||||
window.count = 0;
|
||||
Chart.defaults.global.pointHitDetectionRadius = 1;
|
||||
var customTooltips = function(tooltip) {
|
||||
|
||||
console.log(window.count++, tooltip);
|
||||
|
||||
// Tooltip Element
|
||||
var tooltipEl = $('#chartjs-tooltip');
|
||||
|
||||
@@ -131,6 +124,10 @@
|
||||
type: 'line',
|
||||
data: lineChartData,
|
||||
options: {
|
||||
title:{
|
||||
display:true,
|
||||
text:'Chart.js Line Chart - Custom Tooltips'
|
||||
},
|
||||
tooltips: {
|
||||
enabled: false,
|
||||
custom: customTooltips
|
||||
|
||||
@@ -3,19 +3,20 @@
|
||||
|
||||
<head>
|
||||
<title>Line Chart</title>
|
||||
<script src="../node_modules/moment/min/moment.min.js"></script>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-webkit-box-shadow: 0 0 20px 0 rgba(0, 0, 0, .5);
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:100%;">
|
||||
<canvas id="canvas" style="width:100%;height:100%"></canvas>
|
||||
<div style="width:75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
@@ -24,12 +25,8 @@
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100 * (Math.random() > 0.5 ? -1 : 1));
|
||||
};
|
||||
@@ -39,22 +36,11 @@
|
||||
var randomColor = function(opacity) {
|
||||
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
|
||||
};
|
||||
var newDate = function(days) {
|
||||
var date = new Date();
|
||||
return date.setDate(date.getDate() + days);
|
||||
};
|
||||
var newTimestamp = function(days) {
|
||||
return Date.now() - days * 100000;
|
||||
};
|
||||
|
||||
var config = {
|
||||
type: 'line',
|
||||
data: {
|
||||
//labels: [newTimestamp(0), newTimestamp(1), newTimestamp(2), newTimestamp(3), newTimestamp(4), newTimestamp(5), newTimestamp(6)], // unix timestamps
|
||||
// labels: [newDate(0), newDate(1), newDate(2), newDate(3), newDate(4), newDate(5), newDate(6)], // Date Objects
|
||||
labels: ["01/01/2015 20:00", "01/02/2015 21:00", "01/03/2015 22:00", "01/05/2015 23:00", "01/07/2015 03:00", "01/08/2015 10:00", "01/10/2015"], // Hours
|
||||
// labels: ["01/01/2015", "01/02/2015", "01/03/2015", "01/06/2015", "01/15/2015", "01/17/2015", "01/30/2015"], // Days
|
||||
// labels: ["12/25/2014", "01/08/2015", "01/15/2015", "01/22/2015", "01/29/2015", "02/05/2015", "02/12/2015"], // Weeks
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [{
|
||||
label: "My First dataset",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
@@ -63,97 +49,84 @@
|
||||
}, {
|
||||
label: "My Second dataset",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
fill: false,
|
||||
borderDash: [5, 5],
|
||||
}, {
|
||||
label: "Dataset with point data",
|
||||
data: [{
|
||||
x: "12/31/2014 06:00",
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: "01/04/2015 13:00",
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: "01/07/2015 01:15",
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: "01/15/2015 01:15",
|
||||
y: randomScalingFactor()
|
||||
}],
|
||||
fill: false
|
||||
label: "My Third dataset",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
fill: false,
|
||||
}, {
|
||||
label: "My Fourth dataset",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
fill: false,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
legend: {
|
||||
position: 'bottom',
|
||||
},
|
||||
hover: {
|
||||
mode: 'label'
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: "time",
|
||||
display: true,
|
||||
time: {
|
||||
format: 'MM/DD/YYYY HH:mm',
|
||||
// round: 'day'
|
||||
},
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Date'
|
||||
labelString: 'Month'
|
||||
}
|
||||
}, ],
|
||||
}],
|
||||
yAxes: [{
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'value'
|
||||
labelString: 'Value'
|
||||
}
|
||||
}]
|
||||
},
|
||||
elements: {
|
||||
line: {
|
||||
tension: 0.3
|
||||
}
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Chart.js Line Chart - Legend'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.borderColor = randomColor(0.4);
|
||||
dataset.backgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderColor = randomColor(0.7);
|
||||
dataset.pointBackgroundColor = randomColor(0.5);
|
||||
var background = randomColor(0.5);
|
||||
dataset.borderColor = background;
|
||||
dataset.backgroundColor = background;
|
||||
dataset.pointBorderColor = background;
|
||||
dataset.pointBackgroundColor = background;
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(config.data);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myLine.generateLegend());
|
||||
}
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
return randomScalingFactor();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
var background = randomColor(0.5);
|
||||
var newDataset = {
|
||||
label: 'Dataset ' + config.data.datasets.length,
|
||||
borderColor: randomColor(0.4),
|
||||
backgroundColor: randomColor(0.5),
|
||||
pointBorderColor: randomColor(0.7),
|
||||
pointBackgroundColor: randomColor(0.5),
|
||||
borderColor: background,
|
||||
backgroundColor: background,
|
||||
pointBorderColor: background,
|
||||
pointBackgroundColor: background,
|
||||
pointBorderWidth: 1,
|
||||
fill: false,
|
||||
data: [],
|
||||
};
|
||||
|
||||
@@ -163,31 +136,24 @@
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
config.data.labels.push(
|
||||
myLine.scales['x-axis-0'].labelMoments[myLine.scales['x-axis-0'].labelMoments.length - 1]
|
||||
.clone()
|
||||
.add(1, 'day')
|
||||
.format('MM/DD/YYYY HH:mm')
|
||||
);
|
||||
var month = MONTHS[config.data.labels.length % MONTHS.length];
|
||||
config.data.labels.push(month);
|
||||
|
||||
for (var index = 0; index < config.data.datasets.length; ++index) {
|
||||
config.data.datasets[index].data.push(randomScalingFactor());
|
||||
}
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data.push(randomScalingFactor());
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
@@ -198,7 +164,6 @@
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
@@ -3,33 +3,29 @@
|
||||
|
||||
<head>
|
||||
<title>Line Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-webkit-box-shadow: 0 0 20px 0 rgba(0, 0, 0, .5);
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:50%;">
|
||||
<canvas id="canvas" style="width:100%;height:100%"></canvas>
|
||||
<div style="width:75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addDataset">Add Dataset</button>
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
||||
|
||||
var randomScalingFactor = function() {
|
||||
return Math.ceil(Math.random() * 10.0) * Math.pow(10, Math.ceil(Math.random() * 5));
|
||||
};
|
||||
@@ -56,6 +52,10 @@
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
title:{
|
||||
display:true,
|
||||
text:'Chart.js Line Chart - Logarithmic'
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
display: true,
|
||||
@@ -84,21 +84,11 @@
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(config.data);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myLine.generateLegend());
|
||||
}
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
@@ -108,7 +98,6 @@
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
@@ -128,26 +117,24 @@
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
config.data.labels.push('dataset #' + config.data.labels.length);
|
||||
var month = MONTHS[config.data.labels.length % MONTHS.length];
|
||||
config.data.labels.push(month);
|
||||
|
||||
for (var index = 0; index < config.data.datasets.length; ++index) {
|
||||
config.data.datasets[index].data.push(randomScalingFactor());
|
||||
}
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
@@ -158,7 +145,6 @@
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -3,13 +3,20 @@
|
||||
|
||||
<head>
|
||||
<title>Line Chart Multiple Axes</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:50%;">
|
||||
<canvas id="canvas" style="width:100%;height:100%"></canvas>
|
||||
<div style="width:75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<script>
|
||||
@@ -41,8 +48,6 @@
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(lineChartData);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = Chart.Line(ctx, {
|
||||
@@ -51,6 +56,10 @@
|
||||
responsive: true,
|
||||
hoverMode: 'label',
|
||||
stacked: false,
|
||||
title:{
|
||||
display:true,
|
||||
text:'Chart.js Line Chart - Multi Axis'
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
display: true,
|
||||
|
||||
@@ -3,18 +3,20 @@
|
||||
|
||||
<head>
|
||||
<title>Line Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-webkit-box-shadow: 0 0 20px 0 rgba(0, 0, 0, .5);
|
||||
}
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:100%;">
|
||||
<canvas id="canvas" style="width:100%;height:100%"></canvas>
|
||||
<div style="width:75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
@@ -23,12 +25,9 @@
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
||||
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100);
|
||||
//return 0;
|
||||
@@ -60,6 +59,10 @@
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
title:{
|
||||
display:true,
|
||||
text:'Chart.js Line Chart - Skip Points'
|
||||
},
|
||||
tooltips: {
|
||||
mode: 'label',
|
||||
},
|
||||
@@ -93,21 +96,11 @@
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(config.data);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myLine.generateLegend());
|
||||
}
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
@@ -117,7 +110,6 @@
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
@@ -137,26 +129,24 @@
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
config.data.labels.push('dataset #' + config.data.labels.length);
|
||||
var month = MONTHS[config.data.labels.length % MONTHS.length];
|
||||
config.data.labels.push(month);
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data.push(randomScalingFactor());
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
@@ -167,7 +157,6 @@
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -3,18 +3,20 @@
|
||||
|
||||
<head>
|
||||
<title>Line Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-webkit-box-shadow: 0 0 20px 0 rgba(0, 0, 0, .5);
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:100%;">
|
||||
<canvas id="canvas" style="width:100%;height:100%"></canvas>
|
||||
<div style="width:75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
@@ -23,12 +25,9 @@
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
||||
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100 * (Math.random() > 0.5 ? -1 : 1));
|
||||
};
|
||||
@@ -59,6 +58,10 @@
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
title:{
|
||||
display:true,
|
||||
text:"Chart.js Line Chart - Stacked Area"
|
||||
},
|
||||
tooltips: {
|
||||
mode: 'label',
|
||||
},
|
||||
@@ -92,21 +95,11 @@
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(config.data);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myLine.generateLegend());
|
||||
}
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
@@ -116,7 +109,6 @@
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
@@ -136,26 +128,24 @@
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
config.data.labels.push('dataset #' + config.data.labels.length);
|
||||
var month = MONTHS[config.data.labels.length % MONTHS.length];
|
||||
config.data.labels.push(month);
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data.push(randomScalingFactor());
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
@@ -166,7 +156,6 @@
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Time Scale Point Data</title>
|
||||
<script src="../node_modules/moment/min/moment.min.js"></script>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-webkit-box-shadow: 0 0 20px 0 rgba(0, 0, 0, .5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:100%;">
|
||||
<canvas id="canvas" style="width:100%;height:100%"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100 * (Math.random() > 0.5 ? -1 : 1));
|
||||
};
|
||||
var randomColorFactor = function() {
|
||||
return Math.round(Math.random() * 255);
|
||||
};
|
||||
var randomColor = function(opacity) {
|
||||
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
|
||||
};
|
||||
var newDate = function(days) {
|
||||
var date = new Date();
|
||||
return date.setDate(date.getDate() + days);
|
||||
};
|
||||
var newTimestamp = function(days) {
|
||||
return Date.now() - days * 100000;
|
||||
};
|
||||
|
||||
var config = {
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: [{
|
||||
label: "Dataset with point data",
|
||||
data: [{
|
||||
x: "12/31/2014 06:00",
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: "01/04/2015 13:00",
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: "01/07/2015 01:15",
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: "01/15/2015 01:15",
|
||||
y: randomScalingFactor()
|
||||
}],
|
||||
fill: false
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: "time",
|
||||
display: true,
|
||||
time: {
|
||||
format: 'MM/DD/YYYY HH:mm',
|
||||
// round: 'day'
|
||||
},
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Date'
|
||||
}
|
||||
}, ],
|
||||
yAxes: [{
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'value'
|
||||
}
|
||||
}]
|
||||
},
|
||||
elements: {
|
||||
line: {
|
||||
tension: 0.3
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.borderColor = randomColor(0.4);
|
||||
dataset.backgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderColor = randomColor(0.7);
|
||||
dataset.pointBackgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(config.data);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myLine.generateLegend());
|
||||
}
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
return randomScalingFactor();
|
||||
});
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
var newTime = myLine.scales['x-axis-0'].labelMoments[0][myLine.scales['x-axis-0'].labelMoments[0].length - 1]
|
||||
.clone()
|
||||
.add(1, 'day')
|
||||
.format('MM/DD/YYYY HH:mm');
|
||||
|
||||
for (var index = 0; index < config.data.datasets.length; ++index) {
|
||||
config.data.datasets[index].data.push({
|
||||
x: newTime,
|
||||
y: randomScalingFactor()
|
||||
});
|
||||
}
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
config.data.datasets.forEach(function(dataset, datasetIndex) {
|
||||
dataset.data.pop();
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -3,18 +3,20 @@
|
||||
|
||||
<head>
|
||||
<title>Chart with xAxis Filtering</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-webkit-box-shadow: 0 0 20px 0 rgba(0, 0, 0, .5);
|
||||
}
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:50%;">
|
||||
<canvas id="canvas" style="width:100%;height:100%"></canvas>
|
||||
<div style="width:75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
@@ -24,6 +26,8 @@
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<script>
|
||||
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
||||
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 50 * (Math.random() > 0.5 ? 1 : 1)) + 50;
|
||||
};
|
||||
@@ -37,7 +41,7 @@
|
||||
var config = {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: ["January is a long month", "February", "March", "April", "May", "June", "July"],
|
||||
labels: ["January", "February", "March", "April", "May", "June", "July"],
|
||||
datasets: [{
|
||||
label: "My First dataset",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
@@ -50,6 +54,10 @@
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
title:{
|
||||
display:true,
|
||||
text:"Chart.js Line Chart - X-Axis Filter"
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
display: true,
|
||||
@@ -75,8 +83,6 @@
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(config.data);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
@@ -114,7 +120,8 @@
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
config.data.labels.push('dataset #' + config.data.labels.length);
|
||||
var month = MONTHS[config.data.labels.length % MONTHS.length];
|
||||
config.data.labels.push(month);
|
||||
|
||||
for (var index = 0; index < config.data.datasets.length; ++index) {
|
||||
config.data.datasets[index].data.push(randomScalingFactor());
|
||||
|
||||
+19
-30
@@ -3,18 +3,20 @@
|
||||
|
||||
<head>
|
||||
<title>Line Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-webkit-box-shadow: 0 0 20px 0 rgba(0, 0, 0, .5);
|
||||
}
|
||||
canvas{
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:100%;">
|
||||
<canvas id="canvas" style="width:100%;height:100%"></canvas>
|
||||
<div style="width:75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
@@ -24,12 +26,9 @@
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
||||
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100);
|
||||
//return 0;
|
||||
@@ -53,7 +52,7 @@
|
||||
}, {
|
||||
hidden: true,
|
||||
label: 'hidden dataset',
|
||||
data: [],
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
}, {
|
||||
label: "My Second dataset",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
@@ -61,6 +60,10 @@
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
title:{
|
||||
display:true,
|
||||
text:'Chart.js Line Chart'
|
||||
},
|
||||
tooltips: {
|
||||
mode: 'label',
|
||||
callbacks: {
|
||||
@@ -88,7 +91,7 @@
|
||||
}
|
||||
},
|
||||
hover: {
|
||||
mode: 'label'
|
||||
mode: 'dataset'
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
@@ -121,21 +124,11 @@
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(config.data);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myLine.generateLegend());
|
||||
}
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
@@ -145,7 +138,6 @@
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#changeDataObject').click(function() {
|
||||
@@ -191,26 +183,24 @@
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
config.data.labels.push('dataset #' + config.data.labels.length);
|
||||
var month = MONTHS[config.data.labels.length % MONTHS.length];
|
||||
config.data.labels.push(month);
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data.push(randomScalingFactor());
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
@@ -221,7 +211,6 @@
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
<head>
|
||||
<title>Pie Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
</head>
|
||||
|
||||
|
||||
+17
-18
@@ -3,23 +3,24 @@
|
||||
|
||||
<head>
|
||||
<title>Polar Area Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="canvas-holder" style="width:100%">
|
||||
<div id="canvas-holder" style="width:75%">
|
||||
<canvas id="chart-area"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100);
|
||||
@@ -48,6 +49,7 @@
|
||||
"#949FB1",
|
||||
"#4D5360",
|
||||
],
|
||||
label: 'My dataset' // for legend
|
||||
}],
|
||||
labels: [
|
||||
"Red",
|
||||
@@ -59,6 +61,13 @@
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
legend: {
|
||||
position: 'top',
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Chart.js Polar Area Chart'
|
||||
},
|
||||
scale: {
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
@@ -72,15 +81,8 @@
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("chart-area");
|
||||
window.myPolarArea = Chart.PolarArea(ctx, config);
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myPolarArea.generateLegend());
|
||||
}
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, piece) {
|
||||
$.each(piece.data, function(j, value) {
|
||||
@@ -89,7 +91,6 @@
|
||||
});
|
||||
});
|
||||
window.myPolarArea.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
@@ -102,7 +103,6 @@
|
||||
});
|
||||
|
||||
window.myPolarArea.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -115,7 +115,6 @@
|
||||
});
|
||||
|
||||
window.myPolarArea.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -3,25 +3,26 @@
|
||||
|
||||
<head>
|
||||
<title>Radar Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:50%">
|
||||
<canvas id="canvas" height="450" width="450"></canvas>
|
||||
<div style="width:75%">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addDataset">Add Dataset</button>
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100);
|
||||
@@ -62,6 +63,10 @@
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
title:{
|
||||
display:true,
|
||||
text:"Chart.js Radar Chart - Skip Points"
|
||||
},
|
||||
elements: {
|
||||
line: {
|
||||
tension: 0.0,
|
||||
@@ -74,15 +79,8 @@
|
||||
}
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myRadar.generateLegend());
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
window.myRadar = new Chart(document.getElementById("canvas"), config);
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
@@ -94,7 +92,6 @@
|
||||
});
|
||||
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
@@ -114,7 +111,6 @@
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
@@ -126,14 +122,12 @@
|
||||
});
|
||||
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
@@ -144,7 +138,6 @@
|
||||
});
|
||||
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
+18
-22
@@ -3,12 +3,19 @@
|
||||
|
||||
<head>
|
||||
<title>Radar Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:100%">
|
||||
<div style="width:75%">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
@@ -16,12 +23,6 @@
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100);
|
||||
@@ -45,7 +46,7 @@
|
||||
}, {
|
||||
label: 'Hidden dataset',
|
||||
hidden: true,
|
||||
data: [],
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
}, {
|
||||
label: "My Second dataset",
|
||||
backgroundColor: "rgba(151,187,205,0.2)",
|
||||
@@ -56,8 +57,15 @@
|
||||
},]
|
||||
},
|
||||
options: {
|
||||
legend: {
|
||||
position: 'top',
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Chart.js Radar Chart'
|
||||
},
|
||||
scale: {
|
||||
reverse: true,
|
||||
reverse: false,
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
@@ -65,15 +73,8 @@
|
||||
}
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myRadar.generateLegend());
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
window.myRadar = new Chart(document.getElementById("canvas"), config);
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
@@ -85,7 +86,6 @@
|
||||
});
|
||||
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
@@ -105,7 +105,6 @@
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
@@ -117,14 +116,12 @@
|
||||
});
|
||||
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
@@ -135,7 +132,6 @@
|
||||
});
|
||||
|
||||
window.myRadar.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -3,14 +3,21 @@
|
||||
|
||||
<head>
|
||||
<title>Scatter Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:50%">
|
||||
<div style="width:75%">
|
||||
<div>
|
||||
<canvas id="canvas" height="450" width="600" style="border: 1px solid red;"></canvas>
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
@@ -134,6 +141,10 @@
|
||||
window.myScatter = Chart.Scatter(ctx, {
|
||||
data: scatterChartData,
|
||||
options: {
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Chart.js Scatter Chart - Logarithmic X-Axis'
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: 'logarithmic',
|
||||
|
||||
@@ -3,14 +3,21 @@
|
||||
|
||||
<head>
|
||||
<title>Scatter Chart Multi Axis</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:50%">
|
||||
<div style="width:75%">
|
||||
<div>
|
||||
<canvas id="canvas" height="450" width="600"></canvas>
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
@@ -86,8 +93,6 @@
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(scatterChartData);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myScatter = Chart.Scatter(ctx, {
|
||||
@@ -95,6 +100,10 @@
|
||||
options: {
|
||||
responsive: true,
|
||||
hoverMode: 'single',
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Chart.js Scatter Chart - Multi Axis'
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
position: "bottom",
|
||||
@@ -168,7 +177,7 @@
|
||||
}, {
|
||||
x: randomScalingFactor(),
|
||||
y: randomScalingFactor(),
|
||||
}]
|
||||
}];
|
||||
window.myScatter.update();
|
||||
});
|
||||
</script>
|
||||
|
||||
+14
-5
@@ -3,14 +3,21 @@
|
||||
|
||||
<head>
|
||||
<title>Scatter Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:50%">
|
||||
<div style="width:75%">
|
||||
<div>
|
||||
<canvas id="canvas" height="450" width="600"></canvas>
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
@@ -82,13 +89,15 @@
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
console.log(scatterChartData);
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myScatter = Chart.Scatter(ctx, {
|
||||
data: scatterChartData,
|
||||
options: {
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Chart.js Scatter Chart'
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
position: 'top',
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Line Chart - Combo Time Scale</title>
|
||||
<script src="../../node_modules/moment/min/moment.min.js"></script>
|
||||
<script src="../../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addDataset">Add Dataset</button>
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<script>
|
||||
var timeFormat = 'MM/DD/YYYY HH:mm';
|
||||
|
||||
function randomScalingFactor() {
|
||||
return Math.round(Math.random() * 100 * (Math.random() > 0.5 ? -1 : 1));
|
||||
}
|
||||
|
||||
function randomColorFactor() {
|
||||
return Math.round(Math.random() * 255);
|
||||
}
|
||||
|
||||
function randomColor(opacity) {
|
||||
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
|
||||
}
|
||||
|
||||
function newDateString(days) {
|
||||
return moment().add(days, 'd').format(timeFormat);
|
||||
}
|
||||
|
||||
var config = {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: [newDateString(0), newDateString(1), newDateString(2), newDateString(3), newDateString(4), newDateString(5), newDateString(6)],
|
||||
datasets: [{
|
||||
type: 'bar',
|
||||
label: 'Dataset 1',
|
||||
backgroundColor: "rgba(151,187,205,0.5)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
borderColor: 'white',
|
||||
borderWidth: 2
|
||||
}, {
|
||||
type: 'bar',
|
||||
label: 'Dataset 2',
|
||||
backgroundColor: "rgba(151,187,205,0.5)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
borderColor: 'white',
|
||||
borderWidth: 2
|
||||
}, {
|
||||
type: 'line',
|
||||
label: 'Dataset 3',
|
||||
backgroundColor: "rgba(220,220,220,0.5)",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
|
||||
}, ]
|
||||
},
|
||||
options: {
|
||||
showLines: true,
|
||||
responsive: true,
|
||||
title:{
|
||||
display:true,
|
||||
text:"Chart.js Combo Time Scale"
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: "time",
|
||||
display: true,
|
||||
time: {
|
||||
format: timeFormat,
|
||||
// round: 'day'
|
||||
}
|
||||
}],
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.borderColor = randomColor(0.4);
|
||||
dataset.backgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderColor = randomColor(0.7);
|
||||
dataset.pointBackgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
return randomScalingFactor();
|
||||
});
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
var newDataset = {
|
||||
label: 'Dataset ' + config.data.datasets.length,
|
||||
borderColor: randomColor(0.4),
|
||||
backgroundColor: randomColor(0.5),
|
||||
pointBorderColor: randomColor(0.7),
|
||||
pointBackgroundColor: randomColor(0.5),
|
||||
pointBorderWidth: 1,
|
||||
data: [],
|
||||
};
|
||||
|
||||
for (var index = 0; index < config.data.labels.length; ++index) {
|
||||
newDataset.data.push(randomScalingFactor());
|
||||
}
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
config.data.labels.push(newDateString(config.data.labels.length));
|
||||
|
||||
for (var index = 0; index < config.data.datasets.length; ++index) {
|
||||
config.data.datasets[index].data.push(randomScalingFactor());
|
||||
}
|
||||
|
||||
window.myLine.update();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
config.data.labels.splice(-1, 1); // remove the label first
|
||||
|
||||
config.data.datasets.forEach(function(dataset, datasetIndex) {
|
||||
config.data.datasets[datasetIndex].data.pop();
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,164 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Time Scale Point Data</title>
|
||||
<script src="../../node_modules/moment/min/moment.min.js"></script>
|
||||
<script src="../../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<script>
|
||||
function randomScalingFactor() {
|
||||
return Math.round(Math.random() * 100 * (Math.random() > 0.5 ? -1 : 1));
|
||||
}
|
||||
|
||||
function randomColorFactor() {
|
||||
return Math.round(Math.random() * 255);
|
||||
}
|
||||
|
||||
function randomColor(opacity) {
|
||||
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
|
||||
}
|
||||
|
||||
function newDate(days) {
|
||||
return moment().add(days, 'd').toDate();
|
||||
}
|
||||
|
||||
function newDateString(days) {
|
||||
return moment().add(days, 'd').format();
|
||||
}
|
||||
|
||||
var config = {
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: [{
|
||||
label: "Dataset with string point data",
|
||||
data: [{
|
||||
x: newDateString(0),
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: newDateString(2),
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: newDateString(4),
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: newDateString(5),
|
||||
y: randomScalingFactor()
|
||||
}],
|
||||
fill: false
|
||||
}, {
|
||||
label: "Dataset with date object point data",
|
||||
data: [{
|
||||
x: newDate(0),
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: newDate(2),
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: newDate(4),
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: newDate(5),
|
||||
y: randomScalingFactor()
|
||||
}],
|
||||
fill: false
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
title:{
|
||||
display:true,
|
||||
text:"Chart.js Time Point Data"
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: "time",
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Date'
|
||||
}
|
||||
}, ],
|
||||
yAxes: [{
|
||||
display: true,
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'value'
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.borderColor = randomColor(0.4);
|
||||
dataset.backgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderColor = randomColor(0.7);
|
||||
dataset.pointBackgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
$.each(dataset.data, function(j, dataObj) {
|
||||
dataObj.y = randomScalingFactor();
|
||||
});
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
var lastTime = myLine.scales['x-axis-0'].labelMoments[0].length ? myLine.scales['x-axis-0'].labelMoments[0][myLine.scales['x-axis-0'].labelMoments[0].length - 1] : moment();
|
||||
var newTime = lastTime
|
||||
.clone()
|
||||
.add(1, 'day')
|
||||
.format('MM/DD/YYYY HH:mm');
|
||||
|
||||
for (var index = 0; index < config.data.datasets.length; ++index) {
|
||||
config.data.datasets[index].data.push({
|
||||
x: newTime,
|
||||
y: randomScalingFactor()
|
||||
});
|
||||
}
|
||||
|
||||
window.myLine.update();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
config.data.datasets.forEach(function(dataset, datasetIndex) {
|
||||
dataset.data.pop();
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,198 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Line Chart</title>
|
||||
<script src="../../node_modules/moment/min/moment.min.js"></script>
|
||||
<script src="../../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<button id="randomizeData">Randomize Data</button>
|
||||
<button id="addDataset">Add Dataset</button>
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<script>
|
||||
var timeFormat = 'MM/DD/YYYY HH:mm';
|
||||
|
||||
function randomScalingFactor() {
|
||||
return Math.round(Math.random() * 100 * (Math.random() > 0.5 ? -1 : 1));
|
||||
}
|
||||
|
||||
function randomColorFactor() {
|
||||
return Math.round(Math.random() * 255);
|
||||
}
|
||||
|
||||
function randomColor(opacity) {
|
||||
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
|
||||
}
|
||||
|
||||
function newDate(days) {
|
||||
return moment().add(days, 'd').toDate();
|
||||
}
|
||||
|
||||
function newDateString(days) {
|
||||
return moment().add(days, 'd').format(timeFormat);
|
||||
}
|
||||
|
||||
function newTimestamp(days) {
|
||||
return moment().add(days, 'd').unix();
|
||||
}
|
||||
|
||||
var config = {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [newDate(0), newDate(1), newDate(2), newDate(3), newDate(4), newDate(5), newDate(6)], // Date Objects
|
||||
datasets: [{
|
||||
label: "My First dataset",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
fill: false,
|
||||
borderDash: [5, 5],
|
||||
}, {
|
||||
label: "My Second dataset",
|
||||
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()],
|
||||
}, {
|
||||
label: "Dataset with point data",
|
||||
data: [{
|
||||
x: newDateString(0),
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: newDateString(5),
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: newDateString(7),
|
||||
y: randomScalingFactor()
|
||||
}, {
|
||||
x: newDateString(15),
|
||||
y: randomScalingFactor()
|
||||
}],
|
||||
fill: false
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
title:{
|
||||
display:true,
|
||||
text:"Chart.js Time Scale"
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: "time",
|
||||
time: {
|
||||
format: timeFormat,
|
||||
// round: 'day'
|
||||
tooltipFormat: 'll HH:mm'
|
||||
},
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Date'
|
||||
}
|
||||
}, ],
|
||||
yAxes: [{
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'value'
|
||||
}
|
||||
}]
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.borderColor = randomColor(0.4);
|
||||
dataset.backgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderColor = randomColor(0.7);
|
||||
dataset.pointBackgroundColor = randomColor(0.5);
|
||||
dataset.pointBorderWidth = 1;
|
||||
});
|
||||
|
||||
window.onload = function() {
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
|
||||
};
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
$.each(dataset.data, function(j, dataObj) {
|
||||
if (typeof dataObj === 'object') {
|
||||
dataObj.y = randomScalingFactor();
|
||||
} else {
|
||||
dataset.data[j] = randomScalingFactor();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
var newDataset = {
|
||||
label: 'Dataset ' + config.data.datasets.length,
|
||||
borderColor: randomColor(0.4),
|
||||
backgroundColor: randomColor(0.5),
|
||||
pointBorderColor: randomColor(0.7),
|
||||
pointBackgroundColor: randomColor(0.5),
|
||||
pointBorderWidth: 1,
|
||||
data: [],
|
||||
};
|
||||
|
||||
for (var index = 0; index < config.data.labels.length; ++index) {
|
||||
newDataset.data.push(randomScalingFactor());
|
||||
}
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
config.data.labels.push(newDate(config.data.labels.length));
|
||||
|
||||
for (var index = 0; index < config.data.datasets.length; ++index) {
|
||||
if (typeof config.data.datasets[index].data[0] === "object") {
|
||||
config.data.datasets[index].data.push({
|
||||
x: newDate(config.data.datasets[index].data.length),
|
||||
y: randomScalingFactor(),
|
||||
});
|
||||
} else {
|
||||
config.data.datasets[index].data.push(randomScalingFactor());
|
||||
}
|
||||
}
|
||||
|
||||
window.myLine.update();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myLine.update();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
config.data.labels.splice(-1, 1); // remove the label first
|
||||
|
||||
config.data.datasets.forEach(function(dataset, datasetIndex) {
|
||||
dataset.data.pop();
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -3,18 +3,20 @@
|
||||
|
||||
<head>
|
||||
<title>Line Chart</title>
|
||||
<script src="../Chart.js"></script>
|
||||
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../dist/Chart.bundle.js"></script>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<style>
|
||||
canvas {
|
||||
-webkit-box-shadow: 0 0 20px 0 rgba(0, 0, 0, .5);
|
||||
}
|
||||
canvas {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="width:100%;">
|
||||
<canvas id="canvas" style="width:100%;height:100%"></canvas>
|
||||
<div style="width:75%;">
|
||||
<canvas id="canvas"></canvas>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
@@ -23,12 +25,9 @@
|
||||
<button id="removeDataset">Remove Dataset</button>
|
||||
<button id="addData">Add Data</button>
|
||||
<button id="removeData">Remove Data</button>
|
||||
<div>
|
||||
<h3>Legend</h3>
|
||||
<div id="legendContainer">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
||||
|
||||
var randomScalingFactor = function() {
|
||||
return Math.round(Math.random() * 100 * (Math.random() > 0.5 ? -1 : 1));
|
||||
};
|
||||
@@ -55,6 +54,10 @@
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
title:{
|
||||
display:true,
|
||||
text:"Chart.js Line Chart - Tooltip Hooks"
|
||||
},
|
||||
tooltips: {
|
||||
mode: 'label',
|
||||
callbacks: {
|
||||
@@ -115,15 +118,8 @@
|
||||
var ctx = document.getElementById("canvas").getContext("2d");
|
||||
window.myLine = new Chart(ctx, config);
|
||||
|
||||
updateLegend();
|
||||
};
|
||||
|
||||
function updateLegend() {
|
||||
$legendContainer = $('#legendContainer');
|
||||
$legendContainer.empty();
|
||||
$legendContainer.append(window.myLine.generateLegend());
|
||||
}
|
||||
|
||||
$('#randomizeData').click(function() {
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data = dataset.data.map(function() {
|
||||
@@ -133,7 +129,6 @@
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addDataset').click(function() {
|
||||
@@ -153,26 +148,24 @@
|
||||
|
||||
config.data.datasets.push(newDataset);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#addData').click(function() {
|
||||
if (config.data.datasets.length > 0) {
|
||||
config.data.labels.push('dataset #' + config.data.labels.length);
|
||||
var month = MONTHS[config.data.labels.length % MONTHS.length];
|
||||
config.data.labels.push(month);
|
||||
|
||||
$.each(config.data.datasets, function(i, dataset) {
|
||||
dataset.data.push(randomScalingFactor());
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
}
|
||||
});
|
||||
|
||||
$('#removeDataset').click(function() {
|
||||
config.data.datasets.splice(0, 1);
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
|
||||
$('#removeData').click(function() {
|
||||
@@ -183,7 +176,6 @@
|
||||
});
|
||||
|
||||
window.myLine.update();
|
||||
updateLegend();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*!
|
||||
* Chart.js
|
||||
* http://chartjs.org/
|
||||
* Version: {{ version }}
|
||||
*
|
||||
* Copyright 2015 Nick Downie
|
||||
* Released under the MIT license
|
||||
* https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
|
||||
var Chart = require('./core/core.js')();
|
||||
|
||||
require('./core/core.helpers')(Chart);
|
||||
require('./core/core.element')(Chart);
|
||||
require('./core/core.animation')(Chart);
|
||||
require('./core/core.controller')(Chart);
|
||||
require('./core/core.datasetController')(Chart);
|
||||
require('./core/core.layoutService')(Chart);
|
||||
require('./core/core.legend')(Chart);
|
||||
require('./core/core.scale')(Chart);
|
||||
require('./core/core.scaleService')(Chart);
|
||||
require('./core/core.title')(Chart);
|
||||
require('./core/core.tooltip')(Chart);
|
||||
|
||||
require('./controllers/controller.bar')(Chart);
|
||||
require('./controllers/controller.bubble')(Chart);
|
||||
require('./controllers/controller.doughnut')(Chart);
|
||||
require('./controllers/controller.line')(Chart);
|
||||
require('./controllers/controller.polarArea')(Chart);
|
||||
require('./controllers/controller.radar')(Chart);
|
||||
|
||||
require('./scales/scale.category')(Chart);
|
||||
require('./scales/scale.linear')(Chart);
|
||||
require('./scales/scale.logarithmic')(Chart);
|
||||
require('./scales/scale.radialLinear')(Chart);
|
||||
require('./scales/scale.time')(Chart);
|
||||
|
||||
require('./elements/element.arc')(Chart);
|
||||
require('./elements/element.line')(Chart);
|
||||
require('./elements/element.point')(Chart);
|
||||
require('./elements/element.rectangle')(Chart);
|
||||
|
||||
require('./charts/Chart.Bar')(Chart);
|
||||
require('./charts/Chart.Bubble')(Chart);
|
||||
require('./charts/Chart.Doughnut')(Chart);
|
||||
require('./charts/Chart.Line')(Chart);
|
||||
require('./charts/Chart.PolarArea')(Chart);
|
||||
require('./charts/Chart.Radar')(Chart);
|
||||
require('./charts/Chart.Scatter')(Chart);
|
||||
|
||||
window.Chart = module.exports = Chart;
|
||||
@@ -1,9 +1,6 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this;
|
||||
var Chart = root.Chart;
|
||||
var helpers = Chart.helpers;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
Chart.Bar = function(context, config) {
|
||||
config.type = 'bar';
|
||||
@@ -11,4 +8,4 @@
|
||||
return new Chart(context, config);
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
@@ -1,48 +1,10 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this;
|
||||
var Chart = root.Chart;
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
hover: {
|
||||
mode: 'single',
|
||||
},
|
||||
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: "linear", // bubble should probably use a linear scale by default
|
||||
position: "bottom",
|
||||
id: "x-axis-0", // need an ID so datasets can reference the scale
|
||||
}],
|
||||
yAxes: [{
|
||||
type: "linear",
|
||||
position: "left",
|
||||
id: "y-axis-0",
|
||||
}],
|
||||
},
|
||||
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
title: function(tooltipItems, data) {
|
||||
// Title doesn't make sense for scatter since we format the data as a point
|
||||
return '';
|
||||
},
|
||||
label: function(tooltipItem, data) {
|
||||
return '(' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ')';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
// Register the default config for this type
|
||||
Chart.defaults.bubble = defaultConfig;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
Chart.Bubble = function(context, config) {
|
||||
config.type = 'bubble';
|
||||
return new Chart(context, config);
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
@@ -1,36 +1,11 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this;
|
||||
var Chart = root.Chart;
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
aspectRatio: 1,
|
||||
legendCallback: function(chart) {
|
||||
var text = [];
|
||||
text.push('<ul class="' + chart.id + '-legend">');
|
||||
|
||||
if (chart.data.datasets.length) {
|
||||
for (var i = 0; i < chart.data.datasets[0].data.length; ++i) {
|
||||
text.push('<li><span style="background-color:' + chart.data.datasets[0].backgroundColor[i] + '">');
|
||||
if (chart.data.labels[i]) {
|
||||
text.push(chart.data.labels[i]);
|
||||
}
|
||||
text.push('</span></li>');
|
||||
}
|
||||
}
|
||||
|
||||
text.push('</ul>');
|
||||
return text.join("");
|
||||
}
|
||||
};
|
||||
module.exports = function(Chart) {
|
||||
|
||||
Chart.Doughnut = function(context, config) {
|
||||
config.options = helpers.configMerge(defaultConfig, config.options);
|
||||
config.type = 'doughnut';
|
||||
|
||||
return new Chart(context, config);
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
};
|
||||
@@ -1,14 +1,11 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this;
|
||||
var Chart = root.Chart;
|
||||
var helpers = Chart.helpers;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
Chart.Line = function(context, config) {
|
||||
config.type = 'line';
|
||||
|
||||
return new Chart(context, config);
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
};
|
||||
@@ -1,36 +1,11 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this;
|
||||
var Chart = root.Chart;
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
aspectRatio: 1,
|
||||
legendCallback: function(chart) {
|
||||
var text = [];
|
||||
text.push('<ul class="' + chart.id + '-legend">');
|
||||
|
||||
if (chart.data.datasets.length) {
|
||||
for (var i = 0; i < chart.data.datasets[0].data.length; ++i) {
|
||||
text.push('<li><span style="background-color:' + chart.data.datasets[0].backgroundColor[i] + '">');
|
||||
if (chart.data.labels[i]) {
|
||||
text.push(chart.data.labels[i]);
|
||||
}
|
||||
text.push('</span></li>');
|
||||
}
|
||||
}
|
||||
|
||||
text.push('</ul>');
|
||||
return text.join("");
|
||||
}
|
||||
};
|
||||
module.exports = function(Chart) {
|
||||
|
||||
Chart.PolarArea = function(context, config) {
|
||||
config.options = helpers.configMerge(defaultConfig, config.options);
|
||||
config.type = 'polarArea';
|
||||
|
||||
return new Chart(context, config);
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
};
|
||||
@@ -1,12 +1,11 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var root = this;
|
||||
var Chart = root.Chart;
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
aspectRatio: 1,
|
||||
aspectRatio: 1
|
||||
};
|
||||
|
||||
Chart.Radar = function(context, config) {
|
||||
@@ -15,5 +14,5 @@
|
||||
|
||||
return new Chart(context, config);
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
};
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this;
|
||||
var Chart = root.Chart;
|
||||
var helpers = Chart.helpers;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var defaultConfig = {
|
||||
hover: {
|
||||
mode: 'single',
|
||||
mode: 'single'
|
||||
},
|
||||
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: "linear", // scatter should not use a category axis
|
||||
position: "bottom",
|
||||
id: "x-axis-1", // need an ID so datasets can reference the scale
|
||||
id: "x-axis-1" // need an ID so datasets can reference the scale
|
||||
}],
|
||||
yAxes: [{
|
||||
type: "linear",
|
||||
position: "left",
|
||||
id: "y-axis-1",
|
||||
}],
|
||||
id: "y-axis-1"
|
||||
}]
|
||||
},
|
||||
|
||||
tooltips: {
|
||||
@@ -33,7 +30,7 @@
|
||||
return '(' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ')';
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// Register the default config for this type
|
||||
@@ -46,5 +43,5 @@
|
||||
config.type = 'scatter';
|
||||
return new Chart(context, config);
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
};
|
||||
@@ -1,10 +1,8 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
"use strict";
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.defaults.bar = {
|
||||
hover: {
|
||||
@@ -21,60 +19,30 @@
|
||||
|
||||
// grid line settings
|
||||
gridLines: {
|
||||
offsetGridLines: true,
|
||||
},
|
||||
offsetGridLines: true
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
type: "linear",
|
||||
}],
|
||||
},
|
||||
type: "linear"
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
Chart.controllers.bar = function(chart, datasetIndex) {
|
||||
this.initialize.call(this, chart, datasetIndex);
|
||||
};
|
||||
|
||||
helpers.extend(Chart.controllers.bar.prototype, {
|
||||
|
||||
Chart.controllers.bar = Chart.DatasetController.extend({
|
||||
initialize: function(chart, datasetIndex) {
|
||||
this.chart = chart;
|
||||
this.index = datasetIndex;
|
||||
this.linkScales();
|
||||
this.addElements();
|
||||
},
|
||||
updateIndex: function(datasetIndex) {
|
||||
this.index = datasetIndex;
|
||||
},
|
||||
linkScales: function() {
|
||||
if (!this.getDataset().xAxisID) {
|
||||
this.getDataset().xAxisID = this.chart.options.scales.xAxes[0].id;
|
||||
}
|
||||
Chart.DatasetController.prototype.initialize.call(this, chart, datasetIndex);
|
||||
|
||||
if (!this.getDataset().yAxisID) {
|
||||
this.getDataset().yAxisID = this.chart.options.scales.yAxes[0].id;
|
||||
}
|
||||
// Use this to indicate that this is a bar dataset.
|
||||
this.getDataset().bar = true;
|
||||
},
|
||||
|
||||
getDataset: function() {
|
||||
return this.chart.data.datasets[this.index];
|
||||
},
|
||||
|
||||
getScaleForID: function(scaleID) {
|
||||
return this.chart.scales[scaleID];
|
||||
},
|
||||
|
||||
// Get the number of datasets that display bars. We use this to correctly calculate the bar width
|
||||
getBarCount: function getBarCount() {
|
||||
var barCount = 0;
|
||||
helpers.each(this.chart.data.datasets, function(dataset) {
|
||||
if (helpers.isDatasetVisible(dataset)) {
|
||||
if (dataset.type === 'bar') {
|
||||
++barCount;
|
||||
} else if (dataset.type === undefined && this.chart.config.type === 'bar') {
|
||||
++barCount;
|
||||
}
|
||||
if (helpers.isDatasetVisible(dataset) && dataset.bar) {
|
||||
++barCount;
|
||||
}
|
||||
}, this);
|
||||
});
|
||||
return barCount;
|
||||
},
|
||||
|
||||
@@ -84,7 +52,7 @@
|
||||
this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Rectangle({
|
||||
_chart: this.chart.chart,
|
||||
_datasetIndex: this.index,
|
||||
_index: index,
|
||||
_index: index
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
@@ -93,7 +61,7 @@
|
||||
var rectangle = new Chart.elements.Rectangle({
|
||||
_chart: this.chart.chart,
|
||||
_datasetIndex: this.index,
|
||||
_index: index,
|
||||
_index: index
|
||||
});
|
||||
|
||||
var numBars = this.getBarCount();
|
||||
@@ -102,30 +70,6 @@
|
||||
this.getDataset().metaData.splice(index, 0, rectangle);
|
||||
},
|
||||
|
||||
removeElement: function(index) {
|
||||
this.getDataset().metaData.splice(index, 1);
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.update(true);
|
||||
},
|
||||
|
||||
buildOrUpdateElements: function buildOrUpdateElements() {
|
||||
var numData = this.getDataset().data.length;
|
||||
var numRectangles = this.getDataset().metaData.length;
|
||||
|
||||
// Make sure that we handle number of datapoints changing
|
||||
if (numData < numRectangles) {
|
||||
// Remove excess bars for data points that have been removed
|
||||
this.getDataset().metaData.splice(numData, numRectangles - numData);
|
||||
} else if (numData > numRectangles) {
|
||||
// Add new elements
|
||||
for (var index = numRectangles; index < numData; ++index) {
|
||||
this.addElementAndReset(index);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
update: function update(reset) {
|
||||
var numBars = this.getBarCount();
|
||||
|
||||
@@ -136,8 +80,8 @@
|
||||
|
||||
updateElement: function updateElement(rectangle, index, reset, numBars) {
|
||||
|
||||
var xScale = this.getScaleForID(this.getDataset().xAxisID);
|
||||
var yScale = this.getScaleForID(this.getDataset().yAxisID);
|
||||
var xScale = this.getScaleForId(this.getDataset().xAxisID);
|
||||
var yScale = this.getScaleForId(this.getDataset().yAxisID);
|
||||
|
||||
var yScalePoint;
|
||||
|
||||
@@ -169,20 +113,21 @@
|
||||
datasetLabel: this.getDataset().label,
|
||||
|
||||
// Appearance
|
||||
base: this.calculateBarBase(this.index, index),
|
||||
base: reset ? yScalePoint : this.calculateBarBase(this.index, index),
|
||||
width: this.calculateBarWidth(numBars),
|
||||
backgroundColor: rectangle.custom && rectangle.custom.backgroundColor ? rectangle.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.rectangle.backgroundColor),
|
||||
borderSkipped: rectangle.custom && rectangle.custom.borderSkipped ? rectangle.custom.borderSkipped : this.chart.options.elements.rectangle.borderSkipped,
|
||||
borderColor: rectangle.custom && rectangle.custom.borderColor ? rectangle.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.rectangle.borderColor),
|
||||
borderWidth: rectangle.custom && rectangle.custom.borderWidth ? rectangle.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.rectangle.borderWidth),
|
||||
},
|
||||
borderWidth: rectangle.custom && rectangle.custom.borderWidth ? rectangle.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.rectangle.borderWidth)
|
||||
}
|
||||
});
|
||||
rectangle.pivot();
|
||||
},
|
||||
|
||||
calculateBarBase: function(datasetIndex, index) {
|
||||
|
||||
var xScale = this.getScaleForID(this.getDataset().xAxisID);
|
||||
var yScale = this.getScaleForID(this.getDataset().yAxisID);
|
||||
var xScale = this.getScaleForId(this.getDataset().xAxisID);
|
||||
var yScale = this.getScaleForId(this.getDataset().yAxisID);
|
||||
|
||||
var base = 0;
|
||||
|
||||
@@ -193,14 +138,14 @@
|
||||
if (value < 0) {
|
||||
for (var i = 0; i < datasetIndex; i++) {
|
||||
var negDS = this.chart.data.datasets[i];
|
||||
if (helpers.isDatasetVisible(negDS) && negDS.yAxisID === yScale.id) {
|
||||
if (helpers.isDatasetVisible(negDS) && negDS.yAxisID === yScale.id && negDS.bar) {
|
||||
base += negDS.data[index] < 0 ? negDS.data[index] : 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var j = 0; j < datasetIndex; j++) {
|
||||
var posDS = this.chart.data.datasets[j];
|
||||
if (helpers.isDatasetVisible(posDS) && posDS.yAxisID === yScale.id) {
|
||||
if (helpers.isDatasetVisible(posDS) && posDS.yAxisID === yScale.id && posDS.bar) {
|
||||
base += posDS.data[index] > 0 ? posDS.data[index] : 0;
|
||||
}
|
||||
}
|
||||
@@ -225,17 +170,14 @@
|
||||
|
||||
getRuler: function() {
|
||||
|
||||
var xScale = this.getScaleForID(this.getDataset().xAxisID);
|
||||
var yScale = this.getScaleForID(this.getDataset().yAxisID);
|
||||
/*var datasetCount = !this.chart.isCombo ? this.chart.data.datasets.length : helpers.where(this.chart.data.datasets, function(ds) {
|
||||
return ds.type == 'bar';
|
||||
}).length;*/
|
||||
var xScale = this.getScaleForId(this.getDataset().xAxisID);
|
||||
var yScale = this.getScaleForId(this.getDataset().yAxisID);
|
||||
var datasetCount = this.getBarCount();
|
||||
|
||||
var tickWidth = (function() {
|
||||
var min = xScale.getPixelForValue(null, 1) - xScale.getPixelForValue(null, 0);
|
||||
var min = xScale.getPixelForTick(1) - xScale.getPixelForTick(0);
|
||||
for (var i = 2; i < this.getDataset().data.length; i++) {
|
||||
min = Math.min(xScale.getPixelForValue(null, i) - xScale.getPixelForValue(null, i - 1), min);
|
||||
min = Math.min(xScale.getPixelForTick(i) - xScale.getPixelForTick(i - 1), min);
|
||||
}
|
||||
return min;
|
||||
}).call(this);
|
||||
@@ -252,21 +194,14 @@
|
||||
categorySpacing: categorySpacing,
|
||||
fullBarWidth: fullBarWidth,
|
||||
barWidth: barWidth,
|
||||
barSpacing: barSpacing,
|
||||
barSpacing: barSpacing
|
||||
};
|
||||
},
|
||||
|
||||
calculateBarWidth: function() {
|
||||
|
||||
var xScale = this.getScaleForID(this.getDataset().xAxisID);
|
||||
var xScale = this.getScaleForId(this.getDataset().xAxisID);
|
||||
var ruler = this.getRuler();
|
||||
|
||||
if (xScale.options.stacked) {
|
||||
return ruler.categoryWidth;
|
||||
}
|
||||
|
||||
return ruler.barWidth;
|
||||
|
||||
return xScale.options.stacked ? ruler.categoryWidth : ruler.barWidth;
|
||||
},
|
||||
|
||||
// Get bar index from the given dataset index accounting for the fact that not all bars are visible
|
||||
@@ -274,8 +209,7 @@
|
||||
var barIndex = 0;
|
||||
|
||||
for (var j = 0; j < datasetIndex; ++j) {
|
||||
if (helpers.isDatasetVisible(this.chart.data.datasets[j]) &&
|
||||
(this.chart.data.datasets[j].type === 'bar' || (this.chart.data.datasets[j].type === undefined && this.chart.config.type === 'bar'))) {
|
||||
if (helpers.isDatasetVisible(this.chart.data.datasets[j]) && this.chart.data.datasets[j].bar) {
|
||||
++barIndex;
|
||||
}
|
||||
}
|
||||
@@ -285,12 +219,12 @@
|
||||
|
||||
calculateBarX: function(index, datasetIndex) {
|
||||
|
||||
var yScale = this.getScaleForID(this.getDataset().yAxisID);
|
||||
var xScale = this.getScaleForID(this.getDataset().xAxisID);
|
||||
var yScale = this.getScaleForId(this.getDataset().yAxisID);
|
||||
var xScale = this.getScaleForId(this.getDataset().xAxisID);
|
||||
var barIndex = this.getBarIndex(datasetIndex);
|
||||
|
||||
var ruler = this.getRuler();
|
||||
var leftTick = xScale.getPixelForValue(null, index, barIndex, this.chart.isCombo);
|
||||
var leftTick = xScale.getPixelForValue(null, index, datasetIndex, this.chart.isCombo);
|
||||
leftTick -= this.chart.isCombo ? (ruler.tickWidth / 2) : 0;
|
||||
|
||||
if (xScale.options.stacked) {
|
||||
@@ -307,8 +241,8 @@
|
||||
|
||||
calculateBarY: function(index, datasetIndex) {
|
||||
|
||||
var xScale = this.getScaleForID(this.getDataset().xAxisID);
|
||||
var yScale = this.getScaleForID(this.getDataset().yAxisID);
|
||||
var xScale = this.getScaleForId(this.getDataset().xAxisID);
|
||||
var yScale = this.getScaleForId(this.getDataset().yAxisID);
|
||||
|
||||
var value = this.getDataset().data[index];
|
||||
|
||||
@@ -319,7 +253,7 @@
|
||||
|
||||
for (var i = 0; i < datasetIndex; i++) {
|
||||
var ds = this.chart.data.datasets[i];
|
||||
if (helpers.isDatasetVisible(ds)) {
|
||||
if (helpers.isDatasetVisible(ds) && ds.bar && ds.yAxisID === yScale.id) {
|
||||
if (ds.data[index] < 0) {
|
||||
sumNeg += ds.data[index] || 0;
|
||||
} else {
|
||||
@@ -343,7 +277,10 @@
|
||||
draw: function(ease) {
|
||||
var easingDecimal = ease || 1;
|
||||
helpers.each(this.getDataset().metaData, function(rectangle, index) {
|
||||
rectangle.transition(easingDecimal).draw();
|
||||
var d = this.getDataset().data[index];
|
||||
if (d !== null && d !== undefined && !isNaN(d)) {
|
||||
rectangle.transition(easingDecimal).draw();
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
@@ -366,7 +303,4 @@
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
"use strict";
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.defaults.bubble = {
|
||||
hover: {
|
||||
@@ -15,56 +13,32 @@
|
||||
xAxes: [{
|
||||
type: "linear", // bubble should probably use a linear scale by default
|
||||
position: "bottom",
|
||||
id: "x-axis-0", // need an ID so datasets can reference the scale
|
||||
id: "x-axis-0" // need an ID so datasets can reference the scale
|
||||
}],
|
||||
yAxes: [{
|
||||
type: "linear",
|
||||
position: "left",
|
||||
id: "y-axis-0",
|
||||
}],
|
||||
id: "y-axis-0"
|
||||
}]
|
||||
},
|
||||
|
||||
tooltips: {
|
||||
template: "(<%= value.x %>, <%= value.y %>, <%= value.r %>)",
|
||||
multiTemplate: "<%if (datasetLabel){%><%=datasetLabel%>: <%}%>(<%= value.x %>, <%= value.y %>, <%= value.r %>)",
|
||||
},
|
||||
callbacks: {
|
||||
title: function(tooltipItems, data) {
|
||||
// Title doesn't make sense for scatter since we format the data as a point
|
||||
return '';
|
||||
},
|
||||
label: function(tooltipItem, data) {
|
||||
var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
|
||||
var dataPoint = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
|
||||
return datasetLabel + ': (' + dataPoint.x + ', ' + dataPoint.y + ', ' + dataPoint.r + ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Chart.controllers.bubble = function(chart, datasetIndex) {
|
||||
this.initialize.call(this, chart, datasetIndex);
|
||||
};
|
||||
|
||||
helpers.extend(Chart.controllers.bubble.prototype, {
|
||||
|
||||
initialize: function(chart, datasetIndex) {
|
||||
this.chart = chart;
|
||||
this.index = datasetIndex;
|
||||
this.linkScales();
|
||||
this.addElements();
|
||||
},
|
||||
updateIndex: function(datasetIndex) {
|
||||
this.index = datasetIndex;
|
||||
},
|
||||
|
||||
linkScales: function() {
|
||||
if (!this.getDataset().xAxisID) {
|
||||
this.getDataset().xAxisID = this.chart.options.scales.xAxes[0].id;
|
||||
}
|
||||
|
||||
if (!this.getDataset().yAxisID) {
|
||||
this.getDataset().yAxisID = this.chart.options.scales.yAxes[0].id;
|
||||
}
|
||||
},
|
||||
|
||||
getDataset: function() {
|
||||
return this.chart.data.datasets[this.index];
|
||||
},
|
||||
|
||||
getScaleForId: function(scaleID) {
|
||||
return this.chart.scales[scaleID];
|
||||
},
|
||||
|
||||
Chart.controllers.bubble = Chart.DatasetController.extend({
|
||||
addElements: function() {
|
||||
|
||||
this.getDataset().metaData = this.getDataset().metaData || [];
|
||||
@@ -73,7 +47,7 @@
|
||||
this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({
|
||||
_chart: this.chart.chart,
|
||||
_datasetIndex: this.index,
|
||||
_index: index,
|
||||
_index: index
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
@@ -82,7 +56,7 @@
|
||||
var point = new Chart.elements.Point({
|
||||
_chart: this.chart.chart,
|
||||
_datasetIndex: this.index,
|
||||
_index: index,
|
||||
_index: index
|
||||
});
|
||||
|
||||
// Reset the point
|
||||
@@ -90,31 +64,6 @@
|
||||
|
||||
// Add to the points array
|
||||
this.getDataset().metaData.splice(index, 0, point);
|
||||
|
||||
},
|
||||
removeElement: function(index) {
|
||||
this.getDataset().metaData.splice(index, 1);
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.update(true);
|
||||
},
|
||||
|
||||
buildOrUpdateElements: function buildOrUpdateElements() {
|
||||
// Handle the number of data points changing
|
||||
var numData = this.getDataset().data.length;
|
||||
var numPoints = this.getDataset().metaData.length;
|
||||
|
||||
// Make sure that we handle number of datapoints changing
|
||||
if (numData < numPoints) {
|
||||
// Remove excess bars for data points that have been removed
|
||||
this.getDataset().metaData.splice(numData, numPoints - numData);
|
||||
} else if (numData > numPoints) {
|
||||
// Add new elements
|
||||
for (var index = numPoints; index < numData; ++index) {
|
||||
this.addElementAndReset(index);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
update: function update(reset) {
|
||||
@@ -171,8 +120,8 @@
|
||||
borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.point.borderWidth),
|
||||
|
||||
// Tooltip
|
||||
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius),
|
||||
},
|
||||
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius)
|
||||
}
|
||||
});
|
||||
|
||||
point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
|
||||
@@ -191,7 +140,7 @@
|
||||
helpers.each(this.getDataset().metaData, function(point, index) {
|
||||
point.transition(easingDecimal);
|
||||
point.draw();
|
||||
}, this);
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
@@ -216,4 +165,4 @@
|
||||
point._model.borderWidth = point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.point.borderWidth);
|
||||
}
|
||||
});
|
||||
}).call(this);
|
||||
};
|
||||
@@ -1,28 +1,82 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
//Cache a local reference to Chart.helpers
|
||||
helpers = Chart.helpers;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.defaults.doughnut = {
|
||||
animation: {
|
||||
//Boolean - Whether we animate the rotation of the Doughnut
|
||||
animateRotate: true,
|
||||
//Boolean - Whether we animate scaling the Doughnut from the centre
|
||||
animateScale: false,
|
||||
animateScale: false
|
||||
},
|
||||
aspectRatio: 1,
|
||||
hover: {
|
||||
mode: 'single'
|
||||
},
|
||||
legendCallback: function(chart) {
|
||||
var text = [];
|
||||
text.push('<ul class="' + chart.id + '-legend">');
|
||||
|
||||
if (chart.data.datasets.length) {
|
||||
for (var i = 0; i < chart.data.datasets[0].data.length; ++i) {
|
||||
text.push('<li><span style="background-color:' + chart.data.datasets[0].backgroundColor[i] + '">');
|
||||
if (chart.data.labels[i]) {
|
||||
text.push(chart.data.labels[i]);
|
||||
}
|
||||
text.push('</span></li>');
|
||||
}
|
||||
}
|
||||
|
||||
text.push('</ul>');
|
||||
return text.join("");
|
||||
},
|
||||
legend: {
|
||||
labels: {
|
||||
generateLabels: function(data) {
|
||||
if (data.labels.length && data.datasets.length) {
|
||||
return data.labels.map(function(label, i) {
|
||||
return {
|
||||
text: label,
|
||||
fillStyle: data.datasets[0].backgroundColor[i],
|
||||
hidden: isNaN(data.datasets[0].data[i]),
|
||||
|
||||
// Extra data used for toggling the correct item
|
||||
index: i
|
||||
};
|
||||
});
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
onClick: function(e, legendItem) {
|
||||
helpers.each(this.chart.data.datasets, function(dataset) {
|
||||
dataset.metaHiddenData = dataset.metaHiddenData || [];
|
||||
var idx = legendItem.index;
|
||||
|
||||
if (!isNaN(dataset.data[idx])) {
|
||||
dataset.metaHiddenData[idx] = dataset.data[idx];
|
||||
dataset.data[idx] = NaN;
|
||||
} else if (!isNaN(dataset.metaHiddenData[idx])) {
|
||||
dataset.data[idx] = dataset.metaHiddenData[idx];
|
||||
}
|
||||
});
|
||||
|
||||
this.chart.update();
|
||||
}
|
||||
},
|
||||
|
||||
//The percentage of the chart that we cut out of the middle.
|
||||
cutoutPercentage: 50,
|
||||
|
||||
// Need to override these to give a nice default
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
title: function() { return '';},
|
||||
title: function() {
|
||||
return '';
|
||||
},
|
||||
label: function(tooltipItem, data) {
|
||||
return data.labels[tooltipItem.index] + ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
|
||||
}
|
||||
@@ -36,36 +90,18 @@
|
||||
});
|
||||
|
||||
|
||||
Chart.controllers.doughnut = Chart.controllers.pie = function(chart, datasetIndex) {
|
||||
this.initialize.call(this, chart, datasetIndex);
|
||||
};
|
||||
|
||||
helpers.extend(Chart.controllers.doughnut.prototype, {
|
||||
|
||||
initialize: function(chart, datasetIndex) {
|
||||
this.chart = chart;
|
||||
this.index = datasetIndex;
|
||||
this.linkScales();
|
||||
this.addElements();
|
||||
},
|
||||
updateIndex: function(datasetIndex) {
|
||||
this.index = datasetIndex;
|
||||
},
|
||||
Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({
|
||||
linkScales: function() {
|
||||
// no scales for doughnut
|
||||
},
|
||||
|
||||
getDataset: function() {
|
||||
return this.chart.data.datasets[this.index];
|
||||
},
|
||||
|
||||
addElements: function() {
|
||||
this.getDataset().metaData = this.getDataset().metaData || [];
|
||||
helpers.each(this.getDataset().data, function(value, index) {
|
||||
this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Arc({
|
||||
_chart: this.chart.chart,
|
||||
_datasetIndex: this.index,
|
||||
_index: index,
|
||||
_index: index
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
@@ -74,7 +110,7 @@
|
||||
var arc = new Chart.elements.Arc({
|
||||
_chart: this.chart.chart,
|
||||
_datasetIndex: this.index,
|
||||
_index: index,
|
||||
_index: index
|
||||
});
|
||||
|
||||
if (colorForNewElement && helpers.isArray(this.getDataset().backgroundColor)) {
|
||||
@@ -87,32 +123,11 @@
|
||||
// Add to the points array
|
||||
this.getDataset().metaData.splice(index, 0, arc);
|
||||
},
|
||||
removeElement: function(index) {
|
||||
this.getDataset().metaData.splice(index, 1);
|
||||
},
|
||||
reset: function() {
|
||||
this.update(true);
|
||||
},
|
||||
|
||||
buildOrUpdateElements: function buildOrUpdateElements() {
|
||||
// Make sure we have metaData for each data point
|
||||
var numData = this.getDataset().data.length;
|
||||
var numArcs = this.getDataset().metaData.length;
|
||||
|
||||
// Make sure that we handle number of datapoints changing
|
||||
if (numData < numArcs) {
|
||||
// Remove excess bars for data points that have been removed
|
||||
this.getDataset().metaData.splice(numData, numArcs - numData);
|
||||
} else if (numData > numArcs) {
|
||||
// Add new elements
|
||||
for (var index = numArcs; index < numData; ++index) {
|
||||
this.addElementAndReset(index);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getVisibleDatasetCount: function getVisibleDatasetCount() {
|
||||
return helpers.where(this.chart.data.datasets, function(ds) { return helpers.isDatasetVisible(ds); }).length;
|
||||
return helpers.where(this.chart.data.datasets, function(ds) {
|
||||
return helpers.isDatasetVisible(ds);
|
||||
}).length;
|
||||
},
|
||||
|
||||
// Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
|
||||
@@ -129,14 +144,17 @@
|
||||
},
|
||||
|
||||
update: function update(reset) {
|
||||
var minSize = Math.min(this.chart.chartArea.right - this.chart.chartArea.left, this.chart.chartArea.bottom - this.chart.chartArea.top);
|
||||
|
||||
this.chart.outerRadius = Math.max((helpers.min([this.chart.chart.width, this.chart.chart.height]) / 2) - this.chart.options.elements.arc.borderWidth / 2, 0);
|
||||
this.chart.outerRadius = Math.max((minSize / 2) - this.chart.options.elements.arc.borderWidth / 2, 0);
|
||||
this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0);
|
||||
this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.getVisibleDatasetCount();
|
||||
|
||||
this.getDataset().total = 0;
|
||||
helpers.each(this.getDataset().data, function(value) {
|
||||
this.getDataset().total += Math.abs(value);
|
||||
if (!isNaN(value)) {
|
||||
this.getDataset().total += Math.abs(value);
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.getRingIndex(this.index));
|
||||
@@ -147,14 +165,13 @@
|
||||
}, this);
|
||||
},
|
||||
updateElement: function(arc, index, reset) {
|
||||
var resetModel = {
|
||||
x: this.chart.chart.width / 2,
|
||||
y: this.chart.chart.height / 2,
|
||||
startAngle: Math.PI * -0.5, // use - PI / 2 instead of 3PI / 2 to make animations better. It means that we never deal with overflow during the transition function
|
||||
circumference: (this.chart.options.animation.animateRotate) ? 0 : this.calculateCircumference(this.getDataset().data[index]),
|
||||
outerRadius: (this.chart.options.animation.animateScale) ? 0 : this.outerRadius,
|
||||
innerRadius: (this.chart.options.animation.animateScale) ? 0 : this.innerRadius,
|
||||
};
|
||||
var centerX = (this.chart.chartArea.left + this.chart.chartArea.right) / 2;
|
||||
var centerY = (this.chart.chartArea.top + this.chart.chartArea.bottom) / 2;
|
||||
var startAngle = Math.PI * -0.5; // non reset case handled later
|
||||
var endAngle = Math.PI * -0.5; // non reset case handled later
|
||||
var circumference = reset && this.chart.options.animation.animateRotate ? 0 : this.calculateCircumference(this.getDataset().data[index]);
|
||||
var innerRadius = reset && this.chart.options.animation.animateScale ? 0 : this.innerRadius;
|
||||
var outerRadius = reset && this.chart.options.animation.animateScale ? 0 : this.outerRadius;
|
||||
|
||||
helpers.extend(arc, {
|
||||
// Utility
|
||||
@@ -163,12 +180,14 @@
|
||||
_index: index,
|
||||
|
||||
// Desired view properties
|
||||
_model: reset ? resetModel : {
|
||||
x: this.chart.chart.width / 2,
|
||||
y: this.chart.chart.height / 2,
|
||||
circumference: this.calculateCircumference(this.getDataset().data[index]),
|
||||
outerRadius: this.outerRadius,
|
||||
innerRadius: this.innerRadius,
|
||||
_model: {
|
||||
x: centerX,
|
||||
y: centerY,
|
||||
startAngle: startAngle,
|
||||
endAngle: endAngle,
|
||||
circumference: circumference,
|
||||
outerRadius: outerRadius,
|
||||
innerRadius: innerRadius,
|
||||
|
||||
backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor),
|
||||
hoverBackgroundColor: arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor, index, this.chart.options.elements.arc.hoverBackgroundColor),
|
||||
@@ -176,9 +195,10 @@
|
||||
borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor),
|
||||
|
||||
label: helpers.getValueAtIndexOrDefault(this.getDataset().label, index, this.chart.data.labels[index])
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
// Set correct angles if not resetting
|
||||
if (!reset) {
|
||||
|
||||
if (index === 0) {
|
||||
@@ -188,12 +208,6 @@
|
||||
}
|
||||
|
||||
arc._model.endAngle = arc._model.startAngle + arc._model.circumference;
|
||||
|
||||
|
||||
//Check to see if it's the last arc, if not get the next and update its start angle
|
||||
if (index < this.getDataset().data.length - 1) {
|
||||
this.getDataset().metaData[index + 1]._model.startAngle = arc._model.endAngle;
|
||||
}
|
||||
}
|
||||
|
||||
arc.pivot();
|
||||
@@ -203,7 +217,7 @@
|
||||
var easingDecimal = ease || 1;
|
||||
helpers.each(this.getDataset().metaData, function(arc, index) {
|
||||
arc.transition(easingDecimal).draw();
|
||||
}, this);
|
||||
});
|
||||
},
|
||||
|
||||
setHoverStyle: function(arc) {
|
||||
@@ -225,14 +239,11 @@
|
||||
},
|
||||
|
||||
calculateCircumference: function(value) {
|
||||
if (this.getDataset().total > 0) {
|
||||
if (this.getDataset().total > 0 && !isNaN(value)) {
|
||||
return (Math.PI * 1.999999) * (value / this.getDataset().total);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
@@ -1,12 +1,12 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
"use strict";
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.defaults.line = {
|
||||
showLines: true,
|
||||
|
||||
hover: {
|
||||
mode: "label"
|
||||
},
|
||||
@@ -19,45 +19,12 @@
|
||||
yAxes: [{
|
||||
type: "linear",
|
||||
id: 'y-axis-0'
|
||||
}],
|
||||
},
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Chart.controllers.line = function(chart, datasetIndex) {
|
||||
this.initialize.call(this, chart, datasetIndex);
|
||||
};
|
||||
|
||||
helpers.extend(Chart.controllers.line.prototype, {
|
||||
|
||||
initialize: function(chart, datasetIndex) {
|
||||
this.chart = chart;
|
||||
this.index = datasetIndex;
|
||||
this.linkScales();
|
||||
this.addElements();
|
||||
},
|
||||
updateIndex: function(datasetIndex) {
|
||||
this.index = datasetIndex;
|
||||
},
|
||||
|
||||
linkScales: function() {
|
||||
if (!this.getDataset().xAxisID) {
|
||||
this.getDataset().xAxisID = this.chart.options.scales.xAxes[0].id;
|
||||
}
|
||||
|
||||
if (!this.getDataset().yAxisID) {
|
||||
this.getDataset().yAxisID = this.chart.options.scales.yAxes[0].id;
|
||||
}
|
||||
},
|
||||
|
||||
getDataset: function() {
|
||||
return this.chart.data.datasets[this.index];
|
||||
},
|
||||
|
||||
getScaleForId: function(scaleID) {
|
||||
return this.chart.scales[scaleID];
|
||||
},
|
||||
|
||||
Chart.controllers.line = Chart.DatasetController.extend({
|
||||
addElements: function() {
|
||||
|
||||
this.getDataset().metaData = this.getDataset().metaData || [];
|
||||
@@ -65,14 +32,14 @@
|
||||
this.getDataset().metaDataset = this.getDataset().metaDataset || new Chart.elements.Line({
|
||||
_chart: this.chart.chart,
|
||||
_datasetIndex: this.index,
|
||||
_points: this.getDataset().metaData,
|
||||
_points: this.getDataset().metaData
|
||||
});
|
||||
|
||||
helpers.each(this.getDataset().data, function(value, index) {
|
||||
this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({
|
||||
_chart: this.chart.chart,
|
||||
_datasetIndex: this.index,
|
||||
_index: index,
|
||||
_index: index
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
@@ -81,7 +48,7 @@
|
||||
var point = new Chart.elements.Point({
|
||||
_chart: this.chart.chart,
|
||||
_datasetIndex: this.index,
|
||||
_index: index,
|
||||
_index: index
|
||||
});
|
||||
|
||||
// Reset the point
|
||||
@@ -91,31 +58,8 @@
|
||||
this.getDataset().metaData.splice(index, 0, point);
|
||||
|
||||
// Make sure bezier control points are updated
|
||||
this.updateBezierControlPoints();
|
||||
},
|
||||
removeElement: function(index) {
|
||||
this.getDataset().metaData.splice(index, 1);
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.update(true);
|
||||
},
|
||||
|
||||
buildOrUpdateElements: function buildOrUpdateElements() {
|
||||
// Handle the number of data points changing
|
||||
var numData = this.getDataset().data.length;
|
||||
var numPoints = this.getDataset().metaData.length;
|
||||
|
||||
// Make sure that we handle number of datapoints changing
|
||||
if (numData < numPoints) {
|
||||
// Remove excess bars for data points that have been removed
|
||||
this.getDataset().metaData.splice(numData, numPoints - numData);
|
||||
} else if (numData > numPoints) {
|
||||
// Add new elements
|
||||
for (var index = numPoints; index < numData; ++index) {
|
||||
this.addElementAndReset(index);
|
||||
}
|
||||
}
|
||||
if (this.chart.options.showLines && this.chart.options.elements.line.tension !== 0)
|
||||
this.updateBezierControlPoints();
|
||||
},
|
||||
|
||||
update: function update(reset) {
|
||||
@@ -135,16 +79,16 @@
|
||||
}
|
||||
|
||||
// Update Line
|
||||
helpers.extend(line, {
|
||||
if (this.chart.options.showLines) {
|
||||
// Utility
|
||||
_scale: yScale,
|
||||
_datasetIndex: this.index,
|
||||
line._scale = yScale;
|
||||
line._datasetIndex = this.index;
|
||||
// Data
|
||||
_children: points,
|
||||
line._children = points;
|
||||
// Model
|
||||
_model: {
|
||||
line._model = {
|
||||
// Appearance
|
||||
tension: line.custom && line.custom.tension ? line.custom.tension : (this.getDataset().tension || this.chart.options.elements.line.tension),
|
||||
tension: line.custom && line.custom.tension ? line.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension),
|
||||
backgroundColor: line.custom && line.custom.backgroundColor ? line.custom.backgroundColor : (this.getDataset().backgroundColor || this.chart.options.elements.line.backgroundColor),
|
||||
borderWidth: line.custom && line.custom.borderWidth ? line.custom.borderWidth : (this.getDataset().borderWidth || this.chart.options.elements.line.borderWidth),
|
||||
borderColor: line.custom && line.custom.borderColor ? line.custom.borderColor : (this.getDataset().borderColor || this.chart.options.elements.line.borderColor),
|
||||
@@ -156,17 +100,18 @@
|
||||
// Scale
|
||||
scaleTop: yScale.top,
|
||||
scaleBottom: yScale.bottom,
|
||||
scaleZero: scaleBase,
|
||||
},
|
||||
});
|
||||
line.pivot();
|
||||
scaleZero: scaleBase
|
||||
};
|
||||
line.pivot();
|
||||
}
|
||||
|
||||
// Update Points
|
||||
helpers.each(points, function(point, index) {
|
||||
this.updateElement(point, index, reset);
|
||||
}, this);
|
||||
|
||||
this.updateBezierControlPoints();
|
||||
if (this.chart.options.showLines && this.chart.options.elements.line.tension !== 0)
|
||||
this.updateBezierControlPoints();
|
||||
},
|
||||
|
||||
getPointBackgroundColor: function(point, index) {
|
||||
@@ -225,28 +170,27 @@
|
||||
scaleBase = yScale.getPixelForValue(0);
|
||||
}
|
||||
|
||||
helpers.extend(point, {
|
||||
// Utility
|
||||
_chart: this.chart.chart,
|
||||
_xScale: xScale,
|
||||
_yScale: yScale,
|
||||
_datasetIndex: this.index,
|
||||
_index: index,
|
||||
// Utility
|
||||
point._chart = this.chart.chart;
|
||||
point._xScale = xScale;
|
||||
point._yScale = yScale;
|
||||
point._datasetIndex = this.index;
|
||||
point._index = index;
|
||||
|
||||
// Desired view properties
|
||||
_model: {
|
||||
x: xScale.getPixelForValue(this.getDataset().data[index], index, this.index, this.chart.isCombo),
|
||||
y: reset ? scaleBase : this.calculatePointY(this.getDataset().data[index], index, this.index, this.chart.isCombo),
|
||||
// Appearance
|
||||
tension: point.custom && point.custom.tension ? point.custom.tension : (this.getDataset().tension || this.chart.options.elements.line.tension),
|
||||
radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().radius, index, this.chart.options.elements.point.radius),
|
||||
backgroundColor: this.getPointBackgroundColor(point, index),
|
||||
borderColor: this.getPointBorderColor(point, index),
|
||||
borderWidth: this.getPointBorderWidth(point, index),
|
||||
// Tooltip
|
||||
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius),
|
||||
},
|
||||
});
|
||||
// Desired view properties
|
||||
point._model = {
|
||||
x: xScale.getPixelForValue(this.getDataset().data[index], index, this.index, this.chart.isCombo),
|
||||
y: reset ? scaleBase : this.calculatePointY(this.getDataset().data[index], index, this.index, this.chart.isCombo),
|
||||
// Appearance
|
||||
tension: point.custom && point.custom.tension ? point.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension),
|
||||
radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().radius, index, this.chart.options.elements.point.radius),
|
||||
pointStyle: point.custom && point.custom.pointStyle ? point.custom.pointStyle : helpers.getValueAtIndexOrDefault(this.getDataset().pointStyle, index, this.chart.options.elements.point.pointStyle),
|
||||
backgroundColor: this.getPointBackgroundColor(point, index),
|
||||
borderColor: this.getPointBorderColor(point, index),
|
||||
borderWidth: this.getPointBorderWidth(point, index),
|
||||
// Tooltip
|
||||
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius)
|
||||
};
|
||||
|
||||
point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
|
||||
},
|
||||
@@ -261,9 +205,9 @@
|
||||
var sumPos = 0,
|
||||
sumNeg = 0;
|
||||
|
||||
for (var i = this.chart.data.datasets.length - 1; i > datasetIndex; i--) {
|
||||
for (var i = 0; i < datasetIndex; i++) {
|
||||
var ds = this.chart.data.datasets[i];
|
||||
if (helpers.isDatasetVisible(ds)) {
|
||||
if (ds.type === 'line' && helpers.isDatasetVisible(ds)) {
|
||||
if (ds.data[index] < 0) {
|
||||
sumNeg += ds.data[index] || 0;
|
||||
} else {
|
||||
@@ -277,8 +221,6 @@
|
||||
} else {
|
||||
return yScale.getPixelForValue(sumPos + value);
|
||||
}
|
||||
|
||||
return yScale.getPixelForValue(value);
|
||||
}
|
||||
|
||||
return yScale.getPixelForValue(value);
|
||||
@@ -310,12 +252,13 @@
|
||||
var easingDecimal = ease || 1;
|
||||
|
||||
// Transition Point Locations
|
||||
helpers.each(this.getDataset().metaData, function(point, index) {
|
||||
helpers.each(this.getDataset().metaData, function(point) {
|
||||
point.transition(easingDecimal);
|
||||
}, this);
|
||||
});
|
||||
|
||||
// Transition and Draw the line
|
||||
this.getDataset().metaDataset.transition(easingDecimal).draw();
|
||||
if (this.chart.options.showLines)
|
||||
this.getDataset().metaDataset.transition(easingDecimal).draw();
|
||||
|
||||
// Draw the points
|
||||
helpers.each(this.getDataset().metaData, function(point) {
|
||||
@@ -344,4 +287,4 @@
|
||||
point._model.borderWidth = this.getPointBorderWidth(point, index);
|
||||
}
|
||||
});
|
||||
}).call(this);
|
||||
};
|
||||
|
||||
@@ -1,27 +1,80 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
//Cache a local reference to Chart.helpers
|
||||
helpers = Chart.helpers;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.defaults.polarArea = {
|
||||
|
||||
scale: {
|
||||
type: "radialLinear",
|
||||
lineArc: true, // so that lines are circular
|
||||
lineArc: true // so that lines are circular
|
||||
},
|
||||
|
||||
//Boolean - Whether to animate the rotation of the chart
|
||||
animateRotate: true,
|
||||
animateScale: true,
|
||||
|
||||
aspectRatio: 1,
|
||||
legendCallback: function(chart) {
|
||||
var text = [];
|
||||
text.push('<ul class="' + chart.id + '-legend">');
|
||||
|
||||
if (chart.data.datasets.length) {
|
||||
for (var i = 0; i < chart.data.datasets[0].data.length; ++i) {
|
||||
text.push('<li><span style="background-color:' + chart.data.datasets[0].backgroundColor[i] + '">');
|
||||
if (chart.data.labels[i]) {
|
||||
text.push(chart.data.labels[i]);
|
||||
}
|
||||
text.push('</span></li>');
|
||||
}
|
||||
}
|
||||
|
||||
text.push('</ul>');
|
||||
return text.join("");
|
||||
},
|
||||
legend: {
|
||||
labels: {
|
||||
generateLabels: function(data) {
|
||||
if (data.labels.length && data.datasets.length) {
|
||||
return data.labels.map(function(label, i) {
|
||||
return {
|
||||
text: label,
|
||||
fillStyle: data.datasets[0].backgroundColor[i],
|
||||
hidden: isNaN(data.datasets[0].data[i]),
|
||||
|
||||
// Extra data used for toggling the correct item
|
||||
index: i
|
||||
};
|
||||
});
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
onClick: function(e, legendItem) {
|
||||
helpers.each(this.chart.data.datasets, function(dataset) {
|
||||
dataset.metaHiddenData = dataset.metaHiddenData || [];
|
||||
var idx = legendItem.index;
|
||||
|
||||
if (!isNaN(dataset.data[idx])) {
|
||||
dataset.metaHiddenData[idx] = dataset.data[idx];
|
||||
dataset.data[idx] = NaN;
|
||||
} else if (!isNaN(dataset.metaHiddenData[idx])) {
|
||||
dataset.data[idx] = dataset.metaHiddenData[idx];
|
||||
}
|
||||
});
|
||||
|
||||
this.chart.update();
|
||||
}
|
||||
},
|
||||
|
||||
// Need to override these to give a nice default
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
title: function() { return ''; },
|
||||
title: function() {
|
||||
return '';
|
||||
},
|
||||
label: function(tooltipItem, data) {
|
||||
return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel;
|
||||
}
|
||||
@@ -29,41 +82,17 @@
|
||||
}
|
||||
};
|
||||
|
||||
Chart.controllers.polarArea = function(chart, datasetIndex) {
|
||||
this.initialize.call(this, chart, datasetIndex);
|
||||
};
|
||||
|
||||
helpers.extend(Chart.controllers.polarArea.prototype, {
|
||||
|
||||
initialize: function(chart, datasetIndex) {
|
||||
this.chart = chart;
|
||||
this.index = datasetIndex;
|
||||
this.linkScales();
|
||||
this.addElements();
|
||||
},
|
||||
updateIndex: function(datasetIndex) {
|
||||
this.index = datasetIndex;
|
||||
},
|
||||
|
||||
Chart.controllers.polarArea = Chart.DatasetController.extend({
|
||||
linkScales: function() {
|
||||
// no scales for doughnut
|
||||
},
|
||||
|
||||
getDataset: function() {
|
||||
return this.chart.data.datasets[this.index];
|
||||
},
|
||||
|
||||
getScaleForId: function(scaleID) {
|
||||
return this.chart.scales[scaleID];
|
||||
},
|
||||
|
||||
addElements: function() {
|
||||
this.getDataset().metaData = this.getDataset().metaData || [];
|
||||
helpers.each(this.getDataset().data, function(value, index) {
|
||||
this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Arc({
|
||||
_chart: this.chart.chart,
|
||||
_datasetIndex: this.index,
|
||||
_index: index,
|
||||
_index: index
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
@@ -72,7 +101,7 @@
|
||||
var arc = new Chart.elements.Arc({
|
||||
_chart: this.chart.chart,
|
||||
_datasetIndex: this.index,
|
||||
_index: index,
|
||||
_index: index
|
||||
});
|
||||
|
||||
// Reset the point
|
||||
@@ -81,37 +110,15 @@
|
||||
// Add to the points array
|
||||
this.getDataset().metaData.splice(index, 0, arc);
|
||||
},
|
||||
removeElement: function(index) {
|
||||
this.getDataset().metaData.splice(index, 1);
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.update(true);
|
||||
},
|
||||
|
||||
buildOrUpdateElements: function buildOrUpdateElements() {
|
||||
// Handle the number of data points changing
|
||||
var numData = this.getDataset().data.length;
|
||||
var numPoints = this.getDataset().metaData.length;
|
||||
|
||||
// Make sure that we handle number of datapoints changing
|
||||
if (numData < numPoints) {
|
||||
// Remove excess bars for data points that have been removed
|
||||
this.getDataset().metaData.splice(numData, numPoints - numData);
|
||||
} else if (numData > numPoints) {
|
||||
// Add new elements
|
||||
for (var index = numPoints; index < numData; ++index) {
|
||||
this.addElementAndReset(index);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getVisibleDatasetCount: function getVisibleDatasetCount() {
|
||||
return helpers.where(this.chart.data.datasets, function(ds) { return helpers.isDatasetVisible(ds); }).length;
|
||||
return helpers.where(this.chart.data.datasets, function(ds) {
|
||||
return helpers.isDatasetVisible(ds);
|
||||
}).length;
|
||||
},
|
||||
|
||||
update: function update(reset) {
|
||||
this.chart.outerRadius = Math.max((helpers.min([this.chart.chart.width, this.chart.chart.height]) - this.chart.options.elements.arc.borderWidth / 2) / 2, 0);
|
||||
var minSize = Math.min(this.chart.chartArea.right - this.chart.chartArea.left, this.chart.chartArea.bottom - this.chart.chartArea.top);
|
||||
this.chart.outerRadius = Math.max((minSize - this.chart.options.elements.arc.borderWidth / 2) / 2, 0);
|
||||
this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0);
|
||||
this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.getVisibleDatasetCount();
|
||||
|
||||
@@ -127,21 +134,33 @@
|
||||
this.updateElement(arc, index, reset);
|
||||
}, this);
|
||||
},
|
||||
|
||||
updateElement: function(arc, index, reset) {
|
||||
var circumference = 1 / this.getDataset().data.length * 2;
|
||||
var startAngle = (-0.5 * Math.PI) + (Math.PI * circumference) * index;
|
||||
var endAngle = startAngle + (circumference * Math.PI);
|
||||
var circumference = this.calculateCircumference(this.getDataset().data[index]);
|
||||
var centerX = (this.chart.chartArea.left + this.chart.chartArea.right) / 2;
|
||||
var centerY = (this.chart.chartArea.top + this.chart.chartArea.bottom) / 2;
|
||||
|
||||
// If there is NaN data before us, we need to calculate the starting angle correctly.
|
||||
// We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
|
||||
var notNullIndex = 0;
|
||||
for (var i = 0; i < index; ++i) {
|
||||
if (!isNaN(this.getDataset().data[i])) {
|
||||
++notNullIndex;
|
||||
}
|
||||
}
|
||||
|
||||
var startAngle = (-0.5 * Math.PI) + (circumference * notNullIndex);
|
||||
var endAngle = startAngle + circumference;
|
||||
|
||||
var resetModel = {
|
||||
x: this.chart.chart.width / 2,
|
||||
y: this.chart.chart.height / 2,
|
||||
x: centerX,
|
||||
y: centerY,
|
||||
innerRadius: 0,
|
||||
outerRadius: this.chart.options.animateScale ? 0 : this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]),
|
||||
startAngle: this.chart.options.animateRotate ? Math.PI * -0.5 : startAngle,
|
||||
endAngle: this.chart.options.animateRotate ? Math.PI * -0.5 : endAngle,
|
||||
|
||||
backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor),
|
||||
hoverBackgroundColor: arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor, index, this.chart.options.elements.arc.hoverBackgroundColor),
|
||||
borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth),
|
||||
borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor),
|
||||
|
||||
@@ -157,20 +176,19 @@
|
||||
|
||||
// Desired view properties
|
||||
_model: reset ? resetModel : {
|
||||
x: this.chart.chart.width / 2,
|
||||
y: this.chart.chart.height / 2,
|
||||
x: centerX,
|
||||
y: centerY,
|
||||
innerRadius: 0,
|
||||
outerRadius: this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]),
|
||||
startAngle: startAngle,
|
||||
endAngle: endAngle,
|
||||
|
||||
backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor),
|
||||
hoverBackgroundColor: arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor, index, this.chart.options.elements.arc.hoverBackgroundColor),
|
||||
borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth),
|
||||
borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor),
|
||||
|
||||
label: helpers.getValueAtIndexOrDefault(this.chart.data.labels, index, this.chart.data.labels[index])
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
arc.pivot();
|
||||
@@ -180,7 +198,7 @@
|
||||
var easingDecimal = ease || 1;
|
||||
helpers.each(this.getDataset().metaData, function(arc, index) {
|
||||
arc.transition(easingDecimal).draw();
|
||||
}, this);
|
||||
});
|
||||
},
|
||||
|
||||
setHoverStyle: function(arc) {
|
||||
@@ -189,7 +207,7 @@
|
||||
|
||||
arc._model.backgroundColor = arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(arc._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
||||
arc._model.borderColor = arc.custom && arc.custom.hoverBorderColor ? arc.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(arc._model.borderColor).saturate(0.5).darken(0.1).rgbString());
|
||||
arc._model.borderWidth = arc.custom && arc.custom.hoverBorderWidth ? arc.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, arc._model.borderWidth);
|
||||
arc._model.borderWidth = arc.custom && arc.custom.hoverBorderWidth ? arc.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, arc._model.borderWidth);
|
||||
},
|
||||
|
||||
removeHoverStyle: function(arc) {
|
||||
@@ -202,19 +220,17 @@
|
||||
},
|
||||
|
||||
calculateCircumference: function(value) {
|
||||
if (this.getDataset().total > 0) {
|
||||
return (Math.PI * 2) * (value / this.getDataset().total);
|
||||
} else {
|
||||
if (isNaN(value)) {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
updateScaleRange: function() {
|
||||
helpers.extend(this.chart.scale, {
|
||||
size: helpers.min([this.chart.width, this.chart.height]),
|
||||
xCenter: this.chart.width / 2,
|
||||
yCenter: this.chart.height / 2
|
||||
});
|
||||
},
|
||||
} else {
|
||||
// Count the number of NaN values
|
||||
var numNaN = helpers.where(this.getDataset().data, function(data) {
|
||||
return isNaN(data);
|
||||
}).length;
|
||||
|
||||
return (2 * Math.PI) / (this.getDataset().data.length - numNaN);
|
||||
}
|
||||
}
|
||||
});
|
||||
}).call(this);
|
||||
|
||||
};
|
||||
@@ -1,52 +1,26 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
|
||||
Chart.defaults.radar = {
|
||||
scale: {
|
||||
type: "radialLinear",
|
||||
type: "radialLinear"
|
||||
},
|
||||
elements: {
|
||||
line: {
|
||||
tension: 0, // no bezier in radar
|
||||
tension: 0 // no bezier in radar
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
Chart.controllers.radar = function(chart, datasetIndex) {
|
||||
this.initialize.call(this, chart, datasetIndex);
|
||||
};
|
||||
|
||||
|
||||
helpers.extend(Chart.controllers.radar.prototype, {
|
||||
|
||||
initialize: function(chart, datasetIndex) {
|
||||
this.chart = chart;
|
||||
this.index = datasetIndex;
|
||||
this.linkScales();
|
||||
this.addElements();
|
||||
},
|
||||
updateIndex: function(datasetIndex) {
|
||||
this.index = datasetIndex;
|
||||
},
|
||||
|
||||
Chart.controllers.radar = Chart.DatasetController.extend({
|
||||
linkScales: function() {
|
||||
// No need. Single scale only
|
||||
},
|
||||
|
||||
getDataset: function() {
|
||||
return this.chart.data.datasets[this.index];
|
||||
},
|
||||
|
||||
getScaleForId: function(scaleID) {
|
||||
return this.chart.scales[scaleID];
|
||||
},
|
||||
|
||||
addElements: function() {
|
||||
|
||||
this.getDataset().metaData = this.getDataset().metaData || [];
|
||||
@@ -65,8 +39,8 @@
|
||||
_index: index,
|
||||
_model: {
|
||||
x: 0, //xScale.getPixelForValue(null, index, true),
|
||||
y: 0, //this.chartArea.bottom,
|
||||
},
|
||||
y: 0 //this.chartArea.bottom,
|
||||
}
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
@@ -75,7 +49,7 @@
|
||||
var point = new Chart.elements.Point({
|
||||
_chart: this.chart.chart,
|
||||
_datasetIndex: this.index,
|
||||
_index: index,
|
||||
_index: index
|
||||
});
|
||||
|
||||
// Reset the point
|
||||
@@ -87,30 +61,6 @@
|
||||
// Make sure bezier control points are updated
|
||||
this.updateBezierControlPoints();
|
||||
},
|
||||
removeElement: function(index) {
|
||||
this.getDataset().metaData.splice(index, 1);
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.update(true);
|
||||
},
|
||||
|
||||
buildOrUpdateElements: function buildOrUpdateElements() {
|
||||
// Handle the number of data points changing
|
||||
var numData = this.getDataset().data.length;
|
||||
var numPoints = this.getDataset().metaData.length;
|
||||
|
||||
// Make sure that we handle number of datapoints changing
|
||||
if (numData < numPoints) {
|
||||
// Remove excess bars for data points that have been removed
|
||||
this.getDataset().metaData.splice(numData, numPoints - numData);
|
||||
} else if (numData > numPoints) {
|
||||
// Add new elements
|
||||
for (var index = numPoints; index < numData; ++index) {
|
||||
this.addElementAndReset(index);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
update: function update(reset) {
|
||||
|
||||
@@ -136,17 +86,21 @@
|
||||
// Model
|
||||
_model: {
|
||||
// Appearance
|
||||
tension: this.getDataset().tension || this.chart.options.elements.line.tension,
|
||||
backgroundColor: this.getDataset().backgroundColor || this.chart.options.elements.line.backgroundColor,
|
||||
borderWidth: this.getDataset().borderWidth || this.chart.options.elements.line.borderWidth,
|
||||
borderColor: this.getDataset().borderColor || this.chart.options.elements.line.borderColor,
|
||||
fill: this.getDataset().fill !== undefined ? this.getDataset().fill : this.chart.options.elements.line.fill, // use the value from the this.getDataset() if it was provided. else fall back to the default
|
||||
tension: line.custom && line.custom.tension ? line.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension),
|
||||
backgroundColor: line.custom && line.custom.backgroundColor ? line.custom.backgroundColor : (this.getDataset().backgroundColor || this.chart.options.elements.line.backgroundColor),
|
||||
borderWidth: line.custom && line.custom.borderWidth ? line.custom.borderWidth : (this.getDataset().borderWidth || this.chart.options.elements.line.borderWidth),
|
||||
borderColor: line.custom && line.custom.borderColor ? line.custom.borderColor : (this.getDataset().borderColor || this.chart.options.elements.line.borderColor),
|
||||
fill: line.custom && line.custom.fill ? line.custom.fill : (this.getDataset().fill !== undefined ? this.getDataset().fill : this.chart.options.elements.line.fill),
|
||||
borderCapStyle: line.custom && line.custom.borderCapStyle ? line.custom.borderCapStyle : (this.getDataset().borderCapStyle || this.chart.options.elements.line.borderCapStyle),
|
||||
borderDash: line.custom && line.custom.borderDash ? line.custom.borderDash : (this.getDataset().borderDash || this.chart.options.elements.line.borderDash),
|
||||
borderDashOffset: line.custom && line.custom.borderDashOffset ? line.custom.borderDashOffset : (this.getDataset().borderDashOffset || this.chart.options.elements.line.borderDashOffset),
|
||||
borderJoinStyle: line.custom && line.custom.borderJoinStyle ? line.custom.borderJoinStyle : (this.getDataset().borderJoinStyle || this.chart.options.elements.line.borderJoinStyle),
|
||||
|
||||
// Scale
|
||||
scaleTop: scale.top,
|
||||
scaleBottom: scale.bottom,
|
||||
scaleZero: scaleBase,
|
||||
},
|
||||
scaleZero: scaleBase
|
||||
}
|
||||
});
|
||||
|
||||
this.getDataset().metaDataset.pivot();
|
||||
@@ -175,15 +129,16 @@
|
||||
y: reset ? this.chart.scale.yCenter : pointPosition.y,
|
||||
|
||||
// Appearance
|
||||
tension: point.custom && point.custom.tension ? point.custom.tension : this.chart.options.elements.line.tension,
|
||||
radius: point.custom && point.custom.radius ? point.custom.pointRadius : helpers.getValueAtIndexOrDefault(this.getDataset().pointRadius, index, this.chart.options.elements.point.radius),
|
||||
tension: point.custom && point.custom.tension ? point.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension),
|
||||
radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().pointRadius, index, this.chart.options.elements.point.radius),
|
||||
backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor, index, this.chart.options.elements.point.backgroundColor),
|
||||
borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, this.chart.options.elements.point.borderColor),
|
||||
borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth, index, this.chart.options.elements.point.borderWidth),
|
||||
pointStyle: point.custom && point.custom.pointStyle ? point.custom.pointStyle : helpers.getValueAtIndexOrDefault(this.getDataset().pointStyle, index, this.chart.options.elements.point.pointStyle),
|
||||
|
||||
// Tooltip
|
||||
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius),
|
||||
},
|
||||
hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius)
|
||||
}
|
||||
});
|
||||
|
||||
point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
|
||||
@@ -215,7 +170,7 @@
|
||||
// Transition Point Locations
|
||||
helpers.each(this.getDataset().metaData, function(point, index) {
|
||||
point.transition(easingDecimal);
|
||||
}, this);
|
||||
});
|
||||
|
||||
// Transition and Draw the line
|
||||
this.getDataset().metaDataset.transition(easingDecimal).draw();
|
||||
@@ -231,10 +186,10 @@
|
||||
var dataset = this.chart.data.datasets[point._datasetIndex];
|
||||
var index = point._index;
|
||||
|
||||
point._model.radius = point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
|
||||
point._model.radius = point.custom && point.custom.hoverRadius ? point.custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
|
||||
point._model.backgroundColor = point.custom && point.custom.hoverBackgroundColor ? point.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(point._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
||||
point._model.borderColor = point.custom && point.custom.hoverBorderColor ? point.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(point._model.borderColor).saturate(0.5).darken(0.1).rgbString());
|
||||
point._model.borderWidth = point.custom && point.custom.hoverBorderWidth ? point.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, point._model.borderWidth);
|
||||
point._model.borderWidth = point.custom && point.custom.hoverBorderWidth ? point.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, point._model.borderWidth);
|
||||
},
|
||||
|
||||
removeHoverStyle: function(point) {
|
||||
@@ -246,9 +201,5 @@
|
||||
point._model.borderColor = point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, this.chart.options.elements.point.borderColor);
|
||||
point._model.borderWidth = point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth, index, this.chart.options.elements.point.borderWidth);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
@@ -1,16 +1,15 @@
|
||||
(function() {
|
||||
/*global window: false */
|
||||
"use strict";
|
||||
|
||||
"use strict";
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.defaults.global.animation = {
|
||||
duration: 1000,
|
||||
easing: "easeOutQuart",
|
||||
onProgress: function() {},
|
||||
onComplete: function() {},
|
||||
onProgress: helpers.noop,
|
||||
onComplete: helpers.noop
|
||||
};
|
||||
|
||||
Chart.Animation = Chart.Element.extend({
|
||||
@@ -19,8 +18,8 @@
|
||||
easing: "", // the easing to use for this animation
|
||||
render: null, // render function used by the animation service
|
||||
|
||||
onAnimationProgress: null, // user specified callback to fire on each step of the animation
|
||||
onAnimationComplete: null, // user specified callback to fire when the animation finishes
|
||||
onAnimationProgress: null, // user specified callback to fire on each step of the animation
|
||||
onAnimationComplete: null // user specified callback to fire when the animation finishes
|
||||
});
|
||||
|
||||
Chart.animationService = {
|
||||
@@ -47,17 +46,17 @@
|
||||
});
|
||||
|
||||
// If there are no animations queued, manually kickstart a digest, for lack of a better word
|
||||
if (this.animations.length == 1) {
|
||||
if (this.animations.length === 1) {
|
||||
helpers.requestAnimFrame.call(window, this.digestWrapper);
|
||||
}
|
||||
},
|
||||
// Cancel the animation for a given chart instance
|
||||
cancelAnimation: function(chartInstance) {
|
||||
var index = helpers.findNextWhere(this.animations, function(animationWrapper) {
|
||||
var index = helpers.findIndex(this.animations, function(animationWrapper) {
|
||||
return animationWrapper.chartInstance === chartInstance;
|
||||
});
|
||||
|
||||
if (index) {
|
||||
if (index !== -1) {
|
||||
this.animations.splice(index, 1);
|
||||
chartInstance.animating = false;
|
||||
}
|
||||
@@ -76,24 +75,34 @@
|
||||
this.dropFrames = this.dropFrames % 1;
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.animations.length; i++) {
|
||||
|
||||
var i = 0;
|
||||
while (i < this.animations.length) {
|
||||
if (this.animations[i].animationObject.currentStep === null) {
|
||||
this.animations[i].animationObject.currentStep = 0;
|
||||
}
|
||||
|
||||
this.animations[i].animationObject.currentStep += 1 + framesToDrop;
|
||||
|
||||
if (this.animations[i].animationObject.currentStep > this.animations[i].animationObject.numSteps) {
|
||||
this.animations[i].animationObject.currentStep = this.animations[i].animationObject.numSteps;
|
||||
}
|
||||
|
||||
this.animations[i].animationObject.render(this.animations[i].chartInstance, this.animations[i].animationObject);
|
||||
if (this.animations[i].animationObject.onAnimationProgress && this.animations[i].animationObject.onAnimationProgress.call) {
|
||||
this.animations[i].animationObject.onAnimationProgress.call(this.animations[i].chartInstance, this.animations[i]);
|
||||
}
|
||||
|
||||
if (this.animations[i].animationObject.currentStep === this.animations[i].animationObject.numSteps) {
|
||||
if (this.animations[i].animationObject.onAnimationComplete && this.animations[i].animationObject.onAnimationComplete.call) {
|
||||
this.animations[i].animationObject.onAnimationComplete.call(this.animations[i].chartInstance, this.animations[i]);
|
||||
}
|
||||
|
||||
if (this.animations[i].animationObject.currentStep == this.animations[i].animationObject.numSteps) {
|
||||
// executed the last frame. Remove the animation.
|
||||
this.animations[i].chartInstance.animating = false;
|
||||
|
||||
this.animations.splice(i, 1);
|
||||
// Keep the index in place to offset the splice
|
||||
i--;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,5 +117,4 @@
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
+152
-112
@@ -1,13 +1,8 @@
|
||||
(function() {
|
||||
|
||||
"use strict";
|
||||
|
||||
//Declare root variable - window in the browser, global on the server
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
"use strict";
|
||||
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
//Create a dictionary of chart types, to allow for extension of existing types
|
||||
Chart.types = {};
|
||||
|
||||
@@ -29,7 +24,7 @@
|
||||
Object.defineProperty(this, 'data', {
|
||||
get: function() {
|
||||
return this.config.data;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
//Add the chart instance to the global namespace
|
||||
@@ -40,7 +35,7 @@
|
||||
this.resize(true);
|
||||
}
|
||||
|
||||
this.initialize.call(this);
|
||||
this.initialize();
|
||||
|
||||
return this;
|
||||
};
|
||||
@@ -59,6 +54,8 @@
|
||||
this.ensureScalesHaveIDs();
|
||||
this.buildOrUpdateControllers();
|
||||
this.buildScales();
|
||||
this.buildSurroundingItems();
|
||||
this.updateLayout();
|
||||
this.resetElements();
|
||||
this.initToolTip();
|
||||
this.update();
|
||||
@@ -81,17 +78,22 @@
|
||||
},
|
||||
|
||||
resize: function resize(silent) {
|
||||
this.stop();
|
||||
var canvas = this.chart.canvas;
|
||||
var newWidth = helpers.getMaximumWidth(this.chart.canvas);
|
||||
var newHeight = (this.options.maintainAspectRatio && isNaN(this.chart.aspectRatio) === false && isFinite(this.chart.aspectRatio) && this.chart.aspectRatio !== 0) ? newWidth / this.chart.aspectRatio : helpers.getMaximumHeight(this.chart.canvas);
|
||||
|
||||
var sizeChanged = this.chart.width !== newWidth || this.chart.height !== newHeight;
|
||||
|
||||
if (!sizeChanged)
|
||||
return this;
|
||||
|
||||
canvas.width = this.chart.width = newWidth;
|
||||
canvas.height = this.chart.height = newHeight;
|
||||
|
||||
helpers.retinaScale(this.chart);
|
||||
|
||||
if (!silent) {
|
||||
this.stop();
|
||||
this.update(this.options.responsiveAnimationDuration);
|
||||
}
|
||||
|
||||
@@ -105,14 +107,14 @@
|
||||
if (this.options.scales.xAxes && this.options.scales.xAxes.length) {
|
||||
helpers.each(this.options.scales.xAxes, function(xAxisOptions, index) {
|
||||
xAxisOptions.id = xAxisOptions.id || (defaultXAxisID + index);
|
||||
}, this);
|
||||
});
|
||||
}
|
||||
|
||||
if (this.options.scales.yAxes && this.options.scales.yAxes.length) {
|
||||
// Build the y axes
|
||||
helpers.each(this.options.scales.yAxes, function(yAxisOptions, index) {
|
||||
yAxisOptions.id = yAxisOptions.id || (defaultYAxisID + index);
|
||||
}, this);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -124,52 +126,88 @@
|
||||
if (this.options.scales) {
|
||||
if (this.options.scales.xAxes && this.options.scales.xAxes.length) {
|
||||
helpers.each(this.options.scales.xAxes, function(xAxisOptions, index) {
|
||||
var ScaleClass = Chart.scaleService.getScaleConstructor(xAxisOptions.type);
|
||||
var scale = new ScaleClass({
|
||||
ctx: this.chart.ctx,
|
||||
options: xAxisOptions,
|
||||
chart: this,
|
||||
id: xAxisOptions.id,
|
||||
});
|
||||
var xType = helpers.getValueOrDefault(xAxisOptions.type, 'category');
|
||||
var ScaleClass = Chart.scaleService.getScaleConstructor(xType);
|
||||
if (ScaleClass) {
|
||||
var scale = new ScaleClass({
|
||||
ctx: this.chart.ctx,
|
||||
options: xAxisOptions,
|
||||
chart: this,
|
||||
id: xAxisOptions.id
|
||||
});
|
||||
|
||||
this.scales[scale.id] = scale;
|
||||
this.scales[scale.id] = scale;
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
if (this.options.scales.yAxes && this.options.scales.yAxes.length) {
|
||||
// Build the y axes
|
||||
helpers.each(this.options.scales.yAxes, function(yAxisOptions, index) {
|
||||
var ScaleClass = Chart.scaleService.getScaleConstructor(yAxisOptions.type);
|
||||
var scale = new ScaleClass({
|
||||
ctx: this.chart.ctx,
|
||||
options: yAxisOptions,
|
||||
chart: this,
|
||||
id: yAxisOptions.id,
|
||||
});
|
||||
var yType = helpers.getValueOrDefault(yAxisOptions.type, 'linear');
|
||||
var ScaleClass = Chart.scaleService.getScaleConstructor(yType);
|
||||
if (ScaleClass) {
|
||||
var scale = new ScaleClass({
|
||||
ctx: this.chart.ctx,
|
||||
options: yAxisOptions,
|
||||
chart: this,
|
||||
id: yAxisOptions.id
|
||||
});
|
||||
|
||||
this.scales[scale.id] = scale;
|
||||
this.scales[scale.id] = scale;
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
if (this.options.scale) {
|
||||
// Build radial axes
|
||||
var ScaleClass = Chart.scaleService.getScaleConstructor(this.options.scale.type);
|
||||
var scale = new ScaleClass({
|
||||
ctx: this.chart.ctx,
|
||||
options: this.options.scale,
|
||||
chart: this,
|
||||
});
|
||||
if (ScaleClass) {
|
||||
var scale = new ScaleClass({
|
||||
ctx: this.chart.ctx,
|
||||
options: this.options.scale,
|
||||
chart: this
|
||||
});
|
||||
|
||||
this.scale = scale;
|
||||
this.scale = scale;
|
||||
|
||||
this.scales.radialScale = scale;
|
||||
this.scales.radialScale = scale;
|
||||
}
|
||||
}
|
||||
|
||||
Chart.scaleService.update(this, this.chart.width, this.chart.height);
|
||||
Chart.scaleService.addScalesToLayout(this);
|
||||
},
|
||||
|
||||
buildOrUpdateControllers: function buildOrUpdateControllers(resetNewControllers) {
|
||||
buildSurroundingItems: function() {
|
||||
if (this.options.title) {
|
||||
this.titleBlock = new Chart.Title({
|
||||
ctx: this.chart.ctx,
|
||||
options: this.options.title,
|
||||
chart: this
|
||||
});
|
||||
|
||||
Chart.layoutService.addBox(this, this.titleBlock);
|
||||
}
|
||||
|
||||
if (this.options.legend) {
|
||||
this.legend = new Chart.Legend({
|
||||
ctx: this.chart.ctx,
|
||||
options: this.options.legend,
|
||||
chart: this
|
||||
});
|
||||
|
||||
Chart.layoutService.addBox(this, this.legend);
|
||||
}
|
||||
},
|
||||
|
||||
updateLayout: function() {
|
||||
Chart.layoutService.update(this, this.chart.width, this.chart.height);
|
||||
},
|
||||
|
||||
buildOrUpdateControllers: function buildOrUpdateControllers() {
|
||||
var types = [];
|
||||
var newControllers = [];
|
||||
|
||||
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
|
||||
if (!dataset.type) {
|
||||
dataset.type = this.config.type;
|
||||
@@ -180,56 +218,59 @@
|
||||
|
||||
if (dataset.controller) {
|
||||
dataset.controller.updateIndex(datasetIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
dataset.controller = new Chart.controllers[type](this, datasetIndex);
|
||||
|
||||
if (resetNewControllers) {
|
||||
dataset.controller.reset();
|
||||
} else {
|
||||
dataset.controller = new Chart.controllers[type](this, datasetIndex);
|
||||
newControllers.push(dataset.controller);
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (types.length > 1) {
|
||||
for (var i = 1; i < types.length; i++) {
|
||||
if (types[i] != types[i - 1]) {
|
||||
if (types[i] !== types[i - 1]) {
|
||||
this.isCombo = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newControllers;
|
||||
},
|
||||
|
||||
resetElements: function resetElements() {
|
||||
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
|
||||
dataset.controller.reset();
|
||||
}, this);
|
||||
});
|
||||
},
|
||||
|
||||
update: function update(animationDuration, lazy) {
|
||||
// In case the entire data object changed
|
||||
this.tooltip._data = this.data;
|
||||
|
||||
Chart.scaleService.update(this, this.chart.width, this.chart.height);
|
||||
|
||||
// Make sure dataset controllers are updated and new controllers are reset
|
||||
this.buildOrUpdateControllers(true);
|
||||
var newControllers = this.buildOrUpdateControllers();
|
||||
|
||||
Chart.layoutService.update(this, this.chart.width, this.chart.height);
|
||||
|
||||
// Can only reset the new controllers after the scales have been updated
|
||||
helpers.each(newControllers, function(controller) {
|
||||
controller.reset();
|
||||
});
|
||||
|
||||
// Make sure all dataset controllers have correct meta data counts
|
||||
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
|
||||
dataset.controller.buildOrUpdateElements();
|
||||
}, this);
|
||||
});
|
||||
|
||||
// This will loop through any data and do the appropriate element update for the type
|
||||
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
|
||||
dataset.controller.update();
|
||||
}, this);
|
||||
});
|
||||
this.render(animationDuration, lazy);
|
||||
},
|
||||
|
||||
render: function render(duration, lazy) {
|
||||
|
||||
if ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration == 'undefined' && this.options.animation.duration !== 0)) {
|
||||
if (this.options.animation && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && this.options.animation.duration !== 0))) {
|
||||
var animation = new Chart.Animation();
|
||||
animation.numSteps = (duration || this.options.animation.duration) / 16.66; //60 fps
|
||||
animation.easing = this.options.animation.easing;
|
||||
@@ -244,14 +285,14 @@
|
||||
};
|
||||
|
||||
// user events
|
||||
animation.onAnimationProgress = this.options.onAnimationProgress;
|
||||
animation.onAnimationComplete = this.options.onAnimationComplete;
|
||||
animation.onAnimationProgress = this.options.animation.onProgress;
|
||||
animation.onAnimationComplete = this.options.animation.onComplete;
|
||||
|
||||
Chart.animationService.addAnimation(this, animation, duration, lazy);
|
||||
} else {
|
||||
this.draw();
|
||||
if (this.options.onAnimationComplete && this.options.onAnimationComplete.call) {
|
||||
this.options.onAnimationComplete.call(this);
|
||||
if (this.options.animation && this.options.animation.onComplete && this.options.animation.onComplete.call) {
|
||||
this.options.animation.onComplete.call(this);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
@@ -262,19 +303,28 @@
|
||||
this.clear();
|
||||
|
||||
// Draw all the scales
|
||||
helpers.each(this.scales, function(scale) {
|
||||
scale.draw(this.chartArea);
|
||||
helpers.each(this.boxes, function(box) {
|
||||
box.draw(this.chartArea);
|
||||
}, this);
|
||||
if (this.scale) {
|
||||
this.scale.draw();
|
||||
}
|
||||
|
||||
// Clip out the chart area so that anything outside does not draw. This is necessary for zoom and pan to function
|
||||
this.chart.ctx.save();
|
||||
this.chart.ctx.beginPath();
|
||||
this.chart.ctx.rect(this.chartArea.left, this.chartArea.top, this.chartArea.right - this.chartArea.left, this.chartArea.bottom - this.chartArea.top);
|
||||
this.chart.ctx.clip();
|
||||
|
||||
// Draw each dataset via its respective controller (reversed to support proper line stacking)
|
||||
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
|
||||
if (helpers.isDatasetVisible(dataset)) {
|
||||
dataset.controller.draw(ease);
|
||||
}
|
||||
}, this);
|
||||
}, null, true);
|
||||
|
||||
// Restore from the clipping operation
|
||||
this.chart.ctx.restore();
|
||||
|
||||
// Finally draw the tooltip
|
||||
this.tooltip.transition(easingDecimal).draw();
|
||||
@@ -294,9 +344,9 @@
|
||||
elementsArray.push(element);
|
||||
return elementsArray;
|
||||
}
|
||||
}, this);
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
});
|
||||
|
||||
return elementsArray;
|
||||
},
|
||||
@@ -305,48 +355,41 @@
|
||||
var eventPosition = helpers.getRelativePosition(e, this.chart);
|
||||
var elementsArray = [];
|
||||
|
||||
var found = (function(){
|
||||
for (var i = 0; i < this.data.datasets.length; i++) {
|
||||
if (helpers.isDatasetVisible(this.data.datasets[i])) {
|
||||
for (var j = 0; j < this.data.datasets[i].metaData.length; j++) {
|
||||
if (this.data.datasets[i].metaData[j].inRange(eventPosition.x, eventPosition.y)) {
|
||||
return this.data.datasets[i].metaData[j];
|
||||
var found = (function() {
|
||||
if (this.data.datasets) {
|
||||
for (var i = 0; i < this.data.datasets.length; i++) {
|
||||
if (helpers.isDatasetVisible(this.data.datasets[i])) {
|
||||
for (var j = 0; j < this.data.datasets[i].metaData.length; j++) {
|
||||
if (this.data.datasets[i].metaData[j].inRange(eventPosition.x, eventPosition.y)) {
|
||||
return this.data.datasets[i].metaData[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}).call(this);
|
||||
|
||||
if(!found){
|
||||
if (!found) {
|
||||
return elementsArray;
|
||||
}
|
||||
|
||||
helpers.each(this.data.datasets, function(dataset, dsIndex){
|
||||
if(helpers.isDatasetVisible(dataset)){
|
||||
helpers.each(this.data.datasets, function(dataset, dsIndex) {
|
||||
if (helpers.isDatasetVisible(dataset)) {
|
||||
elementsArray.push(dataset.metaData[found._index]);
|
||||
}
|
||||
}, this);
|
||||
});
|
||||
|
||||
return elementsArray;
|
||||
},
|
||||
|
||||
getDatasetAtEvent: function(e) {
|
||||
var eventPosition = helpers.getRelativePosition(e, this.chart);
|
||||
var elementsArray = [];
|
||||
var elementsArray = this.getElementAtEvent(e);
|
||||
|
||||
helpers.each(this.data.datasets, function(dataset, datasetIndex) {
|
||||
if (helpers.isDatasetVisible(dataset)) {
|
||||
helpers.each(dataset.metaData, function(element, elementIndex) {
|
||||
if (element.inLabelRange(eventPosition.x, eventPosition.y)) {
|
||||
helpers.each(dataset.metaData, function(element, index) {
|
||||
elementsArray.push(element);
|
||||
}, this);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}, this);
|
||||
if (elementsArray.length > 0) {
|
||||
elementsArray = this.data.datasets[elementsArray[0]._datasetIndex].metaData;
|
||||
}
|
||||
|
||||
return elementsArray.length ? elementsArray : [];
|
||||
return elementsArray;
|
||||
},
|
||||
|
||||
generateLegend: function generateLegend() {
|
||||
@@ -382,8 +425,9 @@
|
||||
initToolTip: function initToolTip() {
|
||||
this.tooltip = new Chart.Tooltip({
|
||||
_chart: this.chart,
|
||||
_chartInstance: this,
|
||||
_data: this.data,
|
||||
_options: this.options,
|
||||
_options: this.options
|
||||
}, this);
|
||||
},
|
||||
|
||||
@@ -397,34 +441,27 @@
|
||||
this.lastTooltipActive = this.lastTooltipActive || [];
|
||||
|
||||
// Find Active Elements for hover and tooltips
|
||||
if (e.type == 'mouseout') {
|
||||
if (e.type === 'mouseout') {
|
||||
this.active = [];
|
||||
this.tooltipActive = [];
|
||||
} else {
|
||||
this.active = function() {
|
||||
switch (this.options.hover.mode) {
|
||||
|
||||
var _this = this;
|
||||
var getItemsForMode = function(mode) {
|
||||
switch (mode) {
|
||||
case 'single':
|
||||
return this.getElementAtEvent(e);
|
||||
return _this.getElementAtEvent(e);
|
||||
case 'label':
|
||||
return this.getElementsAtEvent(e);
|
||||
return _this.getElementsAtEvent(e);
|
||||
case 'dataset':
|
||||
return this.getDatasetAtEvent(e);
|
||||
return _this.getDatasetAtEvent(e);
|
||||
default:
|
||||
return e;
|
||||
}
|
||||
}.call(this);
|
||||
this.tooltipActive = function() {
|
||||
switch (this.options.tooltips.mode) {
|
||||
case 'single':
|
||||
return this.getElementAtEvent(e);
|
||||
case 'label':
|
||||
return this.getElementsAtEvent(e);
|
||||
case 'dataset':
|
||||
return this.getDatasetAtEvent(e);
|
||||
default:
|
||||
return e;
|
||||
}
|
||||
}.call(this);
|
||||
};
|
||||
|
||||
this.active = getItemsForMode(this.options.hover.mode);
|
||||
this.tooltipActive = getItemsForMode(this.options.tooltips.mode);
|
||||
}
|
||||
|
||||
// On Hover hook
|
||||
@@ -432,10 +469,14 @@
|
||||
this.options.hover.onHover.call(this, this.active);
|
||||
}
|
||||
|
||||
if (e.type == 'mouseup' || e.type == 'click') {
|
||||
if (e.type === 'mouseup' || e.type === 'click') {
|
||||
if (this.options.onClick) {
|
||||
this.options.onClick.call(this, e, this.active);
|
||||
}
|
||||
|
||||
if (this.legend && this.legend.handleEvent) {
|
||||
this.legend.handleEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
var dataset;
|
||||
@@ -451,7 +492,7 @@
|
||||
case 'dataset':
|
||||
for (var i = 0; i < this.lastActive.length; i++) {
|
||||
if (this.lastActive[i])
|
||||
this.data.datasets[this.lastActive[i]._datasetIndex].controller.removeHoverStyle(this.lastActive[i], this.lastActive[i]._datasetIndex, this.lastActive[i]._index);
|
||||
this.data.datasets[this.lastActive[i]._datasetIndex].controller.removeHoverStyle(this.lastActive[i], this.lastActive[i]._datasetIndex, this.lastActive[i]._index);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -469,7 +510,7 @@
|
||||
case 'dataset':
|
||||
for (var j = 0; j < this.active.length; j++) {
|
||||
if (this.active[j])
|
||||
this.data.datasets[this.active[j]._datasetIndex].controller.setHoverStyle(this.active[j]);
|
||||
this.data.datasets[this.active[j]._datasetIndex].controller.setHoverStyle(this.active[j]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -526,7 +567,6 @@
|
||||
this.lastActive = this.active;
|
||||
this.lastTooltipActive = this.tooltipActive;
|
||||
return this;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
// Base class for all dataset controllers (line, bar, etc)
|
||||
Chart.DatasetController = function(chart, datasetIndex) {
|
||||
this.initialize.call(this, chart, datasetIndex);
|
||||
};
|
||||
|
||||
helpers.extend(Chart.DatasetController.prototype, {
|
||||
initialize: function(chart, datasetIndex) {
|
||||
this.chart = chart;
|
||||
this.index = datasetIndex;
|
||||
this.linkScales();
|
||||
this.addElements();
|
||||
},
|
||||
updateIndex: function(datasetIndex) {
|
||||
this.index = datasetIndex;
|
||||
},
|
||||
|
||||
linkScales: function() {
|
||||
if (!this.getDataset().xAxisID) {
|
||||
this.getDataset().xAxisID = this.chart.options.scales.xAxes[0].id;
|
||||
}
|
||||
|
||||
if (!this.getDataset().yAxisID) {
|
||||
this.getDataset().yAxisID = this.chart.options.scales.yAxes[0].id;
|
||||
}
|
||||
},
|
||||
|
||||
getDataset: function() {
|
||||
return this.chart.data.datasets[this.index];
|
||||
},
|
||||
|
||||
getScaleForId: function(scaleID) {
|
||||
return this.chart.scales[scaleID];
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.update(true);
|
||||
},
|
||||
|
||||
buildOrUpdateElements: function buildOrUpdateElements() {
|
||||
// Handle the number of data points changing
|
||||
var numData = this.getDataset().data.length;
|
||||
var numMetaData = this.getDataset().metaData.length;
|
||||
|
||||
// Make sure that we handle number of datapoints changing
|
||||
if (numData < numMetaData) {
|
||||
// Remove excess bars for data points that have been removed
|
||||
this.getDataset().metaData.splice(numData, numMetaData - numData);
|
||||
} else if (numData > numMetaData) {
|
||||
// Add new elements
|
||||
for (var index = numMetaData; index < numData; ++index) {
|
||||
this.addElementAndReset(index);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Controllers should implement the following
|
||||
addElements: helpers.noop,
|
||||
addElementAndReset: helpers.noop,
|
||||
draw: helpers.noop,
|
||||
removeHoverStyle: helpers.noop,
|
||||
setHoverStyle: helpers.noop,
|
||||
update: helpers.noop
|
||||
});
|
||||
|
||||
Chart.DatasetController.extend = helpers.inherits;
|
||||
|
||||
};
|
||||
+81
-79
@@ -1,91 +1,93 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
"use strict";
|
||||
module.exports = function(Chart) {
|
||||
|
||||
//Declare root variable - window in the browser, global on the server
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.elements = {};
|
||||
Chart.elements = {};
|
||||
|
||||
Chart.Element = function(configuration) {
|
||||
helpers.extend(this, configuration);
|
||||
this.initialize.apply(this, arguments);
|
||||
};
|
||||
helpers.extend(Chart.Element.prototype, {
|
||||
initialize: function() {},
|
||||
pivot: function() {
|
||||
if (!this._view) {
|
||||
this._view = helpers.clone(this._model);
|
||||
}
|
||||
this._start = helpers.clone(this._view);
|
||||
return this;
|
||||
},
|
||||
transition: function(ease) {
|
||||
if (!this._view) {
|
||||
this._view = helpers.clone(this._model);
|
||||
}
|
||||
if (!this._start) {
|
||||
this.pivot();
|
||||
}
|
||||
Chart.Element = function(configuration) {
|
||||
helpers.extend(this, configuration);
|
||||
this.initialize.apply(this, arguments);
|
||||
};
|
||||
helpers.extend(Chart.Element.prototype, {
|
||||
initialize: function() {},
|
||||
pivot: function() {
|
||||
if (!this._view) {
|
||||
this._view = helpers.clone(this._model);
|
||||
}
|
||||
this._start = helpers.clone(this._view);
|
||||
return this;
|
||||
},
|
||||
transition: function(ease) {
|
||||
if (!this._view) {
|
||||
this._view = helpers.clone(this._model);
|
||||
}
|
||||
|
||||
helpers.each(this._model, function(value, key) {
|
||||
// No animation -> No Transition
|
||||
if (ease === 1) {
|
||||
this._view = this._model;
|
||||
this._start = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (key[0] === '_' || !this._model.hasOwnProperty(key)) {
|
||||
// Only non-underscored properties
|
||||
}
|
||||
if (!this._start) {
|
||||
this.pivot();
|
||||
}
|
||||
|
||||
// Init if doesn't exist
|
||||
else if (!this._view[key]) {
|
||||
if (typeof value === 'number' && isNaN(this._view[key]) === false) {
|
||||
this._view[key] = value * ease;
|
||||
} else {
|
||||
this._view[key] = value || null;
|
||||
}
|
||||
}
|
||||
helpers.each(this._model, function(value, key) {
|
||||
|
||||
// No unnecessary computations
|
||||
else if (this._model[key] === this._view[key]) {
|
||||
// It's the same! Woohoo!
|
||||
}
|
||||
if (key[0] === '_' || !this._model.hasOwnProperty(key)) {
|
||||
// Only non-underscored properties
|
||||
}
|
||||
|
||||
// Color transitions if possible
|
||||
else if (typeof value === 'string') {
|
||||
try {
|
||||
var color = helpers.color(this._start[key]).mix(helpers.color(this._model[key]), ease);
|
||||
this._view[key] = color.rgbString();
|
||||
} catch (err) {
|
||||
this._view[key] = value;
|
||||
}
|
||||
}
|
||||
// Number transitions
|
||||
else if (typeof value === 'number') {
|
||||
var startVal = this._start[key] !== undefined && isNaN(this._start[key]) === false ? this._start[key] : 0;
|
||||
this._view[key] = ((this._model[key] - startVal) * ease) + startVal;
|
||||
}
|
||||
// Everything else
|
||||
else {
|
||||
this._view[key] = value;
|
||||
}
|
||||
}, this);
|
||||
// Init if doesn't exist
|
||||
else if (!this._view.hasOwnProperty(key)) {
|
||||
if (typeof value === 'number' && !isNaN(this._view[key])) {
|
||||
this._view[key] = value * ease;
|
||||
} else {
|
||||
this._view[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (ease === 1) {
|
||||
delete this._start;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
tooltipPosition: function() {
|
||||
return {
|
||||
x: this._model.x,
|
||||
y: this._model.y
|
||||
};
|
||||
},
|
||||
hasValue: function() {
|
||||
return helpers.isNumber(this._model.x) && helpers.isNumber(this._model.y);
|
||||
}
|
||||
});
|
||||
// No unnecessary computations
|
||||
else if (value === this._view[key]) {
|
||||
// It's the same! Woohoo!
|
||||
}
|
||||
|
||||
Chart.Element.extend = helpers.inherits;
|
||||
// Color transitions if possible
|
||||
else if (typeof value === 'string') {
|
||||
try {
|
||||
var color = helpers.color(this._start[key]).mix(helpers.color(this._model[key]), ease);
|
||||
this._view[key] = color.rgbString();
|
||||
} catch (err) {
|
||||
this._view[key] = value;
|
||||
}
|
||||
}
|
||||
// Number transitions
|
||||
else if (typeof value === 'number') {
|
||||
var startVal = this._start[key] !== undefined && isNaN(this._start[key]) === false ? this._start[key] : 0;
|
||||
this._view[key] = ((this._model[key] - startVal) * ease) + startVal;
|
||||
}
|
||||
// Everything else
|
||||
else {
|
||||
this._view[key] = value;
|
||||
}
|
||||
}, this);
|
||||
|
||||
}).call(this);
|
||||
return this;
|
||||
},
|
||||
tooltipPosition: function() {
|
||||
return {
|
||||
x: this._model.x,
|
||||
y: this._model.y
|
||||
};
|
||||
},
|
||||
hasValue: function() {
|
||||
return helpers.isNumber(this._model.x) && helpers.isNumber(this._model.y);
|
||||
}
|
||||
});
|
||||
|
||||
Chart.Element.extend = helpers.inherits;
|
||||
|
||||
};
|
||||
|
||||
+892
-800
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+12
-35
@@ -1,21 +1,6 @@
|
||||
/*!
|
||||
* Chart.js
|
||||
* http://chartjs.org/
|
||||
* Version: {{ version }}
|
||||
*
|
||||
* Copyright 2015 Nick Downie
|
||||
* Released under the MIT license
|
||||
* https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
|
||||
(function() {
|
||||
|
||||
"use strict";
|
||||
|
||||
//Declare root variable - window in the browser, global on the server
|
||||
var root = this,
|
||||
previous = root.Chart;
|
||||
module.exports = function() {
|
||||
|
||||
//Occupy the global variable of Chart, and create a simple base class
|
||||
var Chart = function(context, config) {
|
||||
@@ -36,7 +21,7 @@
|
||||
|
||||
// Figure out what the size of the chart will be.
|
||||
// If the canvas has a specified width and height, we use those else
|
||||
// we look to see if the canvas node has a CSS width and height.
|
||||
// we look to see if the canvas node has a CSS width and height.
|
||||
// If there is still no height, fill the parent container
|
||||
this.width = context.canvas.width || parseInt(Chart.helpers.getStyle(context.canvas, 'width')) || Chart.helpers.getMaximumWidth(context.canvas);
|
||||
this.height = context.canvas.height || parseInt(Chart.helpers.getStyle(context.canvas, 'height')) || Chart.helpers.getMaximumHeight(context.canvas);
|
||||
@@ -83,10 +68,15 @@
|
||||
hover: {
|
||||
onHover: null,
|
||||
mode: 'single',
|
||||
animationDuration: 400,
|
||||
animationDuration: 400
|
||||
},
|
||||
onClick: null,
|
||||
defaultColor: 'rgba(0,0,0,0.1)',
|
||||
defaultFontColor: '#666',
|
||||
defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
|
||||
defaultFontSize: 12,
|
||||
defaultFontStyle: 'normal',
|
||||
showLines: true,
|
||||
|
||||
// Element defaults defined in element extensions
|
||||
elements: {},
|
||||
@@ -106,22 +96,9 @@
|
||||
|
||||
return text.join("");
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof amd !== 'undefined') {
|
||||
define(function() {
|
||||
return Chart;
|
||||
});
|
||||
} else if (typeof module === 'object' && module.exports) {
|
||||
module.exports = Chart;
|
||||
}
|
||||
return Chart;
|
||||
|
||||
root.Chart = Chart;
|
||||
|
||||
Chart.noConflict = function() {
|
||||
root.Chart = previous;
|
||||
return Chart;
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
@@ -0,0 +1,323 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
// The layout service is very self explanatory. It's responsible for the layout within a chart.
|
||||
// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
|
||||
// It is this service's responsibility of carrying out that layout.
|
||||
Chart.layoutService = {
|
||||
defaults: {},
|
||||
|
||||
// Register a box to a chartInstance. A box is simply a reference to an object that requires layout. eg. Scales, Legend, Plugins.
|
||||
addBox: function(chartInstance, box) {
|
||||
if (!chartInstance.boxes) {
|
||||
chartInstance.boxes = [];
|
||||
}
|
||||
chartInstance.boxes.push(box);
|
||||
},
|
||||
|
||||
removeBox: function(chartInstance, box) {
|
||||
if (!chartInstance.boxes) {
|
||||
return;
|
||||
}
|
||||
chartInstance.boxes.splice(chartInstance.boxes.indexOf(box), 1);
|
||||
},
|
||||
|
||||
// The most important function
|
||||
update: function(chartInstance, width, height) {
|
||||
|
||||
if (!chartInstance) {
|
||||
return;
|
||||
}
|
||||
|
||||
var xPadding = 0;
|
||||
var yPadding = 0;
|
||||
|
||||
var leftBoxes = helpers.where(chartInstance.boxes, function(box) {
|
||||
return box.options.position === "left";
|
||||
});
|
||||
var rightBoxes = helpers.where(chartInstance.boxes, function(box) {
|
||||
return box.options.position === "right";
|
||||
});
|
||||
var topBoxes = helpers.where(chartInstance.boxes, function(box) {
|
||||
return box.options.position === "top";
|
||||
});
|
||||
var bottomBoxes = helpers.where(chartInstance.boxes, function(box) {
|
||||
return box.options.position === "bottom";
|
||||
});
|
||||
|
||||
// Boxes that overlay the chartarea such as the radialLinear scale
|
||||
var chartAreaBoxes = helpers.where(chartInstance.boxes, function(box) {
|
||||
return box.options.position === "chartArea";
|
||||
});
|
||||
|
||||
function fullWidthSorter(a, b) {
|
||||
|
||||
}
|
||||
|
||||
// Ensure that full width boxes are at the very top / bottom
|
||||
topBoxes.sort(function(a, b) {
|
||||
return (b.options.fullWidth ? 1 : 0) - (a.options.fullWidth ? 1 : 0);
|
||||
});
|
||||
bottomBoxes.sort(function(a, b) {
|
||||
return (a.options.fullWidth ? 1 : 0) - (b.options.fullWidth ? 1 : 0);
|
||||
});
|
||||
|
||||
// Essentially we now have any number of boxes on each of the 4 sides.
|
||||
// Our canvas looks like the following.
|
||||
// The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
|
||||
// B1 is the bottom axis
|
||||
// There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
|
||||
// These locations are single-box locations only, when trying to register a chartArea location that is already taken,
|
||||
// an error will be thrown.
|
||||
//
|
||||
// |----------------------------------------------------|
|
||||
// | T1 (Full Width) |
|
||||
// |----------------------------------------------------|
|
||||
// | | | T2 | |
|
||||
// | |----|-------------------------------------|----|
|
||||
// | | | C1 | | C2 | |
|
||||
// | | |----| |----| |
|
||||
// | | | | |
|
||||
// | L1 | L2 | ChartArea (C0) | R1 |
|
||||
// | | | | |
|
||||
// | | |----| |----| |
|
||||
// | | | C3 | | C4 | |
|
||||
// | |----|-------------------------------------|----|
|
||||
// | | | B1 | |
|
||||
// |----------------------------------------------------|
|
||||
// | B2 (Full Width) |
|
||||
// |----------------------------------------------------|
|
||||
//
|
||||
// What we do to find the best sizing, we do the following
|
||||
// 1. Determine the minimum size of the chart area.
|
||||
// 2. Split the remaining width equally between each vertical axis
|
||||
// 3. Split the remaining height equally between each horizontal axis
|
||||
// 4. Give each layout the maximum size it can be. The layout will return it's minimum size
|
||||
// 5. Adjust the sizes of each axis based on it's minimum reported size.
|
||||
// 6. Refit each axis
|
||||
// 7. Position each axis in the final location
|
||||
// 8. Tell the chart the final location of the chart area
|
||||
// 9. Tell any axes that overlay the chart area the positions of the chart area
|
||||
|
||||
// Step 1
|
||||
var chartWidth = width - (2 * xPadding);
|
||||
var chartHeight = height - (2 * yPadding);
|
||||
var chartAreaWidth = chartWidth / 2; // min 50%
|
||||
var chartAreaHeight = chartHeight / 2; // min 50%
|
||||
|
||||
// Step 2
|
||||
var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);
|
||||
|
||||
// Step 3
|
||||
var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);
|
||||
|
||||
// Step 4
|
||||
var maxChartAreaWidth = chartWidth;
|
||||
var maxChartAreaHeight = chartHeight;
|
||||
var minBoxSizes = [];
|
||||
|
||||
helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);
|
||||
|
||||
function getMinimumBoxSize(box) {
|
||||
var minSize;
|
||||
var isHorizontal = box.isHorizontal();
|
||||
|
||||
if (isHorizontal) {
|
||||
minSize = box.update(box.options.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
|
||||
maxChartAreaHeight -= minSize.height;
|
||||
} else {
|
||||
minSize = box.update(verticalBoxWidth, chartAreaHeight);
|
||||
maxChartAreaWidth -= minSize.width;
|
||||
}
|
||||
|
||||
minBoxSizes.push({
|
||||
horizontal: isHorizontal,
|
||||
minSize: minSize,
|
||||
box: box
|
||||
});
|
||||
}
|
||||
|
||||
// At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
|
||||
// be if the axes are drawn at their minimum sizes.
|
||||
|
||||
// Steps 5 & 6
|
||||
var totalLeftBoxesWidth = xPadding;
|
||||
var totalRightBoxesWidth = xPadding;
|
||||
var totalTopBoxesHeight = yPadding;
|
||||
var totalBottomBoxesHeight = yPadding;
|
||||
|
||||
// Update, and calculate the left and right margins for the horizontal boxes
|
||||
helpers.each(leftBoxes.concat(rightBoxes), fitBox);
|
||||
|
||||
helpers.each(leftBoxes, function(box) {
|
||||
totalLeftBoxesWidth += box.width;
|
||||
});
|
||||
|
||||
helpers.each(rightBoxes, function(box) {
|
||||
totalRightBoxesWidth += box.width;
|
||||
});
|
||||
|
||||
// Set the Left and Right margins for the horizontal boxes
|
||||
helpers.each(topBoxes.concat(bottomBoxes), fitBox);
|
||||
|
||||
// Function to fit a box
|
||||
function fitBox(box) {
|
||||
var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
|
||||
return minBoxSize.box === box;
|
||||
});
|
||||
|
||||
if (minBoxSize) {
|
||||
if (box.isHorizontal()) {
|
||||
var scaleMargin = {
|
||||
left: totalLeftBoxesWidth,
|
||||
right: totalRightBoxesWidth,
|
||||
top: 0,
|
||||
bottom: 0
|
||||
};
|
||||
|
||||
// Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
|
||||
// on the margin. Sometimes they need to increase in size slightly
|
||||
box.update(box.options.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
|
||||
} else {
|
||||
box.update(minBoxSize.minSize.width, maxChartAreaHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out how much margin is on the top and bottom of the vertical boxes
|
||||
helpers.each(topBoxes, function(box) {
|
||||
totalTopBoxesHeight += box.height;
|
||||
});
|
||||
|
||||
helpers.each(bottomBoxes, function(box) {
|
||||
totalBottomBoxesHeight += box.height;
|
||||
});
|
||||
|
||||
// Let the left layout know the final margin
|
||||
helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);
|
||||
|
||||
function finalFitVerticalBox(box) {
|
||||
var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
|
||||
return minBoxSize.box === box;
|
||||
});
|
||||
|
||||
var scaleMargin = {
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: totalTopBoxesHeight,
|
||||
bottom: totalBottomBoxesHeight
|
||||
};
|
||||
|
||||
if (minBoxSize) {
|
||||
box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
|
||||
}
|
||||
}
|
||||
|
||||
// Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
|
||||
totalLeftBoxesWidth = xPadding;
|
||||
totalRightBoxesWidth = xPadding;
|
||||
totalTopBoxesHeight = yPadding;
|
||||
totalBottomBoxesHeight = yPadding;
|
||||
|
||||
helpers.each(leftBoxes, function(box) {
|
||||
totalLeftBoxesWidth += box.width;
|
||||
});
|
||||
|
||||
helpers.each(rightBoxes, function(box) {
|
||||
totalRightBoxesWidth += box.width;
|
||||
});
|
||||
|
||||
helpers.each(topBoxes, function(box) {
|
||||
totalTopBoxesHeight += box.height;
|
||||
});
|
||||
helpers.each(bottomBoxes, function(box) {
|
||||
totalBottomBoxesHeight += box.height;
|
||||
});
|
||||
|
||||
// Figure out if our chart area changed. This would occur if the dataset layout label rotation
|
||||
// changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
|
||||
// without calling `fit` again
|
||||
var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
|
||||
var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;
|
||||
|
||||
if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
|
||||
helpers.each(leftBoxes, function(box) {
|
||||
box.height = newMaxChartAreaHeight;
|
||||
});
|
||||
|
||||
helpers.each(rightBoxes, function(box) {
|
||||
box.height = newMaxChartAreaHeight;
|
||||
});
|
||||
|
||||
helpers.each(topBoxes, function(box) {
|
||||
box.width = newMaxChartAreaWidth;
|
||||
});
|
||||
|
||||
helpers.each(bottomBoxes, function(box) {
|
||||
box.width = newMaxChartAreaWidth;
|
||||
});
|
||||
|
||||
maxChartAreaHeight = newMaxChartAreaHeight;
|
||||
maxChartAreaWidth = newMaxChartAreaWidth;
|
||||
}
|
||||
|
||||
// Step 7 - Position the boxes
|
||||
var left = xPadding;
|
||||
var top = yPadding;
|
||||
var right = 0;
|
||||
var bottom = 0;
|
||||
|
||||
helpers.each(leftBoxes.concat(topBoxes), placeBox);
|
||||
|
||||
// Account for chart width and height
|
||||
left += maxChartAreaWidth;
|
||||
top += maxChartAreaHeight;
|
||||
|
||||
helpers.each(rightBoxes, placeBox);
|
||||
helpers.each(bottomBoxes, placeBox);
|
||||
|
||||
function placeBox(box) {
|
||||
if (box.isHorizontal()) {
|
||||
box.left = box.options.fullWidth ? xPadding : totalLeftBoxesWidth;
|
||||
box.right = box.options.fullWidth ? width - xPadding : totalLeftBoxesWidth + maxChartAreaWidth;
|
||||
box.top = top;
|
||||
box.bottom = top + box.height;
|
||||
|
||||
// Move to next point
|
||||
top = box.bottom;
|
||||
|
||||
} else {
|
||||
|
||||
box.left = left;
|
||||
box.right = left + box.width;
|
||||
box.top = totalTopBoxesHeight;
|
||||
box.bottom = totalTopBoxesHeight + maxChartAreaHeight;
|
||||
|
||||
// Move to next point
|
||||
left = box.right;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 8
|
||||
chartInstance.chartArea = {
|
||||
left: totalLeftBoxesWidth,
|
||||
top: totalTopBoxesHeight,
|
||||
right: totalLeftBoxesWidth + maxChartAreaWidth,
|
||||
bottom: totalTopBoxesHeight + maxChartAreaHeight
|
||||
};
|
||||
|
||||
// Step 9
|
||||
helpers.each(chartAreaBoxes, function(box) {
|
||||
box.left = chartInstance.chartArea.left;
|
||||
box.top = chartInstance.chartArea.top;
|
||||
box.right = chartInstance.chartArea.right;
|
||||
box.bottom = chartInstance.chartArea.bottom;
|
||||
|
||||
box.update(maxChartAreaWidth, maxChartAreaHeight);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,331 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.defaults.global.legend = {
|
||||
|
||||
display: true,
|
||||
position: 'top',
|
||||
fullWidth: true, // marks that this box should take the full width of the canvas (pushing down other boxes)
|
||||
reverse: false,
|
||||
|
||||
// a callback that will handle
|
||||
onClick: function(e, legendItem) {
|
||||
var dataset = this.chart.data.datasets[legendItem.datasetIndex];
|
||||
dataset.hidden = !dataset.hidden;
|
||||
|
||||
// We hid a dataset ... rerender the chart
|
||||
this.chart.update();
|
||||
},
|
||||
|
||||
labels: {
|
||||
boxWidth: 40,
|
||||
padding: 10,
|
||||
// Generates labels shown in the legend
|
||||
// Valid properties to return:
|
||||
// text : text to display
|
||||
// fillStyle : fill of coloured box
|
||||
// strokeStyle: stroke of coloured box
|
||||
// hidden : if this legend item refers to a hidden item
|
||||
// lineCap : cap style for line
|
||||
// lineDash
|
||||
// lineDashOffset :
|
||||
// lineJoin :
|
||||
// lineWidth :
|
||||
generateLabels: function(data) {
|
||||
return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
|
||||
return {
|
||||
text: dataset.label,
|
||||
fillStyle: dataset.backgroundColor,
|
||||
hidden: dataset.hidden,
|
||||
lineCap: dataset.borderCapStyle,
|
||||
lineDash: dataset.borderDash,
|
||||
lineDashOffset: dataset.borderDashOffset,
|
||||
lineJoin: dataset.borderJoinStyle,
|
||||
lineWidth: dataset.borderWidth,
|
||||
strokeStyle: dataset.borderColor,
|
||||
|
||||
// Below is extra data used for toggling the datasets
|
||||
datasetIndex: i
|
||||
};
|
||||
}, this) : [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Chart.Legend = Chart.Element.extend({
|
||||
|
||||
initialize: function(config) {
|
||||
helpers.extend(this, config);
|
||||
|
||||
// Contains hit boxes for each dataset (in dataset order)
|
||||
this.legendHitBoxes = [];
|
||||
|
||||
// Are we in doughnut mode which has a different data type
|
||||
this.doughnutMode = false;
|
||||
},
|
||||
|
||||
// These methods are ordered by lifecyle. Utilities then follow.
|
||||
// Any function defined here is inherited by all legend types.
|
||||
// Any function can be extended by the legend type
|
||||
|
||||
beforeUpdate: helpers.noop,
|
||||
update: function(maxWidth, maxHeight, margins) {
|
||||
|
||||
// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
|
||||
this.beforeUpdate();
|
||||
|
||||
// Absorb the master measurements
|
||||
this.maxWidth = maxWidth;
|
||||
this.maxHeight = maxHeight;
|
||||
this.margins = margins;
|
||||
|
||||
// Dimensions
|
||||
this.beforeSetDimensions();
|
||||
this.setDimensions();
|
||||
this.afterSetDimensions();
|
||||
// Labels
|
||||
this.beforeBuildLabels();
|
||||
this.buildLabels();
|
||||
this.afterBuildLabels();
|
||||
|
||||
// Fit
|
||||
this.beforeFit();
|
||||
this.fit();
|
||||
this.afterFit();
|
||||
//
|
||||
this.afterUpdate();
|
||||
|
||||
return this.minSize;
|
||||
|
||||
},
|
||||
afterUpdate: helpers.noop,
|
||||
|
||||
//
|
||||
|
||||
beforeSetDimensions: helpers.noop,
|
||||
setDimensions: function() {
|
||||
// Set the unconstrained dimension before label rotation
|
||||
if (this.isHorizontal()) {
|
||||
// Reset position before calculating rotation
|
||||
this.width = this.maxWidth;
|
||||
this.left = 0;
|
||||
this.right = this.width;
|
||||
} else {
|
||||
this.height = this.maxHeight;
|
||||
|
||||
// Reset position before calculating rotation
|
||||
this.top = 0;
|
||||
this.bottom = this.height;
|
||||
}
|
||||
|
||||
// Reset padding
|
||||
this.paddingLeft = 0;
|
||||
this.paddingTop = 0;
|
||||
this.paddingRight = 0;
|
||||
this.paddingBottom = 0;
|
||||
|
||||
// Reset minSize
|
||||
this.minSize = {
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
},
|
||||
afterSetDimensions: helpers.noop,
|
||||
|
||||
//
|
||||
|
||||
beforeBuildLabels: helpers.noop,
|
||||
buildLabels: function() {
|
||||
this.legendItems = this.options.labels.generateLabels.call(this, this.chart.data);
|
||||
if(this.options.reverse){
|
||||
this.legendItems.reverse();
|
||||
}
|
||||
},
|
||||
afterBuildLabels: helpers.noop,
|
||||
|
||||
//
|
||||
|
||||
beforeFit: helpers.noop,
|
||||
fit: function() {
|
||||
|
||||
var ctx = this.ctx;
|
||||
var fontSize = helpers.getValueOrDefault(this.options.labels.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var fontStyle = helpers.getValueOrDefault(this.options.labels.fontStyle, Chart.defaults.global.defaultFontStyle);
|
||||
var fontFamily = helpers.getValueOrDefault(this.options.labels.fontFamily, Chart.defaults.global.defaultFontFamily);
|
||||
var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
|
||||
|
||||
// Reset hit boxes
|
||||
this.legendHitBoxes = [];
|
||||
|
||||
// Width
|
||||
if (this.isHorizontal()) {
|
||||
this.minSize.width = this.maxWidth; // fill all the width
|
||||
} else {
|
||||
this.minSize.width = this.options.display ? 10 : 0;
|
||||
}
|
||||
|
||||
// height
|
||||
if (this.isHorizontal()) {
|
||||
this.minSize.height = this.options.display ? 10 : 0;
|
||||
} else {
|
||||
this.minSize.height = this.maxHeight; // fill all the height
|
||||
}
|
||||
|
||||
// Increase sizes here
|
||||
if (this.options.display) {
|
||||
if (this.isHorizontal()) {
|
||||
// Labels
|
||||
|
||||
// Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
|
||||
this.lineWidths = [0];
|
||||
var totalHeight = this.legendItems.length ? fontSize + (this.options.labels.padding) : 0;
|
||||
|
||||
ctx.textAlign = "left";
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.font = labelFont;
|
||||
|
||||
helpers.each(this.legendItems, function(legendItem, i) {
|
||||
var width = this.options.labels.boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
|
||||
if (this.lineWidths[this.lineWidths.length - 1] + width + this.options.labels.padding >= this.width) {
|
||||
totalHeight += fontSize + (this.options.labels.padding);
|
||||
this.lineWidths[this.lineWidths.length] = this.left;
|
||||
}
|
||||
|
||||
// Store the hitbox width and height here. Final position will be updated in `draw`
|
||||
this.legendHitBoxes[i] = {
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: width,
|
||||
height: fontSize
|
||||
};
|
||||
|
||||
this.lineWidths[this.lineWidths.length - 1] += width + this.options.labels.padding;
|
||||
}, this);
|
||||
|
||||
this.minSize.height += totalHeight;
|
||||
|
||||
} else {
|
||||
// TODO vertical
|
||||
}
|
||||
}
|
||||
|
||||
this.width = this.minSize.width;
|
||||
this.height = this.minSize.height;
|
||||
|
||||
},
|
||||
afterFit: helpers.noop,
|
||||
|
||||
// Shared Methods
|
||||
isHorizontal: function() {
|
||||
return this.options.position === "top" || this.options.position === "bottom";
|
||||
},
|
||||
|
||||
// Actualy draw the legend on the canvas
|
||||
draw: function() {
|
||||
if (this.options.display) {
|
||||
var ctx = this.ctx;
|
||||
var cursor = {
|
||||
x: this.left + ((this.width - this.lineWidths[0]) / 2),
|
||||
y: this.top + this.options.labels.padding,
|
||||
line: 0
|
||||
};
|
||||
|
||||
var fontColor = helpers.getValueOrDefault(this.options.labels.fontColor, Chart.defaults.global.defaultFontColor);
|
||||
var fontSize = helpers.getValueOrDefault(this.options.labels.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var fontStyle = helpers.getValueOrDefault(this.options.labels.fontStyle, Chart.defaults.global.defaultFontStyle);
|
||||
var fontFamily = helpers.getValueOrDefault(this.options.labels.fontFamily, Chart.defaults.global.defaultFontFamily);
|
||||
var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
|
||||
|
||||
// Horizontal
|
||||
if (this.isHorizontal()) {
|
||||
// Labels
|
||||
ctx.textAlign = "left";
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.lineWidth = 0.5;
|
||||
ctx.strokeStyle = fontColor; // for strikethrough effect
|
||||
ctx.fillStyle = fontColor; // render in correct colour
|
||||
ctx.font = labelFont;
|
||||
|
||||
helpers.each(this.legendItems, function(legendItem, i) {
|
||||
var textWidth = ctx.measureText(legendItem.text).width;
|
||||
var width = this.options.labels.boxWidth + (fontSize / 2) + textWidth;
|
||||
|
||||
if (cursor.x + width >= this.width) {
|
||||
cursor.y += fontSize + (this.options.labels.padding);
|
||||
cursor.line++;
|
||||
cursor.x = this.left + ((this.width - this.lineWidths[cursor.line]) / 2);
|
||||
}
|
||||
|
||||
// Set the ctx for the box
|
||||
ctx.save();
|
||||
|
||||
var itemOrDefault = function(item, defaulVal) {
|
||||
return item !== undefined ? item : defaulVal;
|
||||
};
|
||||
|
||||
ctx.fillStyle = itemOrDefault(legendItem.fillStyle, Chart.defaults.global.defaultColor);
|
||||
ctx.lineCap = itemOrDefault(legendItem.lineCap, Chart.defaults.global.elements.line.borderCapStyle);
|
||||
ctx.lineDashOffset = itemOrDefault(legendItem.lineDashOffset, Chart.defaults.global.elements.line.borderDashOffset);
|
||||
ctx.lineJoin = itemOrDefault(legendItem.lineJoin, Chart.defaults.global.elements.line.borderJoinStyle);
|
||||
ctx.lineWidth = itemOrDefault(legendItem.lineWidth, Chart.defaults.global.elements.line.borderWidth);
|
||||
ctx.strokeStyle = itemOrDefault(legendItem.strokeStyle, Chart.defaults.global.defaultColor);
|
||||
|
||||
if (ctx.setLineDash) {
|
||||
// IE 9 and 10 do not support line dash
|
||||
ctx.setLineDash(itemOrDefault(legendItem.lineDash, Chart.defaults.global.elements.line.borderDash));
|
||||
}
|
||||
|
||||
// Draw the box
|
||||
ctx.strokeRect(cursor.x, cursor.y, this.options.labels.boxWidth, fontSize);
|
||||
ctx.fillRect(cursor.x, cursor.y, this.options.labels.boxWidth, fontSize);
|
||||
|
||||
ctx.restore();
|
||||
|
||||
this.legendHitBoxes[i].left = cursor.x;
|
||||
this.legendHitBoxes[i].top = cursor.y;
|
||||
|
||||
// Fill the actual label
|
||||
ctx.fillText(legendItem.text, this.options.labels.boxWidth + (fontSize / 2) + cursor.x, cursor.y);
|
||||
|
||||
if (legendItem.hidden) {
|
||||
// Strikethrough the text if hidden
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = 2;
|
||||
ctx.moveTo(this.options.labels.boxWidth + (fontSize / 2) + cursor.x, cursor.y + (fontSize / 2));
|
||||
ctx.lineTo(this.options.labels.boxWidth + (fontSize / 2) + cursor.x + textWidth, cursor.y + (fontSize / 2));
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
cursor.x += width + (this.options.labels.padding);
|
||||
}, this);
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Handle an event
|
||||
handleEvent: function(e) {
|
||||
var position = helpers.getRelativePosition(e, this.chart.chart);
|
||||
|
||||
if (position.x >= this.left && position.x <= this.right && position.y >= this.top && position.y <= this.bottom) {
|
||||
// See if we are touching one of the dataset boxes
|
||||
for (var i = 0; i < this.legendHitBoxes.length; ++i) {
|
||||
var hitBox = this.legendHitBoxes[i];
|
||||
|
||||
if (position.x >= hitBox.left && position.x <= hitBox.left + hitBox.width && position.y >= hitBox.top && position.y <= hitBox.top + hitBox.height) {
|
||||
// Touching an element
|
||||
if (this.options.onClick) {
|
||||
this.options.onClick.call(this, e, this.legendItems[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
+247
-134
@@ -1,9 +1,8 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.defaults.scale = {
|
||||
display: true,
|
||||
@@ -17,40 +16,32 @@
|
||||
drawTicks: true,
|
||||
zeroLineWidth: 1,
|
||||
zeroLineColor: "rgba(0,0,0,0.25)",
|
||||
offsetGridLines: false,
|
||||
offsetGridLines: false
|
||||
},
|
||||
|
||||
// scale label
|
||||
scaleLabel: {
|
||||
fontColor: '#666',
|
||||
fontFamily: 'Helvetica Neue',
|
||||
fontSize: 12,
|
||||
fontStyle: 'normal',
|
||||
|
||||
// actual label
|
||||
labelString: '',
|
||||
|
||||
// display property
|
||||
display: false,
|
||||
display: false
|
||||
},
|
||||
|
||||
// label settings
|
||||
ticks: {
|
||||
beginAtZero: false,
|
||||
fontSize: 12,
|
||||
fontStyle: "normal",
|
||||
fontColor: "#666",
|
||||
fontFamily: "Helvetica Neue",
|
||||
maxRotation: 90,
|
||||
minRotation: 20,
|
||||
mirror: false,
|
||||
padding: 10,
|
||||
reverse: false,
|
||||
display: true,
|
||||
autoSkip: true,
|
||||
autoSkipPadding: 20,
|
||||
callback: function(value) {
|
||||
return '' + value;
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Chart.Scale = Chart.Element.extend({
|
||||
@@ -59,7 +50,9 @@
|
||||
// Any function defined here is inherited by all scale types.
|
||||
// Any function can be extended by the scale type
|
||||
|
||||
beforeUpdate: helpers.noop,
|
||||
beforeUpdate: function() {
|
||||
helpers.callCallback(this.options.beforeUpdate, [this]);
|
||||
},
|
||||
update: function(maxWidth, maxHeight, margins) {
|
||||
|
||||
// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
|
||||
@@ -68,12 +61,23 @@
|
||||
// Absorb the master measurements
|
||||
this.maxWidth = maxWidth;
|
||||
this.maxHeight = maxHeight;
|
||||
this.margins = margins;
|
||||
this.margins = helpers.extend({
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0
|
||||
}, margins);
|
||||
|
||||
// Dimensions
|
||||
this.beforeSetDimensions();
|
||||
this.setDimensions();
|
||||
this.afterSetDimensions();
|
||||
|
||||
// Data min/max
|
||||
this.beforeDataLimits();
|
||||
this.determineDataLimits();
|
||||
this.afterDataLimits();
|
||||
|
||||
// Ticks
|
||||
this.beforeBuildTicks();
|
||||
this.buildTicks();
|
||||
@@ -97,11 +101,15 @@
|
||||
return this.minSize;
|
||||
|
||||
},
|
||||
afterUpdate: helpers.noop,
|
||||
afterUpdate: function() {
|
||||
helpers.callCallback(this.options.afterUpdate, [this]);
|
||||
},
|
||||
|
||||
//
|
||||
|
||||
beforeSetDimensions: helpers.noop,
|
||||
beforeSetDimensions: function() {
|
||||
helpers.callCallback(this.options.beforeSetDimensions, [this]);
|
||||
},
|
||||
setDimensions: function() {
|
||||
// Set the unconstrained dimension before label rotation
|
||||
if (this.isHorizontal()) {
|
||||
@@ -123,15 +131,31 @@
|
||||
this.paddingRight = 0;
|
||||
this.paddingBottom = 0;
|
||||
},
|
||||
afterSetDimensions: helpers.noop,
|
||||
afterSetDimensions: function() {
|
||||
helpers.callCallback(this.options.afterSetDimensions, [this]);
|
||||
},
|
||||
|
||||
// Data limits
|
||||
beforeDataLimits: function() {
|
||||
helpers.callCallback(this.options.beforeDataLimits, [this]);
|
||||
},
|
||||
determineDataLimits: helpers.noop,
|
||||
afterDataLimits: function() {
|
||||
helpers.callCallback(this.options.afterDataLimits, [this]);
|
||||
},
|
||||
|
||||
//
|
||||
|
||||
beforeBuildTicks: helpers.noop,
|
||||
beforeBuildTicks: function() {
|
||||
helpers.callCallback(this.options.beforeBuildTicks, [this]);
|
||||
},
|
||||
buildTicks: helpers.noop,
|
||||
afterBuildTicks: helpers.noop,
|
||||
afterBuildTicks: function() {
|
||||
helpers.callCallback(this.options.afterBuildTicks, [this]);
|
||||
},
|
||||
|
||||
beforeTickToLabelConversion: helpers.noop,
|
||||
beforeTickToLabelConversion: function() {
|
||||
helpers.callCallback(this.options.beforeTickToLabelConversion, [this]);
|
||||
},
|
||||
convertTicksToLabels: function() {
|
||||
// Convert ticks to strings
|
||||
this.ticks = this.ticks.map(function(numericalTick, index, ticks) {
|
||||
@@ -142,94 +166,110 @@
|
||||
},
|
||||
this);
|
||||
},
|
||||
afterTickToLabelConversion: helpers.noop,
|
||||
afterTickToLabelConversion: function() {
|
||||
helpers.callCallback(this.options.afterTickToLabelConversion, [this]);
|
||||
},
|
||||
|
||||
//
|
||||
|
||||
beforeCalculateTickRotation: helpers.noop,
|
||||
beforeCalculateTickRotation: function() {
|
||||
helpers.callCallback(this.options.beforeCalculateTickRotation, [this]);
|
||||
},
|
||||
calculateTickRotation: function() {
|
||||
//Get the width of each grid by calculating the difference
|
||||
//between x offsets between 0 and 1.
|
||||
var labelFont = helpers.fontString(this.options.ticks.fontSize, this.options.ticks.fontStyle, this.options.ticks.fontFamily);
|
||||
this.ctx.font = labelFont;
|
||||
var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var tickFontStyle = helpers.getValueOrDefault(this.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle);
|
||||
var tickFontFamily = helpers.getValueOrDefault(this.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily);
|
||||
var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
|
||||
this.ctx.font = tickLabelFont;
|
||||
|
||||
var firstWidth = this.ctx.measureText(this.ticks[0]).width;
|
||||
var lastWidth = this.ctx.measureText(this.ticks[this.ticks.length - 1]).width;
|
||||
var firstRotated;
|
||||
var lastRotated;
|
||||
|
||||
this.paddingRight = lastWidth / 2 + 3;
|
||||
this.paddingLeft = firstWidth / 2 + 3;
|
||||
|
||||
this.labelRotation = 0;
|
||||
this.paddingRight = 0;
|
||||
this.paddingLeft = 0;
|
||||
|
||||
if (this.options.display && this.isHorizontal()) {
|
||||
var originalLabelWidth = helpers.longestText(this.ctx, labelFont, this.ticks);
|
||||
var cosRotation;
|
||||
var sinRotation;
|
||||
var firstRotatedWidth;
|
||||
if (this.options.display) {
|
||||
if (this.isHorizontal()) {
|
||||
this.paddingRight = lastWidth / 2 + 3;
|
||||
this.paddingLeft = firstWidth / 2 + 3;
|
||||
|
||||
this.labelWidth = originalLabelWidth;
|
||||
|
||||
// Allow 3 pixels x2 padding either side for label readability
|
||||
// only the index matters for a dataset scale, but we want a consistent interface between scales
|
||||
|
||||
var tickWidth = this.getPixelForTick(1) - this.getPixelForTick(0) - 6;
|
||||
|
||||
//Max label rotation can be set or default to 90 - also act as a loop counter
|
||||
while (this.labelWidth > tickWidth && this.labelRotation <= this.options.ticks.maxRotation) {
|
||||
cosRotation = Math.cos(helpers.toRadians(this.labelRotation));
|
||||
sinRotation = Math.sin(helpers.toRadians(this.labelRotation));
|
||||
|
||||
firstRotated = cosRotation * firstWidth;
|
||||
lastRotated = cosRotation * lastWidth;
|
||||
|
||||
// We're right aligning the text now.
|
||||
if (firstRotated + this.options.ticks.fontSize / 2 > this.yLabelWidth) {
|
||||
this.paddingLeft = firstRotated + this.options.ticks.fontSize / 2;
|
||||
if (!this.longestTextCache) {
|
||||
this.longestTextCache = {};
|
||||
}
|
||||
var originalLabelWidth = helpers.longestText(this.ctx, tickLabelFont, this.ticks, this.longestTextCache);
|
||||
var labelWidth = originalLabelWidth;
|
||||
var cosRotation;
|
||||
var sinRotation;
|
||||
|
||||
this.paddingRight = this.options.ticks.fontSize / 2;
|
||||
// Allow 3 pixels x2 padding either side for label readability
|
||||
// only the index matters for a dataset scale, but we want a consistent interface between scales
|
||||
var tickWidth = this.getPixelForTick(1) - this.getPixelForTick(0) - 6;
|
||||
|
||||
if (sinRotation * originalLabelWidth > this.maxHeight) {
|
||||
// go back one step
|
||||
this.labelRotation--;
|
||||
break;
|
||||
//Max label rotation can be set or default to 90 - also act as a loop counter
|
||||
while (labelWidth > tickWidth && this.labelRotation < this.options.ticks.maxRotation) {
|
||||
cosRotation = Math.cos(helpers.toRadians(this.labelRotation));
|
||||
sinRotation = Math.sin(helpers.toRadians(this.labelRotation));
|
||||
|
||||
firstRotated = cosRotation * firstWidth;
|
||||
|
||||
// We're right aligning the text now.
|
||||
if (firstRotated + tickFontSize / 2 > this.yLabelWidth) {
|
||||
this.paddingLeft = firstRotated + tickFontSize / 2;
|
||||
}
|
||||
|
||||
this.paddingRight = tickFontSize / 2;
|
||||
|
||||
if (sinRotation * originalLabelWidth > this.maxHeight) {
|
||||
// go back one step
|
||||
this.labelRotation--;
|
||||
break;
|
||||
}
|
||||
|
||||
this.labelRotation++;
|
||||
labelWidth = cosRotation * originalLabelWidth;
|
||||
}
|
||||
|
||||
this.labelRotation++;
|
||||
this.labelWidth = cosRotation * originalLabelWidth;
|
||||
|
||||
}
|
||||
} else {
|
||||
this.labelWidth = 0;
|
||||
this.paddingRight = 0;
|
||||
this.paddingLeft = 0;
|
||||
}
|
||||
|
||||
if (this.margins) {
|
||||
this.paddingLeft -= this.margins.left;
|
||||
this.paddingRight -= this.margins.right;
|
||||
|
||||
this.paddingLeft = Math.max(this.paddingLeft, 0);
|
||||
this.paddingRight = Math.max(this.paddingRight, 0);
|
||||
this.paddingLeft = Math.max(this.paddingLeft - this.margins.left, 0);
|
||||
this.paddingRight = Math.max(this.paddingRight - this.margins.right, 0);
|
||||
}
|
||||
},
|
||||
afterCalculateTickRotation: helpers.noop,
|
||||
afterCalculateTickRotation: function() {
|
||||
helpers.callCallback(this.options.afterCalculateTickRotation, [this]);
|
||||
},
|
||||
|
||||
//
|
||||
|
||||
beforeFit: helpers.noop,
|
||||
beforeFit: function() {
|
||||
helpers.callCallback(this.options.beforeFit, [this]);
|
||||
},
|
||||
fit: function() {
|
||||
|
||||
this.minSize = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
height: 0
|
||||
};
|
||||
|
||||
var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var tickFontStyle = helpers.getValueOrDefault(this.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle);
|
||||
var tickFontFamily = helpers.getValueOrDefault(this.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily);
|
||||
var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
|
||||
|
||||
var scaleLabelFontSize = helpers.getValueOrDefault(this.options.scaleLabel.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var scaleLabelFontStyle = helpers.getValueOrDefault(this.options.scaleLabel.fontStyle, Chart.defaults.global.defaultFontStyle);
|
||||
var scaleLabelFontFamily = helpers.getValueOrDefault(this.options.scaleLabel.fontFamily, Chart.defaults.global.defaultFontFamily);
|
||||
var scaleLabelFont = helpers.fontString(scaleLabelFontSize, scaleLabelFontStyle, scaleLabelFontFamily);
|
||||
|
||||
// Width
|
||||
if (this.isHorizontal()) {
|
||||
this.minSize.width = this.maxWidth; // fill all the width
|
||||
// subtract the margins to line up with the chartArea if we are a full width scale
|
||||
this.minSize.width = this.isFullWidth() ? this.maxWidth - this.margins.left - this.margins.right : this.maxWidth;
|
||||
} else {
|
||||
this.minSize.width = this.options.gridLines.display && this.options.display ? 10 : 0;
|
||||
}
|
||||
@@ -244,43 +284,42 @@
|
||||
// Are we showing a title for the scale?
|
||||
if (this.options.scaleLabel.display) {
|
||||
if (this.isHorizontal()) {
|
||||
this.minSize.height += (this.options.scaleLabel.fontSize * 1.5);
|
||||
this.minSize.height += (scaleLabelFontSize * 1.5);
|
||||
} else {
|
||||
this.minSize.width += (this.options.scaleLabel.fontSize * 1.5);
|
||||
this.minSize.width += (scaleLabelFontSize * 1.5);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.ticks.display && this.options.display) {
|
||||
// Don't bother fitting the ticks if we are not showing them
|
||||
var labelFont = helpers.fontString(this.options.ticks.fontSize,
|
||||
this.options.ticks.fontStyle, this.options.ticks.fontFamily);
|
||||
if (!this.longestTextCache) {
|
||||
this.longestTextCache = {};
|
||||
}
|
||||
|
||||
var largestTextWidth = helpers.longestText(this.ctx, tickLabelFont, this.ticks, this.longestTextCache);
|
||||
|
||||
if (this.isHorizontal()) {
|
||||
// A horizontal axis is more constrained by the height.
|
||||
var maxLabelHeight = this.maxHeight - this.minSize.height;
|
||||
var longestLabelWidth = helpers.longestText(this.ctx, labelFont, this.ticks);
|
||||
this.longestLabelWidth = largestTextWidth;
|
||||
|
||||
// TODO - improve this calculation
|
||||
var labelHeight = (Math.sin(helpers.toRadians(this.labelRotation)) * longestLabelWidth) + 1.5 * this.options.ticks.fontSize;
|
||||
var labelHeight = (Math.sin(helpers.toRadians(this.labelRotation)) * this.longestLabelWidth) + 1.5 * tickFontSize;
|
||||
|
||||
this.minSize.height = Math.min(this.maxHeight, this.minSize.height + labelHeight);
|
||||
|
||||
labelFont = helpers.fontString(this.options.ticks.fontSize, this.options.ticks.fontStyle, this.options.ticks.fontFamily);
|
||||
this.ctx.font = labelFont;
|
||||
this.ctx.font = tickLabelFont;
|
||||
|
||||
var firstLabelWidth = this.ctx.measureText(this.ticks[0]).width;
|
||||
var lastLabelWidth = this.ctx.measureText(this.ticks[this.ticks.length - 1]).width;
|
||||
|
||||
// Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned which means that the right padding is dominated
|
||||
// by the font height
|
||||
// by the font height
|
||||
var cosRotation = Math.cos(helpers.toRadians(this.labelRotation));
|
||||
var sinRotation = Math.sin(helpers.toRadians(this.labelRotation));
|
||||
this.paddingLeft = this.labelRotation !== 0 ? (cosRotation * firstLabelWidth) + 3 : firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
|
||||
this.paddingRight = this.labelRotation !== 0 ? (sinRotation * (this.options.ticks.fontSize / 2)) + 3 : lastLabelWidth / 2 + 3; // when rotated
|
||||
this.paddingRight = this.labelRotation !== 0 ? (sinRotation * (tickFontSize / 2)) + 3 : lastLabelWidth / 2 + 3; // when rotated
|
||||
} else {
|
||||
// A vertical axis is more constrained by the width. Labels are the dominant factor here, so get that length first
|
||||
var maxLabelWidth = this.maxWidth - this.minSize.width;
|
||||
var largestTextWidth = helpers.longestText(this.ctx, labelFont, this.ticks);
|
||||
|
||||
// Account for padding
|
||||
if (!this.options.ticks.mirror) {
|
||||
@@ -295,32 +334,32 @@
|
||||
this.minSize.width = this.maxWidth;
|
||||
}
|
||||
|
||||
this.paddingTop = this.options.ticks.fontSize / 2;
|
||||
this.paddingBottom = this.options.ticks.fontSize / 2;
|
||||
this.paddingTop = tickFontSize / 2;
|
||||
this.paddingBottom = tickFontSize / 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.margins) {
|
||||
this.paddingLeft -= this.margins.left;
|
||||
this.paddingTop -= this.margins.top;
|
||||
this.paddingRight -= this.margins.right;
|
||||
this.paddingBottom -= this.margins.bottom;
|
||||
|
||||
this.paddingLeft = Math.max(this.paddingLeft, 0);
|
||||
this.paddingTop = Math.max(this.paddingTop, 0);
|
||||
this.paddingRight = Math.max(this.paddingRight, 0);
|
||||
this.paddingBottom = Math.max(this.paddingBottom, 0);
|
||||
this.paddingLeft = Math.max(this.paddingLeft - this.margins.left, 0);
|
||||
this.paddingTop = Math.max(this.paddingTop - this.margins.top, 0);
|
||||
this.paddingRight = Math.max(this.paddingRight - this.margins.right, 0);
|
||||
this.paddingBottom = Math.max(this.paddingBottom - this.margins.bottom, 0);
|
||||
}
|
||||
|
||||
this.width = this.minSize.width;
|
||||
this.height = this.minSize.height;
|
||||
|
||||
},
|
||||
afterFit: helpers.noop,
|
||||
afterFit: function() {
|
||||
helpers.callCallback(this.options.afterFit, [this]);
|
||||
},
|
||||
|
||||
// Shared Methods
|
||||
isHorizontal: function() {
|
||||
return this.options.position == "top" || this.options.position == "bottom";
|
||||
return this.options.position === "top" || this.options.position === "bottom";
|
||||
},
|
||||
isFullWidth: function() {
|
||||
return (this.options.fullWidth);
|
||||
},
|
||||
|
||||
// Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
|
||||
@@ -335,7 +374,11 @@
|
||||
}
|
||||
// If it is in fact an object, dive in one more level
|
||||
if (typeof(rawValue) === "object") {
|
||||
return getRightValue(this.isHorizontal() ? rawValue.x : rawValue.y);
|
||||
if (rawValue instanceof Date) {
|
||||
return rawValue;
|
||||
} else {
|
||||
return getRightValue(this.isHorizontal() ? rawValue.x : rawValue.y);
|
||||
}
|
||||
}
|
||||
|
||||
// Value is good, return it
|
||||
@@ -349,7 +392,7 @@
|
||||
// Used to get data value locations. Value can either be an index or a numerical value
|
||||
getPixelForValue: helpers.noop,
|
||||
|
||||
// Used for tick location, should
|
||||
// Used for tick location, should
|
||||
getPixelForTick: function(index, includeOffset) {
|
||||
if (this.isHorizontal()) {
|
||||
var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
|
||||
@@ -359,7 +402,10 @@
|
||||
if (includeOffset) {
|
||||
pixel += tickWidth / 2;
|
||||
}
|
||||
return this.left + Math.round(pixel);
|
||||
|
||||
var finalVal = this.left + Math.round(pixel);
|
||||
finalVal += this.isFullWidth() ? this.margins.left : 0;
|
||||
return finalVal;
|
||||
} else {
|
||||
var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
|
||||
return this.top + (index * (innerHeight / (this.ticks.length - 1)));
|
||||
@@ -367,12 +413,14 @@
|
||||
},
|
||||
|
||||
// Utility for getting the pixel location of a percentage of scale
|
||||
getPixelForDecimal: function(decimal, includeOffset) {
|
||||
getPixelForDecimal: function(decimal /*, includeOffset*/ ) {
|
||||
if (this.isHorizontal()) {
|
||||
var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
|
||||
var valueOffset = (innerWidth * decimal) + this.paddingLeft;
|
||||
|
||||
return this.left + Math.round(valueOffset);
|
||||
var finalVal = this.left + Math.round(valueOffset);
|
||||
finalVal += this.isFullWidth() ? this.margins.left : 0;
|
||||
return finalVal;
|
||||
} else {
|
||||
return this.top + (decimal * this.height);
|
||||
}
|
||||
@@ -388,24 +436,68 @@
|
||||
var skipRatio;
|
||||
var scaleLabelX;
|
||||
var scaleLabelY;
|
||||
var useAutoskipper = this.options.ticks.autoSkip;
|
||||
|
||||
|
||||
// figure out the maximum number of gridlines to show
|
||||
var maxTicks;
|
||||
|
||||
if (this.options.ticks.maxTicksLimit) {
|
||||
maxTicks = this.options.ticks.maxTicksLimit;
|
||||
}
|
||||
|
||||
var tickFontColor = helpers.getValueOrDefault(this.options.ticks.fontColor, Chart.defaults.global.defaultFontColor);
|
||||
var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var tickFontStyle = helpers.getValueOrDefault(this.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle);
|
||||
var tickFontFamily = helpers.getValueOrDefault(this.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily);
|
||||
var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
|
||||
|
||||
var scaleLabelFontColor = helpers.getValueOrDefault(this.options.scaleLabel.fontColor, Chart.defaults.global.defaultFontColor);
|
||||
var scaleLabelFontSize = helpers.getValueOrDefault(this.options.scaleLabel.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var scaleLabelFontStyle = helpers.getValueOrDefault(this.options.scaleLabel.fontStyle, Chart.defaults.global.defaultFontStyle);
|
||||
var scaleLabelFontFamily = helpers.getValueOrDefault(this.options.scaleLabel.fontFamily, Chart.defaults.global.defaultFontFamily);
|
||||
var scaleLabelFont = helpers.fontString(scaleLabelFontSize, scaleLabelFontStyle, scaleLabelFontFamily);
|
||||
|
||||
var cosRotation = Math.cos(helpers.toRadians(this.labelRotation));
|
||||
var sinRotation = Math.sin(helpers.toRadians(this.labelRotation));
|
||||
var longestRotatedLabel = this.longestLabelWidth * cosRotation;
|
||||
var rotatedLabelHeight = tickFontSize * sinRotation;
|
||||
|
||||
// Make sure we draw text in the correct color and font
|
||||
this.ctx.fillStyle = this.options.ticks.fontColor;
|
||||
var labelFont = helpers.fontString(this.options.ticks.fontSize, this.options.ticks.fontStyle, this.options.ticks.fontFamily);
|
||||
this.ctx.fillStyle = tickFontColor;
|
||||
|
||||
if (this.isHorizontal()) {
|
||||
setContextLineSettings = true;
|
||||
var yTickStart = this.options.position == "bottom" ? this.top : this.bottom - 10;
|
||||
var yTickEnd = this.options.position == "bottom" ? this.top + 10 : this.bottom;
|
||||
var yTickStart = this.options.position === "bottom" ? this.top : this.bottom - 10;
|
||||
var yTickEnd = this.options.position === "bottom" ? this.top + 10 : this.bottom;
|
||||
skipRatio = false;
|
||||
|
||||
if ((this.options.ticks.fontSize + 4) * this.ticks.length > (this.width - (this.paddingLeft + this.paddingRight))) {
|
||||
skipRatio = 1 + Math.floor(((this.options.ticks.fontSize + 4) * this.ticks.length) / (this.width - (this.paddingLeft + this.paddingRight)));
|
||||
if (((longestRotatedLabel / 2) + this.options.ticks.autoSkipPadding) * this.ticks.length > (this.width - (this.paddingLeft + this.paddingRight))) {
|
||||
skipRatio = 1 + Math.floor((((longestRotatedLabel / 2) + this.options.ticks.autoSkipPadding) * this.ticks.length) / (this.width - (this.paddingLeft + this.paddingRight)));
|
||||
}
|
||||
|
||||
// if they defined a max number of ticks,
|
||||
// increase skipRatio until that number is met
|
||||
if (maxTicks && this.ticks.length > maxTicks) {
|
||||
while (!skipRatio || this.ticks.length / (skipRatio || 1) > maxTicks) {
|
||||
if (!skipRatio) {
|
||||
skipRatio = 1;
|
||||
}
|
||||
skipRatio += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!useAutoskipper) {
|
||||
skipRatio = false;
|
||||
}
|
||||
|
||||
helpers.each(this.ticks, function(label, index) {
|
||||
// Blank ticks
|
||||
if ((skipRatio > 1 && index % skipRatio > 0) || (label === undefined || label === null)) {
|
||||
var isLastTick = this.ticks.length === index + 1;
|
||||
|
||||
// Since we always show the last tick,we need may need to hide the last shown one before
|
||||
var shouldSkip = (skipRatio > 1 && index % skipRatio > 0) || (index % skipRatio === 0 && index + skipRatio > this.ticks.length);
|
||||
if (shouldSkip && !isLastTick || (label === undefined || label === null)) {
|
||||
return;
|
||||
}
|
||||
var xLineValue = this.getPixelForTick(index); // xvalues for grid lines
|
||||
@@ -447,7 +539,7 @@
|
||||
this.ctx.save();
|
||||
this.ctx.translate(xLabelValue, (isRotated) ? this.top + 12 : this.options.position === "top" ? this.bottom - 10 : this.top + 10);
|
||||
this.ctx.rotate(helpers.toRadians(this.labelRotation) * -1);
|
||||
this.ctx.font = labelFont;
|
||||
this.ctx.font = tickLabelFont;
|
||||
this.ctx.textAlign = (isRotated) ? "right" : "center";
|
||||
this.ctx.textBaseline = (isRotated) ? "middle" : this.options.position === "top" ? "bottom" : "top";
|
||||
this.ctx.fillText(label, 0, 0);
|
||||
@@ -459,19 +551,19 @@
|
||||
// Draw the scale label
|
||||
this.ctx.textAlign = "center";
|
||||
this.ctx.textBaseline = 'middle';
|
||||
this.ctx.fillStyle = this.options.scaleLabel.fontColor; // render in correct colour
|
||||
this.ctx.font = helpers.fontString(this.options.scaleLabel.fontSize, this.options.scaleLabel.fontStyle, this.options.scaleLabel.fontFamily);
|
||||
this.ctx.fillStyle = scaleLabelFontColor; // render in correct colour
|
||||
this.ctx.font = scaleLabelFont;
|
||||
|
||||
scaleLabelX = this.left + ((this.right - this.left) / 2); // midpoint of the width
|
||||
scaleLabelY = this.options.position == 'bottom' ? this.bottom - (this.options.scaleLabel.fontSize / 2) : this.top + (this.options.scaleLabel.fontSize / 2);
|
||||
scaleLabelY = this.options.position === 'bottom' ? this.bottom - (scaleLabelFontSize / 2) : this.top + (scaleLabelFontSize / 2);
|
||||
|
||||
this.ctx.fillText(this.options.scaleLabel.labelString, scaleLabelX, scaleLabelY);
|
||||
}
|
||||
|
||||
} else {
|
||||
setContextLineSettings = true;
|
||||
var xTickStart = this.options.position == "right" ? this.left : this.right - 5;
|
||||
var xTickEnd = this.options.position == "right" ? this.left + 5 : this.right;
|
||||
var xTickStart = this.options.position === "right" ? this.left : this.right - 5;
|
||||
var xTickEnd = this.options.position === "right" ? this.left + 5 : this.right;
|
||||
|
||||
helpers.each(this.ticks, function(label, index) {
|
||||
// If the callback returned a null or undefined value, do not draw this line
|
||||
@@ -519,7 +611,7 @@
|
||||
|
||||
this.ctx.save();
|
||||
|
||||
if (this.options.position == "left") {
|
||||
if (this.options.position === "left") {
|
||||
if (this.options.ticks.mirror) {
|
||||
xLabelValue = this.right + this.options.ticks.padding;
|
||||
this.ctx.textAlign = "left";
|
||||
@@ -538,10 +630,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.ctx.translate(xLabelValue, yLabelValue);
|
||||
this.ctx.rotate(helpers.toRadians(this.labelRotation) * -1);
|
||||
this.ctx.font = labelFont;
|
||||
this.ctx.font = tickLabelFont;
|
||||
this.ctx.textBaseline = "middle";
|
||||
this.ctx.fillText(label, 0, 0);
|
||||
this.ctx.restore();
|
||||
@@ -550,23 +641,45 @@
|
||||
|
||||
if (this.options.scaleLabel.display) {
|
||||
// Draw the scale label
|
||||
scaleLabelX = this.options.position == 'left' ? this.left + (this.options.scaleLabel.fontSize / 2) : this.right - (this.options.scaleLabel.fontSize / 2);
|
||||
scaleLabelX = this.options.position === 'left' ? this.left + (scaleLabelFontSize / 2) : this.right - (scaleLabelFontSize / 2);
|
||||
scaleLabelY = this.top + ((this.bottom - this.top) / 2);
|
||||
var rotation = this.options.position == 'left' ? -0.5 * Math.PI : 0.5 * Math.PI;
|
||||
var rotation = this.options.position === 'left' ? -0.5 * Math.PI : 0.5 * Math.PI;
|
||||
|
||||
this.ctx.save();
|
||||
this.ctx.translate(scaleLabelX, scaleLabelY);
|
||||
this.ctx.rotate(rotation);
|
||||
this.ctx.textAlign = "center";
|
||||
this.ctx.fillStyle = this.options.scaleLabel.fontColor; // render in correct colour
|
||||
this.ctx.font = helpers.fontString(this.options.scaleLabel.fontSize, this.options.scaleLabel.fontStyle, this.options.scaleLabel.fontFamily);
|
||||
this.ctx.fillStyle =scaleLabelFontColor; // render in correct colour
|
||||
this.ctx.font = scaleLabelFont;
|
||||
this.ctx.textBaseline = 'middle';
|
||||
this.ctx.fillText(this.options.scaleLabel.labelString, 0, 0);
|
||||
this.ctx.restore();
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the line at the edge of the axis
|
||||
this.ctx.lineWidth = this.options.gridLines.lineWidth;
|
||||
this.ctx.strokeStyle = this.options.gridLines.color;
|
||||
var x1 = this.left,
|
||||
x2 = this.right,
|
||||
y1 = this.top,
|
||||
y2 = this.bottom;
|
||||
|
||||
if (this.isHorizontal()) {
|
||||
y1 = y2 = this.options.position === 'top' ? this.bottom : this.top;
|
||||
y1 += helpers.aliasPixel(this.ctx.lineWidth);
|
||||
y2 += helpers.aliasPixel(this.ctx.lineWidth);
|
||||
} else {
|
||||
x1 = x2 = this.options.position === 'left' ? this.right : this.left;
|
||||
x1 += helpers.aliasPixel(this.ctx.lineWidth);
|
||||
x2 += helpers.aliasPixel(this.ctx.lineWidth);
|
||||
}
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(x1, y1);
|
||||
this.ctx.lineTo(x2, y2);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
+10
-312
@@ -1,13 +1,9 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
// The scale service is used to resize charts along with all of their axes. We make this as
|
||||
// a service where scales are registered with their respective charts so that changing the
|
||||
// scales does not require
|
||||
Chart.scaleService = {
|
||||
// Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
|
||||
// use the new chart options to grab the correct scale
|
||||
@@ -28,309 +24,11 @@
|
||||
// Return the scale defaults merged with the global settings so that we always use the latest ones
|
||||
return this.defaults.hasOwnProperty(type) ? helpers.scaleMerge(Chart.defaults.scale, this.defaults[type]) : {};
|
||||
},
|
||||
// The interesting function
|
||||
update: function(chartInstance, width, height) {
|
||||
var xPadding = width > 30 ? 5 : 2;
|
||||
var yPadding = height > 30 ? 5 : 2;
|
||||
|
||||
if (chartInstance) {
|
||||
var leftScales = helpers.where(chartInstance.scales, function(scaleInstance) {
|
||||
return scaleInstance.options.position == "left";
|
||||
});
|
||||
var rightScales = helpers.where(chartInstance.scales, function(scaleInstance) {
|
||||
return scaleInstance.options.position == "right";
|
||||
});
|
||||
var topScales = helpers.where(chartInstance.scales, function(scaleInstance) {
|
||||
return scaleInstance.options.position == "top";
|
||||
});
|
||||
var bottomScales = helpers.where(chartInstance.scales, function(scaleInstance) {
|
||||
return scaleInstance.options.position == "bottom";
|
||||
});
|
||||
|
||||
// Scales that overlay the chartarea such as the radialLinear scale
|
||||
var chartAreaScales = helpers.where(chartInstance.scales, function(scaleInstance) {
|
||||
return scaleInstance.options.position == "chartArea";
|
||||
});
|
||||
|
||||
// Essentially we now have any number of scales on each of the 4 sides.
|
||||
// Our canvas looks like the following.
|
||||
// The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
|
||||
// B1 is the bottom axis
|
||||
// |------------------------------------------------------|
|
||||
// | | T1 | |
|
||||
// |----|-----|-------------------------------------|-----|
|
||||
// | | | | |
|
||||
// | L1 | L2 | Chart area | R1 |
|
||||
// | | | | |
|
||||
// | | | | |
|
||||
// |----|-----|-------------------------------------|-----|
|
||||
// | | B1 | |
|
||||
// | | | |
|
||||
// |------------------------------------------------------|
|
||||
|
||||
// What we do to find the best sizing, we do the following
|
||||
// 1. Determine the minimum size of the chart area.
|
||||
// 2. Split the remaining width equally between each vertical axis
|
||||
// 3. Split the remaining height equally between each horizontal axis
|
||||
// 4. Give each scale the maximum size it can be. The scale will return it's minimum size
|
||||
// 5. Adjust the sizes of each axis based on it's minimum reported size.
|
||||
// 6. Refit each axis
|
||||
// 7. Position each axis in the final location
|
||||
// 8. Tell the chart the final location of the chart area
|
||||
// 9. Tell any axes that overlay the chart area the positions of the chart area
|
||||
|
||||
// Step 1
|
||||
var chartWidth = width / 2; // min 50%
|
||||
var chartHeight = height / 2; // min 50%
|
||||
|
||||
chartWidth -= (2 * xPadding);
|
||||
chartHeight -= (2 * yPadding);
|
||||
|
||||
// Step 2
|
||||
var verticalScaleWidth = (width - chartWidth) / (leftScales.length + rightScales.length);
|
||||
|
||||
// Step 3
|
||||
var horizontalScaleHeight = (height - chartHeight) / (topScales.length + bottomScales.length);
|
||||
|
||||
// Step 4;
|
||||
var minimumScaleSizes = [];
|
||||
|
||||
var verticalScaleMinSizeFunction = function(scaleInstance) {
|
||||
var minSize = scaleInstance.update(verticalScaleWidth, chartHeight);
|
||||
minimumScaleSizes.push({
|
||||
horizontal: false,
|
||||
minSize: minSize,
|
||||
scale: scaleInstance,
|
||||
});
|
||||
};
|
||||
|
||||
var horizontalScaleMinSizeFunction = function(scaleInstance) {
|
||||
var minSize = scaleInstance.update(chartWidth, horizontalScaleHeight);
|
||||
minimumScaleSizes.push({
|
||||
horizontal: true,
|
||||
minSize: minSize,
|
||||
scale: scaleInstance,
|
||||
});
|
||||
};
|
||||
|
||||
// vertical scales
|
||||
helpers.each(leftScales, verticalScaleMinSizeFunction);
|
||||
helpers.each(rightScales, verticalScaleMinSizeFunction);
|
||||
|
||||
// horizontal scales
|
||||
helpers.each(topScales, horizontalScaleMinSizeFunction);
|
||||
helpers.each(bottomScales, horizontalScaleMinSizeFunction);
|
||||
|
||||
// Step 5
|
||||
var maxChartHeight = height - (2 * yPadding);
|
||||
var maxChartWidth = width - (2 * xPadding);
|
||||
|
||||
helpers.each(minimumScaleSizes, function(wrapper) {
|
||||
if (wrapper.horizontal) {
|
||||
maxChartHeight -= wrapper.minSize.height;
|
||||
} else {
|
||||
maxChartWidth -= wrapper.minSize.width;
|
||||
}
|
||||
});
|
||||
|
||||
// At this point, maxChartHeight and maxChartWidth are the size the chart area could
|
||||
// be if the axes are drawn at their minimum sizes.
|
||||
|
||||
// Step 6
|
||||
var verticalScaleFitFunction = function(scaleInstance) {
|
||||
var wrapper = helpers.findNextWhere(minimumScaleSizes, function(wrapper) {
|
||||
return wrapper.scale === scaleInstance;
|
||||
});
|
||||
|
||||
if (wrapper) {
|
||||
scaleInstance.update(wrapper.minSize.width, maxChartHeight);
|
||||
}
|
||||
};
|
||||
|
||||
var horizontalScaleFitFunction = function(scaleInstance) {
|
||||
var wrapper = helpers.findNextWhere(minimumScaleSizes, function(wrapper) {
|
||||
return wrapper.scale === scaleInstance;
|
||||
});
|
||||
|
||||
var scaleMargin = {
|
||||
left: totalLeftWidth,
|
||||
right: totalRightWidth,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
};
|
||||
|
||||
if (wrapper) {
|
||||
scaleInstance.update(maxChartWidth, wrapper.minSize.height, scaleMargin);
|
||||
}
|
||||
};
|
||||
|
||||
var totalLeftWidth = xPadding;
|
||||
var totalRightWidth = xPadding;
|
||||
var totalTopHeight = yPadding;
|
||||
var totalBottomHeight = yPadding;
|
||||
|
||||
helpers.each(leftScales, verticalScaleFitFunction);
|
||||
helpers.each(rightScales, verticalScaleFitFunction);
|
||||
|
||||
// Figure out how much margin is on the left and right of the horizontal axes
|
||||
helpers.each(leftScales, function(scaleInstance) {
|
||||
totalLeftWidth += scaleInstance.width;
|
||||
});
|
||||
|
||||
helpers.each(rightScales, function(scaleInstance) {
|
||||
totalRightWidth += scaleInstance.width;
|
||||
});
|
||||
|
||||
helpers.each(topScales, horizontalScaleFitFunction);
|
||||
helpers.each(bottomScales, horizontalScaleFitFunction);
|
||||
|
||||
helpers.each(topScales, function(scaleInstance) {
|
||||
totalTopHeight += scaleInstance.height;
|
||||
});
|
||||
helpers.each(bottomScales, function(scaleInstance) {
|
||||
totalBottomHeight += scaleInstance.height;
|
||||
});
|
||||
|
||||
// Let the left scale know the final margin
|
||||
helpers.each(leftScales, function(scaleInstance) {
|
||||
var wrapper = helpers.findNextWhere(minimumScaleSizes, function(wrapper) {
|
||||
return wrapper.scale === scaleInstance;
|
||||
});
|
||||
|
||||
var scaleMargin = {
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: totalTopHeight,
|
||||
bottom: totalBottomHeight
|
||||
};
|
||||
|
||||
if (wrapper) {
|
||||
scaleInstance.update(wrapper.minSize.width, maxChartHeight, scaleMargin);
|
||||
}
|
||||
});
|
||||
|
||||
helpers.each(rightScales, function(scaleInstance) {
|
||||
var wrapper = helpers.findNextWhere(minimumScaleSizes, function(wrapper) {
|
||||
return wrapper.scale === scaleInstance;
|
||||
});
|
||||
|
||||
var scaleMargin = {
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: totalTopHeight,
|
||||
bottom: totalBottomHeight
|
||||
};
|
||||
|
||||
if (wrapper) {
|
||||
scaleInstance.update(wrapper.minSize.width, maxChartHeight, scaleMargin);
|
||||
}
|
||||
});
|
||||
|
||||
// Recalculate because the size of each scale might have changed slightly due to the margins (label rotation for instance)
|
||||
totalLeftWidth = xPadding;
|
||||
totalRightWidth = xPadding;
|
||||
totalTopHeight = yPadding;
|
||||
totalBottomHeight = yPadding;
|
||||
|
||||
helpers.each(leftScales, function(scaleInstance) {
|
||||
totalLeftWidth += scaleInstance.width;
|
||||
});
|
||||
|
||||
helpers.each(rightScales, function(scaleInstance) {
|
||||
totalRightWidth += scaleInstance.width;
|
||||
});
|
||||
|
||||
helpers.each(topScales, function(scaleInstance) {
|
||||
totalTopHeight += scaleInstance.height;
|
||||
});
|
||||
helpers.each(bottomScales, function(scaleInstance) {
|
||||
totalBottomHeight += scaleInstance.height;
|
||||
});
|
||||
|
||||
// Figure out if our chart area changed. This would occur if the dataset scale label rotation
|
||||
// changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
|
||||
// without calling `fit` again
|
||||
var newMaxChartHeight = height - totalTopHeight - totalBottomHeight;
|
||||
var newMaxChartWidth = width - totalLeftWidth - totalRightWidth;
|
||||
|
||||
if (newMaxChartWidth !== maxChartWidth || newMaxChartHeight !== maxChartHeight) {
|
||||
helpers.each(leftScales, function(scale) {
|
||||
scale.height = newMaxChartHeight;
|
||||
});
|
||||
|
||||
helpers.each(rightScales, function(scale) {
|
||||
scale.height = newMaxChartHeight;
|
||||
});
|
||||
|
||||
helpers.each(topScales, function(scale) {
|
||||
scale.width = newMaxChartWidth;
|
||||
});
|
||||
|
||||
helpers.each(bottomScales, function(scale) {
|
||||
scale.width = newMaxChartWidth;
|
||||
});
|
||||
|
||||
maxChartHeight = newMaxChartHeight;
|
||||
maxChartWidth = newMaxChartWidth;
|
||||
}
|
||||
|
||||
// Step 7
|
||||
// Position the scales
|
||||
var left = xPadding;
|
||||
var top = yPadding;
|
||||
var right = 0;
|
||||
var bottom = 0;
|
||||
|
||||
var verticalScalePlacer = function(scaleInstance) {
|
||||
scaleInstance.left = left;
|
||||
scaleInstance.right = left + scaleInstance.width;
|
||||
scaleInstance.top = totalTopHeight;
|
||||
scaleInstance.bottom = totalTopHeight + maxChartHeight;
|
||||
|
||||
// Move to next point
|
||||
left = scaleInstance.right;
|
||||
};
|
||||
|
||||
var horizontalScalePlacer = function(scaleInstance) {
|
||||
scaleInstance.left = totalLeftWidth;
|
||||
scaleInstance.right = totalLeftWidth + maxChartWidth;
|
||||
scaleInstance.top = top;
|
||||
scaleInstance.bottom = top + scaleInstance.height;
|
||||
|
||||
// Move to next point
|
||||
top = scaleInstance.bottom;
|
||||
};
|
||||
|
||||
helpers.each(leftScales, verticalScalePlacer);
|
||||
helpers.each(topScales, horizontalScalePlacer);
|
||||
|
||||
// Account for chart width and height
|
||||
left += maxChartWidth;
|
||||
top += maxChartHeight;
|
||||
|
||||
helpers.each(rightScales, verticalScalePlacer);
|
||||
helpers.each(bottomScales, horizontalScalePlacer);
|
||||
|
||||
// Step 8
|
||||
chartInstance.chartArea = {
|
||||
left: totalLeftWidth,
|
||||
top: totalTopHeight,
|
||||
right: totalLeftWidth + maxChartWidth,
|
||||
bottom: totalTopHeight + maxChartHeight,
|
||||
};
|
||||
|
||||
// Step 9
|
||||
helpers.each(chartAreaScales, function(scaleInstance) {
|
||||
scaleInstance.left = chartInstance.chartArea.left;
|
||||
scaleInstance.top = chartInstance.chartArea.top;
|
||||
scaleInstance.right = chartInstance.chartArea.right;
|
||||
scaleInstance.bottom = chartInstance.chartArea.bottom;
|
||||
|
||||
scaleInstance.update(maxChartWidth, maxChartHeight);
|
||||
});
|
||||
}
|
||||
addScalesToLayout: function(chartInstance) {
|
||||
// Adds each scale to the chart.boxes array to be sized accordingly
|
||||
helpers.each(chartInstance.scales, function(scale) {
|
||||
Chart.layoutService.addBox(chartInstance, scale);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
@@ -0,0 +1,193 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.defaults.global.title = {
|
||||
display: false,
|
||||
position: 'top',
|
||||
fullWidth: true, // marks that this box should take the full width of the canvas (pushing down other boxes)
|
||||
|
||||
fontStyle: 'bold',
|
||||
padding: 10,
|
||||
|
||||
// actual title
|
||||
text: ''
|
||||
};
|
||||
|
||||
Chart.Title = Chart.Element.extend({
|
||||
|
||||
initialize: function(config) {
|
||||
helpers.extend(this, config);
|
||||
this.options = helpers.configMerge(Chart.defaults.global.title, config.options);
|
||||
|
||||
// Contains hit boxes for each dataset (in dataset order)
|
||||
this.legendHitBoxes = [];
|
||||
},
|
||||
|
||||
// These methods are ordered by lifecyle. Utilities then follow.
|
||||
|
||||
beforeUpdate: helpers.noop,
|
||||
update: function(maxWidth, maxHeight, margins) {
|
||||
|
||||
// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
|
||||
this.beforeUpdate();
|
||||
|
||||
// Absorb the master measurements
|
||||
this.maxWidth = maxWidth;
|
||||
this.maxHeight = maxHeight;
|
||||
this.margins = margins;
|
||||
|
||||
// Dimensions
|
||||
this.beforeSetDimensions();
|
||||
this.setDimensions();
|
||||
this.afterSetDimensions();
|
||||
// Labels
|
||||
this.beforeBuildLabels();
|
||||
this.buildLabels();
|
||||
this.afterBuildLabels();
|
||||
|
||||
// Fit
|
||||
this.beforeFit();
|
||||
this.fit();
|
||||
this.afterFit();
|
||||
//
|
||||
this.afterUpdate();
|
||||
|
||||
return this.minSize;
|
||||
|
||||
},
|
||||
afterUpdate: helpers.noop,
|
||||
|
||||
//
|
||||
|
||||
beforeSetDimensions: helpers.noop,
|
||||
setDimensions: function() {
|
||||
// Set the unconstrained dimension before label rotation
|
||||
if (this.isHorizontal()) {
|
||||
// Reset position before calculating rotation
|
||||
this.width = this.maxWidth;
|
||||
this.left = 0;
|
||||
this.right = this.width;
|
||||
} else {
|
||||
this.height = this.maxHeight;
|
||||
|
||||
// Reset position before calculating rotation
|
||||
this.top = 0;
|
||||
this.bottom = this.height;
|
||||
}
|
||||
|
||||
// Reset padding
|
||||
this.paddingLeft = 0;
|
||||
this.paddingTop = 0;
|
||||
this.paddingRight = 0;
|
||||
this.paddingBottom = 0;
|
||||
|
||||
// Reset minSize
|
||||
this.minSize = {
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
},
|
||||
afterSetDimensions: helpers.noop,
|
||||
|
||||
//
|
||||
|
||||
beforeBuildLabels: helpers.noop,
|
||||
buildLabels: helpers.noop,
|
||||
afterBuildLabels: helpers.noop,
|
||||
|
||||
//
|
||||
|
||||
beforeFit: helpers.noop,
|
||||
fit: function() {
|
||||
|
||||
var ctx = this.ctx;
|
||||
var fontSize = helpers.getValueOrDefault(this.options.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var fontStyle = helpers.getValueOrDefault(this.options.fontStyle, Chart.defaults.global.defaultFontStyle);
|
||||
var fontFamily = helpers.getValueOrDefault(this.options.fontFamily, Chart.defaults.global.defaultFontFamily);
|
||||
var titleFont = helpers.fontString(fontSize, fontStyle, fontFamily);
|
||||
|
||||
// Width
|
||||
if (this.isHorizontal()) {
|
||||
this.minSize.width = this.maxWidth; // fill all the width
|
||||
} else {
|
||||
this.minSize.width = 0;
|
||||
}
|
||||
|
||||
// height
|
||||
if (this.isHorizontal()) {
|
||||
this.minSize.height = 0;
|
||||
} else {
|
||||
this.minSize.height = this.maxHeight; // fill all the height
|
||||
}
|
||||
|
||||
// Increase sizes here
|
||||
if (this.isHorizontal()) {
|
||||
|
||||
// Title
|
||||
if (this.options.display) {
|
||||
this.minSize.height += fontSize + (this.options.padding * 2);
|
||||
}
|
||||
} else {
|
||||
if (this.options.display) {
|
||||
this.minSize.width += fontSize + (this.options.padding * 2);
|
||||
}
|
||||
}
|
||||
|
||||
this.width = this.minSize.width;
|
||||
this.height = this.minSize.height;
|
||||
|
||||
},
|
||||
afterFit: helpers.noop,
|
||||
|
||||
// Shared Methods
|
||||
isHorizontal: function() {
|
||||
return this.options.position === "top" || this.options.position === "bottom";
|
||||
},
|
||||
|
||||
// Actualy draw the title block on the canvas
|
||||
draw: function() {
|
||||
if (this.options.display) {
|
||||
var ctx = this.ctx;
|
||||
var titleX, titleY;
|
||||
|
||||
var fontColor = helpers.getValueOrDefault(this.options.fontColor, Chart.defaults.global.defaultFontColor);
|
||||
var fontSize = helpers.getValueOrDefault(this.options.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var fontStyle = helpers.getValueOrDefault(this.options.fontStyle, Chart.defaults.global.defaultFontStyle);
|
||||
var fontFamily = helpers.getValueOrDefault(this.options.fontFamily, Chart.defaults.global.defaultFontFamily);
|
||||
var titleFont = helpers.fontString(fontSize, fontStyle, fontFamily);
|
||||
|
||||
ctx.fillStyle = fontColor; // render in correct colour
|
||||
ctx.font = titleFont;
|
||||
|
||||
// Horizontal
|
||||
if (this.isHorizontal()) {
|
||||
// Title
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = 'middle';
|
||||
|
||||
titleX = this.left + ((this.right - this.left) / 2); // midpoint of the width
|
||||
titleY = this.top + ((this.bottom - this.top) / 2); // midpoint of the height
|
||||
|
||||
ctx.fillText(this.options.text, titleX, titleY);
|
||||
} else {
|
||||
|
||||
// Title
|
||||
titleX = this.options.position === 'left' ? this.left + (fontSize / 2) : this.right - (fontSize / 2);
|
||||
titleY = this.top + ((this.bottom - this.top) / 2);
|
||||
var rotation = this.options.position === 'left' ? -0.5 * Math.PI : 0.5 * Math.PI;
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(titleX, titleY);
|
||||
ctx.rotate(rotation);
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText(this.options.text, 0, 0);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
+347
-252
@@ -1,31 +1,22 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
"use strict";
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.defaults.global.tooltips = {
|
||||
enabled: true,
|
||||
custom: null,
|
||||
mode: 'single',
|
||||
backgroundColor: "rgba(0,0,0,0.8)",
|
||||
titleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
|
||||
titleFontSize: 12,
|
||||
titleFontStyle: "bold",
|
||||
titleSpacing: 2,
|
||||
titleMarginBottom: 6,
|
||||
titleColor: "#fff",
|
||||
titleAlign: "left",
|
||||
bodyFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
|
||||
bodyFontSize: 12,
|
||||
bodyFontStyle: "normal",
|
||||
bodySpacing: 2,
|
||||
bodyColor: "#fff",
|
||||
bodyAlign: "left",
|
||||
footerFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
|
||||
footerFontSize: 12,
|
||||
footerFontStyle: "bold",
|
||||
footerSpacing: 2,
|
||||
footerMarginTop: 6,
|
||||
@@ -33,9 +24,10 @@
|
||||
footerAlign: "left",
|
||||
yPadding: 6,
|
||||
xPadding: 6,
|
||||
yAlign : 'center',
|
||||
xAlign : 'center',
|
||||
caretSize: 5,
|
||||
cornerRadius: 6,
|
||||
xOffset: 10,
|
||||
multiKeyBackground: '#fff',
|
||||
callbacks: {
|
||||
// Args are: (tooltipItems, data)
|
||||
@@ -73,8 +65,8 @@
|
||||
// Args are: (tooltipItems, data)
|
||||
beforeFooter: helpers.noop,
|
||||
footer: helpers.noop,
|
||||
afterFooter: helpers.noop,
|
||||
},
|
||||
afterFooter: helpers.noop
|
||||
}
|
||||
};
|
||||
|
||||
// Helper to push or concat based on if the 2nd parameter is an array or not
|
||||
@@ -98,30 +90,31 @@
|
||||
// Positioning
|
||||
xPadding: options.tooltips.xPadding,
|
||||
yPadding: options.tooltips.yPadding,
|
||||
xOffset: options.tooltips.xOffset,
|
||||
xAlign : options.tooltips.yAlign,
|
||||
yAlign : options.tooltips.xAlign,
|
||||
|
||||
// Body
|
||||
bodyColor: options.tooltips.bodyColor,
|
||||
_bodyFontFamily: options.tooltips.bodyFontFamily,
|
||||
_bodyFontStyle: options.tooltips.bodyFontStyle,
|
||||
_bodyFontFamily: helpers.getValueOrDefault(options.tooltips.bodyFontFamily, Chart.defaults.global.defaultFontFamily),
|
||||
_bodyFontStyle: helpers.getValueOrDefault(options.tooltips.bodyFontStyle, Chart.defaults.global.defaultFontStyle),
|
||||
_bodyAlign: options.tooltips.bodyAlign,
|
||||
bodyFontSize: options.tooltips.bodyFontSize,
|
||||
bodyFontSize: helpers.getValueOrDefault(options.tooltips.bodyFontSize, Chart.defaults.global.defaultFontSize),
|
||||
bodySpacing: options.tooltips.bodySpacing,
|
||||
|
||||
// Title
|
||||
titleColor: options.tooltips.titleColor,
|
||||
_titleFontFamily: options.tooltips.titleFontFamily,
|
||||
_titleFontStyle: options.tooltips.titleFontStyle,
|
||||
titleFontSize: options.tooltips.titleFontSize,
|
||||
_titleFontFamily: helpers.getValueOrDefault(options.tooltips.titleFontFamily, Chart.defaults.global.defaultFontFamily),
|
||||
_titleFontStyle: helpers.getValueOrDefault(options.tooltips.titleFontStyle, Chart.defaults.global.defaultFontStyle),
|
||||
titleFontSize: helpers.getValueOrDefault(options.tooltips.titleFontSize, Chart.defaults.global.defaultFontSize),
|
||||
_titleAlign: options.tooltips.titleAlign,
|
||||
titleSpacing: options.tooltips.titleSpacing,
|
||||
titleMarginBottom: options.tooltips.titleMarginBottom,
|
||||
|
||||
// Footer
|
||||
footerColor: options.tooltips.footerColor,
|
||||
_footerFontFamily: options.tooltips.footerFontFamily,
|
||||
_footerFontStyle: options.tooltips.footerFontStyle,
|
||||
footerFontSize: options.tooltips.footerFontSize,
|
||||
_footerFontFamily: helpers.getValueOrDefault(options.tooltips.footerFontFamily, Chart.defaults.global.defaultFontFamily),
|
||||
_footerFontStyle: helpers.getValueOrDefault(options.tooltips.footerFontStyle, Chart.defaults.global.defaultFontStyle),
|
||||
footerFontSize: helpers.getValueOrDefault(options.tooltips.footerFontSize, Chart.defaults.global.defaultFontSize),
|
||||
_footerAlign: options.tooltips.footerAlign,
|
||||
footerSpacing: options.tooltips.footerSpacing,
|
||||
footerMarginTop: options.tooltips.footerMarginTop,
|
||||
@@ -131,8 +124,8 @@
|
||||
cornerRadius: options.tooltips.cornerRadius,
|
||||
backgroundColor: options.tooltips.backgroundColor,
|
||||
opacity: 0,
|
||||
legendColorBackground: options.tooltips.multiKeyBackground,
|
||||
},
|
||||
legendColorBackground: options.tooltips.multiKeyBackground
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -153,8 +146,8 @@
|
||||
|
||||
// Args are: (tooltipItem, data)
|
||||
getBeforeBody: function() {
|
||||
var lines = this._options.tooltips.callbacks.beforeBody.call(this, arguments);
|
||||
return helpers.isArray(lines) ? lines : [lines];
|
||||
var lines = this._options.tooltips.callbacks.beforeBody.apply(this, arguments);
|
||||
return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
|
||||
},
|
||||
|
||||
// Args are: (tooltipItem, data)
|
||||
@@ -162,11 +155,9 @@
|
||||
var lines = [];
|
||||
|
||||
helpers.each(tooltipItems, function(bodyItem) {
|
||||
var beforeLabel = this._options.tooltips.callbacks.beforeLabel.call(this, bodyItem, data) || '';
|
||||
var bodyLabel = this._options.tooltips.callbacks.label.call(this, bodyItem, data) || '';
|
||||
var afterLabel = this._options.tooltips.callbacks.afterLabel.call(this, bodyItem, data) || '';
|
||||
|
||||
lines.push(beforeLabel + bodyLabel + afterLabel);
|
||||
helpers.pushAllIfDefined(this._options.tooltips.callbacks.beforeLabel.call(this, bodyItem, data), lines);
|
||||
helpers.pushAllIfDefined(this._options.tooltips.callbacks.label.call(this, bodyItem, data), lines);
|
||||
helpers.pushAllIfDefined(this._options.tooltips.callbacks.afterLabel.call(this, bodyItem, data), lines);
|
||||
}, this);
|
||||
|
||||
return lines;
|
||||
@@ -174,8 +165,8 @@
|
||||
|
||||
// Args are: (tooltipItem, data)
|
||||
getAfterBody: function() {
|
||||
var lines = this._options.tooltips.callbacks.afterBody.call(this, arguments);
|
||||
return helpers.isArray(lines) ? lines : [lines];
|
||||
var lines = this._options.tooltips.callbacks.afterBody.apply(this, arguments);
|
||||
return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
|
||||
},
|
||||
|
||||
// Get the footer and beforeFooter and afterFooter lines
|
||||
@@ -193,24 +184,25 @@
|
||||
return lines;
|
||||
},
|
||||
|
||||
getAveragePosition: function(elements){
|
||||
getAveragePosition: function(elements) {
|
||||
|
||||
if(!elements.length){
|
||||
if (!elements.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var xPositions = [];
|
||||
var yPositions = [];
|
||||
|
||||
helpers.each(elements, function(el){
|
||||
if(el) {
|
||||
helpers.each(elements, function(el) {
|
||||
if (el) {
|
||||
var pos = el.tooltipPosition();
|
||||
xPositions.push(pos.x);
|
||||
yPositions.push(pos.y);
|
||||
}
|
||||
});
|
||||
|
||||
var x = 0, y = 0;
|
||||
var x = 0,
|
||||
y = 0;
|
||||
for (var i = 0; i < xPositions.length; i++) {
|
||||
x += xPositions[i];
|
||||
y += yPositions[i];
|
||||
@@ -224,10 +216,7 @@
|
||||
},
|
||||
|
||||
update: function(changed) {
|
||||
|
||||
var ctx = this._chart.ctx;
|
||||
|
||||
if(this._active.length){
|
||||
if (this._active.length) {
|
||||
this._model.opacity = 1;
|
||||
|
||||
var element = this._active[0],
|
||||
@@ -236,13 +225,13 @@
|
||||
|
||||
var tooltipItems = [];
|
||||
|
||||
if (this._options.tooltips.mode == 'single') {
|
||||
if (this._options.tooltips.mode === 'single') {
|
||||
var yScale = element._yScale || element._scale; // handle radar || polarArea charts
|
||||
tooltipItems.push({
|
||||
xLabel: element._xScale ? element._xScale.getLabelForIndex(element._index, element._datasetIndex) : '',
|
||||
yLabel: yScale ? yScale.getLabelForIndex(element._index, element._datasetIndex) : '',
|
||||
index: element._index,
|
||||
datasetIndex: element._datasetIndex,
|
||||
datasetIndex: element._datasetIndex
|
||||
});
|
||||
tooltipPosition = this.getAveragePosition(this._active);
|
||||
} else {
|
||||
@@ -258,19 +247,19 @@
|
||||
xLabel: currentElement._xScale ? currentElement._xScale.getLabelForIndex(currentElement._index, currentElement._datasetIndex) : '',
|
||||
yLabel: yScale ? yScale.getLabelForIndex(currentElement._index, currentElement._datasetIndex) : '',
|
||||
index: element._index,
|
||||
datasetIndex: datasetIndex,
|
||||
datasetIndex: datasetIndex
|
||||
});
|
||||
}
|
||||
});
|
||||
}, null, element._yScale.options.stacked);
|
||||
|
||||
helpers.each(this._active, function(active, i) {
|
||||
helpers.each(this._active, function(active) {
|
||||
if (active) {
|
||||
labelColors.push({
|
||||
borderColor: active._view.borderColor,
|
||||
backgroundColor: active._view.backgroundColor
|
||||
});
|
||||
labelColors.push({
|
||||
borderColor: active._view.borderColor,
|
||||
backgroundColor: active._view.backgroundColor
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
}, null, element._yScale.options.stacked);
|
||||
|
||||
tooltipPosition = this.getAveragePosition(this._active);
|
||||
tooltipPosition.y = this._active[0]._yScale.getPixelForDecimal(0.5);
|
||||
@@ -282,17 +271,22 @@
|
||||
beforeBody: this.getBeforeBody(tooltipItems, this._data),
|
||||
body: this.getBody(tooltipItems, this._data),
|
||||
afterBody: this.getAfterBody(tooltipItems, this._data),
|
||||
footer: this.getFooter(tooltipItems, this._data),
|
||||
footer: this.getFooter(tooltipItems, this._data)
|
||||
});
|
||||
|
||||
helpers.extend(this._model, {
|
||||
x: Math.round(tooltipPosition.x),
|
||||
y: Math.round(tooltipPosition.y),
|
||||
caretPadding: tooltipPosition.padding,
|
||||
labelColors: labelColors,
|
||||
caretPadding: helpers.getValueOrDefault(tooltipPosition.padding, 2),
|
||||
labelColors: labelColors
|
||||
});
|
||||
}
|
||||
else{
|
||||
|
||||
// We need to determine alignment of
|
||||
var tooltipSize = this.getTooltipSize(this._model);
|
||||
this.determineAlignment(tooltipSize); // Smart Tooltip placement to stay on the canvas
|
||||
|
||||
helpers.extend(this._model, this.getBackgroundPoint(this._model, tooltipSize));
|
||||
} else {
|
||||
this._model.opacity = 0;
|
||||
}
|
||||
|
||||
@@ -302,219 +296,320 @@
|
||||
|
||||
return this;
|
||||
},
|
||||
draw: function() {
|
||||
getTooltipSize: function getTooltipSize(vm) {
|
||||
var ctx = this._chart.ctx;
|
||||
|
||||
var size = {
|
||||
height: vm.yPadding * 2, // Tooltip Padding
|
||||
width: 0
|
||||
};
|
||||
var combinedBodyLength = vm.body.length + vm.beforeBody.length + vm.afterBody.length;
|
||||
|
||||
size.height += vm.title.length * vm.titleFontSize; // Title Lines
|
||||
size.height += (vm.title.length - 1) * vm.titleSpacing; // Title Line Spacing
|
||||
size.height += vm.title.length ? vm.titleMarginBottom : 0; // Title's bottom Margin
|
||||
size.height += combinedBodyLength * vm.bodyFontSize; // Body Lines
|
||||
size.height += combinedBodyLength ? (combinedBodyLength - 1) * vm.bodySpacing : 0; // Body Line Spacing
|
||||
size.height += vm.footer.length ? vm.footerMarginTop : 0; // Footer Margin
|
||||
size.height += vm.footer.length * (vm.footerFontSize); // Footer Lines
|
||||
size.height += vm.footer.length ? (vm.footer.length - 1) * vm.footerSpacing : 0; // Footer Line Spacing
|
||||
|
||||
// Width
|
||||
ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
|
||||
helpers.each(vm.title, function(line) {
|
||||
size.width = Math.max(size.width, ctx.measureText(line).width);
|
||||
});
|
||||
|
||||
ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
|
||||
helpers.each(vm.beforeBody.concat(vm.afterBody), function(line) {
|
||||
size.width = Math.max(size.width, ctx.measureText(line).width);
|
||||
});
|
||||
helpers.each(vm.body, function(line) {
|
||||
size.width = Math.max(size.width, ctx.measureText(line).width + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0));
|
||||
}, this);
|
||||
|
||||
ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
|
||||
helpers.each(vm.footer, function(line) {
|
||||
size.width = Math.max(size.width, ctx.measureText(line).width);
|
||||
});
|
||||
size.width += 2 * vm.xPadding;
|
||||
|
||||
return size;
|
||||
},
|
||||
determineAlignment: function determineAlignment(size) {
|
||||
if (this._model.y < size.height) {
|
||||
this._model.yAlign = 'top';
|
||||
} else if (this._model.y > (this._chart.height - size.height)) {
|
||||
this._model.yAlign = 'bottom';
|
||||
}
|
||||
|
||||
var lf, rf; // functions to determine left, right alignment
|
||||
var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
|
||||
var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
|
||||
var _this = this;
|
||||
var midX = (this._chartInstance.chartArea.left + this._chartInstance.chartArea.right) / 2;
|
||||
var midY = (this._chartInstance.chartArea.top + this._chartInstance.chartArea.bottom) / 2;
|
||||
|
||||
if (this._model.yAlign === 'center') {
|
||||
lf = function(x) {
|
||||
return x <= midX;
|
||||
};
|
||||
rf = function(x) {
|
||||
return x > midX;
|
||||
};
|
||||
} else {
|
||||
lf = function(x) {
|
||||
return x <= (size.width / 2);
|
||||
};
|
||||
rf = function(x) {
|
||||
return x >= (_this._chart.width - (size.width / 2));
|
||||
};
|
||||
}
|
||||
|
||||
olf = function(x) {
|
||||
return x + size.width > _this._chart.width;
|
||||
};
|
||||
orf = function(x) {
|
||||
return x - size.width < 0;
|
||||
};
|
||||
yf = function(y) {
|
||||
return y <= midY ? 'top' : 'bottom';
|
||||
};
|
||||
|
||||
if (lf(this._model.x)) {
|
||||
this._model.xAlign = 'left';
|
||||
|
||||
// Is tooltip too wide and goes over the right side of the chart.?
|
||||
if (olf(this._model.x)) {
|
||||
this._model.xAlign = 'center';
|
||||
this._model.yAlign = yf(this._model.y);
|
||||
}
|
||||
} else if (rf(this._model.x)) {
|
||||
this._model.xAlign = 'right';
|
||||
|
||||
// Is tooltip too wide and goes outside left edge of canvas?
|
||||
if (orf(this._model.x)) {
|
||||
this._model.xAlign = 'center';
|
||||
this._model.yAlign = yf(this._model.y);
|
||||
}
|
||||
}
|
||||
},
|
||||
getBackgroundPoint: function getBackgroundPoint(vm, size) {
|
||||
// Background Position
|
||||
var pt = {
|
||||
x: vm.x,
|
||||
y: vm.y
|
||||
};
|
||||
|
||||
if (vm.xAlign === 'right') {
|
||||
pt.x -= size.width;
|
||||
} else if (vm.xAlign === 'center') {
|
||||
pt.x -= (size.width / 2);
|
||||
}
|
||||
|
||||
if (vm.yAlign === 'top') {
|
||||
pt.y += vm.caretPadding + vm.caretSize;
|
||||
} else if (vm.yAlign === 'bottom') {
|
||||
pt.y -= size.height + vm.caretPadding + vm.caretSize;
|
||||
} else {
|
||||
pt.y -= (size.height / 2);
|
||||
}
|
||||
|
||||
if (vm.yAlign === 'center') {
|
||||
if (vm.xAlign === 'left') {
|
||||
pt.x += vm.caretPadding + vm.caretSize;
|
||||
} else if (vm.xAlign === 'right') {
|
||||
pt.x -= vm.caretPadding + vm.caretSize;
|
||||
}
|
||||
} else {
|
||||
if (vm.xAlign === 'left') {
|
||||
pt.x -= vm.cornerRadius + vm.caretPadding;
|
||||
} else if (vm.xAlign === 'right') {
|
||||
pt.x += vm.cornerRadius + vm.caretPadding;
|
||||
}
|
||||
}
|
||||
|
||||
return pt;
|
||||
},
|
||||
drawCaret: function drawCaret(tooltipPoint, size, opacity, caretPadding) {
|
||||
var vm = this._view;
|
||||
var ctx = this._chart.ctx;
|
||||
var x1, x2, x3;
|
||||
var y1, y2, y3;
|
||||
|
||||
if (vm.yAlign === 'center') {
|
||||
// Left or right side
|
||||
if (vm.xAlign === 'left') {
|
||||
x1 = tooltipPoint.x;
|
||||
x2 = x1 - vm.caretSize;
|
||||
x3 = x1;
|
||||
} else {
|
||||
x1 = tooltipPoint.x + size.width;
|
||||
x2 = x1 + vm.caretSize;
|
||||
x3 = x1;
|
||||
}
|
||||
|
||||
y2 = tooltipPoint.y + (size.height / 2);
|
||||
y1 = y2 - vm.caretSize;
|
||||
y3 = y2 + vm.caretSize;
|
||||
} else {
|
||||
if (vm.xAlign === 'left') {
|
||||
x1 = tooltipPoint.x + vm.cornerRadius;
|
||||
x2 = x1 + vm.caretSize;
|
||||
x3 = x2 + vm.caretSize;
|
||||
} else if (vm.xAlign === 'right') {
|
||||
x1 = tooltipPoint.x + size.width - vm.cornerRadius;
|
||||
x2 = x1 - vm.caretSize;
|
||||
x3 = x2 - vm.caretSize;
|
||||
} else {
|
||||
x2 = tooltipPoint.x + (size.width / 2);
|
||||
x1 = x2 - vm.caretSize;
|
||||
x3 = x2 + vm.caretSize;
|
||||
}
|
||||
|
||||
if (vm.yAlign === 'top') {
|
||||
y1 = tooltipPoint.y;
|
||||
y2 = y1 - vm.caretSize;
|
||||
y3 = y1;
|
||||
} else {
|
||||
y1 = tooltipPoint.y + size.height;
|
||||
y2 = y1 + vm.caretSize;
|
||||
y3 = y1;
|
||||
}
|
||||
}
|
||||
|
||||
var bgColor = helpers.color(vm.backgroundColor);
|
||||
ctx.fillStyle = bgColor.alpha(opacity * bgColor.alpha()).rgbString();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x1, y1);
|
||||
ctx.lineTo(x2, y2);
|
||||
ctx.lineTo(x3, y3);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
},
|
||||
drawTitle: function drawTitle(pt, vm, ctx, opacity) {
|
||||
if (vm.title.length) {
|
||||
ctx.textAlign = vm._titleAlign;
|
||||
ctx.textBaseline = "top";
|
||||
|
||||
var titleColor = helpers.color(vm.titleColor);
|
||||
ctx.fillStyle = titleColor.alpha(opacity * titleColor.alpha()).rgbString();
|
||||
ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
|
||||
|
||||
helpers.each(vm.title, function(title, i) {
|
||||
ctx.fillText(title, pt.x, pt.y);
|
||||
pt.y += vm.titleFontSize + vm.titleSpacing; // Line Height and spacing
|
||||
|
||||
if (i + 1 === vm.title.length) {
|
||||
pt.y += vm.titleMarginBottom - vm.titleSpacing; // If Last, add margin, remove spacing
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
drawBody: function drawBody(pt, vm, ctx, opacity) {
|
||||
ctx.textAlign = vm._bodyAlign;
|
||||
ctx.textBaseline = "top";
|
||||
|
||||
var bodyColor = helpers.color(vm.bodyColor);
|
||||
ctx.fillStyle = bodyColor.alpha(opacity * bodyColor.alpha()).rgbString();
|
||||
ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
|
||||
|
||||
// Before Body
|
||||
helpers.each(vm.beforeBody, function(beforeBody) {
|
||||
ctx.fillText(beforeBody, pt.x, pt.y);
|
||||
pt.y += vm.bodyFontSize + vm.bodySpacing;
|
||||
});
|
||||
|
||||
helpers.each(vm.body, function(body, i) {
|
||||
// Draw Legend-like boxes if needed
|
||||
if (this._options.tooltips.mode !== 'single') {
|
||||
// Fill a white rect so that colours merge nicely if the opacity is < 1
|
||||
ctx.fillStyle = helpers.color(vm.legendColorBackground).alpha(opacity).rgbaString();
|
||||
ctx.fillRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize);
|
||||
|
||||
// Border
|
||||
ctx.strokeStyle = helpers.color(vm.labelColors[i].borderColor).alpha(opacity).rgbaString();
|
||||
ctx.strokeRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize);
|
||||
|
||||
// Inner square
|
||||
ctx.fillStyle = helpers.color(vm.labelColors[i].backgroundColor).alpha(opacity).rgbaString();
|
||||
ctx.fillRect(pt.x + 1, pt.y + 1, vm.bodyFontSize - 2, vm.bodyFontSize - 2);
|
||||
|
||||
ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbaString(); // Return fill style for text
|
||||
}
|
||||
|
||||
// Body Line
|
||||
ctx.fillText(body, pt.x + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0), pt.y);
|
||||
|
||||
pt.y += vm.bodyFontSize + vm.bodySpacing;
|
||||
}, this);
|
||||
|
||||
// After Body
|
||||
helpers.each(vm.afterBody, function(afterBody) {
|
||||
ctx.fillText(afterBody, pt.x, pt.y);
|
||||
pt.y += vm.bodyFontSize;
|
||||
});
|
||||
|
||||
pt.y -= vm.bodySpacing; // Remove last body spacing
|
||||
},
|
||||
drawFooter: function drawFooter(pt, vm, ctx, opacity) {
|
||||
if (vm.footer.length) {
|
||||
pt.y += vm.footerMarginTop;
|
||||
|
||||
ctx.textAlign = vm._footerAlign;
|
||||
ctx.textBaseline = "top";
|
||||
|
||||
var footerColor = helpers.color(vm.footerColor);
|
||||
ctx.fillStyle = footerColor.alpha(opacity * footerColor.alpha()).rgbString();
|
||||
ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
|
||||
|
||||
helpers.each(vm.footer, function(footer) {
|
||||
ctx.fillText(footer, pt.x, pt.y);
|
||||
pt.y += vm.footerFontSize + vm.footerSpacing;
|
||||
});
|
||||
}
|
||||
},
|
||||
draw: function draw() {
|
||||
var ctx = this._chart.ctx;
|
||||
var vm = this._view;
|
||||
|
||||
if (this._view.opacity === 0) {
|
||||
if (vm.opacity === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get Dimensions
|
||||
|
||||
vm.position = "top";
|
||||
|
||||
var caretPadding = vm.caretPadding || 2;
|
||||
|
||||
var combinedBodyLength = vm.body.length + vm.beforeBody.length + vm.afterBody.length;
|
||||
|
||||
// Height
|
||||
var tooltipHeight = vm.yPadding * 2; // Tooltip Padding
|
||||
|
||||
tooltipHeight += vm.title.length * vm.titleFontSize; // Title Lines
|
||||
tooltipHeight += (vm.title.length - 1) * vm.titleSpacing; // Title Line Spacing
|
||||
tooltipHeight += vm.title.length ? vm.titleMarginBottom : 0; // Title's bottom Margin
|
||||
|
||||
tooltipHeight += combinedBodyLength * vm.bodyFontSize; // Body Lines
|
||||
tooltipHeight += (combinedBodyLength - 1) * vm.bodySpacing; // Body Line Spacing
|
||||
|
||||
tooltipHeight += vm.footer.length ? vm.footerMarginTop : 0; // Footer Margin
|
||||
tooltipHeight += vm.footer.length * (vm.footerFontSize); // Footer Lines
|
||||
tooltipHeight += (vm.footer.length - 1) * vm.footerSpacing; // Footer Line Spacing
|
||||
|
||||
// Width
|
||||
var tooltipWidth = 0;
|
||||
helpers.each(vm.title, function(line, i) {
|
||||
ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
|
||||
tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width);
|
||||
});
|
||||
helpers.each(vm.body, function(line, i) {
|
||||
ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
|
||||
tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width + (this._options.tooltips.mode != 'single' ? (vm.bodyFontSize + 2) : 0));
|
||||
}, this);
|
||||
helpers.each(vm.footer, function(line, i) {
|
||||
ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
|
||||
tooltipWidth = Math.max(tooltipWidth, ctx.measureText(line).width);
|
||||
});
|
||||
tooltipWidth += 2 * vm.xPadding;
|
||||
var tooltipTotalWidth = tooltipWidth + vm.caretSize + caretPadding;
|
||||
|
||||
|
||||
|
||||
// Smart Tooltip placement to stay on the canvas
|
||||
// Top, center, or bottom
|
||||
vm.yAlign = "center";
|
||||
if (vm.y - (tooltipHeight / 2) < 0) {
|
||||
vm.yAlign = "top";
|
||||
} else if (vm.y + (tooltipHeight / 2) > this._chart.height) {
|
||||
vm.yAlign = "bottom";
|
||||
}
|
||||
|
||||
|
||||
// Left or Right
|
||||
vm.xAlign = "right";
|
||||
if (vm.x + tooltipTotalWidth > this._chart.width) {
|
||||
vm.xAlign = "left";
|
||||
}
|
||||
|
||||
|
||||
// Background Position
|
||||
var tooltipX = vm.x,
|
||||
tooltipY = vm.y;
|
||||
|
||||
if (vm.yAlign == 'top') {
|
||||
tooltipY = vm.y - vm.caretSize - vm.cornerRadius;
|
||||
} else if (vm.yAlign == 'bottom') {
|
||||
tooltipY = vm.y - tooltipHeight + vm.caretSize + vm.cornerRadius;
|
||||
} else {
|
||||
tooltipY = vm.y - (tooltipHeight / 2);
|
||||
}
|
||||
|
||||
if (vm.xAlign == 'left') {
|
||||
tooltipX = vm.x - tooltipTotalWidth;
|
||||
} else if (vm.xAlign == 'right') {
|
||||
tooltipX = vm.x + caretPadding + vm.caretSize;
|
||||
} else {
|
||||
tooltipX = vm.x + (tooltipTotalWidth / 2);
|
||||
}
|
||||
|
||||
// Draw Background
|
||||
var caretPadding = vm.caretPadding;
|
||||
var tooltipSize = this.getTooltipSize(vm);
|
||||
var pt = {
|
||||
x: vm.x,
|
||||
y: vm.y
|
||||
};
|
||||
|
||||
// IE11/Edge does not like very small opacities, so snap to 0
|
||||
var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
|
||||
|
||||
if (this._options.tooltips.enabled) {
|
||||
ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString();
|
||||
helpers.drawRoundedRectangle(ctx, tooltipX, tooltipY, tooltipWidth, tooltipHeight, vm.cornerRadius);
|
||||
// Draw Background
|
||||
var bgColor = helpers.color(vm.backgroundColor);
|
||||
ctx.fillStyle = bgColor.alpha(opacity * bgColor.alpha()).rgbString();
|
||||
helpers.drawRoundedRectangle(ctx, pt.x, pt.y, tooltipSize.width, tooltipSize.height, vm.cornerRadius);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
// Draw Caret
|
||||
this.drawCaret(pt, tooltipSize, opacity, caretPadding);
|
||||
|
||||
// Draw Caret
|
||||
if (this._options.tooltips.enabled) {
|
||||
ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString();
|
||||
|
||||
if (vm.xAlign == 'left') {
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(vm.x - caretPadding, vm.y);
|
||||
ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y - vm.caretSize);
|
||||
ctx.lineTo(vm.x - caretPadding - vm.caretSize, vm.y + vm.caretSize);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
} else {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(vm.x + caretPadding, vm.y);
|
||||
ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y - vm.caretSize);
|
||||
ctx.lineTo(vm.x + caretPadding + vm.caretSize, vm.y + vm.caretSize);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
|
||||
// Draw Title, Body, and Footer
|
||||
|
||||
if (this._options.tooltips.enabled) {
|
||||
|
||||
var yBase = tooltipY + vm.yPadding;
|
||||
var xBase = tooltipX + vm.xPadding;
|
||||
// Draw Title, Body, and Footer
|
||||
pt.x += vm.xPadding;
|
||||
pt.y += vm.yPadding;
|
||||
|
||||
// Titles
|
||||
|
||||
if (vm.title.length) {
|
||||
ctx.textAlign = vm._titleAlign;
|
||||
ctx.textBaseline = "top";
|
||||
ctx.fillStyle = helpers.color(vm.titleColor).alpha(opacity).rgbString();
|
||||
ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
|
||||
|
||||
helpers.each(vm.title, function(title, i) {
|
||||
ctx.fillText(title, xBase, yBase);
|
||||
yBase += vm.titleFontSize + vm.titleSpacing; // Line Height and spacing
|
||||
if (i + 1 == vm.title.length) {
|
||||
yBase += vm.titleMarginBottom - vm.titleSpacing; // If Last, add margin, remove spacing
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
this.drawTitle(pt, vm, ctx, opacity);
|
||||
|
||||
// Body
|
||||
ctx.textAlign = vm._bodyAlign;
|
||||
ctx.textBaseline = "top";
|
||||
ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbString();
|
||||
ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
|
||||
|
||||
// Before Body
|
||||
helpers.each(vm.beforeBody, function(beforeBody, i) {
|
||||
ctx.fillText(vm.beforeBody, xBase, yBase);
|
||||
yBase += vm.bodyFontSize + vm.bodySpacing;
|
||||
});
|
||||
|
||||
helpers.each(vm.body, function(body, i) {
|
||||
|
||||
|
||||
// Draw Legend-like boxes if needed
|
||||
if (this._options.tooltips.mode != 'single') {
|
||||
// Fill a white rect so that colours merge nicely if the opacity is < 1
|
||||
ctx.fillStyle = helpers.color('#FFFFFF').alpha(opacity).rgbaString();
|
||||
ctx.fillRect(xBase, yBase, vm.bodyFontSize, vm.bodyFontSize);
|
||||
|
||||
// Border
|
||||
ctx.strokeStyle = helpers.color(vm.labelColors[i].borderColor).alpha(opacity).rgbaString();
|
||||
ctx.strokeRect(xBase, yBase, vm.bodyFontSize, vm.bodyFontSize);
|
||||
|
||||
// Inner square
|
||||
ctx.fillStyle = helpers.color(vm.labelColors[i].backgroundColor).alpha(opacity).rgbaString();
|
||||
ctx.fillRect(xBase + 1, yBase + 1, vm.bodyFontSize - 2, vm.bodyFontSize - 2);
|
||||
|
||||
ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbaString(); // Return fill style for text
|
||||
}
|
||||
|
||||
// Body Line
|
||||
ctx.fillText(body, xBase + (this._options.tooltips.mode != 'single' ? (vm.bodyFontSize + 2) : 0), yBase);
|
||||
|
||||
yBase += vm.bodyFontSize + vm.bodySpacing;
|
||||
|
||||
}, this);
|
||||
|
||||
// After Body
|
||||
helpers.each(vm.afterBody, function(afterBody, i) {
|
||||
ctx.fillText(vm.afterBody, xBase, yBase);
|
||||
yBase += vm.bodyFontSize;
|
||||
});
|
||||
|
||||
yBase -= vm.bodySpacing; // Remove last body spacing
|
||||
|
||||
this.drawBody(pt, vm, ctx, opacity);
|
||||
|
||||
// Footer
|
||||
if (vm.footer.length) {
|
||||
|
||||
yBase += vm.footerMarginTop;
|
||||
|
||||
ctx.textAlign = vm._footerAlign;
|
||||
ctx.textBaseline = "top";
|
||||
ctx.fillStyle = helpers.color(vm.footerColor).alpha(opacity).rgbString();
|
||||
ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
|
||||
|
||||
helpers.each(vm.footer, function(footer, i) {
|
||||
ctx.fillText(footer, xBase, yBase);
|
||||
yBase += vm.footerFontSize + vm.footerSpacing;
|
||||
}, this);
|
||||
}
|
||||
|
||||
this.drawFooter(pt, vm, ctx, opacity);
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
|
||||
@@ -1,96 +1,81 @@
|
||||
/*!
|
||||
* Chart.js
|
||||
* http://chartjs.org/
|
||||
* Version: {{ version }}
|
||||
*
|
||||
* Copyright 2015 Nick Downie
|
||||
* Released under the MIT license
|
||||
* https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
module.exports = function(Chart, moment) {
|
||||
|
||||
(function() {
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
"use strict";
|
||||
Chart.defaults.global.elements.arc = {
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderColor: "#fff",
|
||||
borderWidth: 2
|
||||
};
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
Chart.elements.Arc = Chart.Element.extend({
|
||||
inLabelRange: function(mouseX) {
|
||||
var vm = this._view;
|
||||
|
||||
Chart.defaults.global.elements.arc = {
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderColor: "#fff",
|
||||
borderWidth: 2
|
||||
};
|
||||
if (vm) {
|
||||
return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
inRange: function(chartX, chartY) {
|
||||
|
||||
Chart.elements.Arc = Chart.Element.extend({
|
||||
inLabelRange: function(mouseX) {
|
||||
var vm = this._view;
|
||||
var vm = this._view;
|
||||
|
||||
if (vm) {
|
||||
return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
inRange: function(chartX, chartY) {
|
||||
if (vm) {
|
||||
var pointRelativePosition = helpers.getAngleFromPoint(vm, {
|
||||
x: chartX,
|
||||
y: chartY
|
||||
});
|
||||
|
||||
var vm = this._view;
|
||||
// Put into the range of (-PI/2, 3PI/2]
|
||||
var startAngle = vm.startAngle < (-0.5 * Math.PI) ? vm.startAngle + (2.0 * Math.PI) : vm.startAngle > (1.5 * Math.PI) ? vm.startAngle - (2.0 * Math.PI) : vm.startAngle;
|
||||
var endAngle = vm.endAngle < (-0.5 * Math.PI) ? vm.endAngle + (2.0 * Math.PI) : vm.endAngle > (1.5 * Math.PI) ? vm.endAngle - (2.0 * Math.PI) : vm.endAngle;
|
||||
|
||||
if (vm) {
|
||||
var pointRelativePosition = helpers.getAngleFromPoint(vm, {
|
||||
x: chartX,
|
||||
y: chartY
|
||||
});
|
||||
//Check if within the range of the open/close angle
|
||||
var betweenAngles = (pointRelativePosition.angle >= startAngle && pointRelativePosition.angle <= endAngle),
|
||||
withinRadius = (pointRelativePosition.distance >= vm.innerRadius && pointRelativePosition.distance <= vm.outerRadius);
|
||||
|
||||
// Put into the range of (-PI/2, 3PI/2]
|
||||
var startAngle = vm.startAngle < (-0.5 * Math.PI) ? vm.startAngle + (2.0 * Math.PI) : vm.startAngle > (1.5 * Math.PI) ? vm.startAngle - (2.0 * Math.PI) : vm.startAngle;
|
||||
var endAngle = vm.endAngle < (-0.5 * Math.PI) ? vm.endAngle + (2.0 * Math.PI) : vm.endAngle > (1.5 * Math.PI) ? vm.endAngle - (2.0 * Math.PI) : vm.endAngle;
|
||||
return (betweenAngles && withinRadius);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
tooltipPosition: function() {
|
||||
var vm = this._view;
|
||||
|
||||
//Check if within the range of the open/close angle
|
||||
var betweenAngles = (pointRelativePosition.angle >= startAngle && pointRelativePosition.angle <= endAngle),
|
||||
withinRadius = (pointRelativePosition.distance >= vm.innerRadius && pointRelativePosition.distance <= vm.outerRadius);
|
||||
var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2),
|
||||
rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
|
||||
return {
|
||||
x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
|
||||
y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
|
||||
};
|
||||
},
|
||||
draw: function() {
|
||||
|
||||
return (betweenAngles && withinRadius);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
tooltipPosition: function() {
|
||||
var vm = this._view;
|
||||
var ctx = this._chart.ctx;
|
||||
var vm = this._view;
|
||||
|
||||
var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2),
|
||||
rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
|
||||
return {
|
||||
x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
|
||||
y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
|
||||
};
|
||||
},
|
||||
draw: function() {
|
||||
ctx.beginPath();
|
||||
|
||||
var ctx = this._chart.ctx;
|
||||
var vm = this._view;
|
||||
ctx.arc(vm.x, vm.y, vm.outerRadius, vm.startAngle, vm.endAngle);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(vm.x, vm.y, vm.innerRadius, vm.endAngle, vm.startAngle, true);
|
||||
|
||||
ctx.arc(vm.x, vm.y, vm.outerRadius, vm.startAngle, vm.endAngle);
|
||||
ctx.closePath();
|
||||
ctx.strokeStyle = vm.borderColor;
|
||||
ctx.lineWidth = vm.borderWidth;
|
||||
|
||||
ctx.arc(vm.x, vm.y, vm.innerRadius, vm.endAngle, vm.startAngle, true);
|
||||
ctx.fillStyle = vm.backgroundColor;
|
||||
|
||||
ctx.closePath();
|
||||
ctx.strokeStyle = vm.borderColor;
|
||||
ctx.lineWidth = vm.borderWidth;
|
||||
ctx.fill();
|
||||
ctx.lineJoin = 'bevel';
|
||||
|
||||
ctx.fillStyle = vm.backgroundColor;
|
||||
|
||||
ctx.fill();
|
||||
ctx.lineJoin = 'bevel';
|
||||
|
||||
if (vm.borderWidth) {
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}).call(this);
|
||||
if (vm.borderWidth) {
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,21 +1,8 @@
|
||||
/*!
|
||||
* Chart.js
|
||||
* http://chartjs.org/
|
||||
* Version: {{ version }}
|
||||
*
|
||||
* Copyright 2015 Nick Downie
|
||||
* Released under the MIT license
|
||||
* https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
module.exports = function(Chart) {
|
||||
|
||||
(function() {
|
||||
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.defaults.global.elements.line = {
|
||||
tension: 0.4,
|
||||
@@ -26,7 +13,7 @@
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.0,
|
||||
borderJoinStyle: 'miter',
|
||||
fill: true, // do we fill in the area between the line and its base axis
|
||||
fill: true // do we fill in the area between the line and its base axis
|
||||
};
|
||||
|
||||
Chart.elements.Line = Chart.Element.extend({
|
||||
@@ -34,13 +21,15 @@
|
||||
var ctx = this._chart.ctx;
|
||||
|
||||
if (point._view.skip) {
|
||||
skipHandler.call(this, previousPoint, point, nextPoint);
|
||||
skipHandler.call(this, previousPoint, point, nextPoint);
|
||||
} else if (previousPoint._view.skip) {
|
||||
previousSkipHandler.call(this, previousPoint, point, nextPoint);
|
||||
} else if (point._view.tension === 0) {
|
||||
ctx.lineTo(point._view.x, point._view.y);
|
||||
} else {
|
||||
// Line between points
|
||||
ctx.bezierCurveTo(
|
||||
previousPoint._view.controlPointNextX,
|
||||
previousPoint._view.controlPointNextX,
|
||||
previousPoint._view.controlPointNextY,
|
||||
point._view.controlPointPreviousX,
|
||||
point._view.controlPointPreviousY,
|
||||
@@ -110,7 +99,7 @@
|
||||
ctx.lineTo(previousPoint._view.x, this._view.scaleZero);
|
||||
ctx.moveTo(nextPoint._view.x, this._view.scaleZero);
|
||||
}
|
||||
}, function(previousPoint, point, nextPoint) {
|
||||
}, function(previousPoint, point) {
|
||||
// If we skipped the last point, draw a line to ourselves so that the fill is nice
|
||||
ctx.lineTo(point._view.x, point._view.y);
|
||||
});
|
||||
@@ -154,20 +143,19 @@
|
||||
} else {
|
||||
this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
|
||||
ctx.moveTo(nextPoint._view.x, nextPoint._view.y);
|
||||
}, function(previousPoint, point, nextPoint) {
|
||||
}, function(previousPoint, point) {
|
||||
// If we skipped the last point, move up to our point preventing a line from being drawn
|
||||
ctx.moveTo(point._view.x, point._view.y);
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (this._loop) {
|
||||
if (this._loop && this._children.length > 0) {
|
||||
loopBackToStart();
|
||||
}
|
||||
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
@@ -1,31 +1,19 @@
|
||||
/*!
|
||||
* Chart.js
|
||||
* http://chartjs.org/
|
||||
* Version: {{ version }}
|
||||
*
|
||||
* Copyright 2015 Nick Downie
|
||||
* Released under the MIT license
|
||||
* https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
module.exports = function(Chart) {
|
||||
|
||||
(function() {
|
||||
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.defaults.global.elements.point = {
|
||||
radius: 3,
|
||||
pointStyle: 'circle',
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
// Hover
|
||||
hitRadius: 1,
|
||||
hoverRadius: 4,
|
||||
hoverBorderWidth: 1,
|
||||
hoverBorderWidth: 1
|
||||
};
|
||||
|
||||
|
||||
@@ -67,23 +55,99 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (vm.radius > 0 || vm.borderWidth > 0) {
|
||||
if (typeof vm.pointStyle === 'object' && ((vm.pointStyle.toString() === '[object HTMLImageElement]') || (vm.pointStyle.toString() === '[object HTMLCanvasElement]'))) {
|
||||
ctx.drawImage(vm.pointStyle, vm.x - vm.pointStyle.width / 2, vm.y - vm.pointStyle.height / 2);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.arc(vm.x, vm.y, vm.radius || Chart.defaults.global.elements.point.radius, 0, Math.PI * 2);
|
||||
ctx.closePath();
|
||||
if (!isNaN(vm.radius) && vm.radius > 0) {
|
||||
|
||||
ctx.strokeStyle = vm.borderColor || Chart.defaults.global.defaultColor;
|
||||
ctx.lineWidth = vm.borderWidth || Chart.defaults.global.elements.point.borderWidth;
|
||||
ctx.lineWidth = helpers.getValueOrDefault(vm.borderWidth, Chart.defaults.global.elements.point.borderWidth);
|
||||
|
||||
ctx.fillStyle = vm.backgroundColor || Chart.defaults.global.defaultColor;
|
||||
|
||||
ctx.fill();
|
||||
var radius = vm.radius;
|
||||
|
||||
var xOffset;
|
||||
var yOffset;
|
||||
|
||||
switch (vm.pointStyle) {
|
||||
// Default includes circle
|
||||
default: ctx.beginPath();
|
||||
ctx.arc(vm.x, vm.y, radius, 0, Math.PI * 2);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
break;
|
||||
case 'triangle':
|
||||
ctx.beginPath();
|
||||
var edgeLength = 3 * radius / Math.sqrt(3);
|
||||
var height = edgeLength * Math.sqrt(3) / 2;
|
||||
ctx.moveTo(vm.x - edgeLength / 2, vm.y + height / 3);
|
||||
ctx.lineTo(vm.x + edgeLength / 2, vm.y + height / 3);
|
||||
ctx.lineTo(vm.x, vm.y - 2 * height / 3);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
break;
|
||||
case 'rect':
|
||||
ctx.fillRect(vm.x - 1 / Math.SQRT2 * radius, vm.y - 1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius);
|
||||
ctx.strokeRect(vm.x - 1 / Math.SQRT2 * radius, vm.y - 1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius);
|
||||
break;
|
||||
case 'rectRot':
|
||||
ctx.translate(vm.x, vm.y);
|
||||
ctx.rotate(Math.PI / 4);
|
||||
ctx.fillRect(-1 / Math.SQRT2 * radius, -1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius);
|
||||
ctx.strokeRect(-1 / Math.SQRT2 * radius, -1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius);
|
||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
break;
|
||||
case 'cross':
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(vm.x, vm.y + radius);
|
||||
ctx.lineTo(vm.x, vm.y - radius);
|
||||
ctx.moveTo(vm.x - radius, vm.y);
|
||||
ctx.lineTo(vm.x + radius, vm.y);
|
||||
ctx.closePath();
|
||||
break;
|
||||
case 'crossRot':
|
||||
ctx.beginPath();
|
||||
xOffset = Math.cos(Math.PI / 4) * radius;
|
||||
yOffset = Math.sin(Math.PI / 4) * radius;
|
||||
ctx.moveTo(vm.x - xOffset, vm.y - yOffset);
|
||||
ctx.lineTo(vm.x + xOffset, vm.y + yOffset);
|
||||
ctx.moveTo(vm.x - xOffset, vm.y + yOffset);
|
||||
ctx.lineTo(vm.x + xOffset, vm.y - yOffset);
|
||||
ctx.closePath();
|
||||
break;
|
||||
case 'star':
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(vm.x, vm.y + radius);
|
||||
ctx.lineTo(vm.x, vm.y - radius);
|
||||
ctx.moveTo(vm.x - radius, vm.y);
|
||||
ctx.lineTo(vm.x + radius, vm.y);
|
||||
xOffset = Math.cos(Math.PI / 4) * radius;
|
||||
yOffset = Math.sin(Math.PI / 4) * radius;
|
||||
ctx.moveTo(vm.x - xOffset, vm.y - yOffset);
|
||||
ctx.lineTo(vm.x + xOffset, vm.y + yOffset);
|
||||
ctx.moveTo(vm.x - xOffset, vm.y + yOffset);
|
||||
ctx.lineTo(vm.x + xOffset, vm.y - yOffset);
|
||||
ctx.closePath();
|
||||
break;
|
||||
case 'line':
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(vm.x - radius, vm.y);
|
||||
ctx.lineTo(vm.x + radius, vm.y);
|
||||
ctx.closePath();
|
||||
break;
|
||||
case 'dash':
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(vm.x, vm.y);
|
||||
ctx.lineTo(vm.x + radius, vm.y);
|
||||
ctx.closePath();
|
||||
break;
|
||||
}
|
||||
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
@@ -1,15 +1,14 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
"use strict";
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
Chart.defaults.global.elements.rectangle = {
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 0,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
borderSkipped: 'bottom'
|
||||
};
|
||||
|
||||
Chart.elements.Rectangle = Chart.Element.extend({
|
||||
@@ -38,12 +37,31 @@
|
||||
ctx.strokeStyle = vm.borderColor;
|
||||
ctx.lineWidth = vm.borderWidth;
|
||||
|
||||
// It'd be nice to keep this class totally generic to any rectangle
|
||||
// and simply specify which border to miss out.
|
||||
ctx.moveTo(leftX, vm.base);
|
||||
ctx.lineTo(leftX, top);
|
||||
ctx.lineTo(rightX, top);
|
||||
ctx.lineTo(rightX, vm.base);
|
||||
// Corner points, from bottom-left to bottom-right clockwise
|
||||
// | 1 2 |
|
||||
// | 0 3 |
|
||||
var corners = [
|
||||
[leftX, vm.base],
|
||||
[leftX, top],
|
||||
[rightX, top],
|
||||
[rightX, vm.base]
|
||||
];
|
||||
|
||||
// Find first (starting) corner with fallback to 'bottom'
|
||||
var borders = ['bottom', 'left', 'top', 'right'];
|
||||
var startCorner = borders.indexOf(vm.borderSkipped, 0);
|
||||
if (startCorner === -1)
|
||||
startCorner = 0;
|
||||
|
||||
function cornerAt(index) {
|
||||
return corners[(startCorner + index) % 4];
|
||||
}
|
||||
|
||||
// Draw rectangle from 'startCorner'
|
||||
ctx.moveTo.apply(ctx, cornerAt(0));
|
||||
for (var i = 1; i < 4; i++)
|
||||
ctx.lineTo.apply(ctx, cornerAt(i));
|
||||
|
||||
ctx.fill();
|
||||
if (vm.borderWidth) {
|
||||
ctx.stroke();
|
||||
@@ -78,20 +96,11 @@
|
||||
},
|
||||
tooltipPosition: function() {
|
||||
var vm = this._view;
|
||||
if (vm.y < vm.base) {
|
||||
return {
|
||||
x: vm.x,
|
||||
y: vm.y
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
x: vm.x,
|
||||
y: vm.base
|
||||
};
|
||||
}
|
||||
},
|
||||
return {
|
||||
x: vm.x,
|
||||
y: vm.y
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
@@ -1,50 +1,71 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
// Default config for a category scale
|
||||
var defaultConfig = {
|
||||
position: "bottom",
|
||||
};
|
||||
var helpers = Chart.helpers;
|
||||
// Default config for a category scale
|
||||
var defaultConfig = {
|
||||
position: "bottom"
|
||||
};
|
||||
|
||||
var DatasetScale = Chart.Scale.extend({
|
||||
buildTicks: function(index) {
|
||||
this.ticks = this.chart.data.labels;
|
||||
},
|
||||
var DatasetScale = Chart.Scale.extend({
|
||||
buildTicks: function(index) {
|
||||
this.startIndex = 0;
|
||||
this.endIndex = this.chart.data.labels.length;
|
||||
var findIndex;
|
||||
|
||||
getLabelForIndex: function(index, datasetIndex) {
|
||||
return this.ticks[index];
|
||||
},
|
||||
if (this.options.ticks.min !== undefined) {
|
||||
// user specified min value
|
||||
findIndex = helpers.indexOf(this.chart.data.labels, this.options.ticks.min);
|
||||
this.startIndex = findIndex !== -1 ? findIndex : this.startIndex;
|
||||
}
|
||||
|
||||
// Used to get data value locations. Value can either be an index or a numerical value
|
||||
getPixelForValue: function(value, index, datasetIndex, includeOffset) {
|
||||
if (this.isHorizontal()) {
|
||||
var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
|
||||
var valueWidth = innerWidth / Math.max((this.chart.data.labels.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
|
||||
var widthOffset = (valueWidth * index) + this.paddingLeft;
|
||||
if (this.options.ticks.max !== undefined) {
|
||||
// user specified max value
|
||||
findIndex = helpers.indexOf(this.chart.data.labels, this.options.ticks.max);
|
||||
this.endIndex = findIndex !== -1 ? findIndex : this.endIndex;
|
||||
}
|
||||
|
||||
if (this.options.gridLines.offsetGridLines && includeOffset) {
|
||||
widthOffset += (valueWidth / 2);
|
||||
}
|
||||
// If we are viewing some subset of labels, slice the original array
|
||||
this.ticks = (this.startIndex === 0 && this.endIndex === this.chart.data.labels.length) ? this.chart.data.labels : this.chart.data.labels.slice(this.startIndex, this.endIndex + 1);
|
||||
},
|
||||
|
||||
return this.left + Math.round(widthOffset);
|
||||
} else {
|
||||
var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
|
||||
var valueHeight = innerHeight / Math.max((this.chart.data.labels.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
|
||||
var heightOffset = (valueHeight * index) + this.paddingTop;
|
||||
getLabelForIndex: function(index, datasetIndex) {
|
||||
return this.ticks[index];
|
||||
},
|
||||
|
||||
if (this.options.gridLines.offsetGridLines && includeOffset) {
|
||||
heightOffset += (valueHeight / 2);
|
||||
}
|
||||
// Used to get data value locations. Value can either be an index or a numerical value
|
||||
getPixelForValue: function(value, index, datasetIndex, includeOffset) {
|
||||
// 1 is added because we need the length but we have the indexes
|
||||
var offsetAmt = Math.max((this.ticks.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
|
||||
|
||||
return this.top + Math.round(heightOffset);
|
||||
}
|
||||
},
|
||||
});
|
||||
if (this.isHorizontal()) {
|
||||
var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
|
||||
var valueWidth = innerWidth / offsetAmt;
|
||||
var widthOffset = (valueWidth * (index - this.startIndex)) + this.paddingLeft;
|
||||
|
||||
Chart.scaleService.registerScaleType("category", DatasetScale, defaultConfig);
|
||||
if (this.options.gridLines.offsetGridLines && includeOffset) {
|
||||
widthOffset += (valueWidth / 2);
|
||||
}
|
||||
|
||||
}).call(this);
|
||||
return this.left + Math.round(widthOffset);
|
||||
} else {
|
||||
var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
|
||||
var valueHeight = innerHeight / offsetAmt;
|
||||
var heightOffset = (valueHeight * (index - this.startIndex)) + this.paddingTop;
|
||||
|
||||
if (this.options.gridLines.offsetGridLines && includeOffset) {
|
||||
heightOffset += (valueHeight / 2);
|
||||
}
|
||||
|
||||
return this.top + Math.round(heightOffset);
|
||||
}
|
||||
},
|
||||
getPixelForTick: function(index, includeOffset) {
|
||||
return this.getPixelForValue(this.ticks[index], index + this.startIndex, null, includeOffset);
|
||||
}
|
||||
});
|
||||
|
||||
Chart.scaleService.registerScaleType("category", DatasetScale, defaultConfig);
|
||||
|
||||
};
|
||||
@@ -1,9 +1,8 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
position: "left",
|
||||
@@ -36,20 +35,21 @@
|
||||
};
|
||||
|
||||
var LinearScale = Chart.Scale.extend({
|
||||
buildTicks: function() {
|
||||
|
||||
determineDataLimits: function() {
|
||||
// First Calculate the range
|
||||
this.min = null;
|
||||
this.max = null;
|
||||
|
||||
if (this.options.stacked) {
|
||||
var valuesPerType = {};
|
||||
var hasPositiveValues = false;
|
||||
var hasNegativeValues = false;
|
||||
|
||||
helpers.each(this.chart.data.datasets, function(dataset) {
|
||||
if (valuesPerType[dataset.type] === undefined) {
|
||||
valuesPerType[dataset.type] = {
|
||||
positiveValues: [],
|
||||
negativeValues: [],
|
||||
negativeValues: []
|
||||
};
|
||||
}
|
||||
|
||||
@@ -72,8 +72,10 @@
|
||||
positiveValues[index] = 100;
|
||||
} else {
|
||||
if (value < 0) {
|
||||
hasNegativeValues = true;
|
||||
negativeValues[index] += value;
|
||||
} else {
|
||||
hasPositiveValues = true;
|
||||
positiveValues[index] += value;
|
||||
}
|
||||
}
|
||||
@@ -114,32 +116,6 @@
|
||||
}, this);
|
||||
}
|
||||
|
||||
// Then calulate the ticks
|
||||
this.ticks = [];
|
||||
|
||||
// Figure out what the max number of ticks we can support it is based on the size of
|
||||
// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
|
||||
// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
|
||||
// the graph
|
||||
|
||||
var maxTicks;
|
||||
|
||||
if (this.isHorizontal()) {
|
||||
maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11,
|
||||
Math.ceil(this.width / 50));
|
||||
} else {
|
||||
// The factor of 2 used to scale the font size has been experimentally determined.
|
||||
maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11,
|
||||
Math.ceil(this.height / (2 * this.options.ticks.fontSize)));
|
||||
}
|
||||
|
||||
// Make sure we always have at least 2 ticks
|
||||
maxTicks = Math.max(2, maxTicks);
|
||||
|
||||
// To get a "nice" value for the tick spacing, we will use the appropriately named
|
||||
// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
|
||||
// for details.
|
||||
|
||||
// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
|
||||
// do nothing since that would make the chart weird. If the user really wants a weird chart
|
||||
// axis, they can manually override it
|
||||
@@ -156,11 +132,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.ticks.suggestedMin) {
|
||||
if (this.options.ticks.min !== undefined) {
|
||||
this.min = this.options.ticks.min;
|
||||
} else if (this.options.ticks.suggestedMin !== undefined) {
|
||||
this.min = Math.min(this.min, this.options.ticks.suggestedMin);
|
||||
}
|
||||
|
||||
if (this.options.ticks.suggestedMax) {
|
||||
if (this.options.ticks.max !== undefined) {
|
||||
this.max = this.options.ticks.max;
|
||||
} else if (this.options.ticks.suggestedMax !== undefined) {
|
||||
this.max = Math.max(this.max, this.options.ticks.suggestedMax);
|
||||
}
|
||||
|
||||
@@ -168,20 +148,61 @@
|
||||
this.min--;
|
||||
this.max++;
|
||||
}
|
||||
},
|
||||
buildTicks: function() {
|
||||
|
||||
var niceRange = helpers.niceNum(this.max - this.min, false);
|
||||
var spacing = helpers.niceNum(niceRange / (maxTicks - 1), true);
|
||||
var niceMin = Math.floor(this.min / spacing) * spacing;
|
||||
var niceMax = Math.ceil(this.max / spacing) * spacing;
|
||||
// Then calulate the ticks
|
||||
this.ticks = [];
|
||||
|
||||
var numSpaces = Math.ceil((niceMax - niceMin) / spacing);
|
||||
// Figure out what the max number of ticks we can support it is based on the size of
|
||||
// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
|
||||
// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
|
||||
// the graph
|
||||
|
||||
// Put the values into the ticks array
|
||||
for (var j = 0; j <= numSpaces; ++j) {
|
||||
this.ticks.push(niceMin + (j * spacing));
|
||||
var maxTicks;
|
||||
|
||||
if (this.isHorizontal()) {
|
||||
maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11, Math.ceil(this.width / 50));
|
||||
} else {
|
||||
// The factor of 2 used to scale the font size has been experimentally determined.
|
||||
var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11, Math.ceil(this.height / (2 * tickFontSize)));
|
||||
}
|
||||
|
||||
if (this.options.position == "left" || this.options.position == "right") {
|
||||
// Make sure we always have at least 2 ticks
|
||||
maxTicks = Math.max(2, maxTicks);
|
||||
|
||||
// To get a "nice" value for the tick spacing, we will use the appropriately named
|
||||
// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
|
||||
// for details.
|
||||
|
||||
var spacing;
|
||||
var fixedStepSizeSet = (this.options.ticks.fixedStepSize && this.options.ticks.fixedStepSize > 0) || (this.options.ticks.stepSize && this.options.ticks.stepSize > 0);
|
||||
if (fixedStepSizeSet) {
|
||||
spacing = helpers.getValueOrDefault(this.options.ticks.fixedStepSize, this.options.ticks.stepSize);
|
||||
} else {
|
||||
var niceRange = helpers.niceNum(this.max - this.min, false);
|
||||
spacing = helpers.niceNum(niceRange / (maxTicks - 1), true);
|
||||
}
|
||||
var niceMin = Math.floor(this.min / spacing) * spacing;
|
||||
var niceMax = Math.ceil(this.max / spacing) * spacing;
|
||||
var numSpaces = (niceMax - niceMin) / spacing;
|
||||
|
||||
// If very close to our rounded value, use it.
|
||||
if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
|
||||
numSpaces = Math.round(numSpaces);
|
||||
} else {
|
||||
numSpaces = Math.ceil(numSpaces);
|
||||
}
|
||||
|
||||
// Put the values into the ticks array
|
||||
this.ticks.push(this.options.ticks.min !== undefined ? this.options.ticks.min : niceMin);
|
||||
for (var j = 1; j < numSpaces; ++j) {
|
||||
this.ticks.push(niceMin + (j * spacing));
|
||||
}
|
||||
this.ticks.push(this.options.ticks.max !== undefined ? this.options.ticks.max : niceMax);
|
||||
|
||||
if (this.options.position === "left" || this.options.position === "right") {
|
||||
// We are in a vertical orientation. The top value is the highest. So reverse the array
|
||||
this.ticks.reverse();
|
||||
}
|
||||
@@ -200,24 +221,25 @@
|
||||
this.start = this.min;
|
||||
this.end = this.max;
|
||||
}
|
||||
|
||||
this.zeroLineIndex = this.ticks.indexOf(0);
|
||||
},
|
||||
|
||||
getLabelForIndex: function(index, datasetIndex) {
|
||||
return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
|
||||
},
|
||||
convertTicksToLabels: function() {
|
||||
this.ticksAsNumbers = this.ticks.slice();
|
||||
this.zeroLineIndex = this.ticks.indexOf(0);
|
||||
|
||||
Chart.Scale.prototype.convertTicksToLabels.call(this);
|
||||
},
|
||||
// Utils
|
||||
getPixelForValue: function(value, index, datasetIndex, includeOffset) {
|
||||
// This must be called after fit has been run so that
|
||||
// This must be called after fit has been run so that
|
||||
// this.left, this.top, this.right, and this.bottom have been defined
|
||||
var rightValue = +this.getRightValue(value);
|
||||
var pixel;
|
||||
var range = this.end - this.start;
|
||||
|
||||
if (this.isHorizontal()) {
|
||||
|
||||
var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
|
||||
pixel = this.left + (innerWidth / range * (rightValue - this.start));
|
||||
return Math.round(pixel + this.paddingLeft);
|
||||
@@ -227,7 +249,10 @@
|
||||
return Math.round(pixel);
|
||||
}
|
||||
},
|
||||
getPixelForTick: function(index, includeOffset) {
|
||||
return this.getPixelForValue(this.ticksAsNumbers[index], null, null, includeOffset);
|
||||
}
|
||||
});
|
||||
Chart.scaleService.registerScaleType("linear", LinearScale, defaultConfig);
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
@@ -1,19 +1,18 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
position: "left",
|
||||
|
||||
// label settings
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
callback: function(value, index, arr) {
|
||||
var remain = value / (Math.pow(10, Math.floor(Chart.helpers.log10(value))));
|
||||
|
||||
if (remain === 1 || remain === 2 || remain === 5) {
|
||||
if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === arr.length - 1) {
|
||||
return value.toExponential();
|
||||
} else {
|
||||
return '';
|
||||
@@ -23,10 +22,8 @@
|
||||
};
|
||||
|
||||
var LogarithmicScale = Chart.Scale.extend({
|
||||
buildTicks: function() {
|
||||
|
||||
// Calculate Range (we may break this out into it's own lifecycle function)
|
||||
|
||||
determineDataLimits: function() {
|
||||
// Calculate Range
|
||||
this.min = null;
|
||||
this.max = null;
|
||||
|
||||
@@ -90,6 +87,9 @@
|
||||
}, this);
|
||||
}
|
||||
|
||||
this.min = this.options.ticks.min !== undefined ? this.options.ticks.min : this.min;
|
||||
this.max = this.options.ticks.max !== undefined ? this.options.ticks.max : this.max;
|
||||
|
||||
if (this.min === this.max) {
|
||||
if (this.min !== 0 && this.min !== null) {
|
||||
this.min = Math.pow(10, Math.floor(helpers.log10(this.min)) - 1);
|
||||
@@ -99,40 +99,48 @@
|
||||
this.max = 10;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
buildTicks: function() {
|
||||
// Reset the ticks array. Later on, we will draw a grid line at these positions
|
||||
// The array simply contains the numerical value of the spots where ticks will be
|
||||
this.tickValues = [];
|
||||
this.ticks = [];
|
||||
|
||||
// Figure out what the max number of ticks we can support it is based on the size of
|
||||
// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
|
||||
// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
|
||||
// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
|
||||
// the graph
|
||||
|
||||
var minExponent = Math.floor(helpers.log10(this.min));
|
||||
var maxExponent = Math.ceil(helpers.log10(this.max));
|
||||
var tickVal = this.options.ticks.min !== undefined ? this.options.ticks.min : Math.pow(10, Math.floor(helpers.log10(this.min)));
|
||||
|
||||
for (var exponent = minExponent; exponent < maxExponent; ++exponent) {
|
||||
for (var i = 1; i < 10; ++i) {
|
||||
this.tickValues.push(i * Math.pow(10, exponent));
|
||||
while (tickVal < this.max) {
|
||||
this.ticks.push(tickVal);
|
||||
|
||||
var exp = Math.floor(helpers.log10(tickVal));
|
||||
var significand = Math.floor(tickVal / Math.pow(10, exp)) + 1;
|
||||
|
||||
if (significand === 10) {
|
||||
significand = 1;
|
||||
++exp;
|
||||
}
|
||||
|
||||
tickVal = significand * Math.pow(10, exp);
|
||||
}
|
||||
|
||||
this.tickValues.push(1.0 * Math.pow(10, maxExponent));
|
||||
var lastTick = this.options.ticks.max !== undefined ? this.options.ticks.max : tickVal;
|
||||
this.ticks.push(lastTick);
|
||||
|
||||
if (this.options.position == "left" || this.options.position == "right") {
|
||||
if (this.options.position === "left" || this.options.position === "right") {
|
||||
// We are in a vertical orientation. The top value is the highest. So reverse the array
|
||||
this.tickValues.reverse();
|
||||
this.ticks.reverse();
|
||||
}
|
||||
|
||||
// At this point, we need to update our max and min given the tick values since we have expanded the
|
||||
// range of the scale
|
||||
this.max = helpers.max(this.tickValues);
|
||||
this.min = helpers.min(this.tickValues);
|
||||
this.max = helpers.max(this.ticks);
|
||||
this.min = helpers.min(this.ticks);
|
||||
|
||||
if (this.options.ticks.reverse) {
|
||||
this.tickValues.reverse();
|
||||
this.ticks.reverse();
|
||||
|
||||
this.start = this.max;
|
||||
this.end = this.min;
|
||||
@@ -140,8 +148,11 @@
|
||||
this.start = this.min;
|
||||
this.end = this.max;
|
||||
}
|
||||
},
|
||||
convertTicksToLabels: function() {
|
||||
this.tickValues = this.ticks.slice();
|
||||
|
||||
this.ticks = this.tickValues.slice();
|
||||
Chart.Scale.prototype.convertTicksToLabels.call(this);
|
||||
},
|
||||
// Get the correct tooltip label
|
||||
getLabelForIndex: function(index, datasetIndex) {
|
||||
@@ -163,7 +174,7 @@
|
||||
} else {
|
||||
var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
|
||||
pixel = this.left + (innerWidth / range * (helpers.log10(newVal) - helpers.log10(this.start)));
|
||||
return pixel + this.paddingLeft;
|
||||
pixel += this.paddingLeft;
|
||||
}
|
||||
} else {
|
||||
// Bottom - top since pixels increase downard on a screen
|
||||
@@ -171,13 +182,14 @@
|
||||
pixel = this.top + this.paddingTop;
|
||||
} else {
|
||||
var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
|
||||
return (this.bottom - this.paddingBottom) - (innerHeight / range * (helpers.log10(newVal) - helpers.log10(this.start)));
|
||||
pixel = (this.bottom - this.paddingBottom) - (innerHeight / range * (helpers.log10(newVal) - helpers.log10(this.start)));
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
return pixel;
|
||||
}
|
||||
|
||||
});
|
||||
Chart.scaleService.registerScaleType("logarithmic", LogarithmicScale, defaultConfig);
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
@@ -1,9 +1,8 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
|
||||
var defaultConfig = {
|
||||
display: true,
|
||||
@@ -31,22 +30,18 @@
|
||||
backdropPaddingY: 2,
|
||||
|
||||
//Number - The backdrop padding to the side of the label in pixels
|
||||
backdropPaddingX: 2,
|
||||
backdropPaddingX: 2
|
||||
},
|
||||
|
||||
pointLabels: {
|
||||
//String - Point label font declaration
|
||||
fontFamily: "'Arial'",
|
||||
|
||||
//String - Point label font weight
|
||||
fontStyle: "normal",
|
||||
|
||||
//Number - Point label font size in pixels
|
||||
fontSize: 10,
|
||||
|
||||
//String - Point label font colour
|
||||
fontColor: "#666",
|
||||
},
|
||||
//Function - Used to convert point labels
|
||||
callback: function(label) {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var LinearRadialScale = Chart.Scale.extend({
|
||||
@@ -61,9 +56,10 @@
|
||||
this.yCenter = Math.round(this.height / 2);
|
||||
|
||||
var minSize = helpers.min([this.height, this.width]);
|
||||
this.drawingArea = (this.options.display) ? (minSize / 2) - (this.options.ticks.fontSize / 2 + this.options.ticks.backdropPaddingY) : (minSize / 2);
|
||||
var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
this.drawingArea = (this.options.display) ? (minSize / 2) - (tickFontSize / 2 + this.options.ticks.backdropPaddingY) : (minSize / 2);
|
||||
},
|
||||
buildTicks: function() {
|
||||
determineDataLimits: function() {
|
||||
this.min = null;
|
||||
this.max = null;
|
||||
|
||||
@@ -90,25 +86,6 @@
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (this.min === this.max) {
|
||||
this.min--;
|
||||
this.max++;
|
||||
}
|
||||
|
||||
this.ticks = [];
|
||||
|
||||
// Figure out what the max number of ticks we can support it is based on the size of
|
||||
// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
|
||||
// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
|
||||
// the graph
|
||||
var maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11,
|
||||
Math.ceil(this.drawingArea / (1.5 * this.options.ticks.fontSize)));
|
||||
maxTicks = Math.max(2, maxTicks); // Make sure we always have at least 2 ticks
|
||||
|
||||
// To get a "nice" value for the tick spacing, we will use the appropriately named
|
||||
// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
|
||||
// for details.
|
||||
|
||||
// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
|
||||
// do nothing since that would make the chart weird. If the user really wants a weird chart
|
||||
// axis, they can manually override it
|
||||
@@ -125,15 +102,53 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.ticks.min !== undefined) {
|
||||
this.min = this.options.ticks.min;
|
||||
} else if (this.options.ticks.suggestedMin !== undefined) {
|
||||
this.min = Math.min(this.min, this.options.ticks.suggestedMin);
|
||||
}
|
||||
|
||||
if (this.options.ticks.max !== undefined) {
|
||||
this.max = this.options.ticks.max;
|
||||
} else if (this.options.ticks.suggestedMax !== undefined) {
|
||||
this.max = Math.max(this.max, this.options.ticks.suggestedMax);
|
||||
}
|
||||
|
||||
if (this.min === this.max) {
|
||||
this.min--;
|
||||
this.max++;
|
||||
}
|
||||
},
|
||||
buildTicks: function() {
|
||||
|
||||
|
||||
this.ticks = [];
|
||||
|
||||
// Figure out what the max number of ticks we can support it is based on the size of
|
||||
// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
|
||||
// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
|
||||
// the graph
|
||||
var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize)));
|
||||
maxTicks = Math.max(2, maxTicks); // Make sure we always have at least 2 ticks
|
||||
|
||||
// To get a "nice" value for the tick spacing, we will use the appropriately named
|
||||
// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
|
||||
// for details.
|
||||
|
||||
var niceRange = helpers.niceNum(this.max - this.min, false);
|
||||
var spacing = helpers.niceNum(niceRange / (maxTicks - 1), true);
|
||||
var niceMin = Math.floor(this.min / spacing) * spacing;
|
||||
var niceMax = Math.ceil(this.max / spacing) * spacing;
|
||||
|
||||
var numSpaces = Math.ceil((niceMax - niceMin) / spacing);
|
||||
|
||||
// Put the values into the ticks array
|
||||
for (var j = niceMin; j <= niceMax; j += spacing) {
|
||||
this.ticks.push(j);
|
||||
this.ticks.push(this.options.ticks.min !== undefined ? this.options.ticks.min : niceMin);
|
||||
for (var j = 1; j < numSpaces; ++j) {
|
||||
this.ticks.push(niceMin + (j * spacing));
|
||||
}
|
||||
this.ticks.push(this.options.ticks.max !== undefined ? this.options.ticks.max : niceMax);
|
||||
|
||||
// At this point, we need to update our max and min given the tick values since we have expanded the
|
||||
// range of the scale
|
||||
@@ -152,12 +167,15 @@
|
||||
|
||||
this.zeroLineIndex = this.ticks.indexOf(0);
|
||||
},
|
||||
convertTicksToLabels: function() {
|
||||
Chart.Scale.prototype.convertTicksToLabels.call(this);
|
||||
|
||||
// Point labels
|
||||
this.pointLabels = this.chart.data.labels.map(this.options.pointLabels.callback, this);
|
||||
},
|
||||
getLabelForIndex: function(index, datasetIndex) {
|
||||
return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
|
||||
},
|
||||
getCircumference: function() {
|
||||
return ((Math.PI * 2) / this.getValueCount());
|
||||
},
|
||||
fit: function() {
|
||||
/*
|
||||
* Right, this is really confusing and there is a lot of maths going on here
|
||||
@@ -187,10 +205,14 @@
|
||||
* https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
|
||||
*/
|
||||
|
||||
var pointLabelFontSize = helpers.getValueOrDefault(this.options.pointLabels.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var pointLabeFontStyle = helpers.getValueOrDefault(this.options.pointLabels.fontStyle, Chart.defaults.global.defaultFontStyle);
|
||||
var pointLabeFontFamily = helpers.getValueOrDefault(this.options.pointLabels.fontFamily, Chart.defaults.global.defaultFontFamily);
|
||||
var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily);
|
||||
|
||||
// Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
|
||||
// Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
|
||||
var largestPossibleRadius = helpers.min([(this.height / 2 - this.options.pointLabels.fontSize - 5), this.width / 2]),
|
||||
var largestPossibleRadius = helpers.min([(this.height / 2 - pointLabelFontSize - 5), this.width / 2]),
|
||||
pointPosition,
|
||||
i,
|
||||
textWidth,
|
||||
@@ -206,11 +228,12 @@
|
||||
radiusReductionRight,
|
||||
radiusReductionLeft,
|
||||
maxWidthRadius;
|
||||
this.ctx.font = helpers.fontString(this.options.pointLabels.fontSize, this.options.pointLabels.fontStyle, this.options.pointLabels.fontFamily);
|
||||
this.ctx.font = pointLabeFont;
|
||||
|
||||
for (i = 0; i < this.getValueCount(); i++) {
|
||||
// 5px to space the text slightly out - similar to what we do in the draw function.
|
||||
pointPosition = this.getPointPosition(i, largestPossibleRadius);
|
||||
textWidth = this.ctx.measureText(this.options.ticks.callback(this.chart.data.labels[i])).width + 5;
|
||||
textWidth = this.ctx.measureText(this.pointLabels[i] ? this.pointLabels[i] : '').width + 5;
|
||||
if (i === 0 || i === this.getValueCount() / 2) {
|
||||
// If we're at index zero, or exactly the middle, we're at exactly the top/bottom
|
||||
// of the radar chart, so text will be aligned centrally, so we'll half it and compare
|
||||
@@ -273,9 +296,9 @@
|
||||
},
|
||||
getDistanceFromCenterForValue: function(value) {
|
||||
if (value === null) {
|
||||
return 0; // null always in center
|
||||
}
|
||||
|
||||
return 0; // null always in center
|
||||
}
|
||||
|
||||
// Take into account half font size + the yPadding of the top value
|
||||
var scalingFactor = this.drawingArea / (this.max - this.min);
|
||||
if (this.options.reverse) {
|
||||
@@ -331,22 +354,27 @@
|
||||
}
|
||||
|
||||
if (this.options.ticks.display) {
|
||||
ctx.font = helpers.fontString(this.options.ticks.fontSize, this.options.ticks.fontStyle, this.options.ticks.fontFamily);
|
||||
var tickFontColor = helpers.getValueOrDefault(this.options.ticks.fontColor, Chart.defaults.global.defaultFontColor);
|
||||
var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var tickFontStyle = helpers.getValueOrDefault(this.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle);
|
||||
var tickFontFamily = helpers.getValueOrDefault(this.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily);
|
||||
var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
|
||||
ctx.font = tickLabelFont;
|
||||
|
||||
if (this.options.ticks.showLabelBackdrop) {
|
||||
var labelWidth = ctx.measureText(label).width;
|
||||
ctx.fillStyle = this.options.ticks.backdropColor;
|
||||
ctx.fillRect(
|
||||
this.xCenter - labelWidth / 2 - this.options.ticks.backdropPaddingX,
|
||||
yHeight - this.options.ticks.fontSize / 2 - this.options.ticks.backdropPaddingY,
|
||||
yHeight - tickFontSize / 2 - this.options.ticks.backdropPaddingY,
|
||||
labelWidth + this.options.ticks.backdropPaddingX * 2,
|
||||
this.options.ticks.fontSize + this.options.ticks.backdropPaddingY * 2
|
||||
tickFontSize + this.options.ticks.backdropPaddingY * 2
|
||||
);
|
||||
}
|
||||
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillStyle = this.options.ticks.fontColor;
|
||||
ctx.fillStyle = tickFontColor;
|
||||
ctx.fillText(label, this.xCenter, yHeight);
|
||||
}
|
||||
}
|
||||
@@ -367,11 +395,18 @@
|
||||
}
|
||||
// Extra 3px out for some label spacing
|
||||
var pointLabelPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.options.reverse ? this.min : this.max) + 5);
|
||||
ctx.font = helpers.fontString(this.options.pointLabels.fontSize, this.options.pointLabels.fontStyle, this.options.pointLabels.fontFamily);
|
||||
ctx.fillStyle = this.options.pointLabels.fontColor;
|
||||
|
||||
var pointLabelFontColor = helpers.getValueOrDefault(this.options.pointLabels.fontColor, Chart.defaults.global.defaultFontColor);
|
||||
var pointLabelFontSize = helpers.getValueOrDefault(this.options.pointLabels.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var pointLabeFontStyle = helpers.getValueOrDefault(this.options.pointLabels.fontStyle, Chart.defaults.global.defaultFontStyle);
|
||||
var pointLabeFontFamily = helpers.getValueOrDefault(this.options.pointLabels.fontFamily, Chart.defaults.global.defaultFontFamily);
|
||||
var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily);
|
||||
|
||||
var labelsCount = this.chart.data.labels.length,
|
||||
halfLabelsCount = this.chart.data.labels.length / 2,
|
||||
ctx.font = pointLabeFont;
|
||||
ctx.fillStyle = pointLabelFontColor;
|
||||
|
||||
var labelsCount = this.pointLabels.length,
|
||||
halfLabelsCount = this.pointLabels.length / 2,
|
||||
quarterLabelsCount = halfLabelsCount / 2,
|
||||
upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount),
|
||||
exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount);
|
||||
@@ -394,7 +429,7 @@
|
||||
ctx.textBaseline = 'top';
|
||||
}
|
||||
|
||||
ctx.fillText(this.chart.data.labels[i], pointLabelPosition.x, pointLabelPosition.y);
|
||||
ctx.fillText(this.pointLabels[i] ? this.pointLabels[i] : '', pointLabelPosition.x, pointLabelPosition.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -402,5 +437,4 @@
|
||||
});
|
||||
Chart.scaleService.registerScaleType("radialLinear", LinearRadialScale, defaultConfig);
|
||||
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
+196
-87
@@ -1,41 +1,56 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
/*global window: false */
|
||||
"use strict";
|
||||
|
||||
if (!window.moment) {
|
||||
console.warn('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at http://momentjs.com/');
|
||||
return;
|
||||
}
|
||||
var moment = require('moment');
|
||||
moment = typeof(moment) === 'function' ? moment : window.moment;
|
||||
|
||||
var root = this,
|
||||
Chart = root.Chart,
|
||||
helpers = Chart.helpers;
|
||||
module.exports = function(Chart) {
|
||||
|
||||
var helpers = Chart.helpers;
|
||||
var time = {
|
||||
units: [
|
||||
'millisecond',
|
||||
'second',
|
||||
'minute',
|
||||
'hour',
|
||||
'day',
|
||||
'week',
|
||||
'month',
|
||||
'quarter',
|
||||
'year',
|
||||
],
|
||||
units: [{
|
||||
name: 'millisecond',
|
||||
steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
|
||||
}, {
|
||||
name: 'second',
|
||||
steps: [1, 2, 5, 10, 30]
|
||||
}, {
|
||||
name: 'minute',
|
||||
steps: [1, 2, 5, 10, 30]
|
||||
}, {
|
||||
name: 'hour',
|
||||
steps: [1, 2, 3, 6, 12]
|
||||
}, {
|
||||
name: 'day',
|
||||
steps: [1, 2, 5]
|
||||
}, {
|
||||
name: 'week',
|
||||
maxStep: 4
|
||||
}, {
|
||||
name: 'month',
|
||||
maxStep: 3
|
||||
}, {
|
||||
name: 'quarter',
|
||||
maxStep: 4
|
||||
}, {
|
||||
name: 'year',
|
||||
maxStep: false
|
||||
}]
|
||||
};
|
||||
|
||||
var defaultConfig = {
|
||||
position: "bottom",
|
||||
|
||||
time: {
|
||||
format: false, // false == date objects or use pattern string from http://momentjs.com/docs/#/parsing/string-format/
|
||||
parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
|
||||
format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
|
||||
unit: false, // false == automatic or override with week, month, year, etc.
|
||||
round: false, // none, or override with week, month, year, etc.
|
||||
displayFormat: false, // DEPRECATED
|
||||
|
||||
// defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
|
||||
displayFormats: {
|
||||
'millisecond': 'SSS [ms]',
|
||||
'millisecond': 'h:mm:ss.SSS a', // 11:20:01.123 AM,
|
||||
'second': 'h:mm:ss a', // 11:20:01 AM
|
||||
'minute': 'h:mm:ss a', // 11:20:01 AM
|
||||
'hour': 'MMM D, hA', // Sept 4, 5PM
|
||||
@@ -43,19 +58,30 @@
|
||||
'week': 'll', // Week 46, or maybe "[W]WW - YYYY" ?
|
||||
'month': 'MMM YYYY', // Sept 2015
|
||||
'quarter': '[Q]Q - YYYY', // Q3
|
||||
'year': 'YYYY', // 2015
|
||||
},
|
||||
'year': 'YYYY' // 2015
|
||||
}
|
||||
},
|
||||
ticks: {
|
||||
autoSkip: false,
|
||||
}
|
||||
};
|
||||
|
||||
var TimeScale = Chart.Scale.extend({
|
||||
initialize: function() {
|
||||
if (!moment) {
|
||||
throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com');
|
||||
}
|
||||
|
||||
Chart.Scale.prototype.initialize.call(this);
|
||||
},
|
||||
getLabelMoment: function(datasetIndex, index) {
|
||||
return this.labelMoments[datasetIndex][index];
|
||||
},
|
||||
determineDataLimits: function() {
|
||||
this.labelMoments = [];
|
||||
|
||||
buildLabelMoments: function() {
|
||||
// Only parse these once. If the dataset does not have data as x,y pairs, we will use
|
||||
// these
|
||||
// these
|
||||
var scaleLabelMoments = [];
|
||||
if (this.chart.data.labels && this.chart.data.labels.length > 0) {
|
||||
helpers.each(this.chart.data.labels, function(label, index) {
|
||||
@@ -66,17 +92,8 @@
|
||||
scaleLabelMoments.push(labelMoment);
|
||||
}, this);
|
||||
|
||||
if (this.options.time.min) {
|
||||
this.firstTick = this.parseTime(this.options.time.min);
|
||||
} else {
|
||||
this.firstTick = moment.min.call(this, scaleLabelMoments);
|
||||
}
|
||||
|
||||
if (this.options.time.max) {
|
||||
this.lastTick = this.parseTime(this.options.time.max);
|
||||
} else {
|
||||
this.lastTick = moment.max.call(this, scaleLabelMoments);
|
||||
}
|
||||
this.firstTick = moment.min.call(this, scaleLabelMoments);
|
||||
this.lastTick = moment.max.call(this, scaleLabelMoments);
|
||||
} else {
|
||||
this.firstTick = null;
|
||||
this.lastTick = null;
|
||||
@@ -105,48 +122,98 @@
|
||||
this.labelMoments.push(momentsForDataset);
|
||||
}, this);
|
||||
|
||||
// We will modify these, so clone for later
|
||||
this.firstTick = this.firstTick.clone();
|
||||
this.lastTick = this.lastTick.clone();
|
||||
},
|
||||
// Set these after we've done all the data
|
||||
if (this.options.time.min) {
|
||||
this.firstTick = this.parseTime(this.options.time.min);
|
||||
}
|
||||
|
||||
if (this.options.time.max) {
|
||||
this.lastTick = this.parseTime(this.options.time.max);
|
||||
}
|
||||
|
||||
// We will modify these, so clone for later
|
||||
this.firstTick = (this.firstTick || moment()).clone();
|
||||
this.lastTick = (this.lastTick || moment()).clone();
|
||||
},
|
||||
buildTicks: function(index) {
|
||||
|
||||
this.ticks = [];
|
||||
this.labelMoments = [];
|
||||
|
||||
this.buildLabelMoments();
|
||||
this.unitScale = 1; // How much we scale the unit by, ie 2 means 2x unit per step
|
||||
this.scaleSizeInUnits = 0; // How large the scale is in the base unit (seconds, minutes, etc)
|
||||
|
||||
// Set unit override if applicable
|
||||
if (this.options.time.unit) {
|
||||
this.tickUnit = this.options.time.unit || 'day';
|
||||
this.displayFormat = this.options.time.displayFormats[this.tickUnit];
|
||||
this.tickRange = Math.ceil(this.lastTick.diff(this.firstTick, this.tickUnit, true));
|
||||
this.scaleSizeInUnits = this.lastTick.diff(this.firstTick, this.tickUnit, true);
|
||||
this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, 1);
|
||||
} else {
|
||||
// Determine the smallest needed unit of the time
|
||||
var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
|
||||
var labelCapacity = innerWidth / this.options.ticks.fontSize + 4;
|
||||
var buffer = this.options.time.round ? 0 : 2;
|
||||
var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
|
||||
var innerWidth = this.isHorizontal() ? this.width - (this.paddingLeft + this.paddingRight) : this.height - (this.paddingTop + this.paddingBottom);
|
||||
|
||||
// Crude approximation of what the label length might be
|
||||
var tempFirstLabel = this.tickFormatFunction(this.firstTick, 0, []);
|
||||
var tickLabelWidth = tempFirstLabel.length * tickFontSize;
|
||||
var cosRotation = Math.cos(helpers.toRadians(this.options.ticks.maxRotation));
|
||||
var sinRotation = Math.sin(helpers.toRadians(this.options.ticks.maxRotation));
|
||||
tickLabelWidth = (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
|
||||
var labelCapacity = innerWidth / (tickLabelWidth + 10);
|
||||
|
||||
// Start as small as possible
|
||||
this.tickUnit = 'millisecond';
|
||||
this.tickRange = Math.ceil(this.lastTick.diff(this.firstTick, this.tickUnit, true) + buffer);
|
||||
this.scaleSizeInUnits = this.lastTick.diff(this.firstTick, this.tickUnit, true);
|
||||
this.displayFormat = this.options.time.displayFormats[this.tickUnit];
|
||||
|
||||
// Work our way up to comfort
|
||||
helpers.each(time.units, function(format) {
|
||||
if (this.tickRange <= labelCapacity) {
|
||||
return;
|
||||
}
|
||||
this.tickUnit = format;
|
||||
this.tickRange = Math.ceil(this.lastTick.diff(this.firstTick, this.tickUnit) + buffer);
|
||||
this.displayFormat = this.options.time.displayFormats[format];
|
||||
var unitDefinitionIndex = 0;
|
||||
var unitDefinition = time.units[unitDefinitionIndex];
|
||||
|
||||
}, this);
|
||||
// While we aren't ideal and we don't have units left
|
||||
while (unitDefinitionIndex < time.units.length) {
|
||||
// Can we scale this unit. If `false` we can scale infinitely
|
||||
this.unitScale = 1;
|
||||
|
||||
if (helpers.isArray(unitDefinition.steps) && Math.ceil(this.scaleSizeInUnits / labelCapacity) < helpers.max(unitDefinition.steps)) {
|
||||
// Use one of the prefedined steps
|
||||
for (var idx = 0; idx < unitDefinition.steps.length; ++idx) {
|
||||
if (unitDefinition.steps[idx] > Math.ceil(this.scaleSizeInUnits / labelCapacity)) {
|
||||
this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, unitDefinition.steps[idx]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
} else if ((unitDefinition.maxStep === false) || (Math.ceil(this.scaleSizeInUnits / labelCapacity) < unitDefinition.maxStep)) {
|
||||
// We have a max step. Scale this unit
|
||||
this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, Math.ceil(this.scaleSizeInUnits / labelCapacity));
|
||||
break;
|
||||
} else {
|
||||
// Move to the next unit up
|
||||
++unitDefinitionIndex;
|
||||
unitDefinition = time.units[unitDefinitionIndex];
|
||||
|
||||
this.tickUnit = unitDefinition.name;
|
||||
this.scaleSizeInUnits = this.lastTick.diff(this.firstTick, this.tickUnit, true);
|
||||
this.displayFormat = this.options.time.displayFormats[unitDefinition.name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var roundedStart;
|
||||
|
||||
// Only round the first tick if we have no hard minimum
|
||||
if (!this.options.time.min) {
|
||||
this.firstTick.startOf(this.tickUnit);
|
||||
roundedStart = this.firstTick;
|
||||
} else {
|
||||
roundedStart = this.firstTick.clone().startOf(this.tickUnit);
|
||||
}
|
||||
|
||||
// Only round the last tick if we have no hard maximum
|
||||
if (!this.options.time.max) {
|
||||
this.lastTick.endOf(this.tickUnit);
|
||||
}
|
||||
|
||||
this.firstTick.startOf(this.tickUnit);
|
||||
this.lastTick.endOf(this.tickUnit);
|
||||
this.smallestLabelSeparation = this.width;
|
||||
|
||||
helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) {
|
||||
@@ -160,9 +227,35 @@
|
||||
this.displayFormat = this.options.time.displayFormat;
|
||||
}
|
||||
|
||||
// first tick. will have been rounded correctly if options.time.min is not specified
|
||||
this.ticks.push(this.firstTick.clone());
|
||||
|
||||
// For every unit in between the first and last moment, create a moment and add it to the ticks tick
|
||||
for (var i = 0; i <= this.tickRange; ++i) {
|
||||
this.ticks.push(this.firstTick.clone().add(i, this.tickUnit));
|
||||
for (var i = 1; i < this.scaleSizeInUnits; ++i) {
|
||||
var newTick = roundedStart.clone().add(i, this.tickUnit);
|
||||
|
||||
// Are we greater than the max time
|
||||
if (this.options.time.max && newTick.diff(this.lastTick, this.tickUnit, true) >= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i % this.unitScale === 0) {
|
||||
this.ticks.push(newTick);
|
||||
}
|
||||
}
|
||||
|
||||
// Always show the right tick
|
||||
if (this.ticks[this.ticks.length - 1].diff(this.lastTick, this.tickUnit) !== 0 || this.scaleSizeInUnits === 0) {
|
||||
// this is a weird case. If the <max> option is the same as the end option, we can't just diff the times because the tick was created from the roundedStart
|
||||
// but the last tick was not rounded.
|
||||
if (this.options.time.max) {
|
||||
this.ticks.push(this.lastTick.clone());
|
||||
this.scaleSizeInUnits = this.lastTick.diff(this.ticks[0], this.tickUnit, true);
|
||||
} else {
|
||||
this.scaleSizeInUnits = Math.ceil(this.scaleSizeInUnits / this.unitScale) * this.unitScale;
|
||||
this.ticks.push(this.firstTick.clone().add(this.scaleSizeInUnits, this.tickUnit));
|
||||
this.lastTick = this.ticks[this.ticks.length - 1].clone();
|
||||
}
|
||||
}
|
||||
},
|
||||
// Get tooltip label
|
||||
@@ -173,43 +266,58 @@
|
||||
label = this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
|
||||
}
|
||||
|
||||
// Format nicely
|
||||
if (this.options.time.tooltipFormat) {
|
||||
label = this.parseTime(label).format(this.options.time.tooltipFormat);
|
||||
}
|
||||
|
||||
return label;
|
||||
},
|
||||
convertTicksToLabels: function() {
|
||||
this.ticks = this.ticks.map(function(tick, index, ticks) {
|
||||
var formattedTick = tick.format(this.options.time.displayFormat ? this.options.time.displayFormat : this.options.time.displayFormats[this.tickUnit]);
|
||||
// Function to format an individual tick mark
|
||||
tickFormatFunction: function tickFormatFunction(tick, index, ticks) {
|
||||
var formattedTick = tick.format(this.displayFormat);
|
||||
|
||||
if (this.options.ticks.userCallback) {
|
||||
return this.options.ticks.userCallback(formattedTick, index, ticks);
|
||||
} else {
|
||||
return formattedTick;
|
||||
}
|
||||
}, this);
|
||||
if (this.options.ticks.userCallback) {
|
||||
return this.options.ticks.userCallback(formattedTick, index, ticks);
|
||||
} else {
|
||||
return formattedTick;
|
||||
}
|
||||
},
|
||||
convertTicksToLabels: function() {
|
||||
this.ticks = this.ticks.map(this.tickFormatFunction, this);
|
||||
},
|
||||
getPixelForValue: function(value, index, datasetIndex, includeOffset) {
|
||||
var labelMoment = this.getLabelMoment(datasetIndex, index);
|
||||
var offset = labelMoment.diff(this.firstTick, this.tickUnit, true);
|
||||
|
||||
var decimal = offset / this.tickRange;
|
||||
if (labelMoment) {
|
||||
var offset = labelMoment.diff(this.firstTick, this.tickUnit, true);
|
||||
|
||||
if (this.isHorizontal()) {
|
||||
var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
|
||||
var valueWidth = innerWidth / Math.max(this.ticks.length - 1, 1);
|
||||
var valueOffset = (innerWidth * decimal) + this.paddingLeft;
|
||||
var decimal = offset / this.scaleSizeInUnits;
|
||||
|
||||
return this.left + Math.round(valueOffset);
|
||||
} else {
|
||||
//return this.top + (decimal * (this.height / this.ticks.length));
|
||||
var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
|
||||
var valueHeight = innerHeight / Math.max(this.ticks.length - 1, 1);
|
||||
var heightOffset = (innerHeight * decimal) + this.paddingTop;
|
||||
if (this.isHorizontal()) {
|
||||
var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
|
||||
var valueWidth = innerWidth / Math.max(this.ticks.length - 1, 1);
|
||||
var valueOffset = (innerWidth * decimal) + this.paddingLeft;
|
||||
|
||||
return this.top + Math.round(heightOffset);
|
||||
return this.left + Math.round(valueOffset);
|
||||
} else {
|
||||
var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
|
||||
var valueHeight = innerHeight / Math.max(this.ticks.length - 1, 1);
|
||||
var heightOffset = (innerHeight * decimal) + this.paddingTop;
|
||||
|
||||
return this.top + Math.round(heightOffset);
|
||||
}
|
||||
}
|
||||
},
|
||||
parseTime: function(label) {
|
||||
if (typeof this.options.time.parser === 'string') {
|
||||
return moment(label, this.options.time.parser);
|
||||
}
|
||||
if (typeof this.options.time.parser === 'function') {
|
||||
return this.options.time.parser(label);
|
||||
}
|
||||
// Date objects
|
||||
if (typeof label.getMonth === 'function' || typeof label == 'number') {
|
||||
if (typeof label.getMonth === 'function' || typeof label === 'number') {
|
||||
return moment(label);
|
||||
}
|
||||
// Moment support
|
||||
@@ -218,12 +326,13 @@
|
||||
}
|
||||
// Custom parsing (return an instance of moment)
|
||||
if (typeof this.options.time.format !== 'string' && this.options.time.format.call) {
|
||||
console.warn("options.time.format is deprecated and replaced by options.time.parser. See http://nnnick.github.io/Chart.js/docs-v2/#scales-time-scale");
|
||||
return this.options.time.format(label);
|
||||
}
|
||||
// Moment format parsing
|
||||
return moment(label, this.options.time.format);
|
||||
},
|
||||
}
|
||||
});
|
||||
Chart.scaleService.registerScaleType("time", TimeScale, defaultConfig);
|
||||
|
||||
}).call(this);
|
||||
};
|
||||
+286
-61
@@ -52,11 +52,10 @@ describe('Bar controller tests', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
type: 'line'
|
||||
}, {
|
||||
type: 'bar'
|
||||
bar: true
|
||||
}, {
|
||||
// no type, defaults to bar
|
||||
bar: true
|
||||
}]
|
||||
},
|
||||
config: {
|
||||
@@ -82,13 +81,13 @@ describe('Bar controller tests', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
|
||||
bar: true,
|
||||
}, {
|
||||
bar: true,
|
||||
hidden: true
|
||||
}, {
|
||||
type: 'line'
|
||||
}, {
|
||||
|
||||
bar: true,
|
||||
}]
|
||||
},
|
||||
config: {
|
||||
@@ -142,17 +141,74 @@ describe('Bar controller tests', function() {
|
||||
expect(chart.data.datasets[1].metaData[3] instanceof Chart.elements.Rectangle).toBe(true);
|
||||
});
|
||||
|
||||
it('should remove elements', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{}, {
|
||||
data: [10, 15, 0, -4]
|
||||
}]
|
||||
it('should update elements', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [1, 2],
|
||||
label: 'dataset1',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID',
|
||||
bar: true
|
||||
}, {
|
||||
data: [10, 15, 0, -4],
|
||||
label: 'dataset2'
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
|
||||
var yScale = new VerticalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: verticalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstYScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var verticalSize = yScale.update(50, 200);
|
||||
yScale.top = 0;
|
||||
yScale.left = 0;
|
||||
yScale.right = verticalSize.width;
|
||||
yScale.bottom = verticalSize.height;
|
||||
|
||||
var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
|
||||
var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
|
||||
horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
|
||||
var xScale = new HorizontalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: horizontalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstXScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var horizontalSize = xScale.update(200, 50);
|
||||
xScale.left = yScale.right;
|
||||
xScale.top = yScale.bottom;
|
||||
xScale.right = horizontalSize.width + xScale.left;
|
||||
xScale.bottom = horizontalSize.height + xScale.top;
|
||||
|
||||
var chart = {
|
||||
data: data,
|
||||
config: {
|
||||
type: 'bar'
|
||||
},
|
||||
options: {
|
||||
elements: {
|
||||
rectangle: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderSkipped: 'top',
|
||||
borderColor: 'rgb(0, 0, 255)',
|
||||
borderWidth: 2,
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
@@ -161,26 +217,88 @@ describe('Bar controller tests', function() {
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
firstXScaleID: xScale,
|
||||
firstYScaleID: yScale,
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.bar(chart, 1);
|
||||
controller.removeElement(1);
|
||||
expect(chart.data.datasets[1].metaData.length).toBe(3);
|
||||
|
||||
chart.data.datasets[1].data = [1, 2]; // remove 2 items
|
||||
controller.buildOrUpdateElements();
|
||||
controller.update();
|
||||
|
||||
expect(chart.data.datasets[1].metaData.length).toBe(2);
|
||||
|
||||
var bar1 = chart.data.datasets[1].metaData[0];
|
||||
var bar2 = chart.data.datasets[1].metaData[1];
|
||||
|
||||
expect(bar1._datasetIndex).toBe(1);
|
||||
expect(bar1._index).toBe(0);
|
||||
expect(bar1._xScale).toBe(chart.scales.firstXScaleID);
|
||||
expect(bar1._yScale).toBe(chart.scales.firstYScaleID);
|
||||
expect(bar1._model).toEqual({
|
||||
x: 113.60000000000001,
|
||||
y: 194,
|
||||
label: 'label1',
|
||||
datasetLabel: 'dataset2',
|
||||
|
||||
base: 194,
|
||||
width: 13.680000000000001,
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderSkipped: 'top',
|
||||
borderColor: 'rgb(0, 0, 255)',
|
||||
borderWidth: 2,
|
||||
});
|
||||
|
||||
expect(bar2._datasetIndex).toBe(1);
|
||||
expect(bar2._index).toBe(1);
|
||||
expect(bar2._xScale).toBe(chart.scales.firstXScaleID);
|
||||
expect(bar2._yScale).toBe(chart.scales.firstYScaleID);
|
||||
expect(bar2._model).toEqual({
|
||||
x: 151.60000000000002,
|
||||
y: 6,
|
||||
label: 'label2',
|
||||
datasetLabel: 'dataset2',
|
||||
|
||||
base: 194,
|
||||
width: 13.680000000000001,
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderSkipped: 'top',
|
||||
borderColor: 'rgb(0, 0, 255)',
|
||||
borderWidth: 2,
|
||||
});
|
||||
|
||||
chart.data.datasets[1].data = [1, 2, 3];
|
||||
controller.buildOrUpdateElements();
|
||||
controller.update();
|
||||
|
||||
expect(chart.data.datasets[1].metaData.length).toBe(3); // should add a new meta data item
|
||||
});
|
||||
|
||||
it('should update elements', function() {
|
||||
it ('should get the correct bar points when datasets of different types exist', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [1, 2],
|
||||
label: 'dataset1',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID'
|
||||
yAxisID: 'firstYScaleID',
|
||||
bar: true,
|
||||
}, {
|
||||
data: [10, 15, 0, -4],
|
||||
label: 'dataset2'
|
||||
data: [10, 15],
|
||||
label: 'dataset2',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID',
|
||||
}, {
|
||||
data: [30, 25],
|
||||
label: 'dataset3',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID',
|
||||
bar: true
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
labels: ['label1', 'label2']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
@@ -250,56 +368,163 @@ describe('Bar controller tests', function() {
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.bar(chart, 1);
|
||||
|
||||
chart.data.datasets[1].data = [1, 2]; // remove 2 items
|
||||
var controller = new Chart.controllers.bar(chart, 2);
|
||||
controller.buildOrUpdateElements();
|
||||
controller.update();
|
||||
|
||||
expect(chart.data.datasets[1].metaData.length).toBe(2);
|
||||
|
||||
var bar1 = chart.data.datasets[1].metaData[0];
|
||||
var bar2 = chart.data.datasets[1].metaData[1];
|
||||
var bar1 = chart.data.datasets[2].metaData[0];
|
||||
var bar2 = chart.data.datasets[2].metaData[1];
|
||||
|
||||
expect(bar1._datasetIndex).toBe(1);
|
||||
expect(bar1._index).toBe(0);
|
||||
expect(bar1._xScale).toBe(chart.scales.firstXScaleID);
|
||||
expect(bar1._yScale).toBe(chart.scales.firstYScaleID);
|
||||
expect(bar1._model).toEqual({
|
||||
x: 113.60000000000001,
|
||||
y: 194,
|
||||
label: 'label1',
|
||||
datasetLabel: 'dataset2',
|
||||
expect(bar1._model.x).toBe(119.9);
|
||||
expect(bar1._model.y).toBe(6);
|
||||
expect(bar2._model.x).toBe(186.9);
|
||||
expect(bar2._model.y).toBe(37);
|
||||
});
|
||||
|
||||
base: 194,
|
||||
width: 13.680000000000001,
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 0, 255)',
|
||||
borderWidth: 2,
|
||||
it('should update elements when the scales are stacked', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [10, -10, 10, -10],
|
||||
label: 'dataset1',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID',
|
||||
bar: true
|
||||
}, {
|
||||
data: [10, 15, 0, -4],
|
||||
label: 'dataset2',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID',
|
||||
bar: true
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bar.scales.yAxes[0]);
|
||||
verticalScaleConfig.stacked = true;
|
||||
var yScale = new VerticalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: verticalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstYScaleID'
|
||||
});
|
||||
|
||||
expect(bar2._datasetIndex).toBe(1);
|
||||
expect(bar2._index).toBe(1);
|
||||
expect(bar2._xScale).toBe(chart.scales.firstXScaleID);
|
||||
expect(bar2._yScale).toBe(chart.scales.firstYScaleID);
|
||||
expect(bar2._model).toEqual({
|
||||
x: 151.60000000000002,
|
||||
// Update ticks & set physical dimensions
|
||||
var verticalSize = yScale.update(50, 200);
|
||||
yScale.top = 0;
|
||||
yScale.left = 0;
|
||||
yScale.right = verticalSize.width;
|
||||
yScale.bottom = verticalSize.height;
|
||||
|
||||
var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
|
||||
var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
|
||||
horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bar.scales.xAxes[0]);
|
||||
horizontalScaleConfig.stacked = true;
|
||||
var xScale = new HorizontalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: horizontalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstXScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var horizontalSize = xScale.update(200, 50);
|
||||
xScale.left = yScale.right;
|
||||
xScale.top = yScale.bottom;
|
||||
xScale.right = horizontalSize.width + xScale.left;
|
||||
xScale.bottom = horizontalSize.height + xScale.top;
|
||||
|
||||
var chart = {
|
||||
data: data,
|
||||
config: {
|
||||
type: 'bar'
|
||||
},
|
||||
options: {
|
||||
elements: {
|
||||
rectangle: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 0, 255)',
|
||||
borderWidth: 2,
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
firstXScaleID: xScale,
|
||||
firstYScaleID: yScale,
|
||||
}
|
||||
};
|
||||
|
||||
var controller0 = new Chart.controllers.bar(chart, 0);
|
||||
var controller1 = new Chart.controllers.bar(chart, 1);
|
||||
|
||||
controller0.buildOrUpdateElements();
|
||||
controller0.update();
|
||||
controller1.buildOrUpdateElements();
|
||||
controller1.update();
|
||||
|
||||
expect(chart.data.datasets[0].metaData[0]._model).toEqual(jasmine.objectContaining({
|
||||
x: 106,
|
||||
y: 60,
|
||||
base: 113,
|
||||
width: 30.400000000000002
|
||||
}));
|
||||
expect(chart.data.datasets[0].metaData[1]._model).toEqual(jasmine.objectContaining({
|
||||
x: 144,
|
||||
y: 167,
|
||||
base: 113,
|
||||
width: 30.400000000000002
|
||||
}));
|
||||
expect(chart.data.datasets[0].metaData[2]._model).toEqual(jasmine.objectContaining({
|
||||
x: 183,
|
||||
y: 60,
|
||||
base: 113,
|
||||
width: 30.400000000000002
|
||||
}));
|
||||
expect(chart.data.datasets[0].metaData[3]._model).toEqual(jasmine.objectContaining({
|
||||
x: 222,
|
||||
y: 167,
|
||||
base: 113,
|
||||
width: 30.400000000000002
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[1].metaData[0]._model).toEqual(jasmine.objectContaining({
|
||||
x: 106,
|
||||
y: 6,
|
||||
label: 'label2',
|
||||
datasetLabel: 'dataset2',
|
||||
|
||||
base: 194,
|
||||
width: 13.680000000000001,
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 0, 255)',
|
||||
borderWidth: 2,
|
||||
});
|
||||
|
||||
chart.data.datasets[1].data = [1, 2, 3];
|
||||
controller.buildOrUpdateElements();
|
||||
controller.update();
|
||||
|
||||
expect(chart.data.datasets[1].metaData.length).toBe(3); // should add a new meta data item
|
||||
base: 60,
|
||||
width: 30.400000000000002
|
||||
}));
|
||||
expect(chart.data.datasets[1].metaData[1]._model).toEqual(jasmine.objectContaining({
|
||||
x: 144,
|
||||
y: 33,
|
||||
base: 113,
|
||||
width: 30.400000000000002
|
||||
}));
|
||||
expect(chart.data.datasets[1].metaData[2]._model).toEqual(jasmine.objectContaining({
|
||||
x: 183,
|
||||
y: 60,
|
||||
base: 60,
|
||||
width: 30.400000000000002
|
||||
}));
|
||||
expect(chart.data.datasets[1].metaData[3]._model).toEqual(jasmine.objectContaining({
|
||||
x: 222,
|
||||
y: 189,
|
||||
base: 167,
|
||||
width: 30.400000000000002
|
||||
}));
|
||||
});
|
||||
|
||||
it ('should draw all bars', function() {
|
||||
|
||||
@@ -0,0 +1,836 @@
|
||||
// Test the bubble controller
|
||||
describe('Bubble controller tests', function() {
|
||||
it('Should be constructed', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
xAxisID: 'myXAxis',
|
||||
yAxisID: 'myYAxis',
|
||||
data: []
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.bubble(chart, 0);
|
||||
expect(controller).not.toBe(undefined);
|
||||
expect(controller.index).toBe(0);
|
||||
expect(chart.data.datasets[0].metaData).toEqual([]);
|
||||
|
||||
controller.updateIndex(1);
|
||||
expect(controller.index).toBe(1);
|
||||
});
|
||||
|
||||
it('Should use the first scale IDs if the dataset does not specify them', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: []
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.bubble(chart, 0);
|
||||
expect(chart.data.datasets[0].xAxisID).toBe('firstXScaleID');
|
||||
expect(chart.data.datasets[0].yAxisID).toBe('firstYScaleID');
|
||||
});
|
||||
|
||||
it('Should create point elements for each data item during initialization', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4]
|
||||
}]
|
||||
},
|
||||
config: {
|
||||
type: 'bubble'
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.bubble(chart, 0);
|
||||
|
||||
expect(chart.data.datasets[0].metaData.length).toBe(4); // 4 points created
|
||||
expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[2] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[3] instanceof Chart.elements.Point).toBe(true);
|
||||
});
|
||||
|
||||
it('should draw all elements', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4]
|
||||
}]
|
||||
},
|
||||
config: {
|
||||
type: 'bubble'
|
||||
},
|
||||
options: {
|
||||
showLines: true,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.bubble(chart, 0);
|
||||
|
||||
spyOn(chart.data.datasets[0].metaData[0], 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[1], 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[2], 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[3], 'draw');
|
||||
|
||||
controller.draw();
|
||||
|
||||
expect(chart.data.datasets[0].metaData[0].draw.calls.count()).toBe(1);
|
||||
expect(chart.data.datasets[0].metaData[1].draw.calls.count()).toBe(1);
|
||||
expect(chart.data.datasets[0].metaData[2].draw.calls.count()).toBe(1);
|
||||
expect(chart.data.datasets[0].metaData[3].draw.calls.count()).toBe(1);
|
||||
});
|
||||
|
||||
it('should update elements', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [{
|
||||
x: 10,
|
||||
y: 10,
|
||||
r: 5
|
||||
}, {
|
||||
x: -15,
|
||||
y: -10,
|
||||
r: 1
|
||||
}, {
|
||||
x: 0,
|
||||
y: -9,
|
||||
r: 2
|
||||
}, {
|
||||
x: -4,
|
||||
y: 10,
|
||||
r: 1
|
||||
}],
|
||||
label: 'dataset2',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID'
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bubble.scales.yAxes[0]);
|
||||
var yScale = new VerticalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: verticalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstYScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var verticalSize = yScale.update(50, 200);
|
||||
yScale.top = 0;
|
||||
yScale.left = 0;
|
||||
yScale.right = verticalSize.width;
|
||||
yScale.bottom = verticalSize.height;
|
||||
|
||||
var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bubble.scales.xAxes[0]);
|
||||
horizontalScaleConfig.position = 'bottom';
|
||||
var xScale = new HorizontalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: horizontalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstXScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var horizontalSize = xScale.update(200, 50);
|
||||
xScale.left = yScale.right;
|
||||
xScale.top = yScale.bottom;
|
||||
xScale.right = horizontalSize.width + xScale.left;
|
||||
xScale.bottom = horizontalSize.height + xScale.top;
|
||||
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 200,
|
||||
left: xScale.left,
|
||||
right: xScale.left + 200,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'bubble'
|
||||
},
|
||||
options: {
|
||||
showLines: true,
|
||||
elements: {
|
||||
line: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderCapStyle: 'round',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.1,
|
||||
borderJoinStyle: 'bevel',
|
||||
borderWidth: 1.2,
|
||||
fill: true,
|
||||
tension: 0.1,
|
||||
},
|
||||
point: {
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
hoverRadius: 4,
|
||||
hoverBorderWidth: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle'
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
firstXScaleID: xScale,
|
||||
firstYScaleID: yScale,
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.bubble(chart, 0);
|
||||
controller.update();
|
||||
|
||||
expect(chart.data.datasets[0].metaData[0]._model).toEqual({
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 5,
|
||||
skip: false,
|
||||
|
||||
// Point
|
||||
x: 195,
|
||||
y: 6,
|
||||
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[1]._model).toEqual({
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 1,
|
||||
skip: false,
|
||||
|
||||
// Point
|
||||
x: 89,
|
||||
y: 194,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[2]._model).toEqual({
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 2,
|
||||
skip: false,
|
||||
|
||||
// Point
|
||||
x: 153,
|
||||
y: 185,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[3]._model).toEqual({
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 1,
|
||||
skip: false,
|
||||
|
||||
// Point
|
||||
x: 136,
|
||||
y: 6,
|
||||
});
|
||||
|
||||
// Use dataset level styles for lines & points
|
||||
chart.data.datasets[0].backgroundColor = 'rgb(98, 98, 98)';
|
||||
chart.data.datasets[0].borderColor = 'rgb(8, 8, 8)';
|
||||
chart.data.datasets[0].borderWidth = 0.55;
|
||||
|
||||
// point styles
|
||||
chart.data.datasets[0].radius = 22;
|
||||
chart.data.datasets[0].hitRadius = 3.3;
|
||||
|
||||
controller.update();
|
||||
|
||||
expect(chart.data.datasets[0].metaData[0]._model).toEqual({
|
||||
backgroundColor: 'rgb(98, 98, 98)',
|
||||
borderWidth: 0.55,
|
||||
borderColor: 'rgb(8, 8, 8)',
|
||||
hitRadius: 3.3,
|
||||
radius: 5,
|
||||
skip: false,
|
||||
|
||||
// Point
|
||||
x: 195,
|
||||
y: 6,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[1]._model).toEqual({
|
||||
backgroundColor: 'rgb(98, 98, 98)',
|
||||
borderWidth: 0.55,
|
||||
borderColor: 'rgb(8, 8, 8)',
|
||||
hitRadius: 3.3,
|
||||
radius: 1,
|
||||
skip: false,
|
||||
|
||||
// Point
|
||||
x: 89,
|
||||
y: 194,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[2]._model).toEqual({
|
||||
backgroundColor: 'rgb(98, 98, 98)',
|
||||
borderWidth: 0.55,
|
||||
borderColor: 'rgb(8, 8, 8)',
|
||||
hitRadius: 3.3,
|
||||
radius: 2,
|
||||
skip: false,
|
||||
|
||||
// Point
|
||||
x: 153,
|
||||
y: 185,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[3]._model).toEqual({
|
||||
backgroundColor: 'rgb(98, 98, 98)',
|
||||
borderWidth: 0.55,
|
||||
borderColor: 'rgb(8, 8, 8)',
|
||||
hitRadius: 3.3,
|
||||
radius: 1,
|
||||
skip: false,
|
||||
|
||||
// Point
|
||||
x: 136,
|
||||
y: 6,
|
||||
});
|
||||
|
||||
// point styles
|
||||
chart.data.datasets[0].metaData[0].custom = {
|
||||
radius: 2.2,
|
||||
backgroundColor: 'rgb(0, 1, 3)',
|
||||
borderColor: 'rgb(4, 6, 8)',
|
||||
borderWidth: 0.787,
|
||||
tension: 0.15,
|
||||
skip: true,
|
||||
hitRadius: 5,
|
||||
};
|
||||
|
||||
controller.update();
|
||||
|
||||
expect(chart.data.datasets[0].metaData[0]._model).toEqual({
|
||||
backgroundColor: 'rgb(0, 1, 3)',
|
||||
borderWidth: 0.787,
|
||||
borderColor: 'rgb(4, 6, 8)',
|
||||
hitRadius: 5,
|
||||
radius: 2.2,
|
||||
skip: true,
|
||||
|
||||
// Point
|
||||
x: 195,
|
||||
y: 6,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle number of data point changes in update', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [{
|
||||
x: 10,
|
||||
y: 10,
|
||||
r: 5
|
||||
}, {
|
||||
x: -15,
|
||||
y: -10,
|
||||
r: 1
|
||||
}, {
|
||||
x: 0,
|
||||
y: -9,
|
||||
r: 2
|
||||
}, {
|
||||
x: -4,
|
||||
y: 10,
|
||||
r: 1
|
||||
}],
|
||||
label: 'dataset2',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID'
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bubble.scales.yAxes[0]);
|
||||
var yScale = new VerticalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: verticalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstYScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var verticalSize = yScale.update(50, 200);
|
||||
yScale.top = 0;
|
||||
yScale.left = 0;
|
||||
yScale.right = verticalSize.width;
|
||||
yScale.bottom = verticalSize.height;
|
||||
|
||||
var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bubble.scales.xAxes[0]);
|
||||
var xScale = new HorizontalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: horizontalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstXScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var horizontalSize = xScale.update(200, 50);
|
||||
xScale.left = yScale.right;
|
||||
xScale.top = yScale.bottom;
|
||||
xScale.right = horizontalSize.width + xScale.left;
|
||||
xScale.bottom = horizontalSize.height + xScale.top;
|
||||
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 200,
|
||||
left: xScale.left,
|
||||
right: 200,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
elements: {
|
||||
line: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderWidth: 1.2,
|
||||
},
|
||||
point: {
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
hoverRadius: 4,
|
||||
hoverBorderWidth: 1,
|
||||
radius: 3,
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
firstXScaleID: xScale,
|
||||
firstYScaleID: yScale,
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.bubble(chart, 0);
|
||||
chart.data.datasets[0].data = [{
|
||||
x: 1,
|
||||
y: 1,
|
||||
r: 10
|
||||
}, {
|
||||
x: 10,
|
||||
y: 5,
|
||||
r: 2
|
||||
}]; // remove 2 items
|
||||
controller.buildOrUpdateElements();
|
||||
controller.update();
|
||||
expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Point).toBe(true);
|
||||
|
||||
chart.data.datasets[0].data = [{
|
||||
x: 10,
|
||||
y: 10,
|
||||
r: 5
|
||||
}, {
|
||||
x: -15,
|
||||
y: -10,
|
||||
r: 1
|
||||
}, {
|
||||
x: 0,
|
||||
y: -9,
|
||||
r: 2
|
||||
}, {
|
||||
x: -4,
|
||||
y: 10,
|
||||
r: 1
|
||||
}, {
|
||||
x: -5,
|
||||
y: 0,
|
||||
r: 3
|
||||
}]; // add 3 items
|
||||
controller.buildOrUpdateElements();
|
||||
controller.update();
|
||||
expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[2] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[3] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[4] instanceof Chart.elements.Point).toBe(true);
|
||||
});
|
||||
|
||||
it('should set hover styles', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [{
|
||||
x: 10,
|
||||
y: 10,
|
||||
r: 5
|
||||
}, {
|
||||
x: -15,
|
||||
y: -10,
|
||||
r: 1
|
||||
}, {
|
||||
x: 0,
|
||||
y: -9,
|
||||
r: 2
|
||||
}, {
|
||||
x: -4,
|
||||
y: 10,
|
||||
r: 1
|
||||
}],
|
||||
label: 'dataset2',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID'
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bubble.scales.yAxes[0]);
|
||||
var yScale = new VerticalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: verticalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstYScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var verticalSize = yScale.update(50, 200);
|
||||
yScale.top = 0;
|
||||
yScale.left = 0;
|
||||
yScale.right = verticalSize.width;
|
||||
yScale.bottom = verticalSize.height;
|
||||
|
||||
var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bubble.scales.xAxes[0]);
|
||||
var xScale = new HorizontalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: horizontalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstXScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var horizontalSize = xScale.update(200, 50);
|
||||
xScale.left = yScale.right;
|
||||
xScale.top = yScale.bottom;
|
||||
xScale.right = horizontalSize.width + xScale.left;
|
||||
xScale.bottom = horizontalSize.height + xScale.top;
|
||||
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 200,
|
||||
left: xScale.left,
|
||||
right: 200,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
elements: {
|
||||
line: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderWidth: 1.2,
|
||||
},
|
||||
point: {
|
||||
backgroundColor: 'rgb(255, 255, 0)',
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgb(255, 255, 255)',
|
||||
hitRadius: 1,
|
||||
hoverRadius: 4,
|
||||
hoverBorderWidth: 1,
|
||||
radius: 3,
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
firstXScaleID: xScale,
|
||||
firstYScaleID: yScale,
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.bubble(chart, 0);
|
||||
controller.update();
|
||||
var point = chart.data.datasets[0].metaData[0];
|
||||
|
||||
controller.setHoverStyle(point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(229, 230, 0)');
|
||||
expect(point._model.borderColor).toBe('rgb(230, 230, 230)');
|
||||
expect(point._model.borderWidth).toBe(1);
|
||||
expect(point._model.radius).toBe(9);
|
||||
|
||||
// Can set hover style per dataset
|
||||
chart.data.datasets[0].hoverRadius = 3.3;
|
||||
chart.data.datasets[0].hoverBackgroundColor = 'rgb(77, 79, 81)';
|
||||
chart.data.datasets[0].hoverBorderColor = 'rgb(123, 125, 127)';
|
||||
chart.data.datasets[0].hoverBorderWidth = 2.1;
|
||||
|
||||
controller.setHoverStyle(point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(77, 79, 81)');
|
||||
expect(point._model.borderColor).toBe('rgb(123, 125, 127)');
|
||||
expect(point._model.borderWidth).toBe(2.1);
|
||||
expect(point._model.radius).toBe(8.3);
|
||||
|
||||
// Custom style
|
||||
point.custom = {
|
||||
hoverRadius: 4.4,
|
||||
hoverBorderWidth: 5.5,
|
||||
hoverBackgroundColor: 'rgb(0, 0, 0)',
|
||||
hoverBorderColor: 'rgb(10, 10, 10)'
|
||||
};
|
||||
|
||||
controller.setHoverStyle(point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(0, 0, 0)');
|
||||
expect(point._model.borderColor).toBe('rgb(10, 10, 10)');
|
||||
expect(point._model.borderWidth).toBe(5.5);
|
||||
expect(point._model.radius).toBe(4.4);
|
||||
});
|
||||
|
||||
it('should remove hover styles', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [{
|
||||
x: 10,
|
||||
y: 10,
|
||||
r: 5
|
||||
}, {
|
||||
x: -15,
|
||||
y: -10,
|
||||
r: 1
|
||||
}, {
|
||||
x: 0,
|
||||
y: -9,
|
||||
r: 2
|
||||
}, {
|
||||
x: -4,
|
||||
y: 10,
|
||||
r: 1
|
||||
}],
|
||||
label: 'dataset2',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID'
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.bubble.scales.yAxes[0]);
|
||||
var yScale = new VerticalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: verticalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstYScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var verticalSize = yScale.update(50, 200);
|
||||
yScale.top = 0;
|
||||
yScale.left = 0;
|
||||
yScale.right = verticalSize.width;
|
||||
yScale.bottom = verticalSize.height;
|
||||
|
||||
var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.bubble.scales.xAxes[0]);
|
||||
var xScale = new HorizontalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: horizontalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstXScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var horizontalSize = xScale.update(200, 50);
|
||||
xScale.left = yScale.right;
|
||||
xScale.top = yScale.bottom;
|
||||
xScale.right = horizontalSize.width + xScale.left;
|
||||
xScale.bottom = horizontalSize.height + xScale.top;
|
||||
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 200,
|
||||
left: xScale.left,
|
||||
right: 200,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
elements: {
|
||||
line: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderWidth: 1.2,
|
||||
fill: true,
|
||||
tension: 0.1,
|
||||
},
|
||||
point: {
|
||||
backgroundColor: 'rgb(255, 255, 0)',
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgb(255, 255, 255)',
|
||||
hitRadius: 1,
|
||||
hoverRadius: 4,
|
||||
hoverBorderWidth: 1,
|
||||
radius: 3,
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
firstXScaleID: xScale,
|
||||
firstYScaleID: yScale,
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.bubble(chart, 0);
|
||||
controller.update();
|
||||
var point = chart.data.datasets[0].metaData[0];
|
||||
|
||||
chart.options.elements.point.backgroundColor = 'rgb(45, 46, 47)';
|
||||
chart.options.elements.point.borderColor = 'rgb(50, 51, 52)';
|
||||
chart.options.elements.point.borderWidth = 10.1;
|
||||
chart.options.elements.point.radius = 1.01;
|
||||
|
||||
controller.removeHoverStyle(point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(45, 46, 47)');
|
||||
expect(point._model.borderColor).toBe('rgb(50, 51, 52)');
|
||||
expect(point._model.borderWidth).toBe(10.1);
|
||||
expect(point._model.radius).toBe(5);
|
||||
|
||||
// Can set hover style per dataset
|
||||
chart.data.datasets[0].radius = 3.3;
|
||||
chart.data.datasets[0].backgroundColor = 'rgb(77, 79, 81)';
|
||||
chart.data.datasets[0].borderColor = 'rgb(123, 125, 127)';
|
||||
chart.data.datasets[0].borderWidth = 2.1;
|
||||
|
||||
controller.removeHoverStyle(point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(77, 79, 81)');
|
||||
expect(point._model.borderColor).toBe('rgb(123, 125, 127)');
|
||||
expect(point._model.borderWidth).toBe(2.1);
|
||||
expect(point._model.radius).toBe(5);
|
||||
|
||||
// Custom style
|
||||
point.custom = {
|
||||
radius: 4.4,
|
||||
borderWidth: 5.5,
|
||||
backgroundColor: 'rgb(0, 0, 0)',
|
||||
borderColor: 'rgb(10, 10, 10)'
|
||||
};
|
||||
|
||||
controller.removeHoverStyle(point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(0, 0, 0)');
|
||||
expect(point._model.borderColor).toBe('rgb(10, 10, 10)');
|
||||
expect(point._model.borderWidth).toBe(5.5);
|
||||
expect(point._model.radius).toBe(4.4);
|
||||
});
|
||||
});
|
||||
@@ -41,30 +41,13 @@ describe('Doughnut controller tests', function() {
|
||||
expect(chart.data.datasets[0].metaData[3] instanceof Chart.elements.Arc).toBe(true);
|
||||
});
|
||||
|
||||
it ('Should remove elements', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, 4]
|
||||
}]
|
||||
},
|
||||
config: {
|
||||
type: 'doughnut'
|
||||
},
|
||||
options: {
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.doughnut(chart, 0);
|
||||
controller.removeElement(1);
|
||||
expect(chart.data.datasets[0].metaData.length).toBe(3);
|
||||
});
|
||||
|
||||
it ('Should reset and update elements', function() {
|
||||
var chart = {
|
||||
chart: {
|
||||
width: 100,
|
||||
height: 200,
|
||||
chartArea: {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: 100,
|
||||
bottom: 200,
|
||||
},
|
||||
data: {
|
||||
datasets: [{
|
||||
@@ -99,45 +82,49 @@ describe('Doughnut controller tests', function() {
|
||||
var controller = new Chart.controllers.doughnut(chart, 1);
|
||||
controller.reset(); // reset first
|
||||
|
||||
expect(chart.data.datasets[1].metaData[0]._model).toEqual({
|
||||
expect(chart.data.datasets[1].metaData[0]._model).toEqual(jasmine.objectContaining({
|
||||
x: 50,
|
||||
y: 100,
|
||||
startAngle: Math.PI * -0.5,
|
||||
endAngle: Math.PI * -0.5,
|
||||
circumference: 2.166614539857563,
|
||||
outerRadius: 49,
|
||||
innerRadius: 36.75,
|
||||
});
|
||||
innerRadius: 36.75
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[1].metaData[1]._model).toEqual({
|
||||
expect(chart.data.datasets[1].metaData[1]._model).toEqual(jasmine.objectContaining({
|
||||
x: 50,
|
||||
y: 100,
|
||||
startAngle: Math.PI * -0.5,
|
||||
endAngle: Math.PI * -0.5,
|
||||
circumference: 3.2499218097863447,
|
||||
outerRadius: 49,
|
||||
innerRadius: 36.75,
|
||||
});
|
||||
innerRadius: 36.75
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[1].metaData[2]._model).toEqual({
|
||||
expect(chart.data.datasets[1].metaData[2]._model).toEqual(jasmine.objectContaining({
|
||||
x: 50,
|
||||
y: 100,
|
||||
startAngle: Math.PI * -0.5,
|
||||
endAngle: Math.PI * -0.5,
|
||||
circumference: 0,
|
||||
outerRadius: 49,
|
||||
innerRadius: 36.75,
|
||||
});
|
||||
innerRadius: 36.75
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[1].metaData[3]._model).toEqual({
|
||||
expect(chart.data.datasets[1].metaData[3]._model).toEqual(jasmine.objectContaining({
|
||||
x: 50,
|
||||
y: 100,
|
||||
startAngle: Math.PI * -0.5,
|
||||
endAngle: Math.PI * -0.5,
|
||||
circumference: 0.8666458159430251,
|
||||
outerRadius: 49,
|
||||
innerRadius: 36.75,
|
||||
});
|
||||
innerRadius: 36.75
|
||||
}));
|
||||
|
||||
controller.update();
|
||||
|
||||
expect(chart.data.datasets[1].metaData[0]._model).toEqual({
|
||||
expect(chart.data.datasets[1].metaData[0]._model).toEqual(jasmine.objectContaining({
|
||||
x: 50,
|
||||
y: 100,
|
||||
startAngle: Math.PI * -0.5,
|
||||
@@ -152,9 +139,9 @@ describe('Doughnut controller tests', function() {
|
||||
hoverBackgroundColor: 'rgb(255, 255, 255)',
|
||||
|
||||
label: 'label0',
|
||||
});
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[1].metaData[1]._model).toEqual({
|
||||
expect(chart.data.datasets[1].metaData[1]._model).toEqual(jasmine.objectContaining({
|
||||
x: 50,
|
||||
y: 100,
|
||||
startAngle: 0.5958182130626666,
|
||||
@@ -169,9 +156,9 @@ describe('Doughnut controller tests', function() {
|
||||
hoverBackgroundColor: 'rgb(255, 255, 255)',
|
||||
|
||||
label: 'label1'
|
||||
});
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[1].metaData[2]._model).toEqual({
|
||||
expect(chart.data.datasets[1].metaData[2]._model).toEqual(jasmine.objectContaining({
|
||||
x: 50,
|
||||
y: 100,
|
||||
startAngle: 3.8457400228490113,
|
||||
@@ -186,9 +173,9 @@ describe('Doughnut controller tests', function() {
|
||||
hoverBackgroundColor: 'rgb(255, 255, 255)',
|
||||
|
||||
label: 'label2'
|
||||
});
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[1].metaData[3]._model).toEqual({
|
||||
expect(chart.data.datasets[1].metaData[3]._model).toEqual(jasmine.objectContaining({
|
||||
x: 50,
|
||||
y: 100,
|
||||
startAngle: 3.8457400228490113,
|
||||
@@ -203,7 +190,7 @@ describe('Doughnut controller tests', function() {
|
||||
hoverBackgroundColor: 'rgb(255, 255, 255)',
|
||||
|
||||
label: 'label3'
|
||||
});
|
||||
}));
|
||||
|
||||
// Change the amount of data and ensure that arcs are updated accordingly
|
||||
chart.data.datasets[1].data = [1, 2]; // remove 2 elements from dataset 0
|
||||
@@ -228,9 +215,11 @@ describe('Doughnut controller tests', function() {
|
||||
|
||||
it ('should draw all arcs', function() {
|
||||
var chart = {
|
||||
chart: {
|
||||
width: 100,
|
||||
height: 200,
|
||||
chartArea: {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: 100,
|
||||
bottom: 200,
|
||||
},
|
||||
data: {
|
||||
datasets: [{
|
||||
@@ -275,9 +264,11 @@ describe('Doughnut controller tests', function() {
|
||||
|
||||
it ('should set the hover style of an arc', function() {
|
||||
var chart = {
|
||||
chart: {
|
||||
width: 100,
|
||||
height: 200,
|
||||
chartArea: {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: 100,
|
||||
bottom: 200,
|
||||
},
|
||||
data: {
|
||||
datasets: [{
|
||||
@@ -354,9 +345,11 @@ describe('Doughnut controller tests', function() {
|
||||
|
||||
it ('should unset the hover style of an arc', function() {
|
||||
var chart = {
|
||||
chart: {
|
||||
width: 100,
|
||||
height: 200,
|
||||
chartArea: {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: 100,
|
||||
bottom: 200,
|
||||
},
|
||||
data: {
|
||||
datasets: [{
|
||||
|
||||
+472
-45
@@ -76,33 +76,6 @@ describe('Line controller tests', function() {
|
||||
expect(chart.data.datasets[0].metaDataset instanceof Chart.elements.Line).toBe(true); // 1 line element
|
||||
});
|
||||
|
||||
it('should remove elements', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4]
|
||||
}]
|
||||
},
|
||||
config: {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.line(chart, 0);
|
||||
controller.removeElement(0);
|
||||
expect(chart.data.datasets[0].metaData.length).toBe(3);
|
||||
});
|
||||
|
||||
it('should draw all elements', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
@@ -114,6 +87,7 @@ describe('Line controller tests', function() {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
showLines: true,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
@@ -141,6 +115,45 @@ describe('Line controller tests', function() {
|
||||
expect(chart.data.datasets[0].metaData[3].draw.calls.count()).toBe(1);
|
||||
});
|
||||
|
||||
it('should draw all elements except lines', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4]
|
||||
}]
|
||||
},
|
||||
config: {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
showLines: false,
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.line(chart, 0);
|
||||
|
||||
spyOn(chart.data.datasets[0].metaDataset, 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[0], 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[1], 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[2], 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[3], 'draw');
|
||||
|
||||
controller.draw();
|
||||
|
||||
expect(chart.data.datasets[0].metaDataset.draw.calls.count()).toBe(0);
|
||||
expect(chart.data.datasets[0].metaData[0].draw.calls.count()).toBe(1);
|
||||
expect(chart.data.datasets[0].metaData[2].draw.calls.count()).toBe(1);
|
||||
expect(chart.data.datasets[0].metaData[3].draw.calls.count()).toBe(1);
|
||||
});
|
||||
|
||||
it('should update elements', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
@@ -204,6 +217,7 @@ describe('Line controller tests', function() {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
showLines: true,
|
||||
elements: {
|
||||
line: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
@@ -224,6 +238,7 @@ describe('Line controller tests', function() {
|
||||
hoverRadius: 4,
|
||||
hoverBorderWidth: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle'
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
@@ -267,6 +282,7 @@ describe('Line controller tests', function() {
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0.1,
|
||||
|
||||
@@ -287,6 +303,7 @@ describe('Line controller tests', function() {
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0.1,
|
||||
|
||||
@@ -307,6 +324,7 @@ describe('Line controller tests', function() {
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0.1,
|
||||
|
||||
@@ -327,6 +345,7 @@ describe('Line controller tests', function() {
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0.1,
|
||||
|
||||
@@ -342,7 +361,7 @@ describe('Line controller tests', function() {
|
||||
});
|
||||
|
||||
// Use dataset level styles for lines & points
|
||||
chart.data.datasets[0].tension = 0.2;
|
||||
chart.data.datasets[0].tension = 0;
|
||||
chart.data.datasets[0].backgroundColor = 'rgb(98, 98, 98)';
|
||||
chart.data.datasets[0].borderColor = 'rgb(8, 8, 8)';
|
||||
chart.data.datasets[0].borderWidth = 0.55;
|
||||
@@ -370,7 +389,7 @@ describe('Line controller tests', function() {
|
||||
borderJoinStyle: 'miter',
|
||||
borderWidth: 0.55,
|
||||
fill: false,
|
||||
tension: 0.2,
|
||||
tension: 0,
|
||||
|
||||
scaleTop: 0,
|
||||
scaleBottom: 200,
|
||||
@@ -383,8 +402,9 @@ describe('Line controller tests', function() {
|
||||
borderColor: 'rgb(56, 57, 58)',
|
||||
hitRadius: 3.3,
|
||||
radius: 22,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0.2,
|
||||
tension: 0,
|
||||
|
||||
// Point
|
||||
x: 81,
|
||||
@@ -393,8 +413,8 @@ describe('Line controller tests', function() {
|
||||
// Control points
|
||||
controlPointPreviousX: 81,
|
||||
controlPointPreviousY: 62,
|
||||
controlPointNextX: 91,
|
||||
controlPointNextY: 52.6,
|
||||
controlPointNextX: 81,
|
||||
controlPointNextY: 62,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[1]._model).toEqual({
|
||||
@@ -403,18 +423,19 @@ describe('Line controller tests', function() {
|
||||
borderColor: 'rgb(56, 57, 58)',
|
||||
hitRadius: 3.3,
|
||||
radius: 22,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0.2,
|
||||
tension: 0,
|
||||
|
||||
// Point
|
||||
x: 131,
|
||||
y: 15,
|
||||
|
||||
// Control points
|
||||
controlPointPreviousX: 124.65778768378175,
|
||||
controlPointPreviousY: 9.097346953222619,
|
||||
controlPointNextX: 144.85778768378177,
|
||||
controlPointNextY: 27.897346953222623,
|
||||
controlPointPreviousX: 131,
|
||||
controlPointPreviousY: 15,
|
||||
controlPointNextX: 131,
|
||||
controlPointNextY: 15,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[2]._model).toEqual({
|
||||
@@ -423,18 +444,19 @@ describe('Line controller tests', function() {
|
||||
borderColor: 'rgb(56, 57, 58)',
|
||||
hitRadius: 3.3,
|
||||
radius: 22,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0.2,
|
||||
tension: 0,
|
||||
|
||||
// Point
|
||||
x: 182,
|
||||
y: 156,
|
||||
|
||||
// Control points
|
||||
controlPointPreviousX: 167.76304506745115,
|
||||
controlPointPreviousY: 130.76816898092827,
|
||||
controlPointNextX: 187.96304506745116,
|
||||
controlPointNextY: 166.56816898092828,
|
||||
controlPointPreviousX: 182,
|
||||
controlPointPreviousY: 156,
|
||||
controlPointNextX: 182,
|
||||
controlPointNextY: 156,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[3]._model).toEqual({
|
||||
@@ -443,16 +465,17 @@ describe('Line controller tests', function() {
|
||||
borderColor: 'rgb(56, 57, 58)',
|
||||
hitRadius: 3.3,
|
||||
radius: 22,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0.2,
|
||||
tension: 0,
|
||||
|
||||
// Point
|
||||
x: 232,
|
||||
y: 194,
|
||||
|
||||
// Control points
|
||||
controlPointPreviousX: 222,
|
||||
controlPointPreviousY: 186.4,
|
||||
controlPointPreviousX: 232,
|
||||
controlPointPreviousY: 194,
|
||||
controlPointNextX: 232,
|
||||
controlPointNextY: 194,
|
||||
});
|
||||
@@ -505,6 +528,7 @@ describe('Line controller tests', function() {
|
||||
borderColor: 'rgb(4, 6, 8)',
|
||||
hitRadius: 5,
|
||||
radius: 2.2,
|
||||
pointStyle: 'circle',
|
||||
skip: true,
|
||||
tension: 0.15,
|
||||
|
||||
@@ -520,6 +544,409 @@ describe('Line controller tests', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should update elements when the y scale is stacked', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [10, 15, -4, -4],
|
||||
label: 'dataset2',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID',
|
||||
type: 'line'
|
||||
}, {
|
||||
data: [20, 20, 30, -30],
|
||||
label: 'dataset1',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID',
|
||||
type: 'line'
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
|
||||
verticalScaleConfig.stacked = true;
|
||||
var yScale = new VerticalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: verticalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstYScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var verticalSize = yScale.update(50, 200);
|
||||
yScale.top = 0;
|
||||
yScale.left = 0;
|
||||
yScale.right = verticalSize.width;
|
||||
yScale.bottom = verticalSize.height;
|
||||
|
||||
var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
|
||||
var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
|
||||
horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
|
||||
var xScale = new HorizontalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: horizontalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstXScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var horizontalSize = xScale.update(200, 50);
|
||||
xScale.left = yScale.right;
|
||||
xScale.top = yScale.bottom;
|
||||
xScale.right = horizontalSize.width + xScale.left;
|
||||
xScale.bottom = horizontalSize.height + xScale.top;
|
||||
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 200,
|
||||
left: xScale.left,
|
||||
right: xScale.left + 200,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
showLines: true,
|
||||
elements: {
|
||||
line: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderCapStyle: 'round',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.1,
|
||||
borderJoinStyle: 'bevel',
|
||||
borderWidth: 1.2,
|
||||
fill: true,
|
||||
tension: 0,
|
||||
},
|
||||
point: {
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
hoverRadius: 4,
|
||||
hoverBorderWidth: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle'
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
firstXScaleID: xScale,
|
||||
firstYScaleID: yScale,
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.line(chart, 0);
|
||||
var controller2 = new Chart.controllers.line(chart, 1);
|
||||
controller.update();
|
||||
controller2.update();
|
||||
|
||||
// Line element
|
||||
expect(chart.data.datasets[0].metaDataset._model).toEqual(jasmine.objectContaining({
|
||||
scaleTop: 0,
|
||||
scaleBottom: 200,
|
||||
scaleZero: 100,
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[0].metaData[0]._model).toEqual(jasmine.objectContaining({
|
||||
// Point
|
||||
x: 91,
|
||||
y: 77,
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[0].metaData[1]._model).toEqual(jasmine.objectContaining({
|
||||
// Point
|
||||
x: 141,
|
||||
y: 65,
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[0].metaData[2]._model).toEqual(jasmine.objectContaining({
|
||||
// Point
|
||||
x: 192,
|
||||
y: 109,
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[0].metaData[3]._model).toEqual(jasmine.objectContaining({
|
||||
// Point
|
||||
x: 242,
|
||||
y: 109,
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[1].metaData[0]._model).toEqual(jasmine.objectContaining({
|
||||
// Point
|
||||
x: 91,
|
||||
y: 30,
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[1].metaData[1]._model).toEqual(jasmine.objectContaining({
|
||||
// Point
|
||||
x: 141,
|
||||
y: 18,
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[1].metaData[2]._model).toEqual(jasmine.objectContaining({
|
||||
// Point
|
||||
x: 192,
|
||||
y: 30,
|
||||
}));
|
||||
|
||||
expect(chart.data.datasets[1].metaData[3]._model).toEqual(jasmine.objectContaining({
|
||||
// Point
|
||||
x: 242,
|
||||
y: 180,
|
||||
}));
|
||||
|
||||
|
||||
});
|
||||
|
||||
it('should find the correct scale zero when the data is all positive', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [10, 15, 20, 20],
|
||||
label: 'dataset2',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID',
|
||||
type: 'line'
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
|
||||
verticalScaleConfig.stacked = true;
|
||||
var yScale = new VerticalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: verticalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstYScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var verticalSize = yScale.update(50, 200);
|
||||
yScale.top = 0;
|
||||
yScale.left = 0;
|
||||
yScale.right = verticalSize.width;
|
||||
yScale.bottom = verticalSize.height;
|
||||
|
||||
var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
|
||||
var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
|
||||
horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
|
||||
var xScale = new HorizontalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: horizontalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstXScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var horizontalSize = xScale.update(200, 50);
|
||||
xScale.left = yScale.right;
|
||||
xScale.top = yScale.bottom;
|
||||
xScale.right = horizontalSize.width + xScale.left;
|
||||
xScale.bottom = horizontalSize.height + xScale.top;
|
||||
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 200,
|
||||
left: xScale.left,
|
||||
right: xScale.left + 200,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
showLines: true,
|
||||
elements: {
|
||||
line: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderCapStyle: 'round',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.1,
|
||||
borderJoinStyle: 'bevel',
|
||||
borderWidth: 1.2,
|
||||
fill: true,
|
||||
tension: 0,
|
||||
},
|
||||
point: {
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
hoverRadius: 4,
|
||||
hoverBorderWidth: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle'
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
firstXScaleID: xScale,
|
||||
firstYScaleID: yScale,
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.line(chart, 0);
|
||||
controller.update();
|
||||
|
||||
// Line element
|
||||
expect(chart.data.datasets[0].metaDataset._model).toEqual(jasmine.objectContaining({
|
||||
scaleTop: 0,
|
||||
scaleBottom: 200,
|
||||
scaleZero: 194, // yScale.min is the 0 point
|
||||
}));
|
||||
});
|
||||
|
||||
it('should find the correct scale zero when the data is all negative', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [-10, -15, -20, -20],
|
||||
label: 'dataset2',
|
||||
xAxisID: 'firstXScaleID',
|
||||
yAxisID: 'firstYScaleID',
|
||||
type: 'line'
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var VerticalScaleConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var verticalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
verticalScaleConfig = Chart.helpers.scaleMerge(verticalScaleConfig, Chart.defaults.line.scales.yAxes[0]);
|
||||
verticalScaleConfig.stacked = true;
|
||||
var yScale = new VerticalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: verticalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstYScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var verticalSize = yScale.update(50, 200);
|
||||
yScale.top = 0;
|
||||
yScale.left = 0;
|
||||
yScale.right = verticalSize.width;
|
||||
yScale.bottom = verticalSize.height;
|
||||
|
||||
var HorizontalScaleConstructor = Chart.scaleService.getScaleConstructor('category');
|
||||
var horizontalScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
|
||||
horizontalScaleConfig = Chart.helpers.scaleMerge(horizontalScaleConfig, Chart.defaults.line.scales.xAxes[0]);
|
||||
var xScale = new HorizontalScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: horizontalScaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
id: 'firstXScaleID'
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
var horizontalSize = xScale.update(200, 50);
|
||||
xScale.left = yScale.right;
|
||||
xScale.top = yScale.bottom;
|
||||
xScale.right = horizontalSize.width + xScale.left;
|
||||
xScale.bottom = horizontalSize.height + xScale.top;
|
||||
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 200,
|
||||
left: xScale.left,
|
||||
right: xScale.left + 200,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
showLines: true,
|
||||
elements: {
|
||||
line: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderCapStyle: 'round',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.1,
|
||||
borderJoinStyle: 'bevel',
|
||||
borderWidth: 1.2,
|
||||
fill: true,
|
||||
tension: 0,
|
||||
},
|
||||
point: {
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
hoverRadius: 4,
|
||||
hoverBorderWidth: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle'
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
id: 'firstXScaleID'
|
||||
}],
|
||||
yAxes: [{
|
||||
id: 'firstYScaleID'
|
||||
}]
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
firstXScaleID: xScale,
|
||||
firstYScaleID: yScale,
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.line(chart, 0);
|
||||
controller.update();
|
||||
|
||||
// Line element
|
||||
expect(chart.data.datasets[0].metaDataset._model).toEqual(jasmine.objectContaining({
|
||||
scaleTop: 0,
|
||||
scaleBottom: 200,
|
||||
scaleZero: 6, // yScale.max is the zero point
|
||||
}));
|
||||
});
|
||||
|
||||
it ('should fall back to the line styles for points', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
|
||||
@@ -0,0 +1,508 @@
|
||||
// Test the polar area controller
|
||||
describe('Polar area controller tests', function() {
|
||||
it('Should be constructed', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: []
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.polarArea(chart, 0);
|
||||
expect(controller).not.toBe(undefined);
|
||||
expect(controller.index).toBe(0);
|
||||
expect(chart.data.datasets[0].metaData).toEqual([]);
|
||||
|
||||
controller.updateIndex(1);
|
||||
expect(controller.index).toBe(1);
|
||||
});
|
||||
|
||||
it('Should create arc elements for each data item during initialization', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4]
|
||||
}]
|
||||
},
|
||||
config: {
|
||||
type: 'polarArea'
|
||||
},
|
||||
options: {
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.polarArea(chart, 0);
|
||||
|
||||
expect(chart.data.datasets[0].metaData.length).toBe(4); // 4 arcs created
|
||||
expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Arc).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Arc).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[2] instanceof Chart.elements.Arc).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[3] instanceof Chart.elements.Arc).toBe(true);
|
||||
});
|
||||
|
||||
it('should draw all elements', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4]
|
||||
}]
|
||||
},
|
||||
config: {
|
||||
type: 'polarArea'
|
||||
},
|
||||
options: {
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.polarArea(chart, 0);
|
||||
|
||||
spyOn(chart.data.datasets[0].metaData[0], 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[1], 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[2], 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[3], 'draw');
|
||||
|
||||
controller.draw();
|
||||
|
||||
expect(chart.data.datasets[0].metaData[0].draw.calls.count()).toBe(1);
|
||||
expect(chart.data.datasets[0].metaData[1].draw.calls.count()).toBe(1);
|
||||
expect(chart.data.datasets[0].metaData[2].draw.calls.count()).toBe(1);
|
||||
expect(chart.data.datasets[0].metaData[3].draw.calls.count()).toBe(1);
|
||||
});
|
||||
|
||||
it('should update elements', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4],
|
||||
label: 'dataset2',
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var ScaleConstructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
scaleConfig = Chart.helpers.scaleMerge(scaleConfig, Chart.defaults.polarArea.scale);
|
||||
var scale = new ScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: scaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
scale.update(300, 300);
|
||||
scale.top = 0;
|
||||
scale.left = 0;
|
||||
scale.right = 300;
|
||||
scale.bottom = 300;
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 300,
|
||||
left: 0,
|
||||
right: 300,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
showLines: true,
|
||||
elements: {
|
||||
arc: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderWidth: 1.2,
|
||||
},
|
||||
},
|
||||
},
|
||||
scale: scale
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.polarArea(chart, 0);
|
||||
controller.update();
|
||||
|
||||
expect(chart.data.datasets[0].metaData[0]._model).toEqual({
|
||||
x: 150,
|
||||
y: 150,
|
||||
innerRadius: 0,
|
||||
outerRadius: 59.5,
|
||||
startAngle: -0.5 * Math.PI,
|
||||
endAngle: 0,
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderWidth: 1.2,
|
||||
label: 'label1'
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[1]._model).toEqual({
|
||||
x: 150,
|
||||
y: 150,
|
||||
innerRadius: 0,
|
||||
outerRadius: 80.75,
|
||||
startAngle: 0,
|
||||
endAngle: 0.5 * Math.PI,
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderWidth: 1.2,
|
||||
label: 'label2'
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[2]._model).toEqual({
|
||||
x: 150,
|
||||
y: 150,
|
||||
innerRadius: 0,
|
||||
outerRadius: 17,
|
||||
startAngle: 0.5 * Math.PI,
|
||||
endAngle: Math.PI,
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderWidth: 1.2,
|
||||
label: 'label3'
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[3]._model).toEqual({
|
||||
x: 150,
|
||||
y: 150,
|
||||
innerRadius: 0,
|
||||
outerRadius: 0,
|
||||
startAngle: Math.PI,
|
||||
endAngle: 1.5 * Math.PI,
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderWidth: 1.2,
|
||||
label: 'label4'
|
||||
});
|
||||
|
||||
// arc styles
|
||||
chart.data.datasets[0].backgroundColor = 'rgb(128, 129, 130)';
|
||||
chart.data.datasets[0].borderColor = 'rgb(56, 57, 58)';
|
||||
chart.data.datasets[0].borderWidth = 1.123;
|
||||
|
||||
controller.update();
|
||||
|
||||
expect(chart.data.datasets[0].metaData[0]._model).toEqual({
|
||||
x: 150,
|
||||
y: 150,
|
||||
innerRadius: 0,
|
||||
outerRadius: 59.5,
|
||||
startAngle: -0.5 * Math.PI,
|
||||
endAngle: 0,
|
||||
backgroundColor: 'rgb(128, 129, 130)',
|
||||
borderWidth: 1.123,
|
||||
borderColor: 'rgb(56, 57, 58)',
|
||||
label: 'label1'
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[1]._model).toEqual({
|
||||
x: 150,
|
||||
y: 150,
|
||||
innerRadius: 0,
|
||||
outerRadius: 80.75,
|
||||
startAngle: 0,
|
||||
endAngle: 0.5 * Math.PI,
|
||||
backgroundColor: 'rgb(128, 129, 130)',
|
||||
borderWidth: 1.123,
|
||||
borderColor: 'rgb(56, 57, 58)',
|
||||
label: 'label2'
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[2]._model).toEqual({
|
||||
x: 150,
|
||||
y: 150,
|
||||
innerRadius: 0,
|
||||
outerRadius: 17,
|
||||
startAngle: 0.5 * Math.PI,
|
||||
endAngle: Math.PI,
|
||||
backgroundColor: 'rgb(128, 129, 130)',
|
||||
borderWidth: 1.123,
|
||||
borderColor: 'rgb(56, 57, 58)',
|
||||
label: 'label3'
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[3]._model).toEqual({
|
||||
x: 150,
|
||||
y: 150,
|
||||
innerRadius: 0,
|
||||
outerRadius: 0,
|
||||
startAngle: Math.PI,
|
||||
endAngle: 1.5 * Math.PI,
|
||||
backgroundColor: 'rgb(128, 129, 130)',
|
||||
borderWidth: 1.123,
|
||||
borderColor: 'rgb(56, 57, 58)',
|
||||
label: 'label4'
|
||||
});
|
||||
|
||||
// arc styles
|
||||
chart.data.datasets[0].metaData[0].custom = {
|
||||
backgroundColor: 'rgb(0, 1, 3)',
|
||||
borderColor: 'rgb(4, 6, 8)',
|
||||
borderWidth: 0.787,
|
||||
|
||||
};
|
||||
|
||||
controller.update();
|
||||
|
||||
expect(chart.data.datasets[0].metaData[0]._model).toEqual({
|
||||
x: 150,
|
||||
y: 150,
|
||||
innerRadius: 0,
|
||||
outerRadius: 59.5,
|
||||
startAngle: -0.5 * Math.PI,
|
||||
endAngle: 0,
|
||||
backgroundColor: 'rgb(0, 1, 3)',
|
||||
borderWidth: 0.787,
|
||||
borderColor: 'rgb(4, 6, 8)',
|
||||
label: 'label1'
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle number of data point changes in update', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4],
|
||||
label: 'dataset2',
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var ScaleConstructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
scaleConfig = Chart.helpers.scaleMerge(scaleConfig, Chart.defaults.polarArea.scale);
|
||||
var scale = new ScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: scaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
scale.update(300, 300);
|
||||
scale.top = 0;
|
||||
scale.left = 0;
|
||||
scale.right = 300;
|
||||
scale.bottom = 300;
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 300,
|
||||
left: 0,
|
||||
right: 300,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
showLines: true,
|
||||
elements: {
|
||||
arc: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderWidth: 1.2,
|
||||
},
|
||||
},
|
||||
},
|
||||
scale: scale
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.polarArea(chart, 0);
|
||||
controller.update();
|
||||
expect(chart.data.datasets[0].metaData.length).toBe(4);
|
||||
|
||||
chart.data.datasets[0].data = [1, 2]; // remove 2 items
|
||||
controller.buildOrUpdateElements();
|
||||
controller.update();
|
||||
expect(chart.data.datasets[0].metaData.length).toBe(2);
|
||||
expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Arc).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Arc).toBe(true);
|
||||
|
||||
chart.data.datasets[0].data = [1, 2, 3, 4, 5]; // add 3 items
|
||||
controller.buildOrUpdateElements();
|
||||
controller.update();
|
||||
expect(chart.data.datasets[0].metaData.length).toBe(5);
|
||||
expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Arc).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Arc).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[2] instanceof Chart.elements.Arc).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[3] instanceof Chart.elements.Arc).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[4] instanceof Chart.elements.Arc).toBe(true);
|
||||
});
|
||||
|
||||
it('should set arc hover styles', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4],
|
||||
label: 'dataset2',
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var ScaleConstructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
scaleConfig = Chart.helpers.scaleMerge(scaleConfig, Chart.defaults.polarArea.scale);
|
||||
var scale = new ScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: scaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
scale.update(300, 300);
|
||||
scale.top = 0;
|
||||
scale.left = 0;
|
||||
scale.right = 300;
|
||||
scale.bottom = 300;
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 300,
|
||||
left: 0,
|
||||
right: 300,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
showLines: true,
|
||||
elements: {
|
||||
arc: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderWidth: 1.2,
|
||||
},
|
||||
},
|
||||
},
|
||||
scale: scale
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.polarArea(chart, 0);
|
||||
controller.update();
|
||||
var arc = chart.data.datasets[0].metaData[0];
|
||||
|
||||
controller.setHoverStyle(arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(230, 0, 0)');
|
||||
expect(arc._model.borderColor).toBe('rgb(0, 230, 0)');
|
||||
expect(arc._model.borderWidth).toBe(1.2);
|
||||
|
||||
// Can set hover style per dataset
|
||||
chart.data.datasets[0].hoverBackgroundColor = 'rgb(77, 79, 81)';
|
||||
chart.data.datasets[0].hoverBorderColor = 'rgb(123, 125, 127)';
|
||||
chart.data.datasets[0].hoverBorderWidth = 2.1;
|
||||
|
||||
controller.setHoverStyle(arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(77, 79, 81)');
|
||||
expect(arc._model.borderColor).toBe('rgb(123, 125, 127)');
|
||||
expect(arc._model.borderWidth).toBe(2.1);
|
||||
|
||||
// Custom style
|
||||
arc.custom = {
|
||||
hoverBorderWidth: 5.5,
|
||||
hoverBackgroundColor: 'rgb(0, 0, 0)',
|
||||
hoverBorderColor: 'rgb(10, 10, 10)'
|
||||
};
|
||||
|
||||
controller.setHoverStyle(arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(0, 0, 0)');
|
||||
expect(arc._model.borderColor).toBe('rgb(10, 10, 10)');
|
||||
expect(arc._model.borderWidth).toBe(5.5);
|
||||
});
|
||||
|
||||
it('should remove hover styles', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4],
|
||||
label: 'dataset2',
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var ScaleConstructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
scaleConfig = Chart.helpers.scaleMerge(scaleConfig, Chart.defaults.polarArea.scale);
|
||||
var scale = new ScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: scaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
scale.update(300, 300);
|
||||
scale.top = 0;
|
||||
scale.left = 0;
|
||||
scale.right = 300;
|
||||
scale.bottom = 300;
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 300,
|
||||
left: 0,
|
||||
right: 300,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'line'
|
||||
},
|
||||
options: {
|
||||
showLines: true,
|
||||
elements: {
|
||||
arc: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderWidth: 1.2,
|
||||
},
|
||||
},
|
||||
},
|
||||
scale: scale
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.polarArea(chart, 0);
|
||||
controller.update();
|
||||
var arc = chart.data.datasets[0].metaData[0];
|
||||
|
||||
chart.options.elements.arc.backgroundColor = 'rgb(45, 46, 47)';
|
||||
chart.options.elements.arc.borderColor = 'rgb(50, 51, 52)';
|
||||
chart.options.elements.arc.borderWidth = 10.1;
|
||||
|
||||
controller.removeHoverStyle(arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(45, 46, 47)');
|
||||
expect(arc._model.borderColor).toBe('rgb(50, 51, 52)');
|
||||
expect(arc._model.borderWidth).toBe(10.1);
|
||||
|
||||
// Can set hover style per dataset
|
||||
chart.data.datasets[0].backgroundColor = 'rgb(77, 79, 81)';
|
||||
chart.data.datasets[0].borderColor = 'rgb(123, 125, 127)';
|
||||
chart.data.datasets[0].borderWidth = 2.1;
|
||||
|
||||
controller.removeHoverStyle(arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(77, 79, 81)');
|
||||
expect(arc._model.borderColor).toBe('rgb(123, 125, 127)');
|
||||
expect(arc._model.borderWidth).toBe(2.1);
|
||||
|
||||
// Custom style
|
||||
arc.custom = {
|
||||
borderWidth: 5.5,
|
||||
backgroundColor: 'rgb(0, 0, 0)',
|
||||
borderColor: 'rgb(10, 10, 10)'
|
||||
};
|
||||
|
||||
controller.removeHoverStyle(arc);
|
||||
expect(arc._model.backgroundColor).toBe('rgb(0, 0, 0)');
|
||||
expect(arc._model.borderColor).toBe('rgb(10, 10, 10)');
|
||||
expect(arc._model.borderWidth).toBe(5.5);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,747 @@
|
||||
// Test the polar area controller
|
||||
describe('Radar controller tests', function() {
|
||||
it('Should be constructed', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: []
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.radar(chart, 0);
|
||||
expect(controller).not.toBe(undefined);
|
||||
expect(controller.index).toBe(0);
|
||||
expect(chart.data.datasets[0].metaData).toEqual([]);
|
||||
|
||||
controller.updateIndex(1);
|
||||
expect(controller.index).toBe(1);
|
||||
});
|
||||
|
||||
it('Should create arc elements for each data item during initialization', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4]
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
},
|
||||
config: {
|
||||
type: 'radar'
|
||||
},
|
||||
options: {
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.radar(chart, 0);
|
||||
|
||||
// Line element
|
||||
expect(chart.data.datasets[0].metaDataset instanceof Chart.elements.Line).toBe(true);
|
||||
|
||||
expect(chart.data.datasets[0].metaData.length).toBe(4); // 4 points created
|
||||
expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[2] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[3] instanceof Chart.elements.Point).toBe(true);
|
||||
});
|
||||
|
||||
it('should draw all elements', function() {
|
||||
var chart = {
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4]
|
||||
}]
|
||||
},
|
||||
config: {
|
||||
type: 'radar'
|
||||
},
|
||||
options: {
|
||||
}
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.radar(chart, 0);
|
||||
|
||||
spyOn(chart.data.datasets[0].metaDataset, 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[0], 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[1], 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[2], 'draw');
|
||||
spyOn(chart.data.datasets[0].metaData[3], 'draw');
|
||||
|
||||
controller.draw();
|
||||
|
||||
expect(chart.data.datasets[0].metaDataset.draw.calls.count()).toBe(1);
|
||||
expect(chart.data.datasets[0].metaData[0].draw.calls.count()).toBe(1);
|
||||
expect(chart.data.datasets[0].metaData[1].draw.calls.count()).toBe(1);
|
||||
expect(chart.data.datasets[0].metaData[2].draw.calls.count()).toBe(1);
|
||||
expect(chart.data.datasets[0].metaData[3].draw.calls.count()).toBe(1);
|
||||
});
|
||||
|
||||
it('should update elements', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4],
|
||||
label: 'dataset2'
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var ScaleConstructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
scaleConfig = Chart.helpers.scaleMerge(scaleConfig, Chart.defaults.radar.scale);
|
||||
var scale = new ScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: scaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
scale.top = 0;
|
||||
scale.left = 0;
|
||||
scale.right = 300;
|
||||
scale.bottom = 300;
|
||||
scale.update(300, 300);
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 300,
|
||||
left: 0,
|
||||
right: 300,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'radar'
|
||||
},
|
||||
options: {
|
||||
showLines: true,
|
||||
elements: {
|
||||
line: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderCapStyle: 'round',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.1,
|
||||
borderJoinStyle: 'bevel',
|
||||
borderWidth: 1.2,
|
||||
fill: true,
|
||||
tension: 0.1,
|
||||
},
|
||||
point: {
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
hoverRadius: 4,
|
||||
hoverBorderWidth: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle'
|
||||
}
|
||||
}
|
||||
},
|
||||
scale: scale
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.radar(chart, 0);
|
||||
controller.update();
|
||||
|
||||
// Line element
|
||||
expect(chart.data.datasets[0].metaDataset._model).toEqual({
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderCapStyle: 'round',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.1,
|
||||
borderJoinStyle: 'bevel',
|
||||
borderWidth: 1.2,
|
||||
fill: true,
|
||||
tension: 0.1,
|
||||
|
||||
scaleTop: 0,
|
||||
scaleBottom: 300,
|
||||
scaleZero: {
|
||||
x: 150,
|
||||
y: 133
|
||||
},
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[0]._model).toEqual({
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0.1,
|
||||
|
||||
// Point
|
||||
x: 150,
|
||||
y: 91,
|
||||
|
||||
// Control points
|
||||
controlPointPreviousX: 146.99829997808834,
|
||||
controlPointPreviousY: 91,
|
||||
controlPointNextX: 155.09829997808833,
|
||||
controlPointNextY: 91,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[1]._model).toEqual({
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0.1,
|
||||
|
||||
// Point
|
||||
x: 231,
|
||||
y: 150,
|
||||
|
||||
// Control points
|
||||
controlPointPreviousX: 231,
|
||||
controlPointPreviousY: 145.8377025234528,
|
||||
controlPointNextX: 231,
|
||||
controlPointNextY: 153.4377025234528,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[2]._model).toEqual({
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0.1,
|
||||
|
||||
// Point
|
||||
x: 150,
|
||||
y: 167,
|
||||
|
||||
// Control points
|
||||
controlPointPreviousX: 156.7197526476963,
|
||||
controlPointPreviousY: 167,
|
||||
controlPointNextX: 148.61975264769632,
|
||||
controlPointNextY: 167,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[3]._model).toEqual({
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
radius: 3,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0.1,
|
||||
|
||||
// Point
|
||||
x: 150,
|
||||
y: 150,
|
||||
|
||||
// Control points
|
||||
controlPointPreviousX: 150,
|
||||
controlPointPreviousY: 151.7,
|
||||
controlPointNextX: 150,
|
||||
controlPointNextY: 144.1,
|
||||
});
|
||||
|
||||
// Use dataset level styles for lines & points
|
||||
chart.data.datasets[0].tension = 0;
|
||||
chart.data.datasets[0].backgroundColor = 'rgb(98, 98, 98)';
|
||||
chart.data.datasets[0].borderColor = 'rgb(8, 8, 8)';
|
||||
chart.data.datasets[0].borderWidth = 0.55;
|
||||
chart.data.datasets[0].borderCapStyle = 'butt';
|
||||
chart.data.datasets[0].borderDash = [2, 3];
|
||||
chart.data.datasets[0].borderDashOffset = 7;
|
||||
chart.data.datasets[0].borderJoinStyle = 'miter';
|
||||
chart.data.datasets[0].fill = false;
|
||||
|
||||
// point styles
|
||||
chart.data.datasets[0].pointRadius = 22;
|
||||
chart.data.datasets[0].hitRadius = 3.3;
|
||||
chart.data.datasets[0].pointBackgroundColor = 'rgb(128, 129, 130)';
|
||||
chart.data.datasets[0].pointBorderColor = 'rgb(56, 57, 58)';
|
||||
chart.data.datasets[0].pointBorderWidth = 1.123;
|
||||
|
||||
controller.update();
|
||||
|
||||
expect(chart.data.datasets[0].metaDataset._model).toEqual({
|
||||
backgroundColor: 'rgb(98, 98, 98)',
|
||||
borderCapStyle: 'butt',
|
||||
borderColor: 'rgb(8, 8, 8)',
|
||||
borderDash: [2, 3],
|
||||
borderDashOffset: 7,
|
||||
borderJoinStyle: 'miter',
|
||||
borderWidth: 0.55,
|
||||
fill: false,
|
||||
tension: 0,
|
||||
|
||||
scaleTop: 0,
|
||||
scaleBottom: 300,
|
||||
scaleZero: {
|
||||
x: 150,
|
||||
y: 133
|
||||
}
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[0]._model).toEqual({
|
||||
backgroundColor: 'rgb(128, 129, 130)',
|
||||
borderWidth: 1.123,
|
||||
borderColor: 'rgb(56, 57, 58)',
|
||||
hitRadius: 3.3,
|
||||
radius: 22,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0,
|
||||
|
||||
// Point
|
||||
x: 150,
|
||||
y: 91,
|
||||
|
||||
// Control points
|
||||
controlPointPreviousX: 150,
|
||||
controlPointPreviousY: 91,
|
||||
controlPointNextX: 150,
|
||||
controlPointNextY: 91,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[1]._model).toEqual({
|
||||
backgroundColor: 'rgb(128, 129, 130)',
|
||||
borderWidth: 1.123,
|
||||
borderColor: 'rgb(56, 57, 58)',
|
||||
hitRadius: 3.3,
|
||||
radius: 22,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0,
|
||||
|
||||
// Point
|
||||
x: 231,
|
||||
y: 150,
|
||||
|
||||
// Control points
|
||||
controlPointPreviousX: 231,
|
||||
controlPointPreviousY: 150,
|
||||
controlPointNextX: 231,
|
||||
controlPointNextY: 150,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[2]._model).toEqual({
|
||||
backgroundColor: 'rgb(128, 129, 130)',
|
||||
borderWidth: 1.123,
|
||||
borderColor: 'rgb(56, 57, 58)',
|
||||
hitRadius: 3.3,
|
||||
radius: 22,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0,
|
||||
|
||||
// Point
|
||||
x: 150,
|
||||
y: 167,
|
||||
|
||||
// Control points
|
||||
controlPointPreviousX: 150,
|
||||
controlPointPreviousY: 167,
|
||||
controlPointNextX: 150,
|
||||
controlPointNextY: 167,
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[3]._model).toEqual({
|
||||
backgroundColor: 'rgb(128, 129, 130)',
|
||||
borderWidth: 1.123,
|
||||
borderColor: 'rgb(56, 57, 58)',
|
||||
hitRadius: 3.3,
|
||||
radius: 22,
|
||||
pointStyle: 'circle',
|
||||
skip: false,
|
||||
tension: 0,
|
||||
|
||||
// Point
|
||||
x: 150,
|
||||
y: 150,
|
||||
|
||||
// Control points
|
||||
controlPointPreviousX: 150,
|
||||
controlPointPreviousY: 150,
|
||||
controlPointNextX: 150,
|
||||
controlPointNextY: 150,
|
||||
});
|
||||
|
||||
// Use custom styles for lines & first point
|
||||
chart.data.datasets[0].metaDataset.custom = {
|
||||
tension: 0.25,
|
||||
backgroundColor: 'rgb(55, 55, 54)',
|
||||
borderColor: 'rgb(8, 7, 6)',
|
||||
borderWidth: 0.3,
|
||||
borderCapStyle: 'square',
|
||||
borderDash: [4, 3],
|
||||
borderDashOffset: 4.4,
|
||||
borderJoinStyle: 'round',
|
||||
fill: true,
|
||||
};
|
||||
|
||||
// point styles
|
||||
chart.data.datasets[0].metaData[0].custom = {
|
||||
radius: 2.2,
|
||||
backgroundColor: 'rgb(0, 1, 3)',
|
||||
borderColor: 'rgb(4, 6, 8)',
|
||||
borderWidth: 0.787,
|
||||
tension: 0.15,
|
||||
skip: true,
|
||||
hitRadius: 5,
|
||||
};
|
||||
|
||||
controller.update();
|
||||
|
||||
expect(chart.data.datasets[0].metaDataset._model).toEqual({
|
||||
backgroundColor: 'rgb(55, 55, 54)',
|
||||
borderCapStyle: 'square',
|
||||
borderColor: 'rgb(8, 7, 6)',
|
||||
borderDash: [4, 3],
|
||||
borderDashOffset: 4.4,
|
||||
borderJoinStyle: 'round',
|
||||
borderWidth: 0.3,
|
||||
fill: true,
|
||||
tension: 0.25,
|
||||
|
||||
scaleTop: 0,
|
||||
scaleBottom: 300,
|
||||
scaleZero: {
|
||||
x: 150,
|
||||
y: 133
|
||||
},
|
||||
});
|
||||
|
||||
expect(chart.data.datasets[0].metaData[0]._model).toEqual({
|
||||
backgroundColor: 'rgb(0, 1, 3)',
|
||||
borderWidth: 0.787,
|
||||
borderColor: 'rgb(4, 6, 8)',
|
||||
hitRadius: 5,
|
||||
radius: 2.2,
|
||||
pointStyle: 'circle',
|
||||
skip: true,
|
||||
tension: 0.15,
|
||||
|
||||
// Point
|
||||
x: 150,
|
||||
y: 91,
|
||||
|
||||
// Control points
|
||||
controlPointPreviousX: 145.4974499671325,
|
||||
controlPointPreviousY: 91,
|
||||
controlPointNextX: 157.6474499671325,
|
||||
controlPointNextY: 91,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle number of data point changes in update', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4],
|
||||
label: 'dataset2',
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var ScaleConstructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
scaleConfig = Chart.helpers.scaleMerge(scaleConfig, Chart.defaults.radar.scale);
|
||||
var scale = new ScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: scaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
scale.top = 0;
|
||||
scale.left = 0;
|
||||
scale.right = 300;
|
||||
scale.bottom = 300;
|
||||
scale.update(300, 300);
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 300,
|
||||
left: 0,
|
||||
right: 300,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'radar'
|
||||
},
|
||||
options: {
|
||||
elements: {
|
||||
line: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderCapStyle: 'round',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.1,
|
||||
borderJoinStyle: 'bevel',
|
||||
borderWidth: 1.2,
|
||||
fill: true,
|
||||
tension: 0.1,
|
||||
},
|
||||
point: {
|
||||
backgroundColor: Chart.defaults.global.defaultColor,
|
||||
borderWidth: 1,
|
||||
borderColor: Chart.defaults.global.defaultColor,
|
||||
hitRadius: 1,
|
||||
hoverRadius: 4,
|
||||
hoverBorderWidth: 1,
|
||||
radius: 3,
|
||||
}
|
||||
},
|
||||
},
|
||||
scale: scale
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.radar(chart, 0);
|
||||
controller.update();
|
||||
expect(chart.data.datasets[0].metaData.length).toBe(4);
|
||||
|
||||
chart.data.datasets[0].data = [1, 2]; // remove 2 items
|
||||
controller.buildOrUpdateElements();
|
||||
controller.update();
|
||||
expect(chart.data.datasets[0].metaData.length).toBe(2);
|
||||
expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Point).toBe(true);
|
||||
|
||||
chart.data.datasets[0].data = [1, 2, 3, 4, 5]; // add 3 items
|
||||
controller.buildOrUpdateElements();
|
||||
controller.update();
|
||||
expect(chart.data.datasets[0].metaData.length).toBe(5);
|
||||
expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[2] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[3] instanceof Chart.elements.Point).toBe(true);
|
||||
expect(chart.data.datasets[0].metaData[4] instanceof Chart.elements.Point).toBe(true);
|
||||
});
|
||||
|
||||
it('should set point hover styles', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4],
|
||||
label: 'dataset2',
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var ScaleConstructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
scaleConfig = Chart.helpers.scaleMerge(scaleConfig, Chart.defaults.radar.scale);
|
||||
var scale = new ScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: scaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
scale.top = 0;
|
||||
scale.left = 0;
|
||||
scale.right = 300;
|
||||
scale.bottom = 300;
|
||||
scale.update(300, 300);
|
||||
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 300,
|
||||
left: 0,
|
||||
right: 300,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'radar'
|
||||
},
|
||||
options: {
|
||||
elements: {
|
||||
line: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderCapStyle: 'round',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.1,
|
||||
borderJoinStyle: 'bevel',
|
||||
borderWidth: 1.2,
|
||||
fill: true,
|
||||
skipNull: true,
|
||||
tension: 0.1,
|
||||
},
|
||||
point: {
|
||||
backgroundColor: 'rgb(255, 255, 0)',
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgb(255, 255, 255)',
|
||||
hitRadius: 1,
|
||||
hoverRadius: 4,
|
||||
hoverBorderWidth: 1,
|
||||
radius: 3,
|
||||
}
|
||||
}
|
||||
},
|
||||
scale: scale
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.radar(chart, 0);
|
||||
controller.update();
|
||||
var point = chart.data.datasets[0].metaData[0];
|
||||
|
||||
controller.setHoverStyle(point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(229, 230, 0)');
|
||||
expect(point._model.borderColor).toBe('rgb(230, 230, 230)');
|
||||
expect(point._model.borderWidth).toBe(1);
|
||||
expect(point._model.radius).toBe(4);
|
||||
|
||||
// Can set hover style per dataset
|
||||
chart.data.datasets[0].pointHoverRadius = 3.3;
|
||||
chart.data.datasets[0].pointHoverBackgroundColor = 'rgb(77, 79, 81)';
|
||||
chart.data.datasets[0].pointHoverBorderColor = 'rgb(123, 125, 127)';
|
||||
chart.data.datasets[0].pointHoverBorderWidth = 2.1;
|
||||
|
||||
controller.setHoverStyle(point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(77, 79, 81)');
|
||||
expect(point._model.borderColor).toBe('rgb(123, 125, 127)');
|
||||
expect(point._model.borderWidth).toBe(2.1);
|
||||
expect(point._model.radius).toBe(3.3);
|
||||
|
||||
// Custom style
|
||||
point.custom = {
|
||||
hoverRadius: 4.4,
|
||||
hoverBorderWidth: 5.5,
|
||||
hoverBackgroundColor: 'rgb(0, 0, 0)',
|
||||
hoverBorderColor: 'rgb(10, 10, 10)'
|
||||
};
|
||||
|
||||
controller.setHoverStyle(point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(0, 0, 0)');
|
||||
expect(point._model.borderColor).toBe('rgb(10, 10, 10)');
|
||||
expect(point._model.borderWidth).toBe(5.5);
|
||||
expect(point._model.radius).toBe(4.4);
|
||||
});
|
||||
|
||||
|
||||
it('should remove hover styles', function() {
|
||||
var data = {
|
||||
datasets: [{
|
||||
data: [10, 15, 0, -4],
|
||||
label: 'dataset2',
|
||||
}],
|
||||
labels: ['label1', 'label2', 'label3', 'label4']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var ScaleConstructor = Chart.scaleService.getScaleConstructor('radialLinear');
|
||||
var scaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('radialLinear'));
|
||||
scaleConfig = Chart.helpers.scaleMerge(scaleConfig, Chart.defaults.radar.scale);
|
||||
var scale = new ScaleConstructor({
|
||||
ctx: mockContext,
|
||||
options: scaleConfig,
|
||||
chart: {
|
||||
data: data
|
||||
},
|
||||
});
|
||||
|
||||
// Update ticks & set physical dimensions
|
||||
scale.top = 0;
|
||||
scale.left = 0;
|
||||
scale.right = 300;
|
||||
scale.bottom = 300;
|
||||
scale.update(300, 300);
|
||||
|
||||
|
||||
var chart = {
|
||||
chartArea: {
|
||||
bottom: 300,
|
||||
left: 0,
|
||||
right: 300,
|
||||
top: 0
|
||||
},
|
||||
data: data,
|
||||
config: {
|
||||
type: 'radar'
|
||||
},
|
||||
options: {
|
||||
elements: {
|
||||
line: {
|
||||
backgroundColor: 'rgb(255, 0, 0)',
|
||||
borderCapStyle: 'round',
|
||||
borderColor: 'rgb(0, 255, 0)',
|
||||
borderDash: [],
|
||||
borderDashOffset: 0.1,
|
||||
borderJoinStyle: 'bevel',
|
||||
borderWidth: 1.2,
|
||||
fill: true,
|
||||
skipNull: true,
|
||||
tension: 0.1,
|
||||
},
|
||||
point: {
|
||||
backgroundColor: 'rgb(255, 255, 0)',
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgb(255, 255, 255)',
|
||||
hitRadius: 1,
|
||||
hoverRadius: 4,
|
||||
hoverBorderWidth: 1,
|
||||
radius: 3,
|
||||
}
|
||||
}
|
||||
},
|
||||
scale: scale
|
||||
};
|
||||
|
||||
var controller = new Chart.controllers.radar(chart, 0);
|
||||
controller.update();
|
||||
var point = chart.data.datasets[0].metaData[0];
|
||||
|
||||
chart.options.elements.point.backgroundColor = 'rgb(45, 46, 47)';
|
||||
chart.options.elements.point.borderColor = 'rgb(50, 51, 52)';
|
||||
chart.options.elements.point.borderWidth = 10.1;
|
||||
chart.options.elements.point.radius = 1.01;
|
||||
|
||||
controller.removeHoverStyle(point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(45, 46, 47)');
|
||||
expect(point._model.borderColor).toBe('rgb(50, 51, 52)');
|
||||
expect(point._model.borderWidth).toBe(10.1);
|
||||
expect(point._model.radius).toBe(1.01);
|
||||
|
||||
// Can set hover style per dataset
|
||||
chart.data.datasets[0].radius = 3.3;
|
||||
chart.data.datasets[0].pointBackgroundColor = 'rgb(77, 79, 81)';
|
||||
chart.data.datasets[0].pointBorderColor = 'rgb(123, 125, 127)';
|
||||
chart.data.datasets[0].pointBorderWidth = 2.1;
|
||||
|
||||
controller.removeHoverStyle(point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(77, 79, 81)');
|
||||
expect(point._model.borderColor).toBe('rgb(123, 125, 127)');
|
||||
expect(point._model.borderWidth).toBe(2.1);
|
||||
expect(point._model.radius).toBe(3.3);
|
||||
|
||||
// Custom style
|
||||
point.custom = {
|
||||
radius: 4.4,
|
||||
borderWidth: 5.5,
|
||||
backgroundColor: 'rgb(0, 0, 0)',
|
||||
borderColor: 'rgb(10, 10, 10)'
|
||||
};
|
||||
|
||||
controller.removeHoverStyle(point);
|
||||
expect(point._model.backgroundColor).toBe('rgb(0, 0, 0)');
|
||||
expect(point._model.borderColor).toBe('rgb(10, 10, 10)');
|
||||
expect(point._model.borderWidth).toBe(5.5);
|
||||
expect(point._model.radius).toBe(4.4);
|
||||
});
|
||||
});
|
||||
+191
-18
@@ -225,26 +225,19 @@ describe('Core helper tests', function() {
|
||||
},
|
||||
position: "right",
|
||||
scaleLabel: {
|
||||
fontColor: '#666',
|
||||
fontFamily: 'Helvetica Neue',
|
||||
fontSize: 12,
|
||||
fontStyle: 'normal',
|
||||
labelString: '',
|
||||
display: false,
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: false,
|
||||
fontColor: "#666",
|
||||
fontFamily: "Helvetica Neue",
|
||||
fontSize: 12,
|
||||
fontStyle: "normal",
|
||||
maxRotation: 90,
|
||||
minRotation: 20,
|
||||
mirror: false,
|
||||
padding: 10,
|
||||
reverse: false,
|
||||
display: true,
|
||||
callback: merged.scales.yAxes[1].ticks.callback, // make it nicer, then check explicitly below
|
||||
autoSkip: true,
|
||||
autoSkipPadding: 20
|
||||
},
|
||||
type: 'linear'
|
||||
}, {
|
||||
@@ -262,26 +255,19 @@ describe('Core helper tests', function() {
|
||||
},
|
||||
position: "left",
|
||||
scaleLabel: {
|
||||
fontColor: '#666',
|
||||
fontFamily: 'Helvetica Neue',
|
||||
fontSize: 12,
|
||||
fontStyle: 'normal',
|
||||
labelString: '',
|
||||
display: false,
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: false,
|
||||
fontColor: "#666",
|
||||
fontFamily: "Helvetica Neue",
|
||||
fontSize: 12,
|
||||
fontStyle: "normal",
|
||||
maxRotation: 90,
|
||||
minRotation: 20,
|
||||
mirror: false,
|
||||
padding: 10,
|
||||
reverse: false,
|
||||
display: true,
|
||||
callback: merged.scales.yAxes[2].ticks.callback, // make it nicer, then check explicitly below
|
||||
autoSkip: true,
|
||||
autoSkipPadding: 20
|
||||
},
|
||||
type: 'linear'
|
||||
}]
|
||||
@@ -327,6 +313,13 @@ describe('Core helper tests', function() {
|
||||
expect(helpers.log10(1000)).toBeCloseTo(3, 1e-9);
|
||||
});
|
||||
|
||||
it('should correctly determine if two numbers are essentially equal', function() {
|
||||
expect(helpers.almostEquals(0, Number.EPSILON, 2 * Number.EPSILON)).toBe(true);
|
||||
expect(helpers.almostEquals(1, 1.1, 0.0001)).toBe(false);
|
||||
expect(helpers.almostEquals(1e30, 1e30 + Number.EPSILON, 0)).toBe(false);
|
||||
expect(helpers.almostEquals(1e30, 1e30 + Number.EPSILON, 2 * Number.EPSILON)).toBe(true);
|
||||
});
|
||||
|
||||
it('Should generate ids', function() {
|
||||
expect(helpers.uid()).toBe('chart-0');
|
||||
expect(helpers.uid()).toBe('chart-1');
|
||||
@@ -491,4 +484,184 @@ describe('Core helper tests', function() {
|
||||
args: []
|
||||
}])
|
||||
});
|
||||
|
||||
it ('should get the maximum width and height for a node', function() {
|
||||
// Create div with fixed size as a test bed
|
||||
var div = document.createElement('div');
|
||||
div.style.width = "200px";
|
||||
div.style.height = "300px";
|
||||
|
||||
document.body.appendChild(div);
|
||||
|
||||
// Create the div we want to get the max size for
|
||||
var innerDiv = document.createElement('div');
|
||||
div.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumWidth(innerDiv)).toBe(200);
|
||||
expect(helpers.getMaximumHeight(innerDiv)).toBe(300);
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
|
||||
it ('should get the maximum width of a node that has a max-width style', function() {
|
||||
// Create div with fixed size as a test bed
|
||||
var div = document.createElement('div');
|
||||
div.style.width = "200px";
|
||||
div.style.height = "300px";
|
||||
|
||||
document.body.appendChild(div);
|
||||
|
||||
// Create the div we want to get the max size for and set a max-width style
|
||||
var innerDiv = document.createElement('div');
|
||||
innerDiv.style.maxWidth = "150px";
|
||||
div.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumWidth(innerDiv)).toBe(150);
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
|
||||
it ('should get the maximum height of a node that has a max-height style', function() {
|
||||
// Create div with fixed size as a test bed
|
||||
var div = document.createElement('div');
|
||||
div.style.width = "200px";
|
||||
div.style.height = "300px";
|
||||
|
||||
document.body.appendChild(div);
|
||||
|
||||
// Create the div we want to get the max size for and set a max-height style
|
||||
var innerDiv = document.createElement('div');
|
||||
innerDiv.style.maxHeight = "150px";
|
||||
div.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
|
||||
it ('should get the maximum width of a node when the parent has a max-width style', function() {
|
||||
// Create div with fixed size as a test bed
|
||||
var div = document.createElement('div');
|
||||
div.style.width = "200px";
|
||||
div.style.height = "300px";
|
||||
|
||||
document.body.appendChild(div);
|
||||
|
||||
// Create an inner wrapper around our div we want to size and give that a max-width style
|
||||
var parentDiv = document.createElement('div');
|
||||
parentDiv.style.maxWidth = "150px";
|
||||
div.appendChild(parentDiv);
|
||||
|
||||
// Create the div we want to get the max size for
|
||||
var innerDiv = document.createElement('div');
|
||||
parentDiv.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumWidth(innerDiv)).toBe(150);
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
|
||||
it ('should get the maximum height of a node when the parent has a max-height style', function() {
|
||||
// Create div with fixed size as a test bed
|
||||
var div = document.createElement('div');
|
||||
div.style.width = "200px";
|
||||
div.style.height = "300px";
|
||||
|
||||
document.body.appendChild(div);
|
||||
|
||||
// Create an inner wrapper around our div we want to size and give that a max-height style
|
||||
var parentDiv = document.createElement('div');
|
||||
parentDiv.style.maxHeight = "150px";
|
||||
div.appendChild(parentDiv);
|
||||
|
||||
// Create the div we want to get the max size for
|
||||
var innerDiv = document.createElement('div');
|
||||
innerDiv.style.height = "300px"; // make it large
|
||||
parentDiv.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
|
||||
it ('should get the maximum width of a node that has a percentage max-width style', function() {
|
||||
// Create div with fixed size as a test bed
|
||||
var div = document.createElement('div');
|
||||
div.style.width = "200px";
|
||||
div.style.height = "300px";
|
||||
|
||||
document.body.appendChild(div);
|
||||
|
||||
// Create the div we want to get the max size for and set a max-width style
|
||||
var innerDiv = document.createElement('div');
|
||||
innerDiv.style.maxWidth = "50%";
|
||||
div.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumWidth(innerDiv)).toBe(100);
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
|
||||
it ('should get the maximum height of a node that has a percentage max-height style', function() {
|
||||
// Create div with fixed size as a test bed
|
||||
var div = document.createElement('div');
|
||||
div.style.width = "200px";
|
||||
div.style.height = "300px";
|
||||
|
||||
document.body.appendChild(div);
|
||||
|
||||
// Create the div we want to get the max size for and set a max-height style
|
||||
var innerDiv = document.createElement('div');
|
||||
innerDiv.style.maxHeight = "50%";
|
||||
div.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
|
||||
it ('should get the maximum width of a node when the parent has a percentage max-width style', function() {
|
||||
// Create div with fixed size as a test bed
|
||||
var div = document.createElement('div');
|
||||
div.style.width = "200px";
|
||||
div.style.height = "300px";
|
||||
|
||||
document.body.appendChild(div);
|
||||
|
||||
// Create an inner wrapper around our div we want to size and give that a max-width style
|
||||
var parentDiv = document.createElement('div');
|
||||
parentDiv.style.maxWidth = "50%";
|
||||
div.appendChild(parentDiv);
|
||||
|
||||
// Create the div we want to get the max size for
|
||||
var innerDiv = document.createElement('div');
|
||||
parentDiv.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumWidth(innerDiv)).toBe(100);
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
|
||||
it ('should get the maximum height of a node when the parent has a percentage max-height style', function() {
|
||||
// Create div with fixed size as a test bed
|
||||
var div = document.createElement('div');
|
||||
div.style.width = "200px";
|
||||
div.style.height = "300px";
|
||||
|
||||
document.body.appendChild(div);
|
||||
|
||||
// Create an inner wrapper around our div we want to size and give that a max-height style
|
||||
var parentDiv = document.createElement('div');
|
||||
parentDiv.style.maxHeight = "50%";
|
||||
div.appendChild(parentDiv);
|
||||
|
||||
var innerDiv = document.createElement('div');
|
||||
innerDiv.style.height = "300px"; // make it large
|
||||
parentDiv.appendChild(innerDiv);
|
||||
|
||||
expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
|
||||
|
||||
document.body.removeChild(div);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Tests of the scale service
|
||||
describe('Test the scale service', function() {
|
||||
describe('Test the layout service', function() {
|
||||
it('should fit a simple chart with 2 scales', function() {
|
||||
var chartInstance = {
|
||||
scales: [],
|
||||
boxes: [],
|
||||
};
|
||||
|
||||
var xScaleID = 'xScale';
|
||||
@@ -38,37 +38,37 @@ describe('Test the scale service', function() {
|
||||
id: yScaleID
|
||||
});
|
||||
|
||||
chartInstance.scales.push(xScale);
|
||||
chartInstance.scales.push(yScale);
|
||||
chartInstance.boxes.push(xScale);
|
||||
chartInstance.boxes.push(yScale);
|
||||
|
||||
var canvasWidth = 250;
|
||||
var canvasHeight = 150;
|
||||
Chart.scaleService.update(chartInstance, canvasWidth, canvasHeight);
|
||||
Chart.layoutService.update(chartInstance, canvasWidth, canvasHeight);
|
||||
|
||||
expect(chartInstance.chartArea).toEqual({
|
||||
left: 55,
|
||||
right: 245,
|
||||
top: 5,
|
||||
bottom: 75.0664716027288,
|
||||
left: 50,
|
||||
right: 250,
|
||||
top: 0,
|
||||
bottom: 81.0423977855504,
|
||||
});
|
||||
|
||||
// Is xScale at the right spot
|
||||
expect(xScale.left).toBe(55);
|
||||
expect(xScale.right).toBe(245);
|
||||
expect(xScale.top).toBe(75.0664716027288);
|
||||
expect(xScale.bottom).toBe(145);
|
||||
expect(xScale.labelRotation).toBe(57);
|
||||
expect(xScale.left).toBe(50);
|
||||
expect(xScale.right).toBe(250);
|
||||
expect(xScale.top).toBe(81.0423977855504);
|
||||
expect(xScale.bottom).toBe(150);
|
||||
expect(xScale.labelRotation).toBe(55);
|
||||
|
||||
// Is yScale at the right spot
|
||||
expect(yScale.left).toBe(5);
|
||||
expect(yScale.right).toBe(55);
|
||||
expect(yScale.top).toBe(5);
|
||||
expect(yScale.bottom).toBe(75.0664716027288);
|
||||
expect(yScale.left).toBe(0);
|
||||
expect(yScale.right).toBe(50);
|
||||
expect(yScale.top).toBe(0);
|
||||
expect(yScale.bottom).toBe(81.0423977855504);
|
||||
});
|
||||
|
||||
it('should fit scales that are in the top and right positions', function() {
|
||||
var chartInstance = {
|
||||
scales: [],
|
||||
boxes: [],
|
||||
};
|
||||
|
||||
var xScaleID = 'xScale';
|
||||
@@ -106,37 +106,37 @@ describe('Test the scale service', function() {
|
||||
id: yScaleID
|
||||
});
|
||||
|
||||
chartInstance.scales.push(xScale);
|
||||
chartInstance.scales.push(yScale);
|
||||
chartInstance.boxes.push(xScale);
|
||||
chartInstance.boxes.push(yScale);
|
||||
|
||||
var canvasWidth = 250;
|
||||
var canvasHeight = 150;
|
||||
Chart.scaleService.update(chartInstance, canvasWidth, canvasHeight);
|
||||
Chart.layoutService.update(chartInstance, canvasWidth, canvasHeight);
|
||||
|
||||
expect(chartInstance.chartArea).toEqual({
|
||||
left: 5,
|
||||
right: 195,
|
||||
top: 74.9335283972712,
|
||||
bottom: 145,
|
||||
left: 0,
|
||||
right: 200,
|
||||
top: 68.9576022144496,
|
||||
bottom: 150,
|
||||
});
|
||||
|
||||
// Is xScale at the right spot
|
||||
expect(xScale.left).toBe(5);
|
||||
expect(xScale.right).toBe(195);
|
||||
expect(xScale.top).toBe(5);
|
||||
expect(xScale.bottom).toBe(74.9335283972712);
|
||||
expect(xScale.labelRotation).toBe(57);
|
||||
expect(xScale.left).toBe(0);
|
||||
expect(xScale.right).toBe(200);
|
||||
expect(xScale.top).toBe(0);
|
||||
expect(xScale.bottom).toBe(68.9576022144496);
|
||||
expect(xScale.labelRotation).toBe(55);
|
||||
|
||||
// Is yScale at the right spot
|
||||
expect(yScale.left).toBe(195);
|
||||
expect(yScale.right).toBe(245);
|
||||
expect(yScale.top).toBe(74.9335283972712);
|
||||
expect(yScale.bottom).toBe(145);
|
||||
expect(yScale.left).toBe(200);
|
||||
expect(yScale.right).toBe(250);
|
||||
expect(yScale.top).toBe(68.9576022144496);
|
||||
expect(yScale.bottom).toBe(150);
|
||||
});
|
||||
|
||||
it('should fit multiple axes in the same position', function() {
|
||||
var chartInstance = {
|
||||
scales: [],
|
||||
boxes: [],
|
||||
};
|
||||
|
||||
var xScaleID = 'xScale';
|
||||
@@ -184,37 +184,37 @@ describe('Test the scale service', function() {
|
||||
id: yScaleID2
|
||||
});
|
||||
|
||||
chartInstance.scales.push(xScale);
|
||||
chartInstance.scales.push(yScale1);
|
||||
chartInstance.scales.push(yScale2);
|
||||
chartInstance.boxes.push(xScale);
|
||||
chartInstance.boxes.push(yScale1);
|
||||
chartInstance.boxes.push(yScale2);
|
||||
|
||||
var canvasWidth = 250;
|
||||
var canvasHeight = 150;
|
||||
Chart.scaleService.update(chartInstance, canvasWidth, canvasHeight);
|
||||
Chart.layoutService.update(chartInstance, canvasWidth, canvasHeight);
|
||||
|
||||
expect(chartInstance.chartArea).toEqual({
|
||||
left: 115,
|
||||
right: 245,
|
||||
top: 5,
|
||||
bottom: 68.48521368620018,
|
||||
left: 110,
|
||||
right: 250,
|
||||
top: 0,
|
||||
bottom: 75,
|
||||
});
|
||||
|
||||
// Is xScale at the right spot
|
||||
expect(xScale.left).toBe(115);
|
||||
expect(xScale.right).toBe(245);
|
||||
expect(xScale.top).toBe(68.48521368620018);
|
||||
expect(xScale.bottom).toBe(145);
|
||||
expect(xScale.left).toBe(110);
|
||||
expect(xScale.right).toBe(250);
|
||||
expect(xScale.top).toBe(75);
|
||||
expect(xScale.bottom).toBe(150);
|
||||
|
||||
// Are yScales at the right spot
|
||||
expect(yScale1.left).toBe(5);
|
||||
expect(yScale1.right).toBe(55);
|
||||
expect(yScale1.top).toBe(5);
|
||||
expect(yScale1.bottom).toBe(68.48521368620018);
|
||||
expect(yScale1.left).toBe(0);
|
||||
expect(yScale1.right).toBe(50);
|
||||
expect(yScale1.top).toBe(0);
|
||||
expect(yScale1.bottom).toBe(75);
|
||||
|
||||
expect(yScale2.left).toBe(55);
|
||||
expect(yScale2.right).toBe(115);
|
||||
expect(yScale2.top).toBe(5);
|
||||
expect(yScale2.bottom).toBe(68.48521368620018);
|
||||
expect(yScale2.left).toBe(50);
|
||||
expect(yScale2.right).toBe(110);
|
||||
expect(yScale2.top).toBe(0);
|
||||
expect(yScale2.bottom).toBe(75);
|
||||
});
|
||||
|
||||
// This is an oddball case. What happens is, when the scales are fit the first time they must fit within the assigned size. In this case,
|
||||
@@ -223,7 +223,7 @@ describe('Test the scale service', function() {
|
||||
// due to the lack of label rotation
|
||||
it('should fit scales that overlap the chart area', function() {
|
||||
var chartInstance = {
|
||||
scales: [],
|
||||
boxes: [],
|
||||
};
|
||||
|
||||
var scaleID = 'scaleID';
|
||||
@@ -250,24 +250,111 @@ describe('Test the scale service', function() {
|
||||
id: scaleID
|
||||
});
|
||||
|
||||
chartInstance.scales.push(scale);
|
||||
chartInstance.boxes.push(scale);
|
||||
|
||||
var canvasWidth = 300;
|
||||
var canvasHeight = 350;
|
||||
Chart.scaleService.update(chartInstance, canvasWidth, canvasHeight);
|
||||
Chart.layoutService.update(chartInstance, canvasWidth, canvasHeight);
|
||||
|
||||
expect(chartInstance.chartArea).toEqual({
|
||||
left: 5,
|
||||
right: 295,
|
||||
top: 5,
|
||||
bottom: 345,
|
||||
left: 0,
|
||||
right: 300,
|
||||
top: 0,
|
||||
bottom: 350,
|
||||
});
|
||||
|
||||
expect(scale.left).toBe(5);
|
||||
expect(scale.right).toBe(295);
|
||||
expect(scale.top).toBe(5);
|
||||
expect(scale.bottom).toBe(345);
|
||||
expect(scale.width).toBe(290);
|
||||
expect(scale.height).toBe(340)
|
||||
expect(scale.left).toBe(0);
|
||||
expect(scale.right).toBe(300);
|
||||
expect(scale.top).toBe(0);
|
||||
expect(scale.bottom).toBe(350);
|
||||
expect(scale.width).toBe(300);
|
||||
expect(scale.height).toBe(350)
|
||||
});
|
||||
|
||||
it ('should fix a full width box correctly', function() {
|
||||
var chartInstance = {
|
||||
boxes: [],
|
||||
};
|
||||
|
||||
var xScaleID1= 'xScale1';
|
||||
var xScaleID2 = 'xScale2';
|
||||
var yScaleID = 'yScale2';
|
||||
|
||||
var mockData = {
|
||||
datasets: [{
|
||||
xAxisID: xScaleID1,
|
||||
data: [10, 5, 0, 25, 78, -10]
|
||||
}, {
|
||||
xAxisID: xScaleID2,
|
||||
data: [-19, -20, 0, -99, -50, 0]
|
||||
}],
|
||||
labels: ['tick1', 'tick2', 'tick3', 'tick4', 'tick5']
|
||||
};
|
||||
var mockContext = window.createMockContext();
|
||||
|
||||
var xScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('category'));
|
||||
var XConstructor = Chart.scaleService.getScaleConstructor('category');
|
||||
var xScale1 = new XConstructor({
|
||||
ctx: mockContext,
|
||||
options: xScaleConfig,
|
||||
chart: {
|
||||
data: mockData
|
||||
},
|
||||
id: xScaleID1
|
||||
});
|
||||
var xScale2 = new XConstructor({
|
||||
ctx: mockContext,
|
||||
options: Chart.helpers.extend(Chart.helpers.clone(xScaleConfig), {
|
||||
position: 'top',
|
||||
fullWidth: true
|
||||
}),
|
||||
chart: {
|
||||
data: mockData,
|
||||
},
|
||||
id: xScaleID2
|
||||
});
|
||||
|
||||
var yScaleConfig = Chart.helpers.clone(Chart.scaleService.getScaleDefaults('linear'));
|
||||
var YConstructor = Chart.scaleService.getScaleConstructor('linear');
|
||||
var yScale = new YConstructor({
|
||||
ctx: mockContext,
|
||||
options: yScaleConfig,
|
||||
chart: {
|
||||
data: mockData
|
||||
},
|
||||
id: yScaleID
|
||||
});
|
||||
|
||||
chartInstance.boxes.push(xScale1);
|
||||
chartInstance.boxes.push(xScale2);
|
||||
chartInstance.boxes.push(yScale);
|
||||
|
||||
var canvasWidth = 250;
|
||||
var canvasHeight = 150;
|
||||
Chart.layoutService.update(chartInstance, canvasWidth, canvasHeight);
|
||||
|
||||
expect(chartInstance.chartArea).toEqual({
|
||||
left: 60,
|
||||
right: 250,
|
||||
top: 54.495963211660246,
|
||||
bottom: 80.0664716027288,
|
||||
});
|
||||
|
||||
// Are xScales at the right spot
|
||||
expect(xScale1.left).toBe(60);
|
||||
expect(xScale1.right).toBe(250);
|
||||
expect(xScale1.top).toBeCloseTo(80.06, 1e-3);
|
||||
expect(xScale1.bottom).toBe(150);
|
||||
|
||||
expect(xScale2.left).toBe(0);
|
||||
expect(xScale2.right).toBe(250);
|
||||
expect(xScale2.top).toBe(0);
|
||||
expect(xScale2.bottom).toBeCloseTo(54.49, 1e-3);
|
||||
|
||||
// Is yScale at the right spot
|
||||
expect(yScale.left).toBe(0);
|
||||
expect(yScale.right).toBe(60);
|
||||
expect(yScale.top).toBeCloseTo(54.49, 1e-3);
|
||||
expect(yScale.bottom).toBeCloseTo(80.06, 1e-3);
|
||||
});
|
||||
});
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário