Compare commits

..

150 Commits

Author SHA1 Message Date
Kevin Jahns
fa3c92f44c change parameter order of transaction events 2019-04-19 23:36:00 +02:00
Kevin Jahns
cd82de7742 lint 2019-04-12 20:08:38 +02:00
Kevin Jahns
07a6a0044b simplify exposed APi 2019-04-12 20:04:07 +02:00
Kevin Jahns
4582832a71 rework intro 2019-04-12 14:24:31 +02:00
Kevin Jahns
07ac1d03e3 fix jsdoc 2019-04-11 23:34:56 +02:00
Kevin Jahns
cbcf1facb8 remove todo.md 2019-04-11 17:35:09 +02:00
Kevin Jahns
31ff7ac78c improve jsdoc comments 2019-04-11 13:22:59 +02:00
Kevin Jahns
ed3b31e58f jsdoc fixes 2019-04-11 00:49:07 +02:00
Kevin Jahns
759ecb21f7 rename transaction._replacedItems to transaction._mergeStructs 2019-04-11 00:31:43 +02:00
Kevin Jahns
9c29d820c8 rename AbstractRef to AbstractStructRef 2019-04-11 00:26:42 +02:00
Kevin Jahns
2ef11a5344 splitting an item must always happen inside a transaction, because we always need to check if we can merge it back 2019-04-11 00:23:08 +02:00
Kevin Jahns
9fe47e98d5 type._map points to the last element instead to enable merging of deletes in Map 2019-04-10 21:01:59 +02:00
Kevin Jahns
654510f3ff read struct refs as array 2019-04-10 18:52:22 +02:00
Kevin Jahns
52ec698635 implement some of the commented todos 2019-04-09 04:01:37 +02:00
Kevin Jahns
1b06f59d1c fixed remaining tests 2019-04-09 00:48:24 +02:00
Kevin Jahns
12bcc4d080 fix remaining random tests 2019-04-09 00:31:28 +02:00
Kevin Jahns
e1a9f314a7 fixed part of split/merge logic 2019-04-08 13:41:28 +02:00
Kevin Jahns
7a111de186 refactor read/write of structs 2019-04-07 23:08:08 +02:00
Kevin Jahns
90b3fa9dd9 fixed merging and adapted writeStructs to write end of message 2019-04-07 12:47:04 +02:00
Kevin Jahns
c635963747 Compare origin ids in item.integrate 2019-04-06 15:55:20 +02:00
Kevin Jahns
1b17b5e400 fixed 10 tests 2019-04-06 13:00:32 +02:00
Kevin Jahns
61d9d96d15 fix replace with delete 2019-04-05 21:06:43 +02:00
Kevin Jahns
7d0c048708 Items accept origins as IDs 2019-04-05 19:46:18 +02:00
Kevin Jahns
8a7416ad50 Create Structs based on offset, if necessary
implement offset parameter in Ref.toStruct
2019-04-05 12:38:02 +02:00
Kevin Jahns
e56899a02c after refactor - some tests are working again 2019-04-05 00:37:09 +02:00
Kevin Jahns
30bf3742c9 add internals file and use it to organize imports 2019-04-04 19:35:38 +02:00
Kevin Jahns
8dbd2c4696 restructure EventHandler 2019-04-04 13:50:00 +02:00
Kevin Jahns
6578727c9c fixed all type issues 2019-04-03 13:23:27 +02:00
Kevin Jahns
92ca001cdc implement getMap, getArray, getXml, .. 2019-04-03 03:08:10 +02:00
Kevin Jahns
415de1cc4c all YArray.tests type fixes 2019-04-03 02:30:44 +02:00
Kevin Jahns
e23582b1cd more type fixes and rethinking writeStructs 2019-04-02 23:08:58 +02:00
Kevin Jahns
73c28952c2 fix all types but yxmlelement 2019-03-30 11:00:54 +01:00
Kevin Jahns
1bc1e88d6a fix y-text 2019-03-30 01:08:09 +01:00
Kevin Jahns
c188f813a4 fixed YMap 2019-03-29 13:49:13 +01:00
Kevin Jahns
ff981a8697 fixed YArray 2019-03-29 01:03:02 +01:00
Kevin Jahns
d9ab593b07 prelim refactor commit 2019-03-26 01:14:15 +01:00
Kevin Jahns
293527e62b fix a few tsc errors (96 remaining) 2019-03-13 02:15:43 +01:00
Kevin Jahns
5a42a94cf4 add typescript to lint script 2019-03-13 01:49:51 +01:00
Kevin Jahns
040808300c clean up build script - no more warnings 2019-03-13 01:16:31 +01:00
Kevin Jahns
57975d409e cleanup dependencies 2019-03-13 00:22:38 +01:00
Kevin Jahns
306b2c64f3 Merge branch 'master' of https://github.com/y-js/yjs 2019-03-13 00:04:42 +01:00
Kevin Jahns
585265e9a5 refactor and remove dependency circles 2019-03-13 00:04:19 +01:00
Kevin Jahns
777ae9503a Merge pull request #142 from mtn/mtn-patch-1
Correct typo in README example
2019-03-12 03:36:51 +01:00
Kevin Jahns
4c1798e5fa fix all remaining tests (xml tests) 2019-03-12 01:42:51 +01:00
Kevin Jahns
f4d85e2a3e fix y-text tests 2019-03-12 01:22:06 +01:00
Kevin Jahns
a0f0c9c377 testing: use lib0.testing.compare to compare Maps and sets 2019-03-11 18:34:50 +01:00
Kevin Jahns
95ec2a435a fix remaining y-map tests 2019-03-11 17:52:51 +01:00
Kevin Jahns
da9836fe59 added all y-map tests 2019-03-11 12:31:37 +01:00
Kevin Jahns
3a7411f9e8 reworked some ymap tests (a few are running again) 2019-03-11 00:00:41 +01:00
Kevin Jahns
39cee7c6e7 refix array tests and switch to lib0 2019-03-10 23:26:53 +01:00
Kevin Jahns
0a5753c191 decode items before they are decoded. fixes lots of y-array tests 2019-03-07 18:57:39 +01:00
Kevin Jahns
76b7d0b651 fixed some issues in random tests 2019-03-06 13:29:16 +01:00
Kevin Jahns
99e3e95a00 added remaining y-array tests (random still failing) 2019-03-05 14:00:31 +01:00
Kevin Jahns
93ee4ee287 converted first y-array test to funlib/testing 2019-03-04 14:28:18 +01:00
Kevin Jahns
c5cc403a29 update test commands 2019-03-01 23:45:09 +01:00
Kevin Jahns
75f4a0a5f0 restructuring the project 2019-03-01 23:28:11 +01:00
Michael Noronha
591df5c00a Correct typo in README example
/bower_components -> ./bower_components
2019-02-23 17:30:05 -06:00
Kevin Jahns
f6b4819ae3 prosemirror: implement isChangeOrigin in state 2019-01-31 09:50:52 +01:00
Kevin Jahns
d483d9cc83 13.0.0-78 2019-01-29 01:38:40 +01:00
Kevin Jahns
453407b93d fix connection status and awareness info when disconnected (ws-provider) 2019-01-29 01:38:23 +01:00
Kevin Jahns
e699f92333 13.0.0-77 2019-01-29 00:56:15 +01:00
Kevin Jahns
6ff47719ef Merge branch 'master' of github.com:y-js/yjs 2019-01-29 00:55:22 +01:00
Kevin Jahns
3a0694c35c added utilities to make and recover snapshots 2019-01-29 00:54:58 +01:00
Kevin Jahns
74e5243742 Merge pull request #138 from calibr/yjs
updating YArray's iterator to iterate Types correctly
2019-01-23 11:00:37 +01:00
calibr
dcf43b9797 switch to the next item in YArray's iterator after processing a Type item 2019-01-16 03:12:58 +03:00
Kevin Jahns
77e479c03b working on snapshotting and version history 2019-01-09 23:54:36 +01:00
Kevin Jahns
ec58a99748 add clock vector to awareness protocol 2018-12-22 15:51:09 +01:00
Kevin Jahns
f1eb66655b implemented leveldb persistence for websocket server 2018-12-22 13:45:59 +01:00
Kevin Jahns
7f4ae9fe14 implemented codemirror binding with cursor support 2018-12-21 13:51:38 +01:00
Kevin Jahns
c0ba56a21f update v13 docs 2018-12-19 01:12:29 +01:00
Kevin Jahns
4063e28b5e 13.0.0-76 2018-12-11 20:19:07 +01:00
Kevin Jahns
b6f7cd7869 fix broadcast channel communication 2018-12-11 20:18:11 +01:00
Kevin Jahns
1a79e429ed 13.0.0-75 2018-12-11 19:49:50 +01:00
Kevin Jahns
04066a5678 permission protocol + reduce circular dependencies 2018-12-11 19:49:21 +01:00
Kevin Jahns
e09ef15349 13.0.0-74 2018-12-04 18:07:04 +01:00
Kevin Jahns
3d70eee959 item: increase parent length only if parentSub=null 2018-12-03 23:09:59 +01:00
Kevin Jahns
582095e5a3 improved granularity of prosemirror binding 2018-12-03 17:09:00 +01:00
Kevin Jahns
c9ea3a412e more efficient length computing 2018-11-28 13:20:14 +01:00
Kevin Jahns
a2c51c36e9 implement generic broadcastchannel and apply it to websocket provider 2018-11-27 18:29:25 +01:00
Kevin Jahns
ab3dba5b06 add source file info to examples 2018-11-27 15:24:58 +01:00
Kevin Jahns
3ddff186c2 back to .js extension 2018-11-27 14:59:24 +01:00
Kevin Jahns
9bd199a6e7 add description to each example 2018-11-27 00:57:15 +01:00
Kevin Jahns
01d0825ae6 13.0.0-73 2018-11-26 17:14:48 +01:00
Kevin Jahns
e2f98525d2 clean examples build 2018-11-26 17:14:45 +01:00
Kevin Jahns
70a0a03130 no start content in prosemirror example 2018-11-26 16:59:01 +01:00
Kevin Jahns
656d85c62e add dom example 2018-11-26 16:06:17 +01:00
Kevin Jahns
e168dd48fb proper api endpoints for examples 2018-11-26 14:54:46 +01:00
Kevin Jahns
12d43199d5 add http listener to websocket-server 2018-11-26 13:08:23 +01:00
Kevin Jahns
539fa8b21d examples use hosted server 2018-11-26 02:13:06 +01:00
Kevin Jahns
f572f94586 port support 2018-11-25 23:41:17 +01:00
Kevin Jahns
c12d00b227 mjs nodejs support 2018-11-25 22:39:50 +01:00
Kevin Jahns
e4a5f2caec jsdoc fixes 2018-11-25 05:43:18 +01:00
Kevin Jahns
9f9f465238 update logo link 2018-11-25 04:50:23 +01:00
Kevin Jahns
8450ff86d7 make npm build ready for netlify 2018-11-25 04:41:52 +01:00
Kevin Jahns
70139262c5 add rollup-cli as dependency 2018-11-25 03:36:06 +01:00
Kevin Jahns
9c0da271eb large scale refactoring 2018-11-25 03:17:00 +01:00
Kevin Jahns
ade3e1949d update cdn destination. closes #128 2018-11-20 15:03:28 +01:00
Kevin Jahns
eec63a008f 13.0.0-72 2018-11-20 03:53:55 +01:00
Kevin Jahns
52abcdd043 fix all tests 2018-11-16 12:33:41 +01:00
Kevin Jahns
f94653424a add prosemirror tests 2018-11-14 07:20:06 +01:00
Kevin Jahns
d67a794e2c 13.0.0-71 2018-11-09 01:49:59 +01:00
Kevin Jahns
60318083a6 make websocket-server a binary and add bindings and provider to npm package 2018-11-09 01:49:43 +01:00
Kevin Jahns
7607070452 13.0.0-70 2018-11-09 01:24:06 +01:00
Kevin Jahns
28fb7b6e9c remove logging in prosemirror binding 2018-11-09 01:23:16 +01:00
Kevin Jahns
aafe15757f implemented awareness protocol and added cursor support 2018-11-09 00:13:30 +01:00
Kevin Jahns
31d6ef6296 cleanup prosemirror example 2018-11-06 15:15:27 +01:00
Kevin Jahns
32b8fac37f added prosemirror binding 2018-11-06 13:44:35 +01:00
Kevin Jahns
e8060de914 13.0.0-69 2018-11-02 01:54:53 +01:00
Kevin Jahns
22b036527c further refine build process to also include lib 2018-11-02 01:54:40 +01:00
Kevin Jahns
feb1e030d7 13.0.0-68 2018-11-02 01:52:24 +01:00
Kevin Jahns
bd271e3952 update publish process 2018-11-02 01:52:20 +01:00
Kevin Jahns
df80938190 13.0.0-67 2018-11-02 00:47:09 +01:00
Kevin Jahns
67bbc0a3fe implemented websocket provider 2018-10-30 00:51:09 +01:00
Kevin Jahns
e1ece6dc66 refactoring: removed default connector and persistence, new code style, proper jsdocs, enabled typechecking 2018-10-29 21:58:21 +01:00
Kevin Jahns
fe038822a3 Merge branch 'ydb-integration' of https://github.com/y-js/yjs into ydb-integration 2018-10-22 12:23:47 +02:00
Kevin Jahns
dece14486c start refactoring 2018-10-22 12:23:35 +02:00
Kevin Jahns
2daffbc2ca implement syncstate 2018-10-17 15:14:47 +02:00
Kevin Jahns
4c01a34d09 integrate ydb client and adapt some demos 2018-10-13 14:38:29 +02:00
Kevin Jahns
3b08267daa merge experimental-connectors 2018-10-08 17:11:18 +02:00
Kevin
b98ebddb69 ydb client 2018-10-08 16:09:50 +02:00
Kevin Jahns
9d5bf50676 13.0.0-66 2018-07-17 18:50:03 +02:00
Kevin Jahns
c0972f8158 reset selection also for local transactions 2018-07-17 18:49:28 +02:00
Kevin Jahns
548125a944 13.0.0-65 2018-07-16 18:38:09 +02:00
Kevin Jahns
a7b124ca6e 13.0.0-64 2018-07-16 18:19:36 +02:00
Kevin Jahns
4022374620 dombinding: always set browser range after change 2018-07-16 18:15:24 +02:00
Kevin Jahns
860e4d7af6 13.0.0-63 2018-06-23 00:30:45 +02:00
Kevin Jahns
6376d69b58 fix undo of map update 2018-06-23 00:29:44 +02:00
Kevin Jahns
5cf6f45f19 13.0.0-62 2018-06-13 00:08:01 +02:00
Kevin Jahns
967903673b fixed undo/redo issues and implemented ability to manually flush the UndoManager 2018-06-13 00:06:38 +02:00
Kevin Jahns
2d897f1844 add function to create lots of rooms 2018-06-07 16:36:42 +02:00
Kevin Jahns
fb2f9bc493 add client-server updateCounter support to sync all persisted rooms 2018-06-04 17:35:39 +02:00
Kevin Jahns
6f9ae0c4fc save current state at the beginning in YIndexedDB 2018-06-03 22:39:22 +02:00
Kevin Jahns
9df20fac8a added YIndexedDB 2018-06-03 21:58:51 +02:00
Kevin Jahns
a1fb1a6258 add persistence decoder 2018-06-02 22:16:12 +02:00
Kevin Jahns
417d0ef3b5 save state in FilePersistence 2018-06-02 13:33:04 +02:00
Kevin Jahns
9be256231b enable gc in demo 2018-05-23 16:15:11 +02:00
Kevin Jahns
c122bdc750 BinaryEncoder writes directly to ArrayBuffer, improves memory consumption 2018-05-23 16:06:38 +02:00
Kevin Jahns
4ef36ab81c fix tests 2018-05-23 14:16:54 +02:00
Kevin Jahns
cccc0e1015 implemented experimental websockets-connector 2018-05-23 14:01:00 +02:00
Kevin Jahns
db5312443e 13.0.0-61 2018-05-18 02:02:44 +02:00
Kevin Jahns
dbda07424b fix DomBinding destroy 2018-05-18 02:01:53 +02:00
Kevin Jahns
684d38d6c8 make compatible with webpack and less sophisticated module bundlers 2018-05-13 13:07:24 +02:00
Kevin Jahns
44fa064eb2 Merge branch 'master' of github.com:y-js/yjs 2018-05-12 16:43:28 +02:00
Kevin Jahns
9b6fffd880 Add rollup dependency - closes #110 2018-05-12 16:43:05 +02:00
Kevin Jahns
e9993b2643 Merge pull request #111 from larskarbo/patch-1
(DOCS) Remove y-array duplicates
2018-05-12 16:41:14 +02:00
Kevin Jahns
762e9e8a3a do not log _start in logItemHelper. Fixes #114 2018-05-12 15:42:31 +02:00
Kevin Jahns
6ddeb788c7 Merge branch 'master' of github.com:y-js/yjs 2018-05-09 16:28:07 +02:00
Kevin Jahns
b9245f323c prefer !== undefined check instead of hasOwnProperty 2018-05-09 16:27:55 +02:00
Kevin Jahns
c0e630b635 prefer parentElement instead of parentNode 2018-05-09 14:42:24 +02:00
Lars Karbo
ed2273e2ed Remove y-array duplicates 2018-04-24 12:59:51 -07:00
183 changed files with 13797 additions and 57063 deletions

View File

@@ -1,12 +0,0 @@
{
"presets": [
["latest", {
"es2015": {
"modules": false
}
}]
],
"plugins": [
"external-helpers"
]
}

View File

@@ -1,10 +0,0 @@
{
"source": "./src",
"destination": "./docs",
"plugins": [{
"name": "esdoc-standard-plugin",
"option": {
"accessor": {"access": ["public"], "autoPrivate": true}
}
}]
}

View File

@@ -1,14 +0,0 @@
[ignore]
.*/node_modules/.*
.*/dist/.*
.*/build/.*
[include]
./src/
./tests-lib/
./test/
[libs]
./declarations/
[options]

5
.gitignore vendored
View File

@@ -1,5 +1,4 @@
node_modules
bower_components
dist
.vscode
docs
/y.*
/examples/yjs-dist.js*

50
.jsdoc.json Normal file
View File

@@ -0,0 +1,50 @@
{
"sourceType": "module",
"tags": {
"allowUnknownTags": true,
"dictionaries": ["jsdoc"]
},
"source": {
"include": ["./src"],
"includePattern": ".js$"
},
"plugins": [
"plugins/markdown"
],
"templates": {
"referenceTitle": "Yjs",
"disableSort": false,
"useCollapsibles": true,
"collapse": true,
"resources": {
"y-js.org": "yjs.website"
},
"logo": {
"url": "https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png",
"width": "162px",
"height": "162px",
"link": "/"
},
"tabNames": {
"api": "API",
"tutorials": "Examples"
},
"footerText": "Shared Editing",
"css": [
"./style.css"
],
"default": {
"staticFiles": {
"include": ["examples/"]
}
}
},
"opts": {
"destination": "./docs/",
"encoding": "utf8",
"private": false,
"recurse": true,
"template": "./node_modules/tui-jsdoc-template",
"tutorials": "./examples"
}
}

View File

@@ -1,5 +1,5 @@
# ![Yjs](http://y-js.org/images/yjs.png)
# ![Yjs](https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png)
Yjs is a framework for offline-first p2p shared editing on structured data like
text, richtext, json, or XML. It is fairly easy to get started, as Yjs hides
@@ -66,11 +66,10 @@ missing modules.
### CDN
```
<script src="https://cdn.jsdelivr.net/npm/yjs@12/src/y.js"></script>
<script src="https://cdn.jsdelivr.net/npm/yjs@12/dist/y.js"></script>
<script src="https://cdn.jsdelivr.net/npm/y-array@10/dist/y-array.js"></script>
<script src="https://cdn.jsdelivr.net/npm/y-websockets-client@8/dist/y-websockets-client.js"></script>
<script src="https://cdn.jsdelivr.net/npm/y-memory@8/dist/y-memory.js"></script>
<script src="https://cdn.jsdelivr.net/npm/y-array@10/dist/y-array.js"></script>
<script src="https://cdn.jsdelivr.net/npm/y-map@10/dist/y-map.js"></script>
<script src="https://cdn.jsdelivr.net/npm/y-text@9/dist/y-text.js"></script>
// ..
@@ -89,7 +88,6 @@ var Y = require('yjs')
require('y-array')(Y) // add the y-array type to Yjs
require('y-websockets-client')(Y)
require('y-memory')(Y)
require('y-array')(Y)
require('y-map')(Y)
require('y-text')(Y)
// ..
@@ -102,7 +100,6 @@ import Y from 'yjs'
import yArray from 'y-array'
import yWebsocketsClient from 'y-webrtc'
import yMemory from 'y-memory'
import yArray from 'y-array'
import yMap from 'y-map'
import yText from 'y-text'
// ..
@@ -134,7 +131,7 @@ Here is a simple example of a shared textarea
// name: 'xmpp'
room: 'my-room' // clients connecting to the same room share data
},
sourceDir: '/bower_components', // location of the y-* modules (browser only)
sourceDir: './bower_components', // location of the y-* modules (browser only)
share: {
textarea: 'Text' // y.share.textarea is of type y-text
}
@@ -251,7 +248,7 @@ The promise returns an instance of Y. We denote it with a lower case `y`.
* y-websockets-client aways waits to sync with the server
* y.connector.disconnect()
* Force to disconnect this instance from the other instances
* y.connector.reconnect()
* y.connector.connect()
* Try to reconnect to the other instances (needs to be supported by the
connector)
* Not supported by y-xmpp

370
README.v13.md Normal file
View File

@@ -0,0 +1,370 @@
# ![Yjs](https://user-images.githubusercontent.com/5553757/48975307-61efb100-f06d-11e8-9177-ee895e5916e5.png)
> The shared editing library
Yjs is a library for automatic conflict resolution on shared state. It implements an operation-based CRDT and exposes its internal CRDT model as shared types. Shared types are common data types like `Map` or `Array` with superpowers - changes are automatically distributed to other peers and merged without merge conflicts.
Yjs is **network agnostic** (p2p!), supports many existing **rich text editors**, **offline editing**, **version snapshots**, **shared cursors**, and encodes update messages using **binary protocol encoding**.
* Chat: [https://gitter.im/y-js/yjs](https://gitter.im/y-js/yjs)
* Demos: [https://yjs.website/tutorial-prosemirror.html](https://yjs.website/tutorial-prosemirror.html)
* API Docs: [https://yjs.website/](https://yjs.website/)
### Supported Editors:
| Name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Cursors | Binding | Demo |
|---|:-:|---|---|
| [ProseMirror](https://prosemirror.net/) | ✔ | [y-prosemirror](http://github.com/y-js/y-prosemirror) | [link](https://yjs.website/tutorial-prosemirror.html) |
| [Quill](https://quilljs.com/) | | [y-quill](http://github.com/y-js/y-quill) | [link](https://yjs.website/tutorial-quill.html) |
| [CodeMirror](https://codemirror.net/) | ✔ | [y-codemirror](http://github.com/y-js/y-codemirror) | [link](https://yjs.website/tutorial-codemirror.html) |
| [Ace](https://ace.c9.io/) | | [y-ace](http://github.com/y-js/y-ace) | [link]() |
| [Monaco](https://microsoft.github.io/monaco-editor/) | | [y-monaco](http://github.com/y-js/y-monaco) | [link]() |
### Providers
Setting up the communication between clients, managing awareness information, and storing shared data for offline usage is quite a hassle. *Providers* manage all that for you and are a good off-the-shelf solution
* [y-websockets](http://github.com/y-js/y-websockets)
* [y-webrtc](http://github.com/y-js/y-webrtc)
* [y-dat](http://github.com/y-js/y-dat)
### Shared Types
# Table of Contents
* [Getting Started](#Getting-Started)
* [Tutorial](#Short-Tutorial)
* [Providers](#Providers)
* [Websocket](#Websocket)
* [Ydb](#Ydb)
* [Create a Custom Provider](#Create-a-Custom-Provider)
* [Shared Types](#Shared-Types)
* [YArray](#Yarray)
* [YMap](#YMap)
* [YText](#YText)
* [YXmlFragment and YXmlElement](#YXmlFragment-and-YXmlElement)
* [Create a Custom Type](#Create-a-Custom-Type)
* [Bindings](#Bindings)
* [PromeMirror](#ProseMirror)
* [Quill](#Quill)
* [CodeMirror](#CodeMirror)
* [Ace](#Ace)
* [Monaco](#Monace)
* [DOM](#DOM)
* [Textarea](#Textarea)
* [Create a Custom Binding](#Create-a-Custom-Binding)
* [Transaction](#Transaction)
* [Offline Editing](#Offline-Editing)
* [Awareness](#Awareness)
* [Working with Yjs](#Working-with-Yjs)
* [Typescript Declarations](#Typescript-Declarations)
* [Binary Protocols](#Binary-Protocols)
* [Sync Protocol](#Sync-Protocols)
* [Awareness Protocol](#Awareness-Protocols)
* [Auth Protocol](#Auth-Protocol)
* [Yjs CRDT Algorithm](#Yjs-CRDT-Algorithm)
* [Evaluation](#Evaluation)
* [Existing shared editing libraries](#Exisisting-Javascript-Products)
* [CRDT Algorithms](#CRDT-Algorithms)
* [Comparison of CRDT with OT](#Comparing-CRDT-with-OT)
* [Comparison of CRDT Algorithms](#Comparing-CRDT-Algorithms)
* [Comparison of Yjs with other Implementations](#Comparing-Yjs-with-other-Implementations)
* [License and Author](#License-and-Author)
## Getting Started
Yjs does not hava any dependencies. Install this package with your favorite package manager, or just copy the files into your project.
```sh
npm i yjs
```
##### Quickstart
Yjs itself only knows how to do conflict resolution. You need to choose a provider, that handles how document updates are distributed over the network.
We will start by running a websocket server (part of the [websocket provider](#Websocket-Provider)):
```sh
PORT=1234 node ./node_modules/yjs/provider/websocket/server.js
```
The following client-side code connects to the websocket server and opens a shared document.
```js
import * as Y from 'yjs'
import { WebsocketProvider } from 'yjs/provider/websocket.js'
const provider = new WebsocketProvider('http://localhost:1234')
const sharedDocument = provider.get('my-favourites')
```
All content created in a shared document is shared among all peers that request the same document. Now we define types on the shared document:
```js
sharedDocument.define('movie-ratings', Y.Map)
sharedDocument.define('favourite-food', Y.Array)
```
All clients that define `'movie-ratings'` as `Y.Map` on the shared document named `'my-favourites'` have access to the same shared type. Example:
**Client 1:**
```js
sharedDocument.define('movie-ratings', Y.Map)
sharedDocument.define('favourite-food', Y.Array)
const movies = sharedDocument.get('movie-ratings')
const food = sharedDocument.get('fovourite-food')
movies.set('deadpool', 10)
food.insert(0, ['burger'])
```
**Client 2:**
```js
sharedDocument.define('movie-ratings', Y.Map)
sharedDocument.define('favourite-food', Y.Map) // <- note that this definition differs from client1
const movies = sharedDocument.get('movie-ratings')
const food = sharedDocument.get('fovourite-food')
movies.set('yt rewind', -10)
food.set('pancake', 10)
// after some time, when client1 and client2 synced, the movie list will be merged:
movies.toJSON() // => { 'deadpool': 10, 'yt rewind': -10 }
// But since client1 and client2 defined the types differently,
// they do not have access to each others food list.
food.toJSON() // => { pancake: 10 }
```
Now you understand how types are defined on a shared document. Next you can jump to one of the [tutorials on our website](https://yjs.website/tutorial-prosemirror.html) or continue reading about [Providers](#Providers), [Shared Types](#Shared-Types), and [Bindings](#Bindings).
## API
## Providers
In Yjs, a provider handles the communication channel to *authenticate*, *authorize*, and *exchange document updates*. Yjs ships with some existing providers.
### Websocket Provider
The websocket provider implements a classical client server model. Clients connect to a single endpoint over websocket. The server distributes awareness information and document updates among clients.
The Websocket Provider is a solid choice if you want a central source that handles authentication and authorization. Websockets also send header information and cookies, so you can use existing authentication mechanisms with this server. I recommend that you slightly adapt the server in `./provider/websocket/server.js` to your needs.
* Supports cross-tab communication. When you open the same document in the same browser, changes on the document are exchanged via cross-tab communication ([Broadcast Channel](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API) and [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) as fallback).
* Supports exange of awareness information (e.g. cursors)
##### Start a Websocket Server:
```sh
PORT=1234 node ./node_modules/yjs/provider/websocket/server.js
```
**Websocket Server with Persistence**
Persist document updates in a LevelDB database.
See [LevelDB Persistence](#LevelDB Persistence) for more info.
```sh
PORT=1234 YPERSISTENCE=./dbDir node ./node_modules/yjs/provider/websocket/server.js
```
##### Client Code:
```js
import * as Y from 'yjs'
import { WebsocketProvider } from 'yjs/provider/websocket.js'
const provider = new WebsocketProvider('http://localhost:1234')
// open a websocket connection to http://localhost:1234/my-document-name
const sharedDocument = provider.get('my-document-name')
sharedDocument.on('status', event => {
console.log(event.status) // logs "connected" or "disconnected"
})
```
#### Scaling
These are mere suggestions how you could scale your server environment.
**Option 1:** Websocket servers communicate with each other via a PubSub server. A room is represented by a PubSub channel. The downside of this approach is that the same shared document may be handled by many servers. But the upside is that this approach is fault tolerant, does not have a single point of failure, and is perfectly fit for route balancing.
**Option 2:** Sharding with *consistent hashing*. Each document is handled by a unique server. This patterns requires an entity, like etcd, that performs regular health checks and manages servers. Based on the list of available servers (which is managed by etcd) a proxy calculates which server is responsible for each requested document. The disadvantage of this approach is that it is that load distribution may not be fair. Still, this approach may be the preferred solution if you want to store the shared document in a database - e.g. for indexing.
### Ydb Provider
TODO
### Create Custom Provider
A provider is only a concept. I encourage you to implement the same provider interface found above. This makes it easy to exchange communication protocols.
Since providers handle the communication channel, they will necessarily interact with the [binary protocols](#Binary-Protocols). I suggest that you build upon the existing protocols. But you may also implement a custom communication protocol.
Read section [Sync Protocol](#Sync-Protocol) to learn how syncing works.
## Shared Types
A shared type is just a normal data type like [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) or [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array). But a shared type may also be modified by a remote client. Conflicts are automatically resolved by the rules described in this section - but please note that this is only a rough overview of how conflict resolution works. Please read the [Yjs CRDT Algorithm](#Yjs-CRDT-Algorithm) section for an in-depth description of the conflict resolution approach.
As explained in [Tutorial](#Tutorial), a shared type is shared among all peers when they are defined with the same name on the same shared document. I.e.
```js
sharedDocument.define('my-array', Y.Array)
const myArray = sharedDocument.get('my-array')
```
You may define a shared types several times, as long as you don't change the type definition.
```js
sharedDocument.define('my-array', Y.Array)
const myArray = sharedDocument.get('my-array')
const alsoMyArray = sharedDocument.define('my-array', Y.Array)
console.log(myArray === alsoMyArray) // => true
```
All shared types have an `type.observe(event => ..)` method that allows you to observe any changes. You may also observe all changes on a type and any of its children with the `type.observeDeep(events => ..)` method. Here, `events` is the [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) of events that were fired on type, or any of its children.
All Events inherit from [YEvent](https://yjs.website/module-utils.YEvent.html).
### YMap
> Complete API docs: [https://yjs.website/module-types.ymap](https://yjs.website/module-types.ymap)
The YMap type is very similar to the JavaScript [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map).
YMap fires [YMapEvents](https://yjs.website/module-types.YMapEvent.html).
```js
import * as Y from 'yjs'
const ymap = new Y.Map()
ymap.observe(event => {
console.log('ymap keys changed:', event.keysChanged, event.remote)
})
ymap.set('key', 'value') // => ymap keys changed: Set{ 'key' } false
ymap.delete('key') // => ymap keys changed: Set{ 'key' }
const ymap2 = new YMap()
ymap2.set(1, 'two')
ymap.set('type', ymap2) // => ymap keys changed: Set{ 'type' }
```
##### Concurrent YMap changes
* Concurrent edits on different keys do not affect each other. E.g. if client1 does `ymap.set('a', 1)` and client2 does `ymap.set('b', 2)`, both clients will end up with `YMap{ a: 1, b: 2 }`
* If client1 and client2 `set` the same property at the same time, the edit from the client with the smaller userID will prevail (`sharedDocument.userID`)
* If client1 sets a property `ymap.set('a', 1)` and client2 deletes a property `ymap.delete('a')`, the set operation always prevails.
### YArray
> Complete API docs: [https://yjs.website/module-types.yarray](https://yjs.website/module-types.yarray)
YArray fires [YArrayEvents](https://yjs.website/module-types.YMapEvent.html).
```js
import * as Y from 'yjs'
const yarray = new Y.Array()
yarray.observe(event => {
console.log('yarray changed:', event.addedElements, event.removedElements, event.remote)
})
// insert two elements at position 0
yarray.insert(0, ['a', 1]) // => yarray changed: Set{Item{'a'}, Item{1}}, Set{}, false
console.log(yarray.toArray()) // => ['a', 1]
yarray.delete(1, 1) // yarray changed: Set{}, Set{Item{1}}, false
yarray.insert(1, new Y.Map()) // => yarray changed: Set{YMap{}}, Set{}, false
// The difference between .toArray and .toJSON:
console.log(yarray.toArray()) // => ['a', YMap{}]
console.log(yarray.toJSON()) // => ['a', {}]
```
As you can see from the above example, primitive data is wrapped into an Item. This makes it possible to find the exact location of the change.
##### Concurrent YArray changes
* YArray internally represents the data as a doubly linked list. The Array `['a', YMap{}, 1]` is internally represented as `Item{'a'} <-> YMap{} <-> Item{1}`. Accordingly, the insert operation `yarray.insert(1, ['b'])` is internally transformed to `insert Item{'b'} between Item{'a'} and YMap{}`.
* When an Item is deleted, it is only marked as deleted. Only its content is garbage collected and freed from memory.
* Therefore, the remote operation `insert x between a and b` can still be fulfilled when item `a` or item `b` are deleted.
* In case that two clients insert content between the same items (a concurrent insertion), the order of the insertions is decided based on the `sharedDocument.userID`.
### YText
> Complete API docs: [https://yjs.website/module-types.ytext](https://yjs.website/module-types.ytext)
A YText is basically a [YArray](#YArray) that is optimized for text content.
### YXmlFragment and YXmlElement
> Complete API docs: [https://yjs.website/module-types.yxmlfragment](https://yjs.website/module-types.yxmlfragment) and [https://yjs.website/module-types.yxmlelement](https://yjs.website/module-types.yxmlelement)
### Custom Types
## Bindings
## Transaction
## Binary Protocols
### Sync Protocol
Sync steps
### Awareness Protocol
### Auth Protocol
## Offline Editing
It is trivial with Yjs to persist the local state to indexeddb, so it is always available when working offline. But there are two non-trivial questions that need to answered when implementing a professional offline editing app:
1. How does a client sync down all rooms that were modified while offline?
2. How does a client sync up all rooms that were modified while offline?
Assuming 5000 documents are stored on each client for offline usage. How do we sync up/down each of those documents after a client comes online? It would be inefficient to sync each of those rooms separately. The only provider that currently supports syncing many rooms efficiently is Ydb, because its database layer is optimized to sync many rooms with each client.
If you do not care about 1. and 2. you can use `/persistences/indexeddb.js` to mirror the local state to indexeddb.
## Working with Yjs
### Typescript Declarations
Until [this](https://github.com/Microsoft/TypeScript/issues/7546) is fixed, the only way to get type declarations is by adding Yjs to the list of checked files:
```json
{
"compilerOptions": {
"allowJs": true,
"checkJs": true,
..
},
"maxNodeModuleJsDepth": 5
}
```
## CRDT Algorithm
## License and Author
Yjs and all related projects are [**MIT licensed**](./LICENSE). Some files also contain an additional copyright notice that allows you to copy and modify the code without shipping the copyright notice (e.g. `./provider/websocket/WebsocketProvider.js` and `./provider/websocket/server.js`)
Yjs is based on the research I did as a student at the RWTH i5. I am working on Yjs in my spare time. Please help me by donating or hiring me for consulting, so I can continue to work on this project.
kevin.jahns@protonmail.com

1
examples/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
build

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<style type="text/css" media="screen">
#aceContainer {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.inserted {
position:absolute;
z-index:20;
background-color: #FFC107;
}
.deleted {
position:absolute;
z-index:20;
background-color: #FFC107;
}
</style>
</head>
<body>
<div id="aceContainer"></div>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="../bower_components/ace-builds/src/ace.js"></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,17 +0,0 @@
/* global Y, ace */
let y = new Y('ace-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
window.yAce = y
// bind the textarea to a shared text element
var editor = ace.edit('aceContainer')
editor.setTheme('ace/theme/chrome')
editor.getSession().setMode('ace/mode/javascript')
y.define('ace', Y.Text).bindAce(editor)

View File

@@ -1,19 +0,0 @@
{
"name": "yjs-examples",
"version": "0.0.0",
"homepage": "y-js.org",
"authors": [
"Kevin Jahns <kevin.jahns@rwth-aachen.de>"
],
"description": "Examples for Yjs",
"license": "MIT",
"ignore": [],
"dependencies": {
"quill": "^1.0.0-rc.2",
"ace": "~1.2.3",
"ace-builds": "~1.2.3",
"jquery": "~2.2.2",
"d3": "^3.5.16",
"codemirror": "^5.25.0"
}
}

View File

@@ -1,19 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<style>
#chat p span {
color: blue;
}
</style>
<div id="chat"></div>
<form id="chatform">
<input name="username" type="text" style="width:15%;">
<input name="message" type="text" style="width:60%;">
<input type="submit" value="Send">
</form>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,65 +0,0 @@
/* global Y */
let y = new Y('chat-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
window.yChat = y
let chatprotocol = y.define('chatprotocol', Y.Array)
let chatcontainer = document.querySelector('#chat')
// This functions inserts a message at the specified position in the DOM
function appendMessage (message, position) {
var p = document.createElement('p')
var uname = document.createElement('span')
uname.appendChild(document.createTextNode(message.username + ': '))
p.appendChild(uname)
p.appendChild(document.createTextNode(message.message))
chatcontainer.insertBefore(p, chatcontainer.children[position] || null)
}
// This function makes sure that only 7 messages exist in the chat history.
// The rest is deleted
function cleanupChat () {
if (chatprotocol.length > 7) {
chatprotocol.delete(0, chatprotocol.length - 7)
}
}
cleanupChat()
// Insert the initial content
chatprotocol.toArray().forEach(appendMessage)
// whenever content changes, make sure to reflect the changes in the DOM
chatprotocol.observe(function (event) {
// concurrent insertions may result in a history > 7, so cleanup here
cleanupChat()
chatcontainer.innerHTML = ''
chatprotocol.toArray().forEach(appendMessage)
})
document.querySelector('#chatform').onsubmit = function (event) {
// the form is submitted
var message = {
username: this.querySelector('[name=username]').value,
message: this.querySelector('[name=message]').value
}
if (message.username.length > 0 && message.message.length > 0) {
if (chatprotocol.length > 6) {
// If we are goint to insert the 8th element, make sure to delete first.
chatprotocol.delete(0)
}
// Here we insert a message in the shared chat type.
// This will call the observe function (see line 40)
// and reflect the change in the DOM
chatprotocol.push([message])
this.querySelector('[name=message]').value = ''
}
// Do not send this form!
event.preventDefault()
return false
}

70
examples/codemirror.html Normal file
View File

@@ -0,0 +1,70 @@
<!DOCTYPE html>
<html>
<head>
<title>Yjs CodeMirror Example</title>
<link rel=stylesheet href="https://codemirror.net/lib/codemirror.css">
<style>
#container {
border: grey;
border-style: solid;
border-width: thin;
}
</style>
</head>
<body>
<p>This example shows how to bind a YText type to <a href="https://codemirror.net/">CodeMirror</a> editor.</p>
<p>The content of this editor is shared with every client who visits this domain.</p>
<div class="code-html">
<style>
.remote-caret {
position: absolute;
border-left: black;
border-left-style: solid;
border-left-width: 2px;
height: 1em;
}
.remote-caret > div {
position: relative;
top: -1.05em;
font-size: 13px;
background-color: rgb(250, 129, 0);
font-family: serif;
font-style: normal;
font-weight: normal;
line-height: normal;
user-select: none;
color: white;
padding-left: 2px;
padding-right: 2px;
}
</style>
<div id="container"></div>
</div>
<!-- The actual source file for the following code is found in ./codemirror.js. Run `npm run watch` to compile the files -->
<script class="code-js" src="./build/codemirror.js" type="module">
import * as Y from 'yjs'
import { WebsocketProvider } from 'yjs/provider/websocket.js'
import { CodeMirrorBinding } from 'yjs/bindings/codemirror.js'
import * as conf from './exampleConfig.js'
import CodeMirror from 'codemirror'
import 'codemirror/mode/javascript/javascript.js'
const provider = new WebsocketProvider(conf.serverAddress)
const ydocument = provider.get('codemirror')
const ytext = ydocument.define('codemirror', Y.Text)
const editor = new CodeMirror(document.querySelector('#container'), {
mode: 'javascript',
lineNumbers: true
})
const binding = new CodeMirrorBinding(ytext, editor)
window.codemirrorExample = {
binding, editor, ytext, ydocument
}
</script>
</body>
</html>

22
examples/codemirror.js Normal file
View File

@@ -0,0 +1,22 @@
import { WebsocketProvider } from 'y-websocket'
import { CodeMirrorBinding } from 'y-codemirror'
import * as conf from './exampleConfig.js'
import CodeMirror from 'codemirror'
import 'codemirror/mode/javascript/javascript.js'
const provider = new WebsocketProvider(conf.serverAddress)
const ydocument = provider.get('codemirror')
const ytext = ydocument.getText('codemirror')
const editor = new CodeMirror(document.querySelector('#container'), {
mode: 'javascript',
lineNumbers: true
})
const binding = new CodeMirrorBinding(ytext, editor)
window.codemirrorExample = {
binding, editor, ytext, ydocument
}

View File

@@ -1,24 +0,0 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="codeMirrorContainer"></div>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="../bower_components/codemirror/lib/codemirror.js"></script>
<script src="../bower_components/codemirror/mode/javascript/javascript.js"></script>
<link rel="stylesheet" href="../bower_components/codemirror/lib/codemirror.css">
<style>
.CodeMirror {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
}
</style>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,16 +0,0 @@
/* global Y, CodeMirror */
let y = new Y('codemirror-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
window.yCodeMirror = y
var editor = CodeMirror(document.querySelector('#codeMirrorContainer'), {
mode: 'javascript',
lineNumbers: true
})
y.define('codemirror', Y.Text).bindCodeMirror(editor)

37
examples/dom.html Normal file
View File

@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<title>Yjs Prosemirror Example</title>
<link rel=stylesheet href="https://prosemirror.net/css/editor.css">
<style>
#content {
min-height: 500px;
}
</style>
</head>
<body>
<p>This example shows how to bind a YXmlFragment type to an arbitrary DOM element. We set the DOM element to contenteditable so it basically behaves like a very powerful rich-text editor.</p>
<p>The content of this editor is shared with every client who visits this domain.</p>
<hr>
<div class="code-html">
<div id="content" contenteditable=""></div>
</div>
<!-- The actual source file for the following code is found in ./dom.js. Run `npm run watch` to compile the files -->
<script class="code-js" src="./build/dom.js" type="module">
import * as Y from 'yjs/index.js'
import { WebsocketProvider } from 'yjs/provider/websocket.js'
import { DomBinding } from 'yjs/bindings/dom.js'
import * as conf from './exampleConfig.js'
const provider = new WebsocketProvider(conf.serverAddress)
const ydocument = provider.get('dom')
const type = ydocument.define('xml', Y.XmlFragment)
const binding = new DomBinding(type, document.querySelector('#content'), { scrollingElement: document.scrollingElement })
window.example = {
provider, ydocument, type, binding
}
</script>
</body>
</html>

13
examples/dom.js Normal file
View File

@@ -0,0 +1,13 @@
import * as Y from '../src/index.js'
import { WebsocketProvider } from 'y-websocket'
import { DomBinding } from 'y-dom'
import * as conf from './exampleConfig.js'
const provider = new WebsocketProvider(conf.serverAddress)
const ydocument = provider.get('dom')
const type = ydocument.define('xml', Y.XmlFragment)
const binding = new DomBinding(type, document.querySelector('#content'), { scrollingElement: document.scrollingElement })
window.example = {
provider, ydocument, type, binding
}

View File

@@ -1,20 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<style>
path {
fill: none;
stroke: blue;
stroke-width: 1px;
stroke-linejoin: round;
stroke-linecap: round;
}
</style>
<button type="button" id="clearDrawingCanvas">Clear Drawing</button>
<svg id="drawingCanvas" viewbox="0 0 100 100" width="100%"></svg>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="../bower_components/d3/d3.min.js"></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,74 +0,0 @@
/* globals Y, d3 */
let y = new Y('drawing-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
window.yDrawing = y
var drawing = y.define('drawing', Y.Array)
var renderPath = d3.svg.line()
.x(function (d) { return d[0] })
.y(function (d) { return d[1] })
.interpolate('basic')
var svg = d3.select('#drawingCanvas')
.call(d3.behavior.drag()
.on('dragstart', dragstart)
.on('drag', drag)
.on('dragend', dragend))
// create line from a shared array object and update the line when the array changes
function drawLine (yarray) {
var line = svg.append('path').datum(yarray.toArray())
line.attr('d', renderPath)
yarray.observe(function (event) {
line.remove()
line = svg.append('path').datum(yarray.toArray())
line.attr('d', renderPath)
})
}
// call drawLine every time an array is appended
drawing.observe(function (event) {
event.removedElements.forEach(function () {
// if one is deleted, all will be deleted!!
svg.selectAll('path').remove()
})
event.addedElements.forEach(function (path) {
drawLine(path)
})
})
// draw all existing content
for (var i = 0; i < drawing.length; i++) {
drawLine(drawing.get(i))
}
// clear canvas on request
document.querySelector('#clearDrawingCanvas').onclick = function () {
drawing.delete(0, drawing.length)
}
var sharedLine = null
function dragstart () {
drawing.insert(drawing.length, [Y.Array])
sharedLine = drawing.get(drawing.length - 1)
}
// After one dragged event is recognized, we ignore them for 33ms.
var ignoreDrag = null
function drag () {
if (sharedLine != null && ignoreDrag == null) {
ignoreDrag = window.setTimeout(function () {
ignoreDrag = null
}, 10)
sharedLine.push([d3.mouse(this)])
}
}
function dragend () {
sharedLine = null
window.clearTimeout(ignoreDrag)
ignoreDrag = null
}

View File

@@ -0,0 +1,9 @@
/* eslint-env browser */
const isDeployed = location.hostname === 'yjs.website'
if (!isDeployed) {
console.log('%cYjs: Start your local websocket server by running %c`npm run websocket-server`', 'color:blue', 'color: grey; font-weight: bold')
}
export const serverAddress = isDeployed ? 'wss://api.yjs.website' : 'ws://localhost:1234'

17
examples/examples.json Normal file
View File

@@ -0,0 +1,17 @@
{
"codemirror": {
"title": "CodeMirror Binding"
},
"prosemirror": {
"title": "ProseMirror Binding"
},
"textarea": {
"title": "Textarea Binding"
},
"quill": {
"title": "Quill Binding"
},
"dom": {
"title": "Dom Binding"
}
}

View File

@@ -1,36 +0,0 @@
<!DOCTYPE html>
<html>
</head>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="../bower_components/d3/d3.min.js"></script>
<script src="./index.js"></script>
<style>
magic-drawing .drawingCanvas path {
fill: none;
stroke: blue;
stroke-width: 2px;
stroke-linejoin: round;
stroke-linecap: round;
}
magic-drawing .drawingCanvas {
width: 500px;
height: 500px;
cursor: default;
padding:1px;
border:1px solid #021a40;
}
magic-drawing .clearDrawingButton {
position: absolute;
top: 0;
left: 0;
}
magic-drawing {
position: relative;
display: block;
}
</style>
</head>
<body contenteditable="true">
</body>
</html>

View File

@@ -1,134 +0,0 @@
/* global Y, d3 */
const hooks = {
'magic-drawing': {
fillType: function (dom, type) {
initDrawingBindings(type, dom)
},
createDom: function (type) {
const dom = document.createElement('magic-drawing')
initDrawingBindings(type, dom)
return dom
}
}
}
window.onload = function () {
window.domBinding = new Y.DomBinding(window.yXmlType, document.body, { hooks })
}
window.addMagicDrawing = function addMagicDrawing () {
let mt = document.createElement('magic-drawing')
mt.setAttribute('data-yjs-hook', 'magic-drawing')
document.body.append(mt)
}
var renderPath = d3.svg.line()
.x(function (d) { return d[0] })
.y(function (d) { return d[1] })
.interpolate('basic')
function initDrawingBindings (type, dom) {
dom.contentEditable = 'false'
dom.setAttribute('data-yjs-hook', 'magic-drawing')
var drawing = type.get('drawing')
if (drawing === undefined) {
drawing = type.set('drawing', new Y.Array())
}
var canvas = dom.querySelector('.drawingCanvas')
if (canvas == null) {
canvas = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
canvas.setAttribute('class', 'drawingCanvas')
canvas.setAttribute('viewbox', '0 0 100 100')
dom.insertBefore(canvas, null)
}
var clearDrawingButton = dom.querySelector('.clearDrawingButton')
if (clearDrawingButton == null) {
clearDrawingButton = document.createElement('button')
clearDrawingButton.setAttribute('type', 'button')
clearDrawingButton.setAttribute('class', 'clearDrawingButton')
clearDrawingButton.innerText = 'Clear Drawing'
dom.insertBefore(clearDrawingButton, null)
}
var svg = d3.select(canvas)
.call(d3.behavior.drag()
.on('dragstart', dragstart)
.on('drag', drag)
.on('dragend', dragend))
// create line from a shared array object and update the line when the array changes
function drawLine (yarray, svg) {
var line = svg.append('path').datum(yarray.toArray())
line.attr('d', renderPath)
yarray.observe(function (event) {
line.remove()
line = svg.append('path').datum(yarray.toArray())
line.attr('d', renderPath)
})
}
// call drawLine every time an array is appended
drawing.observe(function (event) {
event.removedElements.forEach(function () {
// if one is deleted, all will be deleted!!
svg.selectAll('path').remove()
})
event.addedElements.forEach(function (path) {
drawLine(path, svg)
})
})
// draw all existing content
for (var i = 0; i < drawing.length; i++) {
drawLine(drawing.get(i), svg)
}
// clear canvas on request
clearDrawingButton.onclick = function () {
drawing.delete(0, drawing.length)
}
var sharedLine = null
function dragstart () {
drawing.insert(drawing.length, [Y.Array])
sharedLine = drawing.get(drawing.length - 1)
}
// After one dragged event is recognized, we ignore them for 33ms.
var ignoreDrag = null
function drag () {
if (sharedLine != null && ignoreDrag == null) {
ignoreDrag = window.setTimeout(function () {
ignoreDrag = null
}, 10)
sharedLine.push([d3.mouse(this)])
}
}
function dragend () {
sharedLine = null
window.clearTimeout(ignoreDrag)
ignoreDrag = null
}
}
let y = new Y('html-editor-drawing-hook-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
window.yXml = y
window.yXmlType = y.define('xml', Y.XmlFragment)
window.undoManager = new Y.utils.UndoManager(window.yXmlType, {
captureTimeout: 500
})
document.onkeydown = function interceptUndoRedo (e) {
if (e.keyCode === 90 && e.metaKey) {
if (!e.shiftKey) {
window.undoManager.undo()
} else {
window.undoManager.redo()
}
e.preventDefault()
}
}

View File

@@ -1,645 +0,0 @@
/*
CanvasJS HTML5 & JavaScript Charts - v1.9.10 GA - https://canvasjs.com/
Copyright 2017 fenopix
--------------------- License Information --------------------
CanvasJS is a commercial product which requires purchase of license. Without a commercial license you can use it for evaluation purposes for upto 30 days. Please refer to the following link for further details.
https://canvasjs.com/license-canvasjs/
*/
(function(){function T(a,c){a.prototype=Sa(c.prototype);a.prototype.constructor=a;a.base=c.prototype}function Sa(a){function c(){}c.prototype=a;return new c}function Ia(a,c,b){"millisecond"===b?a.setMilliseconds(a.getMilliseconds()+1*c):"second"===b?a.setSeconds(a.getSeconds()+1*c):"minute"===b?a.setMinutes(a.getMinutes()+1*c):"hour"===b?a.setHours(a.getHours()+1*c):"day"===b?a.setDate(a.getDate()+1*c):"week"===b?a.setDate(a.getDate()+7*c):"month"===b?a.setMonth(a.getMonth()+1*c):"year"===b&&a.setFullYear(a.getFullYear()+
1*c);return a}function P(a,c){var b=!1;0>a&&(b=!0,a*=-1);a=""+a;for(c=c?c:1;a.length<c;)a="0"+a;return b?"-"+a:a}function ma(a){if(!a)return a;a=a.replace(/^\s\s*/,"");for(var c=/\s/,b=a.length;c.test(a.charAt(--b)););return a.slice(0,b+1)}function Ja(a){a.roundRect=function(a,b,d,f,g,l,k,h){k&&(this.fillStyle=k);h&&(this.strokeStyle=h);"undefined"===typeof g&&(g=5);this.lineWidth=l;this.beginPath();this.moveTo(a+g,b);this.lineTo(a+d-g,b);this.quadraticCurveTo(a+d,b,a+d,b+g);this.lineTo(a+d,b+f-g);
this.quadraticCurveTo(a+d,b+f,a+d-g,b+f);this.lineTo(a+g,b+f);this.quadraticCurveTo(a,b+f,a,b+f-g);this.lineTo(a,b+g);this.quadraticCurveTo(a,b,a+g,b);this.closePath();k&&this.fill();h&&0<l&&this.stroke()}}function Aa(a,c){return a-c}function Ka(a,c){return a.x-c.x}function D(a){var c=((a&16711680)>>16).toString(16),b=((a&65280)>>8).toString(16);a=((a&255)>>0).toString(16);c=2>c.length?"0"+c:c;b=2>b.length?"0"+b:b;a=2>a.length?"0"+a:a;return"#"+c+b+a}function Ta(a,c){var b=this.length>>>0,d=Number(c)||
0,d=0>d?Math.ceil(d):Math.floor(d);for(0>d&&(d+=b);d<b;d++)if(d in this&&this[d]===a)return d;return-1}function y(a){return null===a||"undefined"===typeof a}function sa(a){a.indexOf||(a.indexOf=Ta);return a}function Ua(a){if(I.fSDec)a[I.fSDec("`eeDwdouMhrudods")](I.fSDec("e`u`@ohl`uhnoHuds`uhnoDoe"),function(){I._fTWm&&I._fTWm(a)})}function La(a,c,b){b=b||"normal";var d=a+"_"+c+"_"+b,f=Ma[d];if(isNaN(f)){try{a="position:absolute; left:0px; top:-20000px; padding:0px;margin:0px;border:none;white-space:pre;line-height:normal;font-family:"+
a+"; font-size:"+c+"px; font-weight:"+b+";";if(!da){var g=document.body;da=document.createElement("span");da.innerHTML="";var l=document.createTextNode("Mpgyi");da.appendChild(l);g.appendChild(da)}da.style.display="";da.setAttribute("style",a);f=Math.round(da.offsetHeight);da.style.display="none"}catch(k){f=Math.ceil(1.1*c)}f=Math.max(f,c);Ma[d]=f}return f}function F(a,c){var b=[];if(b={solid:[],shortDash:[3,1],shortDot:[1,1],shortDashDot:[3,1,1,1],shortDashDotDot:[3,1,1,1,1,1],dot:[1,2],dash:[4,
2],dashDot:[4,2,1,2],longDash:[8,2],longDashDot:[8,2,1,2],longDashDotDot:[8,2,1,2,1,2]}[a||"solid"])for(var d=0;d<b.length;d++)b[d]*=c;else b=[];return b}function J(a,c,b,d){return a.addEventListener?(a.addEventListener(c,b,d||!1),b):a.attachEvent?(d=function(d){d=d||window.event;d.preventDefault=d.preventDefault||function(){d.returnValue=!1};d.stopPropagation=d.stopPropagation||function(){d.cancelBubble=!0};b.call(a,d)},a.attachEvent("on"+c,d),d):!1}function Na(a,c,b){a*=Q;c*=Q;a=b.getImageData(a,
c,2,2).data;c=!0;for(b=0;4>b;b++)if(a[b]!==a[b+4]|a[b]!==a[b+8]|a[b]!==a[b+12]){c=!1;break}return c?a[0]<<16|a[1]<<8|a[2]:0}function K(a,c,b){return a in c?c[a]:b[a]}function ta(a,c,b){if(t&&Oa){var d=a.getContext("2d");ua=d.webkitBackingStorePixelRatio||d.mozBackingStorePixelRatio||d.msBackingStorePixelRatio||d.oBackingStorePixelRatio||d.backingStorePixelRatio||1;Q=Ba/ua;a.width=c*Q;a.height=b*Q;Ba!==ua&&(a.style.width=c+"px",a.style.height=b+"px",d.scale(Q,Q))}else a.width=c,a.height=b}function Va(a){if(!Pa){var c=
!1,b=!1;"undefined"===typeof ea.Chart.creditHref?(a.creditHref=S("iuuqr;..b`ow`rkr/bnl."),a.creditText=S("B`ow`rKR/bnl")):(c=a.updateOption("creditText"),b=a.updateOption("creditHref"));if(a.creditHref&&a.creditText){a._creditLink||(a._creditLink=document.createElement("a"),a._creditLink.setAttribute("class","canvasjs-chart-credit"),a._creditLink.setAttribute("style","outline:none;margin:0px;position:absolute;right:2px;top:"+(a.height-14)+"px;color:dimgrey;text-decoration:none;font-size:11px;font-family: Calibri, Lucida Grande, Lucida Sans Unicode, Arial, sans-serif"),
a._creditLink.setAttribute("tabIndex",-1),a._creditLink.setAttribute("target","_blank"));if(0===a.renderCount||c||b)a._creditLink.setAttribute("href",a.creditHref),a._creditLink.innerHTML=a.creditText;a._creditLink&&a.creditHref&&a.creditText?(a._creditLink.parentElement||a._canvasJSContainer.appendChild(a._creditLink),a._creditLink.style.top=a.height-14+"px"):a._creditLink.parentElement&&a._canvasJSContainer.removeChild(a._creditLink)}}}function ia(a,c){var b=document.createElement("canvas");b.setAttribute("class",
"canvasjs-chart-canvas");ta(b,a,c);t||"undefined"===typeof G_vmlCanvasManager||G_vmlCanvasManager.initElement(b);return b}function Ca(a,c,b){if(a&&c&&b){b=b+"."+c;var d="image/"+c;a=a.toDataURL(d);var f=!1,g=document.createElement("a");g.download=b;g.href=a;g.target="_blank";if("undefined"!==typeof Blob&&new Blob){for(var l=a.replace(/^data:[a-z\/]*;base64,/,""),l=atob(l),k=new ArrayBuffer(l.length),k=new Uint8Array(k),h=0;h<l.length;h++)k[h]=l.charCodeAt(h);c=new Blob([k.buffer],{type:"image/"+c});
try{window.navigator.msSaveBlob(c,b),f=!0}catch(m){g.dataset.downloadurl=[d,g.download,g.href].join(":"),g.href=window.URL.createObjectURL(c)}}if(!f)try{event=document.createEvent("MouseEvents"),event.initMouseEvent("click",!0,!1,window,0,0,0,0,0,!1,!1,!1,!1,0,null),g.dispatchEvent?g.dispatchEvent(event):g.fireEvent&&g.fireEvent("onclick")}catch(p){c=window.open(),c.document.write("<img src='"+a+"'></img><div>Please right click on the image and save it to your device</div>"),c.document.close()}}}
function $(a,c,b){c.getAttribute("state")!==b&&(c.setAttribute("state",b),c.setAttribute("type","button"),c.style.position="relative",c.style.margin="0px 0px 0px 0px",c.style.padding="3px 4px 0px 4px",c.style.cssFloat="left",c.setAttribute("title",a._cultureInfo[b+"Text"]),c.innerHTML="<img style='height:16px;' src='"+Wa[b].image+"' alt='"+a._cultureInfo[b+"Text"]+"' />")}function va(){for(var a=null,c=0;c<arguments.length;c++)a=arguments[c],a.style&&(a.style.display="inline")}function aa(){for(var a=
null,c=0;c<arguments.length;c++)(a=arguments[c])&&a.style&&(a.style.display="none")}function L(a,c,b,d){this._defaultsKey=a;this.parent=d;this._eventListeners=[];d={};b&&(ka[b]&&ka[b][a])&&(d=ka[b][a]);this.options=c?c:{_isPlaceholder:!0};this.setOptions(this.options,d)}function A(a,c){c=c||{};A.base.constructor.call(this,"Chart",c,c.theme?c.theme:"theme1");var b=this;this._containerId=a;this._objectsInitialized=!1;this.overlaidCanvasCtx=this.ctx=null;this._indexLabels=[];this._panTimerId=0;this._lastTouchEventType=
"";this._lastTouchData=null;this.isAnimating=!1;this.renderCount=0;this.panEnabled=this.disableToolTip=this.animatedRender=!1;this._defaultCursor="default";this.plotArea={canvas:null,ctx:null,x1:0,y1:0,x2:0,y2:0,width:0,height:0};this._dataInRenderedOrder=[];if(this.container="string"===typeof this._containerId?document.getElementById(this._containerId):this._containerId){this.container.innerHTML="";var d=0,f=0,d=this.options.width?this.width:0<this.container.clientWidth?this.container.clientWidth:
this.width,f=this.options.height?this.height:0<this.container.clientHeight?this.container.clientHeight:this.height;this.width=d;this.height=f;this.x1=this.y1=0;this.x2=this.width;this.y2=this.height;this._selectedColorSet="undefined"!==typeof ja[this.colorSet]?ja[this.colorSet]:ja.colorSet1;this._canvasJSContainer=document.createElement("div");this._canvasJSContainer.setAttribute("class","canvasjs-chart-container");this._canvasJSContainer.style.position="relative";this._canvasJSContainer.style.textAlign=
"left";this._canvasJSContainer.style.cursor="auto";t||(this._canvasJSContainer.style.height="0px");this.container.appendChild(this._canvasJSContainer);this.canvas=ia(d,f);this.canvas.style.position="absolute";this.canvas.getContext&&(this._canvasJSContainer.appendChild(this.canvas),this.ctx=this.canvas.getContext("2d"),this.ctx.textBaseline="top",Ja(this.ctx),t?this.plotArea.ctx=this.ctx:(this.plotArea.canvas=ia(d,f),this.plotArea.canvas.style.position="absolute",this.plotArea.canvas.setAttribute("class",
"plotAreaCanvas"),this._canvasJSContainer.appendChild(this.plotArea.canvas),this.plotArea.ctx=this.plotArea.canvas.getContext("2d")),this.overlaidCanvas=ia(d,f),this.overlaidCanvas.style.position="absolute",this._canvasJSContainer.appendChild(this.overlaidCanvas),this.overlaidCanvasCtx=this.overlaidCanvas.getContext("2d"),this.overlaidCanvasCtx.textBaseline="top",this._eventManager=new na(this),this.windowResizeHandler=J(window,"resize",function(){b._updateSize()&&b.render()}),this._toolBar=document.createElement("div"),
this._toolBar.setAttribute("class","canvasjs-chart-toolbar"),this._toolBar.style.cssText="position: absolute; right: 1px; top: 1px;",this._canvasJSContainer.appendChild(this._toolBar),this.bounds={x1:0,y1:0,x2:this.width,y2:this.height},J(this.overlaidCanvas,"click",function(a){b._mouseEventHandler(a)}),J(this.overlaidCanvas,"mousemove",function(a){b._mouseEventHandler(a)}),J(this.overlaidCanvas,"mouseup",function(a){b._mouseEventHandler(a)}),J(this.overlaidCanvas,"mousedown",function(a){b._mouseEventHandler(a);
aa(b._dropdownMenu)}),J(this.overlaidCanvas,"mouseout",function(a){b._mouseEventHandler(a)}),J(this.overlaidCanvas,window.navigator.msPointerEnabled?"MSPointerDown":"touchstart",function(a){b._touchEventHandler(a)}),J(this.overlaidCanvas,window.navigator.msPointerEnabled?"MSPointerMove":"touchmove",function(a){b._touchEventHandler(a)}),J(this.overlaidCanvas,window.navigator.msPointerEnabled?"MSPointerUp":"touchend",function(a){b._touchEventHandler(a)}),J(this.overlaidCanvas,window.navigator.msPointerEnabled?
"MSPointerCancel":"touchcancel",function(a){b._touchEventHandler(a)}),this.toolTip=new R(this,this.options.toolTip),this.data=null,this.axisX=[],this.axisX2=[],this.axisY=[],this.axisY2=[],this.sessionVariables={axisX:[],axisX2:[],axisY:[],axisY2:[]})}else window.console&&window.console.log('CanvasJS Error: Chart Container with id "'+this._containerId+'" was not found')}function wa(a,c){for(var b=[],d,f=0;f<a.length;f++)if(0==f)b.push(a[0]);else{var g,l,k;k=f-1;g=0===k?0:k-1;l=k===a.length-1?k:k+
1;d=Math.abs((a[l].x-a[g].x)/(0===a[l].x-a[k].x?0.01:a[l].x-a[k].x))*(c-1)/2+1;var h=(a[l].x-a[g].x)/d;d=(a[l].y-a[g].y)/d;b[b.length]=a[k].x>a[g].x&&0<h||a[k].x<a[g].x&&0>h?{x:a[k].x+h/3,y:a[k].y+d/3}:{x:a[k].x,y:a[k].y+d/9};k=f;g=0===k?0:k-1;l=k===a.length-1?k:k+1;d=Math.abs((a[l].x-a[g].x)/(0===a[k].x-a[g].x?0.01:a[k].x-a[g].x))*(c-1)/2+1;h=(a[l].x-a[g].x)/d;d=(a[l].y-a[g].y)/d;b[b.length]=a[k].x>a[g].x&&0<h||a[k].x<a[g].x&&0>h?{x:a[k].x-h/3,y:a[k].y-d/3}:{x:a[k].x,y:a[k].y-d/9};b[b.length]=a[f]}return b}
function Qa(a,c){if(null===a||"undefined"===typeof a)return c;var b=parseFloat(a.toString())*(0<=a.toString().indexOf("%")?c/100:1);return!isNaN(b)&&b<=c&&0<=b?b:c}function la(a,c,b,d,f){"undefined"===typeof f&&(f=0);this._padding=f;this._x1=a;this._y1=c;this._x2=b;this._y2=d;this._rightOccupied=this._leftOccupied=this._bottomOccupied=this._topOccupied=this._padding}function V(a,c){V.base.constructor.call(this,"TextBlock",c);this.ctx=a;this._isDirty=!0;this._wrappedText=null}function oa(a,c){oa.base.constructor.call(this,
"Title",c,a.theme,a);this.chart=a;this.canvas=a.canvas;this.ctx=this.chart.ctx;this.optionsName="title";if(y(this.options.margin)&&a.options.subtitles)for(var b=a.options.subtitles,d=0;d<b.length;d++)if((y(b[d].horizontalAlign)&&"center"===this.horizontalAlign||b[d].horizontalAlign===this.horizontalAlign)&&(y(b[d].verticalAlign)&&"top"===this.verticalAlign||b[d].verticalAlign===this.verticalAlign)&&!b[d].dockInsidePlotArea===!this.dockInsidePlotArea){this.margin=0;break}"undefined"===typeof this.options.fontSize&&
(this.fontSize=this.chart.getAutoFontSize(this.fontSize));this.height=this.width=null;this.bounds={x1:null,y1:null,x2:null,y2:null}}function xa(a,c){xa.base.constructor.call(this,"Subtitle",c,a.theme,a);this.chart=a;this.canvas=a.canvas;this.ctx=this.chart.ctx;this.optionsName="subtitles";this.isOptionsInArray=!0;"undefined"===typeof this.options.fontSize&&(this.fontSize=this.chart.getAutoFontSize(this.fontSize));this.height=this.width=null;this.bounds={x1:null,y1:null,x2:null,y2:null}}function ya(a,
c){ya.base.constructor.call(this,"Legend",c,a.theme,a);this.chart=a;this.canvas=a.canvas;this.ctx=this.chart.ctx;this.ghostCtx=this.chart._eventManager.ghostCtx;this.items=[];this.optionsName="legend";this.height=this.width=0;this.orientation=null;this.dataSeries=[];this.bounds={x1:null,y1:null,x2:null,y2:null};"undefined"===typeof this.options.fontSize&&(this.fontSize=this.chart.getAutoFontSize(this.fontSize));this.lineHeight=La(this.fontFamily,this.fontSize,this.fontWeight);this.horizontalSpacing=
this.fontSize}function Da(a,c){Da.base.constructor.call(this,c);this.chart=a;this.canvas=a.canvas;this.ctx=this.chart.ctx}function ca(a,c,b,d){ca.base.constructor.call(this,"DataSeries",c,a.theme,a);this.chart=a;this.canvas=a.canvas;this._ctx=a.canvas.ctx;this.index=b;this.noDataPointsInPlotArea=0;this.id=d;this.chart._eventManager.objectMap[d]={id:d,objectType:"dataSeries",dataSeriesIndex:b};this.dataPointIds=[];this.plotUnit=[];this.axisY=this.axisX=null;this.optionsName="data";this.isOptionsInArray=
!0;null===this.fillOpacity&&(this.type.match(/area/i)?this.fillOpacity=0.7:this.fillOpacity=1);this.axisPlacement=this.getDefaultAxisPlacement();"undefined"===typeof this.options.indexLabelFontSize&&(this.indexLabelFontSize=this.chart.getAutoFontSize(this.indexLabelFontSize))}function B(a,c,b,d,f){B.base.constructor.call(this,"Axis",c,a.theme,a);this.chart=a;this.canvas=a.canvas;this.ctx=a.ctx;this.intervalStartPosition=this.maxHeight=this.maxWidth=0;this.labels=[];this.dataSeries=[];this._stripLineLabels=
this._ticks=this._labels=null;this.dataInfo={min:Infinity,max:-Infinity,viewPortMin:Infinity,viewPortMax:-Infinity,minDiff:Infinity};this.isOptionsInArray=!0;"axisX"===b?("left"===d||"bottom"===d?(this.optionsName="axisX",y(this.chart.sessionVariables.axisX[f])&&(this.chart.sessionVariables.axisX[f]={}),this.sessionVariables=this.chart.sessionVariables.axisX[f]):(this.optionsName="axisX2",y(this.chart.sessionVariables.axisX2[f])&&(this.chart.sessionVariables.axisX2[f]={}),this.sessionVariables=this.chart.sessionVariables.axisX2[f]),
this.options.interval||(this.intervalType=null),"theme2"===this.chart.theme&&y(this.options.lineThickness)&&(this.lineThickness=2)):"left"===d||"top"===d?(this.optionsName="axisY",y(this.chart.sessionVariables.axisY[f])&&(this.chart.sessionVariables.axisY[f]={}),this.sessionVariables=this.chart.sessionVariables.axisY[f]):(this.optionsName="axisY2",y(this.chart.sessionVariables.axisY2[f])&&(this.chart.sessionVariables.axisY2[f]={}),this.sessionVariables=this.chart.sessionVariables.axisY2[f]);"undefined"===
typeof this.options.titleFontSize&&(this.titleFontSize=this.chart.getAutoFontSize(this.titleFontSize));"undefined"===typeof this.options.labelFontSize&&(this.labelFontSize=this.chart.getAutoFontSize(this.labelFontSize));this.type=b;"axisX"!==b||c&&"undefined"!==typeof c.gridThickness||(this.gridThickness=0);this._position=d;this.lineCoordinates={x1:null,y1:null,x2:null,y2:null,width:null};this.labelAngle=(this.labelAngle%360+360)%360;90<this.labelAngle&&270>this.labelAngle?this.labelAngle-=180:270<=
this.labelAngle&&360>=this.labelAngle&&(this.labelAngle-=360);if(this.options.stripLines&&0<this.options.stripLines.length)for(this.stripLines=[],c=0;c<this.options.stripLines.length;c++)this.stripLines.push(new pa(this.chart,this.options.stripLines[c],a.theme,++this.chart._eventManager.lastObjectId,this));this._titleTextBlock=null;this.hasOptionChanged("viewportMinimum")&&null===this.viewportMinimum&&(this.options.viewportMinimum=void 0,this.sessionVariables.viewportMinimum=null);this.hasOptionChanged("viewportMinimum")||
isNaN(this.sessionVariables.newViewportMinimum)||null===this.sessionVariables.newViewportMinimum?this.sessionVariables.newViewportMinimum=null:this.viewportMinimum=this.sessionVariables.newViewportMinimum;this.hasOptionChanged("viewportMaximum")&&null===this.viewportMaximum&&(this.options.viewportMaximum=void 0,this.sessionVariables.viewportMaximum=null);this.hasOptionChanged("viewportMaximum")||isNaN(this.sessionVariables.newViewportMaximum)||null===this.sessionVariables.newViewportMaximum?this.sessionVariables.newViewportMaximum=
null:this.viewportMaximum=this.sessionVariables.newViewportMaximum;null!==this.minimum&&null!==this.viewportMinimum&&(this.viewportMinimum=Math.max(this.viewportMinimum,this.minimum));null!==this.maximum&&null!==this.viewportMaximum&&(this.viewportMaximum=Math.min(this.viewportMaximum,this.maximum));this.trackChanges("viewportMinimum");this.trackChanges("viewportMaximum")}function pa(a,c,b,d,f){pa.base.constructor.call(this,"StripLine",c,b,f);this.id=d;this.chart=a;this.ctx=this.chart.ctx;this.label=
this.label;this.axis=f;this.optionsName="stripLines";this.isOptionsInArray=!0;this._thicknessType="pixel";null!==this.startValue&&null!==this.endValue&&(this.value=f.logarithmic?Math.sqrt((this.startValue.getTime?this.startValue.getTime():this.startValue)*(this.endValue.getTime?this.endValue.getTime():this.endValue)):((this.startValue.getTime?this.startValue.getTime():this.startValue)+(this.endValue.getTime?this.endValue.getTime():this.endValue))/2,this.thickness=f.logarithmic?Math.log(this.endValue/
this.startValue)/Math.log(f.logarithmBase):Math.max(this.endValue-this.startValue),this._thicknessType="value")}function R(a,c){R.base.constructor.call(this,"ToolTip",c,a.theme,a);this.chart=a;this.canvas=a.canvas;this.ctx=this.chart.ctx;this.currentDataPointIndex=this.currentSeriesIndex=-1;this._timerId=0;this._prevY=this._prevX=NaN;this.optionsName="toolTip";this._initialize()}function na(a){this.chart=a;this.lastObjectId=0;this.objectMap=[];this.rectangularRegionEventSubscriptions=[];this.previousDataPointEventObject=
null;this.ghostCanvas=ia(this.chart.width,this.chart.height);this.ghostCtx=this.ghostCanvas.getContext("2d");this.mouseoveredObjectMaps=[]}function qa(a){var c;a&&ra[a]&&(c=ra[a]);qa.base.constructor.call(this,"CultureInfo",c)}function Ea(a){this.chart=a;this.ctx=this.chart.plotArea.ctx;this.animations=[];this.animationRequestId=null}var I={},t=!!document.createElement("canvas").getContext,ea={Chart:{width:500,height:400,zoomEnabled:!1,zoomType:"x",backgroundColor:"white",theme:"theme1",animationEnabled:!1,
animationDuration:1200,dataPointWidth:null,dataPointMinWidth:null,dataPointMaxWidth:null,colorSet:"colorSet1",culture:"en",creditHref:"",creditText:"CanvasJS",interactivityEnabled:!0,exportEnabled:!1,exportFileName:"Chart",rangeChanging:null,rangeChanged:null,publicProperties:{title:"readWrite",subtitles:"readWrite",toolTip:"readWrite",legend:"readWrite",axisX:"readWrite",axisY:"readWrite",axisX2:"readWrite",axisY2:"readWrite",data:"readWrite",options:"readWrite",bounds:"readOnly",container:"readOnly"}},
Title:{padding:0,text:null,verticalAlign:"top",horizontalAlign:"center",fontSize:20,fontFamily:"Calibri",fontWeight:"normal",fontColor:"black",fontStyle:"normal",borderThickness:0,borderColor:"black",cornerRadius:0,backgroundColor:t?"transparent":null,margin:5,wrap:!0,maxWidth:null,dockInsidePlotArea:!1,publicProperties:{options:"readWrite",bounds:"readOnly",chart:"readOnly"}},Subtitle:{padding:0,text:null,verticalAlign:"top",horizontalAlign:"center",fontSize:14,fontFamily:"Calibri",fontWeight:"normal",
fontColor:"black",fontStyle:"normal",borderThickness:0,borderColor:"black",cornerRadius:0,backgroundColor:null,margin:2,wrap:!0,maxWidth:null,dockInsidePlotArea:!1,publicProperties:{options:"readWrite",bounds:"readOnly",chart:"readOnly"}},Legend:{name:null,verticalAlign:"center",horizontalAlign:"right",fontSize:14,fontFamily:"calibri",fontWeight:"normal",fontColor:"black",fontStyle:"normal",cursor:null,itemmouseover:null,itemmouseout:null,itemmousemove:null,itemclick:null,dockInsidePlotArea:!1,reversed:!1,
backgroundColor:t?"transparent":null,borderColor:t?"transparent":null,borderThickness:0,cornerRadius:0,maxWidth:null,maxHeight:null,markerMargin:null,itemMaxWidth:null,itemWidth:null,itemWrap:!0,itemTextFormatter:null,publicProperties:{options:"readWrite",bounds:"readOnly",chart:"readOnly"}},ToolTip:{enabled:!0,shared:!1,animationEnabled:!0,content:null,contentFormatter:null,reversed:!1,backgroundColor:t?"rgba(255,255,255,.9)":"rgb(255,255,255)",borderColor:null,borderThickness:2,cornerRadius:5,fontSize:14,
fontColor:"black",fontFamily:"Calibri, Arial, Georgia, serif;",fontWeight:"normal",fontStyle:"italic",publicProperties:{options:"readWrite",chart:"readOnly"}},Axis:{minimum:null,maximum:null,viewportMinimum:null,viewportMaximum:null,interval:null,intervalType:null,reversed:!1,logarithmic:!1,logarithmBase:10,title:null,titleFontColor:"black",titleFontSize:20,titleFontFamily:"arial",titleFontWeight:"normal",titleFontStyle:"normal",titleWrap:!0,titleMaxWidth:null,titleBackgroundColor:t?"transparent":
null,titleBorderColor:t?"transparent":null,titleBorderThickness:0,titleCornerRadius:0,labelAngle:0,labelFontFamily:"arial",labelFontColor:"black",labelFontSize:12,labelFontWeight:"normal",labelFontStyle:"normal",labelAutoFit:!0,labelWrap:!0,labelMaxWidth:null,labelFormatter:null,labelBackgroundColor:t?"transparent":null,labelBorderColor:t?"transparent":null,labelBorderThickness:0,labelCornerRadius:0,prefix:"",suffix:"",includeZero:!0,tickLength:5,tickColor:"black",tickThickness:1,lineColor:"black",
lineThickness:1,lineDashType:"solid",gridColor:"A0A0A0",gridThickness:0,gridDashType:"solid",interlacedColor:t?"transparent":null,valueFormatString:null,margin:2,stripLines:[],publicProperties:{options:"readWrite",bounds:"readOnly",chart:"readOnly"}},StripLine:{value:null,startValue:null,endValue:null,color:"orange",opacity:null,thickness:2,lineDashType:"solid",label:"",labelPlacement:"inside",labelAlign:"far",labelWrap:!0,labelMaxWidth:null,labelBackgroundColor:t?"transparent":null,labelBorderColor:t?
"transparent":null,labelBorderThickness:0,labelCornerRadius:0,labelFontFamily:"arial",labelFontColor:"orange",labelFontSize:12,labelFontWeight:"normal",labelFontStyle:"normal",labelFormatter:null,showOnTop:!1,publicProperties:{options:"readWrite",axis:"readOnly",bounds:"readOnly",chart:"readOnly"}},DataSeries:{name:null,dataPoints:null,label:"",bevelEnabled:!1,highlightEnabled:!0,cursor:"default",indexLabel:"",indexLabelPlacement:"auto",indexLabelOrientation:"horizontal",indexLabelFontColor:"black",
indexLabelFontSize:12,indexLabelFontStyle:"normal",indexLabelFontFamily:"Arial",indexLabelFontWeight:"normal",indexLabelBackgroundColor:null,indexLabelLineColor:"gray",indexLabelLineThickness:1,indexLabelLineDashType:"solid",indexLabelMaxWidth:null,indexLabelWrap:!0,indexLabelFormatter:null,lineThickness:2,lineDashType:"solid",connectNullData:!1,nullDataLineDashType:"dash",color:null,lineColor:null,risingColor:"white",fillOpacity:null,startAngle:0,radius:null,innerRadius:null,type:"column",xValueType:"number",
axisXType:"primary",axisYType:"primary",axisXIndex:0,axisYIndex:0,xValueFormatString:null,yValueFormatString:null,zValueFormatString:null,percentFormatString:null,showInLegend:null,legendMarkerType:null,legendMarkerColor:null,legendText:null,legendMarkerBorderColor:t?"transparent":null,legendMarkerBorderThickness:0,markerType:"circle",markerColor:null,markerSize:null,markerBorderColor:t?"transparent":null,markerBorderThickness:0,mouseover:null,mouseout:null,mousemove:null,click:null,toolTipContent:null,
visible:!0,publicProperties:{options:"readWrite",axisX:"readWrite",axisY:"readWrite",chart:"readOnly"}},TextBlock:{x:0,y:0,width:null,height:null,maxWidth:null,maxHeight:null,padding:0,angle:0,text:"",horizontalAlign:"center",fontSize:12,fontFamily:"calibri",fontWeight:"normal",fontColor:"black",fontStyle:"normal",borderThickness:0,borderColor:"black",cornerRadius:0,backgroundColor:null,textBaseline:"top"},CultureInfo:{decimalSeparator:".",digitGroupSeparator:",",zoomText:"Zoom",panText:"Pan",resetText:"Reset",
menuText:"More Options",saveJPGText:"Save as JPEG",savePNGText:"Save as PNG",printText:"Print",days:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),shortDays:"Sun Mon Tue Wed Thu Fri Sat".split(" "),months:"January February March April May June July August September October November December".split(" "),shortMonths:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ")}},ra={en:{}},ja={colorSet1:"#369EAD #C24642 #7F6084 #86B402 #A2D1CF #C8B631 #6DBCEB #52514E #4F81BC #A064A1 #F79647".split(" "),
colorSet2:"#4F81BC #C0504E #9BBB58 #23BFAA #8064A1 #4AACC5 #F79647 #33558B".split(" "),colorSet3:"#8CA1BC #36845C #017E82 #8CB9D0 #708C98 #94838D #F08891 #0366A7 #008276 #EE7757 #E5BA3A #F2990B #03557B #782970".split(" ")},ka={theme1:{Chart:{colorSet:"colorSet1"},Title:{fontFamily:t?"Calibri, Optima, Candara, Verdana, Geneva, sans-serif":"calibri",fontSize:33,fontColor:"#3A3A3A",fontWeight:"bold",verticalAlign:"top",margin:5},Subtitle:{fontFamily:t?"Calibri, Optima, Candara, Verdana, Geneva, sans-serif":
"calibri",fontSize:16,fontColor:"#3A3A3A",fontWeight:"bold",verticalAlign:"top",margin:5},Axis:{titleFontSize:26,titleFontColor:"#666666",titleFontFamily:t?"Calibri, Optima, Candara, Verdana, Geneva, sans-serif":"calibri",labelFontFamily:t?"Calibri, Optima, Candara, Verdana, Geneva, sans-serif":"calibri",labelFontSize:18,labelFontColor:"grey",tickColor:"#BBBBBB",tickThickness:2,gridThickness:2,gridColor:"#BBBBBB",lineThickness:2,lineColor:"#BBBBBB"},Legend:{verticalAlign:"bottom",horizontalAlign:"center",
fontFamily:t?"monospace, sans-serif,arial black":"calibri"},DataSeries:{indexLabelFontColor:"grey",indexLabelFontFamily:t?"Calibri, Optima, Candara, Verdana, Geneva, sans-serif":"calibri",indexLabelFontSize:18,indexLabelLineThickness:1}},theme2:{Chart:{colorSet:"colorSet2"},Title:{fontFamily:"impact, charcoal, arial black, sans-serif",fontSize:32,fontColor:"#333333",verticalAlign:"top",margin:5},Subtitle:{fontFamily:"impact, charcoal, arial black, sans-serif",fontSize:14,fontColor:"#333333",verticalAlign:"top",
margin:5},Axis:{titleFontSize:22,titleFontColor:"rgb(98,98,98)",titleFontFamily:t?"monospace, sans-serif,arial black":"arial",titleFontWeight:"bold",labelFontFamily:t?"monospace, Courier New, Courier":"arial",labelFontSize:16,labelFontColor:"grey",labelFontWeight:"bold",tickColor:"grey",tickThickness:2,gridThickness:2,gridColor:"grey",lineColor:"grey",lineThickness:0},Legend:{verticalAlign:"bottom",horizontalAlign:"center",fontFamily:t?"monospace, sans-serif,arial black":"arial"},DataSeries:{indexLabelFontColor:"grey",
indexLabelFontFamily:t?"Courier New, Courier, monospace":"arial",indexLabelFontWeight:"bold",indexLabelFontSize:18,indexLabelLineThickness:1}},theme3:{Chart:{colorSet:"colorSet1"},Title:{fontFamily:t?"Candara, Optima, Trebuchet MS, Helvetica Neue, Helvetica, Trebuchet MS, serif":"calibri",fontSize:32,fontColor:"#3A3A3A",fontWeight:"bold",verticalAlign:"top",margin:5},Subtitle:{fontFamily:t?"Candara, Optima, Trebuchet MS, Helvetica Neue, Helvetica, Trebuchet MS, serif":"calibri",fontSize:16,fontColor:"#3A3A3A",
fontWeight:"bold",verticalAlign:"top",margin:5},Axis:{titleFontSize:22,titleFontColor:"rgb(98,98,98)",titleFontFamily:t?"Verdana, Geneva, Calibri, sans-serif":"calibri",labelFontFamily:t?"Calibri, Optima, Candara, Verdana, Geneva, sans-serif":"calibri",labelFontSize:18,labelFontColor:"grey",tickColor:"grey",tickThickness:2,gridThickness:2,gridColor:"grey",lineThickness:2,lineColor:"grey"},Legend:{verticalAlign:"bottom",horizontalAlign:"center",fontFamily:t?"monospace, sans-serif,arial black":"calibri"},
DataSeries:{bevelEnabled:!0,indexLabelFontColor:"grey",indexLabelFontFamily:t?"Candara, Optima, Calibri, Verdana, Geneva, sans-serif":"calibri",indexLabelFontSize:18,indexLabelLineColor:"lightgrey",indexLabelLineThickness:2}}},G={numberDuration:1,yearDuration:314496E5,monthDuration:2592E6,weekDuration:6048E5,dayDuration:864E5,hourDuration:36E5,minuteDuration:6E4,secondDuration:1E3,millisecondDuration:1,dayOfWeekFromInt:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" ")};(function(){I.fSDec=
function(a){for(var c="",b=0;b<a.length;b++)c+=String.fromCharCode(Math.ceil(a.length/57/5)^a.charCodeAt(b));return c};I.obj={trVs:"Ush`m!Wdsrhno",fntStr:"qy!B`mhcsh-!Mtbhe`!Fs`oed-!Mtbhe`!R`or!Tohbned-!@sh`m-!r`or,rdshg",txtBl:"udyuC`rdmhod",fnt:"gnou",fSy:"ghmmRuxmd",fTx:"ghmmUdyu",grClr:"fsdx",cntx:"buy",tp:"unq"};delete ea[I.fSDec("Bi`su")][I.fSDec("bsdehuIsdg")];I.pro={sCH:ea[I.fSDec("Bi`su")][I.fSDec("bsdehuIsdg")]};I._fTWm=function(a){if("undefined"===typeof I.pro.sCH&&!Pa)try{var c=a[I.fSDec(I.obj.cntx)];
c[I.fSDec(I.obj.txtBl)]=I.fSDec(I.obj.tp);c[I.fSDec(I.obj.fnt)]=11+I.fSDec(I.obj.fntStr);c[I.fSDec(I.obj.fSy)]=I.fSDec(I.obj.grClr);c[I.fSDec(I.obj.fTx)](I.fSDec(I.obj.trVs),2,a.height-11-2)}catch(b){}}})();var Ma={},da=null,Fa=function(){var a=/D{1,4}|M{1,4}|Y{1,4}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|f{1,3}|t{1,2}|T{1,2}|K|z{1,3}|"[^"]*"|'[^']*'/g,c="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),b="Sun Mon Tue Wed Thu Fri Sat".split(" "),d="January February March April May June July August September October November December".split(" "),
f="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),g=/\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,l=/[^-+\dA-Z]/g;return function(k,h,m){var p=m?m.days:c,n=m?m.months:d,e=m?m.shortDays:b,q=m?m.shortMonths:f;m="";var r=!1;k=k&&k.getTime?k:k?new Date(k):new Date;if(isNaN(k))throw SyntaxError("invalid date");"UTC:"===h.slice(0,4)&&(h=h.slice(4),r=!0);m=r?"getUTC":"get";var s=k[m+"Date"](),x=k[m+"Day"](),
u=k[m+"Month"](),v=k[m+"FullYear"](),z=k[m+"Hours"](),w=k[m+"Minutes"](),t=k[m+"Seconds"](),y=k[m+"Milliseconds"](),A=r?0:k.getTimezoneOffset();return m=h.replace(a,function(a){switch(a){case "D":return s;case "DD":return P(s,2);case "DDD":return e[x];case "DDDD":return p[x];case "M":return u+1;case "MM":return P(u+1,2);case "MMM":return q[u];case "MMMM":return n[u];case "Y":return parseInt(String(v).slice(-2));case "YY":return P(String(v).slice(-2),2);case "YYY":return P(String(v).slice(-3),3);case "YYYY":return P(v,
4);case "h":return z%12||12;case "hh":return P(z%12||12,2);case "H":return z;case "HH":return P(z,2);case "m":return w;case "mm":return P(w,2);case "s":return t;case "ss":return P(t,2);case "f":return String(y).slice(0,1);case "ff":return P(String(y).slice(0,2),2);case "fff":return P(String(y).slice(0,3),3);case "t":return 12>z?"a":"p";case "tt":return 12>z?"am":"pm";case "T":return 12>z?"A":"P";case "TT":return 12>z?"AM":"PM";case "K":return r?"UTC":(String(k).match(g)||[""]).pop().replace(l,"");
case "z":return(0<A?"-":"+")+Math.floor(Math.abs(A)/60);case "zz":return(0<A?"-":"+")+P(Math.floor(Math.abs(A)/60),2);case "zzz":return(0<A?"-":"+")+P(Math.floor(Math.abs(A)/60),2)+P(Math.abs(A)%60,2);default:return a.slice(1,a.length-1)}})}}(),fa=function(a,c,b){if(null===a)return"";a=Number(a);var d=0>a?!0:!1;d&&(a*=-1);var f=b?b.decimalSeparator:".",g=b?b.digitGroupSeparator:",",l="";c=String(c);var l=1,k=b="",h=-1,m=[],p=[],n=0,e=0,q=0,r=!1,s=0,k=c.match(/"[^"]*"|'[^']*'|[eE][+-]*[0]+|[,]+[.]|\u2030|./g);
c=null;for(var x=0;k&&x<k.length;x++)if(c=k[x],"."===c&&0>h)h=x;else{if("%"===c)l*=100;else if("\u2030"===c){l*=1E3;continue}else if(","===c[0]&&"."===c[c.length-1]){l/=Math.pow(1E3,c.length-1);h=x+c.length-1;continue}else"E"!==c[0]&&"e"!==c[0]||"0"!==c[c.length-1]||(r=!0);0>h?(m.push(c),"#"===c||"0"===c?n++:","===c&&q++):(p.push(c),"#"!==c&&"0"!==c||e++)}r&&(c=Math.floor(a),k=-Math.floor(Math.log(a)/Math.LN10+1),s=0===a?0:0===c?-(n+k):String(c).length-n,l/=Math.pow(10,s));0>h&&(h=x);l=(a*l).toFixed(e);
c=l.split(".");l=(c[0]+"").split("");a=(c[1]+"").split("");l&&"0"===l[0]&&l.shift();for(r=k=x=e=h=0;0<m.length;)if(c=m.pop(),"#"===c||"0"===c)if(h++,h===n){var u=l,l=[];if("0"===c)for(c=n-e-(u?u.length:0);0<c;)u.unshift("0"),c--;for(;0<u.length;)b=u.pop()+b,r++,0===r%k&&(x===q&&0<u.length)&&(b=g+b)}else 0<l.length?(b=l.pop()+b,e++,r++):"0"===c&&(b="0"+b,e++,r++),0===r%k&&(x===q&&0<l.length)&&(b=g+b);else"E"!==c[0]&&"e"!==c[0]||"0"!==c[c.length-1]||!/[eE][+-]*[0]+/.test(c)?","===c?(x++,k=r,r=0,0<l.length&&
(b=g+b)):b=1<c.length&&('"'===c[0]&&'"'===c[c.length-1]||"'"===c[0]&&"'"===c[c.length-1])?c.slice(1,c.length-1)+b:c+b:(c=0>s?c.replace("+","").replace("-",""):c.replace("-",""),b+=c.replace(/[0]+/,function(a){return P(s,a.length)}));g="";for(m=!1;0<p.length;)c=p.shift(),"#"===c||"0"===c?0<a.length&&0!==Number(a.join(""))?(g+=a.shift(),m=!0):"0"===c&&(g+="0",m=!0):1<c.length&&('"'===c[0]&&'"'===c[c.length-1]||"'"===c[0]&&"'"===c[c.length-1])?g+=c.slice(1,c.length-1):"E"!==c[0]&&"e"!==c[0]||"0"!==c[c.length-
1]||!/[eE][+-]*[0]+/.test(c)?g+=c:(c=0>s?c.replace("+","").replace("-",""):c.replace("-",""),g+=c.replace(/[0]+/,function(a){return P(s,a.length)}));b+=(m?f:"")+g;return d?"-"+b:b},za=function(a){var c=0,b=0;a=a||window.event;a.offsetX||0===a.offsetX?(c=a.offsetX,b=a.offsetY):a.layerX||0==a.layerX?(c=a.layerX,b=a.layerY):(c=a.pageX-a.target.offsetLeft,b=a.pageY-a.target.offsetTop);return{x:c,y:b}},Oa=!0,Ba=window.devicePixelRatio||1,ua=1,Q=Oa?Ba/ua:1,S=function(a){for(var c="",b=0;b<a.length;b++)c+=
String.fromCharCode(Math.ceil(a.length/57/5)^a.charCodeAt(b));return c},Pa=window&&window[S("mnb`uhno")]&&window[S("mnb`uhno")].href&&window[S("mnb`uhno")].href.indexOf&&(-1!==window[S("mnb`uhno")].href.indexOf(S("b`ow`rkr/bnl"))||-1!==window[S("mnb`uhno")].href.indexOf(S("gdonqhy/bnl"))||-1!==window[S("mnb`uhno")].href.indexOf(S("gheemd"))),Wa={reset:{image:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAcCAYAAAAAwr0iAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAKRSURBVEiJrdY/iF1FFMfxzwnZrGISUSR/JLGIhoh/QiRNBLWxMLIWEkwbgiAoFgoW2mhlY6dgpY2IlRBRxBSKhSAKIklWJRYuMZKAhiyopAiaTY7FvRtmZ+/ed9/zHRjezLw5v/O9d86cuZGZpmURAfdn5o9DfdZNLXpjz+LziPgyIl6MiG0jPTJzZBuyDrP4BVm0P/AKbljTb4ToY/gGewYA7KyCl+1b3DUYANvwbiHw0gCAGRzBOzjTAXEOu0cC4Ch+r5x/HrpdrcZmvIDFSucMtnYCYC++6HmNDw8FKDT34ETrf639/azOr5vwRk/g5fbeuABtgC04XWk9VQLciMP4EH/3AFzErRNC7MXlQmsesSoHsGPE23hmEoBW+61K66HMXFmIMvN8myilXS36R01ub+KfYvw43ZXwYDX+AHP4BAci4pFJomfmr/ihmNofESsBImJGk7mlncrM45n5JPbhz0kAWpsv+juxaX21YIPmVJS2uNzJMS6ZNexC0d+I7fUWXLFyz2kSZlpWPvASlmqAf/FXNXf3FAF2F/1LuFifAlionB6dRuSI2IwHi6lzmXmp6xR8XY0fiIh7psAwh+3FuDkRHQVjl+a8lkXjo0kLUKH7XaV5oO86PmZ1FTzyP4K/XGl9v/zwfbW7BriiuETGCP5ch9bc9f97HF/vcFzCa5gdEPgWq+t/4v0V63oE1uF4h0DiFJ7HnSWMppDdh1dxtsPvJ2wcBNAKbsJXa0Ck5opdaBPsRNu/usba09i1KsaAVzmLt3sghrRjuK1Tf4xkegInxwy8gKf7dKMVH2QRsV5zXR/Cftyu+aKaKbbkQrsdH+PTzLzcqzkOQAVzM+7FHdiqqe2/YT4zF/t8S/sPmawyvC974vcAAAAASUVORK5CYII="},
pan:{image:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAJVSURBVFiFvZe7a1RBGMV/x2hWI4JpfKCIiSBKOoOCkID/wP4BFqIIFkE02ChIiC8QDKlSiI3YqRBsBVGwUNAUdiIEUgjiAzQIIsuKJsfizsXr5t7d+8jmwLDfzHz3nLOzc7+ZxTZlGyDgZiWOCuJ9wH2gCUyuqQFgF/AGcKJNrYkBYBj40CIet+muGQi/96kM4WS7C/Tm5VUg7whJg8BkEGkCR4BDYfodsADUgP6wErO5iCtswsuJb32hdbXy8qzL5TIdmzJinHdZoZIBZcSFkGlAKs1Z3YCketZcBtouuaQNkrblMiBpBrhme7mAgU4wMCvpcFsDkq4C54DFVRTH9h+i6vlE0r5UA5ImgCuh28jB28iIs7BIVCOeStoZD64P4uPAjUTygKSx2FsK2TIwkugfk9Qkfd/E+yMWHQCeSRqx/R3gOp3LazfaS2C4B5gHDgD7U9x3E3uAH7KNpC3AHHAwTL4FHgM9GQ8vAaPA0dB/Abxqk2/gBLA9MXba9r1k/d4LfA3JtwueBeM58ucS+edXnAW23wP10N3advEi9CXizTnyN4bPS7Zn4sH/dq3t18AY4e1YLYSy3g/csj2VnFshZPuOpOeSKHCodUINuGj7YetE6je1PV9QoNPJ9StNHKodx7nRbiWrGHBGXAi5DUiqtQwtpcWK0Jubt8CltA5MEV1IfwO7+VffPwGfia5m34CT4bXujIIX0Qna1/cGMNqV/wUJE2czxD8CQ4X5Sl7Jz7SILwCDpbjKPBRMHAd+EtX4HWV5Spdc2w8kDQGPbH8py/MXMygM69/FKz4AAAAASUVORK5CYII="},
zoom:{image:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK6wAACusBgosNWgAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAMqSURBVFiFvdfbj91TFMDxz57U6GUEMS1aYzyMtCSSDhWjCZMInpAI3khE/QHtgzdRkXgSCS8SES9epKLi0oRKNETjRahREq2KS1stdRujtDPtbA97n5zdn9+5zJxTK9k5v3POXmt991p7r71+IcaoGwkhTOIebMRqzOBTvIG3Y4zTXRmqSoyx5cAKbMJOHMFJnMZ8/jyFaXyMR7G6nb1aH22cP4BvcBxziG3GKfyTIR9D6BYg1KUghPBCDveFlb/24Av8iuUYw41YVsz5G7uxKcZ4aMEpwGt5NY3V/YbHsQ6rcAHOw/kYxigewr5CZw4fYGxBKcCLOFEYehXrMdRhr5yLETxVScsOLOkKAPfn1TYMPIvLFrShUlS2FDZm8XRHACzFAWl3R2xbqPMCYhmeLCAOYEMngAczbcTvuHYxzguIy/FesR9e6gSwU/OoPYHBHgHgviIKX2Flq7k34KhmcVnbi/PC8JX4MgMcxb118wZwdz5aISscqx7VRcox7MrPQ7i+btIAJrAkf9+bI9EPmZY2IAxiTSuAldLq4Y9+AcSUh78KP0tbAcwU35cXMD1JCIFUoGiehlqAz6TNB1f1C0DK+0h+nsNPrQC2a4bqGmlD9kOGcWt+Po6pVgDvSxfJaSkFd4UQBvoAsBYbCoB3a2flM7slA0R8iyt6rAFDeDPbm8eOTpVwGD9qVq7nLbIaZnmksPU1JtsCZMXNmpdRxFasWITzh6Xj3LCzra1OxcD2QjHiGVzdpfORnMqZio2PcF23ABdJF1Np4BPptlyPi6WzPYBzpJZtHe7A6xW9cnyP8TqA//SEIYRL8Bxul7rihvwgtVn78WcGGZXa9HGd5TDujDHuOePXNiHdKjWgZX/YbsxLx/ktqbjVzTlcjUSnvI5JrdlUVp6WesZZ6R1hRrpq9+EVTGS9jTjYAuKIouGpbcurEkIYxC051KNSamazsc+xK8b4S0VnEi/j0hqTP+M27O258egQwZuzs7pI7Mf4WQXIEDc5s9sux+5+1Py2EmP8UOq6GvWhIScxfdYjUERiAt9Jd84J6a16zf8JEKT3yCm8g1UxRv8CC4pyRhzR1uUAAAAASUVORK5CYII="},
menu:{image:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAgCAYAAAAbifjMAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK6wAACusBgosNWgAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAAWdEVYdENyZWF0aW9uIFRpbWUAMDcvMTUvMTTPsvU0AAAAP0lEQVRIie2SMQoAIBDDUvH/X667g8sJJ9KOhYYOkW0qGaU1MPdC0vGSbV19EACo3YMPAFH5BUBUjsqfAPpVXtNgGDfxEDCtAAAAAElFTkSuQmCC"}};L.prototype.setOptions=function(a,c){if(ea[this._defaultsKey]){var b=ea[this._defaultsKey],d;for(d in b)"publicProperties"!==d&&b.hasOwnProperty(d)&&(this[d]=
a&&d in a?a[d]:c&&d in c?c[d]:b[d])}};L.prototype.get=function(a){var c=ea[this._defaultsKey];if("options"===a)return this.options&&this.options._isPlaceholder?null:this.options;if(c.hasOwnProperty(a)||c.publicProperties&&c.publicProperties.hasOwnProperty(a))return this[a];window.console&&window.console.log('Property "'+a+"\" doesn't exist. Please check for typo.")};L.prototype.set=function(a,c,b){b="undefined"===typeof b?!0:b;var d=ea[this._defaultsKey];if("options"===a)this.createUserOptions(c);
else if(d.hasOwnProperty(a)||d.publicProperties&&d.publicProperties.hasOwnProperty(a)&&"readWrite"===d.publicProperties[a])this.options._isPlaceholder&&this.createUserOptions(),this.options[a]=c;else{window.console&&(d.publicProperties&&d.publicProperties.hasOwnProperty(a)&&"readOnly"===d.publicProperties[a]?window.console.log('Property "'+a+'" is read-only.'):window.console.log('Property "'+a+"\" doesn't exist. Please check for typo."));return}b&&(this.chart||this).render()};L.prototype.addTo=function(a,
c,b,d){d="undefined"===typeof d?!0:d;var f=ea[this._defaultsKey];f.hasOwnProperty(a)||f.publicProperties&&f.publicProperties.hasOwnProperty(a)&&"readWrite"===f.publicProperties[a]?(this.options._isPlaceholder&&this.createUserOptions(),"undefined"===typeof this.options[a]&&(this.options[a]=[]),a=this.options[a],b="undefined"===typeof b||null===b?a.length:b,a.splice(b,0,c),d&&(this.chart||this).render()):window.console&&(f.publicProperties&&f.publicProperties.hasOwnProperty(a)&&"readOnly"===f.publicProperties[a]?
window.console.log('Property "'+a+'" is read-only.'):window.console.log('Property "'+a+"\" doesn't exist. Please check for typo."))};L.prototype.createUserOptions=function(a){if("undefined"!==typeof a||this.options._isPlaceholder)if(this.parent.options._isPlaceholder&&this.parent.createUserOptions(),this.isOptionsInArray){this.parent.options[this.optionsName]||(this.parent.options[this.optionsName]=[]);var c=this.parent.options[this.optionsName],b=c.length;this.options._isPlaceholder||(sa(c),b=c.indexOf(this.options));
this.options="undefined"===typeof a?{}:a;c[b]=this.options}else this.options="undefined"===typeof a?{}:a,a=this.parent.options,this.optionsName?c=this.optionsName:(c=this._defaultsKey)&&0!==c.length?(b=c.charAt(0).toLowerCase(),1<c.length&&(b=b.concat(c.slice(1))),c=b):c=void 0,a[c]=this.options};L.prototype.remove=function(a){a="undefined"===typeof a?!0:a;if(this.isOptionsInArray){var c=this.parent.options[this.optionsName];sa(c);var b=c.indexOf(this.options);0<=b&&c.splice(b,1)}else delete this.parent.options[this.optionsName];
a&&(this.chart||this).render()};L.prototype.updateOption=function(a){var c=ea[this._defaultsKey],b=this.options.theme?this.options.theme:this.chart&&this.chart.options.theme?this.chart.options.theme:"theme1",d={},f=this[a];b&&(ka[b]&&ka[b][this._defaultsKey])&&(d=ka[b][this._defaultsKey]);a in c&&(f=a in this.options?this.options[a]:d&&a in d?d[a]:c[a]);if(f===this[a])return!1;this[a]=f;return!0};L.prototype.trackChanges=function(a){if(!this.sessionVariables)throw"Session Variable Store not set";
this.sessionVariables[a]=this.options[a]};L.prototype.isBeingTracked=function(a){this.options._oldOptions||(this.options._oldOptions={});return this.options._oldOptions[a]?!0:!1};L.prototype.hasOptionChanged=function(a){if(!this.sessionVariables)throw"Session Variable Store not set";return this.sessionVariables[a]!==this.options[a]};L.prototype.addEventListener=function(a,c,b){a&&c&&(this._eventListeners[a]=this._eventListeners[a]||[],this._eventListeners[a].push({context:b||this,eventHandler:c}))};
L.prototype.removeEventListener=function(a,c){if(a&&c&&this._eventListeners[a])for(var b=this._eventListeners[a],d=0;d<b.length;d++)if(b[d].eventHandler===c){b[d].splice(d,1);break}};L.prototype.removeAllEventListeners=function(){this._eventListeners=[]};L.prototype.dispatchEvent=function(a,c,b){if(a&&this._eventListeners[a]){c=c||{};for(var d=this._eventListeners[a],f=0;f<d.length;f++)d[f].eventHandler.call(d[f].context,c)}"function"===typeof this[a]&&this[a].call(b||this.chart,c)};T(A,L);A.prototype.destroy=
function(){var a=window,c=this.windowResizeHandler;a.removeEventListener?a.removeEventListener("resize",c):a.detachEvent&&a.detachEvent("onresize",c)};A.prototype._updateOptions=function(){var a=this;this.updateOption("width");this.updateOption("height");this.updateOption("dataPointWidth");this.updateOption("dataPointMinWidth");this.updateOption("dataPointMaxWidth");this.updateOption("interactivityEnabled");this.updateOption("theme");this.updateOption("colorSet")&&(this._selectedColorSet="undefined"!==
typeof ja[this.colorSet]?ja[this.colorSet]:ja.colorSet1);this.updateOption("backgroundColor");this.backgroundColor||(this.backgroundColor="rgba(0,0,0,0)");this.updateOption("culture");this._cultureInfo=new qa(this.options.culture);this.updateOption("animationEnabled");this.animationEnabled=this.animationEnabled&&t;this.updateOption("animationDuration");this.updateOption("rangeChanging");this.updateOption("rangeChanged");this.updateOption("exportEnabled");this.updateOption("exportFileName");this.updateOption("zoomType");
this.options.zoomEnabled?(this._zoomButton||(aa(this._zoomButton=document.createElement("button")),$(this,this._zoomButton,"pan"),this._toolBar.appendChild(this._zoomButton),J(this._zoomButton,"click",function(){a.zoomEnabled?(a.zoomEnabled=!1,a.panEnabled=!0,$(a,a._zoomButton,"zoom")):(a.zoomEnabled=!0,a.panEnabled=!1,$(a,a._zoomButton,"pan"));a.render()})),this._resetButton||(aa(this._resetButton=document.createElement("button")),$(this,this._resetButton,"reset"),this._toolBar.appendChild(this._resetButton),
J(this._resetButton,"click",function(){a.toolTip.hide();a.zoomEnabled||a.panEnabled?(a.zoomEnabled=!0,a.panEnabled=!1,$(a,a._zoomButton,"pan"),a._defaultCursor="default",a.overlaidCanvas.style.cursor=a._defaultCursor):(a.zoomEnabled=!1,a.panEnabled=!1);if(a.sessionVariables.axisX)for(var b=0;b<a.sessionVariables.axisX.length;b++)a.sessionVariables.axisX[b].newViewportMinimum=null,a.sessionVariables.axisX[b].newViewportMaximum=null;if(a.sessionVariables.axisX2)for(b=0;b<a.sessionVariables.axisX2.length;b++)a.sessionVariables.axisX2[b].newViewportMinimum=
null,a.sessionVariables.axisX2[b].newViewportMaximum=null;if(a.sessionVariables.axisY)for(b=0;b<a.sessionVariables.axisY.length;b++)a.sessionVariables.axisY[b].newViewportMinimum=null,a.sessionVariables.axisY[b].newViewportMaximum=null;if(a.sessionVariables.axisY2)for(b=0;b<a.sessionVariables.axisY2.length;b++)a.sessionVariables.axisY2[b].newViewportMinimum=null,a.sessionVariables.axisY2[b].newViewportMaximum=null;a.resetOverlayedCanvas();aa(a._zoomButton,a._resetButton);a._dispatchRangeEvent("rangeChanging",
"reset");a.render();a._dispatchRangeEvent("rangeChanged","reset")}),this.overlaidCanvas.style.cursor=a._defaultCursor),this.zoomEnabled||this.panEnabled||(this._zoomButton?(a._zoomButton.getAttribute("state")===a._cultureInfo.zoomText?(this.panEnabled=!0,this.zoomEnabled=!1):(this.zoomEnabled=!0,this.panEnabled=!1),va(a._zoomButton,a._resetButton)):(this.zoomEnabled=!0,this.panEnabled=!1))):this.panEnabled=this.zoomEnabled=!1;this._menuButton?this.exportEnabled?va(this._menuButton):aa(this._menuButton):
this.exportEnabled&&t&&(this._menuButton=document.createElement("button"),$(this,this._menuButton,"menu"),this._toolBar.appendChild(this._menuButton),J(this._menuButton,"click",function(){"none"!==a._dropdownMenu.style.display||a._dropDownCloseTime&&500>=(new Date).getTime()-a._dropDownCloseTime.getTime()||(a._dropdownMenu.style.display="block",a._menuButton.blur(),a._dropdownMenu.focus())},!0));if(!this._dropdownMenu&&this.exportEnabled&&t){this._dropdownMenu=document.createElement("div");this._dropdownMenu.setAttribute("tabindex",
-1);this._dropdownMenu.style.cssText="position: absolute; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; cursor: pointer;right: 1px;top: 25px;min-width: 120px;outline: 0;border: 1px solid silver;font-size: 14px;font-family: Calibri, Verdana, sans-serif;padding: 5px 0px 5px 0px;text-align: left;background-color: #fff;line-height: 20px;box-shadow: 2px 2px 10px #888888;";a._dropdownMenu.style.display="none";this._toolBar.appendChild(this._dropdownMenu);J(this._dropdownMenu,
"blur",function(){aa(a._dropdownMenu);a._dropDownCloseTime=new Date},!0);var c=document.createElement("div");c.style.cssText="padding: 2px 15px 2px 10px";c.innerHTML=this._cultureInfo.printText;this._dropdownMenu.appendChild(c);J(c,"mouseover",function(){this.style.backgroundColor="#EEEEEE"},!0);J(c,"mouseout",function(){this.style.backgroundColor="transparent"},!0);J(c,"click",function(){a.print();aa(a._dropdownMenu)},!0);c=document.createElement("div");c.style.cssText="padding: 2px 15px 2px 10px";
c.innerHTML=this._cultureInfo.saveJPGText;this._dropdownMenu.appendChild(c);J(c,"mouseover",function(){this.style.backgroundColor="#EEEEEE"},!0);J(c,"mouseout",function(){this.style.backgroundColor="transparent"},!0);J(c,"click",function(){Ca(a.canvas,"jpeg",a.exportFileName);aa(a._dropdownMenu)},!0);c=document.createElement("div");c.style.cssText="padding: 2px 15px 2px 10px";c.innerHTML=this._cultureInfo.savePNGText;this._dropdownMenu.appendChild(c);J(c,"mouseover",function(){this.style.backgroundColor=
"#EEEEEE"},!0);J(c,"mouseout",function(){this.style.backgroundColor="transparent"},!0);J(c,"click",function(){Ca(a.canvas,"png",a.exportFileName);aa(a._dropdownMenu)},!0)}"none"!==this._toolBar.style.display&&this._zoomButton&&(this.panEnabled?$(a,a._zoomButton,"zoom"):$(a,a._zoomButton,"pan"),a._resetButton.getAttribute("state")!==a._cultureInfo.resetText&&$(a,a._resetButton,"reset"));this.options.toolTip&&this.toolTip.options!==this.options.toolTip&&(this.toolTip.options=this.options.toolTip);for(var b in this.toolTip.options)this.toolTip.options.hasOwnProperty(b)&&
this.toolTip.updateOption(b)};A.prototype._updateSize=function(){var a=0,c=0;this.options.width?a=this.width:this.width=a=0<this.container.clientWidth?this.container.clientWidth:this.width;this.options.height?c=this.height:this.height=c=0<this.container.clientHeight?this.container.clientHeight:this.height;return this.canvas.width!==a*Q||this.canvas.height!==c*Q?(ta(this.canvas,a,c),ta(this.overlaidCanvas,a,c),ta(this._eventManager.ghostCanvas,a,c),!0):!1};A.prototype._initialize=function(){this._animator?
this._animator.cancelAllAnimations():this._animator=new Ea(this);this.removeAllEventListeners();this.disableToolTip=!1;this._axes=[];this.pieDoughnutClickHandler=null;this.animationRequestId&&this.cancelRequestAnimFrame.call(window,this.animationRequestId);this._updateOptions();this.animatedRender=t&&this.animationEnabled&&0===this.renderCount;this._updateSize();this.clearCanvas();this.ctx.beginPath();this.axisX=[];this.axisX2=[];this.axisY=[];this.axisY2=[];this._indexLabels=[];this._dataInRenderedOrder=
[];this._events=[];this._eventManager&&this._eventManager.reset();this.plotInfo={axisPlacement:null,axisXValueType:null,plotTypes:[]};this.layoutManager=new la(0,0,this.width,this.height,2);this.plotArea.layoutManager&&this.plotArea.layoutManager.reset();this.data=[];var a=0;if(this.options.data)for(var c=0;c<this.options.data.length;c++)if(a++,!this.options.data[c].type||0<=A._supportedChartTypes.indexOf(this.options.data[c].type)){var b=new ca(this,this.options.data[c],a-1,++this._eventManager.lastObjectId);
null===b.name&&(b.name="DataSeries "+a);null===b.color?1<this.options.data.length?(b._colorSet=[this._selectedColorSet[b.index%this._selectedColorSet.length]],b.color=this._selectedColorSet[b.index%this._selectedColorSet.length]):b._colorSet="line"===b.type||"stepLine"===b.type||"spline"===b.type||"area"===b.type||"stepArea"===b.type||"splineArea"===b.type||"stackedArea"===b.type||"stackedArea100"===b.type||"rangeArea"===b.type||"rangeSplineArea"===b.type||"candlestick"===b.type||"ohlc"===b.type?
[this._selectedColorSet[0]]:this._selectedColorSet:b._colorSet=[b.color];null===b.markerSize&&(("line"===b.type||"stepLine"===b.type||"spline"===b.type||0<=b.type.toLowerCase().indexOf("area"))&&b.dataPoints&&b.dataPoints.length<this.width/16||"scatter"===b.type)&&(b.markerSize=8);"bubble"!==b.type&&"scatter"!==b.type||!b.dataPoints||(b.dataPoints.some?b.dataPoints.some(function(a){return a.x})&&b.dataPoints.sort(Ka):b.dataPoints.sort(Ka));this.data.push(b);var d=b.axisPlacement,f;"normal"===d?"xySwapped"===
this.plotInfo.axisPlacement?f='You cannot combine "'+b.type+'" with bar chart':"none"===this.plotInfo.axisPlacement?f='You cannot combine "'+b.type+'" with pie chart':null===this.plotInfo.axisPlacement&&(this.plotInfo.axisPlacement="normal"):"xySwapped"===d?"normal"===this.plotInfo.axisPlacement?f='You cannot combine "'+b.type+'" with line, area, column or pie chart':"none"===this.plotInfo.axisPlacement?f='You cannot combine "'+b.type+'" with pie chart':null===this.plotInfo.axisPlacement&&(this.plotInfo.axisPlacement=
"xySwapped"):"none"==d&&("normal"===this.plotInfo.axisPlacement?f='You cannot combine "'+b.type+'" with line, area, column or bar chart':"xySwapped"===this.plotInfo.axisPlacement?f='You cannot combine "'+b.type+'" with bar chart':null===this.plotInfo.axisPlacement&&(this.plotInfo.axisPlacement="none"));if(f&&window.console){window.console.log(f);return}}this._objectsInitialized=!0};A._supportedChartTypes=sa("line stepLine spline column area stepArea splineArea bar bubble scatter stackedColumn stackedColumn100 stackedBar stackedBar100 stackedArea stackedArea100 candlestick ohlc rangeColumn rangeBar rangeArea rangeSplineArea pie doughnut funnel".split(" "));
A.prototype.render=function(a){a&&(this.options=a);this._initialize();Ua(this);Va(this);var c=[];for(a=0;a<this.data.length;a++)if("normal"===this.plotInfo.axisPlacement||"xySwapped"===this.plotInfo.axisPlacement){if(!this.data[a].axisYType||"primary"===this.data[a].axisYType)if(this.options.axisY&&0<this.options.axisY.length){if(!this.axisY.length)for(var b=0;b<this.options.axisY.length;b++)"normal"===this.plotInfo.axisPlacement?this._axes.push(this.axisY[b]=new B(this,this.options.axisY[b],"axisY",
"left",b)):"xySwapped"===this.plotInfo.axisPlacement&&this._axes.push(this.axisY[b]=new B(this,this.options.axisY[b],"axisY","bottom",b));this.data[a].axisY=this.axisY[0<=this.data[a].axisYIndex&&this.data[a].axisYIndex<this.axisY.length?this.data[a].axisYIndex:0];this.axisY[0<=this.data[a].axisYIndex&&this.data[a].axisYIndex<this.axisY.length?this.data[a].axisYIndex:0].dataSeries.push(this.data[a])}else this.axisY.length||("normal"===this.plotInfo.axisPlacement?this._axes.push(this.axisY[0]=new B(this,
this.options.axisY,"axisY","left",0)):"xySwapped"===this.plotInfo.axisPlacement&&this._axes.push(this.axisY[0]=new B(this,this.options.axisY,"axisY","bottom",0))),this.data[a].axisY=this.axisY[0],this.axisY[0].dataSeries.push(this.data[a]);if("secondary"===this.data[a].axisYType)if(this.options.axisY2&&0<this.options.axisY2.length){if(!this.axisY2.length)for(b=0;b<this.options.axisY2.length;b++)"normal"===this.plotInfo.axisPlacement?this._axes.push(this.axisY2[b]=new B(this,this.options.axisY2[b],
"axisY","right",b)):"xySwapped"===this.plotInfo.axisPlacement&&this._axes.push(this.axisY2[b]=new B(this,this.options.axisY2[b],"axisY","top",b));this.data[a].axisY=this.axisY2[0<=this.data[a].axisYIndex&&this.data[a].axisYIndex<this.axisY2.length?this.data[a].axisYIndex:0];this.axisY2[0<=this.data[a].axisYIndex&&this.data[a].axisYIndex<this.axisY2.length?this.data[a].axisYIndex:0].dataSeries.push(this.data[a])}else this.axisY2.length||("normal"===this.plotInfo.axisPlacement?this._axes.push(this.axisY2[0]=
new B(this,this.options.axisY2,"axisY","right",0)):"xySwapped"===this.plotInfo.axisPlacement&&this._axes.push(this.axisY2[0]=new B(this,this.options.axisY2,"axisY","top",0))),this.data[a].axisY=this.axisY2[0],this.axisY2[0].dataSeries.push(this.data[a]);if(!this.data[a].axisXType||"primary"===this.data[a].axisXType)if(this.options.axisX&&0<this.options.axisX.length){if(!this.axisX.length)for(b=0;b<this.options.axisX.length;b++)"normal"===this.plotInfo.axisPlacement?this._axes.push(this.axisX[b]=new B(this,
this.options.axisX[b],"axisX","bottom",b)):"xySwapped"===this.plotInfo.axisPlacement&&this._axes.push(this.axisX[b]=new B(this,this.options.axisX[b],"axisX","left",b));this.data[a].axisX=this.axisX[0<=this.data[a].axisXIndex&&this.data[a].axisXIndex<this.axisX.length?this.data[a].axisXIndex:0];this.axisX[0<=this.data[a].axisXIndex&&this.data[a].axisXIndex<this.axisX.length?this.data[a].axisXIndex:0].dataSeries.push(this.data[a])}else this.axisX.length||("normal"===this.plotInfo.axisPlacement?this._axes.push(this.axisX[0]=
new B(this,this.options.axisX,"axisX","bottom",0)):"xySwapped"===this.plotInfo.axisPlacement&&this._axes.push(this.axisX[0]=new B(this,this.options.axisX,"axisX","left",0))),this.data[a].axisX=this.axisX[0],this.axisX[0].dataSeries.push(this.data[a]);if("secondary"===this.data[a].axisXType)if(this.options.axisX2&&0<this.options.axisX2.length){if(!this.axisX2.length)for(b=0;b<this.options.axisX2.length;b++)"normal"===this.plotInfo.axisPlacement?this._axes.push(this.axisX2[b]=new B(this,this.options.axisX2[b],
"axisX","top",b)):"xySwapped"===this.plotInfo.axisPlacement&&this._axes.push(this.axisX2[b]=new B(this,this.options.axisX2[b],"axisX","right",b));this.data[a].axisX=this.axisX2[0<=this.data[a].axisXIndex&&this.data[a].axisXIndex<this.axisX2.length?this.data[a].axisXIndex:0];this.axisX2[0<=this.data[a].axisXIndex&&this.data[a].axisXIndex<this.axisX2.length?this.data[a].axisXIndex:0].dataSeries.push(this.data[a])}else this.axisX2.length||("normal"===this.plotInfo.axisPlacement?this._axes.push(this.axisX2[0]=
new B(this,this.options.axisX2,"axisX","top",0)):"xySwapped"===this.plotInfo.axisPlacement&&this._axes.push(this.axisX2[0]=new B(this,this.options.axisX2,"axisX","right",0))),this.data[a].axisX=this.axisX2[0],this.axisX2[0].dataSeries.push(this.data[a])}if(this.axisY){for(b=1;b<this.axisY.length;b++)"undefined"===typeof this.axisY[b].options.gridThickness&&(this.axisY[b].gridThickness=0);for(b=0;b<this.axisY.length-1;b++)"undefined"===typeof this.axisY[b].options.margin&&(this.axisY[b].margin=10)}if(this.axisY2){for(b=
1;b<this.axisY2.length;b++)"undefined"===typeof this.axisY2[b].options.gridThickness&&(this.axisY2[b].gridThickness=0);for(b=0;b<this.axisY2.length-1;b++)"undefined"===typeof this.axisY2[b].options.margin&&(this.axisY2[b].margin=10)}this.axisY&&0<this.axisY.length&&(this.axisY2&&0<this.axisY2.length)&&(0<this.axisY[0].gridThickness&&"undefined"===typeof this.axisY2[0].options.gridThickness?this.axisY2[0].gridThickness=0:0<this.axisY2[0].gridThickness&&"undefined"===typeof this.axisY[0].options.gridThickness&&
(this.axisY[0].gridThickness=0));if(this.axisX)for(b=0;b<this.axisX.length;b++)"undefined"===typeof this.axisX[b].options.gridThickness&&(this.axisX[b].gridThickness=0);if(this.axisX2)for(b=0;b<this.axisX2.length;b++)"undefined"===typeof this.axisX2[b].options.gridThickness&&(this.axisX2[b].gridThickness=0);this.axisX&&0<this.axisX.length&&(this.axisX2&&0<this.axisX2.length)&&(0<this.axisX[0].gridThickness&&"undefined"===typeof this.axisX2[0].options.gridThickness?this.axisX2[0].gridThickness=0:0<
this.axisX2[0].gridThickness&&"undefined"===typeof this.axisX[0].options.gridThickness&&(this.axisX[0].gridThickness=0));b=!1;if(0<this._axes.length&&(this.zoomEnabled||this.panEnabled))for(a=0;a<this._axes.length;a++)if(null!==this._axes[a].viewportMinimum||null!==this._axes[a].viewportMaximum){b=!0;break}b?va(this._zoomButton,this._resetButton):(aa(this._zoomButton,this._resetButton),this.options.zoomEnabled&&(this.zoomEnabled=!0,this.panEnabled=!1));this._processData();this.options.title&&(this.title=
new oa(this,this.options.title),this.title.dockInsidePlotArea?c.push(this.title):this.title.render());if(this.options.subtitles)for(this.subtitles=[],a=0;a<this.options.subtitles.length;a++)b=new xa(this,this.options.subtitles[a]),this.subtitles.push(b),b.dockInsidePlotArea?c.push(b):b.render();this.legend=new ya(this,this.options.legend);for(a=0;a<this.data.length;a++)(this.data[a].showInLegend||"pie"===this.data[a].type||"doughnut"===this.data[a].type)&&this.legend.dataSeries.push(this.data[a]);
this.legend.dockInsidePlotArea?c.push(this.legend):this.legend.render();if("normal"===this.plotInfo.axisPlacement||"xySwapped"===this.plotInfo.axisPlacement)B.setLayoutAndRender(this.axisX,this.axisX2,this.axisY,this.axisY2,this.plotInfo.axisPlacement,this.layoutManager.getFreeSpace());else if("none"===this.plotInfo.axisPlacement)this.preparePlotArea();else return;for(a=0;a<c.length;a++)c[a].render();var d=[];if(this.animatedRender){var f=ia(this.width,this.height);f.getContext("2d").drawImage(this.canvas,
0,0,this.width,this.height)}var c=this.ctx.miterLimit,g;this.ctx.miterLimit=3;for(a=0;a<this.plotInfo.plotTypes.length;a++)for(var l=this.plotInfo.plotTypes[a],k=0;k<l.plotUnits.length;k++){var h=l.plotUnits[k],m=null;h.targetCanvas=null;this.animatedRender&&(h.targetCanvas=ia(this.width,this.height),h.targetCanvasCtx=h.targetCanvas.getContext("2d"),g=h.targetCanvasCtx.miterLimit,h.targetCanvasCtx.miterLimit=3);"line"===h.type?m=this.renderLine(h):"stepLine"===h.type?m=this.renderStepLine(h):"spline"===
h.type?m=this.renderSpline(h):"column"===h.type?m=this.renderColumn(h):"bar"===h.type?m=this.renderBar(h):"area"===h.type?m=this.renderArea(h):"stepArea"===h.type?m=this.renderStepArea(h):"splineArea"===h.type?m=this.renderSplineArea(h):"stackedColumn"===h.type?m=this.renderStackedColumn(h):"stackedColumn100"===h.type?m=this.renderStackedColumn100(h):"stackedBar"===h.type?m=this.renderStackedBar(h):"stackedBar100"===h.type?m=this.renderStackedBar100(h):"stackedArea"===h.type?m=this.renderStackedArea(h):
"stackedArea100"===h.type?m=this.renderStackedArea100(h):"bubble"===h.type?m=m=this.renderBubble(h):"scatter"===h.type?m=this.renderScatter(h):"pie"===h.type?this.renderPie(h):"doughnut"===h.type?this.renderPie(h):"candlestick"===h.type?m=this.renderCandlestick(h):"ohlc"===h.type?m=this.renderCandlestick(h):"rangeColumn"===h.type?m=this.renderRangeColumn(h):"rangeBar"===h.type?m=this.renderRangeBar(h):"rangeArea"===h.type?m=this.renderRangeArea(h):"rangeSplineArea"===h.type&&(m=this.renderRangeSplineArea(h));
for(b=0;b<h.dataSeriesIndexes.length;b++)this._dataInRenderedOrder.push(this.data[h.dataSeriesIndexes[b]]);this.animatedRender&&(h.targetCanvasCtx.miterLimit=g,m&&d.push(m))}this.ctx.miterLimit=c;this.animatedRender&&0<this._indexLabels.length&&(g=ia(this.width,this.height).getContext("2d"),d.push(this.renderIndexLabels(g)));var p=this;0<d.length?(p.disableToolTip=!0,p._animator.animate(200,p.animationDuration,function(a){p.ctx.clearRect(0,0,p.width,p.height);p.ctx.drawImage(f,0,0,Math.floor(p.width*
Q),Math.floor(p.height*Q),0,0,p.width,p.height);for(var b=0;b<d.length;b++)m=d[b],1>a&&"undefined"!==typeof m.startTimePercent?a>=m.startTimePercent&&m.animationCallback(m.easingFunction(a-m.startTimePercent,0,1,1-m.startTimePercent),m):m.animationCallback(m.easingFunction(a,0,1,1),m);p.dispatchEvent("dataAnimationIterationEnd",{chart:p})},function(){d=[];for(var a=0;a<p.plotInfo.plotTypes.length;a++)for(var b=p.plotInfo.plotTypes[a],c=0;c<b.plotUnits.length;c++)b.plotUnits[c].targetCanvas=null;f=
null;p.disableToolTip=!1})):(0<p._indexLabels.length&&p.renderIndexLabels(),p.dispatchEvent("dataAnimationIterationEnd",{chart:p}));this.attachPlotAreaEventHandlers();this.zoomEnabled||(this.panEnabled||!this._zoomButton||"none"===this._zoomButton.style.display)||aa(this._zoomButton,this._resetButton);this.toolTip._updateToolTip();this.renderCount++};A.prototype.attachPlotAreaEventHandlers=function(){this.attachEvent({context:this,chart:this,mousedown:this._plotAreaMouseDown,mouseup:this._plotAreaMouseUp,
mousemove:this._plotAreaMouseMove,cursor:this.panEnabled?"move":"default",capture:!0,bounds:this.plotArea})};A.prototype.categoriseDataSeries=function(){for(var a="",c=0;c<this.data.length;c++)if(a=this.data[c],a.dataPoints&&(0!==a.dataPoints.length&&a.visible)&&0<=A._supportedChartTypes.indexOf(a.type)){for(var b=null,d=!1,f=null,g=!1,l=0;l<this.plotInfo.plotTypes.length;l++)if(this.plotInfo.plotTypes[l].type===a.type){d=!0;b=this.plotInfo.plotTypes[l];break}d||(b={type:a.type,totalDataSeries:0,
plotUnits:[]},this.plotInfo.plotTypes.push(b));for(l=0;l<b.plotUnits.length;l++)if(b.plotUnits[l].axisYType===a.axisYType&&b.plotUnits[l].axisXType===a.axisXType&&b.plotUnits[l].axisYIndex===a.axisYIndex&&b.plotUnits[l].axisXIndex===a.axisXIndex){g=!0;f=b.plotUnits[l];break}g||(f={type:a.type,previousDataSeriesCount:0,index:b.plotUnits.length,plotType:b,axisXType:a.axisXType,axisYType:a.axisYType,axisYIndex:a.axisYIndex,axisXIndex:a.axisXIndex,axisY:"primary"===a.axisYType?this.axisY[0<=a.axisYIndex&&
a.axisYIndex<this.axisY.length?a.axisYIndex:0]:this.axisY2[0<=a.axisYIndex&&a.axisYIndex<this.axisY2.length?a.axisYIndex:0],axisX:"primary"===a.axisXType?this.axisX[0<=a.axisXIndex&&a.axisXIndex<this.axisX.length?a.axisXIndex:0]:this.axisX2[0<=a.axisXIndex&&a.axisXIndex<this.axisX2.length?a.axisXIndex:0],dataSeriesIndexes:[],yTotals:[]},b.plotUnits.push(f));b.totalDataSeries++;f.dataSeriesIndexes.push(c);a.plotUnit=f}for(c=0;c<this.plotInfo.plotTypes.length;c++)for(b=this.plotInfo.plotTypes[c],l=
a=0;l<b.plotUnits.length;l++)b.plotUnits[l].previousDataSeriesCount=a,a+=b.plotUnits[l].dataSeriesIndexes.length};A.prototype.assignIdToDataPoints=function(){for(var a=0;a<this.data.length;a++){var c=this.data[a];if(c.dataPoints)for(var b=c.dataPoints.length,d=0;d<b;d++)c.dataPointIds[d]=++this._eventManager.lastObjectId}};A.prototype._processData=function(){this.assignIdToDataPoints();this.categoriseDataSeries();for(var a=0;a<this.plotInfo.plotTypes.length;a++)for(var c=this.plotInfo.plotTypes[a],
b=0;b<c.plotUnits.length;b++){var d=c.plotUnits[b];"line"===d.type||"stepLine"===d.type||"spline"===d.type||"column"===d.type||"area"===d.type||"stepArea"===d.type||"splineArea"===d.type||"bar"===d.type||"bubble"===d.type||"scatter"===d.type?this._processMultiseriesPlotUnit(d):"stackedColumn"===d.type||"stackedBar"===d.type||"stackedArea"===d.type?this._processStackedPlotUnit(d):"stackedColumn100"===d.type||"stackedBar100"===d.type||"stackedArea100"===d.type?this._processStacked100PlotUnit(d):"candlestick"!==
d.type&&"ohlc"!==d.type&&"rangeColumn"!==d.type&&"rangeBar"!==d.type&&"rangeArea"!==d.type&&"rangeSplineArea"!==d.type||this._processMultiYPlotUnit(d)}};A.prototype._processMultiseriesPlotUnit=function(a){if(a.dataSeriesIndexes&&!(1>a.dataSeriesIndexes.length))for(var c=a.axisY.dataInfo,b=a.axisX.dataInfo,d,f,g=!1,l=0;l<a.dataSeriesIndexes.length;l++){var k=this.data[a.dataSeriesIndexes[l]],h=0,m=!1,p=!1,n;if("normal"===k.axisPlacement||"xySwapped"===k.axisPlacement)var e=a.axisX.sessionVariables.newViewportMinimum?
a.axisX.sessionVariables.newViewportMinimum:this.options.axisX&&this.options.axisX.viewportMinimum?this.options.axisX.viewportMinimum:this.options.axisX&&this.options.axisX.minimum?this.options.axisX.minimum:a.axisX.logarithmic?0:-Infinity,q=a.axisX.sessionVariables.newViewportMaximum?a.axisX.sessionVariables.newViewportMaximum:this.options.axisX&&this.options.axisX.viewportMaximum?this.options.axisX.viewportMaximum:this.options.axisX&&this.options.axisX.maximum?this.options.axisX.maximum:Infinity;
if(k.dataPoints[h].x&&k.dataPoints[h].x.getTime||"dateTime"===k.xValueType)g=!0;for(h=0;h<k.dataPoints.length;h++){"undefined"===typeof k.dataPoints[h].x&&(k.dataPoints[h].x=h+(a.axisX.logarithmic?1:0));k.dataPoints[h].x.getTime?(g=!0,d=k.dataPoints[h].x.getTime()):d=k.dataPoints[h].x;f=k.dataPoints[h].y;d<b.min&&(b.min=d);d>b.max&&(b.max=d);f<c.min&&"number"===typeof f&&(c.min=f);f>c.max&&"number"===typeof f&&(c.max=f);if(0<h){if(a.axisX.logarithmic){var r=d/k.dataPoints[h-1].x;1>r&&(r=1/r);b.minDiff>
r&&1!==r&&(b.minDiff=r)}else r=d-k.dataPoints[h-1].x,0>r&&(r*=-1),b.minDiff>r&&0!==r&&(b.minDiff=r);null!==f&&null!==k.dataPoints[h-1].y&&(a.axisY.logarithmic?(r=f/k.dataPoints[h-1].y,1>r&&(r=1/r),c.minDiff>r&&1!==r&&(c.minDiff=r)):(r=f-k.dataPoints[h-1].y,0>r&&(r*=-1),c.minDiff>r&&0!==r&&(c.minDiff=r)))}if(d<e&&!m)null!==f&&(n=d);else{if(!m&&(m=!0,0<h)){h-=2;continue}if(d>q&&!p)p=!0;else if(d>q&&p)continue;k.dataPoints[h].label&&(a.axisX.labels[d]=k.dataPoints[h].label);d<b.viewPortMin&&(b.viewPortMin=
d);d>b.viewPortMax&&(b.viewPortMax=d);null===f?b.viewPortMin===d&&n<d&&(b.viewPortMin=n):(f<c.viewPortMin&&"number"===typeof f&&(c.viewPortMin=f),f>c.viewPortMax&&"number"===typeof f&&(c.viewPortMax=f))}}this.plotInfo.axisXValueType=k.xValueType=g?"dateTime":"number"}};A.prototype._processStackedPlotUnit=function(a){if(a.dataSeriesIndexes&&!(1>a.dataSeriesIndexes.length)){for(var c=a.axisY.dataInfo,b=a.axisX.dataInfo,d,f,g=!1,l=[],k=[],h=Infinity,m=-Infinity,p=0;p<a.dataSeriesIndexes.length;p++){var n=
this.data[a.dataSeriesIndexes[p]],e=0,q=!1,r=!1,s;if("normal"===n.axisPlacement||"xySwapped"===n.axisPlacement)var x=this.sessionVariables.axisX.newViewportMinimum?this.sessionVariables.axisX.newViewportMinimum:this.options.axisX&&this.options.axisX.viewportMinimum?this.options.axisX.viewportMinimum:this.options.axisX&&this.options.axisX.minimum?this.options.axisX.minimum:-Infinity,u=this.sessionVariables.axisX.newViewportMaximum?this.sessionVariables.axisX.newViewportMaximum:this.options.axisX&&
this.options.axisX.viewportMaximum?this.options.axisX.viewportMaximum:this.options.axisX&&this.options.axisX.maximum?this.options.axisX.maximum:Infinity;if(n.dataPoints[e].x&&n.dataPoints[e].x.getTime||"dateTime"===n.xValueType)g=!0;for(e=0;e<n.dataPoints.length;e++){"undefined"===typeof n.dataPoints[e].x&&(n.dataPoints[e].x=e+(a.axisX.logarithmic?1:0));n.dataPoints[e].x.getTime?(g=!0,d=n.dataPoints[e].x.getTime()):d=n.dataPoints[e].x;f=y(n.dataPoints[e].y)?0:n.dataPoints[e].y;d<b.min&&(b.min=d);
d>b.max&&(b.max=d);if(0<e){if(a.axisX.logarithmic){var v=d/n.dataPoints[e-1].x;1>v&&(v=1/v);b.minDiff>v&&1!==v&&(b.minDiff=v)}else v=d-n.dataPoints[e-1].x,0>v&&(v*=-1),b.minDiff>v&&0!==v&&(b.minDiff=v);null!==f&&null!==n.dataPoints[e-1].y&&(a.axisY.logarithmic?0<f&&(v=f/n.dataPoints[e-1].y,1>v&&(v=1/v),c.minDiff>v&&1!==v&&(c.minDiff=v)):(v=f-n.dataPoints[e-1].y,0>v&&(v*=-1),c.minDiff>v&&0!==v&&(c.minDiff=v)))}if(d<x&&!q)null!==n.dataPoints[e].y&&(s=d);else{if(!q&&(q=!0,0<e)){e-=2;continue}if(d>u&&
!r)r=!0;else if(d>u&&r)continue;n.dataPoints[e].label&&(a.axisX.labels[d]=n.dataPoints[e].label);d<b.viewPortMin&&(b.viewPortMin=d);d>b.viewPortMax&&(b.viewPortMax=d);null===n.dataPoints[e].y?b.viewPortMin===d&&s<d&&(b.viewPortMin=s):(a.yTotals[d]=(a.yTotals[d]?a.yTotals[d]:0)+Math.abs(f),0<=f?l[d]?l[d]+=f:(l[d]=f,h=Math.min(f,h)):k[d]?k[d]+=f:(k[d]=f,m=Math.max(f,m)))}}this.plotInfo.axisXValueType=n.xValueType=g?"dateTime":"number"}for(e in l)l.hasOwnProperty(e)&&!isNaN(e)&&(a=l[e],a<c.min&&(c.min=
Math.min(a,h)),a>c.max&&(c.max=a),e<b.viewPortMin||e>b.viewPortMax||(a<c.viewPortMin&&(c.viewPortMin=Math.min(a,h)),a>c.viewPortMax&&(c.viewPortMax=a)));for(e in k)k.hasOwnProperty(e)&&!isNaN(e)&&(a=k[e],a<c.min&&(c.min=a),a>c.max&&(c.max=Math.max(a,m)),e<b.viewPortMin||e>b.viewPortMax||(a<c.viewPortMin&&(c.viewPortMin=a),a>c.viewPortMax&&(c.viewPortMax=Math.max(a,m))))}};A.prototype._processStacked100PlotUnit=function(a){if(a.dataSeriesIndexes&&!(1>a.dataSeriesIndexes.length)){for(var c=a.axisY.dataInfo,
b=a.axisX.dataInfo,d,f,g=!1,l=!1,k=!1,h=[],m=0;m<a.dataSeriesIndexes.length;m++){var p=this.data[a.dataSeriesIndexes[m]],n=0,e=!1,q=!1,r;if("normal"===p.axisPlacement||"xySwapped"===p.axisPlacement)var s=this.sessionVariables.axisX.newViewportMinimum?this.sessionVariables.axisX.newViewportMinimum:this.options.axisX&&this.options.axisX.viewportMinimum?this.options.axisX.viewportMinimum:this.options.axisX&&this.options.axisX.minimum?this.options.axisX.minimum:-Infinity,x=this.sessionVariables.axisX.newViewportMaximum?
this.sessionVariables.axisX.newViewportMaximum:this.options.axisX&&this.options.axisX.viewportMaximum?this.options.axisX.viewportMaximum:this.options.axisX&&this.options.axisX.maximum?this.options.axisX.maximum:Infinity;if(p.dataPoints[n].x&&p.dataPoints[n].x.getTime||"dateTime"===p.xValueType)g=!0;for(n=0;n<p.dataPoints.length;n++){"undefined"===typeof p.dataPoints[n].x&&(p.dataPoints[n].x=n+(a.axisX.logarithmic?1:0));p.dataPoints[n].x.getTime?(g=!0,d=p.dataPoints[n].x.getTime()):d=p.dataPoints[n].x;
f=y(p.dataPoints[n].y)?null:p.dataPoints[n].y;d<b.min&&(b.min=d);d>b.max&&(b.max=d);if(0<n){if(a.axisX.logarithmic){var u=d/p.dataPoints[n-1].x;1>u&&(u=1/u);b.minDiff>u&&1!==u&&(b.minDiff=u)}else u=d-p.dataPoints[n-1].x,0>u&&(u*=-1),b.minDiff>u&&0!==u&&(b.minDiff=u);y(f)||null===p.dataPoints[n-1].y||(a.axisY.logarithmic?0<f&&(u=f/p.dataPoints[n-1].y,1>u&&(u=1/u),c.minDiff>u&&1!==u&&(c.minDiff=u)):(u=f-p.dataPoints[n-1].y,0>u&&(u*=-1),c.minDiff>u&&0!==u&&(c.minDiff=u)))}if(d<s&&!e)null!==f&&(r=d);
else{if(!e&&(e=!0,0<n)){n-=2;continue}if(d>x&&!q)q=!0;else if(d>x&&q)continue;p.dataPoints[n].label&&(a.axisX.labels[d]=p.dataPoints[n].label);d<b.viewPortMin&&(b.viewPortMin=d);d>b.viewPortMax&&(b.viewPortMax=d);null===f?b.viewPortMin===d&&r<d&&(b.viewPortMin=r):(a.yTotals[d]=(a.yTotals[d]?a.yTotals[d]:0)+Math.abs(f),0<=f?l=!0:0>f&&(k=!0),h[d]=h[d]?h[d]+Math.abs(f):Math.abs(f))}}this.plotInfo.axisXValueType=p.xValueType=g?"dateTime":"number"}a.axisY.logarithmic?(c.max=y(c.viewPortMax)?99*Math.pow(a.axisY.logarithmBase,
-0.05):Math.max(c.viewPortMax,99*Math.pow(a.axisY.logarithmBase,-0.05)),c.min=y(c.viewPortMin)?1:Math.min(c.viewPortMin,1)):l&&!k?(c.max=y(c.viewPortMax)?99:Math.max(c.viewPortMax,99),c.min=y(c.viewPortMin)?1:Math.min(c.viewPortMin,1)):l&&k?(c.max=y(c.viewPortMax)?99:Math.max(c.viewPortMax,99),c.min=y(c.viewPortMin)?-99:Math.min(c.viewPortMin,-99)):!l&&k&&(c.max=y(c.viewPortMax)?-1:Math.max(c.viewPortMax,-1),c.min=y(c.viewPortMin)?-99:Math.min(c.viewPortMin,-99));c.viewPortMin=c.min;c.viewPortMax=
c.max;a.dataPointYSums=h}};A.prototype._processMultiYPlotUnit=function(a){if(a.dataSeriesIndexes&&!(1>a.dataSeriesIndexes.length))for(var c=a.axisY.dataInfo,b=a.axisX.dataInfo,d,f,g,l,k=!1,h=0;h<a.dataSeriesIndexes.length;h++){var m=this.data[a.dataSeriesIndexes[h]],p=0,n=!1,e=!1,q,r,s;if("normal"===m.axisPlacement||"xySwapped"===m.axisPlacement)var x=this.sessionVariables.axisX.newViewportMinimum?this.sessionVariables.axisX.newViewportMinimum:this.options.axisX&&this.options.axisX.viewportMinimum?
this.options.axisX.viewportMinimum:this.options.axisX&&this.options.axisX.minimum?this.options.axisX.minimum:-Infinity,u=this.sessionVariables.axisX.newViewportMaximum?this.sessionVariables.axisX.newViewportMaximum:this.options.axisX&&this.options.axisX.viewportMaximum?this.options.axisX.viewportMaximum:this.options.axisX&&this.options.axisX.maximum?this.options.axisX.maximum:Infinity;if(m.dataPoints[p].x&&m.dataPoints[p].x.getTime||"dateTime"===m.xValueType)k=!0;for(p=0;p<m.dataPoints.length;p++){"undefined"===
typeof m.dataPoints[p].x&&(m.dataPoints[p].x=p+(a.axisX.logarithmic?1:0));m.dataPoints[p].x.getTime?(k=!0,d=m.dataPoints[p].x.getTime()):d=m.dataPoints[p].x;if((f=m.dataPoints[p].y)&&f.length){g=Math.min.apply(null,f);l=Math.max.apply(null,f);r=!0;for(var v=0;v<f.length;v++)null===f.k&&(r=!1);r&&(n||(s=q),q=d)}d<b.min&&(b.min=d);d>b.max&&(b.max=d);g<c.min&&(c.min=g);l>c.max&&(c.max=l);0<p&&(a.axisX.logarithmic?(r=d/m.dataPoints[p-1].x,1>r&&(r=1/r),b.minDiff>r&&1!==r&&(b.minDiff=r)):(r=d-m.dataPoints[p-
1].x,0>r&&(r*=-1),b.minDiff>r&&0!==r&&(b.minDiff=r)),f&&(null!==f[0]&&m.dataPoints[p-1].y&&null!==m.dataPoints[p-1].y[0])&&(a.axisY.logarithmic?(r=f[0]/m.dataPoints[p-1].y[0],1>r&&(r=1/r),c.minDiff>r&&1!==r&&(c.minDiff=r)):(r=f[0]-m.dataPoints[p-1].y[0],0>r&&(r*=-1),c.minDiff>r&&0!==r&&(c.minDiff=r))));if(!(d<x)||n){if(!n&&(n=!0,0<p)){p-=2;q=s;continue}if(d>u&&!e)e=!0;else if(d>u&&e)continue;m.dataPoints[p].label&&(a.axisX.labels[d]=m.dataPoints[p].label);d<b.viewPortMin&&(b.viewPortMin=d);d>b.viewPortMax&&
(b.viewPortMax=d);if(b.viewPortMin===d&&f)for(v=0;v<f.length;v++)if(null===f[v]&&q<d){b.viewPortMin=q;break}null===f?b.viewPortMin===d&&q<d&&(b.viewPortMin=q):(g<c.viewPortMin&&(c.viewPortMin=g),l>c.viewPortMax&&(c.viewPortMax=l))}}this.plotInfo.axisXValueType=m.xValueType=k?"dateTime":"number"}};A.prototype.getDataPointAtXY=function(a,c,b){b=b||!1;for(var d=[],f=this._dataInRenderedOrder.length-1;0<=f;f--){var g=null;(g=this._dataInRenderedOrder[f].getDataPointAtXY(a,c,b))&&d.push(g)}a=null;c=!1;
for(b=0;b<d.length;b++)if("line"===d[b].dataSeries.type||"stepLine"===d[b].dataSeries.type||"area"===d[b].dataSeries.type||"stepArea"===d[b].dataSeries.type)if(f=K("markerSize",d[b].dataPoint,d[b].dataSeries)||8,d[b].distance<=f/2){c=!0;break}for(b=0;b<d.length;b++)c&&"line"!==d[b].dataSeries.type&&"stepLine"!==d[b].dataSeries.type&&"area"!==d[b].dataSeries.type&&"stepArea"!==d[b].dataSeries.type||(a?d[b].distance<=a.distance&&(a=d[b]):a=d[b]);return a};A.prototype.getObjectAtXY=function(a,c,b){var d=
null;if(b=this.getDataPointAtXY(a,c,b||!1))d=b.dataSeries.dataPointIds[b.dataPointIndex];else if(t)d=Na(a,c,this._eventManager.ghostCtx);else for(b=0;b<this.legend.items.length;b++){var f=this.legend.items[b];a>=f.x1&&(a<=f.x2&&c>=f.y1&&c<=f.y2)&&(d=f.id)}return d};A.prototype.getAutoFontSize=function(a,c,b){a/=400;return Math.max(10,Math.round(Math.min(this.width,this.height)*a))};A.prototype.resetOverlayedCanvas=function(){this.overlaidCanvasCtx.clearRect(0,0,this.width,this.height)};A.prototype.clearCanvas=
function(){this.ctx.clearRect(0,0,this.width,this.height);this.backgroundColor&&(this.ctx.fillStyle=this.backgroundColor,this.ctx.fillRect(0,0,this.width,this.height))};A.prototype.attachEvent=function(a){this._events.push(a)};A.prototype._touchEventHandler=function(a){if(a.changedTouches&&this.interactivityEnabled){var c=[],b=a.changedTouches,d=b?b[0]:a,f=null;switch(a.type){case "touchstart":case "MSPointerDown":c=["mousemove","mousedown"];this._lastTouchData=za(d);this._lastTouchData.time=new Date;
break;case "touchmove":case "MSPointerMove":c=["mousemove"];break;case "touchend":case "MSPointerUp":c="touchstart"===this._lastTouchEventType||"MSPointerDown"===this._lastTouchEventType?["mouseup","click"]:["mouseup"];break;default:return}if(!(b&&1<b.length)){f=za(d);f.time=new Date;try{var g=f.y-this._lastTouchData.y;if(15<Math.abs(g)&&this._lastTouchData.scroll){this._lastTouchData.scroll=!0;var l=window.parent||window;l&&l.scrollBy&&l.scrollBy(0,-g)}}catch(k){}this._lastTouchEventType=a.type;
if(this._lastTouchData.scroll&&this.zoomEnabled)this.isDrag&&this.resetOverlayedCanvas(),this.isDrag=!1;else for(b=0;b<c.length;b++)f=c[b],g=document.createEvent("MouseEvent"),g.initMouseEvent(f,!0,!0,window,1,d.screenX,d.screenY,d.clientX,d.clientY,!1,!1,!1,!1,0,null),d.target.dispatchEvent(g),a.preventManipulation&&a.preventManipulation()}}};A.prototype._dispatchRangeEvent=function(a,c){var b={chart:this};b.type=a;b.trigger=c;var d=[];this.axisX&&0<this.axisX.length&&d.push("axisX");this.axisX2&&
0<this.axisX2.length&&d.push("axisX2");this.axisY&&0<this.axisY.length&&d.push("axisY");this.axisY2&&0<this.axisY2.length&&d.push("axisY2");for(var f=0;f<d.length;f++)if(y(b[d[f]])&&(b[d[f]]=[]),"axisY"===d[f])for(var g=0;g<this.axisY.length;g++)b[d[f]].push({viewportMinimum:this[d[f]][g].sessionVariables.newViewportMinimum,viewportMaximum:this[d[f]][g].sessionVariables.newViewportMaximum});else if("axisY2"===d[f])for(g=0;g<this.axisY2.length;g++)b[d[f]].push({viewportMinimum:this[d[f]][g].sessionVariables.newViewportMinimum,
viewportMaximum:this[d[f]][g].sessionVariables.newViewportMaximum});else if("axisX"===d[f])for(g=0;g<this.axisX.length;g++)b[d[f]].push({viewportMinimum:this[d[f]][g].sessionVariables.newViewportMinimum,viewportMaximum:this[d[f]][g].sessionVariables.newViewportMaximum});else if("axisX2"===d[f])for(g=0;g<this.axisX2.length;g++)b[d[f]].push({viewportMinimum:this[d[f]][g].sessionVariables.newViewportMinimum,viewportMaximum:this[d[f]][g].sessionVariables.newViewportMaximum});this.dispatchEvent(a,b,this)};
A.prototype._mouseEventHandler=function(a){"undefined"===typeof a.target&&a.srcElement&&(a.target=a.srcElement);var c=za(a),b=a.type,d,f;a.which?f=3==a.which:a.button&&(f=2==a.button);A.capturedEventParam&&(d=A.capturedEventParam,"mouseup"===b&&(A.capturedEventParam=null,d.chart.overlaidCanvas.releaseCapture?d.chart.overlaidCanvas.releaseCapture():document.documentElement.removeEventListener("mouseup",d.chart._mouseEventHandler,!1)),d.hasOwnProperty(b)&&("mouseup"!==b||d.chart.overlaidCanvas.releaseCapture?
a.target===d.chart.overlaidCanvas&&d[b].call(d.context,c.x,c.y):a.target!==d.chart.overlaidCanvas&&(d.chart.isDrag=!1)));if(this.interactivityEnabled)if(this._ignoreNextEvent)this._ignoreNextEvent=!1;else if(a.preventManipulation&&a.preventManipulation(),a.preventDefault&&a.preventDefault(),!f){if(!A.capturedEventParam&&this._events){for(var g=0;g<this._events.length;g++)if(this._events[g].hasOwnProperty(b))if(d=this._events[g],f=d.bounds,c.x>=f.x1&&c.x<=f.x2&&c.y>=f.y1&&c.y<=f.y2){d[b].call(d.context,
c.x,c.y);"mousedown"===b&&!0===d.capture?(A.capturedEventParam=d,this.overlaidCanvas.setCapture?this.overlaidCanvas.setCapture():document.documentElement.addEventListener("mouseup",this._mouseEventHandler,!1)):"mouseup"===b&&(d.chart.overlaidCanvas.releaseCapture?d.chart.overlaidCanvas.releaseCapture():document.documentElement.removeEventListener("mouseup",this._mouseEventHandler,!1));break}else d=null;a.target.style.cursor=d&&d.cursor?d.cursor:this._defaultCursor}b=this.plotArea;if(c.x<b.x1||c.x>
b.x2||c.y<b.y1||c.y>b.y2)this.toolTip&&this.toolTip.enabled?this.toolTip.hide():this.resetOverlayedCanvas();this.isDrag&&this.zoomEnabled||!this._eventManager||this._eventManager.mouseEventHandler(a)}};A.prototype._plotAreaMouseDown=function(a,c){this.isDrag=!0;this.dragStartPoint={x:a,y:c}};A.prototype._plotAreaMouseUp=function(a,c){if(("normal"===this.plotInfo.axisPlacement||"xySwapped"===this.plotInfo.axisPlacement)&&this.isDrag){var b=c-this.dragStartPoint.y,d=a-this.dragStartPoint.x,f=0<=this.zoomType.indexOf("x"),
g=0<=this.zoomType.indexOf("y"),l=!1;this.resetOverlayedCanvas();if("xySwapped"===this.plotInfo.axisPlacement)var k=g,g=f,f=k;if(this.panEnabled||this.zoomEnabled){if(this.panEnabled)for(f=g=0;f<this._axes.length;f++)b=this._axes[f],b.logarithmic?b.viewportMinimum<b.minimum?(g=b.minimum/b.viewportMinimum,b.sessionVariables.newViewportMinimum=b.viewportMinimum*g,b.sessionVariables.newViewportMaximum=b.viewportMaximum*g,l=!0):b.viewportMaximum>b.maximum&&(g=b.viewportMaximum/b.maximum,b.sessionVariables.newViewportMinimum=
b.viewportMinimum/g,b.sessionVariables.newViewportMaximum=b.viewportMaximum/g,l=!0):b.viewportMinimum<b.minimum?(g=b.minimum-b.viewportMinimum,b.sessionVariables.newViewportMinimum=b.viewportMinimum+g,b.sessionVariables.newViewportMaximum=b.viewportMaximum+g,l=!0):b.viewportMaximum>b.maximum&&(g=b.viewportMaximum-b.maximum,b.sessionVariables.newViewportMinimum=b.viewportMinimum-g,b.sessionVariables.newViewportMaximum=b.viewportMaximum-g,l=!0);else if((!f||2<Math.abs(d))&&(!g||2<Math.abs(b))&&this.zoomEnabled){if(!this.dragStartPoint)return;
b=f?this.dragStartPoint.x:this.plotArea.x1;d=g?this.dragStartPoint.y:this.plotArea.y1;f=f?a:this.plotArea.x2;g=g?c:this.plotArea.y2;2<Math.abs(b-f)&&2<Math.abs(d-g)&&this._zoomPanToSelectedRegion(b,d,f,g)&&(l=!0)}l&&(this._ignoreNextEvent=!0,this._dispatchRangeEvent("rangeChanging","zoom"),this.render(),this._dispatchRangeEvent("rangeChanged","zoom"),l&&(this.zoomEnabled&&"none"===this._zoomButton.style.display)&&(va(this._zoomButton,this._resetButton),$(this,this._zoomButton,"pan"),$(this,this._resetButton,
"reset")))}}this.isDrag=!1};A.prototype._plotAreaMouseMove=function(a,c){if(this.isDrag&&"none"!==this.plotInfo.axisPlacement){var b=0,d=0,f=b=null,f=0<=this.zoomType.indexOf("x"),g=0<=this.zoomType.indexOf("y"),l=this;"xySwapped"===this.plotInfo.axisPlacement&&(b=g,g=f,f=b);b=this.dragStartPoint.x-a;d=this.dragStartPoint.y-c;2<Math.abs(b)&&8>Math.abs(b)&&(this.panEnabled||this.zoomEnabled)?this.toolTip.hide():this.panEnabled||this.zoomEnabled||this.toolTip.mouseMoveHandler(a,c);if((!f||2<Math.abs(b)||
!g||2<Math.abs(d))&&(this.panEnabled||this.zoomEnabled))if(this.panEnabled)f={x1:f?this.plotArea.x1+b:this.plotArea.x1,y1:g?this.plotArea.y1+d:this.plotArea.y1,x2:f?this.plotArea.x2+b:this.plotArea.x2,y2:g?this.plotArea.y2+d:this.plotArea.y2},clearTimeout(l._panTimerId),l._panTimerId=setTimeout(function(b,d,e,f){return function(){l._zoomPanToSelectedRegion(b,d,e,f,!0)&&(l._dispatchRangeEvent("rangeChanging","pan"),l.render(),l._dispatchRangeEvent("rangeChanged","pan"),l.dragStartPoint.x=a,l.dragStartPoint.y=
c)}}(f.x1,f.y1,f.x2,f.y2),0);else if(this.zoomEnabled){this.resetOverlayedCanvas();b=this.overlaidCanvasCtx.globalAlpha;this.overlaidCanvasCtx.fillStyle="#A89896";var d=f?this.dragStartPoint.x:this.plotArea.x1,k=g?this.dragStartPoint.y:this.plotArea.y1,h=f?a-this.dragStartPoint.x:this.plotArea.x2-this.plotArea.x1,m=g?c-this.dragStartPoint.y:this.plotArea.y2-this.plotArea.y1;this.validateRegion(d,k,f?a:this.plotArea.x2-this.plotArea.x1,g?c:this.plotArea.y2-this.plotArea.y1,"xy"!==this.zoomType).isValid&&
(this.resetOverlayedCanvas(),this.overlaidCanvasCtx.fillStyle="#99B2B5");this.overlaidCanvasCtx.globalAlpha=0.7;this.overlaidCanvasCtx.fillRect(d,k,h,m);this.overlaidCanvasCtx.globalAlpha=b}}else this.toolTip.mouseMoveHandler(a,c)};A.prototype._zoomPanToSelectedRegion=function(a,c,b,d,f){a=this.validateRegion(a,c,b,d,f);c=a.axesWithValidRange;b=a.axesRanges;if(a.isValid)for(d=0;d<c.length;d++)f=b[d],c[d].setViewPortRange(f.val1,f.val2);return a.isValid};A.prototype.validateRegion=function(a,c,b,d,
f){f=f||!1;for(var g=0<=this.zoomType.indexOf("x"),l=0<=this.zoomType.indexOf("y"),k=!1,h=[],m=[],p=[],n=0;n<this.axisX.length;n++)this.axisX[n]&&g&&m.push(this.axisX[n]);for(n=0;n<this.axisX2.length;n++)this.axisX2[n]&&g&&m.push(this.axisX2[n]);for(n=0;n<this.axisY.length;n++)this.axisY[n]&&l&&m.push(this.axisY[n]);for(n=0;n<this.axisY2.length;n++)this.axisY2[n]&&l&&m.push(this.axisY2[n]);for(g=0;g<m.length;g++){var l=m[g],n=l.convertPixelToValue({x:a,y:c}),e=l.convertPixelToValue({x:b,y:d});if(n>
e)var q=e,e=n,n=q;if(isFinite(l.dataInfo.minDiff))if(!(l.logarithmic&&e/n<Math.pow(l.dataInfo.minDiff,3)||!l.logarithmic&&Math.abs(e-n)<3*Math.abs(l.dataInfo.minDiff)||n<l.minimum||e>l.maximum))h.push(l),p.push({val1:n,val2:e}),k=!0;else if(!f){k=!1;break}}return{isValid:k,axesWithValidRange:h,axesRanges:p}};A.prototype.preparePlotArea=function(){var a=this.plotArea;!t&&(0<a.x1||0<a.y1)&&a.ctx.translate(a.x1,a.y1);if((this.axisX[0]||this.axisX2[0])&&(this.axisY[0]||this.axisY2[0])){var c=this.axisX[0]?
this.axisX[0].lineCoordinates:this.axisX2[0].lineCoordinates;if(this.axisY&&0<this.axisY.length&&this.axisY[0]){var b=this.axisY[0];a.x1=c.x1<c.x2?c.x1:b.lineCoordinates.x1;a.y1=c.y1<b.lineCoordinates.y1?c.y1:b.lineCoordinates.y1;a.x2=c.x2>b.lineCoordinates.x2?c.x2:b.lineCoordinates.x2;a.y2=c.y2>c.y1?c.y2:b.lineCoordinates.y2;a.width=a.x2-a.x1;a.height=a.y2-a.y1}this.axisY2&&0<this.axisY2.length&&this.axisY2[0]&&(b=this.axisY2[0],a.x1=c.x1<c.x2?c.x1:b.lineCoordinates.x1,a.y1=c.y1<b.lineCoordinates.y1?
c.y1:b.lineCoordinates.y1,a.x2=c.x2>b.lineCoordinates.x2?c.x2:b.lineCoordinates.x2,a.y2=c.y2>c.y1?c.y2:b.lineCoordinates.y2,a.width=a.x2-a.x1,a.height=a.y2-a.y1)}else c=this.layoutManager.getFreeSpace(),a.x1=c.x1,a.x2=c.x2,a.y1=c.y1,a.y2=c.y2,a.width=c.width,a.height=c.height;t||(a.canvas.width=a.width,a.canvas.height=a.height,a.canvas.style.left=a.x1+"px",a.canvas.style.top=a.y1+"px",(0<a.x1||0<a.y1)&&a.ctx.translate(-a.x1,-a.y1));a.layoutManager=new la(a.x1,a.y1,a.x2,a.y2,2)};A.prototype.renderIndexLabels=
function(a){var c=a||this.plotArea.ctx,b=this.plotArea,d=0,f=0,g=0,l=0,k=d=l=f=g=0,h=0;for(a=0;a<this._indexLabels.length;a++){var m=this._indexLabels[a],p=m.chartType.toLowerCase(),n,e,k=K("indexLabelFontColor",m.dataPoint,m.dataSeries),h=K("indexLabelFontSize",m.dataPoint,m.dataSeries);n=K("indexLabelFontFamily",m.dataPoint,m.dataSeries);e=K("indexLabelFontStyle",m.dataPoint,m.dataSeries);var l=K("indexLabelFontWeight",m.dataPoint,m.dataSeries),q=K("indexLabelBackgroundColor",m.dataPoint,m.dataSeries),
f=K("indexLabelMaxWidth",m.dataPoint,m.dataSeries),g=K("indexLabelWrap",m.dataPoint,m.dataSeries),r=K("indexLabelLineDashType",m.dataPoint,m.dataSeries),s=K("indexLabelLineColor",m.dataPoint,m.dataSeries),x=y(m.dataPoint.indexLabelLineThickness)?y(m.dataSeries.options.indexLabelLineThickness)?0:m.dataSeries.options.indexLabelLineThickness:m.dataPoint.indexLabelLineThickness,d=0<x?Math.min(10,("normal"===this.plotInfo.axisPlacement?this.plotArea.height:this.plotArea.width)<<0):0,u={percent:null,total:null},
v=null;if(0<=m.dataSeries.type.indexOf("stacked")||"pie"===m.dataSeries.type||"doughnut"===m.dataSeries.type)u=this.getPercentAndTotal(m.dataSeries,m.dataPoint);if(m.dataSeries.indexLabelFormatter||m.dataPoint.indexLabelFormatter)v={chart:this,dataSeries:m.dataSeries,dataPoint:m.dataPoint,index:m.indexKeyword,total:u.total,percent:u.percent};var z=m.dataPoint.indexLabelFormatter?m.dataPoint.indexLabelFormatter(v):m.dataPoint.indexLabel?this.replaceKeywordsWithValue(m.dataPoint.indexLabel,m.dataPoint,
m.dataSeries,null,m.indexKeyword):m.dataSeries.indexLabelFormatter?m.dataSeries.indexLabelFormatter(v):m.dataSeries.indexLabel?this.replaceKeywordsWithValue(m.dataSeries.indexLabel,m.dataPoint,m.dataSeries,null,m.indexKeyword):null;if(null!==z&&""!==z){var u=K("indexLabelPlacement",m.dataPoint,m.dataSeries),v=K("indexLabelOrientation",m.dataPoint,m.dataSeries),w=m.direction,Z=m.dataSeries.axisX,ba=m.dataSeries.axisY,A=!1,q=new V(c,{x:0,y:0,maxWidth:f?f:0.5*this.width,maxHeight:g?5*h:1.5*h,angle:"horizontal"===
v?0:-90,text:z,padding:0,backgroundColor:q,horizontalAlign:"left",fontSize:h,fontFamily:n,fontWeight:l,fontColor:k,fontStyle:e,textBaseline:"top"});q.measureText();m.dataSeries.indexLabelMaxWidth=q.maxWidth;if("stackedarea100"===p){if(m.point.x<b.x1||m.point.x>b.x2||m.point.y<b.y1-1||m.point.y>b.y2+1)continue}else if("rangearea"===p||"rangesplinearea"===p){if(m.dataPoint.x<Z.viewportMinimum||m.dataPoint.x>Z.viewportMaximum||Math.max.apply(null,m.dataPoint.y)<ba.viewportMinimum||Math.min.apply(null,
m.dataPoint.y)>ba.viewportMaximum)continue}else if(0<=p.indexOf("line")||0<=p.indexOf("area")||0<=p.indexOf("bubble")||0<=p.indexOf("scatter")){if(m.dataPoint.x<Z.viewportMinimum||m.dataPoint.x>Z.viewportMaximum||m.dataPoint.y<ba.viewportMinimum||m.dataPoint.y>ba.viewportMaximum)continue}else if(0<=p.indexOf("column")){if(m.dataPoint.x<Z.viewportMinimum||m.dataPoint.x>Z.viewportMaximum||m.bounds.y1>b.y2||m.bounds.y2<b.y1)continue}else if(0<=p.indexOf("bar")){if(m.dataPoint.x<Z.viewportMinimum||m.dataPoint.x>
Z.viewportMaximum||m.bounds.x1>b.x2||m.bounds.x2<b.x1)continue}else if("candlestick"===p||"ohlc"===p){if(m.dataPoint.x<Z.viewportMinimum||m.dataPoint.x>Z.viewportMaximum||Math.max.apply(null,m.dataPoint.y)<ba.viewportMinimum||Math.min.apply(null,m.dataPoint.y)>ba.viewportMaximum)continue}else if(m.dataPoint.x<Z.viewportMinimum||m.dataPoint.x>Z.viewportMaximum)continue;f=l=2;"horizontal"===v?(k=q.width,h=q.height):(h=q.width,k=q.height);if("normal"===this.plotInfo.axisPlacement){if(0<=p.indexOf("line")||
0<=p.indexOf("area"))u="auto",l=4;else if(0<=p.indexOf("stacked"))"auto"===u&&(u="inside");else if("bubble"===p||"scatter"===p)u="inside";n=m.point.x-k/2;"inside"!==u?(f=b.y1,g=b.y2,0<w?(e=m.point.y-h-l-d,e<f&&(e="auto"===u?Math.max(m.point.y,f)+l+d:f+l+d,A=e+h>m.point.y)):(e=m.point.y+l+d,e>g-h-l-d&&(e="auto"===u?Math.min(m.point.y,g)-h-l-d:g-h-l-d,A=e<m.point.y))):(f=Math.max(m.bounds.y1,b.y1),g=Math.min(m.bounds.y2,b.y2),d=0<=p.indexOf("range")?0<w?Math.max(m.bounds.y1,b.y1)+h/2+l:Math.min(m.bounds.y2,
b.y2)-h/2-l:(Math.max(m.bounds.y1,b.y1)+Math.min(m.bounds.y2,b.y2))/2,0<w?(e=Math.max(m.point.y,d)-h/2,e<f&&("bubble"===p||"scatter"===p)&&(e=Math.max(m.point.y-h-l,b.y1+l))):(e=Math.min(m.point.y,d)-h/2,e>g-h-l&&("bubble"===p||"scatter"===p)&&(e=Math.min(m.point.y+l,b.y2-h-l))),e=Math.min(e,g-h))}else 0<=p.indexOf("line")||0<=p.indexOf("area")||0<=p.indexOf("scatter")?(u="auto",f=4):0<=p.indexOf("stacked")?"auto"===u&&(u="inside"):"bubble"===p&&(u="inside"),e=m.point.y-h/2,"inside"!==u?(l=b.x1,g=
b.x2,0>w?(n=m.point.x-k-f-d,n<l&&(n="auto"===u?Math.max(m.point.x,l)+f+d:l+f+d,A=n+k>m.point.x)):(n=m.point.x+f+d,n>g-k-f-d&&(n="auto"===u?Math.min(m.point.x,g)-k-f-d:g-k-f-d,A=n<m.point.x))):(l=Math.max(m.bounds.x1,b.x1),Math.min(m.bounds.x2,b.x2),d=0<=p.indexOf("range")?0>w?Math.max(m.bounds.x1,b.x1)+k/2+f:Math.min(m.bounds.x2,b.x2)-k/2-f:(Math.max(m.bounds.x1,b.x1)+Math.min(m.bounds.x2,b.x2))/2,n=0>w?Math.max(m.point.x,d)-k/2:Math.min(m.point.x,d)-k/2,n=Math.max(n,l));"vertical"===v&&(e+=h);q.x=
n;q.y=e;q.render(!0);x&&("inside"!==u&&(0>p.indexOf("bar")&&m.point.x>b.x1&&m.point.x<b.x2||!A)&&(0>p.indexOf("column")&&m.point.y>b.y1&&m.point.y<b.y2||!A))&&(c.lineWidth=x,c.strokeStyle=s?s:"gray",c.setLineDash&&c.setLineDash(F(r,x)),c.beginPath(),c.moveTo(m.point.x,m.point.y),0<=p.indexOf("bar")?c.lineTo(n+(0<m.direction?0:k),e+("horizontal"===v?h:-h)/2):0<=p.indexOf("column")?c.lineTo(n+k/2,e+((0<m.direction?h:-h)+("horizontal"===v?h:-h))/2):c.lineTo(n+k/2,e+((e<m.point.y?h:-h)+("horizontal"===
v?h:-h))/2),c.stroke())}}c={source:c,dest:this.plotArea.ctx,animationCallback:E.fadeInAnimation,easingFunction:E.easing.easeInQuad,animationBase:0,startTimePercent:0.7};for(a=0;a<this._indexLabels.length;a++)m=this._indexLabels[a],q=K("indexLabelBackgroundColor",m.dataPoint,m.dataSeries),m.dataSeries.indexLabelBackgroundColor=y(q)?t?"transparent":null:q;return c};A.prototype.renderLine=function(a){var c=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var b=this._eventManager.ghostCtx;
c.save();var d=this.plotArea;c.beginPath();c.rect(d.x1,d.y1,d.width,d.height);c.clip();for(var d=[],f,g=0;g<a.dataSeriesIndexes.length;g++){var l=a.dataSeriesIndexes[g],k=this.data[l];c.lineWidth=k.lineThickness;var h=k.dataPoints,m="solid";if(c.setLineDash){var p=F(k.nullDataLineDashType,k.lineThickness),m=k.lineDashType,n=F(m,k.lineThickness);c.setLineDash(n)}var e=k.id;this._eventManager.objectMap[e]={objectType:"dataSeries",dataSeriesIndex:l};e=D(e);b.strokeStyle=e;b.lineWidth=0<k.lineThickness?
Math.max(k.lineThickness,4):0;var e=k._colorSet,q=e=k.lineColor=k.options.lineColor?k.options.lineColor:e[0];c.strokeStyle=e;var r=!0,s=0,x,u;c.beginPath();if(0<h.length){for(var v=!1,s=0;s<h.length;s++)if(x=h[s].x.getTime?h[s].x.getTime():h[s].x,!(x<a.axisX.dataInfo.viewPortMin||x>a.axisX.dataInfo.viewPortMax&&(!k.connectNullData||!v)))if("number"!==typeof h[s].y)0<s&&!(k.connectNullData||v||r)&&(c.stroke(),t&&b.stroke()),v=!0;else{x=a.axisX.convertValueToPixel(x);u=a.axisY.convertValueToPixel(h[s].y);
var z=k.dataPointIds[s];this._eventManager.objectMap[z]={id:z,objectType:"dataPoint",dataSeriesIndex:l,dataPointIndex:s,x1:x,y1:u};r||v?(!r&&k.connectNullData?(c.setLineDash&&(k.options.nullDataLineDashType||m===k.lineDashType&&k.lineDashType!==k.nullDataLineDashType)&&(c.stroke(),c.beginPath(),c.moveTo(f.x,f.y),m=k.nullDataLineDashType,c.setLineDash(p)),c.lineTo(x,u),t&&b.lineTo(x,u)):(c.beginPath(),c.moveTo(x,u),t&&(b.beginPath(),b.moveTo(x,u))),v=r=!1):(c.lineTo(x,u),t&&b.lineTo(x,u),0==s%500&&
(c.stroke(),c.beginPath(),c.moveTo(x,u),t&&(b.stroke(),b.beginPath(),b.moveTo(x,u))));f={x:x,y:u};s<h.length-1&&(q!==(h[s].lineColor||e)||m!==(h[s].lineDashType||k.lineDashType))&&(c.stroke(),c.beginPath(),c.moveTo(x,u),q=h[s].lineColor||e,c.strokeStyle=q,c.setLineDash&&(h[s].lineDashType?(m=h[s].lineDashType,c.setLineDash(F(m,k.lineThickness))):(m=k.lineDashType,c.setLineDash(n))));if(0<h[s].markerSize||0<k.markerSize){var w=k.getMarkerProperties(s,x,u,c);d.push(w);z=D(z);t&&d.push({x:x,y:u,ctx:b,
type:w.type,size:w.size,color:z,borderColor:z,borderThickness:w.borderThickness})}(h[s].indexLabel||k.indexLabel||h[s].indexLabelFormatter||k.indexLabelFormatter)&&this._indexLabels.push({chartType:"line",dataPoint:h[s],dataSeries:k,point:{x:x,y:u},direction:0>h[s].y===a.axisY.reversed?1:-1,color:e})}c.stroke();t&&b.stroke()}}O.drawMarkers(d);c.restore();c.beginPath();t&&b.beginPath();return{source:c,dest:this.plotArea.ctx,animationCallback:E.xClipAnimation,easingFunction:E.easing.linear,animationBase:0}}};
A.prototype.renderStepLine=function(a){var c=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var b=this._eventManager.ghostCtx;c.save();var d=this.plotArea;c.beginPath();c.rect(d.x1,d.y1,d.width,d.height);c.clip();for(var d=[],f,g=0;g<a.dataSeriesIndexes.length;g++){var l=a.dataSeriesIndexes[g],k=this.data[l];c.lineWidth=k.lineThickness;var h=k.dataPoints,m="solid";if(c.setLineDash){var p=F(k.nullDataLineDashType,k.lineThickness),m=k.lineDashType,n=F(m,k.lineThickness);c.setLineDash(n)}var e=
k.id;this._eventManager.objectMap[e]={objectType:"dataSeries",dataSeriesIndex:l};e=D(e);b.strokeStyle=e;b.lineWidth=0<k.lineThickness?Math.max(k.lineThickness,4):0;var e=k._colorSet,q=e=k.lineColor=k.options.lineColor?k.options.lineColor:e[0];c.strokeStyle=e;var r=!0,s=0,x,u;c.beginPath();if(0<h.length){for(var v=!1,s=0;s<h.length;s++)if(x=h[s].getTime?h[s].x.getTime():h[s].x,!(x<a.axisX.dataInfo.viewPortMin||x>a.axisX.dataInfo.viewPortMax&&(!k.connectNullData||!v)))if("number"!==typeof h[s].y)0<
s&&!(k.connectNullData||v||r)&&(c.stroke(),t&&b.stroke()),v=!0;else{var z=u;x=a.axisX.convertValueToPixel(x);u=a.axisY.convertValueToPixel(h[s].y);var w=k.dataPointIds[s];this._eventManager.objectMap[w]={id:w,objectType:"dataPoint",dataSeriesIndex:l,dataPointIndex:s,x1:x,y1:u};r||v?(!r&&k.connectNullData?(c.setLineDash&&(k.options.nullDataLineDashType||m===k.lineDashType&&k.lineDashType!==k.nullDataLineDashType)&&(c.stroke(),c.beginPath(),c.moveTo(f.x,f.y),m=k.nullDataLineDashType,c.setLineDash(p)),
c.lineTo(x,z),c.lineTo(x,u),t&&(b.lineTo(x,z),b.lineTo(x,u))):(c.beginPath(),c.moveTo(x,u),t&&(b.beginPath(),b.moveTo(x,u))),v=r=!1):(c.lineTo(x,z),t&&b.lineTo(x,z),c.lineTo(x,u),t&&b.lineTo(x,u),0==s%500&&(c.stroke(),c.beginPath(),c.moveTo(x,u),t&&(b.stroke(),b.beginPath(),b.moveTo(x,u))));f={x:x,y:u};s<h.length-1&&(q!==(h[s].lineColor||e)||m!==(h[s].lineDashType||k.lineDashType))&&(c.stroke(),c.beginPath(),c.moveTo(x,u),q=h[s].lineColor||e,c.strokeStyle=q,c.setLineDash&&(h[s].lineDashType?(m=h[s].lineDashType,
c.setLineDash(F(m,k.lineThickness))):(m=k.lineDashType,c.setLineDash(n))));if(0<h[s].markerSize||0<k.markerSize)z=k.getMarkerProperties(s,x,u,c),d.push(z),w=D(w),t&&d.push({x:x,y:u,ctx:b,type:z.type,size:z.size,color:w,borderColor:w,borderThickness:z.borderThickness});(h[s].indexLabel||k.indexLabel||h[s].indexLabelFormatter||k.indexLabelFormatter)&&this._indexLabels.push({chartType:"stepLine",dataPoint:h[s],dataSeries:k,point:{x:x,y:u},direction:0>h[s].y===a.axisY.reversed?1:-1,color:e})}c.stroke();
t&&b.stroke()}}O.drawMarkers(d);c.restore();c.beginPath();t&&b.beginPath();return{source:c,dest:this.plotArea.ctx,animationCallback:E.xClipAnimation,easingFunction:E.easing.linear,animationBase:0}}};A.prototype.renderSpline=function(a){function c(a){a=wa(a,2);if(0<a.length){b.beginPath();t&&d.beginPath();b.moveTo(a[0].x,a[0].y);a[0].newStrokeStyle&&(b.strokeStyle=a[0].newStrokeStyle);a[0].newLineDashArray&&b.setLineDash(a[0].newLineDashArray);t&&d.moveTo(a[0].x,a[0].y);for(var c=0;c<a.length-3;c+=
3)if(b.bezierCurveTo(a[c+1].x,a[c+1].y,a[c+2].x,a[c+2].y,a[c+3].x,a[c+3].y),t&&d.bezierCurveTo(a[c+1].x,a[c+1].y,a[c+2].x,a[c+2].y,a[c+3].x,a[c+3].y),0<c&&0===c%3E3||a[c+3].newStrokeStyle||a[c+3].newLineDashArray)b.stroke(),b.beginPath(),b.moveTo(a[c+3].x,a[c+3].y),a[c+3].newStrokeStyle&&(b.strokeStyle=a[c+3].newStrokeStyle),a[c+3].newLineDashArray&&b.setLineDash(a[c+3].newLineDashArray),t&&(d.stroke(),d.beginPath(),d.moveTo(a[c+3].x,a[c+3].y));b.stroke();t&&d.stroke()}}var b=a.targetCanvasCtx||this.plotArea.ctx;
if(!(0>=a.dataSeriesIndexes.length)){var d=this._eventManager.ghostCtx;b.save();var f=this.plotArea;b.beginPath();b.rect(f.x1,f.y1,f.width,f.height);b.clip();for(var f=[],g=0;g<a.dataSeriesIndexes.length;g++){var l=a.dataSeriesIndexes[g],k=this.data[l];b.lineWidth=k.lineThickness;var h=k.dataPoints,m="solid";if(b.setLineDash){var p=F(k.nullDataLineDashType,k.lineThickness),m=k.lineDashType,n=F(m,k.lineThickness);b.setLineDash(n)}var e=k.id;this._eventManager.objectMap[e]={objectType:"dataSeries",
dataSeriesIndex:l};e=D(e);d.strokeStyle=e;d.lineWidth=0<k.lineThickness?Math.max(k.lineThickness,4):0;var e=k._colorSet,q=e=k.lineColor=k.options.lineColor?k.options.lineColor:e[0];b.strokeStyle=e;var r=0,s,x,u=[];b.beginPath();if(0<h.length)for(x=!1,r=0;r<h.length;r++)if(s=h[r].getTime?h[r].x.getTime():h[r].x,!(s<a.axisX.dataInfo.viewPortMin||s>a.axisX.dataInfo.viewPortMax&&(!k.connectNullData||!x)))if("number"!==typeof h[r].y)0<r&&!x&&(k.connectNullData?b.setLineDash&&(0<u.length&&(k.options.nullDataLineDashType||
!h[r-1].lineDashType))&&(u[u.length-1].newLineDashArray=p,m=k.nullDataLineDashType):(c(u),u=[])),x=!0;else{s=a.axisX.convertValueToPixel(s);x=a.axisY.convertValueToPixel(h[r].y);var v=k.dataPointIds[r];this._eventManager.objectMap[v]={id:v,objectType:"dataPoint",dataSeriesIndex:l,dataPointIndex:r,x1:s,y1:x};u[u.length]={x:s,y:x};r<h.length-1&&(q!==(h[r].lineColor||e)||m!==(h[r].lineDashType||k.lineDashType))&&(q=h[r].lineColor||e,u[u.length-1].newStrokeStyle=q,b.setLineDash&&(h[r].lineDashType?(m=
h[r].lineDashType,u[u.length-1].newLineDashArray=F(m,k.lineThickness)):(m=k.lineDashType,u[u.length-1].newLineDashArray=n)));if(0<h[r].markerSize||0<k.markerSize){var z=k.getMarkerProperties(r,s,x,b);f.push(z);v=D(v);t&&f.push({x:s,y:x,ctx:d,type:z.type,size:z.size,color:v,borderColor:v,borderThickness:z.borderThickness})}(h[r].indexLabel||k.indexLabel||h[r].indexLabelFormatter||k.indexLabelFormatter)&&this._indexLabels.push({chartType:"spline",dataPoint:h[r],dataSeries:k,point:{x:s,y:x},direction:0>
h[r].y===a.axisY.reversed?1:-1,color:e});x=!1}c(u)}O.drawMarkers(f);b.restore();b.beginPath();t&&d.beginPath();return{source:b,dest:this.plotArea.ctx,animationCallback:E.xClipAnimation,easingFunction:E.easing.linear,animationBase:0}}};var N=function(a,c,b,d,f,g,l,k,h,m,p,n,e){"undefined"===typeof e&&(e=1);l=l||0;k=k||"black";var q=15<d-c&&15<f-b?8:0.35*Math.min(d-c,f-b);a.beginPath();a.moveTo(c,b);a.save();a.fillStyle=g;a.globalAlpha=e;a.fillRect(c,b,d-c,f-b);a.globalAlpha=1;0<l&&(e=0===l%2?0:0.5,
a.beginPath(),a.lineWidth=l,a.strokeStyle=k,a.moveTo(c,b),a.rect(c-e,b-e,d-c+2*e,f-b+2*e),a.stroke());a.restore();!0===h&&(a.save(),a.beginPath(),a.moveTo(c,b),a.lineTo(c+q,b+q),a.lineTo(d-q,b+q),a.lineTo(d,b),a.closePath(),l=a.createLinearGradient((d+c)/2,b+q,(d+c)/2,b),l.addColorStop(0,g),l.addColorStop(1,"rgba(255, 255, 255, .4)"),a.fillStyle=l,a.fill(),a.restore());!0===m&&(a.save(),a.beginPath(),a.moveTo(c,f),a.lineTo(c+q,f-q),a.lineTo(d-q,f-q),a.lineTo(d,f),a.closePath(),l=a.createLinearGradient((d+
c)/2,f-q,(d+c)/2,f),l.addColorStop(0,g),l.addColorStop(1,"rgba(255, 255, 255, .4)"),a.fillStyle=l,a.fill(),a.restore());!0===p&&(a.save(),a.beginPath(),a.moveTo(c,b),a.lineTo(c+q,b+q),a.lineTo(c+q,f-q),a.lineTo(c,f),a.closePath(),l=a.createLinearGradient(c+q,(f+b)/2,c,(f+b)/2),l.addColorStop(0,g),l.addColorStop(1,"rgba(255, 255, 255, 0.1)"),a.fillStyle=l,a.fill(),a.restore());!0===n&&(a.save(),a.beginPath(),a.moveTo(d,b),a.lineTo(d-q,b+q),a.lineTo(d-q,f-q),a.lineTo(d,f),l=a.createLinearGradient(d-
q,(f+b)/2,d,(f+b)/2),l.addColorStop(0,g),l.addColorStop(1,"rgba(255, 255, 255, 0.1)"),a.fillStyle=l,l.addColorStop(0,g),l.addColorStop(1,"rgba(255, 255, 255, 0.1)"),a.fillStyle=l,a.fill(),a.closePath(),a.restore())};A.prototype.renderColumn=function(a){var c=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var b=null,d=this.plotArea,f=0,g,l,k,h=a.axisY.convertValueToPixel(a.axisY.logarithmic?a.axisY.viewportMinimum:0),f=this.dataPointMinWidth=this.dataPointMinWidth?this.dataPointMinWidth:
this.dataPointWidth?this.dataPointWidth:1,m=this.dataPointMaxWidth=this.dataPointMaxWidth?this.dataPointMaxWidth:this.dataPointWidth?this.dataPointWidth:Math.min(0.15*this.width,0.9*(this.plotArea.width/a.plotType.totalDataSeries))<<0,p=a.axisX.dataInfo.minDiff;isFinite(p)||(p=0.3*Math.abs(a.axisX.range));p=this.dataPointWidth=this.dataPointWidth?this.dataPointWidth:0.9*(d.width*(a.axisX.logarithmic?Math.log(p)/Math.log(a.axisX.range):Math.abs(p)/Math.abs(a.axisX.range))/a.plotType.totalDataSeries)<<
0;this.dataPointMaxWidth&&f>m&&(f=Math.min(this.dataPointWidth?this.dataPointWidth:Infinity,m));!this.dataPointMaxWidth&&(this.dataPointMinWidth&&m<f)&&(m=Math.max(this.dataPointWidth?this.dataPointWidth:-Infinity,f));p<f&&(p=f);p>m&&(p=m);c.save();t&&this._eventManager.ghostCtx.save();c.beginPath();c.rect(d.x1,d.y1,d.width,d.height);c.clip();t&&(this._eventManager.ghostCtx.beginPath(),this._eventManager.ghostCtx.rect(d.x1,d.y1,d.width,d.height),this._eventManager.ghostCtx.clip());for(d=0;d<a.dataSeriesIndexes.length;d++){var m=
a.dataSeriesIndexes[d],n=this.data[m],e=n.dataPoints;if(0<e.length)for(var q=5<p&&n.bevelEnabled?!0:!1,f=0;f<e.length;f++)if(e[f].getTime?k=e[f].x.getTime():k=e[f].x,!(k<a.axisX.dataInfo.viewPortMin||k>a.axisX.dataInfo.viewPortMax)&&"number"===typeof e[f].y){g=a.axisX.convertValueToPixel(k);l=a.axisY.convertValueToPixel(e[f].y);g=a.axisX.reversed?g+a.plotType.totalDataSeries*p/2-(a.previousDataSeriesCount+d)*p<<0:g-a.plotType.totalDataSeries*p/2+(a.previousDataSeriesCount+d)*p<<0;var r=a.axisX.reversed?
g-p<<0:g+p<<0,s;0<=e[f].y?s=h:(s=l,l=h);l>s&&(b=l,l=s,s=b);b=e[f].color?e[f].color:n._colorSet[f%n._colorSet.length];N(c,g,l,r,s,b,0,null,q&&0<=e[f].y,0>e[f].y&&q,!1,!1,n.fillOpacity);b=n.dataPointIds[f];this._eventManager.objectMap[b]={id:b,objectType:"dataPoint",dataSeriesIndex:m,dataPointIndex:f,x1:g,y1:l,x2:r,y2:s};b=D(b);t&&N(this._eventManager.ghostCtx,g,l,r,s,b,0,null,!1,!1,!1,!1);(e[f].indexLabel||n.indexLabel||e[f].indexLabelFormatter||n.indexLabelFormatter)&&this._indexLabels.push({chartType:"column",
dataPoint:e[f],dataSeries:n,point:{x:g+(r-g)/2,y:0>e[f].y===a.axisY.reversed?l:s},direction:0>e[f].y===a.axisY.reversed?1:-1,bounds:{x1:g,y1:Math.min(l,s),x2:r,y2:Math.max(l,s)},color:b})}}c.restore();t&&this._eventManager.ghostCtx.restore();return{source:c,dest:this.plotArea.ctx,animationCallback:E.yScaleAnimation,easingFunction:E.easing.easeOutQuart,animationBase:h<a.axisY.bounds.y1?a.axisY.bounds.y1:h>a.axisY.bounds.y2?a.axisY.bounds.y2:h}}};A.prototype.renderStackedColumn=function(a){var c=a.targetCanvasCtx||
this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var b=null,d=this.plotArea,f=[],g=[],l=[],k=0,h,m=a.axisY.convertValueToPixel(a.axisY.logarithmic?a.axisY.viewportMinimum:0),k=this.dataPointMinWidth?this.dataPointMinWidth:this.dataPointWidth?this.dataPointWidth:1,p=this.dataPointMaxWidth?this.dataPointMaxWidth:this.dataPointWidth?this.dataPointWidth:0.15*this.width<<0,n=a.axisX.dataInfo.minDiff;isFinite(n)||(n=0.3*Math.abs(a.axisX.range));n=this.dataPointWidth?this.dataPointWidth:0.9*(d.width*
(a.axisX.logarithmic?Math.log(n)/Math.log(a.axisX.range):Math.abs(n)/Math.abs(a.axisX.range))/a.plotType.plotUnits.length)<<0;this.dataPointMaxWidth&&k>p&&(k=Math.min(this.dataPointWidth?this.dataPointWidth:Infinity,p));!this.dataPointMaxWidth&&(this.dataPointMinWidth&&p<k)&&(p=Math.max(this.dataPointWidth?this.dataPointWidth:-Infinity,k));n<k&&(n=k);n>p&&(n=p);c.save();t&&this._eventManager.ghostCtx.save();c.beginPath();c.rect(d.x1,d.y1,d.width,d.height);c.clip();t&&(this._eventManager.ghostCtx.beginPath(),
this._eventManager.ghostCtx.rect(d.x1,d.y1,d.width,d.height),this._eventManager.ghostCtx.clip());for(p=0;p<a.dataSeriesIndexes.length;p++){var e=a.dataSeriesIndexes[p],q=this.data[e],r=q.dataPoints;if(0<r.length){var s=5<n&&q.bevelEnabled?!0:!1;c.strokeStyle="#4572A7 ";for(k=0;k<r.length;k++)if(b=r[k].x.getTime?r[k].x.getTime():r[k].x,!(b<a.axisX.dataInfo.viewPortMin||b>a.axisX.dataInfo.viewPortMax)&&"number"===typeof r[k].y){var d=a.axisX.convertValueToPixel(b),x=d-a.plotType.plotUnits.length*n/
2+a.index*n<<0,u=x+n<<0,v;if(a.axisY.logarithmic)l[b]=r[k].y+(l[b]?l[b]:0),0<l[b]&&(h=a.axisY.convertValueToPixel(l[b]),v=f[b]?f[b]:m,f[b]=h);else if(h=a.axisY.convertValueToPixel(r[k].y),0<=r[k].y){var z=f[b]?f[b]:0;h-=z;v=m-z;f[b]=z+(v-h)}else z=g[b]?g[b]:0,v=h+z,h=m+z,g[b]=z+(v-h);b=r[k].color?r[k].color:q._colorSet[k%q._colorSet.length];N(c,x,h,u,v,b,0,null,s&&0<=r[k].y,0>r[k].y&&s,!1,!1,q.fillOpacity);b=q.dataPointIds[k];this._eventManager.objectMap[b]={id:b,objectType:"dataPoint",dataSeriesIndex:e,
dataPointIndex:k,x1:x,y1:h,x2:u,y2:v};b=D(b);t&&N(this._eventManager.ghostCtx,x,h,u,v,b,0,null,!1,!1,!1,!1);(r[k].indexLabel||q.indexLabel||r[k].indexLabelFormatter||q.indexLabelFormatter)&&this._indexLabels.push({chartType:"stackedColumn",dataPoint:r[k],dataSeries:q,point:{x:d,y:0<=r[k].y?h:v},direction:0>r[k].y===a.axisY.reversed?1:-1,bounds:{x1:x,y1:Math.min(h,v),x2:u,y2:Math.max(h,v)},color:b})}}}c.restore();t&&this._eventManager.ghostCtx.restore();return{source:c,dest:this.plotArea.ctx,animationCallback:E.yScaleAnimation,
easingFunction:E.easing.easeOutQuart,animationBase:m<a.axisY.bounds.y1?a.axisY.bounds.y1:m>a.axisY.bounds.y2?a.axisY.bounds.y2:m}}};A.prototype.renderStackedColumn100=function(a){var c=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var b=null,d=this.plotArea,f=[],g=[],l=[],k=0,h,m=a.axisY.convertValueToPixel(a.axisY.logarithmic?a.axisY.viewportMinimum:0),k=this.dataPointMinWidth?this.dataPointMinWidth:this.dataPointWidth?this.dataPointWidth:1,p=this.dataPointMaxWidth?this.dataPointMaxWidth:
this.dataPointWidth?this.dataPointWidth:0.15*this.width<<0,n=a.axisX.dataInfo.minDiff;isFinite(n)||(n=0.3*Math.abs(a.axisX.range));n=this.dataPointWidth?this.dataPointWidth:0.9*(d.width*(a.axisX.logarithmic?Math.log(n)/Math.log(a.axisX.range):Math.abs(n)/Math.abs(a.axisX.range))/a.plotType.plotUnits.length)<<0;this.dataPointMaxWidth&&k>p&&(k=Math.min(this.dataPointWidth?this.dataPointWidth:Infinity,p));!this.dataPointMaxWidth&&(this.dataPointMinWidth&&p<k)&&(p=Math.max(this.dataPointWidth?this.dataPointWidth:
-Infinity,k));n<k&&(n=k);n>p&&(n=p);c.save();t&&this._eventManager.ghostCtx.save();c.beginPath();c.rect(d.x1,d.y1,d.width,d.height);c.clip();t&&(this._eventManager.ghostCtx.beginPath(),this._eventManager.ghostCtx.rect(d.x1,d.y1,d.width,d.height),this._eventManager.ghostCtx.clip());for(p=0;p<a.dataSeriesIndexes.length;p++){var e=a.dataSeriesIndexes[p],q=this.data[e],r=q.dataPoints;if(0<r.length)for(var s=5<n&&q.bevelEnabled?!0:!1,k=0;k<r.length;k++)if(b=r[k].x.getTime?r[k].x.getTime():r[k].x,!(b<a.axisX.dataInfo.viewPortMin||
b>a.axisX.dataInfo.viewPortMax)&&"number"===typeof r[k].y){d=a.axisX.convertValueToPixel(b);h=0!==a.dataPointYSums[b]?100*(r[k].y/a.dataPointYSums[b]):0;var x=d-a.plotType.plotUnits.length*n/2+a.index*n<<0,u=x+n<<0,v;if(a.axisY.logarithmic){l[b]=h+(l[b]?l[b]:0);if(0>=l[b])continue;h=a.axisY.convertValueToPixel(l[b]);v=f[b]?f[b]:m;f[b]=h}else if(h=a.axisY.convertValueToPixel(h),0<=r[k].y){var z=f[b]?f[b]:0;h-=z;v=m-z;f[b]=z+(v-h)}else z=g[b]?g[b]:0,v=h+z,h=m+z,g[b]=z+(v-h);b=r[k].color?r[k].color:
q._colorSet[k%q._colorSet.length];N(c,x,h,u,v,b,0,null,s&&0<=r[k].y,0>r[k].y&&s,!1,!1,q.fillOpacity);b=q.dataPointIds[k];this._eventManager.objectMap[b]={id:b,objectType:"dataPoint",dataSeriesIndex:e,dataPointIndex:k,x1:x,y1:h,x2:u,y2:v};b=D(b);t&&N(this._eventManager.ghostCtx,x,h,u,v,b,0,null,!1,!1,!1,!1);(r[k].indexLabel||q.indexLabel||r[k].indexLabelFormatter||q.indexLabelFormatter)&&this._indexLabels.push({chartType:"stackedColumn100",dataPoint:r[k],dataSeries:q,point:{x:d,y:0<=r[k].y?h:v},direction:0>
r[k].y===a.axisY.reversed?1:-1,bounds:{x1:x,y1:Math.min(h,v),x2:u,y2:Math.max(h,v)},color:b})}}c.restore();t&&this._eventManager.ghostCtx.restore();return{source:c,dest:this.plotArea.ctx,animationCallback:E.yScaleAnimation,easingFunction:E.easing.easeOutQuart,animationBase:m<a.axisY.bounds.y1?a.axisY.bounds.y1:m>a.axisY.bounds.y2?a.axisY.bounds.y2:m}}};A.prototype.renderBar=function(a){var c=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var b=null,d=this.plotArea,f=0,g,
l,k,h=a.axisY.convertValueToPixel(a.axisY.logarithmic?a.axisY.viewportMinimum:0),f=this.dataPointMinWidth?this.dataPointMinWidth:this.dataPointWidth?this.dataPointWidth:1,m=this.dataPointMaxWidth?this.dataPointMaxWidth:this.dataPointWidth?this.dataPointWidth:Math.min(0.15*this.height,0.9*(this.plotArea.height/a.plotType.totalDataSeries))<<0,p=a.axisX.dataInfo.minDiff;isFinite(p)||(p=0.3*Math.abs(a.axisX.range));p=this.dataPointWidth?this.dataPointWidth:0.9*(d.height*(a.axisX.logarithmic?Math.log(p)/
Math.log(a.axisX.range):Math.abs(p)/Math.abs(a.axisX.range))/a.plotType.totalDataSeries)<<0;this.dataPointMaxWidth&&f>m&&(f=Math.min(this.dataPointWidth?this.dataPointWidth:Infinity,m));!this.dataPointMaxWidth&&(this.dataPointMinWidth&&m<f)&&(m=Math.max(this.dataPointWidth?this.dataPointWidth:-Infinity,f));p<f&&(p=f);p>m&&(p=m);c.save();t&&this._eventManager.ghostCtx.save();c.beginPath();c.rect(d.x1,d.y1,d.width,d.height);c.clip();t&&(this._eventManager.ghostCtx.beginPath(),this._eventManager.ghostCtx.rect(d.x1,
d.y1,d.width,d.height),this._eventManager.ghostCtx.clip());for(d=0;d<a.dataSeriesIndexes.length;d++){var m=a.dataSeriesIndexes[d],n=this.data[m],e=n.dataPoints;if(0<e.length){var q=5<p&&n.bevelEnabled?!0:!1;c.strokeStyle="#4572A7 ";for(f=0;f<e.length;f++)if(e[f].getTime?k=e[f].x.getTime():k=e[f].x,!(k<a.axisX.dataInfo.viewPortMin||k>a.axisX.dataInfo.viewPortMax)&&"number"===typeof e[f].y){l=a.axisX.convertValueToPixel(k);g=a.axisY.convertValueToPixel(e[f].y);l=a.axisX.reversed?l+a.plotType.totalDataSeries*
p/2-(a.previousDataSeriesCount+d)*p<<0:l-a.plotType.totalDataSeries*p/2+(a.previousDataSeriesCount+d)*p<<0;var r=a.axisX.reversed?l-p<<0:l+p<<0,s;0<=e[f].y?s=h:(s=g,g=h);b=e[f].color?e[f].color:n._colorSet[f%n._colorSet.length];N(c,s,l,g,r,b,0,null,q,!1,!1,!1,n.fillOpacity);b=n.dataPointIds[f];this._eventManager.objectMap[b]={id:b,objectType:"dataPoint",dataSeriesIndex:m,dataPointIndex:f,x1:s,y1:l,x2:g,y2:r};b=D(b);t&&N(this._eventManager.ghostCtx,s,l,g,r,b,0,null,!1,!1,!1,!1);(e[f].indexLabel||n.indexLabel||
e[f].indexLabelFormatter||n.indexLabelFormatter)&&this._indexLabels.push({chartType:"bar",dataPoint:e[f],dataSeries:n,point:{x:0<=e[f].y?g:s,y:l+(r-l)/2},direction:0>e[f].y===a.axisY.reversed?1:-1,bounds:{x1:Math.min(s,g),y1:l,x2:Math.max(s,g),y2:r},color:b})}}}c.restore();t&&this._eventManager.ghostCtx.restore();return{source:c,dest:this.plotArea.ctx,animationCallback:E.xScaleAnimation,easingFunction:E.easing.easeOutQuart,animationBase:h<a.axisY.bounds.x1?a.axisY.bounds.x1:h>a.axisY.bounds.x2?a.axisY.bounds.x2:
h}}};A.prototype.renderStackedBar=function(a){var c=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var b=null,d=this.plotArea,f=[],g=[],l=[],k=0,h,m=a.axisY.convertValueToPixel(a.axisY.logarithmic?a.axisY.viewportMinimum:0),k=this.dataPointMinWidth?this.dataPointMinWidth:this.dataPointWidth?this.dataPointWidth:1,p=this.dataPointMaxWidth?this.dataPointMaxWidth:this.dataPointWidth?this.dataPointWidth:0.15*this.height<<0,n=a.axisX.dataInfo.minDiff;isFinite(n)||(n=0.3*Math.abs(a.axisX.range));
n=this.dataPointWidth?this.dataPointWidth:0.9*(d.height*(a.axisX.logarithmic?Math.log(n)/Math.log(a.axisX.range):Math.abs(n)/Math.abs(a.axisX.range))/a.plotType.plotUnits.length)<<0;this.dataPointMaxWidth&&k>p&&(k=Math.min(this.dataPointWidth?this.dataPointWidth:Infinity,p));!this.dataPointMaxWidth&&(this.dataPointMinWidth&&p<k)&&(p=Math.max(this.dataPointWidth?this.dataPointWidth:-Infinity,k));n<k&&(n=k);n>p&&(n=p);c.save();t&&this._eventManager.ghostCtx.save();c.beginPath();c.rect(d.x1,d.y1,d.width,
d.height);c.clip();t&&(this._eventManager.ghostCtx.beginPath(),this._eventManager.ghostCtx.rect(d.x1,d.y1,d.width,d.height),this._eventManager.ghostCtx.clip());for(p=0;p<a.dataSeriesIndexes.length;p++){var e=a.dataSeriesIndexes[p],q=this.data[e],r=q.dataPoints;if(0<r.length){var s=5<n&&q.bevelEnabled?!0:!1;c.strokeStyle="#4572A7 ";for(k=0;k<r.length;k++)if(b=r[k].x.getTime?r[k].x.getTime():r[k].x,!(b<a.axisX.dataInfo.viewPortMin||b>a.axisX.dataInfo.viewPortMax)&&"number"===typeof r[k].y){var d=a.axisX.convertValueToPixel(b),
x=d-a.plotType.plotUnits.length*n/2+a.index*n<<0,u=x+n<<0,v;if(a.axisY.logarithmic)l[b]=r[k].y+(l[b]?l[b]:0),0<l[b]&&(v=f[b]?f[b]:m,f[b]=h=a.axisY.convertValueToPixel(l[b]));else if(h=a.axisY.convertValueToPixel(r[k].y),0<=r[k].y){var z=f[b]?f[b]:0;v=m+z;h+=z;f[b]=z+(h-v)}else z=g[b]?g[b]:0,v=h-z,h=m-z,g[b]=z+(h-v);b=r[k].color?r[k].color:q._colorSet[k%q._colorSet.length];N(c,v,x,h,u,b,0,null,s,!1,!1,!1,q.fillOpacity);b=q.dataPointIds[k];this._eventManager.objectMap[b]={id:b,objectType:"dataPoint",
dataSeriesIndex:e,dataPointIndex:k,x1:v,y1:x,x2:h,y2:u};b=D(b);t&&N(this._eventManager.ghostCtx,v,x,h,u,b,0,null,!1,!1,!1,!1);(r[k].indexLabel||q.indexLabel||r[k].indexLabelFormatter||q.indexLabelFormatter)&&this._indexLabels.push({chartType:"stackedBar",dataPoint:r[k],dataSeries:q,point:{x:0<=r[k].y?h:v,y:d},direction:0>r[k].y===a.axisY.reversed?1:-1,bounds:{x1:Math.min(v,h),y1:x,x2:Math.max(v,h),y2:u},color:b})}}}c.restore();t&&this._eventManager.ghostCtx.restore();return{source:c,dest:this.plotArea.ctx,
animationCallback:E.xScaleAnimation,easingFunction:E.easing.easeOutQuart,animationBase:m<a.axisY.bounds.x1?a.axisY.bounds.x1:m>a.axisY.bounds.x2?a.axisY.bounds.x2:m}}};A.prototype.renderStackedBar100=function(a){var c=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var b=null,d=this.plotArea,f=[],g=[],l=[],k=0,h,m=a.axisY.convertValueToPixel(a.axisY.logarithmic?a.axisY.viewportMinimum:0),k=this.dataPointMinWidth?this.dataPointMinWidth:this.dataPointWidth?this.dataPointWidth:
1,p=this.dataPointMaxWidth?this.dataPointMaxWidth:this.dataPointWidth?this.dataPointWidth:0.15*this.height<<0,n=a.axisX.dataInfo.minDiff;isFinite(n)||(n=0.3*Math.abs(a.axisX.range));n=this.dataPointWidth?this.dataPointWidth:0.9*(d.height*(a.axisX.logarithmic?Math.log(n)/Math.log(a.axisX.range):Math.abs(n)/Math.abs(a.axisX.range))/a.plotType.plotUnits.length)<<0;this.dataPointMaxWidth&&k>p&&(k=Math.min(this.dataPointWidth?this.dataPointWidth:Infinity,p));!this.dataPointMaxWidth&&(this.dataPointMinWidth&&
p<k)&&(p=Math.max(this.dataPointWidth?this.dataPointWidth:-Infinity,k));n<k&&(n=k);n>p&&(n=p);c.save();t&&this._eventManager.ghostCtx.save();c.beginPath();c.rect(d.x1,d.y1,d.width,d.height);c.clip();t&&(this._eventManager.ghostCtx.beginPath(),this._eventManager.ghostCtx.rect(d.x1,d.y1,d.width,d.height),this._eventManager.ghostCtx.clip());for(p=0;p<a.dataSeriesIndexes.length;p++){var e=a.dataSeriesIndexes[p],q=this.data[e],r=q.dataPoints;if(0<r.length){var s=5<n&&q.bevelEnabled?!0:!1;c.strokeStyle=
"#4572A7 ";for(k=0;k<r.length;k++)if(b=r[k].x.getTime?r[k].x.getTime():r[k].x,!(b<a.axisX.dataInfo.viewPortMin||b>a.axisX.dataInfo.viewPortMax)&&"number"===typeof r[k].y){var d=a.axisX.convertValueToPixel(b),x;x=0!==a.dataPointYSums[b]?100*(r[k].y/a.dataPointYSums[b]):0;var u=d-a.plotType.plotUnits.length*n/2+a.index*n<<0,v=u+n<<0;if(a.axisY.logarithmic){l[b]=x+(l[b]?l[b]:0);if(0>=l[b])continue;x=f[b]?f[b]:m;f[b]=h=a.axisY.convertValueToPixel(l[b])}else if(h=a.axisY.convertValueToPixel(x),0<=r[k].y){var z=
f[b]?f[b]:0;x=m+z;h+=z;f[b]=z+(h-x)}else z=g[b]?g[b]:0,x=h-z,h=m-z,g[b]=z+(h-x);b=r[k].color?r[k].color:q._colorSet[k%q._colorSet.length];N(c,x,u,h,v,b,0,null,s,!1,!1,!1,q.fillOpacity);b=q.dataPointIds[k];this._eventManager.objectMap[b]={id:b,objectType:"dataPoint",dataSeriesIndex:e,dataPointIndex:k,x1:x,y1:u,x2:h,y2:v};b=D(b);t&&N(this._eventManager.ghostCtx,x,u,h,v,b,0,null,!1,!1,!1,!1);(r[k].indexLabel||q.indexLabel||r[k].indexLabelFormatter||q.indexLabelFormatter)&&this._indexLabels.push({chartType:"stackedBar100",
dataPoint:r[k],dataSeries:q,point:{x:0<=r[k].y?h:x,y:d},direction:0>r[k].y===a.axisY.reversed?1:-1,bounds:{x1:Math.min(x,h),y1:u,x2:Math.max(x,h),y2:v},color:b})}}}c.restore();t&&this._eventManager.ghostCtx.restore();return{source:c,dest:this.plotArea.ctx,animationCallback:E.xScaleAnimation,easingFunction:E.easing.easeOutQuart,animationBase:m<a.axisY.bounds.x1?a.axisY.bounds.x1:m>a.axisY.bounds.x2?a.axisY.bounds.x2:m}}};A.prototype.renderArea=function(a){var c,b;function d(){w&&(0<e.lineThickness&&
f.stroke(),a.axisY.logarithmic||0>=a.axisY.viewportMinimum&&0<=a.axisY.viewportMaximum?z=v:0>a.axisY.viewportMaximum?z=k.y1:0<a.axisY.viewportMinimum&&(z=l.y2),f.lineTo(s,z),f.lineTo(w.x,z),f.closePath(),f.globalAlpha=e.fillOpacity,f.fill(),f.globalAlpha=1,t&&(g.lineTo(s,z),g.lineTo(w.x,z),g.closePath(),g.fill()),f.beginPath(),f.moveTo(s,x),g.beginPath(),g.moveTo(s,x),w={x:s,y:x})}var f=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var g=this._eventManager.ghostCtx,l=a.axisX.lineCoordinates,
k=a.axisY.lineCoordinates,h=[],m=this.plotArea,p;f.save();t&&g.save();f.beginPath();f.rect(m.x1,m.y1,m.width,m.height);f.clip();t&&(g.beginPath(),g.rect(m.x1,m.y1,m.width,m.height),g.clip());for(m=0;m<a.dataSeriesIndexes.length;m++){var n=a.dataSeriesIndexes[m],e=this.data[n],q=e.dataPoints,h=e.id;this._eventManager.objectMap[h]={objectType:"dataSeries",dataSeriesIndex:n};h=D(h);g.fillStyle=h;h=[];c=!0;var r=0,s,x,u,v=a.axisY.convertValueToPixel(a.axisY.logarithmic?a.axisY.viewportMinimum:0),z,w=
null;if(0<q.length){var y=e._colorSet[r%e._colorSet.length],ba=e.lineColor=e.options.lineColor||y,A=ba;f.fillStyle=y;f.strokeStyle=ba;f.lineWidth=e.lineThickness;b="solid";if(f.setLineDash){var B=F(e.nullDataLineDashType,e.lineThickness);b=e.lineDashType;var W=F(b,e.lineThickness);f.setLineDash(W)}for(var X=!0;r<q.length;r++)if(u=q[r].x.getTime?q[r].x.getTime():q[r].x,!(u<a.axisX.dataInfo.viewPortMin||u>a.axisX.dataInfo.viewPortMax&&(!e.connectNullData||!X)))if("number"!==typeof q[r].y)e.connectNullData||
(X||c)||d(),X=!0;else{s=a.axisX.convertValueToPixel(u);x=a.axisY.convertValueToPixel(q[r].y);c||X?(!c&&e.connectNullData?(f.setLineDash&&(e.options.nullDataLineDashType||b===e.lineDashType&&e.lineDashType!==e.nullDataLineDashType)&&(c=s,b=x,s=p.x,x=p.y,d(),f.moveTo(p.x,p.y),s=c,x=b,w=p,b=e.nullDataLineDashType,f.setLineDash(B)),f.lineTo(s,x),t&&g.lineTo(s,x)):(f.beginPath(),f.moveTo(s,x),t&&(g.beginPath(),g.moveTo(s,x)),w={x:s,y:x}),X=c=!1):(f.lineTo(s,x),t&&g.lineTo(s,x),0==r%250&&d());p={x:s,y:x};
r<q.length-1&&(A!==(q[r].lineColor||ba)||b!==(q[r].lineDashType||e.lineDashType))&&(d(),A=q[r].lineColor||ba,f.strokeStyle=A,f.setLineDash&&(q[r].lineDashType?(b=q[r].lineDashType,f.setLineDash(F(b,e.lineThickness))):(b=e.lineDashType,f.setLineDash(W))));var H=e.dataPointIds[r];this._eventManager.objectMap[H]={id:H,objectType:"dataPoint",dataSeriesIndex:n,dataPointIndex:r,x1:s,y1:x};0!==q[r].markerSize&&(0<q[r].markerSize||0<e.markerSize)&&(u=e.getMarkerProperties(r,s,x,f),h.push(u),H=D(H),t&&h.push({x:s,
y:x,ctx:g,type:u.type,size:u.size,color:H,borderColor:H,borderThickness:u.borderThickness}));(q[r].indexLabel||e.indexLabel||q[r].indexLabelFormatter||e.indexLabelFormatter)&&this._indexLabels.push({chartType:"area",dataPoint:q[r],dataSeries:e,point:{x:s,y:x},direction:0>q[r].y===a.axisY.reversed?1:-1,color:y})}d();O.drawMarkers(h)}}f.restore();t&&this._eventManager.ghostCtx.restore();return{source:f,dest:this.plotArea.ctx,animationCallback:E.xClipAnimation,easingFunction:E.easing.linear,animationBase:0}}};
A.prototype.renderSplineArea=function(a){function c(){var c=wa(u,2);if(0<c.length){if(0<m.lineThickness){b.beginPath();b.moveTo(c[0].x,c[0].y);c[0].newStrokeStyle&&(b.strokeStyle=c[0].newStrokeStyle);c[0].newLineDashArray&&b.setLineDash(c[0].newLineDashArray);for(var e=0;e<c.length-3;e+=3)if(b.bezierCurveTo(c[e+1].x,c[e+1].y,c[e+2].x,c[e+2].y,c[e+3].x,c[e+3].y),t&&d.bezierCurveTo(c[e+1].x,c[e+1].y,c[e+2].x,c[e+2].y,c[e+3].x,c[e+3].y),c[e+3].newStrokeStyle||c[e+3].newLineDashArray)b.stroke(),b.beginPath(),
b.moveTo(c[e+3].x,c[e+3].y),c[e+3].newStrokeStyle&&(b.strokeStyle=c[e+3].newStrokeStyle),c[e+3].newLineDashArray&&b.setLineDash(c[e+3].newLineDashArray);b.stroke()}b.beginPath();b.moveTo(c[0].x,c[0].y);t&&(d.beginPath(),d.moveTo(c[0].x,c[0].y));for(e=0;e<c.length-3;e+=3)b.bezierCurveTo(c[e+1].x,c[e+1].y,c[e+2].x,c[e+2].y,c[e+3].x,c[e+3].y),t&&d.bezierCurveTo(c[e+1].x,c[e+1].y,c[e+2].x,c[e+2].y,c[e+3].x,c[e+3].y);a.axisY.logarithmic||0>=a.axisY.viewportMinimum&&0<=a.axisY.viewportMaximum?s=r:0>a.axisY.viewportMaximum?
s=g.y1:0<a.axisY.viewportMinimum&&(s=f.y2);x={x:c[0].x,y:c[0].y};b.lineTo(c[c.length-1].x,s);b.lineTo(x.x,s);b.closePath();b.globalAlpha=m.fillOpacity;b.fill();b.globalAlpha=1;t&&(d.lineTo(c[c.length-1].x,s),d.lineTo(x.x,s),d.closePath(),d.fill())}}var b=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var d=this._eventManager.ghostCtx,f=a.axisX.lineCoordinates,g=a.axisY.lineCoordinates,l=[],k=this.plotArea;b.save();t&&d.save();b.beginPath();b.rect(k.x1,k.y1,k.width,k.height);
b.clip();t&&(d.beginPath(),d.rect(k.x1,k.y1,k.width,k.height),d.clip());for(k=0;k<a.dataSeriesIndexes.length;k++){var h=a.dataSeriesIndexes[k],m=this.data[h],p=m.dataPoints,l=m.id;this._eventManager.objectMap[l]={objectType:"dataSeries",dataSeriesIndex:h};l=D(l);d.fillStyle=l;var l=[],n=0,e,q,r=a.axisY.convertValueToPixel(a.axisY.logarithmic?a.axisY.viewportMinimum:0),s,x=null,u=[];if(0<p.length){var v=m._colorSet[n%m._colorSet.length],z=m.lineColor=m.options.lineColor||v,w=z;b.fillStyle=v;b.strokeStyle=
z;b.lineWidth=m.lineThickness;var y="solid";if(b.setLineDash){var A=F(m.nullDataLineDashType,m.lineThickness),y=m.lineDashType,B=F(y,m.lineThickness);b.setLineDash(B)}for(q=!1;n<p.length;n++)if(e=p[n].x.getTime?p[n].x.getTime():p[n].x,!(e<a.axisX.dataInfo.viewPortMin||e>a.axisX.dataInfo.viewPortMax&&(!m.connectNullData||!q)))if("number"!==typeof p[n].y)0<n&&!q&&(m.connectNullData?b.setLineDash&&(0<u.length&&(m.options.nullDataLineDashType||!p[n-1].lineDashType))&&(u[u.length-1].newLineDashArray=A,
y=m.nullDataLineDashType):(c(),u=[])),q=!0;else{e=a.axisX.convertValueToPixel(e);q=a.axisY.convertValueToPixel(p[n].y);var M=m.dataPointIds[n];this._eventManager.objectMap[M]={id:M,objectType:"dataPoint",dataSeriesIndex:h,dataPointIndex:n,x1:e,y1:q};u[u.length]={x:e,y:q};n<p.length-1&&(w!==(p[n].lineColor||z)||y!==(p[n].lineDashType||m.lineDashType))&&(w=p[n].lineColor||z,u[u.length-1].newStrokeStyle=w,b.setLineDash&&(p[n].lineDashType?(y=p[n].lineDashType,u[u.length-1].newLineDashArray=F(y,m.lineThickness)):
(y=m.lineDashType,u[u.length-1].newLineDashArray=B)));if(0!==p[n].markerSize&&(0<p[n].markerSize||0<m.markerSize)){var W=m.getMarkerProperties(n,e,q,b);l.push(W);M=D(M);t&&l.push({x:e,y:q,ctx:d,type:W.type,size:W.size,color:M,borderColor:M,borderThickness:W.borderThickness})}(p[n].indexLabel||m.indexLabel||p[n].indexLabelFormatter||m.indexLabelFormatter)&&this._indexLabels.push({chartType:"splineArea",dataPoint:p[n],dataSeries:m,point:{x:e,y:q},direction:0>p[n].y===a.axisY.reversed?1:-1,color:v});
q=!1}c();O.drawMarkers(l)}}b.restore();t&&this._eventManager.ghostCtx.restore();return{source:b,dest:this.plotArea.ctx,animationCallback:E.xClipAnimation,easingFunction:E.easing.linear,animationBase:0}}};A.prototype.renderStepArea=function(a){var c,b;function d(){w&&(0<e.lineThickness&&f.stroke(),a.axisY.logarithmic||0>=a.axisY.viewportMinimum&&0<=a.axisY.viewportMaximum?z=v:0>a.axisY.viewportMaximum?z=k.y1:0<a.axisY.viewportMinimum&&(z=l.y2),f.lineTo(s,z),f.lineTo(w.x,z),f.closePath(),f.globalAlpha=
e.fillOpacity,f.fill(),f.globalAlpha=1,t&&(g.lineTo(s,z),g.lineTo(w.x,z),g.closePath(),g.fill()),f.beginPath(),f.moveTo(s,x),g.beginPath(),g.moveTo(s,x),w={x:s,y:x})}var f=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var g=this._eventManager.ghostCtx,l=a.axisX.lineCoordinates,k=a.axisY.lineCoordinates,h=[],m=this.plotArea,p;f.save();t&&g.save();f.beginPath();f.rect(m.x1,m.y1,m.width,m.height);f.clip();t&&(g.beginPath(),g.rect(m.x1,m.y1,m.width,m.height),g.clip());for(m=
0;m<a.dataSeriesIndexes.length;m++){var n=a.dataSeriesIndexes[m],e=this.data[n],q=e.dataPoints,h=e.id;this._eventManager.objectMap[h]={objectType:"dataSeries",dataSeriesIndex:n};h=D(h);g.fillStyle=h;h=[];c=!0;var r=0,s,x,u,v=a.axisY.convertValueToPixel(a.axisY.logarithmic?a.axisY.viewportMinimum:0),z,w=null;b=!1;if(0<q.length){var y=e._colorSet[r%e._colorSet.length],A=e.lineColor=e.options.lineColor||y,B=A;f.fillStyle=y;f.strokeStyle=A;f.lineWidth=e.lineThickness;var M="solid";if(f.setLineDash){var W=
F(e.nullDataLineDashType,e.lineThickness),M=e.lineDashType,X=F(M,e.lineThickness);f.setLineDash(X)}for(;r<q.length;r++)if(u=q[r].x.getTime?q[r].x.getTime():q[r].x,!(u<a.axisX.dataInfo.viewPortMin||u>a.axisX.dataInfo.viewPortMax&&(!e.connectNullData||!b))){var H=x;"number"!==typeof q[r].y?(e.connectNullData||(b||c)||d(),b=!0):(s=a.axisX.convertValueToPixel(u),x=a.axisY.convertValueToPixel(q[r].y),c||b?(!c&&e.connectNullData?(f.setLineDash&&(e.options.nullDataLineDashType||M===e.lineDashType&&e.lineDashType!==
e.nullDataLineDashType)&&(c=s,b=x,s=p.x,x=p.y,d(),f.moveTo(p.x,p.y),s=c,x=b,w=p,M=e.nullDataLineDashType,f.setLineDash(W)),f.lineTo(s,H),f.lineTo(s,x),t&&(g.lineTo(s,H),g.lineTo(s,x))):(f.beginPath(),f.moveTo(s,x),t&&(g.beginPath(),g.moveTo(s,x)),w={x:s,y:x}),b=c=!1):(f.lineTo(s,H),t&&g.lineTo(s,H),f.lineTo(s,x),t&&g.lineTo(s,x),0==r%250&&d()),p={x:s,y:x},r<q.length-1&&(B!==(q[r].lineColor||A)||M!==(q[r].lineDashType||e.lineDashType))&&(d(),B=q[r].lineColor||A,f.strokeStyle=B,f.setLineDash&&(q[r].lineDashType?
(M=q[r].lineDashType,f.setLineDash(F(M,e.lineThickness))):(M=e.lineDashType,f.setLineDash(X)))),u=e.dataPointIds[r],this._eventManager.objectMap[u]={id:u,objectType:"dataPoint",dataSeriesIndex:n,dataPointIndex:r,x1:s,y1:x},0!==q[r].markerSize&&(0<q[r].markerSize||0<e.markerSize)&&(H=e.getMarkerProperties(r,s,x,f),h.push(H),u=D(u),t&&h.push({x:s,y:x,ctx:g,type:H.type,size:H.size,color:u,borderColor:u,borderThickness:H.borderThickness})),(q[r].indexLabel||e.indexLabel||q[r].indexLabelFormatter||e.indexLabelFormatter)&&
this._indexLabels.push({chartType:"stepArea",dataPoint:q[r],dataSeries:e,point:{x:s,y:x},direction:0>q[r].y===a.axisY.reversed?1:-1,color:y}))}d();O.drawMarkers(h)}}f.restore();t&&this._eventManager.ghostCtx.restore();return{source:f,dest:this.plotArea.ctx,animationCallback:E.xClipAnimation,easingFunction:E.easing.linear,animationBase:0}}};A.prototype.renderStackedArea=function(a){function c(){if(!(1>k.length)){for(0<w.lineThickness&&b.stroke();0<k.length;){var a=k.pop();b.lineTo(a.x,a.y);t&&s.lineTo(a.x,
a.y)}b.closePath();b.globalAlpha=w.fillOpacity;b.fill();b.globalAlpha=1;b.beginPath();t&&(s.closePath(),s.fill(),s.beginPath());k=[]}}var b=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var d=null,f=[],g=this.plotArea,l=[],k=[],h=[],m=[],p=0,n,e,q,r=a.axisY.convertValueToPixel(a.axisY.logarithmic?a.axisY.viewportMinimum:0),s=this._eventManager.ghostCtx,x,u,v;t&&s.beginPath();b.save();t&&s.save();b.beginPath();b.rect(g.x1,g.y1,g.width,g.height);b.clip();t&&(s.beginPath(),
s.rect(g.x1,g.y1,g.width,g.height),s.clip());d=[];for(g=0;g<a.dataSeriesIndexes.length;g++){var z=a.dataSeriesIndexes[g],w=this.data[z],y=w.dataPoints;w.dataPointIndexes=[];for(p=0;p<y.length;p++)z=y[p].x.getTime?y[p].x.getTime():y[p].x,w.dataPointIndexes[z]=p,d[z]||(h.push(z),d[z]=!0);h.sort(Aa)}for(g=0;g<a.dataSeriesIndexes.length;g++){z=a.dataSeriesIndexes[g];w=this.data[z];y=w.dataPoints;u=!0;k=[];p=w.id;this._eventManager.objectMap[p]={objectType:"dataSeries",dataSeriesIndex:z};p=D(p);s.fillStyle=
p;if(0<h.length){var d=w._colorSet[0],A=w.lineColor=w.options.lineColor||d,B=A;b.fillStyle=d;b.strokeStyle=A;b.lineWidth=w.lineThickness;v="solid";if(b.setLineDash){var M=F(w.nullDataLineDashType,w.lineThickness);v=w.lineDashType;var W=F(v,w.lineThickness);b.setLineDash(W)}for(var X=!0,p=0;p<h.length;p++){q=h[p];var H=null,H=0<=w.dataPointIndexes[q]?y[w.dataPointIndexes[q]]:{x:q,y:null};if(!(q<a.axisX.dataInfo.viewPortMin||q>a.axisX.dataInfo.viewPortMax&&(!w.connectNullData||!X)))if("number"!==typeof H.y)w.connectNullData||
(X||u)||c(),X=!0;else{n=a.axisX.convertValueToPixel(q);var ga=l[q]?l[q]:0;if(a.axisY.logarithmic){m[q]=H.y+(m[q]?m[q]:0);if(0>=m[q])continue;e=a.axisY.convertValueToPixel(m[q])}else e=a.axisY.convertValueToPixel(H.y),e-=ga;k.push({x:n,y:r-ga});l[q]=r-e;u||X?(!u&&w.connectNullData?(b.setLineDash&&(w.options.nullDataLineDashType||v===w.lineDashType&&w.lineDashType!==w.nullDataLineDashType)&&(u=k.pop(),v=k[k.length-1],c(),b.moveTo(x.x,x.y),k.push(v),k.push(u),v=w.nullDataLineDashType,b.setLineDash(M)),
b.lineTo(n,e),t&&s.lineTo(n,e)):(b.beginPath(),b.moveTo(n,e),t&&(s.beginPath(),s.moveTo(n,e))),X=u=!1):(b.lineTo(n,e),t&&s.lineTo(n,e),0==p%250&&(c(),b.moveTo(n,e),t&&s.moveTo(n,e),k.push({x:n,y:r-ga})));x={x:n,y:e};p<y.length-1&&(B!==(y[p].lineColor||A)||v!==(y[p].lineDashType||w.lineDashType))&&(c(),b.beginPath(),b.moveTo(n,e),k.push({x:n,y:r-ga}),B=y[p].lineColor||A,b.strokeStyle=B,b.setLineDash&&(y[p].lineDashType?(v=y[p].lineDashType,b.setLineDash(F(v,w.lineThickness))):(v=w.lineDashType,b.setLineDash(W))));
if(0<=w.dataPointIndexes[q]){var ha=w.dataPointIds[w.dataPointIndexes[q]];this._eventManager.objectMap[ha]={id:ha,objectType:"dataPoint",dataSeriesIndex:z,dataPointIndex:w.dataPointIndexes[q],x1:n,y1:e}}0<=w.dataPointIndexes[q]&&0!==H.markerSize&&(0<H.markerSize||0<w.markerSize)&&(q=w.getMarkerProperties(w.dataPointIndexes[q],n,e,b),f.push(q),markerColor=D(ha),t&&f.push({x:n,y:e,ctx:s,type:q.type,size:q.size,color:markerColor,borderColor:markerColor,borderThickness:q.borderThickness}));(H.indexLabel||
w.indexLabel||H.indexLabelFormatter||w.indexLabelFormatter)&&this._indexLabels.push({chartType:"stackedArea",dataPoint:H,dataSeries:w,point:{x:n,y:e},direction:0>y[p].y===a.axisY.reversed?1:-1,color:d})}}c();b.moveTo(n,e);t&&s.moveTo(n,e)}delete w.dataPointIndexes}O.drawMarkers(f);b.restore();t&&s.restore();return{source:b,dest:this.plotArea.ctx,animationCallback:E.xClipAnimation,easingFunction:E.easing.linear,animationBase:0}}};A.prototype.renderStackedArea100=function(a){function c(){for(0<w.lineThickness&&
b.stroke();0<k.length;){var a=k.pop();b.lineTo(a.x,a.y);t&&v.lineTo(a.x,a.y)}b.closePath();b.globalAlpha=w.fillOpacity;b.fill();b.globalAlpha=1;b.beginPath();t&&(v.closePath(),v.fill(),v.beginPath());k=[]}var b=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var d=null,f=this.plotArea,g=[],l=[],k=[],h=[],m=[],p=0,n,e,q,r,s,x,u=a.axisY.convertValueToPixel(a.axisY.logarithmic?a.axisY.viewportMinimum:0),v=this._eventManager.ghostCtx;b.save();t&&v.save();b.beginPath();b.rect(f.x1,
f.y1,f.width,f.height);b.clip();t&&(v.beginPath(),v.rect(f.x1,f.y1,f.width,f.height),v.clip());d=[];for(f=0;f<a.dataSeriesIndexes.length;f++){var z=a.dataSeriesIndexes[f],w=this.data[z],y=w.dataPoints;w.dataPointIndexes=[];for(p=0;p<y.length;p++)z=y[p].x.getTime?y[p].x.getTime():y[p].x,w.dataPointIndexes[z]=p,d[z]||(h.push(z),d[z]=!0);h.sort(Aa)}for(f=0;f<a.dataSeriesIndexes.length;f++){z=a.dataSeriesIndexes[f];w=this.data[z];y=w.dataPoints;s=!0;d=w.id;this._eventManager.objectMap[d]={objectType:"dataSeries",
dataSeriesIndex:z};d=D(d);v.fillStyle=d;k=[];if(0<h.length){var d=w._colorSet[p%w._colorSet.length],A=w.lineColor=w.options.lineColor||d,B=A;b.fillStyle=d;b.strokeStyle=A;b.lineWidth=w.lineThickness;x="solid";if(b.setLineDash){var M=F(w.nullDataLineDashType,w.lineThickness);x=w.lineDashType;var W=F(x,w.lineThickness);b.setLineDash(W)}for(var X=!0,p=0;p<h.length;p++){q=h[p];var H=null,H=0<=w.dataPointIndexes[q]?y[w.dataPointIndexes[q]]:{x:q,y:null};if(!(q<a.axisX.dataInfo.viewPortMin||q>a.axisX.dataInfo.viewPortMax&&
(!w.connectNullData||!X)))if("number"!==typeof H.y)w.connectNullData||(X||s)||c(),X=!0;else{var ga;ga=0!==a.dataPointYSums[q]?100*(H.y/a.dataPointYSums[q]):0;n=a.axisX.convertValueToPixel(q);var ha=l[q]?l[q]:0;if(a.axisY.logarithmic){m[q]=ga+(m[q]?m[q]:0);if(0>=m[q])continue;e=a.axisY.convertValueToPixel(m[q])}else e=a.axisY.convertValueToPixel(ga),e-=ha;k.push({x:n,y:u-ha});l[q]=u-e;s||X?(!s&&w.connectNullData?(b.setLineDash&&(w.options.nullDataLineDashType||x===w.lineDashType&&w.lineDashType!==
w.nullDataLineDashType)&&(s=k.pop(),x=k[k.length-1],c(),b.moveTo(r.x,r.y),k.push(x),k.push(s),x=w.nullDataLineDashType,b.setLineDash(M)),b.lineTo(n,e),t&&v.lineTo(n,e)):(b.beginPath(),b.moveTo(n,e),t&&(v.beginPath(),v.moveTo(n,e))),X=s=!1):(b.lineTo(n,e),t&&v.lineTo(n,e),0==p%250&&(c(),b.moveTo(n,e),t&&v.moveTo(n,e),k.push({x:n,y:u-ha})));r={x:n,y:e};p<y.length-1&&(B!==(y[p].lineColor||A)||x!==(y[p].lineDashType||w.lineDashType))&&(c(),b.beginPath(),b.moveTo(n,e),k.push({x:n,y:u-ha}),B=y[p].lineColor||
A,b.strokeStyle=B,b.setLineDash&&(y[p].lineDashType?(x=y[p].lineDashType,b.setLineDash(F(x,w.lineThickness))):(x=w.lineDashType,b.setLineDash(W))));if(0<=w.dataPointIndexes[q]){var Ga=w.dataPointIds[w.dataPointIndexes[q]];this._eventManager.objectMap[Ga]={id:Ga,objectType:"dataPoint",dataSeriesIndex:z,dataPointIndex:w.dataPointIndexes[q],x1:n,y1:e}}0<=w.dataPointIndexes[q]&&0!==H.markerSize&&(0<H.markerSize||0<w.markerSize)&&(q=w.getMarkerProperties(p,n,e,b),g.push(q),markerColor=D(Ga),t&&g.push({x:n,
y:e,ctx:v,type:q.type,size:q.size,color:markerColor,borderColor:markerColor,borderThickness:q.borderThickness}));(H.indexLabel||w.indexLabel||H.indexLabelFormatter||w.indexLabelFormatter)&&this._indexLabels.push({chartType:"stackedArea100",dataPoint:H,dataSeries:w,point:{x:n,y:e},direction:0>y[p].y===a.axisY.reversed?1:-1,color:d})}}c();b.moveTo(n,e);t&&v.moveTo(n,e)}delete w.dataPointIndexes}O.drawMarkers(g);b.restore();t&&v.restore();return{source:b,dest:this.plotArea.ctx,animationCallback:E.xClipAnimation,
easingFunction:E.easing.linear,animationBase:0}}};A.prototype.renderBubble=function(a){var c=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var b=this.plotArea,d=0,f,g;c.save();t&&this._eventManager.ghostCtx.save();c.beginPath();c.rect(b.x1,b.y1,b.width,b.height);c.clip();t&&(this._eventManager.ghostCtx.beginPath(),this._eventManager.ghostCtx.rect(b.x1,b.y1,b.width,b.height),this._eventManager.ghostCtx.clip());for(var l=-Infinity,k=Infinity,h=0;h<a.dataSeriesIndexes.length;h++)for(var m=
a.dataSeriesIndexes[h],p=this.data[m],n=p.dataPoints,e=0,d=0;d<n.length;d++)f=n[d].getTime?f=n[d].x.getTime():f=n[d].x,f<a.axisX.dataInfo.viewPortMin||f>a.axisX.dataInfo.viewPortMax||"undefined"===typeof n[d].z||(e=n[d].z,e>l&&(l=e),e<k&&(k=e));for(var q=25*Math.PI,b=Math.max(Math.pow(0.25*Math.min(b.height,b.width)/2,2)*Math.PI,q),h=0;h<a.dataSeriesIndexes.length;h++)if(m=a.dataSeriesIndexes[h],p=this.data[m],n=p.dataPoints,0<n.length)for(c.strokeStyle="#4572A7 ",d=0;d<n.length;d++)if(f=n[d].getTime?
f=n[d].x.getTime():f=n[d].x,!(f<a.axisX.dataInfo.viewPortMin||f>a.axisX.dataInfo.viewPortMax)&&"number"===typeof n[d].y){f=a.axisX.convertValueToPixel(f);g=a.axisY.convertValueToPixel(n[d].y);var e=n[d].z,r=2*Math.max(Math.sqrt((l===k?b/2:q+(b-q)/(l-k)*(e-k))/Math.PI)<<0,1),e=p.getMarkerProperties(d,c);e.size=r;c.globalAlpha=p.fillOpacity;O.drawMarker(f,g,c,e.type,e.size,e.color,e.borderColor,e.borderThickness);c.globalAlpha=1;var s=p.dataPointIds[d];this._eventManager.objectMap[s]={id:s,objectType:"dataPoint",
dataSeriesIndex:m,dataPointIndex:d,x1:f,y1:g,size:r};r=D(s);t&&O.drawMarker(f,g,this._eventManager.ghostCtx,e.type,e.size,r,r,e.borderThickness);(n[d].indexLabel||p.indexLabel||n[d].indexLabelFormatter||p.indexLabelFormatter)&&this._indexLabels.push({chartType:"bubble",dataPoint:n[d],dataSeries:p,point:{x:f,y:g},direction:1,bounds:{x1:f-e.size/2,y1:g-e.size/2,x2:f+e.size/2,y2:g+e.size/2},color:null})}c.restore();t&&this._eventManager.ghostCtx.restore();return{source:c,dest:this.plotArea.ctx,animationCallback:E.fadeInAnimation,
easingFunction:E.easing.easeInQuad,animationBase:0}}};A.prototype.renderScatter=function(a){var c=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var b=this.plotArea,d=0,f,g;c.save();t&&this._eventManager.ghostCtx.save();c.beginPath();c.rect(b.x1,b.y1,b.width,b.height);c.clip();t&&(this._eventManager.ghostCtx.beginPath(),this._eventManager.ghostCtx.rect(b.x1,b.y1,b.width,b.height),this._eventManager.ghostCtx.clip());for(var l=0;l<a.dataSeriesIndexes.length;l++){var k=a.dataSeriesIndexes[l],
h=this.data[k],m=h.dataPoints;if(0<m.length){c.strokeStyle="#4572A7 ";Math.pow(0.3*Math.min(b.height,b.width)/2,2);for(var p=0,n=0,d=0;d<m.length;d++)if(f=m[d].getTime?f=m[d].x.getTime():f=m[d].x,!(f<a.axisX.dataInfo.viewPortMin||f>a.axisX.dataInfo.viewPortMax)&&"number"===typeof m[d].y){f=a.axisX.convertValueToPixel(f);g=a.axisY.convertValueToPixel(m[d].y);var e=h.getMarkerProperties(d,f,g,c);c.globalAlpha=h.fillOpacity;O.drawMarker(e.x,e.y,e.ctx,e.type,e.size,e.color,e.borderColor,e.borderThickness);
c.globalAlpha=1;Math.sqrt((p-f)*(p-f)+(n-g)*(n-g))<Math.min(e.size,5)&&m.length>Math.min(this.plotArea.width,this.plotArea.height)||(p=h.dataPointIds[d],this._eventManager.objectMap[p]={id:p,objectType:"dataPoint",dataSeriesIndex:k,dataPointIndex:d,x1:f,y1:g},p=D(p),t&&O.drawMarker(e.x,e.y,this._eventManager.ghostCtx,e.type,e.size,p,p,e.borderThickness),(m[d].indexLabel||h.indexLabel||m[d].indexLabelFormatter||h.indexLabelFormatter)&&this._indexLabels.push({chartType:"scatter",dataPoint:m[d],dataSeries:h,
point:{x:f,y:g},direction:1,bounds:{x1:f-e.size/2,y1:g-e.size/2,x2:f+e.size/2,y2:g+e.size/2},color:null}),p=f,n=g)}}}c.restore();t&&this._eventManager.ghostCtx.restore();return{source:c,dest:this.plotArea.ctx,animationCallback:E.fadeInAnimation,easingFunction:E.easing.easeInQuad,animationBase:0}}};A.prototype.renderCandlestick=function(a){var c=a.targetCanvasCtx||this.plotArea.ctx,b=this._eventManager.ghostCtx;if(!(0>=a.dataSeriesIndexes.length)){var d=null,d=this.plotArea,f=0,g,l,k,h,m,p,f=this.dataPointMinWidth?
this.dataPointMinWidth:this.dataPointWidth?this.dataPointWidth:1;g=this.dataPointMaxWidth?this.dataPointMaxWidth:this.dataPointWidth?this.dataPointWidth:0.015*this.width;var n=a.axisX.dataInfo.minDiff;isFinite(n)||(n=0.3*Math.abs(a.axisX.range));n=this.dataPointWidth?this.dataPointWidth:0.7*d.width*(a.axisX.logarithmic?Math.log(n)/Math.log(a.axisX.range):Math.abs(n)/Math.abs(a.axisX.range))<<0;this.dataPointMaxWidth&&f>g&&(f=Math.min(this.dataPointWidth?this.dataPointWidth:Infinity,g));!this.dataPointMaxWidth&&
(this.dataPointMinWidth&&g<f)&&(g=Math.max(this.dataPointWidth?this.dataPointWidth:-Infinity,f));n<f&&(n=f);n>g&&(n=g);c.save();t&&b.save();c.beginPath();c.rect(d.x1,d.y1,d.width,d.height);c.clip();t&&(b.beginPath(),b.rect(d.x1,d.y1,d.width,d.height),b.clip());for(var e=0;e<a.dataSeriesIndexes.length;e++){var q=a.dataSeriesIndexes[e],r=this.data[q],s=r.dataPoints;if(0<s.length)for(var x=5<n&&r.bevelEnabled?!0:!1,f=0;f<s.length;f++)if(s[f].getTime?p=s[f].x.getTime():p=s[f].x,!(p<a.axisX.dataInfo.viewPortMin||
p>a.axisX.dataInfo.viewPortMax)&&null!==s[f].y&&s[f].y.length&&"number"===typeof s[f].y[0]&&"number"===typeof s[f].y[1]&&"number"===typeof s[f].y[2]&&"number"===typeof s[f].y[3]){g=a.axisX.convertValueToPixel(p);l=a.axisY.convertValueToPixel(s[f].y[0]);k=a.axisY.convertValueToPixel(s[f].y[1]);h=a.axisY.convertValueToPixel(s[f].y[2]);m=a.axisY.convertValueToPixel(s[f].y[3]);var u=g-n/2<<0,v=u+n<<0,d=s[f].color?s[f].color:r._colorSet[0],z=Math.round(Math.max(1,0.15*n)),w=0===z%2?0:0.5,y=r.dataPointIds[f];
this._eventManager.objectMap[y]={id:y,objectType:"dataPoint",dataSeriesIndex:q,dataPointIndex:f,x1:u,y1:l,x2:v,y2:k,x3:g,y3:h,x4:g,y4:m,borderThickness:z,color:d};c.strokeStyle=d;c.beginPath();c.lineWidth=z;b.lineWidth=Math.max(z,4);"candlestick"===r.type?(c.moveTo(g-w,k),c.lineTo(g-w,Math.min(l,m)),c.stroke(),c.moveTo(g-w,Math.max(l,m)),c.lineTo(g-w,h),c.stroke(),N(c,u,Math.min(l,m),v,Math.max(l,m),s[f].y[0]<=s[f].y[3]?r.risingColor:d,z,d,x,x,!1,!1,r.fillOpacity),t&&(d=D(y),b.strokeStyle=d,b.moveTo(g-
w,k),b.lineTo(g-w,Math.min(l,m)),b.stroke(),b.moveTo(g-w,Math.max(l,m)),b.lineTo(g-w,h),b.stroke(),N(b,u,Math.min(l,m),v,Math.max(l,m),d,0,null,!1,!1,!1,!1))):"ohlc"===r.type&&(c.moveTo(g-w,k),c.lineTo(g-w,h),c.stroke(),c.beginPath(),c.moveTo(g,l),c.lineTo(u,l),c.stroke(),c.beginPath(),c.moveTo(g,m),c.lineTo(v,m),c.stroke(),t&&(d=D(y),b.strokeStyle=d,b.moveTo(g-w,k),b.lineTo(g-w,h),b.stroke(),b.beginPath(),b.moveTo(g,l),b.lineTo(u,l),b.stroke(),b.beginPath(),b.moveTo(g,m),b.lineTo(v,m),b.stroke()));
(s[f].indexLabel||r.indexLabel||s[f].indexLabelFormatter||r.indexLabelFormatter)&&this._indexLabels.push({chartType:r.type,dataPoint:s[f],dataSeries:r,point:{x:u+(v-u)/2,y:a.axisY.reversed?h:k},direction:1,bounds:{x1:u,y1:Math.min(k,h),x2:v,y2:Math.max(k,h)},color:d})}}c.restore();t&&b.restore();return{source:c,dest:this.plotArea.ctx,animationCallback:E.fadeInAnimation,easingFunction:E.easing.easeInQuad,animationBase:0}}};A.prototype.renderRangeColumn=function(a){var c=a.targetCanvasCtx||this.plotArea.ctx;
if(!(0>=a.dataSeriesIndexes.length)){var b=null,d=this.plotArea,f=0,g,l,f=this.dataPointMinWidth?this.dataPointMinWidth:this.dataPointWidth?this.dataPointWidth:1;g=this.dataPointMaxWidth?this.dataPointMaxWidth:this.dataPointWidth?this.dataPointWidth:0.03*this.width;var k=a.axisX.dataInfo.minDiff;isFinite(k)||(k=0.3*Math.abs(a.axisX.range));k=this.dataPointWidth?this.dataPointWidth:0.9*(d.width*(a.axisX.logarithmic?Math.log(k)/Math.log(a.axisX.range):Math.abs(k)/Math.abs(a.axisX.range))/a.plotType.totalDataSeries)<<
0;this.dataPointMaxWidth&&f>g&&(f=Math.min(this.dataPointWidth?this.dataPointWidth:Infinity,g));!this.dataPointMaxWidth&&(this.dataPointMinWidth&&g<f)&&(g=Math.max(this.dataPointWidth?this.dataPointWidth:-Infinity,f));k<f&&(k=f);k>g&&(k=g);c.save();t&&this._eventManager.ghostCtx.save();c.beginPath();c.rect(d.x1,d.y1,d.width,d.height);c.clip();t&&(this._eventManager.ghostCtx.beginPath(),this._eventManager.ghostCtx.rect(d.x1,d.y1,d.width,d.height),this._eventManager.ghostCtx.clip());for(var h=0;h<a.dataSeriesIndexes.length;h++){var m=
a.dataSeriesIndexes[h],p=this.data[m],n=p.dataPoints;if(0<n.length)for(var e=5<k&&p.bevelEnabled?!0:!1,f=0;f<n.length;f++)if(n[f].getTime?l=n[f].x.getTime():l=n[f].x,!(l<a.axisX.dataInfo.viewPortMin||l>a.axisX.dataInfo.viewPortMax)&&null!==n[f].y&&n[f].y.length&&"number"===typeof n[f].y[0]&&"number"===typeof n[f].y[1]){b=a.axisX.convertValueToPixel(l);d=a.axisY.convertValueToPixel(n[f].y[0]);g=a.axisY.convertValueToPixel(n[f].y[1]);var q=a.axisX.reversed?b+a.plotType.totalDataSeries*k/2-(a.previousDataSeriesCount+
h)*k<<0:b-a.plotType.totalDataSeries*k/2+(a.previousDataSeriesCount+h)*k<<0,r=a.axisX.reversed?q-k<<0:q+k<<0,b=n[f].color?n[f].color:p._colorSet[f%p._colorSet.length];if(d>g){var s=d,d=g;g=s}s=p.dataPointIds[f];this._eventManager.objectMap[s]={id:s,objectType:"dataPoint",dataSeriesIndex:m,dataPointIndex:f,x1:q,y1:d,x2:r,y2:g};N(c,q,d,r,g,b,0,b,e,e,!1,!1,p.fillOpacity);b=D(s);t&&N(this._eventManager.ghostCtx,q,d,r,g,b,0,null,!1,!1,!1,!1);if(n[f].indexLabel||p.indexLabel||n[f].indexLabelFormatter||
p.indexLabelFormatter)this._indexLabels.push({chartType:"rangeColumn",dataPoint:n[f],dataSeries:p,indexKeyword:0,point:{x:q+(r-q)/2,y:n[f].y[1]>=n[f].y[0]?g:d},direction:n[f].y[1]>=n[f].y[0]?-1:1,bounds:{x1:q,y1:Math.min(d,g),x2:r,y2:Math.max(d,g)},color:b}),this._indexLabels.push({chartType:"rangeColumn",dataPoint:n[f],dataSeries:p,indexKeyword:1,point:{x:q+(r-q)/2,y:n[f].y[1]>=n[f].y[0]?d:g},direction:n[f].y[1]>=n[f].y[0]?1:-1,bounds:{x1:q,y1:Math.min(d,g),x2:r,y2:Math.max(d,g)},color:b})}}c.restore();
t&&this._eventManager.ghostCtx.restore();return{source:c,dest:this.plotArea.ctx,animationCallback:E.fadeInAnimation,easingFunction:E.easing.easeInQuad,animationBase:0}}};A.prototype.renderRangeBar=function(a){var c=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var b=null,d=this.plotArea,f=0,g,l,k,f=this.dataPointMinWidth?this.dataPointMinWidth:this.dataPointWidth?this.dataPointWidth:1;g=this.dataPointMaxWidth?this.dataPointMaxWidth:this.dataPointWidth?this.dataPointWidth:
Math.min(0.15*this.height,0.9*(this.plotArea.height/a.plotType.totalDataSeries))<<0;var h=a.axisX.dataInfo.minDiff;isFinite(h)||(h=0.3*Math.abs(a.axisX.range));h=this.dataPointWidth?this.dataPointWidth:0.9*(d.height*(a.axisX.logarithmic?Math.log(h)/Math.log(a.axisX.range):Math.abs(h)/Math.abs(a.axisX.range))/a.plotType.totalDataSeries)<<0;this.dataPointMaxWidth&&f>g&&(f=Math.min(this.dataPointWidth?this.dataPointWidth:Infinity,g));!this.dataPointMaxWidth&&(this.dataPointMinWidth&&g<f)&&(g=Math.max(this.dataPointWidth?
this.dataPointWidth:-Infinity,f));h<f&&(h=f);h>g&&(h=g);c.save();t&&this._eventManager.ghostCtx.save();c.beginPath();c.rect(d.x1,d.y1,d.width,d.height);c.clip();t&&(this._eventManager.ghostCtx.beginPath(),this._eventManager.ghostCtx.rect(d.x1,d.y1,d.width,d.height),this._eventManager.ghostCtx.clip());for(var m=0;m<a.dataSeriesIndexes.length;m++){var p=a.dataSeriesIndexes[m],n=this.data[p],e=n.dataPoints;if(0<e.length){var q=5<h&&n.bevelEnabled?!0:!1;c.strokeStyle="#4572A7 ";for(f=0;f<e.length;f++)if(e[f].getTime?
k=e[f].x.getTime():k=e[f].x,!(k<a.axisX.dataInfo.viewPortMin||k>a.axisX.dataInfo.viewPortMax)&&null!==e[f].y&&e[f].y.length&&"number"===typeof e[f].y[0]&&"number"===typeof e[f].y[1]){d=a.axisY.convertValueToPixel(e[f].y[0]);g=a.axisY.convertValueToPixel(e[f].y[1]);l=a.axisX.convertValueToPixel(k);l=a.axisX.reversed?l+a.plotType.totalDataSeries*h/2-(a.previousDataSeriesCount+m)*h<<0:l-a.plotType.totalDataSeries*h/2+(a.previousDataSeriesCount+m)*h<<0;var r=a.axisX.reversed?l-h<<0:l+h<<0;d>g&&(b=d,d=
g,g=b);b=e[f].color?e[f].color:n._colorSet[f%n._colorSet.length];N(c,d,l,g,r,b,0,null,q,!1,!1,!1,n.fillOpacity);b=n.dataPointIds[f];this._eventManager.objectMap[b]={id:b,objectType:"dataPoint",dataSeriesIndex:p,dataPointIndex:f,x1:d,y1:l,x2:g,y2:r};b=D(b);t&&N(this._eventManager.ghostCtx,d,l,g,r,b,0,null,!1,!1,!1,!1);if(e[f].indexLabel||n.indexLabel||e[f].indexLabelFormatter||n.indexLabelFormatter)this._indexLabels.push({chartType:"rangeBar",dataPoint:e[f],dataSeries:n,indexKeyword:0,point:{x:e[f].y[1]>=
e[f].y[0]?d:g,y:l+(r-l)/2},direction:e[f].y[1]>=e[f].y[0]?-1:1,bounds:{x1:Math.min(d,g),y1:l,x2:Math.max(d,g),y2:r},color:b}),this._indexLabels.push({chartType:"rangeBar",dataPoint:e[f],dataSeries:n,indexKeyword:1,point:{x:e[f].y[1]>=e[f].y[0]?g:d,y:l+(r-l)/2},direction:e[f].y[1]>=e[f].y[0]?1:-1,bounds:{x1:Math.min(d,g),y1:l,x2:Math.max(d,g),y2:r},color:b})}}}c.restore();t&&this._eventManager.ghostCtx.restore();return{source:c,dest:this.plotArea.ctx,animationCallback:E.fadeInAnimation,easingFunction:E.easing.easeInQuad,
animationBase:0}}};A.prototype.renderRangeArea=function(a){function c(){if(x){var a=null;0<h.lineThickness&&b.stroke();for(var c=l.length-1;0<=c;c--)a=l[c],b.lineTo(a.x,a.y),d.lineTo(a.x,a.y);b.closePath();b.globalAlpha=h.fillOpacity;b.fill();b.globalAlpha=1;d.fill();if(0<h.lineThickness){b.beginPath();b.moveTo(a.x,a.y);for(c=0;c<l.length;c++)a=l[c],b.lineTo(a.x,a.y);b.stroke()}b.beginPath();b.moveTo(e,q);d.beginPath();d.moveTo(e,q);x={x:e,y:q};l=[];l.push({x:e,y:r})}}var b=a.targetCanvasCtx||this.plotArea.ctx;
if(!(0>=a.dataSeriesIndexes.length)){var d=this._eventManager.ghostCtx,f=[],g=this.plotArea;b.save();t&&d.save();b.beginPath();b.rect(g.x1,g.y1,g.width,g.height);b.clip();t&&(d.beginPath(),d.rect(g.x1,g.y1,g.width,g.height),d.clip());for(g=0;g<a.dataSeriesIndexes.length;g++){var l=[],k=a.dataSeriesIndexes[g],h=this.data[k],m=h.dataPoints,f=h.id;this._eventManager.objectMap[f]={objectType:"dataSeries",dataSeriesIndex:k};f=D(f);d.fillStyle=f;var f=[],p=!0,n=0,e,q,r,s,x=null;if(0<m.length){var u=h._colorSet[n%
h._colorSet.length],v=h.lineColor=h.options.lineColor||u,z=v;b.fillStyle=u;b.strokeStyle=v;b.lineWidth=h.lineThickness;var w="solid";if(b.setLineDash){var y=F(h.nullDataLineDashType,h.lineThickness),w=h.lineDashType,A=F(w,h.lineThickness);b.setLineDash(A)}for(var B=!0;n<m.length;n++)if(s=m[n].x.getTime?m[n].x.getTime():m[n].x,!(s<a.axisX.dataInfo.viewPortMin||s>a.axisX.dataInfo.viewPortMax&&(!h.connectNullData||!B)))if(null!==m[n].y&&m[n].y.length&&"number"===typeof m[n].y[0]&&"number"===typeof m[n].y[1]){e=
a.axisX.convertValueToPixel(s);q=a.axisY.convertValueToPixel(m[n].y[0]);r=a.axisY.convertValueToPixel(m[n].y[1]);p||B?(h.connectNullData&&!p?(b.setLineDash&&(h.options.nullDataLineDashType||w===h.lineDashType&&h.lineDashType!==h.nullDataLineDashType)&&(l[l.length-1].newLineDashArray=A,w=h.nullDataLineDashType,b.setLineDash(y)),b.lineTo(e,q),t&&d.lineTo(e,q),l.push({x:e,y:r})):(b.beginPath(),b.moveTo(e,q),x={x:e,y:q},l=[],l.push({x:e,y:r}),t&&(d.beginPath(),d.moveTo(e,q))),B=p=!1):(b.lineTo(e,q),l.push({x:e,
y:r}),t&&d.lineTo(e,q),0==n%250&&c());s=h.dataPointIds[n];this._eventManager.objectMap[s]={id:s,objectType:"dataPoint",dataSeriesIndex:k,dataPointIndex:n,x1:e,y1:q,y2:r};n<m.length-1&&(z!==(m[n].lineColor||v)||w!==(m[n].lineDashType||h.lineDashType))&&(c(),z=m[n].lineColor||v,l[l.length-1].newStrokeStyle=z,b.strokeStyle=z,b.setLineDash&&(m[n].lineDashType?(w=m[n].lineDashType,l[l.length-1].newLineDashArray=F(w,h.lineThickness),b.setLineDash(l[l.length-1].newLineDashArray)):(w=h.lineDashType,l[l.length-
1].newLineDashArray=A,b.setLineDash(A))));if(0!==m[n].markerSize&&(0<m[n].markerSize||0<h.markerSize)){var M=h.getMarkerProperties(n,e,r,b);f.push(M);var W=D(s);t&&f.push({x:e,y:r,ctx:d,type:M.type,size:M.size,color:W,borderColor:W,borderThickness:M.borderThickness});M=h.getMarkerProperties(n,e,q,b);f.push(M);W=D(s);t&&f.push({x:e,y:q,ctx:d,type:M.type,size:M.size,color:W,borderColor:W,borderThickness:M.borderThickness})}if(m[n].indexLabel||h.indexLabel||m[n].indexLabelFormatter||h.indexLabelFormatter)this._indexLabels.push({chartType:"rangeArea",
dataPoint:m[n],dataSeries:h,indexKeyword:0,point:{x:e,y:q},direction:m[n].y[0]>m[n].y[1]===a.axisY.reversed?-1:1,color:u}),this._indexLabels.push({chartType:"rangeArea",dataPoint:m[n],dataSeries:h,indexKeyword:1,point:{x:e,y:r},direction:m[n].y[0]>m[n].y[1]===a.axisY.reversed?1:-1,color:u})}else B||p||c(),B=!0;c();O.drawMarkers(f)}}b.restore();t&&this._eventManager.ghostCtx.restore();return{source:b,dest:this.plotArea.ctx,animationCallback:E.xClipAnimation,easingFunction:E.easing.linear,animationBase:0}}};
A.prototype.renderRangeSplineArea=function(a){function c(a,c){var e=wa(q,2);if(0<e.length){if(0<k.lineThickness){b.strokeStyle=c;b.setLineDash&&b.setLineDash(a);b.beginPath();b.moveTo(e[0].x,e[0].y);for(var f=0;f<e.length-3;f+=3){if(e[f].newStrokeStyle||e[f].newLineDashArray)b.stroke(),b.beginPath(),b.moveTo(e[f].x,e[f].y),e[f].newStrokeStyle&&(b.strokeStyle=e[f].newStrokeStyle),e[f].newLineDashArray&&b.setLineDash(e[f].newLineDashArray);b.bezierCurveTo(e[f+1].x,e[f+1].y,e[f+2].x,e[f+2].y,e[f+3].x,
e[f+3].y)}b.stroke()}b.beginPath();b.moveTo(e[0].x,e[0].y);t&&(d.beginPath(),d.moveTo(e[0].x,e[0].y));for(f=0;f<e.length-3;f+=3)b.bezierCurveTo(e[f+1].x,e[f+1].y,e[f+2].x,e[f+2].y,e[f+3].x,e[f+3].y),t&&d.bezierCurveTo(e[f+1].x,e[f+1].y,e[f+2].x,e[f+2].y,e[f+3].x,e[f+3].y);e=wa(r,2);b.lineTo(r[r.length-1].x,r[r.length-1].y);for(f=e.length-1;2<f;f-=3)b.bezierCurveTo(e[f-1].x,e[f-1].y,e[f-2].x,e[f-2].y,e[f-3].x,e[f-3].y),t&&d.bezierCurveTo(e[f-1].x,e[f-1].y,e[f-2].x,e[f-2].y,e[f-3].x,e[f-3].y);b.closePath();
b.globalAlpha=k.fillOpacity;b.fill();t&&(d.closePath(),d.fill());b.globalAlpha=1;if(0<k.lineThickness){b.strokeStyle=c;b.setLineDash&&b.setLineDash(a);b.beginPath();b.moveTo(e[0].x,e[0].y);for(var g=f=0;f<e.length-3;f+=3,g++){if(q[g].newStrokeStyle||q[g].newLineDashArray)b.stroke(),b.beginPath(),b.moveTo(e[f].x,e[f].y),q[g].newStrokeStyle&&(b.strokeStyle=q[g].newStrokeStyle),q[g].newLineDashArray&&b.setLineDash(q[g].newLineDashArray);b.bezierCurveTo(e[f+1].x,e[f+1].y,e[f+2].x,e[f+2].y,e[f+3].x,e[f+
3].y)}b.stroke()}b.beginPath()}}var b=a.targetCanvasCtx||this.plotArea.ctx;if(!(0>=a.dataSeriesIndexes.length)){var d=this._eventManager.ghostCtx,f=[],g=this.plotArea;b.save();t&&d.save();b.beginPath();b.rect(g.x1,g.y1,g.width,g.height);b.clip();t&&(d.beginPath(),d.rect(g.x1,g.y1,g.width,g.height),d.clip());for(g=0;g<a.dataSeriesIndexes.length;g++){var l=a.dataSeriesIndexes[g],k=this.data[l],h=k.dataPoints,f=k.id;this._eventManager.objectMap[f]={objectType:"dataSeries",dataSeriesIndex:l};f=D(f);d.fillStyle=
f;var f=[],m=0,p,n,e,q=[],r=[];if(0<h.length){var s=k._colorSet[m%k._colorSet.length],x=k.lineColor=k.options.lineColor||s,u=x;b.fillStyle=s;b.lineWidth=k.lineThickness;var v="solid",z;if(b.setLineDash){var w=F(k.nullDataLineDashType,k.lineThickness),v=k.lineDashType;z=F(v,k.lineThickness)}for(n=!1;m<h.length;m++)if(p=h[m].x.getTime?h[m].x.getTime():h[m].x,!(p<a.axisX.dataInfo.viewPortMin||p>a.axisX.dataInfo.viewPortMax&&(!k.connectNullData||!n)))if(null!==h[m].y&&h[m].y.length&&"number"===typeof h[m].y[0]&&
"number"===typeof h[m].y[1]){p=a.axisX.convertValueToPixel(p);n=a.axisY.convertValueToPixel(h[m].y[0]);e=a.axisY.convertValueToPixel(h[m].y[1]);var y=k.dataPointIds[m];this._eventManager.objectMap[y]={id:y,objectType:"dataPoint",dataSeriesIndex:l,dataPointIndex:m,x1:p,y1:n,y2:e};q[q.length]={x:p,y:n};r[r.length]={x:p,y:e};m<h.length-1&&(u!==(h[m].lineColor||x)||v!==(h[m].lineDashType||k.lineDashType))&&(u=h[m].lineColor||x,q[q.length-1].newStrokeStyle=u,b.setLineDash&&(h[m].lineDashType?(v=h[m].lineDashType,
q[q.length-1].newLineDashArray=F(v,k.lineThickness)):(v=k.lineDashType,q[q.length-1].newLineDashArray=z)));if(0!==h[m].markerSize&&(0<h[m].markerSize||0<k.markerSize)){var A=k.getMarkerProperties(m,p,n,b);f.push(A);var B=D(y);t&&f.push({x:p,y:n,ctx:d,type:A.type,size:A.size,color:B,borderColor:B,borderThickness:A.borderThickness});A=k.getMarkerProperties(m,p,e,b);f.push(A);B=D(y);t&&f.push({x:p,y:e,ctx:d,type:A.type,size:A.size,color:B,borderColor:B,borderThickness:A.borderThickness})}if(h[m].indexLabel||
k.indexLabel||h[m].indexLabelFormatter||k.indexLabelFormatter)this._indexLabels.push({chartType:"rangeSplineArea",dataPoint:h[m],dataSeries:k,indexKeyword:0,point:{x:p,y:n},direction:h[m].y[0]<=h[m].y[1]?-1:1,color:s}),this._indexLabels.push({chartType:"rangeSplineArea",dataPoint:h[m],dataSeries:k,indexKeyword:1,point:{x:p,y:e},direction:h[m].y[0]<=h[m].y[1]?1:-1,color:s});n=!1}else 0<m&&!n&&(k.connectNullData?b.setLineDash&&(0<q.length&&(k.options.nullDataLineDashType||!h[m-1].lineDashType))&&(q[q.length-
1].newLineDashArray=w,v=k.nullDataLineDashType):(c(z,x),q=[],r=[])),n=!0;c(z,x);O.drawMarkers(f)}}b.restore();t&&this._eventManager.ghostCtx.restore();return{source:b,dest:this.plotArea.ctx,animationCallback:E.xClipAnimation,easingFunction:E.easing.linear,animationBase:0}}};var Ha=function(a,c,b,d,f,g,l,k,h){if(!(0>b)){"undefined"===typeof k&&(k=1);if(!t){var m=Number((l%(2*Math.PI)).toFixed(8));Number((g%(2*Math.PI)).toFixed(8))===m&&(l-=1E-4)}a.save();a.globalAlpha=k;"pie"===f?(a.beginPath(),a.moveTo(c.x,
c.y),a.arc(c.x,c.y,b,g,l,!1),a.fillStyle=d,a.strokeStyle="white",a.lineWidth=2,a.closePath(),a.fill()):"doughnut"===f&&(a.beginPath(),a.arc(c.x,c.y,b,g,l,!1),0<=h&&a.arc(c.x,c.y,h*b,l,g,!0),a.closePath(),a.fillStyle=d,a.strokeStyle="white",a.lineWidth=2,a.fill());a.globalAlpha=1;a.restore()}};A.prototype.renderPie=function(a){function c(){if(m&&p){for(var a=0,b=0,c=0,d=0,f=0;f<p.length;f++){var g=p[f],k=m.dataPointIds[f],l={id:k,objectType:"dataPoint",dataPointIndex:f,dataSeriesIndex:0};q.push(l);
var n={percent:null,total:null},r=null,n=h.getPercentAndTotal(m,g);if(m.indexLabelFormatter||g.indexLabelFormatter)r={chart:h.options,dataSeries:m,dataPoint:g,total:n.total,percent:n.percent};n=g.indexLabelFormatter?g.indexLabelFormatter(r):g.indexLabel?h.replaceKeywordsWithValue(g.indexLabel,g,m,f):m.indexLabelFormatter?m.indexLabelFormatter(r):m.indexLabel?h.replaceKeywordsWithValue(m.indexLabel,g,m,f):g.label?g.label:"";h._eventManager.objectMap[k]=l;l.center={x:z.x,y:z.y};l.y=g.y;l.radius=B;l.percentInnerRadius=
M;l.indexLabelText=n;l.indexLabelPlacement=m.indexLabelPlacement;l.indexLabelLineColor=g.indexLabelLineColor?g.indexLabelLineColor:m.options.indexLabelLineColor?m.options.indexLabelLineColor:g.color?g.color:m._colorSet[f%m._colorSet.length];l.indexLabelLineThickness=y(g.indexLabelLineThickness)?m.indexLabelLineThickness:g.indexLabelLineThickness;l.indexLabelLineDashType=g.indexLabelLineDashType?g.indexLabelLineDashType:m.indexLabelLineDashType;l.indexLabelFontColor=g.indexLabelFontColor?g.indexLabelFontColor:
m.indexLabelFontColor;l.indexLabelFontStyle=g.indexLabelFontStyle?g.indexLabelFontStyle:m.indexLabelFontStyle;l.indexLabelFontWeight=g.indexLabelFontWeight?g.indexLabelFontWeight:m.indexLabelFontWeight;l.indexLabelFontSize=y(g.indexLabelFontSize)?m.indexLabelFontSize:g.indexLabelFontSize;l.indexLabelFontFamily=g.indexLabelFontFamily?g.indexLabelFontFamily:m.indexLabelFontFamily;l.indexLabelBackgroundColor=g.indexLabelBackgroundColor?g.indexLabelBackgroundColor:m.options.indexLabelBackgroundColor?
m.options.indexLabelBackgroundColor:m.indexLabelBackgroundColor;l.indexLabelMaxWidth=g.indexLabelMaxWidth?g.indexLabelMaxWidth:m.indexLabelMaxWidth?m.indexLabelMaxWidth:0.33*e.width;l.indexLabelWrap="undefined"!==typeof g.indexLabelWrap?g.indexLabelWrap:m.indexLabelWrap;l.startAngle=0===f?m.startAngle?m.startAngle/180*Math.PI:0:q[f-1].endAngle;l.startAngle=(l.startAngle+2*Math.PI)%(2*Math.PI);l.endAngle=l.startAngle+2*Math.PI/t*Math.abs(g.y);g=(l.endAngle+l.startAngle)/2;g=(g+2*Math.PI)%(2*Math.PI);
l.midAngle=g;if(l.midAngle>Math.PI/2-u&&l.midAngle<Math.PI/2+u){if(0===a||q[c].midAngle>l.midAngle)c=f;a++}else if(l.midAngle>3*Math.PI/2-u&&l.midAngle<3*Math.PI/2+u){if(0===b||q[d].midAngle>l.midAngle)d=f;b++}l.hemisphere=g>Math.PI/2&&g<=3*Math.PI/2?"left":"right";l.indexLabelTextBlock=new V(h.plotArea.ctx,{fontSize:l.indexLabelFontSize,fontFamily:l.indexLabelFontFamily,fontColor:l.indexLabelFontColor,fontStyle:l.indexLabelFontStyle,fontWeight:l.indexLabelFontWeight,horizontalAlign:"left",backgroundColor:l.indexLabelBackgroundColor,
maxWidth:l.indexLabelMaxWidth,maxHeight:l.indexLabelWrap?5*l.indexLabelFontSize:1.5*l.indexLabelFontSize,text:l.indexLabelText,padding:0,textBaseline:"top"});l.indexLabelTextBlock.measureText()}k=g=0;n=!1;for(f=0;f<p.length;f++)l=q[(c+f)%p.length],1<a&&(l.midAngle>Math.PI/2-u&&l.midAngle<Math.PI/2+u)&&(g<=a/2&&!n?(l.hemisphere="right",g++):(l.hemisphere="left",n=!0));n=!1;for(f=0;f<p.length;f++)l=q[(d+f)%p.length],1<b&&(l.midAngle>3*Math.PI/2-u&&l.midAngle<3*Math.PI/2+u)&&(k<=b/2&&!n?(l.hemisphere=
"left",k++):(l.hemisphere="right",n=!0))}}function b(a){var b=h.plotArea.ctx;b.clearRect(e.x1,e.y1,e.width,e.height);b.fillStyle=h.backgroundColor;b.fillRect(e.x1,e.y1,e.width,e.height);for(b=0;b<p.length;b++){var c=q[b].startAngle,d=q[b].endAngle;if(d>c){var f=0.07*B*Math.cos(q[b].midAngle),g=0.07*B*Math.sin(q[b].midAngle),k=!1;if(p[b].exploded){if(1E-9<Math.abs(q[b].center.x-(z.x+f))||1E-9<Math.abs(q[b].center.y-(z.y+g)))q[b].center.x=z.x+f*a,q[b].center.y=z.y+g*a,k=!0}else if(0<Math.abs(q[b].center.x-
z.x)||0<Math.abs(q[b].center.y-z.y))q[b].center.x=z.x+f*(1-a),q[b].center.y=z.y+g*(1-a),k=!0;k&&(f={},f.dataSeries=m,f.dataPoint=m.dataPoints[b],f.index=b,h.toolTip.highlightObjects([f]));Ha(h.plotArea.ctx,q[b].center,q[b].radius,p[b].color?p[b].color:m._colorSet[b%m._colorSet.length],m.type,c,d,m.fillOpacity,q[b].percentInnerRadius)}}a=h.plotArea.ctx;a.save();a.fillStyle="black";a.strokeStyle="grey";a.textBaseline="middle";a.lineJoin="round";for(b=b=0;b<p.length;b++)c=q[b],c.indexLabelText&&(c.indexLabelTextBlock.y-=
c.indexLabelTextBlock.height/2,d=0,d="left"===c.hemisphere?"inside"!==m.indexLabelPlacement?-(c.indexLabelTextBlock.width+n):-c.indexLabelTextBlock.width/2:"inside"!==m.indexLabelPlacement?n:-c.indexLabelTextBlock.width/2,c.indexLabelTextBlock.x+=d,c.indexLabelTextBlock.render(!0),c.indexLabelTextBlock.x-=d,c.indexLabelTextBlock.y+=c.indexLabelTextBlock.height/2,"inside"!==c.indexLabelPlacement&&0<c.indexLabelLineThickness&&(d=c.center.x+B*Math.cos(c.midAngle),f=c.center.y+B*Math.sin(c.midAngle),
a.strokeStyle=c.indexLabelLineColor,a.lineWidth=c.indexLabelLineThickness,a.setLineDash&&a.setLineDash(F(c.indexLabelLineDashType,c.indexLabelLineThickness)),a.beginPath(),a.moveTo(d,f),a.lineTo(c.indexLabelTextBlock.x,c.indexLabelTextBlock.y),a.lineTo(c.indexLabelTextBlock.x+("left"===c.hemisphere?-n:n),c.indexLabelTextBlock.y),a.stroke()),a.lineJoin="miter");a.save()}function d(a,b){var c=0,c=a.indexLabelTextBlock.y-a.indexLabelTextBlock.height/2,d=a.indexLabelTextBlock.y+a.indexLabelTextBlock.height/
2,e=b.indexLabelTextBlock.y-b.indexLabelTextBlock.height/2,f=b.indexLabelTextBlock.y+b.indexLabelTextBlock.height/2;return c=b.indexLabelTextBlock.y>a.indexLabelTextBlock.y?e-d:c-f}function f(a){for(var b=null,c=1;c<p.length;c++)if(b=(a+c+q.length)%q.length,q[b].hemisphere!==q[a].hemisphere){b=null;break}else if(q[b].indexLabelText&&b!==a&&(0>d(q[b],q[a])||("right"===q[a].hemisphere?q[b].indexLabelTextBlock.y>=q[a].indexLabelTextBlock.y:q[b].indexLabelTextBlock.y<=q[a].indexLabelTextBlock.y)))break;
else b=null;return b}function g(a,b,c){c=(c||0)+1;if(1E3<c)return 0;b=b||0;var e=0,h=z.y-1*s,m=z.y+1*s;if(0<=a&&a<p.length){var k=q[a];if(0>b&&k.indexLabelTextBlock.y<h||0<b&&k.indexLabelTextBlock.y>m)return 0;var l=0,n=0,n=l=l=0;0>b?k.indexLabelTextBlock.y-k.indexLabelTextBlock.height/2>h&&k.indexLabelTextBlock.y-k.indexLabelTextBlock.height/2+b<h&&(b=-(h-(k.indexLabelTextBlock.y-k.indexLabelTextBlock.height/2+b))):k.indexLabelTextBlock.y+k.indexLabelTextBlock.height/2<h&&k.indexLabelTextBlock.y+
k.indexLabelTextBlock.height/2+b>m&&(b=k.indexLabelTextBlock.y+k.indexLabelTextBlock.height/2+b-m);b=k.indexLabelTextBlock.y+b;h=0;h="right"===k.hemisphere?z.x+Math.sqrt(Math.pow(s,2)-Math.pow(b-z.y,2)):z.x-Math.sqrt(Math.pow(s,2)-Math.pow(b-z.y,2));n=z.x+B*Math.cos(k.midAngle);l=z.y+B*Math.sin(k.midAngle);l=Math.sqrt(Math.pow(h-n,2)+Math.pow(b-l,2));n=Math.acos(B/s);l=Math.acos((s*s+B*B-l*l)/(2*B*s));b=l<n?b-k.indexLabelTextBlock.y:0;h=null;for(m=1;m<p.length;m++)if(h=(a-m+q.length)%q.length,q[h].hemisphere!==
q[a].hemisphere){h=null;break}else if(q[h].indexLabelText&&q[h].hemisphere===q[a].hemisphere&&h!==a&&(0>d(q[h],q[a])||("right"===q[a].hemisphere?q[h].indexLabelTextBlock.y<=q[a].indexLabelTextBlock.y:q[h].indexLabelTextBlock.y>=q[a].indexLabelTextBlock.y)))break;else h=null;n=h;l=f(a);m=h=0;0>b?(m="right"===k.hemisphere?n:l,e=b,null!==m&&(n=-b,b=k.indexLabelTextBlock.y-k.indexLabelTextBlock.height/2-(q[m].indexLabelTextBlock.y+q[m].indexLabelTextBlock.height/2),b-n<r&&(h=-n,m=g(m,h,c+1),+m.toFixed(v)>
+h.toFixed(v)&&(e=b>r?-(b-r):-(n-(m-h)))))):0<b&&(m="right"===k.hemisphere?l:n,e=b,null!==m&&(n=b,b=q[m].indexLabelTextBlock.y-q[m].indexLabelTextBlock.height/2-(k.indexLabelTextBlock.y+k.indexLabelTextBlock.height/2),b-n<r&&(h=n,m=g(m,h,c+1),+m.toFixed(v)<+h.toFixed(v)&&(e=b>r?b-r:n-(h-m)))));e&&(c=k.indexLabelTextBlock.y+e,b=0,b="right"===k.hemisphere?z.x+Math.sqrt(Math.pow(s,2)-Math.pow(c-z.y,2)):z.x-Math.sqrt(Math.pow(s,2)-Math.pow(c-z.y,2)),k.midAngle>Math.PI/2-u&&k.midAngle<Math.PI/2+u?(h=(a-
1+q.length)%q.length,h=q[h],a=q[(a+1+q.length)%q.length],"left"===k.hemisphere&&"right"===h.hemisphere&&b>h.indexLabelTextBlock.x?b=h.indexLabelTextBlock.x-15:"right"===k.hemisphere&&("left"===a.hemisphere&&b<a.indexLabelTextBlock.x)&&(b=a.indexLabelTextBlock.x+15)):k.midAngle>3*Math.PI/2-u&&k.midAngle<3*Math.PI/2+u&&(h=(a-1+q.length)%q.length,h=q[h],a=q[(a+1+q.length)%q.length],"right"===k.hemisphere&&"left"===h.hemisphere&&b<h.indexLabelTextBlock.x?b=h.indexLabelTextBlock.x+15:"left"===k.hemisphere&&
("right"===a.hemisphere&&b>a.indexLabelTextBlock.x)&&(b=a.indexLabelTextBlock.x-15)),k.indexLabelTextBlock.y=c,k.indexLabelTextBlock.x=b,k.indexLabelAngle=Math.atan2(k.indexLabelTextBlock.y-z.y,k.indexLabelTextBlock.x-z.x))}return e}function l(){var a=h.plotArea.ctx;a.fillStyle="grey";a.strokeStyle="grey";a.font="16px Arial";a.textBaseline="middle";for(var b=a=0,c=0,k=!0,b=0;10>b&&(1>b||0<c);b++){if(m.radius||!m.radius&&"undefined"!==typeof m.innerRadius&&null!==m.innerRadius&&B-c<=E)k=!1;k&&(B-=
c);c=0;if("inside"!==m.indexLabelPlacement){s=B*x;for(a=0;a<p.length;a++){var l=q[a];l.indexLabelTextBlock.x=z.x+s*Math.cos(l.midAngle);l.indexLabelTextBlock.y=z.y+s*Math.sin(l.midAngle);l.indexLabelAngle=l.midAngle;l.radius=B;l.percentInnerRadius=M}for(var u,t,a=0;a<p.length;a++){var l=q[a],w=f(a);if(null!==w){u=q[a];t=q[w];var y=0,y=d(u,t)-r;if(0>y){for(var A=t=0,D=0;D<p.length;D++)D!==a&&q[D].hemisphere===l.hemisphere&&(q[D].indexLabelTextBlock.y<l.indexLabelTextBlock.y?t++:A++);t=y/(t+A||1)*A;
var A=-1*(y-t),C=D=0;"right"===l.hemisphere?(D=g(a,t),A=-1*(y-D),C=g(w,A),+C.toFixed(v)<+A.toFixed(v)&&+D.toFixed(v)<=+t.toFixed(v)&&g(a,-(A-C))):(D=g(w,t),A=-1*(y-D),C=g(a,A),+C.toFixed(v)<+A.toFixed(v)&&+D.toFixed(v)<=+t.toFixed(v)&&g(w,-(A-C)))}}}}else for(a=0;a<p.length;a++)l=q[a],s="pie"===m.type?0.7*B:0.8*B,w=z.x+s*Math.cos(l.midAngle),t=z.y+s*Math.sin(l.midAngle),l.indexLabelTextBlock.x=w,l.indexLabelTextBlock.y=t;for(a=0;a<p.length;a++)if(l=q[a],w=l.indexLabelTextBlock.measureText(),0!==w.height&&
0!==w.width)w=w=0,"right"===l.hemisphere?(w=e.x2-(l.indexLabelTextBlock.x+l.indexLabelTextBlock.width+n),w*=-1):w=e.x1-(l.indexLabelTextBlock.x-l.indexLabelTextBlock.width-n),0<w&&(!k&&l.indexLabelText&&(t="right"===l.hemisphere?e.x2-l.indexLabelTextBlock.x:l.indexLabelTextBlock.x-e.x1,0.3*l.indexLabelTextBlock.maxWidth>t?l.indexLabelText="":l.indexLabelTextBlock.maxWidth=0.85*t,0.3*l.indexLabelTextBlock.maxWidth<t&&(l.indexLabelTextBlock.x-="right"===l.hemisphere?2:-2)),Math.abs(l.indexLabelTextBlock.y-
l.indexLabelTextBlock.height/2-z.y)<B||Math.abs(l.indexLabelTextBlock.y+l.indexLabelTextBlock.height/2-z.y)<B)&&(w/=Math.abs(Math.cos(l.indexLabelAngle)),9<w&&(w*=0.3),w>c&&(c=w)),w=w=0,0<l.indexLabelAngle&&l.indexLabelAngle<Math.PI?(w=e.y2-(l.indexLabelTextBlock.y+l.indexLabelTextBlock.height/2+5),w*=-1):w=e.y1-(l.indexLabelTextBlock.y-l.indexLabelTextBlock.height/2-5),0<w&&(!k&&l.indexLabelText&&(t=0<l.indexLabelAngle&&l.indexLabelAngle<Math.PI?-1:1,0===g(a,w*t)&&g(a,2*t)),Math.abs(l.indexLabelTextBlock.x-
z.x)<B&&(w/=Math.abs(Math.sin(l.indexLabelAngle)),9<w&&(w*=0.3),w>c&&(c=w)));var F=function(a,b,c){for(var d=[],e=0;d.push(q[b]),b!==c;b=(b+1+p.length)%p.length);d.sort(function(a,b){return a.y-b.y});for(b=0;b<d.length;b++)if(c=d[b],e<0.7*a)e+=c.indexLabelTextBlock.height,c.indexLabelTextBlock.text="",c.indexLabelText="",c.indexLabelTextBlock.measureText();else break};(function(){for(var a=-1,b=-1,c=0,e=!1,g=0;g<p.length;g++)if(e=!1,u=q[g],u.indexLabelText){var h=f(g);if(null!==h){var k=q[h];y=0;
y=d(u,k);var l;if(l=0>y){l=u.indexLabelTextBlock.x;var m=u.indexLabelTextBlock.y-u.indexLabelTextBlock.height/2,r=u.indexLabelTextBlock.y+u.indexLabelTextBlock.height/2,s=k.indexLabelTextBlock.y-k.indexLabelTextBlock.height/2,x=k.indexLabelTextBlock.x+k.indexLabelTextBlock.width,v=k.indexLabelTextBlock.y+k.indexLabelTextBlock.height/2;l=u.indexLabelTextBlock.x+u.indexLabelTextBlock.width<k.indexLabelTextBlock.x-n||l>x+n||m>v+n||r<s-n?!1:!0}l?(0>a&&(a=g),h!==a&&(b=h,c+=-y),0===g%Math.max(p.length/
10,3)&&(e=!0)):e=!0;e&&(0<c&&0<=a&&0<=b)&&(F(c,a,b),b=a=-1,c=0)}}0<c&&F(c,a,b)})()}}function k(){h.plotArea.layoutManager.reset();h.title&&(h.title.dockInsidePlotArea||"center"===h.title.horizontalAlign&&"center"===h.title.verticalAlign)&&h.title.render();if(h.subtitles)for(var a=0;a<h.subtitles.length;a++){var b=h.subtitles[a];(b.dockInsidePlotArea||"center"===b.horizontalAlign&&"center"===b.verticalAlign)&&b.render()}h.legend&&(h.legend.dockInsidePlotArea||"center"===h.legend.horizontalAlign&&"center"===
h.legend.verticalAlign)&&h.legend.render()}var h=this;if(!(0>=a.dataSeriesIndexes.length)){var m=this.data[a.dataSeriesIndexes[0]],p=m.dataPoints,n=10,e=this.plotArea,q=[],r=2,s,x=1.3,u=20/180*Math.PI,v=6,z={x:(e.x2+e.x1)/2,y:(e.y2+e.y1)/2},t=0;a=!1;for(var A=0;A<p.length;A++)t+=Math.abs(p[A].y),!a&&("undefined"!==typeof p[A].indexLabel&&null!==p[A].indexLabel&&0<p[A].indexLabel.toString().length)&&(a=!0),!a&&("undefined"!==typeof p[A].label&&null!==p[A].label&&0<p[A].label.toString().length)&&(a=
!0);if(0!==t){a=a||"undefined"!==typeof m.indexLabel&&null!==m.indexLabel&&0<m.indexLabel.toString().length;var B="inside"!==m.indexLabelPlacement&&a?0.75*Math.min(e.width,e.height)/2:0.92*Math.min(e.width,e.height)/2;m.radius&&(B=Qa(m.radius,B));var E="undefined"!==typeof m.innerRadius&&null!==m.innerRadius?Qa(m.innerRadius,B):0.7*B;m.radius=B;"doughnut"===m.type&&(m.innerRadius=E);var M=Math.min(E/B,(B-1)/B);this.pieDoughnutClickHandler=function(a){h.isAnimating||!y(a.dataSeries.explodeOnClick)&&
!a.dataSeries.explodeOnClick||(a=a.dataPoint,a.exploded=a.exploded?!1:!0,1<this.dataPoints.length&&h._animator.animate(0,500,function(a){b(a);k()}))};c();l();l();l();l();this.disableToolTip=!0;this._animator.animate(0,this.animatedRender?this.animationDuration:0,function(a){var b=h.plotArea.ctx;b.clearRect(e.x1,e.y1,e.width,e.height);b.fillStyle=h.backgroundColor;b.fillRect(e.x1,e.y1,e.width,e.height);a=q[0].startAngle+2*Math.PI*a;for(b=0;b<p.length;b++){var c=0===b?q[b].startAngle:d,d=c+(q[b].endAngle-
q[b].startAngle),f=!1;d>a&&(d=a,f=!0);var g=p[b].color?p[b].color:m._colorSet[b%m._colorSet.length];d>c&&Ha(h.plotArea.ctx,q[b].center,q[b].radius,g,m.type,c,d,m.fillOpacity,q[b].percentInnerRadius);if(f)break}k()},function(){h.disableToolTip=!1;h._animator.animate(0,h.animatedRender?500:0,function(a){b(a);k()})})}}};A.prototype.animationRequestId=null;A.prototype.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||
window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1E3/60)}}();A.prototype.cancelRequestAnimFrame=window.cancelAnimationFrame||window.webkitCancelRequestAnimationFrame||window.mozCancelRequestAnimationFrame||window.oCancelRequestAnimationFrame||window.msCancelRequestAnimationFrame||clearTimeout;A.prototype.set=function(a,c,b){b="undefined"===typeof b?!0:b;"options"===a?(this.options=c,b&&this.render()):A.base.set.call(this,a,c,b)};A.prototype.exportChart=
function(a){a="undefined"===typeof a?{}:a;var c=a.format?a.format:"png",b=a.fileName?a.fileName:this.exportFileName;if(a.toDataURL)return this.canvas.toDataURL("image/"+c);Ca(this.canvas,c,b)};A.prototype.print=function(){var a=this.exportChart({toDataURL:!0}),c=document.createElement("iframe");c.setAttribute("class","canvasjs-chart-print-frame");c.setAttribute("style","position:absolute; width:100%; border: 0px; margin: 0px 0px 0px 0px; padding 0px 0px 0px 0px;");c.style.height=this.height+"px";
this._canvasJSContainer.appendChild(c);var b=this,d=c.contentWindow||c.contentDocument.document||c.contentDocument;d.document.open();d.document.write('<!DOCTYPE HTML>\n<html><body style="margin: 0px 0px 0px 0px; padding: 0px 0px 0px 0px;"><img src="'+a+'"/><body/></html>');d.document.close();setTimeout(function(){d.focus();d.print();setTimeout(function(){b._canvasJSContainer.removeChild(c)},1E3)},500)};la.prototype.registerSpace=function(a,c){"top"===a?this._topOccupied+=c.height:"bottom"===a?this._bottomOccupied+=
c.height:"left"===a?this._leftOccupied+=c.width:"right"===a&&(this._rightOccupied+=c.width)};la.prototype.unRegisterSpace=function(a,c){"top"===a?this._topOccupied-=c.height:"bottom"===a?this._bottomOccupied-=c.height:"left"===a?this._leftOccupied-=c.width:"right"===a&&(this._rightOccupied-=c.width)};la.prototype.getFreeSpace=function(){return{x1:this._x1+this._leftOccupied,y1:this._y1+this._topOccupied,x2:this._x2-this._rightOccupied,y2:this._y2-this._bottomOccupied,width:this._x2-this._x1-this._rightOccupied-
this._leftOccupied,height:this._y2-this._y1-this._bottomOccupied-this._topOccupied}};la.prototype.reset=function(){this._rightOccupied=this._leftOccupied=this._bottomOccupied=this._topOccupied=this._padding};T(V,L);V.prototype.render=function(a){if(0!==this.fontSize){a&&this.ctx.save();var c=this.ctx.font;this.ctx.textBaseline=this.textBaseline;var b=0;this._isDirty&&this.measureText(this.ctx);this.ctx.translate(this.x,this.y+b);"middle"===this.textBaseline&&(b=-this._lineHeight/2);this.ctx.font=
this._getFontString();this.ctx.rotate(Math.PI/180*this.angle);var d=0,f=this.padding,g=null;this.ctx.roundRect||Ja(this.ctx);(0<this.borderThickness&&this.borderColor||this.backgroundColor)&&this.ctx.roundRect(0,b,this.width,this.height,this.cornerRadius,this.borderThickness,this.backgroundColor,this.borderColor);this.ctx.fillStyle=this.fontColor;for(b=0;b<this._wrappedText.lines.length;b++)g=this._wrappedText.lines[b],"right"===this.horizontalAlign?d=this.width-g.width-this.padding:"left"===this.horizontalAlign?
d=this.padding:"center"===this.horizontalAlign&&(d=(this.width-2*this.padding)/2-g.width/2+this.padding),this.ctx.fillText(g.text,d,f),f+=g.height;this.ctx.font=c;a&&this.ctx.restore()}};V.prototype.setText=function(a){this.text=a;this._isDirty=!0;this._wrappedText=null};V.prototype.measureText=function(){this._lineHeight=La(this.fontFamily,this.fontSize,this.fontWeight);if(null===this.maxWidth)throw"Please set maxWidth and height for TextBlock";this._wrapText(this.ctx);this._isDirty=!1;return{width:this.width,
height:this.height}};V.prototype._getLineWithWidth=function(a,c,b){a=String(a);if(!a)return{text:"",width:0};var d=b=0,f=a.length-1,g=Infinity;for(this.ctx.font=this._getFontString();d<=f;){var g=Math.floor((d+f)/2),l=a.substr(0,g+1);b=this.ctx.measureText(l).width;if(b<c)d=g+1;else if(b>c)f=g-1;else break}b>c&&1<l.length&&(l=l.substr(0,l.length-1),b=this.ctx.measureText(l).width);c=!0;if(l.length===a.length||" "===a[l.length])c=!1;c&&(a=l.split(" "),1<a.length&&a.pop(),l=a.join(" "),b=this.ctx.measureText(l).width);
return{text:l,width:b}};V.prototype._wrapText=function(){var a=new String(ma(String(this.text))),c=[],b=this.ctx.font,d=0,f=0;this.ctx.font=this._getFontString();if(0===this.frontSize)f=d=0;else for(;0<a.length;){var g=this.maxHeight-2*this.padding,l=this._getLineWithWidth(a,this.maxWidth-2*this.padding,!1);l.height=this._lineHeight;c.push(l);var k=f,f=Math.max(f,l.width),d=d+l.height,a=ma(a.slice(l.text.length,a.length));g&&d>g&&(l=c.pop(),d-=l.height,f=k)}this._wrappedText={lines:c,width:f,height:d};
this.width=f+2*this.padding;this.height=d+2*this.padding;this.ctx.font=b};V.prototype._getFontString=function(){var a;a=""+(this.fontStyle?this.fontStyle+" ":"");a+=this.fontWeight?this.fontWeight+" ":"";a+=this.fontSize?this.fontSize+"px ":"";var c=this.fontFamily?this.fontFamily+"":"";!t&&c&&(c=c.split(",")[0],"'"!==c[0]&&'"'!==c[0]&&(c="'"+c+"'"));return a+=c};T(oa,L);oa.prototype.render=function(){if(this.text){var a=this.dockInsidePlotArea?this.chart.plotArea:this.chart,c=a.layoutManager.getFreeSpace(),
b=c.x1,d=c.y1,f=0,g=0,l=this.chart._menuButton&&this.chart.exportEnabled&&"top"===this.verticalAlign?22:0,k,h;"top"===this.verticalAlign||"bottom"===this.verticalAlign?(null===this.maxWidth&&(this.maxWidth=c.width-4-l*("center"===this.horizontalAlign?2:1)),g=0.5*c.height-this.margin-2,f=0):"center"===this.verticalAlign&&("left"===this.horizontalAlign||"right"===this.horizontalAlign?(null===this.maxWidth&&(this.maxWidth=c.height-4),g=0.5*c.width-this.margin-2):"center"===this.horizontalAlign&&(null===
this.maxWidth&&(this.maxWidth=c.width-4),g=0.5*c.height-4));this.wrap||(g=Math.min(g,Math.max(1.5*this.fontSize,this.fontSize+2.5*this.padding)));var g=new V(this.ctx,{fontSize:this.fontSize,fontFamily:this.fontFamily,fontColor:this.fontColor,fontStyle:this.fontStyle,fontWeight:this.fontWeight,horizontalAlign:this.horizontalAlign,verticalAlign:this.verticalAlign,borderColor:this.borderColor,borderThickness:this.borderThickness,backgroundColor:this.backgroundColor,maxWidth:this.maxWidth,maxHeight:g,
cornerRadius:this.cornerRadius,text:this.text,padding:this.padding,textBaseline:"top"}),m=g.measureText();"top"===this.verticalAlign||"bottom"===this.verticalAlign?("top"===this.verticalAlign?(d=c.y1+2,h="top"):"bottom"===this.verticalAlign&&(d=c.y2-2-m.height,h="bottom"),"left"===this.horizontalAlign?b=c.x1+2:"center"===this.horizontalAlign?b=c.x1+c.width/2-m.width/2:"right"===this.horizontalAlign&&(b=c.x2-2-m.width-l),k=this.horizontalAlign,this.width=m.width,this.height=m.height):"center"===this.verticalAlign&&
("left"===this.horizontalAlign?(b=c.x1+2,d=c.y2-2-(this.maxWidth/2-m.width/2),f=-90,h="left",this.width=m.height,this.height=m.width):"right"===this.horizontalAlign?(b=c.x2-2,d=c.y1+2+(this.maxWidth/2-m.width/2),f=90,h="right",this.width=m.height,this.height=m.width):"center"===this.horizontalAlign&&(d=a.y1+(a.height/2-m.height/2),b=a.x1+(a.width/2-m.width/2),h="center",this.width=m.width,this.height=m.height),k="center");g.x=b;g.y=d;g.angle=f;g.horizontalAlign=k;g.render(!0);a.layoutManager.registerSpace(h,
{width:this.width+("left"===h||"right"===h?this.margin+2:0),height:this.height+("top"===h||"bottom"===h?this.margin+2:0)});this.bounds={x1:b,y1:d,x2:b+this.width,y2:d+this.height};this.ctx.textBaseline="top"}};T(xa,L);xa.prototype.render=oa.prototype.render;T(ya,L);ya.prototype.render=function(){var a=this.dockInsidePlotArea?this.chart.plotArea:this.chart,c=a.layoutManager.getFreeSpace(),b=null,d=0,f=0,g=0,l=0,k=this.markerMargin=this.chart.options.legend&&!y(this.chart.options.legend.markerMargin)?
this.chart.options.legend.markerMargin:0.3*this.fontSize;this.height=0;var h=[],m=[];"top"===this.verticalAlign||"bottom"===this.verticalAlign?(this.orientation="horizontal",b=this.verticalAlign,g=this.maxWidth=null!==this.maxWidth?this.maxWidth:c.width,l=this.maxHeight=null!==this.maxHeight?this.maxHeight:0.5*c.height):"center"===this.verticalAlign&&(this.orientation="vertical",b=this.horizontalAlign,g=this.maxWidth=null!==this.maxWidth?this.maxWidth:0.5*c.width,l=this.maxHeight=null!==this.maxHeight?
this.maxHeight:c.height);for(var p=0;p<this.dataSeries.length;p++){var n=this.dataSeries[p];if(n.dataPoints&&n.dataPoints.length)if("pie"!==n.type&&"doughnut"!==n.type&&"funnel"!==n.type){var e=n.legendMarkerType=n.legendMarkerType?n.legendMarkerType:"line"!==n.type&&"stepLine"!==n.type&&"spline"!==n.type&&"scatter"!==n.type&&"bubble"!==n.type||!n.markerType?ca.getDefaultLegendMarker(n.type):n.markerType,q=n.legendText?n.legendText:this.itemTextFormatter?this.itemTextFormatter({chart:this.chart,legend:this.options,
dataSeries:n,dataPoint:null}):n.name,r=n.legendMarkerColor=n.legendMarkerColor?n.legendMarkerColor:n.markerColor?n.markerColor:n._colorSet[0],s=n.markerSize||"line"!==n.type&&"stepLine"!==n.type&&"spline"!==n.type?0.75*this.lineHeight:0,x=n.legendMarkerBorderColor?n.legendMarkerBorderColor:n.markerBorderColor,u=n.legendMarkerBorderThickness?n.legendMarkerBorderThickness:n.markerBorderThickness?Math.max(1,Math.round(0.2*s)):0,q=this.chart.replaceKeywordsWithValue(q,n.dataPoints[0],n,p),e={markerType:e,
markerColor:r,text:q,textBlock:null,chartType:n.type,markerSize:s,lineColor:n._colorSet[0],dataSeriesIndex:n.index,dataPointIndex:null,markerBorderColor:x,markerBorderThickness:u};h.push(e)}else for(var v=0;v<n.dataPoints.length;v++){var t=n.dataPoints[v],e=t.legendMarkerType?t.legendMarkerType:n.legendMarkerType?n.legendMarkerType:ca.getDefaultLegendMarker(n.type),q=t.legendText?t.legendText:n.legendText?n.legendText:this.itemTextFormatter?this.itemTextFormatter({chart:this.chart,legend:this.options,
dataSeries:n,dataPoint:t}):t.name?t.name:"DataPoint: "+(v+1),r=t.legendMarkerColor?t.legendMarkerColor:n.legendMarkerColor?n.legendMarkerColor:t.color?t.color:n.color?n.color:n._colorSet[v%n._colorSet.length],s=0.75*this.lineHeight,x=t.legendMarkerBorderColor?t.legendMarkerBorderColor:n.legendMarkerBorderColor?n.legendMarkerBorderColor:t.markerBorderColor?t.markerBorderColor:n.markerBorderColor,u=t.legendMarkerBorderThickness?t.legendMarkerBorderThickness:n.legendMarkerBorderThickness?n.legendMarkerBorderThickness:
t.markerBorderThickness||n.markerBorderThickness?Math.max(1,Math.round(0.2*s)):0,q=this.chart.replaceKeywordsWithValue(q,t,n,v),e={markerType:e,markerColor:r,text:q,textBlock:null,chartType:n.type,markerSize:s,dataSeriesIndex:p,dataPointIndex:v,markerBorderColor:x,markerBorderThickness:u};(t.showInLegend||n.showInLegend&&!1!==t.showInLegend)&&h.push(e)}}!0===this.reversed&&h.reverse();if(0<h.length){n=null;r=v=q=t=0;q=null!==this.itemWidth?null!==this.itemMaxWidth?Math.min(this.itemWidth,this.itemMaxWidth,
g):this.itemMaxWidth=Math.min(this.itemWidth,g):null!==this.itemMaxWidth?Math.min(this.itemMaxWidth,g):this.itemMaxWidth=g;s=0===s?0.75*this.lineHeight:s;q-=s+k;for(p=0;p<h.length;p++){e=h[p];if("line"===e.chartType||"spline"===e.chartType||"stepLine"===e.chartType)q-=2*0.1*this.lineHeight;if(!(0>=l||"undefined"===typeof l||0>=q||"undefined"===typeof q)){if("horizontal"===this.orientation){e.textBlock=new V(this.ctx,{x:0,y:0,maxWidth:q,maxHeight:this.itemWrap?l:this.lineHeight,angle:0,text:e.text,
horizontalAlign:"left",fontSize:this.fontSize,fontFamily:this.fontFamily,fontWeight:this.fontWeight,fontColor:this.fontColor,fontStyle:this.fontStyle,textBaseline:"middle"});e.textBlock.measureText();null!==this.itemWidth&&(e.textBlock.width=this.itemWidth-(s+k+("line"===e.chartType||"spline"===e.chartType||"stepLine"===e.chartType?2*0.1*this.lineHeight:0)));if(!n||n.width+Math.round(e.textBlock.width+s+k+(0===n.width?0:this.horizontalSpacing)+("line"===e.chartType||"spline"===e.chartType||"stepLine"===
e.chartType?2*0.1*this.lineHeight:0))>g)n={items:[],width:0},m.push(n),this.height+=v,v=0;v=Math.max(v,e.textBlock.height)}else e.textBlock=new V(this.ctx,{x:0,y:0,maxWidth:q,maxHeight:!0===this.itemWrap?l:1.5*this.fontSize,angle:0,text:e.text,horizontalAlign:"left",fontSize:this.fontSize,fontFamily:this.fontFamily,fontWeight:this.fontWeight,fontColor:this.fontColor,fontStyle:this.fontStyle,textBaseline:"middle"}),e.textBlock.measureText(),null!==this.itemWidth&&(e.textBlock.width=this.itemWidth-
(s+k+("line"===e.chartType||"spline"===e.chartType||"stepLine"===e.chartType?2*0.1*this.lineHeight:0))),this.height<l-this.lineHeight?(n={items:[],width:0},m.push(n)):(n=m[t],t=(t+1)%m.length),this.height+=e.textBlock.height;e.textBlock.x=n.width;e.textBlock.y=0;n.width+=Math.round(e.textBlock.width+s+k+(0===n.width?0:this.horizontalSpacing)+("line"===e.chartType||"spline"===e.chartType||"stepLine"===e.chartType?2*0.1*this.lineHeight:0));n.items.push(e);this.width=Math.max(n.width,this.width);r=e.textBlock.width+
(s+k+("line"===e.chartType||"spline"===e.chartType||"stepLine"===e.chartType?2*0.1*this.lineHeight:0))}}this.itemWidth=r;this.height=!1===this.itemWrap?m.length*this.lineHeight:this.height+v;this.height=Math.min(l,this.height);this.width=Math.min(g,this.width)}"top"===this.verticalAlign?(f="left"===this.horizontalAlign?c.x1:"right"===this.horizontalAlign?c.x2-this.width:c.x1+c.width/2-this.width/2,d=c.y1):"center"===this.verticalAlign?(f="left"===this.horizontalAlign?c.x1:"right"===this.horizontalAlign?
c.x2-this.width:c.x1+c.width/2-this.width/2,d=c.y1+c.height/2-this.height/2):"bottom"===this.verticalAlign&&(f="left"===this.horizontalAlign?c.x1:"right"===this.horizontalAlign?c.x2-this.width:c.x1+c.width/2-this.width/2,d=c.y2-this.height);this.items=h;for(p=0;p<this.items.length;p++)e=h[p],e.id=++this.chart._eventManager.lastObjectId,this.chart._eventManager.objectMap[e.id]={id:e.id,objectType:"legendItem",legendItemIndex:p,dataSeriesIndex:e.dataSeriesIndex,dataPointIndex:e.dataPointIndex};(0<this.borderThickness&&
this.borderColor||this.backgroundColor)&&this.ctx.roundRect(f,d,this.width,this.height,this.cornerRadius,this.borderThickness,this.backgroundColor,this.borderColor);for(p=c=0;p<m.length;p++){n=m[p];for(t=v=0;t<n.items.length;t++){e=n.items[t];r=e.textBlock.x+f+(0===t?0.2*s:this.horizontalSpacing);x=d+c;q=r;this.chart.data[e.dataSeriesIndex].visible||(this.ctx.globalAlpha=0.5);this.ctx.save();this.ctx.beginPath();this.ctx.rect(f,d,g,Math.max(l-l%this.lineHeight,0));this.ctx.clip();if("line"===e.chartType||
"stepLine"===e.chartType||"spline"===e.chartType)this.ctx.strokeStyle=e.lineColor,this.ctx.lineWidth=Math.ceil(this.lineHeight/8),this.ctx.beginPath(),this.ctx.moveTo(r-0.1*this.lineHeight,x+this.lineHeight/2),this.ctx.lineTo(r+0.85*this.lineHeight,x+this.lineHeight/2),this.ctx.stroke(),q-=0.1*this.lineHeight;O.drawMarker(r+s/2,x+this.lineHeight/2,this.ctx,e.markerType,e.markerSize,e.markerColor,e.markerBorderColor,e.markerBorderThickness);e.textBlock.x=r+k+s;if("line"===e.chartType||"stepLine"===
e.chartType||"spline"===e.chartType)e.textBlock.x+=0.1*this.lineHeight;e.textBlock.y=Math.round(x+this.lineHeight/2);e.textBlock.render(!0);this.ctx.restore();v=0<t?Math.max(v,e.textBlock.height):e.textBlock.height;this.chart.data[e.dataSeriesIndex].visible||(this.ctx.globalAlpha=1);r=D(e.id);this.ghostCtx.fillStyle=r;this.ghostCtx.beginPath();this.ghostCtx.fillRect(q,e.textBlock.y-this.lineHeight/2,e.textBlock.x+e.textBlock.width-q,e.textBlock.height);e.x1=this.chart._eventManager.objectMap[e.id].x1=
q;e.y1=this.chart._eventManager.objectMap[e.id].y1=e.textBlock.y-this.lineHeight/2;e.x2=this.chart._eventManager.objectMap[e.id].x2=e.textBlock.x+e.textBlock.width;e.y2=this.chart._eventManager.objectMap[e.id].y2=e.textBlock.y+e.textBlock.height-this.lineHeight/2}c+=v}0<h.length&&a.layoutManager.registerSpace(b,{width:this.width+2+2,height:this.height+5+5});this.bounds={x1:f,y1:d,x2:f+this.width,y2:d+this.height}};T(Da,L);Da.prototype.render=function(){var a=this.chart.layoutManager.getFreeSpace();
this.ctx.fillStyle="red";this.ctx.fillRect(a.x1,a.y1,a.x2,a.y2)};T(ca,L);ca.prototype.getDefaultAxisPlacement=function(){var a=this.type;if("column"===a||"line"===a||"stepLine"===a||"spline"===a||"area"===a||"stepArea"===a||"splineArea"===a||"stackedColumn"===a||"stackedLine"===a||"bubble"===a||"scatter"===a||"stackedArea"===a||"stackedColumn100"===a||"stackedLine100"===a||"stackedArea100"===a||"candlestick"===a||"ohlc"===a||"rangeColumn"===a||"rangeArea"===a||"rangeSplineArea"===a)return"normal";
if("bar"===a||"stackedBar"===a||"stackedBar100"===a||"rangeBar"===a)return"xySwapped";if("pie"===a||"doughnut"===a||"funnel"===a)return"none";window.console.log("Unknown Chart Type: "+a);return null};ca.getDefaultLegendMarker=function(a){if("column"===a||"stackedColumn"===a||"stackedLine"===a||"bar"===a||"stackedBar"===a||"stackedBar100"===a||"bubble"===a||"scatter"===a||"stackedColumn100"===a||"stackedLine100"===a||"stepArea"===a||"candlestick"===a||"ohlc"===a||"rangeColumn"===a||"rangeBar"===a||
"rangeArea"===a||"rangeSplineArea"===a)return"square";if("line"===a||"stepLine"===a||"spline"===a||"pie"===a||"doughnut"===a||"funnel"===a)return"circle";if("area"===a||"splineArea"===a||"stackedArea"===a||"stackedArea100"===a)return"triangle";window.console.log("Unknown Chart Type: "+a);return null};ca.prototype.getDataPointAtX=function(a,c){if(!this.dataPoints||0===this.dataPoints.length)return null;var b={dataPoint:null,distance:Infinity,index:NaN},d=null,f=0,g=0,l=1,k=Infinity,h=0,m=0,p=0;"none"!==
this.chart.plotInfo.axisPlacement&&(this.axisX.logarithmic?(p=Math.log(this.dataPoints[this.dataPoints.length-1].x/this.dataPoints[0].x),p=1<p?Math.min(Math.max((this.dataPoints.length-1)/p*Math.log(a/this.dataPoints[0].x)>>0,0),this.dataPoints.length):0):(p=this.dataPoints[this.dataPoints.length-1].x-this.dataPoints[0].x,p=0<p?Math.min(Math.max((this.dataPoints.length-1)/p*(a-this.dataPoints[0].x)>>0,0),this.dataPoints.length):0));for(;;){g=0<l?p+f:p-f;if(0<=g&&g<this.dataPoints.length){var d=this.dataPoints[g],
n=this.axisX.logarithmic?d.x>a?d.x/a:a/d.x:Math.abs(d.x-a);n<b.distance&&(b.dataPoint=d,b.distance=n,b.index=g);d=n;d<=k?k=d:0<l?h++:m++;if(1E3<h&&1E3<m)break}else if(0>p-f&&p+f>=this.dataPoints.length)break;-1===l?(f++,l=1):l=-1}return c||b.dataPoint.x!==a?c&&null!==b.dataPoint?b:null:b};ca.prototype.getDataPointAtXY=function(a,c,b){if(!this.dataPoints||0===this.dataPoints.length||a<this.chart.plotArea.x1||a>this.chart.plotArea.x2||c<this.chart.plotArea.y1||c>this.chart.plotArea.y2)return null;b=
b||!1;var d=[],f=0,g=0,l=1,k=!1,h=Infinity,m=0,p=0,n=0;"none"!==this.chart.plotInfo.axisPlacement&&(n=(this.chart.axisX[0]?this.chart.axisX[0]:this.chart.axisX2[0]).getXValueAt({x:a,y:c}),this.axisX.logarithmic?(g=Math.log(this.dataPoints[this.dataPoints.length-1].x/this.dataPoints[0].x),n=1<g?Math.min(Math.max((this.dataPoints.length-1)/g*Math.log(n/this.dataPoints[0].x)>>0,0),this.dataPoints.length):0):(g=this.dataPoints[this.dataPoints.length-1].x-this.dataPoints[0].x,n=0<g?Math.min(Math.max((this.dataPoints.length-
1)/g*(n-this.dataPoints[0].x)>>0,0),this.dataPoints.length):0));for(;;){g=0<l?n+f:n-f;if(0<=g&&g<this.dataPoints.length){var e=this.chart._eventManager.objectMap[this.dataPointIds[g]],q=this.dataPoints[g],r=null;if(e){switch(this.type){case "column":case "stackedColumn":case "stackedColumn100":case "bar":case "stackedBar":case "stackedBar100":case "rangeColumn":case "rangeBar":a>=e.x1&&(a<=e.x2&&c>=e.y1&&c<=e.y2)&&(d.push({dataPoint:q,dataPointIndex:g,dataSeries:this,distance:Math.min(Math.abs(e.x1-
a),Math.abs(e.x2-a),Math.abs(e.y1-c),Math.abs(e.y2-c))}),k=!0);break;case "line":case "stepLine":case "spline":case "area":case "stepArea":case "stackedArea":case "stackedArea100":case "splineArea":case "scatter":var s=K("markerSize",q,this)||4,t=b?20:s,r=Math.sqrt(Math.pow(e.x1-a,2)+Math.pow(e.y1-c,2));r<=t&&d.push({dataPoint:q,dataPointIndex:g,dataSeries:this,distance:r});g=Math.abs(e.x1-a);g<=h?h=g:0<l?m++:p++;r<=s/2&&(k=!0);break;case "rangeArea":case "rangeSplineArea":s=K("markerSize",q,this)||
4;t=b?20:s;r=Math.min(Math.sqrt(Math.pow(e.x1-a,2)+Math.pow(e.y1-c,2)),Math.sqrt(Math.pow(e.x1-a,2)+Math.pow(e.y2-c,2)));r<=t&&d.push({dataPoint:q,dataPointIndex:g,dataSeries:this,distance:r});g=Math.abs(e.x1-a);g<=h?h=g:0<l?m++:p++;r<=s/2&&(k=!0);break;case "bubble":s=e.size;r=Math.sqrt(Math.pow(e.x1-a,2)+Math.pow(e.y1-c,2));r<=s/2&&(d.push({dataPoint:q,dataPointIndex:g,dataSeries:this,distance:r}),k=!0);break;case "pie":case "doughnut":s=e.center;t="doughnut"===this.type?e.percentInnerRadius*e.radius:
0;r=Math.sqrt(Math.pow(s.x-a,2)+Math.pow(s.y-c,2));r<e.radius&&r>t&&(r=Math.atan2(c-s.y,a-s.x),0>r&&(r+=2*Math.PI),r=Number(((180*(r/Math.PI)%360+360)%360).toFixed(12)),s=Number(((180*(e.startAngle/Math.PI)%360+360)%360).toFixed(12)),t=Number(((180*(e.endAngle/Math.PI)%360+360)%360).toFixed(12)),0===t&&1<e.endAngle&&(t=360),s>=t&&0!==q.y&&(t+=360,r<s&&(r+=360)),r>s&&r<t&&(d.push({dataPoint:q,dataPointIndex:g,dataSeries:this,distance:0}),k=!0));break;case "candlestick":if(a>=e.x1-e.borderThickness/
2&&a<=e.x2+e.borderThickness/2&&c>=e.y2-e.borderThickness/2&&c<=e.y3+e.borderThickness/2||Math.abs(e.x2-a+e.x1-a)<e.borderThickness&&c>=e.y1&&c<=e.y4)d.push({dataPoint:q,dataPointIndex:g,dataSeries:this,distance:Math.min(Math.abs(e.x1-a),Math.abs(e.x2-a),Math.abs(e.y2-c),Math.abs(e.y3-c))}),k=!0;break;case "ohlc":if(Math.abs(e.x2-a+e.x1-a)<e.borderThickness&&c>=e.y2&&c<=e.y3||a>=e.x1&&a<=(e.x2+e.x1)/2&&c>=e.y1-e.borderThickness/2&&c<=e.y1+e.borderThickness/2||a>=(e.x1+e.x2)/2&&a<=e.x2&&c>=e.y4-e.borderThickness/
2&&c<=e.y4+e.borderThickness/2)d.push({dataPoint:q,dataPointIndex:g,dataSeries:this,distance:Math.min(Math.abs(e.x1-a),Math.abs(e.x2-a),Math.abs(e.y2-c),Math.abs(e.y3-c))}),k=!0}if(k||1E3<m&&1E3<p)break}}else if(0>n-f&&n+f>=this.dataPoints.length)break;-1===l?(f++,l=1):l=-1}a=null;for(c=0;c<d.length;c++)a?d[c].distance<=a.distance&&(a=d[c]):a=d[c];return a};ca.prototype.getMarkerProperties=function(a,c,b,d){var f=this.dataPoints;return{x:c,y:b,ctx:d,type:f[a].markerType?f[a].markerType:this.markerType,
size:f[a].markerSize?f[a].markerSize:this.markerSize,color:f[a].markerColor?f[a].markerColor:this.markerColor?this.markerColor:f[a].color?f[a].color:this.color?this.color:this._colorSet[a%this._colorSet.length],borderColor:f[a].markerBorderColor?f[a].markerBorderColor:this.markerBorderColor?this.markerBorderColor:null,borderThickness:f[a].markerBorderThickness?f[a].markerBorderThickness:this.markerBorderThickness?this.markerBorderThickness:null}};T(B,L);B.prototype.createExtraLabelsForLog=function(a){a=
(a||0)+1;if(!(5<a)){var c=this.logLabelValues[0]||this.intervalStartPosition;if(Math.log(this.range)/Math.log(c/this.viewportMinimum)<this.noTicks-1){for(var b=B.getNiceNumber((c-this.viewportMinimum)/Math.min(Math.max(2,this.noTicks-this.logLabelValues.length),3),!0),d=Math.ceil(this.viewportMinimum/b)*b;d<c;d+=b)d<this.viewportMinimum||this.logLabelValues.push(d);this.logLabelValues.sort(Aa);this.createExtraLabelsForLog(a)}}};B.prototype.createLabels=function(){var a,c,b=0,d=0,f,g=0,l=0,d=0,k=this.interval,
h=0,m,p=0.6*this.chart.height,b=!1;if(this.dataSeries&&0<this.dataSeries.length)for(d=0;d<this.dataSeries.length;d++)"dateTime"===this.dataSeries[d].xValueType&&(b=!0);if("axisX"===this.type&&b&&!this.logarithmic)for(this.intervalStartPosition=this.getLabelStartPoint(new Date(this.viewportMinimum),this.intervalType,this.interval),f=Ia(new Date(this.viewportMaximum),this.interval,this.intervalType),b=this.intervalStartPosition;b<f;Ia(b,k,this.intervalType))a=b.getTime(),a=this.labelFormatter?this.labelFormatter({chart:this.chart,
axis:this.options,value:b,label:this.labels[b]?this.labels[b]:null}):"axisX"===this.type&&this.labels[a]?this.labels[a]:Fa(b,this.valueFormatString,this.chart._cultureInfo),a=new V(this.ctx,{x:0,y:0,maxWidth:g,backgroundColor:this.labelBackgroundColor,borderColor:this.labelBorderColor,borderThickness:this.labelBorderThickness,cornerRadius:this.labelCornerRadius,maxHeight:l,angle:this.labelAngle,text:this.prefix+a+this.suffix,horizontalAlign:"left",fontSize:this.labelFontSize,fontFamily:this.labelFontFamily,
fontWeight:this.labelFontWeight,fontColor:this.labelFontColor,fontStyle:this.labelFontStyle,textBaseline:"middle"}),this._labels.push({position:b.getTime(),textBlock:a,effectiveHeight:null});else{f=this.viewportMaximum;if(this.labels){a=Math.ceil(k);for(var k=Math.ceil(this.intervalStartPosition),n=!1,b=k;b<this.viewportMaximum;b+=a)if(this.labels[b])n=!0;else{n=!1;break}n&&(this.interval=a,this.intervalStartPosition=k)}if(this.logarithmic&&!this.equidistantInterval){this.logLabelValues||(this.logLabelValues=
[],this.createExtraLabelsForLog());for(var e=0;e<this.logLabelValues.length;e++)b=this.logLabelValues[e],b<this.viewportMinimum||(a=this.labelFormatter?this.labelFormatter({chart:this.chart,axis:this.options,value:b,label:this.labels[b]?this.labels[b]:null}):"axisX"===this.type&&this.labels[b]?this.labels[b]:fa(b,this.valueFormatString,this.chart._cultureInfo),a=new V(this.ctx,{x:0,y:0,maxWidth:g,maxHeight:l,angle:this.labelAngle,text:this.prefix+a+this.suffix,backgroundColor:this.labelBackgroundColor,
borderColor:this.labelBorderColor,borderThickness:this.labelBorderThickness,cornerRadius:this.labelCornerRadius,horizontalAlign:"left",fontSize:this.labelFontSize,fontFamily:this.labelFontFamily,fontWeight:this.labelFontWeight,fontColor:this.labelFontColor,fontStyle:this.labelFontStyle,textBaseline:"middle"}),this._labels.push({position:b,textBlock:a,effectiveHeight:null}))}for(b=this.intervalStartPosition;b<=f;b=parseFloat((this.logarithmic&&this.equidistantInterval?b*Math.pow(this.logarithmBase,
this.interval):b+this.interval).toFixed(12)))a=this.labelFormatter?this.labelFormatter({chart:this.chart,axis:this.options,value:b,label:this.labels[b]?this.labels[b]:null}):"axisX"===this.type&&this.labels[b]?this.labels[b]:fa(b,this.valueFormatString,this.chart._cultureInfo),a=new V(this.ctx,{x:0,y:0,maxWidth:g,maxHeight:l,angle:this.labelAngle,text:this.prefix+a+this.suffix,horizontalAlign:"left",backgroundColor:this.labelBackgroundColor,borderColor:this.labelBorderColor,borderThickness:this.labelBorderThickness,
cornerRadius:this.labelCornerRadius,fontSize:this.labelFontSize,fontFamily:this.labelFontFamily,fontWeight:this.labelFontWeight,fontColor:this.labelFontColor,fontStyle:this.labelFontStyle,textBaseline:"middle"}),this._labels.push({position:b,textBlock:a,effectiveHeight:null})}if("bottom"===this._position||"top"===this._position)h=this.logarithmic&&!this.equidistantInterval&&2<=this._labels.length?this.lineCoordinates.width*Math.log(Math.min(this._labels[this._labels.length-1].position/this._labels[this._labels.length-
2].position,this._labels[1].position/this._labels[0].position))/Math.log(this.range):this.lineCoordinates.width/(this.logarithmic&&this.equidistantInterval?Math.log(this.range)/Math.log(this.logarithmBase):Math.abs(this.range))*G[this.intervalType+"Duration"]*this.interval,g="undefined"===typeof this.options.labelMaxWidth?0.5*this.chart.width>>0:this.options.labelMaxWidth,this.chart.panEnabled||(l="undefined"===typeof this.options.labelWrap||this.labelWrap?0.8*this.chart.height>>0:1.5*this.labelFontSize);
else if("left"===this._position||"right"===this._position)h=this.logarithmic&&!this.equidistantInterval&&2<=this._labels.length?this.lineCoordinates.height*Math.log(Math.min(this._labels[this._labels.length-1].position/this._labels[this._labels.length-2].position,this._labels[1].position/this._labels[0].position))/Math.log(this.range):this.lineCoordinates.height/(this.logarithmic&&this.equidistantInterval?Math.log(this.range)/Math.log(this.logarithmBase):Math.abs(this.range))*G[this.intervalType+
"Duration"]*this.interval,this.chart.panEnabled||(g="undefined"===typeof this.options.labelMaxWidth?0.3*this.chart.width>>0:this.options.labelMaxWidth),l="undefined"===typeof this.options.labelWrap||this.labelWrap?0.3*this.chart.height>>0:1.5*this.labelFontSize;for(d=0;d<this._labels.length;d++){a=this._labels[d].textBlock;a.maxWidth=g;a.maxHeight=l;var q=a.measureText();m=q.height}f=[];n=k=0;if(this.labelAutoFit||this.options.labelAutoFit)if(y(this.labelAngle)||(this.labelAngle=(this.labelAngle%
360+360)%360,90<this.labelAngle&&270>this.labelAngle?this.labelAngle-=180:270<=this.labelAngle&&360>=this.labelAngle&&(this.labelAngle-=360)),"bottom"===this._position||"top"===this._position)if(g=0.9*h>>0,n=0,!this.chart.panEnabled&&1<=this._labels.length){this.sessionVariables.labelFontSize=this.labelFontSize;this.sessionVariables.labelMaxWidth=g;this.sessionVariables.labelMaxHeight=l;this.sessionVariables.labelAngle=this.labelAngle;this.sessionVariables.labelWrap=this.labelWrap;for(b=0;b<this._labels.length;b++){a=
this._labels[b].textBlock;for(var r,s=a.text.split(" "),d=0;d<s.length;d++)e=s[d],this.ctx.font=a.fontStyle+" "+a.fontWeight+" "+a.fontSize+"px "+a.fontFamily,e=this.ctx.measureText(e),e.width>n&&(r=b,n=e.width)}b=0;for(b=this.intervalStartPosition<this.viewportMinimum?1:0;b<this._labels.length;b++)if(a=this._labels[b].textBlock,q=a.measureText(),b<this._labels.length-1&&(e=b+1,c=this._labels[e].textBlock,c=c.measureText()),f.push(a.height),this.sessionVariables.labelMaxHeight=Math.max.apply(Math,
f),Math.cos(Math.PI/180*Math.abs(this.labelAngle)),Math.sin(Math.PI/180*Math.abs(this.labelAngle)),d=g*Math.sin(Math.PI/180*Math.abs(this.labelAngle))+(l-a.fontSize/2)*Math.cos(Math.PI/180*Math.abs(this.labelAngle)),y(this.options.labelAngle)&&isNaN(this.options.labelAngle)&&0!==this.options.labelAngle)if(this.sessionVariables.labelMaxHeight=0===this.labelAngle?l:Math.min((d-g*Math.cos(Math.PI/180*Math.abs(this.labelAngle)))/Math.sin(Math.PI/180*Math.abs(this.labelAngle)),d),s=(p-(m+a.fontSize/2)*
Math.cos(Math.PI/180*Math.abs(-25)))/Math.sin(Math.PI/180*Math.abs(-25)),!y(this.options.labelWrap))this.labelWrap?y(this.options.labelMaxWidth)?(this.sessionVariables.labelMaxWidth=Math.min(Math.max(g,n),s),this.sessionVariables.labelWrap=this.labelWrap,q.width+c.width>>0>2*g&&(this.sessionVariables.labelAngle=-25)):(this.sessionVariables.labelWrap=this.labelWrap,this.sessionVariables.labelMaxWidth=this.options.labelMaxWidth,this.sessionVariables.labelAngle=this.sessionVariables.labelMaxWidth>g?
-25:this.sessionVariables.labelAngle):y(this.options.labelMaxWidth)?(this.sessionVariables.labelWrap=this.labelWrap,this.sessionVariables.labelMaxHeight=l,this.sessionVariables.labelMaxWidth=g,q.width+c.width>>0>2*g&&(this.sessionVariables.labelAngle=-25,this.sessionVariables.labelMaxWidth=s)):(this.sessionVariables.labelAngle=this.sessionVariables.labelMaxWidth>g?-25:this.sessionVariables.labelAngle,this.sessionVariables.labelMaxWidth=this.options.labelMaxWidth,this.sessionVariables.labelMaxHeight=
l,this.sessionVariables.labelWrap=this.labelWrap);else{if(y(this.options.labelWrap))if(!y(this.options.labelMaxWidth))this.options.labelMaxWidth<g?(this.sessionVariables.labelMaxWidth=this.options.labelMaxWidth,this.sessionVariables.labelMaxHeight=d):(this.sessionVariables.labelAngle=-25,this.sessionVariables.labelMaxWidth=this.options.labelMaxWidth,this.sessionVariables.labelMaxHeight=l);else if(!y(c))if(d=q.width+c.width>>0,e=this.labelFontSize,n<g)d-2*g>k&&(k=d-2*g,d>=2*g&&d<2.2*g?(this.sessionVariables.labelMaxWidth=
g,y(this.options.labelFontSize)&&12<e&&(e=Math.floor(12/13*e),a.measureText()),this.sessionVariables.labelFontSize=y(this.options.labelFontSize)?e:this.options.labelFontSize,this.sessionVariables.labelAngle=this.labelAngle):d>=2.2*g&&d<2.8*g?(this.sessionVariables.labelAngle=-25,this.sessionVariables.labelMaxWidth=s,this.sessionVariables.labelFontSize=e):d>=2.8*g&&d<3.2*g?(this.sessionVariables.labelMaxWidth=Math.max(g,n),this.sessionVariables.labelWrap=!0,y(this.options.labelFontSize)&&12<this.labelFontSize&&
(this.labelFontSize=Math.floor(12/13*this.labelFontSize),a.measureText()),this.sessionVariables.labelFontSize=y(this.options.labelFontSize)?e:this.options.labelFontSize,this.sessionVariables.labelAngle=this.labelAngle):d>=3.2*g&&d<3.6*g?(this.sessionVariables.labelAngle=-25,this.sessionVariables.labelWrap=!0,this.sessionVariables.labelMaxWidth=s,this.sessionVariables.labelFontSize=this.labelFontSize):d>3.6*g&&d<5*g?(y(this.options.labelFontSize)&&12<e&&(e=Math.floor(12/13*e),a.measureText()),this.sessionVariables.labelFontSize=
y(this.options.labelFontSize)?e:this.options.labelFontSize,this.sessionVariables.labelWrap=!0,this.sessionVariables.labelAngle=-25,this.sessionVariables.labelMaxWidth=s):d>5*g&&(this.sessionVariables.labelWrap=!0,this.sessionVariables.labelMaxWidth=g,this.sessionVariables.labelFontSize=e,this.sessionVariables.labelMaxHeight=l,this.sessionVariables.labelAngle=this.labelAngle));else if(r===b&&(0===r&&n+this._labels[r+1].textBlock.measureText().width-2*g>k||r===this._labels.length-1&&n+this._labels[r-
1].textBlock.measureText().width-2*g>k||0<r&&r<this._labels.length-1&&n+this._labels[r+1].textBlock.measureText().width-2*g>k&&n+this._labels[r-1].textBlock.measureText().width-2*g>k))k=0===r?n+this._labels[r+1].textBlock.measureText().width-2*g:n+this._labels[r-1].textBlock.measureText().width-2*g,this.sessionVariables.labelFontSize=y(this.options.labelFontSize)?e:this.options.labelFontSize,this.sessionVariables.labelWrap=!0,this.sessionVariables.labelAngle=-25,this.sessionVariables.labelMaxWidth=
s;else if(0===k)for(this.sessionVariables.labelFontSize=y(this.options.labelFontSize)?e:this.options.labelFontSize,this.sessionVariables.labelWrap=!0,d=0;d<this._labels.length;d++)a=this._labels[d].textBlock,a.maxWidth=this.sessionVariables.labelMaxWidth=Math.min(Math.max(g,n),s),q=a.measureText(),d<this._labels.length-1&&(e=d+1,c=this._labels[e].textBlock,c.maxWidth=this.sessionVariables.labelMaxWidth=Math.min(Math.max(g,n),s),c=c.measureText(),q.width+c.width>>0>2*g&&(this.sessionVariables.labelAngle=
-25))}else(this.sessionVariables.labelAngle=this.labelAngle,this.sessionVariables.labelMaxHeight=0===this.labelAngle?l:Math.min((d-g*Math.cos(Math.PI/180*Math.abs(this.labelAngle)))/Math.sin(Math.PI/180*Math.abs(this.labelAngle)),d),s=0!=this.labelAngle?(p-(m+a.fontSize/2)*Math.cos(Math.PI/180*Math.abs(this.labelAngle)))/Math.sin(Math.PI/180*Math.abs(this.labelAngle)):g,this.sessionVariables.labelMaxHeight=l=this.labelWrap?(p-s*Math.sin(Math.PI/180*Math.abs(this.labelAngle)))/Math.cos(Math.PI/180*
Math.abs(this.labelAngle)):1.5*this.labelFontSize,y(this.options.labelWrap))?y(this.options.labelWrap)&&(this.labelWrap&&!y(this.options.labelMaxWidth)?(this.sessionVariables.labelWrap=this.labelWrap,this.sessionVariables.labelMaxWidth=this.options.labelMaxWidth?this.options.labelMaxWidth:s,this.sessionVariables.labelMaxHeight=l):(this.sessionVariables.labelAngle=this.labelAngle,this.sessionVariables.labelMaxWidth=s,this.sessionVariables.labelMaxHeight=d<0.9*h?0.9*h:d,this.sessionVariables.labelWrap=
this.labelWrap)):(this.options.labelWrap?(this.sessionVariables.labelWrap=this.labelWrap,this.sessionVariables.labelMaxWidth=this.options.labelMaxWidth?this.options.labelMaxWidth:s):(y(this.options.labelMaxWidth),this.sessionVariables.labelMaxWidth=this.options.labelMaxWidth?this.options.labelMaxWidth:s,this.sessionVariables.labelWrap=this.labelWrap),this.sessionVariables.labelMaxHeight=l);for(d=0;d<this._labels.length;d++)a=this._labels[d].textBlock,a.maxWidth=this.labelMaxWidth=this.sessionVariables.labelMaxWidth,
a.fontSize=this.sessionVariables.labelFontSize,a.angle=this.labelAngle=this.sessionVariables.labelAngle,a.wrap=this.labelWrap=this.sessionVariables.labelWrap,a.maxHeight=this.sessionVariables.labelMaxHeight,a.measureText()}else for(b=0;b<this._labels.length;b++)a=this._labels[b].textBlock,a.maxWidth=this.labelMaxWidth=y(this.options.labelMaxWidth)?this.sessionVariables.labelMaxWidth:this.options.labelMaxWidth,a.fontSize=this.labelFontSize=y(this.options.labelFontSize)?this.sessionVariables.labelFontSize:
this.options.labelFontSize,a.angle=this.labelAngle=y(this.options.labelAngle)?this.sessionVariables.labelAngle:this.labelAngle,a.wrap=this.labelWrap=y(this.options.labelWrap)?this.sessionVariables.labelWrap:this.options.labelWrap,a.maxHeight=this.sessionVariables.labelMaxHeight,a.measureText();else if("left"===this._position||"right"===this._position)if(g=y(this.options.labelMaxWidth)?0.3*this.chart.width>>0:this.options.labelMaxWidth,l="undefined"===typeof this.options.labelWrap||this.labelWrap?
0.3*this.chart.height>>0:1.5*this.labelFontSize,!this.chart.panEnabled&&1<=this._labels.length){this.sessionVariables.labelFontSize=this.labelFontSize;this.sessionVariables.labelMaxWidth=g;this.sessionVariables.labelMaxHeight=l;this.sessionVariables.labelAngle=y(this.sessionVariables.labelAngle)?0:this.sessionVariables.labelAngle;this.sessionVariables.labelWrap=this.labelWrap;for(b=0;b<this._labels.length;b++)(a=this._labels[b].textBlock,q=a.measureText(),b<this._labels.length-1&&(e=b+1,c=this._labels[e].textBlock,
c=c.measureText()),f.push(a.height),this.sessionVariables.labelMaxHeight=Math.max.apply(Math,f),d=g*Math.sin(Math.PI/180*Math.abs(this.labelAngle))+(l-a.fontSize/2)*Math.cos(Math.PI/180*Math.abs(this.labelAngle)),Math.cos(Math.PI/180*Math.abs(this.labelAngle)),Math.sin(Math.PI/180*Math.abs(this.labelAngle)),y(this.options.labelAngle)&&isNaN(this.options.labelAngle)&&0!==this.options.labelAngle)?y(this.options.labelWrap)?y(this.options.labelWrap)&&(y(this.options.labelMaxWidth)?y(c)||(h=q.height+c.height>>
0,h-2*l>n&&(n=h-2*l,h>=2*l&&h<2.4*l?(y(this.options.labelFontSize)&&12<this.labelFontSize&&(this.labelFontSize=Math.floor(12/13*this.labelFontSize),a.measureText()),this.sessionVariables.labelMaxHeight=l,this.sessionVariables.labelFontSize=y(this.options.labelFontSize)?this.labelFontSize:this.options.labelFontSize):h>=2.4*l&&h<2.8*l?(this.sessionVariables.labelMaxHeight=d,this.sessionVariables.labelFontSize=this.labelFontSize,this.sessionVariables.labelWrap=!0):h>=2.8*l&&h<3.2*l?(this.sessionVariables.labelMaxHeight=
l,this.sessionVariables.labelWrap=!0,y(this.options.labelFontSize)&&12<this.labelFontSize&&(this.labelFontSize=Math.floor(12/13*this.labelFontSize),a.measureText()),this.sessionVariables.labelFontSize=y(this.options.labelFontSize)?this.labelFontSize:this.options.labelFontSize,this.sessionVariables.labelAngle=y(this.sessionVariables.labelAngle)?0:this.sessionVariables.labelAngle):h>=3.2*l&&h<3.6*l?(this.sessionVariables.labelMaxHeight=d,this.sessionVariables.labelWrap=!0,this.sessionVariables.labelFontSize=
this.labelFontSize):h>3.6*l&&h<10*l?(y(this.options.labelFontSize)&&12<this.labelFontSize&&(this.labelFontSize=Math.floor(12/13*this.labelFontSize),a.measureText()),this.sessionVariables.labelFontSize=y(this.options.labelFontSize)?this.labelFontSize:this.options.labelFontSize,this.sessionVariables.labelMaxWidth=g,this.sessionVariables.labelMaxHeight=l,this.sessionVariables.labelAngle=y(this.sessionVariables.labelAngle)?0:this.sessionVariables.labelAngle):h>10*l&&h<50*l&&(y(this.options.labelFontSize)&&
12<this.labelFontSize&&(this.labelFontSize=Math.floor(12/13*this.labelFontSize),a.measureText()),this.sessionVariables.labelFontSize=y(this.options.labelFontSize)?this.labelFontSize:this.options.labelFontSize,this.sessionVariables.labelMaxHeight=l,this.sessionVariables.labelMaxWidth=g,this.sessionVariables.labelAngle=y(this.sessionVariables.labelAngle)?0:this.sessionVariables.labelAngle))):(this.sessionVariables.labelMaxHeight=l,this.sessionVariables.labelMaxWidth=this.options.labelMaxWidth?this.options.labelMaxWidth:
this.sessionVariables.labelMaxWidth)):(this.sessionVariables.labelMaxWidth=this.labelWrap?this.options.labelMaxWidth?this.options.labelMaxWidth:this.sessionVariables.labelMaxWidth:this.labelMaxWidth?this.options.labelMaxWidth?this.options.labelMaxWidth:this.sessionVariables.labelMaxWidth:g,this.sessionVariables.labelMaxHeight=l):(this.sessionVariables.labelAngle=this.labelAngle,this.sessionVariables.labelMaxWidth=0===this.labelAngle?g:Math.min((d-l*Math.sin(Math.PI/180*Math.abs(this.labelAngle)))/
Math.cos(Math.PI/180*Math.abs(this.labelAngle)),l),y(this.options.labelWrap))?y(this.options.labelWrap)&&(this.labelWrap&&!y(this.options.labelMaxWidth)?(this.sessionVariables.labelMaxWidth=this.options.labelMaxWidth?this.options.labelMaxWidth>this.options.labelMaxWidth:this.sessionVariables.labelMaxWidth,this.sessionVariables.labelWrap=this.labelWrap,this.sessionVariables.labelMaxHeight=d):(this.sessionVariables.labelMaxWidth=this.options.labelMaxWidth?this.options.labelMaxWidth:g,this.sessionVariables.labelMaxHeight=
0===this.labelAngle?l:d,y(this.options.labelMaxWidth)&&(this.sessionVariables.labelAngle=this.labelAngle))):this.options.labelWrap?(this.sessionVariables.labelMaxHeight=0===this.labelAngle?l:d,this.sessionVariables.labelWrap=this.labelWrap,this.sessionVariables.labelMaxWidth=g):(this.sessionVariables.labelMaxHeight=l,y(this.options.labelMaxWidth),this.sessionVariables.labelMaxWidth=this.options.labelMaxWidth?this.options.labelMaxWidth:this.sessionVariables.labelMaxWidth,this.sessionVariables.labelWrap=
this.labelWrap);for(d=0;d<this._labels.length;d++)a=this._labels[d].textBlock,a.maxWidth=this.labelMaxWidth=this.sessionVariables.labelMaxWidth,a.fontSize=this.labelFontSize=this.sessionVariables.labelFontSize,a.angle=this.labelAngle=this.sessionVariables.labelAngle,a.wrap=this.labelWrap=this.sessionVariables.labelWrap,a.maxHeight=this.sessionVariables.labelMaxHeight,a.measureText()}else for(b=0;b<this._labels.length;b++)a=this._labels[b].textBlock,a.maxWidth=this.labelMaxWidth=y(this.options.labelMaxWidth)?
this.sessionVariables.labelMaxWidth:this.options.labelMaxWidth,a.fontSize=this.labelFontSize=y(this.options.labelFontSize)?this.sessionVariables.labelFontSize:this.options.labelFontSize,a.angle=this.labelAngle=y(this.options.labelAngle)?this.sessionVariables.labelAngle:this.labelAngle,a.wrap=this.labelWrap=y(this.options.labelWrap)?this.sessionVariables.labelWrap:this.options.labelWrap,a.maxHeight=this.sessionVariables.labelMaxHeight,a.measureText();for(b=0;b<this.stripLines.length;b++){var g=this.stripLines[b],
x;if("outside"===g.labelPlacement){l=this.sessionVariables.labelMaxWidth;if("bottom"===this._position||"top"===this._position)x="undefined"===typeof g.options.labelWrap?this.sessionVariables.labelMaxHeight:g.labelWrap?0.8*this.chart.height>>0:1.5*this.labelFontSize;if("left"===this._position||"right"===this._position)x="undefined"===typeof g.options.labelWrap?this.sessionVariables.labelMaxHeight:g.labelWrap?0.8*this.chart.width>>0:1.5*this.labelFontSize;c=y(g.options.labelBackgroundColor)?"#EEEEEE":
g.options.labelBackgroundColor}else l="bottom"===this._position||"top"===this._position?0.9*this.chart.width>>0:0.9*this.chart.height>>0,x="undefined"===typeof g.options.labelWrap||g.labelWrap?"bottom"===this._position||"top"===this._position?0.8*this.chart.width>>0:0.8*this.chart.height>>0:1.5*this.labelFontSize,c=y(g.options.labelBackgroundColor)?y(g.startValue)&&0!==g.startValue?t?"transparent":null:"#EEEEEE":g.options.labelBackgroundColor;a=new V(this.ctx,{x:0,y:0,backgroundColor:c,borderColor:g.labelBorderColor,
borderThickness:g.labelBorderThickness,cornerRadius:g.labelCornerRadius,maxWidth:g.options.labelMaxWidth?g.options.labelMaxWidth:l,maxHeight:x,angle:this.labelAngle,text:g.labelFormatter?g.labelFormatter({chart:this.chart,axis:this,stripLine:g}):g.label,horizontalAlign:"left",fontSize:"outside"===g.labelPlacement?g.options.labelFontSize?g.options.labelFontSize:this.labelFontSize:g.labelFontSize,fontFamily:"outside"===g.labelPlacement?g.options.labelFontFamily?g.options.labelFontFamily:this.labelFontFamily:
g.labelFontFamily,fontWeight:"outside"===g.labelPlacement?g.options.fontWeight?g.options.fontWeight:this.fontWeight:g.fontWeight,fontColor:g.options.labelFontColor||g.color,fontStyle:"outside"===g.labelPlacement?g.options.fontStyle?g.options.fontStyle:this.fontWeight:g.fontStyle,textBaseline:"middle"});this._stripLineLabels.push({position:g.value,textBlock:a,effectiveHeight:null,stripLine:g})}};B.prototype.createLabelsAndCalculateWidth=function(){var a=0,c=0;this._labels=[];this._stripLineLabels=
[];if("left"===this._position||"right"===this._position){this.createLabels();for(c=0;c<this._labels.length;c++){var b=this._labels[c].textBlock,d=b.measureText(),f=0,f=0===this.labelAngle?d.width:d.width*Math.cos(Math.PI/180*Math.abs(this.labelAngle))+(d.height-b.fontSize/2)*Math.sin(Math.PI/180*Math.abs(this.labelAngle));a<f&&(a=f);this._labels[c].effectiveWidth=f}for(c=0;c<this._stripLineLabels.length;c++)"outside"===this._stripLineLabels[c].stripLine.labelPlacement&&(this._stripLineLabels[c].stripLine.value>
this.viewportMinimum&&this._stripLineLabels[c].stripLine.value<this.viewportMaximum)&&(b=this._stripLineLabels[c].textBlock,d=b.measureText(),f=0===this.labelAngle?d.width:d.width*Math.cos(Math.PI/180*Math.abs(this.labelAngle))+(d.height-b.fontSize/2)*Math.sin(Math.PI/180*Math.abs(this.labelAngle)),a<f&&(a=f),this._stripLineLabels[c].effectiveWidth=f)}return(this.title?this._titleTextBlock.measureText().height+2:0)+a+this.tickLength+5};B.prototype.createLabelsAndCalculateHeight=function(){var a=0;
this._labels=[];this._stripLineLabels=[];var c,b=0;this.createLabels();if("bottom"===this._position||"top"===this._position){for(b=0;b<this._labels.length;b++){c=this._labels[b].textBlock;var d=c.measureText(),f=0,f=0===this.labelAngle?d.height:d.width*Math.sin(Math.PI/180*Math.abs(this.labelAngle))+(d.height-c.fontSize/2)*Math.cos(Math.PI/180*Math.abs(this.labelAngle));a<f&&(a=f);this._labels[b].effectiveHeight=f}for(b=0;b<this._stripLineLabels.length;b++)"outside"===this._stripLineLabels[b].stripLine.labelPlacement&&
(c=this._stripLineLabels[b].textBlock,d=c.measureText(),f=0===this.labelAngle?d.height:d.width*Math.sin(Math.PI/180*Math.abs(this.labelAngle))+(d.height-c.fontSize/2)*Math.cos(Math.PI/180*Math.abs(this.labelAngle)),a<f&&(a=f),this._stripLineLabels[b].effectiveHeight=f)}return(this.title?this._titleTextBlock.measureText().height+2:0)+a+this.tickLength+5};B.setLayoutAndRender=function(a,c,b,d,f,g){var l,k,h,m,p=a[0]?a[0].chart:c[0].chart,n=p.ctx;if(a&&0<a.length)for(var e=0;e<a.length;e++)a[e]&&a[e].calculateAxisParameters();
if(c&&0<c.length)for(e=0;e<c.length;e++)c[e].calculateAxisParameters();if(b&&0<b.length)for(e=0;e<b.length;e++)b[e].calculateAxisParameters();if(d&&0<d.length)for(e=0;e<d.length;e++)d[e].calculateAxisParameters();var q=0,r=0,s=0,t=0,u=0,v=0,z=0,w,A,B=k=0,D,E,F,G;D=E=F=G=!1;if(a&&0<a.length)for(e=0;e<a.length;e++)a[e]&&a[e].title&&(a[e]._titleTextBlock=new V(a[e].ctx,{text:a[e].title,horizontalAlign:"center",fontSize:a[e].titleFontSize,fontFamily:a[e].titleFontFamily,fontWeight:a[e].titleFontWeight,
fontColor:a[e].titleFontColor,fontStyle:a[e].titleFontStyle,borderColor:a[e].titleBorderColor,borderThickness:a[e].titleBorderThickness,backgroundColor:a[e].titleBackgroundColor,cornerRadius:a[e].titleCornerRadius,textBaseline:"top"}));if(c&&0<c.length)for(e=0;e<c.length;e++)c[e]&&c[e].title&&(c[e]._titleTextBlock=new V(c[e].ctx,{text:c[e].title,horizontalAlign:"center",fontSize:c[e].titleFontSize,fontFamily:c[e].titleFontFamily,fontWeight:c[e].titleFontWeight,fontColor:c[e].titleFontColor,fontStyle:c[e].titleFontStyle,
borderColor:c[e].titleBorderColor,borderThickness:c[e].titleBorderThickness,backgroundColor:c[e].titleBackgroundColor,cornerRadius:c[e].titleCornerRadius,textBaseline:"top"}));if(b&&0<b.length)for(e=0;e<b.length;e++)b[e]&&b[e].title&&(b[e]._titleTextBlock=new V(b[e].ctx,{text:b[e].title,horizontalAlign:"center",fontSize:b[e].titleFontSize,fontFamily:b[e].titleFontFamily,fontWeight:b[e].titleFontWeight,fontColor:b[e].titleFontColor,fontStyle:b[e].titleFontStyle,borderColor:b[e].titleBorderColor,borderThickness:b[e].titleBorderThickness,
backgroundColor:b[e].titleBackgroundColor,cornerRadius:b[e].titleCornerRadius,textBaseline:"top"}));if(d&&0<d.length)for(e=0;e<d.length;e++)d[e]&&d[e].title&&(d[e]._titleTextBlock=new V(d[e].ctx,{text:d[e].title,horizontalAlign:"center",fontSize:d[e].titleFontSize,fontFamily:d[e].titleFontFamily,fontWeight:d[e].titleFontWeight,fontColor:d[e].titleFontColor,fontStyle:d[e].titleFontStyle,borderColor:d[e].titleBorderColor,borderThickness:d[e].titleBorderThickness,backgroundColor:d[e].titleBackgroundColor,
cornerRadius:d[e].titleCornerRadius,textBaseline:"top"}));if("normal"===f){var t=[],u=[],v=[],z=[],H=[],I=[],L=[],J=[];if(a&&0<a.length)for(e=0;e<a.length;e++)a[e]&&a[e].title&&(a[e]._titleTextBlock.maxWidth=a[e].titleMaxWidth||g.width,a[e]._titleTextBlock.maxHeight=a[e].titleWrap?0.8*g.height:1.5*a[e].titleFontSize,a[e]._titleTextBlock.angle=0);if(c&&0<c.length)for(e=0;e<c[e].length;e++)c[e]&&c[e].title&&(c[e]._titleTextBlock.maxWidth=c[e].titleMaxWidth||g.width,c[e]._titleTextBlock.maxHeight=c[e].titleWrap?
0.8*g.height:1.5*c[e].titleFontSize,c[e]._titleTextBlock.angle=0);if(b&&0<b.length)for(e=0;e<b.length;e++)b[e]&&b[e].title&&(b[e]._titleTextBlock.maxWidth=b[e].titleMaxWidth||g.height,b[e]._titleTextBlock.maxHeight=b[e].titleWrap?0.8*g.width:1.5*b[e].titleFontSize,b[e]._titleTextBlock.angle=-90);if(d&&0<d.length)for(e=0;e<d.length;e++)d[e]&&d[e].title&&(d[e]._titleTextBlock.maxWidth=d[e].titleMaxWidth||g.height,d[e]._titleTextBlock.maxHeight=d[e].titleWrap?0.8*g.width:1.5*d[e].titleFontSize,d[e]._titleTextBlock.angle=
90);for(;4>q;){var N=0,Q=0,O=0,P=0,K=f=0,C=0,R=0,Y=0,U=0,T=0,S=0;if(b&&0<b.length)for(v=[],e=T=0;e<b.length;e++)v.push(Math.ceil(b[e]?b[e].createLabelsAndCalculateWidth():0)),T+=v[e],C+=b[e]?b[e].margin:0;else v.push(Math.ceil(b[0]?b[0].createLabelsAndCalculateWidth():0));L.push(v);if(d&&0<d.length)for(z=[],e=S=0;e<d.length;e++)z.push(Math.ceil(d[e]?d[e].createLabelsAndCalculateWidth():0)),S+=z[e],R+=d[e]?d[e].margin:0;else z.push(Math.ceil(d[0]?d[0].createLabelsAndCalculateWidth():0));J.push(z);
l=Math.round(g.x1+T+C);h=Math.round(g.x2-S-R>p.width-10?p.width-10:g.x2-S-R);if(a&&0<a.length)for(t=[],e=Y=0;e<a.length;e++)a[e]&&(a[e].lineCoordinates={}),a[e].lineCoordinates.width=Math.abs(h-l),a[e].title&&(a[e]._titleTextBlock.maxWidth=0<a[e].titleMaxWidth&&a[e].titleMaxWidth<a[e].lineCoordinates.width?a[e].titleMaxWidth:a[e].lineCoordinates.width),t.push(Math.ceil(a[e]?a[e].createLabelsAndCalculateHeight():0)),Y+=t[e],f+=a[e]?a[e].margin:0;else t.push(Math.ceil(a[0]?a[0].createLabelsAndCalculateHeight():
0));H.push(t);if(c&&0<c.length)for(u=[],e=U=0;e<c.length;e++)c[e]&&(c[e].lineCoordinates={}),c[e].lineCoordinates.width=Math.abs(h-l),c[e].title&&(c[e]._titleTextBlock.maxWidth=0<c[e].titleMaxWidth&&c[e].titleMaxWidth<c[e].lineCoordinates.width?c[e].titleMaxWidth:c[e].lineCoordinates.width),u.push(Math.ceil(c[e]?c[e].createLabelsAndCalculateHeight():0)),U+=u[e],K+=c[e]?c[e].margin:0;else u.push(Math.ceil(c[0]?c[0].createLabelsAndCalculateHeight():0));I.push(u);if(a&&0<a.length)for(e=0;e<a.length;e++)a[e]&&
(a[e].lineCoordinates.x1=l,h=Math.round(g.x2-S-R>p.width-10?p.width-10:g.x2-S-R),a[e]._labels&&1<a[e]._labels.length&&(k=m=0,m=a[e]._labels[1],k="dateTime"===a[e].chart.plotInfo.axisXValueType?a[e]._labels[a[e]._labels.length-2]:a[e]._labels[a[e]._labels.length-1],r=m.textBlock.width*Math.cos(Math.PI/180*Math.abs(m.textBlock.angle))+(m.textBlock.height-k.textBlock.fontSize/2)*Math.sin(Math.PI/180*Math.abs(m.textBlock.angle)),s=k.textBlock.width*Math.cos(Math.PI/180*Math.abs(k.textBlock.angle))+(k.textBlock.height-
k.textBlock.fontSize/2)*Math.sin(Math.PI/180*Math.abs(k.textBlock.angle))),a[e]&&(a[e].labelAutoFit&&!y(w)&&!y(A))&&(k=0,0<a[e].labelAngle?A+s>h&&(k+=0<a[e].labelAngle?A+s-h-S:0):0>a[e].labelAngle?w-r<l&&w-r<a[e].viewportMinimum&&(B=l-(C+a[e].tickLength+v+w-r+a[e].labelFontSize/2)):0===a[e].labelAngle&&(A+s>h&&(k=A+s/2-h-S),w-r<l&&w-r<a[e].viewportMinimum&&(B=l-C-a[e].tickLength-v-w+r/2)),a[e].viewportMaximum===a[e].maximum&&a[e].viewportMinimum===a[e].minimum&&0<a[e].labelAngle&&0<k?h-=k:a[e].viewportMaximum===
a[e].maximum&&a[e].viewportMinimum===a[e].minimum&&0>a[e].labelAngle&&0<B?l+=B:a[e].viewportMaximum===a[e].maximum&&a[e].viewportMinimum===a[e].minimum&&0===a[e].labelAngle&&(0<B&&(l+=B),0<k&&(h-=k))),p.panEnabled?Y=p.sessionVariables.axisX.height:p.sessionVariables.axisX.height=Y,k=Math.round(g.y2-Y-f+N),m=Math.round(g.y2),a[e].lineCoordinates.x2=h,a[e].lineCoordinates.width=h-l,a[e].lineCoordinates.y1=k,a[e].lineCoordinates.y2=k,a[e].bounds={x1:l,y1:k,x2:h,y2:m-(Y+f-t[e]-N),width:h-l,height:m-k}),
N+=t[e]+a[e].margin;if(c&&0<c.length)for(e=0;e<c.length;e++)c[e].lineCoordinates.x1=Math.round(g.x1+T+C),c[e].lineCoordinates.x2=Math.round(g.x2-S-R>p.width-10?p.width-10:g.x2-S-R),c[e].lineCoordinates.width=Math.abs(h-l),c[e]._labels&&1<c[e]._labels.length&&(m=c[e]._labels[1],k="dateTime"===c[e].chart.plotInfo.axisXValueType?c[e]._labels[c[e]._labels.length-2]:c[e]._labels[c[e]._labels.length-1],r=m.textBlock.width*Math.cos(Math.PI/180*Math.abs(m.textBlock.angle))+(m.textBlock.height-k.textBlock.fontSize/
2)*Math.sin(Math.PI/180*Math.abs(m.textBlock.angle)),s=k.textBlock.width*Math.cos(Math.PI/180*Math.abs(k.textBlock.angle))+(k.textBlock.height-k.textBlock.fontSize/2)*Math.sin(Math.PI/180*Math.abs(k.textBlock.angle))),p.panEnabled?U=p.sessionVariables.axisX2.height:p.sessionVariables.axisX2.height=U,k=Math.round(g.y1),m=Math.round(g.y2+c[e].margin),c[e].lineCoordinates.y1=k+U+K-Q,c[e].lineCoordinates.y2=k,c[e].bounds={x1:l,y1:k+(U+K-u[e]-Q),x2:h,y2:m,width:h-l,height:m-k},Q+=u[e]+c[e].margin;if(b&&
0<b.length)for(e=0;e<b.length;e++)C=10,b[e]&&(l=Math.round(a[0]?a[0].lineCoordinates.x1:c[0].lineCoordinates.x1),C=b[e]._labels&&0<b[e]._labels.length?b[e]._labels[b[e]._labels.length-1].textBlock.height/2:10,k=Math.round(g.y1+U+K<Math.max(C,10)?Math.max(C,10):g.y1+U+K),h=Math.round(a[0]?a[0].lineCoordinates.x1:c[0].lineCoordinates.x1),C=0<a.length?0:b[e]._labels&&0<b[e]._labels.length?b[e]._labels[0].textBlock.height/2:10,m=Math.round(g.y2-Y-f-C),b[e].lineCoordinates={x1:h-O,y1:k,x2:h-O,y2:m,height:Math.abs(m-
k)},b[e].bounds={x1:l-(v[e]+O),y1:k,x2:h,y2:m,width:h-l,height:m-k},b[e].title&&(b[e]._titleTextBlock.maxWidth=0<b[e].titleMaxWidth&&b[e].titleMaxWidth<b[e].lineCoordinates.height?b[e].titleMaxWidth:b[e].lineCoordinates.height),O+=v[e]+b[e].margin);if(d&&0<d.length)for(e=0;e<d.length;e++)d[e]&&(l=Math.round(a[0]?a[0].lineCoordinates.x2:c[0].lineCoordinates.x2),h=Math.round(l),C=d[e]._labels&&0<d[e]._labels.length?d[e]._labels[d[e]._labels.length-1].textBlock.height/2:0,k=Math.round(g.y1+U+K<Math.max(C,
10)?Math.max(C,10):g.y1+U+K),C=0<a.length?0:d[e]._labels&&0<d[e]._labels.length?d[e]._labels[0].textBlock.height/2:0,m=Math.round(g.y2-(Y+f+C)),d[e].lineCoordinates={x1:l+P,y1:k,x2:l+P,y2:m,height:Math.abs(m-k)},d[e].bounds={x1:l,y1:k,x2:h+(z[e]+P),y2:m,width:h-l,height:m-k},d[e].title&&(d[e]._titleTextBlock.maxWidth=0<d[e].titleMaxWidth&&d[e].titleMaxWidth<d[e].lineCoordinates.height?d[e].titleMaxWidth:d[e].lineCoordinates.height),P+=z[e]+d[e].margin);if(a&&0<a.length)for(e=0;e<a.length;e++)a[e]&&
(a[e].calculateValueToPixelConversionParameters(),a[e]._labels&&1<a[e]._labels.length&&(w=(a[e].logarithmic?Math.log(a[e]._labels[1].position/a[e].viewportMinimum)/a[e].conversionParameters.lnLogarithmBase:a[e]._labels[1].position-a[e].viewportMinimum)*Math.abs(a[e].conversionParameters.pixelPerUnit)+a[e].lineCoordinates.x1,A="dateTime"===a[e].chart.plotInfo.axisXValueType?(a[e].logarithmic?Math.log(a[e]._labels[a[e]._labels.length-2].position/a[e].viewportMinimum)/a[e].conversionParameters.lnLogarithmBase:
a[e]._labels[a[e]._labels.length-2].position-a[e].viewportMinimum)*Math.abs(a[e].conversionParameters.pixelPerUnit)+a[e].lineCoordinates.x1:(a[e].logarithmic?Math.log(a[e]._labels[a[e]._labels.length-1].position/a[e].viewportMinimum)/a[e].conversionParameters.lnLogarithmBase:a[e]._labels[a[e]._labels.length-1].position-a[e].viewportMinimum)*Math.abs(a[e].conversionParameters.pixelPerUnit)+a[e].lineCoordinates.x1));if(c&&0<c.length)for(e=0;e<c.length;e++)c[e].calculateValueToPixelConversionParameters(),
c[e]._labels&&1<c[e]._labels.length&&(w=(c[e].logarithmic?Math.log(c[e]._labels[1].position/c[e].viewportMinimum)/c[e].conversionParameters.lnLogarithmBase:c[e]._labels[1].position-c[e].viewportMinimum)*Math.abs(c[e].conversionParameters.pixelPerUnit)+c[e].lineCoordinates.x1,A="dateTime"===c[e].chart.plotInfo.axisXValueType?(c[e].logarithmic?Math.log(c[e]._labels[c[e]._labels.length-2].position/c[e].viewportMinimum)/c[e].conversionParameters.lnLogarithmBase:c[e]._labels[c[e]._labels.length-2].position-
c[e].viewportMinimum)*Math.abs(c[e].conversionParameters.pixelPerUnit)+c[e].lineCoordinates.x1:(c[e].logarithmic?Math.log(c[e]._labels[c[e]._labels.length-1].position/c[e].viewportMinimum)/c[e].conversionParameters.lnLogarithmBase:c[e]._labels[c[e]._labels.length-1].position-c[e].viewportMinimum)*Math.abs(c[e].conversionParameters.pixelPerUnit)+c[e].lineCoordinates.x1);if(b&&0<b.length)for(e=0;e<b.length;e++)b[e].calculateValueToPixelConversionParameters();if(d&&0<d.length)for(e=0;e<d.length;e++)d[e].calculateValueToPixelConversionParameters();
if(0<q){if(a&&0<a.length)for(e=0;e<a.length;e++)D=H[q-1][e]===H[q][e]?!0:!1;else D=!0;if(c&&0<c.length)for(e=0;e<c.length;e++)E=I[q-1][e]===I[q][e]?!0:!1;else E=!0;if(b&&0<b.length)for(e=0;e<b.length;e++)F=L[q-1][e]===L[q][e]?!0:!1;else F=!0;if(d&&0<d.length)for(e=0;e<d.length;e++)G=J[q-1][e]===J[q][e]?!0:!1;else G=!0}if(D&&E&&F&&G)break;q++}n.save();n.beginPath();a[0]&&n.rect(5,a[0].bounds.y1,a[0].chart.width-10,a[0].bounds.height);c[0]&&n.rect(5,c[c.length-1].bounds.y1,c[0].chart.width-10,c[0].bounds.height);
n.clip();if(a&&0<a.length)for(e=0;e<a.length;e++)a[e].renderLabelsTicksAndTitle();if(c&&0<c.length)for(e=0;e<c.length;e++)c[e].renderLabelsTicksAndTitle();n.restore();if(b&&0<b.length)for(e=0;e<b.length;e++)b[e].renderLabelsTicksAndTitle();if(d&&0<d.length)for(e=0;e<d.length;e++)d[e].renderLabelsTicksAndTitle()}else{w=[];A=[];B=[];r=[];s=[];H=[];I=[];L=[];if(a&&0<a.length)for(e=0;e<a.length;e++)a[e]&&a[e].title&&(a[e]._titleTextBlock.maxWidth=a[e].titleMaxWidth||g.width,a[e]._titleTextBlock.maxHeight=
a[e].titleWrap?0.8*g.height:1.5*a[e].titleFontSize,a[e]._titleTextBlock.angle=-90);if(c&&0<c.length)for(e=0;e<c.length;e++)c[e]&&c[e].title&&(c[e]._titleTextBlock.maxWidth=c[e].titleMaxWidth||g.width,c[e]._titleTextBlock.maxHeight=c[e].titleWrap?0.8*g.height:1.5*c[e].titleFontSize,c[e]._titleTextBlock.angle=90);if(b&&0<b.length)for(e=0;e<b.length;e++)b[e]&&b[e].title&&(b[e]._titleTextBlock.maxWidth=b[e].titleMaxWidth||g.width,b[e]._titleTextBlock.maxHeight=b[e].titleWrap?0.8*g.height:1.5*b[e].titleFontSize,
b[e]._titleTextBlock.angle=0);if(d&&0<d.length)for(e=0;e<d.length;e++)d[e]&&d[e].title&&(d[e]._titleTextBlock.maxWidth=d[e].titleMaxWidth||g.width,d[e]._titleTextBlock.maxHeight=d[e].titleWrap?0.8*g.height:1.5*d[e].titleFontSize,d[e]._titleTextBlock.angle=0);for(;4>q;){U=Y=T=P=R=C=K=f=O=J=Q=N=0;if(a&&0<a.length)for(B=[],e=Y=0;e<a.length;e++)B.push(Math.ceil(a[e]?a[e].createLabelsAndCalculateWidth():0)),Y+=B[e],f+=a[e]?a[e].margin:0;else B.push(Math.ceil(a[0]?a[0].createLabelsAndCalculateWidth():0));
I.push(B);if(c&&0<c.length)for(r=[],e=U=0;e<c.length;e++)r.push(Math.ceil(c[e]?c[e].createLabelsAndCalculateWidth():0)),U+=r[e],K+=c[e]?c[e].margin:0;else r.push(Math.ceil(c[0]?c[0].createLabelsAndCalculateWidth():0));L.push(r);if(b&&0<b.length)for(e=0;e<b.length;e++)b[e].lineCoordinates={},l=Math.round(g.x1+Y+f),h=Math.round(g.x2-U-K>p.width-10?p.width-10:g.x2-U-K),b[e].labelAutoFit&&!y(t)&&(0<!a.length&&(l=0>b[e].labelAngle?Math.max(l,t):0===b[e].labelAngle?Math.max(l,t/2):l),0<!c.length&&(h=0<
b[e].labelAngle?h-u/2:0===b[e].labelAngle?h-u/2:h)),b[e].lineCoordinates.x1=l,b[e].lineCoordinates.x2=h,b[e].lineCoordinates.width=Math.abs(h-l),b[e].title&&(b[e]._titleTextBlock.maxWidth=0<b[e].titleMaxWidth&&b[e].titleMaxWidth<b[e].lineCoordinates.width?b[e].titleMaxWidth:b[e].lineCoordinates.width);if(d&&0<d.length)for(e=0;e<d.length;e++)d[e].lineCoordinates={},l=Math.round(g.x1+Y+f),h=Math.round(g.x2-U-K>d[e].chart.width-10?d[e].chart.width-10:g.x2-U-K),d[e]&&d[e].labelAutoFit&&!y(v)&&(0<!a.length&&
(l=0<d[e].labelAngle?Math.max(l,v):0===d[e].labelAngle?Math.max(l,v/2):l),0<!c.length&&(h-=z/2)),d[e].lineCoordinates.x1=l,d[e].lineCoordinates.x2=h,d[e].lineCoordinates.width=Math.abs(h-l),d[e].title&&(d[e]._titleTextBlock.maxWidth=0<d[e].titleMaxWidth&&d[e].titleMaxWidth<d[e].lineCoordinates.width?d[e].titleMaxWidth:d[e].lineCoordinates.width);if(b&&0<b.length)for(w=[],e=P=0;e<b.length;e++)w.push(Math.ceil(b[e]?b[e].createLabelsAndCalculateHeight():0)),P+=w[e]+b[e].margin,C+=b[e].margin;else w.push(Math.ceil(b[0]?
b[0].createLabelsAndCalculateHeight():0));s.push(w);if(d&&0<d.length)for(A=[],e=T=0;e<d.length;e++)A.push(Math.ceil(d[e]?d[e].createLabelsAndCalculateHeight():0)),T+=A[e],R+=d[e].margin;else A.push(Math.ceil(d[0]?d[0].createLabelsAndCalculateHeight():0));H.push(A);if(b&&0<b.length)for(e=0;e<b.length;e++)0<b[e]._labels.length&&(m=b[e]._labels[0],k=b[e]._labels[b[e]._labels.length-1],t=m.textBlock.width*Math.cos(Math.PI/180*Math.abs(m.textBlock.angle))+(m.textBlock.height-k.textBlock.fontSize/2)*Math.sin(Math.PI/
180*Math.abs(m.textBlock.angle)),u=k.textBlock.width*Math.cos(Math.PI/180*Math.abs(k.textBlock.angle))+(k.textBlock.height-k.textBlock.fontSize/2)*Math.sin(Math.PI/180*Math.abs(k.textBlock.angle)));if(d&&0<d.length)for(e=0;e<d.length;e++)d[e]&&0<d[e]._labels.length&&(m=d[e]._labels[0],k=d[e]._labels[d[e]._labels.length-1],v=m.textBlock.width*Math.cos(Math.PI/180*Math.abs(m.textBlock.angle))+(m.textBlock.height-k.textBlock.fontSize/2)*Math.sin(Math.PI/180*Math.abs(m.textBlock.angle)),z=k.textBlock.width*
Math.cos(Math.PI/180*Math.abs(k.textBlock.angle))+(k.textBlock.height-k.textBlock.fontSize/2)*Math.sin(Math.PI/180*Math.abs(k.textBlock.angle)));if(p.panEnabled)for(e=0;e<b.length;e++)w[e]=p.sessionVariables.axisY.height;else for(e=0;e<b.length;e++)p.sessionVariables.axisY.height=w[e];if(b&&0<b.length)for(e=b.length-1;0<=e;e--)k=Math.round(g.y2),m=Math.round(g.y2>b[e].chart.height-10?b[e].chart.height-10:g.y2),b[e].lineCoordinates.y1=k-(w[e]+b[e].margin+N),b[e].lineCoordinates.y2=k-(w[e]+b[e].margin+
N),b[e].bounds={x1:l,y1:k-(w[e]+N+b[e].margin),x2:h,y2:m-(N+b[e].margin),width:h-l,height:w[e]},b[e].title&&(b[e]._titleTextBlock.maxWidth=0<b[e].titleMaxWidth&&b[e].titleMaxWidth<b[e].lineCoordinates.width?b[e].titleMaxWidth:b[e].lineCoordinates.width),N+=w[e]+b[e].margin;if(d&&0<d.length)for(e=d.length-1;0<=e;e--)d[e]&&(k=Math.round(g.y1),m=Math.round(g.y1+(A[e]+d[e].margin+Q)),d[e].lineCoordinates.y1=m,d[e].lineCoordinates.y2=m,d[e].bounds={x1:l,y1:k+(d[e].margin+Q),x2:h,y2:m,width:h-l,height:T},
d[e].title&&(d[e]._titleTextBlock.maxWidth=0<d[e].titleMaxWidth&&d[e].titleMaxWidth<d[e].lineCoordinates.width?d[e].titleMaxWidth:d[e].lineCoordinates.width),Q+=A[e]+d[e].margin);if(a&&0<a.length)for(e=0;e<a.length;e++){C=a[e]._labels&&0<a[e]._labels.length?a[e]._labels[0].textBlock.fontSize/2:0;l=Math.round(g.x1+f);k=d&&0<d.length?Math.round(d[0]?d[0].lineCoordinates.y2:g.y1<Math.max(C,10)?Math.max(C,10):g.y1):g.y1<Math.max(C,10)?Math.max(C,10):g.y1;h=Math.round(g.x1+Y+f);m=b&&0<b.length?Math.round(b[0]?
b[0].lineCoordinates.y1:g.y2-P>p.height-Math.max(C,10)?p.height-Math.max(C,10):g.y2-P):g.y2>p.height-Math.max(C,10)?p.height-Math.max(C,10):g.y2;if(b&&0<b.length)for(C=0;C<b.length;C++)b[C]&&b[C].labelAutoFit&&(h=0>b[C].labelAngle?Math.max(h,t):0===b[C].labelAngle?Math.max(h,t/2):h,l=0>b[C].labelAngle||0===b[C].labelAngle?h-Y:l);if(d&&0<d.length)for(C=0;C<d.length;C++)d[C]&&d[C].labelAutoFit&&(h=d[C].lineCoordinates.x1,l=h-Y);a[e].lineCoordinates={x1:h-J,y1:k,x2:h-J,y2:m,height:Math.abs(m-k)};a[e].bounds=
{x1:h-(B[e]+J),y1:k,x2:h,y2:m,width:h-l,height:m-k};a[e].title&&(a[e]._titleTextBlock.maxWidth=0<a[e].titleMaxWidth&&a[e].titleMaxWidth<a[e].lineCoordinates.height?a[e].titleMaxWidth:a[e].lineCoordinates.height);a[e].calculateValueToPixelConversionParameters();J+=B[e]+a[e].margin}if(c&&0<c.length)for(e=0;e<c.length;e++){C=c[e]._labels&&0<c[e]._labels.length?c[e]._labels[0].textBlock.fontSize/2:0;l=Math.round(g.x1-f);k=d&&0<d.length?Math.round(d[0]?d[0].lineCoordinates.y2:g.y1<Math.max(C,10)?Math.max(C,
10):g.y1):g.y1<Math.max(C,10)?Math.max(C,10):g.y1;h=Math.round(g.x2-U-K);m=b&&0<b.length?Math.round(b[0]?b[0].lineCoordinates.y1:g.y2-P>p.height-Math.max(C,10)?p.height-Math.max(C,10):g.y2-P):g.y2>p.height-Math.max(C,10)?p.height-Math.max(C,10):g.y2;if(b&&0<b.length)for(C=0;C<b.length;C++)b[C]&&b[C].labelAutoFit&&(h=0>b[C].labelAngle?Math.max(h,t):0===b[C].labelAngle?Math.max(h,t/2):h,l=0>b[C].labelAngle||0===b[C].labelAngle?h-U:l);if(d&&0<d.length)for(C=0;C<d.length;C++)d[C]&&d[C].labelAutoFit&&
(h=d[C].lineCoordinates.x2,l=h-U);c[e].lineCoordinates={x1:h+O,y1:k,x2:h+O,y2:m,height:Math.abs(m-k)};c[e].bounds={x1:l,y1:k,x2:h+r[e]+O,y2:m,width:h-l,height:m-k};c[e].title&&(c[e]._titleTextBlock.maxWidth=0<c[e].titleMaxWidth&&c[e].titleMaxWidth<c[e].lineCoordinates.height?c[e].titleMaxWidth:c[e].lineCoordinates.height);c[e].calculateValueToPixelConversionParameters();O+=r[e]+c[e].margin}if(b&&0<b.length)for(e=0;e<b.length;e++)b[e].calculateValueToPixelConversionParameters();if(d&&0<d.length)for(e=
0;e<d.length;e++)d[e].calculateValueToPixelConversionParameters();if(0<q){if(a&&0<a.length)for(e=0;e<a.length;e++)D=I[q-1][e]===I[q][e]?!0:!1;else D=!0;if(c&&0<c.length)for(e=0;e<c.length;e++)E=L[q-1][e]===L[q][e]?!0:!1;else E=!0;if(b&&0<b.length)for(e=0;e<b.length;e++)F=s[q-1][e]===s[q][e]?!0:!1;else F=!0;if(d&&0<d.length)for(e=0;e<d.length;e++)G=H[q-1][e]===H[q][e]?!0:!1;else G=!0}if(D&&E&&F&&G)break;q++}if(b&&0<b.length)for(e=0;e<b.length;e++)b[e].renderLabelsTicksAndTitle();if(d&&0<d.length)for(e=
0;e<d.length;e++)d[e].renderLabelsTicksAndTitle();if(a&&0<a.length)for(e=0;e<a.length;e++)a[e].renderLabelsTicksAndTitle();if(c&&0<c.length)for(e=0;e<c.length;e++)c[e].renderLabelsTicksAndTitle()}p.preparePlotArea();g=p.plotArea;n.save();n.beginPath();n.rect(g.x1,g.y1,Math.abs(g.x2-g.x1),Math.abs(g.y2-g.y1));n.clip();if(a&&0<a.length)for(e=0;e<a.length;e++)a[e].renderStripLinesOfThicknessType("value");if(c&&0<c.length)for(e=0;e<c.length;e++)c[e].renderStripLinesOfThicknessType("value");if(b&&0<b.length)for(e=
0;e<b.length;e++)b[e].renderStripLinesOfThicknessType("value");if(d&&0<d.length)for(e=0;e<d.length;e++)d[e].renderStripLinesOfThicknessType("value");if(a&&0<a.length)for(e=0;e<a.length;e++)a[e].renderInterlacedColors();if(c&&0<c.length)for(e=0;e<c.length;e++)c[e].renderInterlacedColors();if(b&&0<b.length)for(e=0;e<b.length;e++)b[e].renderInterlacedColors();if(d&&0<d.length)for(e=0;e<d.length;e++)d[e].renderInterlacedColors();n.restore();if(a&&0<a.length)for(e=0;e<a.length;e++)a[e].renderGrid();if(c&&
0<c.length)for(e=0;e<c.length;e++)c[e].renderGrid();if(b&&0<b.length)for(e=0;e<b.length;e++)b[e].renderGrid();if(d&&0<d.length)for(e=0;e<d.length;e++)d[e].renderGrid();if(a&&0<a.length)for(e=0;e<a.length;e++)a[e].renderAxisLine();if(c&&0<c.length)for(e=0;e<c.length;e++)c[e].renderAxisLine();if(b&&0<b.length)for(e=0;e<b.length;e++)b[e].renderAxisLine();if(d&&0<d.length)for(e=0;e<d.length;e++)d[e].renderAxisLine();if(a&&0<a.length)for(e=0;e<a.length;e++)a[e].renderStripLinesOfThicknessType("pixel");
if(c&&0<c.length)for(e=0;e<c.length;e++)c[e].renderStripLinesOfThicknessType("pixel");if(b&&0<b.length)for(e=0;e<b.length;e++)b[e].renderStripLinesOfThicknessType("pixel");if(d&&0<d.length)for(e=0;e<d.length;e++)d[e].renderStripLinesOfThicknessType("pixel")};B.prototype.renderLabelsTicksAndTitle=function(){var a=!1,c=0,b=0,d=1,f=0;0!==this.labelAngle&&360!==this.labelAngle&&(d=1.2);if("undefined"===typeof this.options.interval){if("bottom"===this._position||"top"===this._position)if(this.logarithmic&&
!this.equidistantInterval&&this.labelAutoFit){for(var c=[],d=0!==this.labelAngle&&360!==this.labelAngle?1:1.2,g,l=this.viewportMaximum,k=this.lineCoordinates.width/Math.log(this.range),h=this._labels.length-1;0<=h;h--){p=this._labels[h];if(p.position<this.viewportMinimum)break;p.position>this.viewportMaximum||!(h===this._labels.length-1||g<Math.log(l/p.position)*k/d)||(c.push(p),l=p.position,g=p.textBlock.width*Math.abs(Math.cos(Math.PI/180*this.labelAngle))+p.textBlock.height*Math.abs(Math.sin(Math.PI/
180*this.labelAngle)))}this._labels=c}else{for(h=0;h<this._labels.length;h++)p=this._labels[h],p.position<this.viewportMinimum||(p=p.textBlock.width*Math.abs(Math.cos(Math.PI/180*this.labelAngle))+p.textBlock.height*Math.abs(Math.sin(Math.PI/180*this.labelAngle)),c+=p);c>this.lineCoordinates.width*d&&this.labelAutoFit&&(a=!0)}if("left"===this._position||"right"===this._position)if(this.logarithmic&&!this.equidistantInterval&&this.labelAutoFit){for(var c=[],m,l=this.viewportMaximum,k=this.lineCoordinates.height/
Math.log(this.range),h=this._labels.length-1;0<=h;h--){p=this._labels[h];if(p.position<this.viewportMinimum)break;p.position>this.viewportMaximum||!(h===this._labels.length-1||m<Math.log(l/p.position)*k)||(c.push(p),l=p.position,m=p.textBlock.height*Math.abs(Math.cos(Math.PI/180*this.labelAngle))+p.textBlock.width*Math.abs(Math.sin(Math.PI/180*this.labelAngle)))}this._labels=c}else{for(h=0;h<this._labels.length;h++)p=this._labels[h],p.position<this.viewportMinimum||(p=p.textBlock.height*Math.abs(Math.cos(Math.PI/
180*this.labelAngle))+p.textBlock.width*Math.abs(Math.sin(Math.PI/180*this.labelAngle)),b+=p);b>this.lineCoordinates.height*d&&this.labelAutoFit&&(a=!0)}}if("bottom"===this._position){for(var p,h=0;h<this._labels.length;h++)p=this._labels[h],p.position<this.viewportMinimum||p.position>this.viewportMaximum||(b=this.getPixelCoordinatesOnAxis(p.position),a&&0!==f++%2&&this.labelAutoFit||(this.tickThickness&&(this.ctx.lineWidth=this.tickThickness,this.ctx.strokeStyle=this.tickColor,d=1===this.ctx.lineWidth%
2?(b.x<<0)+0.5:b.x<<0,this.ctx.beginPath(),this.ctx.moveTo(d,b.y<<0),this.ctx.lineTo(d,b.y+this.tickLength<<0),this.ctx.stroke()),0===p.textBlock.angle?(b.x-=p.textBlock.width/2,b.y+=this.tickLength+p.textBlock.fontSize/2):(b.x-=0>this.labelAngle?p.textBlock.width*Math.cos(Math.PI/180*this.labelAngle):0,b.y+=this.tickLength+Math.abs(0>this.labelAngle?p.textBlock.width*Math.sin(Math.PI/180*this.labelAngle)-5:5)),p.textBlock.x=b.x,p.textBlock.y=b.y,p.textBlock.render(!0)));this.title&&(this._titleTextBlock.measureText(),
this._titleTextBlock.x=this.lineCoordinates.x1+this.lineCoordinates.width/2-this._titleTextBlock.width/2,this._titleTextBlock.y=this.bounds.y2-this._titleTextBlock.height-3,this.titleMaxWidth=this._titleTextBlock.maxWidth,this._titleTextBlock.render(!0))}else if("top"===this._position){for(h=0;h<this._labels.length;h++)p=this._labels[h],p.position<this.viewportMinimum||p.position>this.viewportMaximum||(b=this.getPixelCoordinatesOnAxis(p.position),a&&0!==f++%2&&this.labelAutoFit||(this.tickThickness&&
(this.ctx.lineWidth=this.tickThickness,this.ctx.strokeStyle=this.tickColor,d=1===this.ctx.lineWidth%2?(b.x<<0)+0.5:b.x<<0,this.ctx.beginPath(),this.ctx.moveTo(d,b.y<<0),this.ctx.lineTo(d,b.y-this.tickLength<<0),this.ctx.stroke()),0===p.textBlock.angle?(b.x-=p.textBlock.width/2,b.y-=this.tickLength+p.textBlock.height/2):(b.x+=(p.textBlock.height-this.tickLength-this.labelFontSize/2)*Math.sin(Math.PI/180*this.labelAngle)-(0<this.labelAngle?p.textBlock.width*Math.cos(Math.PI/180*this.labelAngle):0),
b.y-=this.tickLength+(p.textBlock.height/2*Math.cos(Math.PI/180*this.labelAngle)+(0<this.labelAngle?p.textBlock.width*Math.sin(Math.PI/180*this.labelAngle):0))),p.textBlock.x=b.x,p.textBlock.y=b.y,p.textBlock.render(!0)));this.title&&(this._titleTextBlock.measureText(),this._titleTextBlock.x=this.lineCoordinates.x1+this.lineCoordinates.width/2-this._titleTextBlock.width/2,this._titleTextBlock.y=this.bounds.y1+1,this.titleMaxWidth=this._titleTextBlock.maxWidth,this._titleTextBlock.render(!0))}else if("left"===
this._position){for(h=0;h<this._labels.length;h++)p=this._labels[h],p.position<this.viewportMinimum||p.position>this.viewportMaximum||(b=this.getPixelCoordinatesOnAxis(p.position),a&&0!==f++%2&&this.labelAutoFit||(this.tickThickness&&(this.ctx.lineWidth=this.tickThickness,this.ctx.strokeStyle=this.tickColor,d=1===this.ctx.lineWidth%2?(b.y<<0)+0.5:b.y<<0,this.ctx.beginPath(),this.ctx.moveTo(b.x<<0,d),this.ctx.lineTo(b.x-this.tickLength<<0,d),this.ctx.stroke()),0===this.labelAngle?(p.textBlock.y=b.y,
p.textBlock.x=b.x-p.textBlock.width*Math.cos(Math.PI/180*this.labelAngle)-this.tickLength-5):(p.textBlock.y=b.y-p.textBlock.width*Math.sin(Math.PI/180*this.labelAngle),p.textBlock.x=0<this.labelAngle?b.x-p.textBlock.width*Math.cos(Math.PI/180*this.labelAngle)-this.tickLength-5:b.x-p.textBlock.width*Math.cos(Math.PI/180*this.labelAngle)+(p.textBlock.height-p.textBlock.fontSize/2-5)*Math.sin(Math.PI/180*this.labelAngle)-this.tickLength),p.textBlock.render(!0)));this.title&&(this._titleTextBlock.measureText(),
this._titleTextBlock.x=this.bounds.x1+1,this._titleTextBlock.y=this.lineCoordinates.height/2+this._titleTextBlock.width/2+this.lineCoordinates.y1,this.titleMaxWidth=this._titleTextBlock.maxWidth,this._titleTextBlock.render(!0))}else if("right"===this._position){for(h=0;h<this._labels.length;h++)p=this._labels[h],p.position<this.viewportMinimum||p.position>this.viewportMaximum||(b=this.getPixelCoordinatesOnAxis(p.position),a&&0!==f++%2&&this.labelAutoFit||(this.tickThickness&&(this.ctx.lineWidth=this.tickThickness,
this.ctx.strokeStyle=this.tickColor,d=1===this.ctx.lineWidth%2?(b.y<<0)+0.5:b.y<<0,this.ctx.beginPath(),this.ctx.moveTo(b.x<<0,d),this.ctx.lineTo(b.x+this.tickLength<<0,d),this.ctx.stroke()),0===this.labelAngle?(p.textBlock.y=b.y,p.textBlock.x=b.x+this.tickLength+5):(p.textBlock.y=0>this.labelAngle?b.y:b.y-(p.textBlock.height-p.textBlock.fontSize/2-5)*Math.cos(Math.PI/180*this.labelAngle),p.textBlock.x=0<this.labelAngle?b.x+(p.textBlock.height-p.textBlock.fontSize/2-5)*Math.sin(Math.PI/180*this.labelAngle)+
this.tickLength:b.x+this.tickLength+5),p.textBlock.render(!0)));this.title&&(this._titleTextBlock.measureText(),this._titleTextBlock.x=this.bounds.x2-1,this._titleTextBlock.y=this.lineCoordinates.height/2-this._titleTextBlock.width/2+this.lineCoordinates.y1,this.titleMaxWidth=this._titleTextBlock.maxWidth,this._titleTextBlock.render(!0))}};B.prototype.renderInterlacedColors=function(){var a=this.chart.plotArea.ctx,c,b,d=this.chart.plotArea,f=0;c=!0;if(("bottom"===this._position||"top"===this._position)&&
this.interlacedColor)for(a.fillStyle=this.interlacedColor,f=0;f<this._labels.length;f++)c?(c=this.getPixelCoordinatesOnAxis(this._labels[f].position),b=f+1>this._labels.length-1?this.getPixelCoordinatesOnAxis(this.viewportMaximum):this.getPixelCoordinatesOnAxis(this._labels[f+1].position),a.fillRect(Math.min(b.x,c.x),d.y1,Math.abs(b.x-c.x),Math.abs(d.y1-d.y2)),c=!1):c=!0;else if(("left"===this._position||"right"===this._position)&&this.interlacedColor)for(a.fillStyle=this.interlacedColor,f=0;f<this._labels.length;f++)c?
(b=this.getPixelCoordinatesOnAxis(this._labels[f].position),c=f+1>this._labels.length-1?this.getPixelCoordinatesOnAxis(this.viewportMaximum):this.getPixelCoordinatesOnAxis(this._labels[f+1].position),a.fillRect(d.x1,Math.min(b.y,c.y),Math.abs(d.x1-d.x2),Math.abs(c.y-b.y)),c=!1):c=!0;a.beginPath()};B.prototype.renderStripLinesOfThicknessType=function(a){if(this.stripLines&&0<this.stripLines.length&&a){for(var c=this,b,d=0,f=0,g=!1,l=!1,k=[],h=[],l=!1,d=0;d<this.stripLines.length;d++){var m=this.stripLines[d];
m._thicknessType===a&&("pixel"===a&&(m.value<this.viewportMinimum||m.value>this.viewportMaximum||y(m.value)||isNaN(this.range))||k.push(m))}for(d=0;d<this._stripLineLabels.length;d++)if(m=this.stripLines[d],b=this._stripLineLabels[d],!(b.position<this.viewportMinimum||b.position>this.viewportMaximum||isNaN(this.range))){a=this.getPixelCoordinatesOnAxis(b.position);if("outside"===b.stripLine.labelPlacement)if(m&&(this.ctx.strokeStyle=m.color,"pixel"===m._thicknessType&&(this.ctx.lineWidth=m.thickness)),
"bottom"===this._position){var p=1===this.ctx.lineWidth%2?(a.x<<0)+0.5:a.x<<0;this.ctx.beginPath();this.ctx.moveTo(p,a.y<<0);this.ctx.lineTo(p,a.y+this.tickLength<<0);this.ctx.stroke();0===this.labelAngle?(a.x-=b.textBlock.width/2,a.y+=this.tickLength+b.textBlock.fontSize/2):(a.x-=0>this.labelAngle?b.textBlock.width*Math.cos(Math.PI/180*this.labelAngle):0,a.y+=this.tickLength+Math.abs(0>this.labelAngle?b.textBlock.width*Math.sin(Math.PI/180*this.labelAngle)-5:5))}else"top"===this._position?(p=1===
this.ctx.lineWidth%2?(a.x<<0)+0.5:a.x<<0,this.ctx.beginPath(),this.ctx.moveTo(p,a.y<<0),this.ctx.lineTo(p,a.y-this.tickLength<<0),this.ctx.stroke(),0===this.labelAngle?(a.x-=b.textBlock.width/2,a.y-=this.tickLength+b.textBlock.height):(a.x+=(b.textBlock.height-this.tickLength-this.labelFontSize/2)*Math.sin(Math.PI/180*this.labelAngle)-(0<this.labelAngle?b.textBlock.width*Math.cos(Math.PI/180*this.labelAngle):0),a.y-=this.tickLength+(b.textBlock.height*Math.cos(Math.PI/180*this.labelAngle)+(0<this.labelAngle?
b.textBlock.width*Math.sin(Math.PI/180*this.labelAngle):0)))):"left"===this._position?(p=1===this.ctx.lineWidth%2?(a.y<<0)+0.5:a.y<<0,this.ctx.beginPath(),this.ctx.moveTo(a.x<<0,p),this.ctx.lineTo(a.x-this.tickLength<<0,p),this.ctx.stroke(),0===this.labelAngle?a.x=a.x-b.textBlock.width*Math.cos(Math.PI/180*this.labelAngle)-this.tickLength-5:(a.y-=b.textBlock.width*Math.sin(Math.PI/180*this.labelAngle),a.x=0<this.labelAngle?a.x-b.textBlock.width*Math.cos(Math.PI/180*this.labelAngle)-this.tickLength-
5:a.x-b.textBlock.width*Math.cos(Math.PI/180*this.labelAngle)+(b.textBlock.height-b.textBlock.fontSize/2-5)*Math.sin(Math.PI/180*this.labelAngle)-this.tickLength)):"right"===this._position&&(p=1===this.ctx.lineWidth%2?(a.y<<0)+0.5:a.y<<0,this.ctx.beginPath(),this.ctx.moveTo(a.x<<0,p),this.ctx.lineTo(a.x+this.tickLength<<0,p),this.ctx.stroke(),0===this.labelAngle?a.x=a.x+this.tickLength+5:(a.y=0>this.labelAngle?a.y:a.y-(b.textBlock.height-b.textBlock.fontSize/2-5)*Math.cos(Math.PI/180*this.labelAngle),
a.x=0<this.labelAngle?a.x+(b.textBlock.height-b.textBlock.fontSize/2-5)*Math.sin(Math.PI/180*this.labelAngle)+this.tickLength:a.x+this.tickLength+5));else b.textBlock.angle=-90,"bottom"===this._position?(b.textBlock.maxWidth=this.options.stripLines[d].labelMaxWidth?this.options.stripLines[d].labelMaxWidth:this.chart.plotArea.height-3,b.textBlock.measureText(),a.x-b.textBlock.height>this.chart.plotArea.x1?y(m.startValue)?a.x-=b.textBlock.height-b.textBlock.fontSize/2:a.x-=b.textBlock.height/2-b.textBlock.fontSize/
2+3:(b.textBlock.angle=90,y(m.startValue)?a.x+=b.textBlock.height-b.textBlock.fontSize/2:a.x+=b.textBlock.height/2-b.textBlock.fontSize/2+3),a.y=-90===b.textBlock.angle?"near"===b.stripLine.labelAlign?this.chart.plotArea.y2-3:"center"===b.stripLine.labelAlign?(this.chart.plotArea.y2+this.chart.plotArea.y1+b.textBlock.width)/2:this.chart.plotArea.y1+b.textBlock.width+3:"near"===b.stripLine.labelAlign?this.chart.plotArea.y2-b.textBlock.width-3:"center"===b.stripLine.labelAlign?(this.chart.plotArea.y2+
this.chart.plotArea.y1-b.textBlock.width)/2:this.chart.plotArea.y1+3):"top"===this._position?(b.textBlock.maxWidth=this.options.stripLines[d].labelMaxWidth?this.options.stripLines[d].labelMaxWidth:this.chart.plotArea.height-3,b.textBlock.measureText(),a.x-b.textBlock.height>this.chart.plotArea.x1?y(m.startValue)?a.x-=b.textBlock.height-b.textBlock.fontSize/2:a.x-=b.textBlock.height/2-b.textBlock.fontSize/2+3:(b.textBlock.angle=90,y(m.startValue)?a.x+=b.textBlock.height-b.textBlock.fontSize/2:a.x+=
b.textBlock.height/2-b.textBlock.fontSize/2+3),a.y=-90===b.textBlock.angle?"near"===b.stripLine.labelAlign?this.chart.plotArea.y1+b.textBlock.width+3:"center"===b.stripLine.labelAlign?(this.chart.plotArea.y2+this.chart.plotArea.y1+b.textBlock.width)/2:this.chart.plotArea.y2-3:"near"===b.stripLine.labelAlign?this.chart.plotArea.y1+3:"center"===b.stripLine.labelAlign?(this.chart.plotArea.y2+this.chart.plotArea.y1-b.textBlock.width)/2:this.chart.plotArea.y2-b.textBlock.width-3):"left"===this._position?
(b.textBlock.maxWidth=this.options.stripLines[d].labelMaxWidth?this.options.stripLines[d].labelMaxWidth:this.chart.plotArea.width-3,b.textBlock.angle=0,b.textBlock.measureText(),a.y-b.textBlock.height>this.chart.plotArea.y1?y(m.startValue)?a.y-=b.textBlock.height-b.textBlock.fontSize/2:a.y-=b.textBlock.height/2-b.textBlock.fontSize+3:a.y-b.textBlock.height<this.chart.plotArea.y2?a.y+=b.textBlock.fontSize/2+3:y(m.startValue)?a.y-=b.textBlock.height-b.textBlock.fontSize/2:a.y-=b.textBlock.height/2-
b.textBlock.fontSize+3,a.x="near"===b.stripLine.labelAlign?this.chart.plotArea.x1+3:"center"===b.stripLine.labelAlign?(this.chart.plotArea.x2+this.chart.plotArea.x1)/2-b.textBlock.width/2:this.chart.plotArea.x2-b.textBlock.width-3):"right"===this._position&&(b.textBlock.maxWidth=this.options.stripLines[d].labelMaxWidth?this.options.stripLines[d].labelMaxWidth:this.chart.plotArea.width-3,b.textBlock.angle=0,b.textBlock.measureText(),a.y-+b.textBlock.height>this.chart.plotArea.y1?y(m.startValue)?a.y-=
b.textBlock.height-b.textBlock.fontSize/2:a.y-=b.textBlock.height/2-b.textBlock.fontSize/2-3:a.y-b.textBlock.height<this.chart.plotArea.y2?a.y+=b.textBlock.fontSize/2+3:y(m.startValue)?a.y-=b.textBlock.height-b.textBlock.fontSize/2:a.y-=b.textBlock.height/2-b.textBlock.fontSize/2+3,a.x="near"===b.stripLine.labelAlign?this.chart.plotArea.x2-b.textBlock.width-3:"center"===b.stripLine.labelAlign?(this.chart.plotArea.x2+this.chart.plotArea.x1)/2-b.textBlock.width/2:this.chart.plotArea.x1+3);b.textBlock.x=
a.x;b.textBlock.y=a.y;h.push(b)}if(!l){l=!1;this.ctx.save();this.ctx.beginPath();this.ctx.rect(this.chart.plotArea.x1,this.chart.plotArea.y1,this.chart.plotArea.width,this.chart.plotArea.height);this.ctx.clip();for(d=0;d<k.length;d++)m=k[d],m.showOnTop?g||(g=!0,this.chart.addEventListener("dataAnimationIterationEnd",function(){this.ctx.save();this.ctx.beginPath();this.ctx.rect(this.chart.plotArea.x1,this.chart.plotArea.y1,this.chart.plotArea.width,this.chart.plotArea.height);this.ctx.clip();for(f=
0;f<k.length;f++)m=k[f],m.showOnTop&&m.render();this.ctx.restore()},m)):m.render();for(d=0;d<h.length;d++)b=h[d],b.stripLine.showOnTop?l||(l=!0,this.chart.addEventListener("dataAnimationIterationEnd",function(){for(f=0;f<h.length;f++)b=h[f],"inside"===b.stripLine.labelPlacement&&b.stripLine.showOnTop&&(c.ctx.save(),c.ctx.beginPath(),c.ctx.rect(c.chart.plotArea.x1,c.chart.plotArea.y1,c.chart.plotArea.width,c.chart.plotArea.height),c.ctx.clip(),b.textBlock.render(!0),c.ctx.restore())},b.textBlock)):
"inside"===b.stripLine.labelPlacement&&b.textBlock.render(!0);this.ctx.restore();l=!0}if(l)for(l=!1,d=0;d<h.length;d++)b=h[d],b.stripLine.showOnTop?l||(l=!0,this.chart.addEventListener("dataAnimationIterationEnd",function(){for(f=0;f<h.length;f++)b=h[f],"outside"===b.stripLine.labelPlacement&&b.stripLine.showOnTop&&b.textBlock.render(!0)},b.textBlock)):"outside"===b.stripLine.labelPlacement&&b.textBlock.render(!0)}};B.prototype.renderGrid=function(){if(this.gridThickness&&0<this.gridThickness){var a=
this.chart.ctx;a.save();var c,b=this.chart.plotArea;a.lineWidth=this.gridThickness;a.strokeStyle=this.gridColor;a.setLineDash&&a.setLineDash(F(this.gridDashType,this.gridThickness));if("bottom"===this._position||"top"===this._position)for(d=0;d<this._labels.length;d++)this._labels[d].position<this.viewportMinimum||this._labels[d].position>this.viewportMaximum||(a.beginPath(),c=this.getPixelCoordinatesOnAxis(this._labels[d].position),c=1===a.lineWidth%2?(c.x<<0)+0.5:c.x<<0,a.moveTo(c,b.y1<<0),a.lineTo(c,
b.y2<<0),a.stroke());else if("left"===this._position||"right"===this._position)for(var d=0;d<this._labels.length;d++)this._labels[d].position<this.viewportMinimum||this._labels[d].position>this.viewportMaximum||(a.beginPath(),c=this.getPixelCoordinatesOnAxis(this._labels[d].position),c=1===a.lineWidth%2?(c.y<<0)+0.5:c.y<<0,a.moveTo(b.x1<<0,c),a.lineTo(b.x2<<0,c),a.stroke());a.restore()}};B.prototype.renderAxisLine=function(){var a=this.chart.ctx;a.save();if("bottom"===this._position||"top"===this._position){if(this.lineThickness){a.lineWidth=
this.lineThickness;a.strokeStyle=this.lineColor?this.lineColor:"black";a.setLineDash&&a.setLineDash(F(this.lineDashType,this.lineThickness));var c=1===this.lineThickness%2?(this.lineCoordinates.y1<<0)+0.5:this.lineCoordinates.y1<<0;a.beginPath();a.moveTo(this.lineCoordinates.x1,c);a.lineTo(this.lineCoordinates.x2,c);a.stroke()}}else"left"!==this._position&&"right"!==this._position||!this.lineThickness||(a.lineWidth=this.lineThickness,a.strokeStyle=this.lineColor,a.setLineDash&&a.setLineDash(F(this.lineDashType,
this.lineThickness)),c=1===this.lineThickness%2?(this.lineCoordinates.x1<<0)+0.5:this.lineCoordinates.x1<<0,a.beginPath(),a.moveTo(c,this.lineCoordinates.y1),a.lineTo(c,this.lineCoordinates.y2),a.stroke());a.restore()};B.prototype.getPixelCoordinatesOnAxis=function(a){var c={};if("bottom"===this._position||"top"===this._position)c.x=this.convertValueToPixel(a),c.y=this.lineCoordinates.y1;if("left"===this._position||"right"===this._position)c.y=this.convertValueToPixel(a),c.x=this.lineCoordinates.x2;
return c};B.prototype.convertPixelToValue=function(a){if("undefined"===typeof a)return null;var c=0,c=0,c="number"===typeof a?a:"left"===this._position||"right"===this._position?a.y:a.x;return c=this.logarithmic?Math.pow(this.logarithmBase,(c-this.conversionParameters.reference)/this.conversionParameters.pixelPerUnit)*this.viewportMinimum:this.conversionParameters.minimum+(c-this.conversionParameters.reference)/this.conversionParameters.pixelPerUnit};B.prototype.convertValueToPixel=function(a){return this.logarithmic?
this.conversionParameters.reference+this.conversionParameters.pixelPerUnit*Math.log(a/this.conversionParameters.minimum)/this.conversionParameters.lnLogarithmBase+0.5<<0:this.conversionParameters.reference+this.conversionParameters.pixelPerUnit*(a-this.conversionParameters.minimum)+0.5<<0};B.prototype.setViewPortRange=function(a,c){this.sessionVariables.newViewportMinimum=this.viewportMinimum=Math.min(a,c);this.sessionVariables.newViewportMaximum=this.viewportMaximum=Math.max(a,c)};B.prototype.getXValueAt=
function(a){if(!a)return null;var c=null;"left"===this._position?c=this.convertPixelToValue(a.y):"bottom"===this._position&&(c=this.convertPixelToValue(a.x));return c};B.prototype.calculateValueToPixelConversionParameters=function(a){a={pixelPerUnit:null,minimum:null,reference:null};var c=this.lineCoordinates.width,b=this.lineCoordinates.height;a.minimum=this.viewportMinimum;if("bottom"===this._position||"top"===this._position)this.logarithmic?(a.lnLogarithmBase=Math.log(this.logarithmBase),a.pixelPerUnit=
(this.reversed?-1:1)*c*a.lnLogarithmBase/Math.log(Math.abs(this.range))):a.pixelPerUnit=(this.reversed?-1:1)*c/Math.abs(this.range),a.reference=this.reversed?this.lineCoordinates.x2:this.lineCoordinates.x1;if("left"===this._position||"right"===this._position)this.logarithmic?(a.lnLogarithmBase=Math.log(this.logarithmBase),a.pixelPerUnit=(this.reversed?1:-1)*b*a.lnLogarithmBase/Math.log(Math.abs(this.range))):a.pixelPerUnit=(this.reversed?1:-1)*b/Math.abs(this.range),a.reference=this.reversed?this.lineCoordinates.y1:
this.lineCoordinates.y2;this.conversionParameters=a};B.prototype.calculateAxisParameters=function(){if(this.logarithmic)this.calculateLogarithamicAxisParameters();else{var a=this.chart.layoutManager.getFreeSpace(),c=!1,b=!1;"bottom"===this._position||"top"===this._position?(this.maxWidth=a.width,this.maxHeight=a.height):(this.maxWidth=a.height,this.maxHeight=a.width);var a="axisX"===this.type?"xySwapped"===this.chart.plotInfo.axisPlacement?62:70:"xySwapped"===this.chart.plotInfo.axisPlacement?50:
40,d=4;"axisX"===this.type&&(d=600>this.maxWidth?8:6);var a=Math.max(d,Math.floor(this.maxWidth/a)),f,g,l,d=0;!y(this.options.viewportMinimum)&&(!y(this.options.viewportMaximum)&&this.options.viewportMinimum>=this.options.viewportMaximum)&&(this.viewportMinimum=this.viewportMaximum=null);if(y(this.options.viewportMinimum)&&!y(this.sessionVariables.newViewportMinimum)&&!isNaN(this.sessionVariables.newViewportMinimum))this.viewportMinimum=this.sessionVariables.newViewportMinimum;else if(null===this.viewportMinimum||
isNaN(this.viewportMinimum))this.viewportMinimum=this.minimum;if(y(this.options.viewportMaximum)&&!y(this.sessionVariables.newViewportMaximum)&&!isNaN(this.sessionVariables.newViewportMaximum))this.viewportMaximum=this.sessionVariables.newViewportMaximum;else if(null===this.viewportMaximum||isNaN(this.viewportMaximum))this.viewportMaximum=this.maximum;if("axisX"===this.type){if(this.dataSeries&&0<this.dataSeries.length)for(f=0;f<this.dataSeries.length;f++)"dateTime"===this.dataSeries[f].xValueType&&
(b=!0);f=null!==this.viewportMinimum?this.viewportMinimum:this.dataInfo.viewPortMin;g=null!==this.viewportMaximum?this.viewportMaximum:this.dataInfo.viewPortMax;0===g-f&&(d="undefined"===typeof this.options.interval?0.4:this.options.interval,g+=d,f-=d);Infinity!==this.dataInfo.minDiff?l=this.dataInfo.minDiff:1<g-f?l=0.5*Math.abs(g-f):(l=1,b&&(c=!0))}else"axisY"===this.type&&(f=null!==this.viewportMinimum?this.viewportMinimum:this.dataInfo.viewPortMin,g=null!==this.viewportMaximum?this.viewportMaximum:
this.dataInfo.viewPortMax,isFinite(f)||isFinite(g)?isFinite(f)?isFinite(g)||(g=f):f=g:(g="undefined"===typeof this.options.interval?-Infinity:this.options.interval,f="undefined"!==typeof this.options.interval||isFinite(this.dataInfo.minDiff)?0:Infinity),0===f&&0===g?(g+=9,f=0):0===g-f?(d=Math.min(Math.abs(0.01*Math.abs(g)),5),g+=d,f-=d):f>g?(d=Math.min(Math.abs(0.01*Math.abs(g-f)),5),0<=g?f=g-d:g=isFinite(f)?f+d:0):(d=Math.min(Math.abs(0.01*Math.abs(g-f)),0.05),0!==g&&(g+=d),0!==f&&(f-=d)),l=Infinity!==
this.dataInfo.minDiff?this.dataInfo.minDiff:1<g-f?0.5*Math.abs(g-f):1,this.includeZero&&(null===this.viewportMinimum||isNaN(this.viewportMinimum))&&0<f&&(f=0),this.includeZero&&(null===this.viewportMaximum||isNaN(this.viewportMaximum))&&0>g&&(g=0));d=(isNaN(this.viewportMaximum)||null===this.viewportMaximum?g:this.viewportMaximum)-(isNaN(this.viewportMinimum)||null===this.viewportMinimum?f:this.viewportMinimum);if("axisX"===this.type&&b){this.intervalType||(d/1<=a?(this.interval=1,this.intervalType=
"millisecond"):d/2<=a?(this.interval=2,this.intervalType="millisecond"):d/5<=a?(this.interval=5,this.intervalType="millisecond"):d/10<=a?(this.interval=10,this.intervalType="millisecond"):d/20<=a?(this.interval=20,this.intervalType="millisecond"):d/50<=a?(this.interval=50,this.intervalType="millisecond"):d/100<=a?(this.interval=100,this.intervalType="millisecond"):d/200<=a?(this.interval=200,this.intervalType="millisecond"):d/250<=a?(this.interval=250,this.intervalType="millisecond"):d/300<=a?(this.interval=
300,this.intervalType="millisecond"):d/400<=a?(this.interval=400,this.intervalType="millisecond"):d/500<=a?(this.interval=500,this.intervalType="millisecond"):d/(1*G.secondDuration)<=a?(this.interval=1,this.intervalType="second"):d/(2*G.secondDuration)<=a?(this.interval=2,this.intervalType="second"):d/(5*G.secondDuration)<=a?(this.interval=5,this.intervalType="second"):d/(10*G.secondDuration)<=a?(this.interval=10,this.intervalType="second"):d/(15*G.secondDuration)<=a?(this.interval=15,this.intervalType=
"second"):d/(20*G.secondDuration)<=a?(this.interval=20,this.intervalType="second"):d/(30*G.secondDuration)<=a?(this.interval=30,this.intervalType="second"):d/(1*G.minuteDuration)<=a?(this.interval=1,this.intervalType="minute"):d/(2*G.minuteDuration)<=a?(this.interval=2,this.intervalType="minute"):d/(5*G.minuteDuration)<=a?(this.interval=5,this.intervalType="minute"):d/(10*G.minuteDuration)<=a?(this.interval=10,this.intervalType="minute"):d/(15*G.minuteDuration)<=a?(this.interval=15,this.intervalType=
"minute"):d/(20*G.minuteDuration)<=a?(this.interval=20,this.intervalType="minute"):d/(30*G.minuteDuration)<=a?(this.interval=30,this.intervalType="minute"):d/(1*G.hourDuration)<=a?(this.interval=1,this.intervalType="hour"):d/(2*G.hourDuration)<=a?(this.interval=2,this.intervalType="hour"):d/(3*G.hourDuration)<=a?(this.interval=3,this.intervalType="hour"):d/(6*G.hourDuration)<=a?(this.interval=6,this.intervalType="hour"):d/(1*G.dayDuration)<=a?(this.interval=1,this.intervalType="day"):d/(2*G.dayDuration)<=
a?(this.interval=2,this.intervalType="day"):d/(4*G.dayDuration)<=a?(this.interval=4,this.intervalType="day"):d/(1*G.weekDuration)<=a?(this.interval=1,this.intervalType="week"):d/(2*G.weekDuration)<=a?(this.interval=2,this.intervalType="week"):d/(3*G.weekDuration)<=a?(this.interval=3,this.intervalType="week"):d/(1*G.monthDuration)<=a?(this.interval=1,this.intervalType="month"):d/(2*G.monthDuration)<=a?(this.interval=2,this.intervalType="month"):d/(3*G.monthDuration)<=a?(this.interval=3,this.intervalType=
"month"):d/(6*G.monthDuration)<=a?(this.interval=6,this.intervalType="month"):(this.interval=d/(1*G.yearDuration)<=a?1:d/(2*G.yearDuration)<=a?2:d/(4*G.yearDuration)<=a?4:Math.floor(B.getNiceNumber(d/(a-1),!0)/G.yearDuration),this.intervalType="year"));if(null===this.viewportMinimum||isNaN(this.viewportMinimum))this.viewportMinimum=f-l/2;if(null===this.viewportMaximum||isNaN(this.viewportMaximum))this.viewportMaximum=g+l/2;c?this.autoValueFormatString="MMM DD YYYY HH:mm":"year"===this.intervalType?
this.autoValueFormatString="YYYY":"month"===this.intervalType?this.autoValueFormatString="MMM YYYY":"week"===this.intervalType?this.autoValueFormatString="MMM DD YYYY":"day"===this.intervalType?this.autoValueFormatString="MMM DD YYYY":"hour"===this.intervalType?this.autoValueFormatString="hh:mm TT":"minute"===this.intervalType?this.autoValueFormatString="hh:mm TT":"second"===this.intervalType?this.autoValueFormatString="hh:mm:ss TT":"millisecond"===this.intervalType&&(this.autoValueFormatString="fff'ms'");
this.valueFormatString||(this.valueFormatString=this.autoValueFormatString)}else{this.intervalType="number";d=B.getNiceNumber(d,!1);this.interval=this.options&&0<this.options.interval?this.options.interval:B.getNiceNumber(d/(a-1),!0);if(null===this.viewportMinimum||isNaN(this.viewportMinimum))this.viewportMinimum="axisX"===this.type?f-l/2:Math.floor(f/this.interval)*this.interval;if(null===this.viewportMaximum||isNaN(this.viewportMaximum))this.viewportMaximum="axisX"===this.type?g+l/2:Math.ceil(g/
this.interval)*this.interval;0===this.viewportMaximum&&0===this.viewportMinimum&&(0===this.options.viewportMinimum?this.viewportMaximum+=10:0===this.options.viewportMaximum&&(this.viewportMinimum-=10),this.options&&"undefined"===typeof this.options.interval&&(this.interval=B.getNiceNumber((this.viewportMaximum-this.viewportMinimum)/(a-1),!0)))}if(null===this.minimum||null===this.maximum)if("axisX"===this.type?(f=null!==this.minimum?this.minimum:this.dataInfo.min,g=null!==this.maximum?this.maximum:
this.dataInfo.max,0===g-f&&(d="undefined"===typeof this.options.interval?0.4:this.options.interval,g+=d,f-=d),l=Infinity!==this.dataInfo.minDiff?this.dataInfo.minDiff:1<g-f?0.5*Math.abs(g-f):1):"axisY"===this.type&&(f=null!==this.minimum?this.minimum:this.dataInfo.min,g=null!==this.maximum?this.maximum:this.dataInfo.max,isFinite(f)||isFinite(g)?0===f&&0===g?(g+=9,f=0):0===g-f?(d=Math.min(Math.abs(0.01*Math.abs(g)),5),g+=d,f-=d):f>g?(d=Math.min(Math.abs(0.01*Math.abs(g-f)),5),0<=g?f=g-d:g=isFinite(f)?
f+d:0):(d=Math.min(Math.abs(0.01*Math.abs(g-f)),0.05),0!==g&&(g+=d),0!==f&&(f-=d)):(g="undefined"===typeof this.options.interval?-Infinity:this.options.interval,f="undefined"!==typeof this.options.interval||isFinite(this.dataInfo.minDiff)?0:Infinity),l=Infinity!==this.dataInfo.minDiff?this.dataInfo.minDiff:1<g-f?0.5*Math.abs(g-f):1,this.includeZero&&(null===this.minimum||isNaN(this.minimum))&&0<f&&(f=0),this.includeZero&&(null===this.maximum||isNaN(this.maximum))&&0>g&&(g=0)),"axisX"===this.type&&
b){if(null===this.minimum||isNaN(this.minimum))this.minimum=f-l/2;if(null===this.maximum||isNaN(this.maximum))this.maximum=g+l/2}else this.intervalType="number",null===this.minimum&&(this.minimum="axisX"===this.type?f-l/2:Math.floor(f/this.interval)*this.interval,this.minimum=Math.min(this.minimum,null===this.sessionVariables.viewportMinimum||isNaN(this.sessionVariables.viewportMinimum)?Infinity:this.sessionVariables.viewportMinimum)),null===this.maximum&&(this.maximum="axisX"===this.type?g+l/2:Math.ceil(g/
this.interval)*this.interval,this.maximum=Math.max(this.maximum,null===this.sessionVariables.viewportMaximum||isNaN(this.sessionVariables.viewportMaximum)?-Infinity:this.sessionVariables.viewportMaximum)),0===this.maximum&&0===this.minimum&&(0===this.options.minimum?this.maximum+=10:0===this.options.maximum&&(this.minimum-=10));y(this.sessionVariables.newViewportMinimum)&&(this.viewportMinimum=Math.max(this.viewportMinimum,this.minimum));y(this.sessionVariables.newViewportMaximum)&&(this.viewportMaximum=
Math.min(this.viewportMaximum,this.maximum));this.range=this.viewportMaximum-this.viewportMinimum;this.intervalStartPosition="axisX"===this.type&&b?this.getLabelStartPoint(new Date(this.viewportMinimum),this.intervalType,this.interval):Math.floor((this.viewportMinimum+0.2*this.interval)/this.interval)*this.interval;if(!this.valueFormatString&&(this.valueFormatString="#,##0.##",1>this.range)){c=Math.floor(Math.abs(Math.log(this.range)/Math.LN10))+2;if(isNaN(c)||!isFinite(c))c=2;if(2<c)for(b=0;b<c-
2;b++)this.valueFormatString+="#"}}};B.prototype.calculateLogarithamicAxisParameters=function(){var a=this.chart.layoutManager.getFreeSpace(),c=Math.log(this.logarithmBase),b;"bottom"===this._position||"top"===this._position?(this.maxWidth=a.width,this.maxHeight=a.height):(this.maxWidth=a.height,this.maxHeight=a.width);var a="axisX"===this.type?500>this.maxWidth?7:Math.max(7,Math.floor(this.maxWidth/100)):Math.max(Math.floor(this.maxWidth/50),3),d,f,g,l;l=1;if(null===this.viewportMinimum||isNaN(this.viewportMinimum))this.viewportMinimum=
this.minimum;if(null===this.viewportMaximum||isNaN(this.viewportMaximum))this.viewportMaximum=this.maximum;"axisX"===this.type?(d=null!==this.viewportMinimum?this.viewportMinimum:this.dataInfo.viewPortMin,f=null!==this.viewportMaximum?this.viewportMaximum:this.dataInfo.viewPortMax,1===f/d&&(l=Math.pow(this.logarithmBase,"undefined"===typeof this.options.interval?0.4:this.options.interval),f*=l,d/=l),g=Infinity!==this.dataInfo.minDiff?this.dataInfo.minDiff:f/d>this.logarithmBase?f/d*Math.pow(this.logarithmBase,
0.5):this.logarithmBase):"axisY"===this.type&&(d=null!==this.viewportMinimum?this.viewportMinimum:this.dataInfo.viewPortMin,f=null!==this.viewportMaximum?this.viewportMaximum:this.dataInfo.viewPortMax,0>=d&&!isFinite(f)?(f="undefined"===typeof this.options.interval?0:this.options.interval,d=1):0>=d?d=f:isFinite(f)||(f=d),1===d&&1===f?(f*=this.logarithmBase-1/this.logarithmBase,d=1):1===f/d?(l=Math.min(f*Math.pow(this.logarithmBase,0.01),Math.pow(this.logarithmBase,5)),f*=l,d/=l):d>f?(l=Math.min(d/
f*Math.pow(this.logarithmBase,0.01),Math.pow(this.logarithmBase,5)),1<=f?d=f/l:f=d*l):(l=Math.min(f/d*Math.pow(this.logarithmBase,0.01),Math.pow(this.logarithmBase,0.04)),1!==f&&(f*=l),1!==d&&(d/=l)),g=Infinity!==this.dataInfo.minDiff?this.dataInfo.minDiff:f/d>this.logarithmBase?f/d*Math.pow(this.logarithmBase,0.5):this.logarithmBase,this.includeZero&&(null===this.viewportMinimum||isNaN(this.viewportMinimum))&&1<d&&(d=1),this.includeZero&&(null===this.viewportMaximum||isNaN(this.viewportMaximum))&&
1>f&&(f=1));l=(isNaN(this.viewportMaximum)||null===this.viewportMaximum?f:this.viewportMaximum)/(isNaN(this.viewportMinimum)||null===this.viewportMinimum?d:this.viewportMinimum);linearRange=(isNaN(this.viewportMaximum)||null===this.viewportMaximum?f:this.viewportMaximum)-(isNaN(this.viewportMinimum)||null===this.viewportMinimum?d:this.viewportMinimum);this.intervalType="number";l=Math.pow(this.logarithmBase,B.getNiceNumber(Math.abs(Math.log(l)/c),!1));this.options&&0<this.options.interval?this.interval=
this.options.interval:(this.interval=B.getNiceExponent(Math.log(l)/c/(a-1),!0),b=B.getNiceNumber(linearRange/(a-1),!0));if(null===this.viewportMinimum||isNaN(this.viewportMinimum))this.viewportMinimum="axisX"===this.type?d/Math.sqrt(g):Math.pow(this.logarithmBase,this.interval*Math.floor(Math.log(d)/c/this.interval));if(null===this.viewportMaximum||isNaN(this.viewportMaximum))this.viewportMaximum="axisX"===this.type?f*Math.sqrt(g):Math.pow(this.logarithmBase,this.interval*Math.ceil(Math.log(f)/c/
this.interval));1===this.viewportMaximum&&1===this.viewportMinimum&&(1===this.options.viewportMinimum?this.viewportMaximum*=this.logarithmBase-1/this.logarithmBase:1===this.options.viewportMaximum&&(this.viewportMinimum/=this.logarithmBase-1/this.logarithmBase),this.options&&"undefined"===typeof this.options.interval&&(this.interval=B.getNiceExponent(Math.ceil(Math.log(l)/c)/(a-1)),b=B.getNiceNumber((this.viewportMaximum-this.viewportMinimum)/(a-1),!0)));if(null===this.minimum||null===this.maximum)"axisX"===
this.type?(d=null!==this.minimum?this.minimum:this.dataInfo.min,f=null!==this.maximum?this.maximum:this.dataInfo.max,1===f/d&&(l=Math.pow(this.logarithmBase,"undefined"===typeof this.options.interval?0.4:this.options.interval),f*=l,d/=l),g=Infinity!==this.dataInfo.minDiff?this.dataInfo.minDiff:f/d>this.logarithmBase?f/d*Math.pow(this.logarithmBase,0.5):this.logarithmBase):"axisY"===this.type&&(d=null!==this.minimum?this.minimum:this.dataInfo.min,f=null!==this.maximum?this.maximum:this.dataInfo.max,
isFinite(d)||isFinite(f)?1===d&&1===f?(f*=this.logarithmBase,d/=this.logarithmBase):1===f/d?(l=Math.pow(this.logarithmBase,this.interval),f*=l,d/=l):d>f?(l=Math.min(0.01*(d/f),5),1<=f?d=f/l:f=d*l):(l=Math.min(f/d*Math.pow(this.logarithmBase,0.01),Math.pow(this.logarithmBase,0.04)),1!==f&&(f*=l),1!==d&&(d/=l)):(f="undefined"===typeof this.options.interval?0:this.options.interval,d=1),g=Infinity!==this.dataInfo.minDiff?this.dataInfo.minDiff:f/d>this.logarithmBase?f/d*Math.pow(this.logarithmBase,0.5):
this.logarithmBase,this.includeZero&&(null===this.minimum||isNaN(this.minimum))&&1<d&&(d=1),this.includeZero&&(null===this.maximum||isNaN(this.maximum))&&1>f&&(f=1)),this.intervalType="number",null===this.minimum&&(this.minimum="axisX"===this.type?d/Math.sqrt(g):Math.pow(this.logarithmBase,this.interval*Math.floor(Math.log(d)/c/this.interval)),this.minimum=Math.min(this.minimum,null===this.sessionVariables.viewportMinimum||isNaN(this.sessionVariables.viewportMinimum)?"undefined"===typeof this.sessionVariables.newViewportMinimum?
Infinity:this.sessionVariables.newViewportMinimum:this.sessionVariables.viewportMinimum)),null===this.maximum&&(this.maximum="axisX"===this.type?f*Math.sqrt(g):Math.pow(this.logarithmBase,this.interval*Math.ceil(Math.log(f)/c/this.interval)),this.maximum=Math.max(this.maximum,null===this.sessionVariables.viewportMaximum||isNaN(this.sessionVariables.viewportMaximum)?"undefined"===typeof this.sessionVariables.newViewportMaximum?0:this.sessionVariables.newViewportMaximum:this.sessionVariables.viewportMaximum)),
1===this.maximum&&1===this.minimum&&(1===this.options.minimum?this.maximum*=this.logarithmBase-1/this.logarithmBase:1===this.options.maximum&&(this.minimum/=this.logarithmBase-1/this.logarithmBase));this.viewportMinimum=Math.max(this.viewportMinimum,this.minimum);this.viewportMaximum=Math.min(this.viewportMaximum,this.maximum);this.viewportMinimum>this.viewportMaximum&&(!this.options.viewportMinimum&&!this.options.minimum||this.options.viewportMaximum||this.options.maximum?this.options.viewportMinimum||
this.options.minimum||!this.options.viewportMaximum&&!this.options.maximum||(this.viewportMinimum=this.minimum=(this.options.viewportMaximum||this.options.maximum)/Math.pow(this.logarithmBase,2*Math.ceil(this.interval))):this.viewportMaximum=this.maximum=this.options.viewportMinimum||this.options.minimum);d=Math.pow(this.logarithmBase,Math.floor(Math.log(this.viewportMinimum)/(c*this.interval)+0.2)*this.interval);this.range=this.viewportMaximum/this.viewportMinimum;this.noTicks=a;if(!this.options.interval&&
this.range<Math.pow(this.logarithmBase,8>this.viewportMaximum||3>a?2:3)){for(c=Math.floor(this.viewportMinimum/b+0.5)*b;c<this.viewportMinimum;)c+=b;this.equidistantInterval=!1;this.intervalStartPosition=c;this.interval=b}else this.options.interval||(b=Math.ceil(this.interval),this.range>this.interval&&(this.interval=b,d=Math.pow(this.logarithmBase,Math.floor(Math.log(this.viewportMinimum)/(c*this.interval)+0.2)*this.interval))),this.equidistantInterval=!0,this.intervalStartPosition=d;if(!this.valueFormatString&&
(this.valueFormatString="#,##0.##",1>this.viewportMinimum)){c=Math.floor(Math.abs(Math.log(this.viewportMinimum)/Math.LN10))+2;if(isNaN(c)||!isFinite(c))c=2;if(2<c)for(b=0;b<c-2;b++)this.valueFormatString+="#"}};B.getNiceExponent=function(a,c){var b=Math.floor(Math.log(a)/Math.LN10),d=a/Math.pow(10,b),d=0>b?1>=d?1:5>=d?5:10:Math.max(Math.floor(d),1);return Number((d*Math.pow(10,b)).toFixed(20))};B.getNiceNumber=function(a,c){var b=Math.floor(Math.log(a)/Math.LN10),d=a/Math.pow(10,b);return Number(((c?
1.5>d?1:3>d?2:7>d?5:10:1>=d?1:2>=d?2:5>=d?5:10)*Math.pow(10,b)).toFixed(20))};B.prototype.getLabelStartPoint=function(){var a=G[this.intervalType+"Duration"]*this.interval,a=new Date(Math.floor(this.viewportMinimum/a)*a);if("millisecond"!==this.intervalType)if("second"===this.intervalType)0<a.getMilliseconds()&&(a.setSeconds(a.getSeconds()+1),a.setMilliseconds(0));else if("minute"===this.intervalType){if(0<a.getSeconds()||0<a.getMilliseconds())a.setMinutes(a.getMinutes()+1),a.setSeconds(0),a.setMilliseconds(0)}else if("hour"===
this.intervalType){if(0<a.getMinutes()||0<a.getSeconds()||0<a.getMilliseconds())a.setHours(a.getHours()+1),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0)}else if("day"===this.intervalType){if(0<a.getHours()||0<a.getMinutes()||0<a.getSeconds()||0<a.getMilliseconds())a.setDate(a.getDate()+1),a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0)}else if("week"===this.intervalType){if(0<a.getDay()||0<a.getHours()||0<a.getMinutes()||0<a.getSeconds()||0<a.getMilliseconds())a.setDate(a.getDate()+
(7-a.getDay())),a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0)}else if("month"===this.intervalType){if(1<a.getDate()||0<a.getHours()||0<a.getMinutes()||0<a.getSeconds()||0<a.getMilliseconds())a.setMonth(a.getMonth()+1),a.setDate(1),a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0)}else"year"===this.intervalType&&(0<a.getMonth()||1<a.getDate()||0<a.getHours()||0<a.getMinutes()||0<a.getSeconds()||0<a.getMilliseconds())&&(a.setFullYear(a.getFullYear()+1),a.setMonth(0),
a.setDate(1),a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0));return a};T(pa,L);pa.prototype.createUserOptions=function(a){if("undefined"!==typeof a||this.options._isPlaceholder){var c=0;this.parent.options._isPlaceholder&&this.parent.createUserOptions();this.options._isPlaceholder||(sa(this.parent.stripLines),c=this.parent.options.stripLines.indexOf(this.options));this.options="undefined"===typeof a?{}:a;this.parent.options.stripLines[c]=this.options}};pa.prototype.render=function(){this.ctx.save();
var a=this.parent.getPixelCoordinatesOnAxis(this.value),c=Math.abs("pixel"===this._thicknessType?this.thickness:this.parent.conversionParameters.pixelPerUnit*this.thickness);if(0<c){var b=null===this.opacity?1:this.opacity;this.ctx.strokeStyle=this.color;this.ctx.beginPath();var d=this.ctx.globalAlpha;this.ctx.globalAlpha=b;D(this.id);var f,g,l,k;this.ctx.lineWidth=c;this.ctx.setLineDash&&this.ctx.setLineDash(F(this.lineDashType,c));if("bottom"===this.parent._position||"top"===this.parent._position)f=
g=1===this.ctx.lineWidth%2?(a.x<<0)+0.5:a.x<<0,l=this.chart.plotArea.y1,k=this.chart.plotArea.y2,this.bounds={x1:f-c/2,y1:l,x2:g+c/2,y2:k};else if("left"===this.parent._position||"right"===this.parent._position)l=k=1===this.ctx.lineWidth%2?(a.y<<0)+0.5:a.y<<0,f=this.chart.plotArea.x1,g=this.chart.plotArea.x2,this.bounds={x1:f,y1:l-c/2,x2:g,y2:k+c/2};this.ctx.moveTo(f,l);this.ctx.lineTo(g,k);this.ctx.stroke();this.ctx.globalAlpha=d}this.ctx.restore()};T(R,L);R.prototype._initialize=function(){if(this.enabled){this.container=
document.createElement("div");this.container.setAttribute("class","canvasjs-chart-tooltip");this.container.style.position="absolute";this.container.style.height="auto";this.container.style.boxShadow="1px 1px 2px 2px rgba(0,0,0,0.1)";this.container.style.zIndex="1000";this.container.style.display="none";var a;a='<div style=" width: auto;height: auto;min-width: 50px;';a+="line-height: auto;";a+="margin: 0px 0px 0px 0px;";a+="padding: 5px;";a+="font-family: Calibri, Arial, Georgia, serif;";a+="font-weight: normal;";
a+="font-style: "+(t?"italic;":"normal;");a+="font-size: 14px;";a+="color: #000000;";a+="text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);";a+="text-align: left;";a+="border: 2px solid gray;";a+=t?"background: rgba(255,255,255,.9);":"background: rgb(255,255,255);";a+="text-indent: 0px;";a+="white-space: nowrap;";a+="border-radius: 5px;";a+="-moz-user-select:none;";a+="-khtml-user-select: none;";a+="-webkit-user-select: none;";a+="-ms-user-select: none;";a+="user-select: none;";t||(a+="filter: alpha(opacity = 90);",
a+="filter: progid:DXImageTransform.Microsoft.Shadow(Strength=3, Direction=135, Color='#666666');");a+='} "> Sample Tooltip</div>';this.container.innerHTML=a;this.contentDiv=this.container.firstChild;this.container.style.borderRadius=this.contentDiv.style.borderRadius;this.chart._canvasJSContainer.appendChild(this.container)}};R.prototype.mouseMoveHandler=function(a,c){this._lastUpdated&&40>(new Date).getTime()-this._lastUpdated||(this._lastUpdated=(new Date).getTime(),this._updateToolTip(a,c))};
R.prototype._updateToolTip=function(a,c,b){b="undefined"===typeof b?!0:b;this.container||this._initialize();this.enabled||this.hide();if(!this.chart.disableToolTip){if("undefined"===typeof a||"undefined"===typeof c){if(isNaN(this._prevX)||isNaN(this._prevY))return;a=this._prevX;c=this._prevY}else this._prevX=a,this._prevY=c;var d=null,f=null,g=[],l=0;if(this.shared&&this.enabled&&"none"!==this.chart.plotInfo.axisPlacement){if("xySwapped"===this.chart.plotInfo.axisPlacement){f=[];if(this.chart.axisX)for(var k=
0;k<this.chart.axisX.length;k++){for(var l=this.chart.axisX[k].convertPixelToValue({y:c}),h=null,d=0;d<this.chart.axisX[k].dataSeries.length;d++)(h=this.chart.axisX[k].dataSeries[d].getDataPointAtX(l,b))&&0<=h.index&&(h.dataSeries=this.chart.axisX[k].dataSeries[d],null!==h.dataPoint.y&&f.push(h));h=null}if(this.chart.axisX2)for(k=0;k<this.chart.axisX2.length;k++){l=this.chart.axisX2[k].convertPixelToValue({y:c});h=null;for(d=0;d<this.chart.axisX2[k].dataSeries.length;d++)(h=this.chart.axisX2[k].dataSeries[d].getDataPointAtX(l,
b))&&0<=h.index&&(h.dataSeries=this.chart.axisX2[k].dataSeries[d],null!==h.dataPoint.y&&f.push(h));h=null}}else{f=[];if(this.chart.axisX)for(k=0;k<this.chart.axisX.length;k++)for(l=this.chart.axisX[k].convertPixelToValue({x:a}),h=null,d=0;d<this.chart.axisX[k].dataSeries.length;d++)(h=this.chart.axisX[k].dataSeries[d].getDataPointAtX(l,b))&&0<=h.index&&(h.dataSeries=this.chart.axisX[k].dataSeries[d],null!==h.dataPoint.y&&f.push(h));if(this.chart.axisX2)for(k=0;k<this.chart.axisX2.length;k++)for(l=
this.chart.axisX2[k].convertPixelToValue({x:a}),h=null,d=0;d<this.chart.axisX2[k].dataSeries.length;d++)(h=this.chart.axisX2[k].dataSeries[d].getDataPointAtX(l,b))&&0<=h.index&&(h.dataSeries=this.chart.axisX2[k].dataSeries[d],null!==h.dataPoint.y&&f.push(h))}if(0===f.length)return;f.sort(function(a,b){return a.distance-b.distance});b=f[0];for(d=0;d<f.length;d++)f[d].dataPoint.x.valueOf()===b.dataPoint.x.valueOf()&&g.push(f[d]);f=null}else{if(h=this.chart.getDataPointAtXY(a,c,b))this.currentDataPointIndex=
h.dataPointIndex,this.currentSeriesIndex=h.dataSeries.index;else if(t)if(h=Na(a,c,this.chart._eventManager.ghostCtx),0<h&&"undefined"!==typeof this.chart._eventManager.objectMap[h]){h=this.chart._eventManager.objectMap[h];if("legendItem"===h.objectType)return;this.currentSeriesIndex=h.dataSeriesIndex;this.currentDataPointIndex=0<=h.dataPointIndex?h.dataPointIndex:-1}else this.currentDataPointIndex=-1;else this.currentDataPointIndex=-1;if(0<=this.currentSeriesIndex){f=this.chart.data[this.currentSeriesIndex];
h={};if(0<=this.currentDataPointIndex)d=f.dataPoints[this.currentDataPointIndex],h.dataSeries=f,h.dataPoint=d,h.index=this.currentDataPointIndex,h.distance=Math.abs(d.x-l);else{if(!this.enabled||"line"!==f.type&&"stepLine"!==f.type&&"spline"!==f.type&&"area"!==f.type&&"stepArea"!==f.type&&"splineArea"!==f.type&&"stackedArea"!==f.type&&"stackedArea100"!==f.type&&"rangeArea"!==f.type&&"rangeSplineArea"!==f.type&&"candlestick"!==f.type&&"ohlc"!==f.type)return;l=f.axisX.convertPixelToValue({x:a});h=f.getDataPointAtX(l,
b);h.dataSeries=f;this.currentDataPointIndex=h.index;d=h.dataPoint}if(!y(h.dataPoint.y))if(h.dataSeries.axisY)if(0<h.dataPoint.y.length){for(d=b=0;d<h.dataPoint.y.length;d++)h.dataPoint.y[d]<h.dataSeries.axisY.viewportMinimum?b--:h.dataPoint.y[d]>h.dataSeries.axisY.viewportMaximum&&b++;b<h.dataPoint.y.length&&b>-h.dataPoint.y.length&&g.push(h)}else"column"===f.type||"bar"===f.type?0>h.dataPoint.y?0>h.dataSeries.axisY.viewportMinimum&&h.dataSeries.axisY.viewportMaximum>=h.dataPoint.y&&g.push(h):h.dataSeries.axisY.viewportMinimum<=
h.dataPoint.y&&0<=h.dataSeries.axisY.viewportMaximum&&g.push(h):"bubble"===f.type?(b=this.chart._eventManager.objectMap[f.dataPointIds[h.index]].size/2,h.dataPoint.y>=h.dataSeries.axisY.viewportMinimum-b&&h.dataPoint.y<=h.dataSeries.axisY.viewportMaximum+b&&g.push(h)):(0<=h.dataSeries.type.indexOf("100")||"stackedColumn"===f.type||"stackedBar"===f.type||h.dataPoint.y>=h.dataSeries.axisY.viewportMinimum&&h.dataPoint.y<=h.dataSeries.axisY.viewportMaximum)&&g.push(h);else g.push(h)}}if(0<g.length&&(this.highlightObjects(g),
this.enabled))if(b="",b=this.getToolTipInnerHTML({entries:g}),null!==b){this.contentDiv.innerHTML=b;this.contentDiv.innerHTML=b;b=!1;"none"===this.container.style.display&&(b=!0,this.container.style.display="block");try{this.contentDiv.style.background=this.backgroundColor?this.backgroundColor:t?"rgba(255,255,255,.9)":"rgb(255,255,255)",this.borderColor=this.contentDiv.style.borderRightColor=this.contentDiv.style.borderLeftColor=this.contentDiv.style.borderColor=this.options.borderColor?this.options.borderColor:
g[0].dataPoint.color?g[0].dataPoint.color:g[0].dataSeries.color?g[0].dataSeries.color:g[0].dataSeries._colorSet[g[0].index%g[0].dataSeries._colorSet.length],this.contentDiv.style.borderWidth=this.borderThickness||0===this.borderThickness?this.borderThickness+"px":"2px",this.contentDiv.style.borderRadius=this.cornerRadius||0===this.cornerRadius?this.cornerRadius+"px":"5px",this.container.style.borderRadius=this.contentDiv.style.borderRadius,this.contentDiv.style.fontSize=this.fontSize||0===this.fontSize?
this.fontSize+"px":"14px",this.contentDiv.style.color=this.fontColor?this.fontColor:"#000000",this.contentDiv.style.fontFamily=this.fontFamily?this.fontFamily:"Calibri, Arial, Georgia, serif;",this.contentDiv.style.fontWeight=this.fontWeight?this.fontWeight:"normal",this.contentDiv.style.fontStyle=this.fontStyle?this.fontStyle:t?"italic":"normal"}catch(m){}"pie"===g[0].dataSeries.type||"doughnut"===g[0].dataSeries.type||"funnel"===g[0].dataSeries.type||"bar"===g[0].dataSeries.type||"rangeBar"===g[0].dataSeries.type||
"stackedBar"===g[0].dataSeries.type||"stackedBar100"===g[0].dataSeries.type?a=a-10-this.container.clientWidth:(a=g[0].dataSeries.axisX.convertValueToPixel(g[0].dataPoint.x)-this.container.clientWidth<<0,a-=10);0>a&&(a+=this.container.clientWidth+20);a+this.container.clientWidth>Math.max(this.chart.container.clientWidth,this.chart.width)&&(a=Math.max(0,Math.max(this.chart.container.clientWidth,this.chart.width)-this.container.clientWidth));a+="px";c=1!==g.length||this.shared||"line"!==g[0].dataSeries.type&&
"stepLine"!==g[0].dataSeries.type&&"spline"!==g[0].dataSeries.type&&"area"!==g[0].dataSeries.type&&"stepArea"!==g[0].dataSeries.type&&"splineArea"!==g[0].dataSeries.type?"bar"===g[0].dataSeries.type||"rangeBar"===g[0].dataSeries.type||"stackedBar"===g[0].dataSeries.type||"stackedBar100"===g[0].dataSeries.type?g[0].dataSeries.axisX.convertValueToPixel(g[0].dataPoint.x):c:g[0].dataSeries.axisY.convertValueToPixel(g[0].dataPoint.y);c=-c+10;0<c+this.container.clientHeight+5&&(c-=c+this.container.clientHeight+
5-0);this.container.style.left=a;this.container.style.bottom=c+"px";!this.animationEnabled||b?this.disableAnimation():this.enableAnimation()}else this.hide(!1)}};R.prototype.highlightObjects=function(a){var c=this.chart.overlaidCanvasCtx;this.chart.resetOverlayedCanvas();c.clearRect(0,0,this.chart.width,this.chart.height);c.save();var b=this.chart.plotArea,d=0;c.beginPath();c.rect(b.x1,b.y1,b.x2-b.x1,b.y2-b.y1);c.clip();for(b=0;b<a.length;b++){var f=a[b];if((f=this.chart._eventManager.objectMap[f.dataSeries.dataPointIds[f.index]])&&
f.objectType&&"dataPoint"===f.objectType){var d=this.chart.data[f.dataSeriesIndex],g=d.dataPoints[f.dataPointIndex],l=f.dataPointIndex;!1===g.highlightEnabled||!0!==d.highlightEnabled&&!0!==g.highlightEnabled||("line"===d.type||"stepLine"===d.type||"spline"===d.type||"scatter"===d.type||"area"===d.type||"stepArea"===d.type||"splineArea"===d.type||"stackedArea"===d.type||"stackedArea100"===d.type||"rangeArea"===d.type||"rangeSplineArea"===d.type?(g=d.getMarkerProperties(l,f.x1,f.y1,this.chart.overlaidCanvasCtx),
g.size=Math.max(1.5*g.size<<0,10),g.borderColor=g.borderColor||"#FFFFFF",g.borderThickness=g.borderThickness||Math.ceil(0.1*g.size),O.drawMarkers([g]),"undefined"!==typeof f.y2&&(g=d.getMarkerProperties(l,f.x1,f.y2,this.chart.overlaidCanvasCtx),g.size=Math.max(1.5*g.size<<0,10),g.borderColor=g.borderColor||"#FFFFFF",g.borderThickness=g.borderThickness||Math.ceil(0.1*g.size),O.drawMarkers([g]))):"bubble"===d.type?(g=d.getMarkerProperties(l,f.x1,f.y1,this.chart.overlaidCanvasCtx),g.size=f.size,g.color=
"white",g.borderColor="white",c.globalAlpha=0.3,O.drawMarkers([g]),c.globalAlpha=1):"column"===d.type||"stackedColumn"===d.type||"stackedColumn100"===d.type||"bar"===d.type||"rangeBar"===d.type||"stackedBar"===d.type||"stackedBar100"===d.type||"rangeColumn"===d.type?N(c,f.x1,f.y1,f.x2,f.y2,"white",0,null,!1,!1,!1,!1,0.3):"pie"===d.type||"doughnut"===d.type?Ha(c,f.center,f.radius,"white",d.type,f.startAngle,f.endAngle,0.3,f.percentInnerRadius):"candlestick"===d.type?(c.globalAlpha=1,c.strokeStyle=
f.color,c.lineWidth=2*f.borderThickness,d=0===c.lineWidth%2?0:0.5,c.beginPath(),c.moveTo(f.x3-d,Math.min(f.y2,f.y3)),c.lineTo(f.x3-d,Math.min(f.y1,f.y4)),c.stroke(),c.beginPath(),c.moveTo(f.x3-d,Math.max(f.y1,f.y4)),c.lineTo(f.x3-d,Math.max(f.y2,f.y3)),c.stroke(),N(c,f.x1,Math.min(f.y1,f.y4),f.x2,Math.max(f.y1,f.y4),"transparent",2*f.borderThickness,f.color,!1,!1,!1,!1),c.globalAlpha=1):"ohlc"===d.type&&(c.globalAlpha=1,c.strokeStyle=f.color,c.lineWidth=2*f.borderThickness,d=0===c.lineWidth%2?0:0.5,
c.beginPath(),c.moveTo(f.x3-d,f.y2),c.lineTo(f.x3-d,f.y3),c.stroke(),c.beginPath(),c.moveTo(f.x3,f.y1),c.lineTo(f.x1,f.y1),c.stroke(),c.beginPath(),c.moveTo(f.x3,f.y4),c.lineTo(f.x2,f.y4),c.stroke(),c.globalAlpha=1))}}c.restore();c.globalAlpha=1;c.beginPath()};R.prototype.getToolTipInnerHTML=function(a){a=a.entries;for(var c=null,b=null,d=null,f=0,g="",l=!0,k=0;k<a.length;k++)if(a[k].dataSeries.toolTipContent||a[k].dataPoint.toolTipContent){l=!1;break}if(l&&(this.content&&"function"===typeof this.content||
this.contentFormatter))a={chart:this.chart,toolTip:this.options,entries:a},c=this.contentFormatter?this.contentFormatter(a):this.content(a);else if(this.shared&&"none"!==this.chart.plotInfo.axisPlacement){for(var h=null,m="",k=0;k<a.length;k++)if(b=a[k].dataSeries,d=a[k].dataPoint,f=a[k].index,g="",0===k&&(l&&!this.content)&&(this.chart.axisX&&0<this.chart.axisX.length?m+="undefined"!==typeof this.chart.axisX[0].labels[d.x]?this.chart.axisX[0].labels[d.x]:"{x}":this.chart.axisX2&&0<this.chart.axisX2.length&&
(m+="undefined"!==typeof this.chart.axisX2[0].labels[d.x]?this.chart.axisX2[0].labels[d.x]:"{x}"),m+="</br>",m=this.chart.replaceKeywordsWithValue(m,d,b,f)),null!==d.toolTipContent&&("undefined"!==typeof d.toolTipContent||null!==b.options.toolTipContent)){if("line"===b.type||"stepLine"===b.type||"spline"===b.type||"area"===b.type||"stepArea"===b.type||"splineArea"===b.type||"column"===b.type||"bar"===b.type||"scatter"===b.type||"stackedColumn"===b.type||"stackedColumn100"===b.type||"stackedBar"===
b.type||"stackedBar100"===b.type||"stackedArea"===b.type||"stackedArea100"===b.type)this.chart.axisX&&1<this.chart.axisX.length&&(g+=h!=b.axisXIndex?b.axisX.title?b.axisX.title+"<br/>":"X:{axisXIndex}<br/>":""),g+=d.toolTipContent?d.toolTipContent:b.toolTipContent?b.toolTipContent:this.content&&"function"!==typeof this.content?this.content:"<span style='\""+(this.options.fontColor?"":"'color:{color};'")+"\"'>{name}:</span>&nbsp;&nbsp;{y}",h=b.axisXIndex;else if("bubble"===b.type)this.chart.axisX&&
1<this.chart.axisX.length&&(g+=h!=b.axisXIndex?b.axisX.title?b.axisX.title+"<br/>":"X:{axisXIndex}<br/>":""),g+=d.toolTipContent?d.toolTipContent:b.toolTipContent?b.toolTipContent:this.content&&"function"!==typeof this.content?this.content:"<span style='\""+(this.options.fontColor?"":"'color:{color};'")+"\"'>{name}:</span>&nbsp;&nbsp;{y}, &nbsp;&nbsp;{z}";else if("rangeColumn"===b.type||"rangeBar"===b.type||"rangeArea"===b.type||"rangeSplineArea"===b.type)this.chart.axisX&&1<this.chart.axisX.length&&
(g+=h!=b.axisXIndex?b.axisX.title?b.axisX.title+"<br/>":"X:{axisXIndex}<br/>":""),g+=d.toolTipContent?d.toolTipContent:b.toolTipContent?b.toolTipContent:this.content&&"function"!==typeof this.content?this.content:"<span style='\""+(this.options.fontColor?"":"'color:{color};'")+"\"'>{name}:</span>&nbsp;&nbsp;{y[0]},&nbsp;{y[1]}";else if("candlestick"===b.type||"ohlc"===b.type)this.chart.axisX&&1<this.chart.axisX.length&&(g+=h!=b.axisXIndex?b.axisX.title?b.axisX.title+"<br/>":"X:{axisXIndex}<br/>":
""),g+=d.toolTipContent?d.toolTipContent:b.toolTipContent?b.toolTipContent:this.content&&"function"!==typeof this.content?this.content:"<span style='\""+(this.options.fontColor?"":"'color:{color};'")+"\"'>{name}:</span><br/>Open: &nbsp;&nbsp;{y[0]}<br/>High: &nbsp;&nbsp;&nbsp;{y[1]}<br/>Low:&nbsp;&nbsp;&nbsp;{y[2]}<br/>Close: &nbsp;&nbsp;{y[3]}";null===c&&(c="");!0===this.reversed?(c=this.chart.replaceKeywordsWithValue(g,d,b,f)+c,k<a.length-1&&(c="</br>"+c)):(c+=this.chart.replaceKeywordsWithValue(g,
d,b,f),k<a.length-1&&(c+="</br>"))}null!==c&&(c=m+c)}else{b=a[0].dataSeries;d=a[0].dataPoint;f=a[0].index;if(null===d.toolTipContent||"undefined"===typeof d.toolTipContent&&null===b.options.toolTipContent)return null;if("line"===b.type||"stepLine"===b.type||"spline"===b.type||"area"===b.type||"stepArea"===b.type||"splineArea"===b.type||"column"===b.type||"bar"===b.type||"scatter"===b.type||"stackedColumn"===b.type||"stackedColumn100"===b.type||"stackedBar"===b.type||"stackedBar100"===b.type||"stackedArea"===
b.type||"stackedArea100"===b.type)g=d.toolTipContent?d.toolTipContent:b.toolTipContent?b.toolTipContent:this.content&&"function"!==typeof this.content?this.content:"<span style='\""+(this.options.fontColor?"":"'color:{color};'")+"\"'>"+(d.label?"{label}":"{x}")+":</span>&nbsp;&nbsp;{y}";else if("bubble"===b.type)g=d.toolTipContent?d.toolTipContent:b.toolTipContent?b.toolTipContent:this.content&&"function"!==typeof this.content?this.content:"<span style='\""+(this.options.fontColor?"":"'color:{color};'")+
"\"'>"+(d.label?"{label}":"{x}")+":</span>&nbsp;&nbsp;{y}, &nbsp;&nbsp;{z}";else if("pie"===b.type||"doughnut"===b.type||"funnel"===b.type)g=d.toolTipContent?d.toolTipContent:b.toolTipContent?b.toolTipContent:this.content&&"function"!==typeof this.content?this.content:"<span style='\""+(this.options.fontColor?"":"'color:{color};'")+"\"'>"+(d.name?"{name}:</span>&nbsp;&nbsp;":d.label?"{label}:</span>&nbsp;&nbsp;":"</span>")+"{y}";else if("rangeColumn"===b.type||"rangeBar"===b.type||"rangeArea"===b.type||
"rangeSplineArea"===b.type)g=d.toolTipContent?d.toolTipContent:b.toolTipContent?b.toolTipContent:this.content&&"function"!==typeof this.content?this.content:"<span style='\""+(this.options.fontColor?"":"'color:{color};'")+"\"'>"+(d.label?"{label}":"{x}")+" :</span>&nbsp;&nbsp;{y[0]}, &nbsp;{y[1]}";else if("candlestick"===b.type||"ohlc"===b.type)g=d.toolTipContent?d.toolTipContent:b.toolTipContent?b.toolTipContent:this.content&&"function"!==typeof this.content?this.content:"<span style='\""+(this.options.fontColor?
"":"'color:{color};'")+"\"'>"+(d.label?"{label}":"{x}")+"</span><br/>Open: &nbsp;&nbsp;{y[0]}<br/>High: &nbsp;&nbsp;&nbsp;{y[1]}<br/>Low: &nbsp;&nbsp;&nbsp;&nbsp;{y[2]}<br/>Close: &nbsp;&nbsp;{y[3]}";null===c&&(c="");c+=this.chart.replaceKeywordsWithValue(g,d,b,f)}return c};R.prototype.enableAnimation=function(){this.container.style.WebkitTransition||(this.container.style.WebkitTransition="left .2s ease-out, bottom .2s ease-out",this.container.style.MozTransition="left .2s ease-out, bottom .2s ease-out",
this.container.style.MsTransition="left .2s ease-out, bottom .2s ease-out",this.container.style.transition="left .2s ease-out, bottom .2s ease-out")};R.prototype.disableAnimation=function(){this.container.style.WebkitTransition&&(this.container.style.WebkitTransition="",this.container.style.MozTransition="",this.container.style.MsTransition="",this.container.style.transition="")};R.prototype.hide=function(a){this.container&&(this.container.style.display="none",this.currentSeriesIndex=-1,this._prevY=
this._prevX=NaN,("undefined"===typeof a||a)&&this.chart.resetOverlayedCanvas())};R.prototype.show=function(a,c,b){this._updateToolTip(a,c,"undefined"===typeof b?!1:b)};A.prototype.getPercentAndTotal=function(a,c){var b=null,d=null,f=null;if(0<=a.type.indexOf("stacked"))d=0,b=c.x.getTime?c.x.getTime():c.x,b in a.plotUnit.yTotals&&(d=a.plotUnit.yTotals[b],f=isNaN(c.y)?0:0===d?0:100*(c.y/d));else if("pie"===a.type||"doughnut"===a.type){for(i=d=0;i<a.dataPoints.length;i++)isNaN(a.dataPoints[i].y)||(d+=
a.dataPoints[i].y);f=isNaN(c.y)?0:100*(c.y/d)}return{percent:f,total:d}};A.prototype.replaceKeywordsWithValue=function(a,c,b,d,f){var g=this;f="undefined"===typeof f?0:f;if((0<=b.type.indexOf("stacked")||"pie"===b.type||"doughnut"===b.type)&&(0<=a.indexOf("#percent")||0<=a.indexOf("#total"))){var l="#percent",k="#total",h=this.getPercentAndTotal(b,c),k=isNaN(h.total)?k:h.total,l=isNaN(h.percent)?l:h.percent;do{h="";if(b.percentFormatString)h=b.percentFormatString;else{var h="#,##0.",m=Math.max(Math.ceil(Math.log(1/
Math.abs(l))/Math.LN10),2);if(isNaN(m)||!isFinite(m))m=2;for(var p=0;p<m;p++)h+="#";b.percentFormatString=h}a=a.replace("#percent",fa(l,h,g._cultureInfo));a=a.replace("#total",fa(k,b.yValueFormatString?b.yValueFormatString:"#,##0.########",g._cultureInfo))}while(0<=a.indexOf("#percent")||0<=a.indexOf("#total"))}return a.replace(/\{.*?\}|"[^"]*"|'[^']*'/g,function(a){if('"'===a[0]&&'"'===a[a.length-1]||"'"===a[0]&&"'"===a[a.length-1])return a.slice(1,a.length-1);a=ma(a.slice(1,a.length-1));a=a.replace("#index",
f);var e=null;try{var h=a.match(/(.*?)\s*\[\s*(.*?)\s*\]/);h&&0<h.length&&(e=ma(h[2]),a=ma(h[1]))}catch(k){}h=null;if("color"===a)return c.color?c.color:b.color?b.color:b._colorSet[d%b._colorSet.length];if(c.hasOwnProperty(a))h=c;else if(b.hasOwnProperty(a))h=b;else return"";h=h[a];null!==e&&(h=h[e]);if("x"===a)if("dateTime"===g.plotInfo.axisXValueType||"dateTime"===b.xValueType||c.x&&c.x.getTime){if(g.plotInfo.plotTypes[0].plotUnits[0].axisX&&!g.plotInfo.plotTypes[0].plotUnits[0].axisX.logarithmic)return Fa(h,
c.xValueFormatString?c.xValueFormatString:b.xValueFormatString?b.xValueFormatString:b.xValueFormatString=g.axisX&&g.axisX.autoValueFormatString?g.axisX.autoValueFormatString:"DD MMM YY",g._cultureInfo)}else return fa(h,c.xValueFormatString?c.xValueFormatString:b.xValueFormatString?b.xValueFormatString:b.xValueFormatString="#,##0.########",g._cultureInfo);else return"y"===a?fa(h,c.yValueFormatString?c.yValueFormatString:b.yValueFormatString?b.yValueFormatString:b.yValueFormatString="#,##0.########",
g._cultureInfo):"z"===a?fa(h,c.zValueFormatString?c.zValueFormatString:b.zValueFormatString?b.zValueFormatString:b.zValueFormatString="#,##0.########",g._cultureInfo):h})};na.prototype.reset=function(){this.lastObjectId=0;this.objectMap=[];this.rectangularRegionEventSubscriptions=[];this.previousDataPointEventObject=null;this.eventObjects=[];t&&(this.ghostCtx.clearRect(0,0,this.chart.width,this.chart.height),this.ghostCtx.beginPath())};na.prototype.getNewObjectTrackingId=function(){return++this.lastObjectId};
na.prototype.mouseEventHandler=function(a){if("mousemove"===a.type||"click"===a.type){var c=[],b=za(a),d=null;if((d=this.chart.getObjectAtXY(b.x,b.y,!1))&&"undefined"!==typeof this.objectMap[d])if(d=this.objectMap[d],"dataPoint"===d.objectType){var f=this.chart.data[d.dataSeriesIndex],g=f.dataPoints[d.dataPointIndex],l=d.dataPointIndex;d.eventParameter={x:b.x,y:b.y,dataPoint:g,dataSeries:f.options,dataPointIndex:l,dataSeriesIndex:f.index,chart:this.chart};d.eventContext={context:g,userContext:g,mouseover:"mouseover",
mousemove:"mousemove",mouseout:"mouseout",click:"click"};c.push(d);d=this.objectMap[f.id];d.eventParameter={x:b.x,y:b.y,dataPoint:g,dataSeries:f.options,dataPointIndex:l,dataSeriesIndex:f.index,chart:this.chart};d.eventContext={context:f,userContext:f.options,mouseover:"mouseover",mousemove:"mousemove",mouseout:"mouseout",click:"click"};c.push(this.objectMap[f.id])}else"legendItem"===d.objectType&&(f=this.chart.data[d.dataSeriesIndex],g=null!==d.dataPointIndex?f.dataPoints[d.dataPointIndex]:null,
d.eventParameter={x:b.x,y:b.y,dataSeries:f.options,dataPoint:g,dataPointIndex:d.dataPointIndex,dataSeriesIndex:d.dataSeriesIndex,chart:this.chart},d.eventContext={context:this.chart.legend,userContext:this.chart.legend.options,mouseover:"itemmouseover",mousemove:"itemmousemove",mouseout:"itemmouseout",click:"itemclick"},c.push(d));f=[];for(b=0;b<this.mouseoveredObjectMaps.length;b++){g=!0;for(d=0;d<c.length;d++)if(c[d].id===this.mouseoveredObjectMaps[b].id){g=!1;break}g?this.fireEvent(this.mouseoveredObjectMaps[b],
"mouseout",a):f.push(this.mouseoveredObjectMaps[b])}this.mouseoveredObjectMaps=f;for(b=0;b<c.length;b++){f=!1;for(d=0;d<this.mouseoveredObjectMaps.length;d++)if(c[b].id===this.mouseoveredObjectMaps[d].id){f=!0;break}f||(this.fireEvent(c[b],"mouseover",a),this.mouseoveredObjectMaps.push(c[b]));"click"===a.type?this.fireEvent(c[b],"click",a):"mousemove"===a.type&&this.fireEvent(c[b],"mousemove",a)}}};na.prototype.fireEvent=function(a,c,b){if(a&&c){var d=a.eventParameter,f=a.eventContext,g=a.eventContext.userContext;
g&&(f&&g[f[c]])&&g[f[c]].call(g,d);"mouseout"!==c?g.cursor&&g.cursor!==b.target.style.cursor&&(b.target.style.cursor=g.cursor):(b.target.style.cursor=this.chart._defaultCursor,delete a.eventParameter,delete a.eventContext);"click"===c&&("dataPoint"===a.objectType&&this.chart.pieDoughnutClickHandler)&&this.chart.pieDoughnutClickHandler.call(this.chart.data[a.dataSeriesIndex],d)}};T(qa,L);Ea.prototype.animate=function(a,c,b,d,f){var g=this;this.chart.isAnimating=!0;f=f||E.easing.linear;b&&this.animations.push({startTime:(new Date).getTime()+
(a?a:0),duration:c,animationCallback:b,onComplete:d});for(a=[];0<this.animations.length;)if(c=this.animations.shift(),b=(new Date).getTime(),d=0,c.startTime<=b&&(d=f(Math.min(b-c.startTime,c.duration),0,1,c.duration),d=Math.min(d,1),isNaN(d)||!isFinite(d))&&(d=1),1>d&&a.push(c),c.animationCallback(d),1<=d&&c.onComplete)c.onComplete();this.animations=a;0<this.animations.length?this.animationRequestId=this.chart.requestAnimFrame.call(window,function(){g.animate.call(g)}):this.chart.isAnimating=!1};
Ea.prototype.cancelAllAnimations=function(){this.animations=[];this.animationRequestId&&this.chart.cancelRequestAnimFrame.call(window,this.animationRequestId);this.animationRequestId=null;this.chart.isAnimating=!1};var E={yScaleAnimation:function(a,c){if(0!==a){var b=c.dest,d=c.source.canvas,f=c.animationBase;b.drawImage(d,0,0,d.width,d.height,0,f-f*a,b.canvas.width/Q,a*b.canvas.height/Q)}},xScaleAnimation:function(a,c){if(0!==a){var b=c.dest,d=c.source.canvas,f=c.animationBase;b.drawImage(d,0,0,
d.width,d.height,f-f*a,0,a*b.canvas.width/Q,b.canvas.height/Q)}},xClipAnimation:function(a,c){if(0!==a){var b=c.dest,d=c.source.canvas;b.save();0<a&&b.drawImage(d,0,0,d.width*a,d.height,0,0,d.width*a/Q,d.height/Q);b.restore()}},fadeInAnimation:function(a,c){if(0!==a){var b=c.dest,d=c.source.canvas;b.save();b.globalAlpha=a;b.drawImage(d,0,0,d.width,d.height,0,0,b.canvas.width/Q,b.canvas.height/Q);b.restore()}},easing:{linear:function(a,c,b,d){return b*a/d+c},easeOutQuad:function(a,c,b,d){return-b*
(a/=d)*(a-2)+c},easeOutQuart:function(a,c,b,d){return-b*((a=a/d-1)*a*a*a-1)+c},easeInQuad:function(a,c,b,d){return b*(a/=d)*a+c},easeInQuart:function(a,c,b,d){return b*(a/=d)*a*a*a+c}}},O={drawMarker:function(a,c,b,d,f,g,l,k){if(b){var h=1;b.fillStyle=g?g:"#000000";b.strokeStyle=l?l:"#000000";b.lineWidth=k?k:0;"circle"===d?(b.moveTo(a,c),b.beginPath(),b.arc(a,c,f/2,0,2*Math.PI,!1),g&&b.fill(),k&&(l?b.stroke():(h=b.globalAlpha,b.globalAlpha=0.15,b.strokeStyle="black",b.stroke(),b.globalAlpha=h))):
"square"===d?(b.beginPath(),b.rect(a-f/2,c-f/2,f,f),g&&b.fill(),k&&(l?b.stroke():(h=b.globalAlpha,b.globalAlpha=0.15,b.strokeStyle="black",b.stroke(),b.globalAlpha=h))):"triangle"===d?(b.beginPath(),b.moveTo(a-f/2,c+f/2),b.lineTo(a+f/2,c+f/2),b.lineTo(a,c-f/2),b.closePath(),g&&b.fill(),k&&(l?b.stroke():(h=b.globalAlpha,b.globalAlpha=0.15,b.strokeStyle="black",b.stroke(),b.globalAlpha=h)),b.beginPath()):"cross"===d&&(b.strokeStyle=g,b.lineWidth=f/4,b.beginPath(),b.moveTo(a-f/2,c-f/2),b.lineTo(a+f/
2,c+f/2),b.stroke(),b.moveTo(a+f/2,c-f/2),b.lineTo(a-f/2,c+f/2),b.stroke())}},drawMarkers:function(a){for(var c=0;c<a.length;c++){var b=a[c];O.drawMarker(b.x,b.y,b.ctx,b.type,b.size,b.color,b.borderColor,b.borderThickness)}}},Ra={Chart:A,addColorSet:function(a,c){ja[a]=c},addCultureInfo:function(a,c){ra[a]=c},formatNumber:function(a,c,b){b=b||"en";if(ra[b])return fa(a,c||"#,##0.##",new qa(b));throw"Unknown Culture Name";},formatDate:function(a,c,b){b=b||"en";if(ra[b])return Fa(a,c||"DD MMM YYYY",
new qa(b));throw"Unknown Culture Name";}};Ra.Chart.version="v1.9.10 GA";window.CanvasJS=Ra})();
/*
excanvas is used to support IE678 which do not implement HTML5 Canvas Element. You can safely remove the following excanvas code if you don't need to support older browsers.
Copyright 2006 Google Inc. https://code.google.com/p/explorercanvas/
Licensed under the Apache License, Version 2.0
*/
document.createElement("canvas").getContext||function(){function V(){return this.context_||(this.context_=new C(this))}function W(a,b,c){var g=M.call(arguments,2);return function(){return a.apply(b,g.concat(M.call(arguments)))}}function N(a){return String(a).replace(/&/g,"&amp;").replace(/"/g,"&quot;")}function O(a){a.namespaces.g_vml_||a.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml","#default#VML");a.namespaces.g_o_||a.namespaces.add("g_o_","urn:schemas-microsoft-com:office:office","#default#VML");
a.styleSheets.ex_canvas_||(a=a.createStyleSheet(),a.owningElement.id="ex_canvas_",a.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}")}function X(a){var b=a.srcElement;switch(a.propertyName){case "width":b.getContext().clearRect();b.style.width=b.attributes.width.nodeValue+"px";b.firstChild.style.width=b.clientWidth+"px";break;case "height":b.getContext().clearRect(),b.style.height=b.attributes.height.nodeValue+"px",b.firstChild.style.height=b.clientHeight+
"px"}}function Y(a){a=a.srcElement;a.firstChild&&(a.firstChild.style.width=a.clientWidth+"px",a.firstChild.style.height=a.clientHeight+"px")}function D(){return[[1,0,0],[0,1,0],[0,0,1]]}function t(a,b){for(var c=D(),g=0;3>g;g++)for(var e=0;3>e;e++){for(var f=0,d=0;3>d;d++)f+=a[g][d]*b[d][e];c[g][e]=f}return c}function P(a,b){b.fillStyle=a.fillStyle;b.lineCap=a.lineCap;b.lineJoin=a.lineJoin;b.lineWidth=a.lineWidth;b.miterLimit=a.miterLimit;b.shadowBlur=a.shadowBlur;b.shadowColor=a.shadowColor;b.shadowOffsetX=
a.shadowOffsetX;b.shadowOffsetY=a.shadowOffsetY;b.strokeStyle=a.strokeStyle;b.globalAlpha=a.globalAlpha;b.font=a.font;b.textAlign=a.textAlign;b.textBaseline=a.textBaseline;b.arcScaleX_=a.arcScaleX_;b.arcScaleY_=a.arcScaleY_;b.lineScale_=a.lineScale_}function Q(a){var b=a.indexOf("(",3),c=a.indexOf(")",b+1),b=a.substring(b+1,c).split(",");if(4!=b.length||"a"!=a.charAt(3))b[3]=1;return b}function E(a,b,c){return Math.min(c,Math.max(b,a))}function F(a,b,c){0>c&&c++;1<c&&c--;return 1>6*c?a+6*(b-a)*c:
1>2*c?b:2>3*c?a+6*(b-a)*(2/3-c):a}function G(a){if(a in H)return H[a];var b,c=1;a=String(a);if("#"==a.charAt(0))b=a;else if(/^rgb/.test(a)){c=Q(a);b="#";for(var g,e=0;3>e;e++)g=-1!=c[e].indexOf("%")?Math.floor(255*(parseFloat(c[e])/100)):+c[e],b+=v[E(g,0,255)];c=+c[3]}else if(/^hsl/.test(a)){e=c=Q(a);b=parseFloat(e[0])/360%360;0>b&&b++;g=E(parseFloat(e[1])/100,0,1);e=E(parseFloat(e[2])/100,0,1);if(0==g)g=e=b=e;else{var f=0.5>e?e*(1+g):e+g-e*g,d=2*e-f;g=F(d,f,b+1/3);e=F(d,f,b);b=F(d,f,b-1/3)}b="#"+
v[Math.floor(255*g)]+v[Math.floor(255*e)]+v[Math.floor(255*b)];c=c[3]}else b=Z[a]||a;return H[a]={color:b,alpha:c}}function C(a){this.m_=D();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.fillStyle=this.strokeStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=1*q;this.globalAlpha=1;this.font="10px sans-serif";this.textAlign="left";this.textBaseline="alphabetic";this.canvas=a;var b="width:"+a.clientWidth+"px;height:"+a.clientHeight+"px;overflow:hidden;position:absolute",
c=a.ownerDocument.createElement("div");c.style.cssText=b;a.appendChild(c);b=c.cloneNode(!1);b.style.backgroundColor="red";b.style.filter="alpha(opacity=0)";a.appendChild(b);this.element_=c;this.lineScale_=this.arcScaleY_=this.arcScaleX_=1}function R(a,b,c,g){a.currentPath_.push({type:"bezierCurveTo",cp1x:b.x,cp1y:b.y,cp2x:c.x,cp2y:c.y,x:g.x,y:g.y});a.currentX_=g.x;a.currentY_=g.y}function S(a,b){var c=G(a.strokeStyle),g=c.color,c=c.alpha*a.globalAlpha,e=a.lineScale_*a.lineWidth;1>e&&(c*=e);b.push("<g_vml_:stroke",
' opacity="',c,'"',' joinstyle="',a.lineJoin,'"',' miterlimit="',a.miterLimit,'"',' endcap="',$[a.lineCap]||"square",'"',' weight="',e,'px"',' color="',g,'" />')}function T(a,b,c,g){var e=a.fillStyle,f=a.arcScaleX_,d=a.arcScaleY_,k=g.x-c.x,n=g.y-c.y;if(e instanceof w){var h=0,l=g=0,u=0,m=1;if("gradient"==e.type_){h=e.x1_/f;c=e.y1_/d;var p=s(a,e.x0_/f,e.y0_/d),h=s(a,h,c),h=180*Math.atan2(h.x-p.x,h.y-p.y)/Math.PI;0>h&&(h+=360);1E-6>h&&(h=0)}else p=s(a,e.x0_,e.y0_),g=(p.x-c.x)/k,l=(p.y-c.y)/n,k/=f*q,
n/=d*q,m=x.max(k,n),u=2*e.r0_/m,m=2*e.r1_/m-u;f=e.colors_;f.sort(function(a,b){return a.offset-b.offset});d=f.length;p=f[0].color;c=f[d-1].color;k=f[0].alpha*a.globalAlpha;a=f[d-1].alpha*a.globalAlpha;for(var n=[],r=0;r<d;r++){var t=f[r];n.push(t.offset*m+u+" "+t.color)}b.push('<g_vml_:fill type="',e.type_,'"',' method="none" focus="100%"',' color="',p,'"',' color2="',c,'"',' colors="',n.join(","),'"',' opacity="',a,'"',' g_o_:opacity2="',k,'"',' angle="',h,'"',' focusposition="',g,",",l,'" />')}else e instanceof
I?k&&n&&b.push("<g_vml_:fill",' position="',-c.x/k*f*f,",",-c.y/n*d*d,'"',' type="tile"',' src="',e.src_,'" />'):(e=G(a.fillStyle),b.push('<g_vml_:fill color="',e.color,'" opacity="',e.alpha*a.globalAlpha,'" />'))}function s(a,b,c){a=a.m_;return{x:q*(b*a[0][0]+c*a[1][0]+a[2][0])-r,y:q*(b*a[0][1]+c*a[1][1]+a[2][1])-r}}function z(a,b,c){isFinite(b[0][0])&&(isFinite(b[0][1])&&isFinite(b[1][0])&&isFinite(b[1][1])&&isFinite(b[2][0])&&isFinite(b[2][1]))&&(a.m_=b,c&&(a.lineScale_=aa(ba(b[0][0]*b[1][1]-b[0][1]*
b[1][0]))))}function w(a){this.type_=a;this.r1_=this.y1_=this.x1_=this.r0_=this.y0_=this.x0_=0;this.colors_=[]}function I(a,b){if(!a||1!=a.nodeType||"IMG"!=a.tagName)throw new A("TYPE_MISMATCH_ERR");if("complete"!=a.readyState)throw new A("INVALID_STATE_ERR");switch(b){case "repeat":case null:case "":this.repetition_="repeat";break;case "repeat-x":case "repeat-y":case "no-repeat":this.repetition_=b;break;default:throw new A("SYNTAX_ERR");}this.src_=a.src;this.width_=a.width;this.height_=a.height}
function A(a){this.code=this[a];this.message=a+": DOM Exception "+this.code}var x=Math,k=x.round,J=x.sin,K=x.cos,ba=x.abs,aa=x.sqrt,q=10,r=q/2;navigator.userAgent.match(/MSIE ([\d.]+)?/);var M=Array.prototype.slice;O(document);var U={init:function(a){a=a||document;a.createElement("canvas");a.attachEvent("onreadystatechange",W(this.init_,this,a))},init_:function(a){a=a.getElementsByTagName("canvas");for(var b=0;b<a.length;b++)this.initElement(a[b])},initElement:function(a){if(!a.getContext){a.getContext=
V;O(a.ownerDocument);a.innerHTML="";a.attachEvent("onpropertychange",X);a.attachEvent("onresize",Y);var b=a.attributes;b.width&&b.width.specified?a.style.width=b.width.nodeValue+"px":a.width=a.clientWidth;b.height&&b.height.specified?a.style.height=b.height.nodeValue+"px":a.height=a.clientHeight}return a}};U.init();for(var v=[],d=0;16>d;d++)for(var B=0;16>B;B++)v[16*d+B]=d.toString(16)+B.toString(16);var Z={aliceblue:"#F0F8FF",antiquewhite:"#FAEBD7",aquamarine:"#7FFFD4",azure:"#F0FFFF",beige:"#F5F5DC",
bisque:"#FFE4C4",black:"#000000",blanchedalmond:"#FFEBCD",blueviolet:"#8A2BE2",brown:"#A52A2A",burlywood:"#DEB887",cadetblue:"#5F9EA0",chartreuse:"#7FFF00",chocolate:"#D2691E",coral:"#FF7F50",cornflowerblue:"#6495ED",cornsilk:"#FFF8DC",crimson:"#DC143C",cyan:"#00FFFF",darkblue:"#00008B",darkcyan:"#008B8B",darkgoldenrod:"#B8860B",darkgray:"#A9A9A9",darkgreen:"#006400",darkgrey:"#A9A9A9",darkkhaki:"#BDB76B",darkmagenta:"#8B008B",darkolivegreen:"#556B2F",darkorange:"#FF8C00",darkorchid:"#9932CC",darkred:"#8B0000",
darksalmon:"#E9967A",darkseagreen:"#8FBC8F",darkslateblue:"#483D8B",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",darkturquoise:"#00CED1",darkviolet:"#9400D3",deeppink:"#FF1493",deepskyblue:"#00BFFF",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1E90FF",firebrick:"#B22222",floralwhite:"#FFFAF0",forestgreen:"#228B22",gainsboro:"#DCDCDC",ghostwhite:"#F8F8FF",gold:"#FFD700",goldenrod:"#DAA520",grey:"#808080",greenyellow:"#ADFF2F",honeydew:"#F0FFF0",hotpink:"#FF69B4",indianred:"#CD5C5C",indigo:"#4B0082",
ivory:"#FFFFF0",khaki:"#F0E68C",lavender:"#E6E6FA",lavenderblush:"#FFF0F5",lawngreen:"#7CFC00",lemonchiffon:"#FFFACD",lightblue:"#ADD8E6",lightcoral:"#F08080",lightcyan:"#E0FFFF",lightgoldenrodyellow:"#FAFAD2",lightgreen:"#90EE90",lightgrey:"#D3D3D3",lightpink:"#FFB6C1",lightsalmon:"#FFA07A",lightseagreen:"#20B2AA",lightskyblue:"#87CEFA",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#B0C4DE",lightyellow:"#FFFFE0",limegreen:"#32CD32",linen:"#FAF0E6",magenta:"#FF00FF",mediumaquamarine:"#66CDAA",
mediumblue:"#0000CD",mediumorchid:"#BA55D3",mediumpurple:"#9370DB",mediumseagreen:"#3CB371",mediumslateblue:"#7B68EE",mediumspringgreen:"#00FA9A",mediumturquoise:"#48D1CC",mediumvioletred:"#C71585",midnightblue:"#191970",mintcream:"#F5FFFA",mistyrose:"#FFE4E1",moccasin:"#FFE4B5",navajowhite:"#FFDEAD",oldlace:"#FDF5E6",olivedrab:"#6B8E23",orange:"#FFA500",orangered:"#FF4500",orchid:"#DA70D6",palegoldenrod:"#EEE8AA",palegreen:"#98FB98",paleturquoise:"#AFEEEE",palevioletred:"#DB7093",papayawhip:"#FFEFD5",
peachpuff:"#FFDAB9",peru:"#CD853F",pink:"#FFC0CB",plum:"#DDA0DD",powderblue:"#B0E0E6",rosybrown:"#BC8F8F",royalblue:"#4169E1",saddlebrown:"#8B4513",salmon:"#FA8072",sandybrown:"#F4A460",seagreen:"#2E8B57",seashell:"#FFF5EE",sienna:"#A0522D",skyblue:"#87CEEB",slateblue:"#6A5ACD",slategray:"#708090",slategrey:"#708090",snow:"#FFFAFA",springgreen:"#00FF7F",steelblue:"#4682B4",tan:"#D2B48C",thistle:"#D8BFD8",tomato:"#FF6347",turquoise:"#40E0D0",violet:"#EE82EE",wheat:"#F5DEB3",whitesmoke:"#F5F5F5",yellowgreen:"#9ACD32"},
H={},L={},$={butt:"flat",round:"round"},d=C.prototype;d.clearRect=function(){this.textMeasureEl_&&(this.textMeasureEl_.removeNode(!0),this.textMeasureEl_=null);this.element_.innerHTML=""};d.beginPath=function(){this.currentPath_=[]};d.moveTo=function(a,b){var c=s(this,a,b);this.currentPath_.push({type:"moveTo",x:c.x,y:c.y});this.currentX_=c.x;this.currentY_=c.y};d.lineTo=function(a,b){var c=s(this,a,b);this.currentPath_.push({type:"lineTo",x:c.x,y:c.y});this.currentX_=c.x;this.currentY_=c.y};d.bezierCurveTo=
function(a,b,c,g,e,f){e=s(this,e,f);a=s(this,a,b);c=s(this,c,g);R(this,a,c,e)};d.quadraticCurveTo=function(a,b,c,g){a=s(this,a,b);c=s(this,c,g);g={x:this.currentX_+2/3*(a.x-this.currentX_),y:this.currentY_+2/3*(a.y-this.currentY_)};R(this,g,{x:g.x+(c.x-this.currentX_)/3,y:g.y+(c.y-this.currentY_)/3},c)};d.arc=function(a,b,c,g,e,f){c*=q;var d=f?"at":"wa",k=a+K(g)*c-r,n=b+J(g)*c-r;g=a+K(e)*c-r;e=b+J(e)*c-r;k!=g||f||(k+=0.125);a=s(this,a,b);k=s(this,k,n);g=s(this,g,e);this.currentPath_.push({type:d,
x:a.x,y:a.y,radius:c,xStart:k.x,yStart:k.y,xEnd:g.x,yEnd:g.y})};d.rect=function(a,b,c,g){this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+g);this.lineTo(a,b+g);this.closePath()};d.strokeRect=function(a,b,c,g){var e=this.currentPath_;this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+g);this.lineTo(a,b+g);this.closePath();this.stroke();this.currentPath_=e};d.fillRect=function(a,b,c,g){var e=this.currentPath_;this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+
c,b+g);this.lineTo(a,b+g);this.closePath();this.fill();this.currentPath_=e};d.createLinearGradient=function(a,b,c,g){var e=new w("gradient");e.x0_=a;e.y0_=b;e.x1_=c;e.y1_=g;return e};d.createRadialGradient=function(a,b,c,g,e,f){var d=new w("gradientradial");d.x0_=a;d.y0_=b;d.r0_=c;d.x1_=g;d.y1_=e;d.r1_=f;return d};d.drawImage=function(a,b){var c,g,e,d,r,y,n,h;e=a.runtimeStyle.width;d=a.runtimeStyle.height;a.runtimeStyle.width="auto";a.runtimeStyle.height="auto";var l=a.width,u=a.height;a.runtimeStyle.width=
e;a.runtimeStyle.height=d;if(3==arguments.length)c=arguments[1],g=arguments[2],r=y=0,n=e=l,h=d=u;else if(5==arguments.length)c=arguments[1],g=arguments[2],e=arguments[3],d=arguments[4],r=y=0,n=l,h=u;else if(9==arguments.length)r=arguments[1],y=arguments[2],n=arguments[3],h=arguments[4],c=arguments[5],g=arguments[6],e=arguments[7],d=arguments[8];else throw Error("Invalid number of arguments");var m=s(this,c,g),p=[];p.push(" <g_vml_:group",' coordsize="',10*q,",",10*q,'"',' coordorigin="0,0"',' style="width:',
10,"px;height:",10,"px;position:absolute;");if(1!=this.m_[0][0]||this.m_[0][1]||1!=this.m_[1][1]||this.m_[1][0]){var t=[];t.push("M11=",this.m_[0][0],",","M12=",this.m_[1][0],",","M21=",this.m_[0][1],",","M22=",this.m_[1][1],",","Dx=",k(m.x/q),",","Dy=",k(m.y/q),"");var v=s(this,c+e,g),w=s(this,c,g+d);c=s(this,c+e,g+d);m.x=x.max(m.x,v.x,w.x,c.x);m.y=x.max(m.y,v.y,w.y,c.y);p.push("padding:0 ",k(m.x/q),"px ",k(m.y/q),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",t.join(""),", sizingmethod='clip');")}else p.push("top:",
k(m.y/q),"px;left:",k(m.x/q),"px;");p.push(' ">','<g_vml_:image src="',a.src,'"',' style="width:',q*e,"px;"," height:",q*d,'px"',' cropleft="',r/l,'"',' croptop="',y/u,'"',' cropright="',(l-r-n)/l,'"',' cropbottom="',(u-y-h)/u,'"'," />","</g_vml_:group>");this.element_.insertAdjacentHTML("BeforeEnd",p.join(""))};d.stroke=function(a){var b=[];b.push("<g_vml_:shape",' filled="',!!a,'"',' style="position:absolute;width:',10,"px;height:",10,'px;"',' coordorigin="0,0"',' coordsize="',10*q,",",10*q,'"',
' stroked="',!a,'"',' path="');for(var c={x:null,y:null},d={x:null,y:null},e=0;e<this.currentPath_.length;e++){var f=this.currentPath_[e];switch(f.type){case "moveTo":b.push(" m ",k(f.x),",",k(f.y));break;case "lineTo":b.push(" l ",k(f.x),",",k(f.y));break;case "close":b.push(" x ");f=null;break;case "bezierCurveTo":b.push(" c ",k(f.cp1x),",",k(f.cp1y),",",k(f.cp2x),",",k(f.cp2y),",",k(f.x),",",k(f.y));break;case "at":case "wa":b.push(" ",f.type," ",k(f.x-this.arcScaleX_*f.radius),",",k(f.y-this.arcScaleY_*
f.radius)," ",k(f.x+this.arcScaleX_*f.radius),",",k(f.y+this.arcScaleY_*f.radius)," ",k(f.xStart),",",k(f.yStart)," ",k(f.xEnd),",",k(f.yEnd))}if(f){if(null==c.x||f.x<c.x)c.x=f.x;if(null==d.x||f.x>d.x)d.x=f.x;if(null==c.y||f.y<c.y)c.y=f.y;if(null==d.y||f.y>d.y)d.y=f.y}}b.push(' ">');a?T(this,b,c,d):S(this,b);b.push("</g_vml_:shape>");this.element_.insertAdjacentHTML("beforeEnd",b.join(""))};d.fill=function(){this.stroke(!0)};d.closePath=function(){this.currentPath_.push({type:"close"})};d.save=function(){var a=
{};P(this,a);this.aStack_.push(a);this.mStack_.push(this.m_);this.m_=t(D(),this.m_)};d.restore=function(){this.aStack_.length&&(P(this.aStack_.pop(),this),this.m_=this.mStack_.pop())};d.translate=function(a,b){z(this,t([[1,0,0],[0,1,0],[a,b,1]],this.m_),!1)};d.rotate=function(a){var b=K(a);a=J(a);z(this,t([[b,a,0],[-a,b,0],[0,0,1]],this.m_),!1)};d.scale=function(a,b){this.arcScaleX_*=a;this.arcScaleY_*=b;z(this,t([[a,0,0],[0,b,0],[0,0,1]],this.m_),!0)};d.transform=function(a,b,c,d,e,f){z(this,t([[a,
b,0],[c,d,0],[e,f,1]],this.m_),!0)};d.setTransform=function(a,b,c,d,e,f){z(this,[[a,b,0],[c,d,0],[e,f,1]],!0)};d.drawText_=function(a,b,c,d,e){var f=this.m_;d=0;var r=1E3,t=0,n=[],h;h=this.font;if(L[h])h=L[h];else{var l=document.createElement("div").style;try{l.font=h}catch(u){}h=L[h]={style:l.fontStyle||"normal",variant:l.fontVariant||"normal",weight:l.fontWeight||"normal",size:l.fontSize||10,family:l.fontFamily||"sans-serif"}}var l=h,m=this.element_;h={};for(var p in l)h[p]=l[p];p=parseFloat(m.currentStyle.fontSize);
m=parseFloat(l.size);"number"==typeof l.size?h.size=l.size:-1!=l.size.indexOf("px")?h.size=m:-1!=l.size.indexOf("em")?h.size=p*m:-1!=l.size.indexOf("%")?h.size=p/100*m:-1!=l.size.indexOf("pt")?h.size=m/0.75:h.size=p;h.size*=0.981;p=h.style+" "+h.variant+" "+h.weight+" "+h.size+"px "+h.family;m=this.element_.currentStyle;l=this.textAlign.toLowerCase();switch(l){case "left":case "center":case "right":break;case "end":l="ltr"==m.direction?"right":"left";break;case "start":l="rtl"==m.direction?"right":
"left";break;default:l="left"}switch(this.textBaseline){case "hanging":case "top":t=h.size/1.75;break;case "middle":break;default:case null:case "alphabetic":case "ideographic":case "bottom":t=-h.size/2.25}switch(l){case "right":d=1E3;r=0.05;break;case "center":d=r=500}b=s(this,b+0,c+t);n.push('<g_vml_:line from="',-d,' 0" to="',r,' 0.05" ',' coordsize="100 100" coordorigin="0 0"',' filled="',!e,'" stroked="',!!e,'" style="position:absolute;width:1px;height:1px;">');e?S(this,n):T(this,n,{x:-d,y:0},
{x:r,y:h.size});e=f[0][0].toFixed(3)+","+f[1][0].toFixed(3)+","+f[0][1].toFixed(3)+","+f[1][1].toFixed(3)+",0,0";b=k(b.x/q)+","+k(b.y/q);n.push('<g_vml_:skew on="t" matrix="',e,'" ',' offset="',b,'" origin="',d,' 0" />','<g_vml_:path textpathok="true" />','<g_vml_:textpath on="true" string="',N(a),'" style="v-text-align:',l,";font:",N(p),'" /></g_vml_:line>');this.element_.insertAdjacentHTML("beforeEnd",n.join(""))};d.fillText=function(a,b,c,d){this.drawText_(a,b,c,d,!1)};d.strokeText=function(a,
b,c,d){this.drawText_(a,b,c,d,!0)};d.measureText=function(a){this.textMeasureEl_||(this.element_.insertAdjacentHTML("beforeEnd",'<span style="position:absolute;top:-20000px;left:0;padding:0;margin:0;border:none;white-space:pre;"></span>'),this.textMeasureEl_=this.element_.lastChild);var b=this.element_.ownerDocument;this.textMeasureEl_.innerHTML="";this.textMeasureEl_.style.font=this.font;this.textMeasureEl_.appendChild(b.createTextNode(a));return{width:this.textMeasureEl_.offsetWidth}};d.clip=function(){};
d.arcTo=function(){};d.createPattern=function(a,b){return new I(a,b)};w.prototype.addColorStop=function(a,b){b=G(b);this.colors_.push({offset:a,color:b.color,alpha:b.alpha})};d=A.prototype=Error();d.INDEX_SIZE_ERR=1;d.DOMSTRING_SIZE_ERR=2;d.HIERARCHY_REQUEST_ERR=3;d.WRONG_DOCUMENT_ERR=4;d.INVALID_CHARACTER_ERR=5;d.NO_DATA_ALLOWED_ERR=6;d.NO_MODIFICATION_ALLOWED_ERR=7;d.NOT_FOUND_ERR=8;d.NOT_SUPPORTED_ERR=9;d.INUSE_ATTRIBUTE_ERR=10;d.INVALID_STATE_ERR=11;d.SYNTAX_ERR=12;d.INVALID_MODIFICATION_ERR=
13;d.NAMESPACE_ERR=14;d.INVALID_ACCESS_ERR=15;d.VALIDATION_ERR=16;d.TYPE_MISMATCH_ERR=17;G_vmlCanvasManager=U;CanvasRenderingContext2D=C;CanvasGradient=w;CanvasPattern=I;DOMException=A}();

View File

@@ -1,10 +0,0 @@
<!DOCTYPE html>
<html>
</head>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="./index.js"></script>
</head>
<body contenteditable="true">
</body>
</html>

View File

@@ -1,29 +0,0 @@
/* global Y */
window.onload = function () {
window.domBinding = new Y.DomBinding(window.yXmlType, document.body, { scrollingElement: document.scrollingElement })
}
let y = new Y('htmleditor', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
window.y = y
window.yXmlType = y.define('xml', Y.XmlFragment)
window.undoManager = new Y.utils.UndoManager(window.yXmlType, {
captureTimeout: 500
})
document.onkeydown = function interceptUndoRedo (e) {
if (e.keyCode === 90 && (e.metaKey || e.ctrlKey)) {
if (!e.shiftKey) {
window.undoManager.undo()
} else {
window.undoManager.redo()
}
e.preventDefault()
}
}

View File

@@ -1,24 +0,0 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="codeMirrorContainer"></div>
<script src="../bower_components/codemirror/lib/codemirror.js"></script>
<script src="../bower_components/codemirror/mode/javascript/javascript.js"></script>
<link rel="stylesheet" href="../bower_components/codemirror/lib/codemirror.css">
<style>
.CodeMirror {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
}
</style>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src='../../../y-indexeddb/y-indexeddb.js'></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,19 +0,0 @@
/* global Y, CodeMirror */
const persistence = new Y.IndexedDB()
const connector = {
connector: {
name: 'websockets-client',
room: 'codemirror-example'
}
}
const y = new Y('codemirror-example', connector, persistence)
window.yCodeMirror = y
var editor = CodeMirror(document.querySelector('#codeMirrorContainer'), {
mode: 'javascript',
lineNumbers: true
})
y.define('codemirror', Y.Text).bindCodeMirror(editor)

View File

@@ -1,55 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<style>
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 7px;
}
.one {
grid-column: 1 ;
}
.two {
grid-column: 2;
}
.three {
grid-column: 3;
}
textarea {
width: calc(100% - 10px)
}
.editor-container {
background-color: #4caf50;
padding: 4px 5px 10px 5px;
border-radius: 11px;
}
.editor-container[disconnected] {
background-color: red;
}
.disconnected-info {
display: none;
}
.editor-container[disconnected] .disconnected-info {
display: inline;
}
</style>
<div class="wrapper">
<div id="container1" class="one editor-container">
<h1>Server 1 <span class="disconnected-info">(disconnected)</span></h1>
<textarea id="textarea1" rows=40 autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
</div>
<div id="container2" class="two editor-container">
<h1>Server 2 <span class="disconnected-info">(disconnected)</span></h1>
<textarea id="textarea2" rows=40 autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
</div>
<div id="container3" class="three editor-container">
<h1>Server 3 <span class="disconnected-info">(disconnected)</span></h1>
<textarea id="textarea3" rows=40 autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
</div>
</div>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,38 +0,0 @@
/* global Y */
function bindYjsInstance (y, suffix) {
y.define('textarea', Y.Text).bind(document.getElementById('textarea' + suffix))
y.connector.socket.on('connection', function () {
document.getElementById('container' + suffix).removeAttribute('disconnected')
})
y.connector.socket.on('disconnect', function () {
document.getElementById('container' + suffix).setAttribute('disconnected', true)
})
}
let y1 = new Y('infinite-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
window.y1 = y1
bindYjsInstance(y1, '1')
let y2 = new Y('infinite-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
window.y2 = y2
bindYjsInstance(y2, '2')
let y3 = new Y('infinite-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
window.y3 = y3
bindYjsInstance(y1, '3')

View File

@@ -1,24 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
.draggable {
cursor: move;
}
</style>
</head>
<body>
<svg id="puzzle-example" width="100%" viewBox="0 0 800 800">
<g>
<path d="M 311.76636,154.23389 C 312.14136,171.85693 318.14087,184.97998 336.13843,184.23047 C 354.13647,183.48047 351.88647,180.48096 354.88599,178.98096 C 357.8855,177.48096 368.38452,170.35693 380.00806,169.98193 C 424.61841,168.54297 419.78296,223.6001 382.25757,223.6001 C 377.75806,223.6001 363.51001,219.10107 356.38599,211.97656 C 349.26196,204.85254 310.64185,207.10254 314.76636,236.34863 C 316.34888,247.5708 324.08374,267.90723 324.84595,286.23486 C 325.29321,296.99414 323.17603,307.00635 321.58911,315.6377 C 360.11353,305.4585 367.73462,304.30518 404.00513,312.83936 C 410.37915,314.33887 436.62573,310.21436 421.25269,290.3418 C 405.87964,270.46924 406.25464,248.34717 417.12817,240.84814 C 428.00171,233.34912 446.74976,228.84961 457.99829,234.09912 C 469.24683,239.34814 484.61987,255.84619 475.24585,271.59424 C 465.87231,287.34229 452.74878,290.7168 456.49829,303.84033 C 460.2478,316.96387 479.74536,320.33838 500.74292,321.83789 C 509.70142,322.47803 527.97192,323.28467 542.10864,320.12939 C 549.91821,318.38672 556.92212,315.89502 562.46753,313.56396 C 561.40796,277.80664 560.84888,245.71729 560.3606,241.97314 C 558.85278,230.41455 542.49536,217.28564 525.86499,223.2251 C 520.61548,225.1001 519.86548,231.84912 505.24243,232.59912 C 444.92798,235.69238 462.06958,143.26709 525.86499,180.48096 C 539.52759,188.45068 575.19409,190.7583 570.10913,156.85889 C 567.85962,141.86035 553.98608,102.86523 553.98608,102.86523 C 553.98608,102.86523 477.23755,111.82227 451.99878,91.991699 C 441.50024,83.74292 444.87476,69.494629 449.37427,61.245605 C 453.87378,52.996582 465.12231,46.622559 464.74731,36.123779 C 463.02563,-12.086426 392.96704,-10.902832 396.5061,36.873535 C 397.25562,46.997314 406.62964,52.621582 410.75415,60.495605 C 420.00757,78.161377 405.50024,96.073486 384.50757,99.490723 C 377.36206,100.65381 349.17505,102.65332 320.39429,102.23486 C 319.677,102.22461 318.95923,102.21143 318.24194,102.19775 C 315.08423,120.9751 311.55688,144.39697 311.76636,154.23389 z " style="fill:#f2c569;stroke:#000000" id="path2502"/>
<path d="M 500.74292,321.83789 C 479.74536,320.33838 460.2478,316.96387 456.49829,303.84033 C 452.74878,290.7168 465.87231,287.34229 475.24585,271.59424 C 484.61987,255.84619 469.24683,239.34814 457.99829,234.09912 C 446.74976,228.84961 428.00171,233.34912 417.12817,240.84814 C 406.25464,248.34717 405.87964,270.46924 421.25269,290.3418 C 436.62573,310.21436 410.37915,314.33887 404.00513,312.83936 C 367.73462,304.30518 360.11353,305.4585 321.58911,315.6377 C 320.56372,321.21484 319.75854,326.2207 320.01538,330.46191 C 320.76538,342.83545 329.3894,385.95508 327.8894,392.7041 C 326.3894,399.45312 313.64136,418.20117 297.89331,407.32715 C 282.14526,396.45361 276.52075,393.4541 265.27222,394.5791 C 254.02368,395.70361 239.77563,402.07812 239.77563,419.32568 C 239.77563,436.57373 250.27417,449.69727 268.64673,447.82227 C 287.36353,445.9126 317.92163,423.11035 325.63989,452.69678 C 330.1394,469.94434 330.51392,487.19238 330.1394,498.44092 C 329.95825,503.87646 326.09985,518.06592 322.16089,531.28125 C 353.2854,532.73682 386.47095,531.26611 394.2561,529.93701 C 430.30933,523.78174 429.31909,496.09766 412.62866,477.44385 C 406.25464,470.31934 401.75513,455.32129 405.87964,444.82275 C 414.07056,423.97314 458.8064,422.17773 473.37134,438.82324 C 483.86987,450.82178 475.99585,477.44385 468.49683,482.69287 C 453.52222,493.17529 457.22485,516.83008 473.37134,528.06201 C 504.79126,549.91943 572.35913,535.56152 572.35913,535.56152 C 572.35913,535.56152 567.85962,498.06592 567.48462,471.81934 C 567.10962,445.57275 589.60669,450.07227 593.3562,450.07227 C 597.10571,450.07227 604.22974,455.32129 609.47925,459.4458 C 614.72876,463.57031 618.85327,469.94434 630.85181,470.69434 C 677.43726,473.60596 674.58813,420.7373 631.97632,413.32666 C 623.35229,411.82666 614.72876,416.32617 603.10522,424.57519 C 591.48169,432.82422 577.23315,425.32519 570.10913,417.45117 C 566.07788,412.99561 563.8479,360.16406 562.46753,313.56396 C 556.92212,315.89502 549.91821,318.38672 542.10864,320.12939 C 527.97192,323.28467 509.70142,322.47803 500.74292,321.83789 z " style="fill:#f3f3d6;stroke:#000000" id="path2504"/>
<path d="M 240.52563,141.86035 C 257.60327,159.6499 243.94507,188.68799 214.65356,190.22949 C 185.09448,191.78516 164.66675,157.17822 190.28589,136.61621 C 200.49585,128.42139 198.05786,114.12158 179.78296,106.98975 C 154.4187,97.091553 90.54419,107.73975 90.54419,107.73975 C 90.54419,107.73975 100.88794,135.11328 101.41772,168.48242 C 101.79272,192.104 68.796875,189.47949 63.172607,186.85498 C 57.54834,184.23047 45.924805,173.73145 37.675781,173.73145 C -14.411865,173.73145 -10.013184,245.84375 39.925537,232.22412 C 48.174316,229.97461 56.42334,220.97559 68.796875,222.47559 C 81.17041,223.9751 87.544434,232.59912 87.544434,246.09766 C 87.544434,252.51709 87.0354,281.24268 86.340576,312.87012 C 119.15894,313.67676 160.60962,314.46582 170.03442,313.58887 C 186.15698,312.08936 195.90601,301.59033 188.40698,293.3418 C 180.90796,285.09277 156.16089,256.59619 179.03296,239.34814 C 201.90503,222.10059 235.65112,231.84912 239.77563,247.22217 C 243.90015,262.59521 240.52563,273.46924 234.90112,279.09326 C 229.27661,284.71777 210.52905,298.96582 221.40259,308.71484 C 232.27661,318.46338 263.77222,330.83691 302.39282,320.71338 C 309.58862,318.82715 315.92114,317.13525 321.58911,315.6377 C 323.17603,307.00635 325.29321,296.99414 324.84595,286.23486 C 324.08374,267.90723 316.34888,247.5708 314.76636,236.34863 C 310.64185,207.10254 349.26196,204.85254 356.38599,211.97656 C 363.51001,219.10107 377.75806,223.6001 382.25757,223.6001 C 419.78296,223.6001 424.61841,168.54297 380.00806,169.98193 C 368.38452,170.35693 357.8855,177.48096 354.88599,178.98096 C 351.88647,180.48096 354.13647,183.48047 336.13843,184.23047 C 318.14087,184.97998 312.14136,171.85693 311.76636,154.23389 C 311.55688,144.39697 315.08423,120.9751 318.24194,102.19775 C 290.37524,101.67725 262.46069,98.968262 254.39868,97.991211 C 233.38013,95.443359 217.17456,117.53662 240.52563,141.86035 z " style="fill:#bebcdb;stroke:#000000" id="path2506"/>
<path d="M 325.63989,452.69678 C 317.92163,423.11035 287.36353,445.9126 268.64673,447.82227 C 250.27417,449.69727 239.77563,436.57373 239.77563,419.32568 C 239.77563,402.07812 254.02368,395.70361 265.27222,394.5791 C 276.52075,393.4541 282.14526,396.45361 297.89331,407.32715 C 313.64136,418.20117 326.3894,399.45313 327.8894,392.7041 C 329.3894,385.95508 320.76538,342.83545 320.01538,330.46191 C 319.75855,326.2207 320.56372,321.21484 321.58911,315.6377 C 315.92114,317.13525 309.58862,318.82715 302.39282,320.71338 C 263.77222,330.83691 232.27661,318.46338 221.40259,308.71484 C 210.52905,298.96582 229.27661,284.71777 234.90112,279.09326 C 240.52563,273.46924 243.90015,262.59521 239.77563,247.22217 C 235.65112,231.84912 201.90503,222.10059 179.03296,239.34814 C 156.16089,256.59619 180.90796,285.09277 188.40698,293.3418 C 195.90601,301.59033 186.15698,312.08936 170.03442,313.58887 C 160.60962,314.46582 119.15894,313.67676 86.340576,312.87012 C 85.573975,347.74561 84.581299,386.15088 83.794922,402.07812 C 82.295166,432.44922 109.29175,422.32568 115.66577,420.82568 C 122.04028,419.32568 126.16479,409.57715 143.03735,408.45215 C 185.9231,405.59326 186.09985,466.69629 144.16235,467.69482 C 128.41431,468.06982 113.79126,451.19678 108.16675,447.44727 C 102.54272,443.69775 87.919433,442.94775 83.794922,457.9458 C 82.01709,464.41113 78.118652,481.65137 78.098144,496.18994 C 78.071045,515.38037 82.295166,531.81201 82.295166,531.81201 C 82.295166,531.81201 105.54224,526.5625 149.41187,526.5625 C 193.28149,526.5625 199.65552,547.93506 194.78101,558.80859 C 189.90649,569.68213 181.28296,568.93213 179.40796,583.18066 C 172.7063,634.11133 253.34106,631.08203 249.14917,584.68018 C 247.96948,571.62354 237.16528,571.66699 232.27661,557.68359 C 222.17944,528.80273 244.64966,523.56299 257.39819,524.68799 C 263.59351,525.23437 290.95679,529.73389 320.75757,531.21582 C 321.22437,531.23877 321.69312,531.25928 322.16089,531.28125 C 326.09985,518.06592 329.95825,503.87646 330.1394,498.44092 C 330.51392,487.19238 330.1394,469.94434 325.63989,452.69678 z " style="fill:#d3ea9d;stroke:#000000" id="path2508"/>
</g>
</svg>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="../bower_components/d3/d3.js"></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,67 +0,0 @@
/* global Y, d3 */
let y = new Y('jigsaw-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
let jigsaw = y.define('jigsaw', Y.Map)
window.yJigsaw = y
var origin // mouse start position - translation of piece
var drag = d3.behavior.drag()
.on('dragstart', function (params) {
// get the translation of the element
var translation = d3
.select(this)
.attr('transform')
.slice(10, -1)
.split(',')
.map(Number)
// mouse coordinates
var mouse = d3.mouse(this.parentNode)
origin = {
x: mouse[0] - translation[0],
y: mouse[1] - translation[1]
}
})
.on('drag', function () {
var mouse = d3.mouse(this.parentNode)
var x = mouse[0] - origin.x // =^= mouse - mouse at dragstart + translation at dragstart
var y = mouse[1] - origin.y
d3.select(this).attr('transform', 'translate(' + x + ',' + y + ')')
})
.on('dragend', function (piece, i) {
// save the current translation of the puzzle piece
var mouse = d3.mouse(this.parentNode)
var x = mouse[0] - origin.x
var y = mouse[1] - origin.y
jigsaw.set(piece, {x: x, y: y})
})
var data = ['piece1', 'piece2', 'piece3', 'piece4']
var pieces = d3.select(document.querySelector('#puzzle-example')).selectAll('path').data(data)
pieces
.classed('draggable', true)
.attr('transform', function (piece) {
var translation = piece.get('translation') || {x: 0, y: 0}
return 'translate(' + translation.x + ',' + translation.y + ')'
}).call(drag)
data.forEach(function (piece) {
jigsaw.observe(function () {
// whenever a property of a piece changes, update the translation of the pieces
pieces
.transition()
.attr('transform', function (piece) {
var translation = piece.get(piece)
if (translation == null || typeof translation.x !== 'number' || typeof translation.y !== 'number') {
translation = { x: 0, y: 0 }
}
return 'translate(' + translation.x + ',' + translation.y + ')'
})
})
})

View File

@@ -1,21 +0,0 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="monacoContainer"></div>
<style>
#monacoContainer {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
}
</style>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="../node_modules/monaco-editor/min/vs/loader.js"></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,22 +0,0 @@
/* global Y, monaco */
require.config({ paths: { 'vs': '../node_modules/monaco-editor/min/vs' } })
let y = new Y('monaco-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
require(['vs/editor/editor.main'], function () {
window.yMonaco = y
// Create Monaco editor
var editor = monaco.editor.create(document.getElementById('monacoContainer'), {
language: 'javascript'
})
// Bind to y.share.monaco
y.define('monaco', Y.Text).bindMonaco(editor)
})

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +0,0 @@
{
"name": "examples",
"version": "0.0.0",
"description": "",
"scripts": {
"dist": "rollup -c",
"watch": "rollup -cw"
},
"author": "Kevin Jahns",
"license": "MIT",
"dependencies": {
"monaco-editor": "^0.8.3",
"rollup": "^0.52.3"
},
"devDependencies": {
"standard": "^10.0.2"
},
"standard": {
"ignore": [
"bower_components"
]
}
}

View File

@@ -0,0 +1,159 @@
import { Plugin } from 'prosemirror-state'
import crel from 'crel'
import * as Y from '../src/index.js'
import { prosemirrorPluginKey } from 'y-prosemirror'
import * as encoding from 'lib0/encoding.js'
import * as decoding from 'lib0/decoding.js'
import * as historyProtocol from 'y-protocols/history.js'
const niceColors = ['#3cb44b', '#4363d8', '#f58231', '#911eb4', '#46f0f0', '#f032e6', '#bcf60c', '#008080', '#9a6324', '#800000', '#808000', '#000075', '#808080']
const createUserCSS = (userid, username, color = 'rgb(250, 129, 0)', color2 = 'rgba(250, 129, 0, .41)') => `
[ychange_state][ychange_user="${userid}"]:hover::before {
content: "${username}" !important;
background-color: ${color} !important;
}
[ychange_state="added"][ychange_user="${userid}"] {
background-color: ${color2} !important;
}
[ychange_state="removed"][ychange_user="${userid}"] {
color: ${color} !important;
}
`
export const noteHistoryPlugin = new Plugin({
state: {
init (initargs, state) {
return new NoteHistoryPlugin()
},
apply (tr, pluginState) {
return pluginState
}
},
view (editorView) {
const hstate = noteHistoryPlugin.getState(editorView.state)
hstate.init(editorView)
return {
destroy: hstate.destroy.bind(hstate)
}
}
})
const createWrapper = () => {
const wrapper = crel('div', { style: 'display: flex;' })
const historyContainer = crel('div', { style: 'align-self: baseline; flex-basis: 250px;', class: 'shared-history' })
wrapper.insertBefore(historyContainer, null)
const userStyleContainer = crel('style')
wrapper.insertBefore(userStyleContainer, null)
return { wrapper, historyContainer, userStyleContainer }
}
class NoteHistoryPlugin {
init (editorView) {
this.editorView = editorView
const { historyContainer, wrapper, userStyleContainer } = createWrapper()
this.userStyleContainer = userStyleContainer
this.wrapper = wrapper
this.historyContainer = historyContainer
const n = editorView.dom.parentNode.parentNode
n.parentNode.replaceChild(this.wrapper, n)
n.style['flex-grow'] = '1'
wrapper.insertBefore(n, this.wrapper.firstChild)
this.render()
const y = prosemirrorPluginKey.getState(this.editorView.state).y
const history = y.define('history', Y.Array)
history.observe(this.render.bind(this))
}
destroy () {
this.wrapper.parentNode.replaceChild(this.wrapper.firstChild, this.wrapper)
const y = prosemirrorPluginKey.getState(this.editorView.state).y
const history = y.define('history', Y.Array)
history.unobserve(this.render)
}
render () {
const y = prosemirrorPluginKey.getState(this.editorView.state).y
const history = y.define('history', Y.Array).toArray()
const fragment = document.createDocumentFragment()
const snapshotBtn = crel('button', { type: 'button' }, ['snapshot'])
fragment.insertBefore(snapshotBtn, null)
let _prevSnap = null // empty
snapshotBtn.addEventListener('click', () => {
const awareness = y.getAwarenessInfo()
const userMap = new Map()
const aw = y.getLocalAwarenessInfo()
userMap.set(y.userID, aw.name || 'unknown')
awareness.forEach((a, userID) => {
userMap.set(userID, a.name || 'Unknown')
})
this.snapshot(userMap)
})
history.forEach(buf => {
const decoder = decoding.createDecoder(buf)
const snapshot = historyProtocol.readHistorySnapshot(decoder)
const date = new Date(decoding.readUint32(decoder) * 1000)
const restoreBtn = crel('button', { type: 'button' }, ['restore'])
const a = crel('a', [
'• ' + date.toUTCString(), restoreBtn
])
const el = crel('div', [ a ])
let prevSnapshot = _prevSnap // rebind to new variable
restoreBtn.addEventListener('click', event => {
if (prevSnapshot === null) {
prevSnapshot = { ds: snapshot.ds, sm: new Map() }
}
this.editorView.dispatch(this.editorView.state.tr.setMeta(prosemirrorPluginKey, { snapshot, prevSnapshot, restore: true }))
event.stopPropagation()
})
a.addEventListener('click', () => {
console.log('setting snapshot')
if (prevSnapshot === null) {
prevSnapshot = { ds: snapshot.ds, sm: new Map() }
}
this.renderSnapshot(snapshot, prevSnapshot)
})
fragment.insertBefore(el, null)
_prevSnap = snapshot
})
this.historyContainer.innerHTML = ''
this.historyContainer.insertBefore(fragment, null)
}
renderSnapshot (snapshot, prevSnapshot) {
this.editorView.dispatch(this.editorView.state.tr.setMeta(prosemirrorPluginKey, { snapshot, prevSnapshot }))
/**
* @type {Array<string|null>}
*/
let colors = niceColors.slice()
let style = ''
snapshot.userMap.forEach((name, userid) => {
/**
* @type {any}
*/
const randInt = name.split('').map(s => s.charCodeAt(0)).reduce((a, b) => a + b)
let color = null
let i = 0
for (; i < colors.length && color === null; i++) {
color = colors[(randInt + i) % colors.length]
}
if (color === null) {
colors = niceColors.slice()
i = 0
color = colors[randInt % colors.length]
}
colors[randInt % colors.length] = null
style += createUserCSS(userid, name, color, color + '69')
})
this.userStyleContainer.innerHTML = style
}
/**
* @param {Map<number, string>} [updatedUserMap] Maps from userid (yjs model) to account name (e.g. mail address)
*/
snapshot (updatedUserMap = new Map()) {
const y = prosemirrorPluginKey.getState(this.editorView.state).y
const history = y.define('history', Y.Array)
const encoder = encoding.createEncoder()
historyProtocol.writeHistorySnapshot(encoder, y, updatedUserMap)
encoding.writeUint32(encoder, Math.floor(Date.now() / 1000))
history.push([encoding.toBuffer(encoder)])
}
}

View File

@@ -0,0 +1,197 @@
import { Schema } from 'prosemirror-model'
const brDOM = ['br']
const calcYchangeDomAttrs = (attrs, domAttrs = {}) => {
domAttrs = Object.assign({}, domAttrs)
if (attrs.ychange !== null) {
domAttrs.ychange_user = attrs.ychange.user
domAttrs.ychange_state = attrs.ychange.state
}
return domAttrs
}
// :: Object
// [Specs](#model.NodeSpec) for the nodes defined in this schema.
export const nodes = {
// :: NodeSpec The top level document node.
doc: {
content: 'block+'
},
// :: NodeSpec A plain paragraph textblock. Represented in the DOM
// as a `<p>` element.
paragraph: {
attrs: { ychange: { default: null } },
content: 'inline*',
group: 'block',
parseDOM: [{ tag: 'p' }],
toDOM (node) { return ['p', calcYchangeDomAttrs(node.attrs), 0] }
},
// :: NodeSpec A blockquote (`<blockquote>`) wrapping one or more blocks.
blockquote: {
attrs: { ychange: { default: null } },
content: 'block+',
group: 'block',
defining: true,
parseDOM: [{ tag: 'blockquote' }],
toDOM (node) { return ['blockquote', calcYchangeDomAttrs(node.attrs), 0] }
},
// :: NodeSpec A horizontal rule (`<hr>`).
horizontal_rule: {
attrs: { ychange: { default: null } },
group: 'block',
parseDOM: [{ tag: 'hr' }],
toDOM (node) {
return ['hr', calcYchangeDomAttrs(node.attrs)]
}
},
// :: NodeSpec A heading textblock, with a `level` attribute that
// should hold the number 1 to 6. Parsed and serialized as `<h1>` to
// `<h6>` elements.
heading: {
attrs: {
level: { default: 1 },
ychange: { default: null }
},
content: 'inline*',
group: 'block',
defining: true,
parseDOM: [{ tag: 'h1', attrs: { level: 1 } },
{ tag: 'h2', attrs: { level: 2 } },
{ tag: 'h3', attrs: { level: 3 } },
{ tag: 'h4', attrs: { level: 4 } },
{ tag: 'h5', attrs: { level: 5 } },
{ tag: 'h6', attrs: { level: 6 } }],
toDOM (node) { return ['h' + node.attrs.level, calcYchangeDomAttrs(node.attrs), 0] }
},
// :: NodeSpec A code listing. Disallows marks or non-text inline
// nodes by default. Represented as a `<pre>` element with a
// `<code>` element inside of it.
code_block: {
attrs: { ychange: { default: null } },
content: 'text*',
marks: '',
group: 'block',
code: true,
defining: true,
parseDOM: [{ tag: 'pre', preserveWhitespace: 'full' }],
toDOM (node) { return ['pre', calcYchangeDomAttrs(node.attrs), ['code', 0]] }
},
// :: NodeSpec The text node.
text: {
group: 'inline'
},
// :: NodeSpec An inline image (`<img>`) node. Supports `src`,
// `alt`, and `href` attributes. The latter two default to the empty
// string.
image: {
inline: true,
attrs: {
ychange: { default: null },
src: {},
alt: { default: null },
title: { default: null }
},
group: 'inline',
draggable: true,
parseDOM: [{ tag: 'img[src]',
getAttrs (dom) {
return {
src: dom.getAttribute('src'),
title: dom.getAttribute('title'),
alt: dom.getAttribute('alt')
}
} }],
toDOM (node) {
const domAttrs = {
src: node.attrs.src,
title: node.attrs.title,
alt: node.attrs.alt
}
return ['img', calcYchangeDomAttrs(node.attrs, domAttrs)]
}
},
// :: NodeSpec A hard line break, represented in the DOM as `<br>`.
hard_break: {
inline: true,
group: 'inline',
selectable: false,
parseDOM: [{ tag: 'br' }],
toDOM () { return brDOM }
}
}
const emDOM = ['em', 0]; const strongDOM = ['strong', 0]; const codeDOM = ['code', 0]
// :: Object [Specs](#model.MarkSpec) for the marks in the schema.
export const marks = {
// :: MarkSpec A link. Has `href` and `title` attributes. `title`
// defaults to the empty string. Rendered and parsed as an `<a>`
// element.
link: {
attrs: {
href: {},
title: { default: null }
},
inclusive: false,
parseDOM: [{ tag: 'a[href]',
getAttrs (dom) {
return { href: dom.getAttribute('href'), title: dom.getAttribute('title') }
} }],
toDOM (node) { return ['a', node.attrs, 0] }
},
// :: MarkSpec An emphasis mark. Rendered as an `<em>` element.
// Has parse rules that also match `<i>` and `font-style: italic`.
em: {
parseDOM: [{ tag: 'i' }, { tag: 'em' }, { style: 'font-style=italic' }],
toDOM () { return emDOM }
},
// :: MarkSpec A strong mark. Rendered as `<strong>`, parse rules
// also match `<b>` and `font-weight: bold`.
strong: {
parseDOM: [{ tag: 'strong' },
// This works around a Google Docs misbehavior where
// pasted content will be inexplicably wrapped in `<b>`
// tags with a font-weight normal.
{ tag: 'b', getAttrs: node => node.style.fontWeight !== 'normal' && null },
{ style: 'font-weight', getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null }],
toDOM () { return strongDOM }
},
// :: MarkSpec Code font mark. Represented as a `<code>` element.
code: {
parseDOM: [{ tag: 'code' }],
toDOM () { return codeDOM }
},
ychange: {
attrs: {
user: { default: null },
state: { default: null }
},
inclusive: false,
parseDOM: [{ tag: 'ychange' }],
toDOM (node) {
return ['ychange', { ychange_user: node.attrs.user, ychange_state: node.attrs.state }, 0]
}
}
}
// :: Schema
// This schema rougly corresponds to the document schema used by
// [CommonMark](http://commonmark.org/), minus the list elements,
// which are defined in the [`prosemirror-schema-list`](#schema-list)
// module.
//
// To reuse elements from this schema, extend or read from its
// `spec.nodes` and `spec.marks` [properties](#model.Schema.spec).
export const schema = new Schema({ nodes, marks })

330
examples/prosemirror.css Normal file
View File

@@ -0,0 +1,330 @@
.ProseMirror {
position: relative;
}
.ProseMirror {
word-wrap: break-word;
white-space: pre-wrap;
-webkit-font-variant-ligatures: none;
font-variant-ligatures: none;
}
.ProseMirror pre {
white-space: pre-wrap;
}
.ProseMirror li {
position: relative;
}
.ProseMirror-hideselection *::selection { background: transparent; }
.ProseMirror-hideselection *::-moz-selection { background: transparent; }
.ProseMirror-hideselection { caret-color: transparent; }
.ProseMirror-selectednode {
outline: 2px solid #8cf;
}
/* Make sure li selections wrap around markers */
li.ProseMirror-selectednode {
outline: none;
}
li.ProseMirror-selectednode:after {
content: "";
position: absolute;
left: -32px;
right: -2px; top: -2px; bottom: -2px;
border: 2px solid #8cf;
pointer-events: none;
}
.ProseMirror-textblock-dropdown {
min-width: 3em;
}
.ProseMirror-menu {
margin: 0 -4px;
line-height: 1;
}
.ProseMirror-tooltip .ProseMirror-menu {
width: -webkit-fit-content;
width: fit-content;
white-space: pre;
}
.ProseMirror-menuitem {
margin-right: 3px;
display: inline-block;
}
.ProseMirror-menuseparator {
border-right: 1px solid #ddd;
margin-right: 3px;
}
.ProseMirror-menu-dropdown, .ProseMirror-menu-dropdown-menu {
font-size: 90%;
white-space: nowrap;
}
.ProseMirror-menu-dropdown {
vertical-align: 1px;
cursor: pointer;
position: relative;
padding-right: 15px;
}
.ProseMirror-menu-dropdown-wrap {
padding: 1px 0 1px 4px;
display: inline-block;
position: relative;
}
.ProseMirror-menu-dropdown:after {
content: "";
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid currentColor;
opacity: .6;
position: absolute;
right: 4px;
top: calc(50% - 2px);
}
.ProseMirror-menu-dropdown-menu, .ProseMirror-menu-submenu {
position: absolute;
background: white;
color: #666;
border: 1px solid #aaa;
padding: 2px;
}
.ProseMirror-menu-dropdown-menu {
z-index: 15;
min-width: 6em;
}
.ProseMirror-menu-dropdown-item {
cursor: pointer;
padding: 2px 8px 2px 4px;
}
.ProseMirror-menu-dropdown-item:hover {
background: #f2f2f2;
}
.ProseMirror-menu-submenu-wrap {
position: relative;
margin-right: -4px;
}
.ProseMirror-menu-submenu-label:after {
content: "";
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
border-left: 4px solid currentColor;
opacity: .6;
position: absolute;
right: 4px;
top: calc(50% - 4px);
}
.ProseMirror-menu-submenu {
display: none;
min-width: 4em;
left: 100%;
top: -3px;
}
.ProseMirror-menu-active {
background: #eee;
border-radius: 4px;
}
.ProseMirror-menu-active {
background: #eee;
border-radius: 4px;
}
.ProseMirror-menu-disabled {
opacity: .3;
}
.ProseMirror-menu-submenu-wrap:hover .ProseMirror-menu-submenu, .ProseMirror-menu-submenu-wrap-active .ProseMirror-menu-submenu {
display: block;
}
.ProseMirror-menubar {
border-top-left-radius: inherit;
border-top-right-radius: inherit;
position: relative;
min-height: 1em;
color: #666;
padding: 1px 6px;
top: 0; left: 0; right: 0;
border-bottom: 1px solid silver;
background: white;
z-index: 10;
-moz-box-sizing: border-box;
box-sizing: border-box;
overflow: visible;
}
.ProseMirror-icon {
display: inline-block;
line-height: .8;
vertical-align: -2px; /* Compensate for padding */
padding: 2px 8px;
cursor: pointer;
}
.ProseMirror-menu-disabled.ProseMirror-icon {
cursor: default;
}
.ProseMirror-icon svg {
fill: currentColor;
height: 1em;
}
.ProseMirror-icon span {
vertical-align: text-top;
}
.ProseMirror-gapcursor {
display: none;
pointer-events: none;
position: absolute;
}
.ProseMirror-gapcursor:after {
content: "";
display: block;
position: absolute;
top: -2px;
width: 20px;
border-top: 1px solid black;
animation: ProseMirror-cursor-blink 1.1s steps(2, start) infinite;
}
@keyframes ProseMirror-cursor-blink {
to {
visibility: hidden;
}
}
.ProseMirror-focused .ProseMirror-gapcursor {
display: block;
}
/* Add space around the hr to make clicking it easier */
.ProseMirror-example-setup-style hr {
padding: 2px 10px;
border: none;
margin: 1em 0;
}
.ProseMirror-example-setup-style hr:after {
content: "";
display: block;
height: 1px;
background-color: silver;
line-height: 2px;
}
.ProseMirror ul, .ProseMirror ol {
padding-left: 30px;
}
.ProseMirror blockquote {
padding-left: 1em;
border-left: 3px solid #eee;
margin-left: 0; margin-right: 0;
}
.ProseMirror-example-setup-style img {
cursor: default;
}
.ProseMirror-prompt {
background: white;
padding: 5px 10px 5px 15px;
border: 1px solid silver;
position: fixed;
border-radius: 3px;
z-index: 11;
box-shadow: -.5px 2px 5px rgba(0, 0, 0, .2);
}
.ProseMirror-prompt h5 {
margin: 0;
font-weight: normal;
font-size: 100%;
color: #444;
}
.ProseMirror-prompt input[type="text"],
.ProseMirror-prompt textarea {
background: #eee;
border: none;
outline: none;
}
.ProseMirror-prompt input[type="text"] {
padding: 0 4px;
}
.ProseMirror-prompt-close {
position: absolute;
left: 2px; top: 1px;
color: #666;
border: none; background: transparent; padding: 0;
}
.ProseMirror-prompt-close:after {
content: "✕";
font-size: 12px;
}
.ProseMirror-invalid {
background: #ffc;
border: 1px solid #cc7;
border-radius: 4px;
padding: 5px 10px;
position: absolute;
min-width: 10em;
}
.ProseMirror-prompt-buttons {
margin-top: 5px;
display: none;
}
#editor, .editor {
background: white;
color: black;
background-clip: padding-box;
border-radius: 4px;
border: 2px solid rgba(0, 0, 0, 0.2);
padding: 5px 0;
margin-bottom: 23px;
}
.ProseMirror p:first-child,
.ProseMirror h1:first-child,
.ProseMirror h2:first-child,
.ProseMirror h3:first-child,
.ProseMirror h4:first-child,
.ProseMirror h5:first-child,
.ProseMirror h6:first-child {
margin-top: 10px;
}
.ProseMirror {
padding: 4px 8px 4px 14px;
line-height: 1.2;
outline: none;
}
.ProseMirror p { margin-bottom: 1em }

117
examples/prosemirror.html Normal file
View File

@@ -0,0 +1,117 @@
<!DOCTYPE html>
<html>
<head>
<title>Yjs Prosemirror Example</title>
<link rel=stylesheet href="./prosemirror.css">
<style>
placeholder {
display: inline;
border: 1px solid #ccc;
color: #ccc;
}
placeholder:after {
content: "☁";
font-size: 200%;
line-height: 0.1;
font-weight: bold;
}
.ProseMirror img { max-width: 100px }
/* this is a rough fix for the first cursor position when the first paragraph is empty */
.ProseMirror > .ProseMirror-yjs-cursor:first-child {
margin-top: 16px;
}
.ProseMirror p:first-child, .ProseMirror h1:first-child, .ProseMirror h2:first-child, .ProseMirror h3:first-child, .ProseMirror h4:first-child, .ProseMirror h5:first-child, .ProseMirror h6:first-child {
margin-top: 16px
}
.ProseMirror-yjs-cursor {
position: absolute;
border-left: black;
border-left-style: solid;
border-left-width: 2px;
border-color: orange;
height: 1em;
word-break: normal;
}
.ProseMirror-yjs-cursor > div {
position: relative;
top: -1.05em;
font-size: 13px;
background-color: rgb(250, 129, 0);
font-family: serif;
font-style: normal;
font-weight: normal;
line-height: normal;
user-select: none;
color: white;
padding-left: 2px;
padding-right: 2px;
}
[ychange_state] {
position: relative;
}
[ychange_state]:hover::before {
content: attr(ychange_user);
background-color: #fa8100;
position: absolute;
top: -14px;
right: 0;
font-size: 12px;
padding: 0 2px;
border-radius: 3px 3px 0 0;
color: #fdfdfe;
user-select: none;
word-break: normal;
}
*[ychange_state='added'] {
background-color: #fa810069;
}
ychange[ychange_state='removed'] {
color: rgb(250, 129, 0);
text-decoration: line-through;
}
*:not(ychange)[ychange_state='removed'] {
background-color: #ff9494c9;
text-decoration: line-through;
}
img[ychange_state='removed'] {
padding: 2px;
}
</style>
</head>
<body>
<p>This example shows how to bind a YXmlFragment type to a <a href="http://prosemirror.net">Prosemirror</a> editor.</p>
<p>The content of this editor is shared with every client who visits this domain.</p>
<div class="code-html">
<div id="editor" style="margin-bottom: 23px"></div>
<div style="display: none" id="content"></div>
</div>
<!-- The actual source file for the following code is found in ./prosemirror.js. Run `npm run watch` to compile the files -->
<script class="code-js" src="./build/prosemirror.js" type="module">
import * as Y from 'yjs'
import { WebsocketProvider } from 'yjs/provider/websocket.js'
import { prosemirrorPlugin, cursorPlugin } from 'yjs/bindings/prosemirror'
import * as conf from './exampleConfig.js'
import { EditorState } from 'prosemirror-state'
import { EditorView } from 'prosemirror-view'
import { DOMParser } from 'prosemirror-model'
import { schema } from 'prosemirror-schema-basic'
import { exampleSetup } from 'prosemirror-example-setup'
const provider = new WebsocketProvider(conf.serverAddress)
const ydocument = provider.get('prosemirror')
const type = ydocument.define('prosemirror', Y.XmlFragment)
const prosemirrorView = new EditorView(document.querySelector('#editor'), {
state: EditorState.create({
doc: DOMParser.fromSchema(schema).parse(document.querySelector('#content')),
plugins: exampleSetup({schema}).concat([prosemirrorPlugin(type), cursorPlugin])
})
})
window.example = { provider, ydocument, type, prosemirrorView }
</script>
</body>
</html>

25
examples/prosemirror.js Normal file
View File

@@ -0,0 +1,25 @@
import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket'
import { prosemirrorPlugin, cursorPlugin } from 'y-prosemirror'
import * as conf from './exampleConfig.js'
import { EditorState } from 'prosemirror-state'
import { EditorView } from 'prosemirror-view'
import { DOMParser } from 'prosemirror-model'
import { schema } from './prosemirror-schema.js'
import { exampleSetup } from 'prosemirror-example-setup'
// import { noteHistoryPlugin } from './prosemirror-history.js'
const provider = new WebsocketProvider(conf.serverAddress)
const ydocument = provider.get('prosemirror', { gc: false })
const type = ydocument.define('prosemirror', Y.XmlFragment)
const prosemirrorView = new EditorView(document.querySelector('#editor'), {
state: EditorState.create({
doc: DOMParser.fromSchema(schema).parse(document.querySelector('#content')),
plugins: exampleSetup({ schema }).concat([prosemirrorPlugin(type), cursorPlugin])
})
})
window.example = { provider, ydocument, type, prosemirrorView }

View File

@@ -1,21 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<!-- Main quill library -->
<script src="../../node_modules/quill/dist/quill.min.js"></script>
<link href="../../node_modules/quill/dist/quill.snow.css" rel="stylesheet">
<!-- Quill cursors module -->
<script src="../../node_modules/quill-cursors/dist/quill-cursors.min.js"></script>
<link href="../../node_modules/quill-cursors/dist/quill-cursors.css" rel="stylesheet">
<!-- Yjs Library and connector -->
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
</head>
<body>
<div id="quill-container">
<div id="quill">
</div>
</div>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,78 +0,0 @@
/* global Y, Quill, QuillCursors */
Quill.register('modules/cursors', QuillCursors)
let y = new Y('quill-0', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
let users = y.define('users', Y.Array)
let myUserInfo = new Y.Map()
myUserInfo.set('name', 'dada')
myUserInfo.set('color', 'red')
users.push([myUserInfo])
let quill = new Quill('#quill-container', {
modules: {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block'],
[{ color: [] }, { background: [] }], // Snow theme fills in values
[{ script: 'sub' }, { script: 'super' }],
['link', 'image'],
['link', 'code-block'],
[{ list: 'ordered' }, { list: 'bullet' }]
],
cursors: {
hideDelay: 500
}
},
placeholder: 'Compose an epic...',
theme: 'snow' // or 'bubble'
})
let cursors = quill.getModule('cursors')
function drawCursors () {
cursors.clearCursors()
users.map((user, userId) => {
if (user !== myUserInfo) {
let relativeRange = user.get('range')
let lastUpdated = new Date(user.get('last updated'))
if (lastUpdated != null && new Date() - lastUpdated < 20000 && relativeRange != null) {
let start = Y.utils.fromRelativePosition(y, relativeRange.start).offset
let end = Y.utils.fromRelativePosition(y, relativeRange.end).offset
let range = { index: start, length: end - start }
cursors.setCursor(userId + '', range, user.get('name'), user.get('color'))
}
}
})
}
users.observeDeep(drawCursors)
drawCursors()
quill.on('selection-change', function (range) {
if (range != null) {
myUserInfo.set('range', {
start: Y.utils.getRelativePosition(yText, range.index),
end: Y.utils.getRelativePosition(yText, range.index + range.length)
})
} else {
myUserInfo.delete('range')
}
myUserInfo.set('last updated', new Date().toString())
})
let yText = y.define('quill', Y.Text)
let quillBinding = new Y.QuillBinding(yText, quill)
window.quillBinding = quillBinding
window.yText = yText
window.y = y
window.quill = quill
window.users = users
window.cursors = cursors

51
examples/quill.html Normal file
View File

@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<title>Yjs Quill Example</title>
<link rel="stylesheet" href="https://cdn.quilljs.com/1.3.6/quill.snow.css">
</head>
<body>
<p>This example shows how to bind a YText type to <a href="https://quilljs.com">Quill</a> editor.</p>
<p>The content of this editor is shared with every client who visits this domain.</p>
<div class="code-html">
<div id="quill-container">
<div id="quill">
</div>
</div>
</div>
<!-- The actual source file for the following code is found in ./quill.js. Run `npm run watch` to compile the files -->
<script class="code-js" src="./build/quill.js" type="module">
import * as Y from 'yjs'
import { WebsocketProvider } from 'yjs/provider/websocket.js'
import { QuillBinding } from 'yjs/bindings/quill.js'
import * as conf from './exampleConfig.js'
import Quill from 'quill'
const provider = new WebsocketProvider(conf.serverAddress)
const ydocument = provider.get('quill')
const ytext = ydocument.define('quill', Y.Text)
const quill = new Quill('#quill-container', {
modules: {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block'],
[{ color: [] }, { background: [] }], // Snow theme fills in values
[{ script: 'sub' }, { script: 'super' }],
['link', 'image'],
['link', 'code-block'],
[{ list: 'ordered' }, { list: 'bullet' }]
]
},
placeholder: 'Compose an epic...',
theme: 'snow' // or 'bubble'
})
window.quillBinding = new QuillBinding(ytext, quill)
</script>
</body>
</html>

30
examples/quill.js Normal file
View File

@@ -0,0 +1,30 @@
import * as Y from '../src/index.js'
import { WebsocketProvider } from 'y-websocket'
import { QuillBinding } from 'y-quill'
import * as conf from './exampleConfig.js'
import Quill from 'quill'
const provider = new WebsocketProvider(conf.serverAddress)
const ydocument = provider.get('quill')
const ytext = ydocument.define('quill', Y.Text)
const quill = new Quill('#quill-container', {
modules: {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block'],
[{ color: [] }, { background: [] }], // Snow theme fills in values
[{ script: 'sub' }, { script: 'super' }],
['link', 'image'],
['link', 'code-block'],
[{ list: 'ordered' }, { list: 'bullet' }]
]
},
placeholder: 'Compose an epic...',
theme: 'snow' // or 'bubble'
})
window.quillBinding = new QuillBinding(ytext, quill)

View File

@@ -1,18 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<!-- Main Quill library -->
<script src="../../node_modules/quill/dist/quill.min.js"></script>
<link href="../../node_modules/quill/dist/quill.snow.css" rel="stylesheet">
<!-- Yjs Library and connector -->
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
</head>
<body>
<div id="quill-container">
<div id="quill">
</div>
</div>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,33 +0,0 @@
/* global Y, Quill */
let y = new Y('quill-cursors-0', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
let quill = new Quill('#quill-container', {
modules: {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block'],
[{ color: [] }, { background: [] }], // Snow theme fills in values
[{ script: 'sub' }, { script: 'super' }],
['link', 'image'],
['link', 'code-block'],
[{ list: 'ordered' }, { list: 'bullet' }]
]
},
placeholder: 'Compose an epic...',
theme: 'snow' // or 'bubble'
})
let yText = y.define('quill', Y.Text)
let quillBinding = new Y.QuillBinding(yText, quill)
window.quillBinding = quillBinding
window.yText = yText
window.y = y
window.quill = quill

View File

@@ -1,29 +0,0 @@
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
var pkg = require('./package.json')
export default {
input: 'yjs-dist.mjs',
name: 'Y',
output: {
file: 'yjs-dist.js',
format: 'umd'
},
plugins: [
nodeResolve({
main: true,
module: true,
browser: true
}),
commonjs()
],
sourcemap: true,
banner: `
/**
* ${pkg.name} - ${pkg.description}
* @version v${pkg.version}
* @license ${pkg.license}
*/
`
}

View File

@@ -1,31 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<!-- quill does not include dist files! We are using the hosted version instead -->
<!--link rel="stylesheet" href="../bower_components/quill/dist/quill.snow.css" /-->
<link href="https://cdn.quilljs.com/1.0.4/quill.snow.css" rel="stylesheet">
<link href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.5.1/katex.min.css" rel="stylesheet">
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.2.0/styles/monokai-sublime.min.css" rel="stylesheet">
<style>
#quill-container {
border: 1px solid gray;
box-shadow: 0px 0px 10px gray;
}
</style>
</head>
<body>
<div id="quill-container">
<div id="quill">
</div>
</div>
<script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.5.1/katex.min.js" type="text/javascript"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.2.0/highlight.min.js" type="text/javascript"></script>
<script src="https://cdn.quilljs.com/1.0.4/quill.js"></script>
<!-- quill does not include dist files! We are using the hosted version instead (see above)
<script src="../bower_components/quill/dist/quill.js"></script>
-->
<script src="../bower_components/yjs/y.js"></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,49 +0,0 @@
/* global Y, Quill */
// register yjs service worker
if ('serviceWorker' in navigator) {
// Register service worker
// it is important to copy yjs-sw-template to the root directory!
navigator.serviceWorker.register('./yjs-sw-template.js').then(function (reg) {
console.log('Yjs service worker registration succeeded. Scope is ' + reg.scope)
}).catch(function (err) {
console.error('Yjs service worker registration failed with error ' + err)
})
}
// initialize a shared object. This function call returns a promise!
Y({
db: {
name: 'memory'
},
connector: {
name: 'serviceworker',
room: 'ServiceWorkerExample2'
},
sourceDir: '/bower_components',
share: {
richtext: 'Richtext' // y.share.richtext is of type Y.Richtext
}
}).then(function (y) {
window.yServiceWorker = y
// create quill element
window.quill = new Quill('#quill', {
modules: {
formula: true,
syntax: true,
toolbar: [
[{ size: ['small', false, 'large', 'huge'] }],
['bold', 'italic', 'underline'],
[{ color: [] }, { background: [] }], // Snow theme fills in values
[{ script: 'sub' }, { script: 'super' }],
['link', 'image'],
['link', 'code-block'],
[{ list: 'ordered' }]
]
},
theme: 'snow'
})
// bind quill to richtext type
y.share.richtext.bind(window.quill)
})

View File

@@ -1,22 +0,0 @@
/* eslint-env worker */
// copy and modify this file
self.DBConfig = {
name: 'indexeddb'
}
self.ConnectorConfig = {
name: 'websockets-client',
// url: '..',
options: {
jsonp: false
}
}
importScripts(
'/bower_components/yjs/y.js',
'/bower_components/y-memory/y-memory.js',
'/bower_components/y-indexeddb/y-indexeddb.js',
'/bower_components/y-websockets-client/y-websockets-client.js',
'/bower_components/y-serviceworker/yjs-sw-include.js'
)

29
examples/style.css Normal file
View File

@@ -0,0 +1,29 @@
footer img {
display: none;
}
nav .title h1 a {
display: none;
}
footer {
background-color: #b93c1d;
}
#resizer {
background-color: #b93c1d;
}
.main section article.readme h1:first-child img {
display: none;
}
.main section article.readme h1:first-child {
margin-bottom: 16px;
margin-top: 30px;
}
.main section article.readme h1:first-child::before {
content: "Yjs";
font-size: 2em;
}

32
examples/textarea.html Normal file
View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<title>Yjs Textarea Example</title>
</head>
<body>
<p>This example shows how to bind a YText type to a DOM Textarea.</p>
<p>The content of this textarea is shared with every client who visits this domain.</p>
<div class="code-html">
<textarea style="width:80%;" rows=40 autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
</div>
<!-- The actual source file for the following code is found in ./textarea.js. Run `npm run watch` to compile the files -->
<script class="code-js" src="./build/textarea.js" type="module">
import * as Y from 'yjs'
import { WebsocketProvider } from 'yjs/provider/websocket.js'
import { TextareaBinding } from 'yjs/bindings/textarea.js'
import * as conf from './exampleConfig.js'
const provider = new WebsocketProvider(conf.serverAddress)
const ydocument = provider.get('textarea')
const type = ydocument.define('textarea', Y.Text)
const textarea = document.querySelector('textarea')
const binding = new TextareaBinding(type, textarea)
window.textareaExample = {
provider, ydocument, type, textarea, binding
}
</script>
</body>
</html>

14
examples/textarea.js Normal file
View File

@@ -0,0 +1,14 @@
import { WebsocketProvider } from 'y-websocket'
import { TextareaBinding } from 'y-textarea'
import * as conf from './exampleConfig.js'
const provider = new WebsocketProvider(conf.serverAddress)
const ydocument = provider.get('textarea')
const type = ydocument.getText('textarea')
const textarea = document.querySelector('textarea')
const binding = new TextareaBinding(type, textarea)
window.textareaExample = {
provider, ydocument, type, textarea, binding
}

View File

@@ -1,9 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<textarea style="width:80%;" rows=40 autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -1,15 +0,0 @@
/* global Y */
let y = new Y('textarea-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
window.yTextarea = y
// bind the textarea to a shared text element
let type = y.define('textarea', Y.Text)
let textarea = document.querySelector('textarea')
window.binding = new Y.TextareaBinding(type, textarea)

View File

@@ -1,43 +0,0 @@
<!DOCTYPE html>
<html>
</head>
<!-- jquery is not required for YXml. It is just here for convenience, and to test batch operations. -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="../../y.js"></script>
<script src='../../../y-websockets-client/y-websockets-client.js'></script>
<script src="./index.js"></script>
</head>
<body>
<h1> Shared DOM Example </h1>
<p> Use native DOM function or jQuery to manipulate the shared DOM (window.sharedDom). </p>
<div class="command">
<button type="button">Execute</button>
<input type="text" value='$(sharedDom).append("<h3>Appended headline</h3>")' size="40"/>
</div>
<div class="command">
<button type="button">Execute</button>
<input type="text" value='$(sharedDom).attr("align","right")' size="40"/>
</div>
<div class="command">
<button type="button">Execute</button>
<input type="text" value='$(sharedDom).attr("style","color:blue;")' size="40"/>
</div>
<script>
/* global $ */
var commands = document.querySelectorAll('.command')
Array.prototype.forEach.call(commands, function (command) {
var execute = function () {
// eslint-disable-next-line no-eval
eval(command.querySelector('input').value)
}
command.querySelector('button').onclick = execute
$(command.querySelector('input')).keyup(function (e) {
if (e.keyCode === 13) {
execute()
}
})
})
</script>
</body>
</html>

View File

@@ -1,13 +0,0 @@
/* global Y */
let y = new Y('xml-example', {
connector: {
name: 'websockets-client',
url: 'http://127.0.0.1:1234'
}
})
window.yXml = y
// bind xml type to a dom, and put it in body
window.sharedDom = y.define('xml', Y.XmlElement).toDom()
document.body.appendChild(window.sharedDom)

View File

@@ -1,9 +0,0 @@
import Y from '../src/Y.js'
import yWebsocketsClient from '../../y-websockets-client/src/y-websockets-client.js'
import extendYIndexedDBPersistence from '../../y-indexeddb/src/y-indexeddb.js'
Y.extend(yWebsocketsClient)
extendYIndexedDBPersistence(Y)
export default Y

8040
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +1,41 @@
{
"name": "yjs",
"version": "13.0.0-60",
"description": "A framework for real-time p2p shared editing on any data",
"main": "./y.node.js",
"browser": "./y.js",
"module": "./src/y.js",
"version": "13.0.0-78",
"description": "A ",
"main": "./dist/yjs.js",
"module": "./dist/yjs.mjs'",
"sideEffects": false,
"scripts": {
"test": "npm run lint",
"debug": "concurrently 'rollup -wc rollup.test.js' 'cutest-serve y.test.js -o'",
"lint": "standard",
"docs": "esdoc",
"test": "npm run dist && PRODUCTION=1 node ./dist/tests.js --repitition-time 50 --production",
"test-exhaustive": "npm run lint && npm run dist && node ./dist/tests.js --repitition-time 10000",
"dist": "rm -rf dist examples/build && rollup -c",
"watch": "rollup -wc",
"lint": "standard && tsc",
"docs": "rm -rf docs; jsdoc --configure ./.jsdoc.json --verbose --readme ./README.v13.md --package ./package.json || true",
"serve-docs": "npm run docs && serve ./docs/",
"dist": "rollup -c rollup.browser.js; rollup -c rollup.node.js",
"watch": "concurrently 'rollup -wc rollup.browser.js' 'rollup -wc rollup.node.js'",
"postversion": "npm run dist",
"postpublish": "tag-dist-files --overwrite-existing-tag"
"postversion": "npm run lint && PRODUCTION=1 npm run dist && node ./dist/tests.js --repitition-time 1000",
"debug": "concurrently 'live-server --port=3443 --entry-file=test.html' 'npm run watch'",
"trace-deopt": "clear && rollup -c && node --trace-deopt dist/test.js",
"trace-opt": "clear && rollup -c && node --trace-opt dist/test.js"
},
"files": [
"y.*",
"src/*",
".esdoc.json",
"docs/*"
"dist/*",
"examples/*",
"docs/*",
"README.md",
"LICENSE"
],
"dictionaries": {
"doc": "docs",
"example": "examples",
"test": "tests"
},
"standard": {
"ignore": [
"/y.js",
"/y.js.map"
"/dist",
"/node_modules",
"/docs",
"/examples/build"
]
},
"repository": {
@@ -33,13 +43,7 @@
"url": "https://github.com/y-js/yjs.git"
},
"keywords": [
"Yjs",
"OT",
"Collaboration",
"Synchronization",
"ShareJS",
"Coweb",
"Concurrency"
"crdt"
],
"author": "Kevin Jahns",
"email": "kevin.jahns@rwth-aachen.de",
@@ -48,28 +52,29 @@
"url": "https://github.com/y-js/yjs/issues"
},
"homepage": "http://y-js.org",
"dependencies": {
"lib0": "0.0.0"
},
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-plugin-external-helpers": "^6.22.0",
"babel-plugin-transform-regenerator": "^6.24.1",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-latest": "^6.24.1",
"chance": "^1.0.9",
"concurrently": "^3.4.0",
"cutest": "^0.1.9",
"esdoc": "^1.0.4",
"codemirror": "^5.42.0",
"concurrently": "^3.6.1",
"esdoc": "^1.1.0",
"esdoc-standard-plugin": "^1.0.0",
"quill": "^1.3.5",
"quill-cursors": "^1.0.2",
"rollup-plugin-babel": "^2.7.1",
"rollup-plugin-commonjs": "^8.0.2",
"rollup-plugin-inject": "^2.0.0",
"rollup-plugin-multi-entry": "^2.0.1",
"rollup-plugin-node-resolve": "^3.0.0",
"rollup-plugin-uglify": "^1.0.2",
"rollup-regenerator-runtime": "^6.23.1",
"rollup-watch": "^3.2.2",
"standard": "^10.0.2",
"tag-dist-files": "^0.1.6"
"jsdoc": "^3.5.5",
"live-server": "^1.2.1",
"prosemirror-example-setup": "^1.0.1",
"prosemirror-schema-basic": "^1.0.0",
"prosemirror-state": "^1.2.2",
"prosemirror-view": "^1.6.5",
"quill": "^1.3.6",
"quill-cursors": "^1.0.3",
"rollup": "^1.1.2",
"rollup-cli": "^1.0.9",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-terser": "^4.0.4",
"standard": "^11.0.1",
"tui-jsdoc-template": "^1.2.2",
"typescript": "^3.3.3333"
}
}

View File

@@ -1,46 +0,0 @@
import babel from 'rollup-plugin-babel'
import uglify from 'rollup-plugin-uglify'
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
var pkg = require('./package.json')
export default {
input: 'src/Y.dist.js',
name: 'Y',
sourcemap: true,
output: {
file: 'y.js',
format: 'umd'
},
plugins: [
nodeResolve({
main: true,
module: true,
browser: true
}),
commonjs(),
babel(),
uglify({
mangle: {
except: ['YMap', 'Y', 'YArray', 'YText', 'YXmlHook', 'YXmlFragment', 'YXmlElement', 'YXmlEvent', 'YXmlText', 'YEvent', 'YArrayEvent', 'YMapEvent', 'Type', 'Delete', 'ItemJSON', 'ItemString', 'Item']
},
output: {
comments: function (node, comment) {
var text = comment.value
var type = comment.type
if (type === 'comment2') {
// multiline comment
return /@license/i.test(text)
}
}
}
})
],
banner: `
/**
* ${pkg.name} - ${pkg.description}
* @version v${pkg.version}
* @license ${pkg.license}
*/
`
}

105
rollup.config.js Normal file
View File

@@ -0,0 +1,105 @@
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import { terser } from 'rollup-plugin-terser'
const customModules = new Set([
'y-websocket',
'y-codemirror',
'y-ace',
'y-textarea',
'y-quill',
'y-dom',
'y-prosemirror'
])
/**
* @type {Set<any>}
*/
const customLibModules = new Set([
'lib0',
'y-protocols'
])
const debugResolve = {
resolveId (importee) {
if (importee === 'yjs') {
return `${process.cwd()}/src/index.js`
}
if (customModules.has(importee.split('/')[0])) {
return `${process.cwd()}/../${importee}/src/${importee}.js`
}
if (customLibModules.has(importee.split('/')[0])) {
return `${process.cwd()}/../${importee}`
}
return null
}
}
const minificationPlugins = process.env.PRODUCTION ? [terser({
module: true,
compress: {
hoist_vars: true,
module: true,
passes: 5,
pure_getters: true,
unsafe_comps: true,
unsafe_undefined: true
},
mangle: {
toplevel: true
}
})] : []
export default [{
input: './src/index.js',
output: [{
name: 'Y',
file: 'dist/yjs.js',
format: 'cjs',
sourcemap: true,
paths: path => {
if (/^lib0\//.test(path)) {
return `lib0/dist/${path.slice(5)}`
}
return path
}
}, {
name: 'Y',
file: 'dist/yjs.mjs',
format: 'es',
sourcemap: true
}],
external: id => /^lib0\//.test(id)
}, {
input: './tests/index.js',
output: {
name: 'test',
file: 'dist/tests.js',
format: 'iife',
sourcemap: true
},
plugins: [
debugResolve,
nodeResolve({
sourcemap: true,
module: true,
browser: true
}),
commonjs()
]
}, {
input: ['./examples/codemirror.js', './examples/textarea.js'], // './examples/quill.js', './examples/dom.js', './examples/prosemirror.js'
output: {
dir: 'examples/build',
format: 'esm',
sourcemap: true
},
plugins: [
debugResolve,
nodeResolve({
sourcemap: true,
module: true,
browser: true
}),
commonjs(),
...minificationPlugins
]
}]

View File

@@ -1,28 +0,0 @@
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
var pkg = require('./package.json')
export default {
input: 'src/Y.dist.js',
nameame: 'Y',
sourcemap: true,
output: {
file: 'y.node.js',
format: 'cjs'
},
plugins: [
nodeResolve({
main: true,
module: true,
browser: true
}),
commonjs()
],
banner: `
/**
* ${pkg.name} - ${pkg.description}
* @version v${pkg.version}
* @license ${pkg.license}
*/
`
}

View File

@@ -1,22 +0,0 @@
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import multiEntry from 'rollup-plugin-multi-entry'
export default {
input: 'test/index.js',
name: 'y-tests',
sourcemap: true,
output: {
file: 'y.test.js',
format: 'umd'
},
plugins: [
multiEntry(),
nodeResolve({
main: true,
module: true,
browser: true
}),
commonjs()
]
}

View File

@@ -1,47 +0,0 @@
import { createMutualExclude } from '../Util/mutualExclude.js'
/**
* Abstract class for bindings.
*
* A binding handles data binding from a Yjs type to a data object. For example,
* you can bind a Quill editor instance to a YText instance with the `QuillBinding` class.
*
* It is expected that a concrete implementation accepts two parameters
* (type and binding target).
*
* @example
* const quill = new Quill(document.createElement('div'))
* const type = y.define('quill', Y.Text)
* const binding = new Y.QuillBinding(quill, type)
*
*/
export default class Binding {
/**
* @param {YType} type Yjs type.
* @param {any} target Binding Target.
*/
constructor (type, target) {
/**
* The Yjs type that is bound to `target`
* @type {YType}
*/
this.type = type
/**
* The target that `type` is bound to.
* @type {*}
*/
this.target = target
/**
* @private
*/
this._mutualExclude = createMutualExclude()
}
/**
* Remove all data observers (both from the type and the target).
*/
destroy () {
this.type = null
this.target = null
}
}

View File

@@ -1,141 +0,0 @@
/* global MutationObserver */
import Binding from '../Binding.js'
import { createAssociation, removeAssociation } from './util.js'
import { beforeTransactionSelectionFixer, afterTransactionSelectionFixer } from './selection.js'
import { defaultFilter, applyFilterOnType } from './filter.js'
import typeObserver from './typeObserver.js'
import domObserver from './domObserver.js'
/**
* A binding that binds the children of a YXmlFragment to a DOM element.
*
* This binding is automatically destroyed when its parent is deleted.
*
* @example
* const div = document.createElement('div')
* const type = y.define('xml', Y.XmlFragment)
* const binding = new Y.QuillBinding(type, div)
*
*/
export default class DomBinding extends Binding {
/**
* @param {YXmlFragment} type The bind source. This is the ultimate source of
* truth.
* @param {Element} target The bind target. Mirrors the target.
* @param {Object} [opts] Optional configurations
* @param {FilterFunction} [opts.filter=defaultFilter] The filter function to use.
*/
constructor (type, target, opts = {}) {
// Binding handles textType as this.type and domTextarea as this.target
super(type, target)
this.opts = opts
opts.document = opts.document || document
opts.hooks = opts.hooks || {}
this.scrollingElement = opts.scrollingElement || null
/**
* Maps each DOM element to the type that it is associated with.
* @type {Map}
*/
this.domToType = new Map()
/**
* Maps each YXml type to the DOM element that it is associated with.
* @type {Map}
*/
this.typeToDom = new Map()
/**
* Defines which DOM attributes and elements to filter out.
* Also filters remote changes.
* @type {FilterFunction}
*/
this.filter = opts.filter || defaultFilter
// set initial value
target.innerHTML = ''
type.forEach(child => {
target.insertBefore(child.toDom(opts.document, opts.hooks, this), null)
})
this._typeObserver = typeObserver.bind(this)
this._domObserver = (mutations) => {
domObserver.call(this, mutations, opts.document)
}
type.observeDeep(this._typeObserver)
this._mutationObserver = new MutationObserver(this._domObserver)
this._mutationObserver.observe(target, {
childList: true,
attributes: true,
characterData: true,
subtree: true
})
const y = type._y
// Force flush dom changes before Type changes are applied (they might
// modify the dom)
this._beforeTransactionHandler = (y, transaction, remote) => {
this._domObserver(this._mutationObserver.takeRecords())
beforeTransactionSelectionFixer(y, this, transaction, remote)
}
y.on('beforeTransaction', this._beforeTransactionHandler)
this._afterTransactionHandler = (y, transaction, remote) => {
afterTransactionSelectionFixer(y, this, transaction, remote)
// remove associations
// TODO: this could be done more efficiently
// e.g. Always delete using the following approach, or removeAssociation
// in dom/type-observer..
transaction.deletedStructs.forEach(type => {
const dom = this.typeToDom.get(type)
if (dom !== undefined) {
removeAssociation(this, dom, type)
}
})
}
y.on('afterTransaction', this._afterTransactionHandler)
// Before calling observers, apply dom filter to all changed and new types.
this._beforeObserverCallsHandler = (y, transaction) => {
// Apply dom filter to new and changed types
transaction.changedTypes.forEach((subs, type) => {
// Only check attributes. New types are filtered below.
if ((subs.size > 1 || (subs.size === 1 && subs.has(null) === false))) {
applyFilterOnType(y, this, type)
}
})
transaction.newTypes.forEach(type => {
applyFilterOnType(y, this, type)
})
}
y.on('beforeObserverCalls', this._beforeObserverCallsHandler)
createAssociation(this, target, type)
}
/**
* NOTE: currently does not apply filter to existing elements!
* @param {FilterFunction} filter The filter function to use from now on.
*/
setFilter (filter) {
this.filter = filter
// TODO: apply filter to all elements
}
/**
* Remove all properties that are handled by this class.
*/
destroy () {
this.domToType = null
this.typeToDom = null
this.type.unobserve(this._typeObserver)
this._mutationObserver.disconnect()
const y = this.type._y
y.off('beforeTransaction', this._beforeTransactionHandler)
y.off('beforeObserverCalls', this._beforeObserverCallsHandler)
y.off('afterObserverCalls', this._afterObserverCallsHandler)
y.off('afterTransaction', this._afterTransactionHandler)
super.destroy()
}
}
/**
* A filter defines which elements and attributes to share.
* Return null if the node should be filtered. Otherwise return the Map of
* accepted attributes.
*
* @typedef {function(nodeName: String, attrs: Map): Map|null} FilterFunction
*/

View File

@@ -1,144 +0,0 @@
import YXmlHook from '../../Types/YXml/YXmlHook.js'
import {
iterateUntilUndeleted,
removeAssociation,
insertNodeHelper } from './util.js'
import diff from '../../Util/simpleDiff.js'
import YXmlFragment from '../../Types/YXml/YXmlFragment.js'
/**
* 1. Check if any of the nodes was deleted
* 2. Iterate over the children.
* 2.1 If a node exists that is not yet bound to a type, insert a new node
* 2.2 If _contents.length < dom.childNodes.length, fill the
* rest of _content with childNodes
* 2.3 If a node was moved, delete it and
* recreate a new yxml element that is bound to that node.
* You can detect that a node was moved because expectedId
* !== actualId in the list
* @private
*/
function applyChangesFromDom (binding, dom, yxml, _document) {
if (yxml == null || yxml === false || yxml.constructor === YXmlHook) {
return
}
const y = yxml._y
const knownChildren = new Set()
for (let i = dom.childNodes.length - 1; i >= 0; i--) {
const type = binding.domToType.get(dom.childNodes[i])
if (type !== undefined && type !== false) {
knownChildren.add(type)
}
}
// 1. Check if any of the nodes was deleted
yxml.forEach(function (childType) {
if (knownChildren.has(childType) === false) {
childType._delete(y)
removeAssociation(binding, binding.typeToDom.get(childType), childType)
}
})
// 2. iterate
const childNodes = dom.childNodes
const len = childNodes.length
let prevExpectedType = null
let expectedType = iterateUntilUndeleted(yxml._start)
for (let domCnt = 0; domCnt < len; domCnt++) {
const childNode = childNodes[domCnt]
const childType = binding.domToType.get(childNode)
if (childType !== undefined) {
if (childType === false) {
// should be ignored or is going to be deleted
continue
}
if (expectedType !== null) {
if (expectedType !== childType) {
// 2.3 Not expected node
if (childType._parent !== yxml) {
// child was moved from another parent
// childType is going to be deleted by its previous parent
removeAssociation(binding, childNode, childType)
} else {
// child was moved to a different position.
removeAssociation(binding, childNode, childType)
childType._delete(y)
}
prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding)
} else {
// Found expected node. Continue.
prevExpectedType = expectedType
expectedType = iterateUntilUndeleted(expectedType._right)
}
} else {
// 2.2 Fill _content with child nodes
prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding)
}
} else {
// 2.1 A new node was found
prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding)
}
}
}
/**
* @private
*/
export default function domObserver (mutations, _document) {
this._mutualExclude(() => {
this.type._y.transact(() => {
let diffChildren = new Set()
mutations.forEach(mutation => {
const dom = mutation.target
const yxml = this.domToType.get(dom)
if (yxml === undefined) { // In case yxml is undefined, we double check if we forgot to bind the dom
let parent = dom
let yParent
do {
parent = parent.parentNode
yParent = this.domToType.get(parent)
} while (yParent === undefined && parent !== null)
if (yParent !== false && yParent !== undefined && yParent.constructor !== YXmlHook) {
diffChildren.add(parent)
}
return
} else if (yxml === false || yxml.constructor === YXmlHook) {
// dom element is filtered / a dom hook
return
}
switch (mutation.type) {
case 'characterData':
var change = diff(yxml.toString(), dom.nodeValue)
yxml.delete(change.pos, change.remove)
yxml.insert(change.pos, change.insert)
break
case 'attributes':
if (yxml.constructor === YXmlFragment) {
break
}
let name = mutation.attributeName
let val = dom.getAttribute(name)
// check if filter accepts attribute
let attributes = new Map()
attributes.set(name, val)
if (yxml.constructor !== YXmlFragment && this.filter(dom.nodeName, attributes).size > 0) {
if (yxml.getAttribute(name) !== val) {
if (val == null) {
yxml.removeAttribute(name)
} else {
yxml.setAttribute(name, val)
}
}
}
break
case 'childList':
diffChildren.add(mutation.target)
break
}
})
for (let dom of diffChildren) {
const yxml = this.domToType.get(dom)
applyChangesFromDom(this, dom, yxml, _document)
}
})
})
}

View File

@@ -1,59 +0,0 @@
import { YXmlText, YXmlElement, YXmlHook } from '../../Types/YXml/YXml.js'
import { createAssociation, domsToTypes } from './util.js'
import { filterDomAttributes, defaultFilter } from './filter.js'
/**
* Creates a Yjs type (YXml) based on the contents of a DOM Element.
*
* @param {Element|TextNode} element The DOM Element
* @param {?Document} _document Optional. Provide the global document object
* @param {Hooks} [hooks = {}] Optional. Set of Yjs Hooks
* @param {Filter} [filter=defaultFilter] Optional. Dom element filter
* @param {?DomBinding} binding Warning: This property is for internal use only!
* @return {YXmlElement | YXmlText}
*/
export default function domToType (element, _document = document, hooks = {}, filter = defaultFilter, binding) {
let type
switch (element.nodeType) {
case _document.ELEMENT_NODE:
let hookName = null
let hook
// configure `hookName !== undefined` if element is a hook.
if (element.hasAttribute('data-yjs-hook')) {
hookName = element.getAttribute('data-yjs-hook')
hook = hooks[hookName]
if (hook === undefined) {
console.error(`Unknown hook "${hookName}". Deleting yjsHook dataset property.`)
delete element.removeAttribute('data-yjs-hook')
hookName = null
}
}
if (hookName === null) {
// Not a hook
const attrs = filterDomAttributes(element, filter)
if (attrs === null) {
type = false
} else {
type = new YXmlElement(element.nodeName)
attrs.forEach((val, key) => {
type.setAttribute(key, val)
})
type.insert(0, domsToTypes(element.childNodes, document, hooks, filter, binding))
}
} else {
// Is a hook
type = new YXmlHook(hookName)
hook.fillType(element, type)
}
break
case _document.TEXT_NODE:
type = new YXmlText()
type.insert(0, element.nodeValue)
break
default:
throw new Error('Can\'t transform this node type to a YXml type!')
}
createAssociation(binding, element, type)
return type
}

View File

@@ -1,60 +0,0 @@
import isParentOf from '../../Util/isParentOf.js'
/**
* Default filter method (does nothing).
*
* @param {String} nodeName The nodeName of the element
* @param {Map} attrs Map of key-value pairs that are attributes of the node.
* @return {Map | null} The allowed attributes or null, if the element should be
* filtered.
*/
export function defaultFilter (nodeName, attrs) {
// TODO: implement basic filter that filters out dangerous properties!
return attrs
}
/**
*
*/
export function filterDomAttributes (dom, filter) {
const attrs = new Map()
for (let i = dom.attributes.length - 1; i >= 0; i--) {
const attr = dom.attributes[i]
attrs.set(attr.name, attr.value)
}
return filter(dom.nodeName, attrs)
}
/**
* Applies a filter on a type.
*
* @param {Y} y The Yjs instance.
* @param {DomBinding} binding The DOM binding instance that has the dom filter.
* @param {YXmlElement | YXmlFragment } type The type to apply the filter to.
*
* @private
*/
export function applyFilterOnType (y, binding, type) {
if (isParentOf(binding.type, type)) {
const nodeName = type.nodeName
let attributes = new Map()
if (type.getAttributes !== undefined) {
let attrs = type.getAttributes()
for (let key in attrs) {
attributes.set(key, attrs[key])
}
}
const filteredAttributes = binding.filter(nodeName, new Map(attributes))
if (filteredAttributes === null) {
type._delete(y)
} else {
// iterate original attributes
attributes.forEach((value, key) => {
// delete all attributes that are not in filteredAttributes
if (filteredAttributes.has(key) === false) {
type.removeAttribute(key)
}
})
}
}
}

View File

@@ -1,84 +0,0 @@
/* globals getSelection */
import { getRelativePosition, fromRelativePosition } from '../../Util/relativePosition.js'
let browserSelection = null
let relativeSelection = null
/**
* @private
*/
export let beforeTransactionSelectionFixer
if (typeof getSelection !== 'undefined') {
beforeTransactionSelectionFixer = function _beforeTransactionSelectionFixer (y, domBinding, transaction, remote) {
if (!remote) {
return
}
relativeSelection = { from: null, to: null, fromY: null, toY: null }
browserSelection = getSelection()
const anchorNode = browserSelection.anchorNode
const anchorNodeType = domBinding.domToType.get(anchorNode)
if (anchorNode !== null && anchorNodeType !== undefined) {
relativeSelection.from = getRelativePosition(anchorNodeType, browserSelection.anchorOffset)
relativeSelection.fromY = anchorNodeType._y
}
const focusNode = browserSelection.focusNode
const focusNodeType = domBinding.domToType.get(focusNode)
if (focusNode !== null && focusNodeType !== undefined) {
relativeSelection.to = getRelativePosition(focusNodeType, browserSelection.focusOffset)
relativeSelection.toY = focusNodeType._y
}
}
} else {
beforeTransactionSelectionFixer = function _fakeBeforeTransactionSelectionFixer () {}
}
/**
* @private
*/
export function afterTransactionSelectionFixer (y, domBinding, transaction, remote) {
if (relativeSelection === null || !remote) {
return
}
const to = relativeSelection.to
const from = relativeSelection.from
const fromY = relativeSelection.fromY
const toY = relativeSelection.toY
let shouldUpdate = false
let anchorNode = browserSelection.anchorNode
let anchorOffset = browserSelection.anchorOffset
let focusNode = browserSelection.focusNode
let focusOffset = browserSelection.focusOffset
if (from !== null) {
let sel = fromRelativePosition(fromY, from)
if (sel !== null) {
let node = domBinding.typeToDom.get(sel.type)
let offset = sel.offset
if (node !== anchorNode || offset !== anchorOffset) {
anchorNode = node
anchorOffset = offset
shouldUpdate = true
}
}
}
if (to !== null) {
let sel = fromRelativePosition(toY, to)
if (sel !== null) {
let node = domBinding.typeToDom.get(sel.type)
let offset = sel.offset
if (node !== focusNode || offset !== focusOffset) {
focusNode = node
focusOffset = offset
shouldUpdate = true
}
}
}
if (shouldUpdate) {
browserSelection.setBaseAndExtent(
anchorNode,
anchorOffset,
focusNode,
focusOffset
)
}
}

View File

@@ -1,100 +0,0 @@
/* global getSelection */
import YXmlText from '../../Types/YXml/YXmlText.js'
import YXmlHook from '../../Types/YXml/YXmlHook.js'
import { removeDomChildrenUntilElementFound } from './util.js'
function findScrollReference (scrollingElement) {
if (scrollingElement !== null) {
let anchor = getSelection().anchorNode
if (anchor == null) {
let children = scrollingElement.children // only iterate through non-text nodes
for (let i = 0; i < children.length; i++) {
const elem = children[i]
const rect = elem.getBoundingClientRect()
if (rect.top >= 0) {
return { elem, top: rect.top }
}
}
} else {
if (anchor.nodeType === document.TEXT_NODE) {
anchor = anchor.parentElement
}
const top = anchor.getBoundingClientRect().top
return { elem: anchor, top: top }
}
}
return null
}
function fixScroll (scrollingElement, ref) {
if (ref !== null) {
const { elem, top } = ref
const currentTop = elem.getBoundingClientRect().top
const newScroll = scrollingElement.scrollTop + currentTop - top
if (newScroll >= 0) {
scrollingElement.scrollTop = newScroll
}
}
}
/**
* @private
*/
export default function typeObserver (events) {
this._mutualExclude(() => {
const scrollRef = findScrollReference(this.scrollingElement)
events.forEach(event => {
const yxml = event.target
const dom = this.typeToDom.get(yxml)
if (dom !== undefined && dom !== false) {
if (yxml.constructor === YXmlText) {
dom.nodeValue = yxml.toString()
// TODO: use hasOwnProperty instead of === undefined check
} else if (event.attributesChanged !== undefined) {
// update attributes
event.attributesChanged.forEach(attributeName => {
const value = yxml.getAttribute(attributeName)
if (value === undefined) {
dom.removeAttribute(attributeName)
} else {
dom.setAttribute(attributeName, value)
}
})
/*
* TODO: instead of hard-checking the types, it would be best to
* specify the type's features. E.g.
* - _yxmlHasAttributes
* - _yxmlHasChildren
* Furthermore, the features shouldn't be encoded in the types,
* only in the attributes (above)
*/
if (event.childListChanged && yxml.constructor !== YXmlHook) {
let currentChild = dom.firstChild
yxml.forEach(childType => {
const childNode = this.typeToDom.get(childType)
switch (childNode) {
case undefined:
// Does not exist. Create it.
const node = childType.toDom(this.opts.document, this.opts.hooks, this)
dom.insertBefore(node, currentChild)
break
case false:
// nop
break
default:
// Is already attached to the dom.
// Find it and remove all dom nodes in-between.
removeDomChildrenUntilElementFound(dom, currentChild, childNode)
currentChild = childNode.nextSibling
break
}
})
removeDomChildrenUntilElementFound(dom, currentChild, null)
}
}
}
})
fixScroll(this.scrollingElement, scrollRef)
})
}

View File

@@ -1,124 +0,0 @@
import domToType from './domToType.js'
/**
* Iterates items until an undeleted item is found.
*
* @private
*/
export function iterateUntilUndeleted (item) {
while (item !== null && item._deleted) {
item = item._right
}
return item
}
/**
* Removes an association (the information that a DOM element belongs to a
* type).
*
* @param {DomBinding} domBinding The binding object
* @param {Element} dom The dom that is to be associated with type
* @param {YXmlElement|YXmlHook} type The type that is to be associated with dom
*
*/
export function removeAssociation (domBinding, dom, type) {
domBinding.domToType.delete(dom)
domBinding.typeToDom.delete(type)
}
/**
* Creates an association (the information that a DOM element belongs to a
* type).
*
* @param {DomBinding} domBinding The binding object
* @param {Element} dom The dom that is to be associated with type
* @param {YXmlElement|YXmlHook} type The type that is to be associated with dom
*
*/
export function createAssociation (domBinding, dom, type) {
if (domBinding !== undefined) {
domBinding.domToType.set(dom, type)
domBinding.typeToDom.set(type, dom)
}
}
/**
* If oldDom is associated with a type, associate newDom with the type and
* forget about oldDom. If oldDom is not associated with any type, nothing happens.
*
* @param {DomBinding} domBinding The binding object
* @param {Element} oldDom The existing dom
* @param {Element} newDom The new dom object
*/
export function switchAssociation (domBinding, oldDom, newDom) {
if (domBinding !== undefined) {
const type = domBinding.domToType.get(oldDom)
if (type !== undefined) {
removeAssociation(domBinding, oldDom, type)
createAssociation(domBinding, newDom, type)
}
}
}
/**
* Insert Dom Elements after one of the children of this YXmlFragment.
* The Dom elements will be bound to a new YXmlElement and inserted at the
* specified position.
*
* @param {YXmlElement} type The type in which to insert DOM elements.
* @param {YXmlElement|null} prev The reference node. New YxmlElements are
* inserted after this node. Set null to insert at
* the beginning.
* @param {Array<Element>} doms The Dom elements to insert.
* @param {?Document} _document Optional. Provide the global document object.
* @param {DomBinding} binding The dom binding
* @return {Array<YXmlElement>} The YxmlElements that are inserted.
*
* @private
*/
export function insertDomElementsAfter (type, prev, doms, _document, binding) {
const types = domsToTypes(doms, _document, binding.opts.hooks, binding.filter, binding)
return type.insertAfter(prev, types)
}
export function domsToTypes (doms, _document, hooks, filter, binding) {
const types = []
for (let dom of doms) {
const t = domToType(dom, _document, hooks, filter, binding)
if (t !== false) {
types.push(t)
}
}
return types
}
/**
* @private
*/
export function insertNodeHelper (yxml, prevExpectedNode, child, _document, binding) {
let insertedNodes = insertDomElementsAfter(yxml, prevExpectedNode, [child], _document, binding)
if (insertedNodes.length > 0) {
return insertedNodes[0]
} else {
return prevExpectedNode
}
}
/**
* Remove children until `elem` is found.
*
* @param {Element} parent The parent of `elem` and `currentChild`.
* @param {Element} currentChild Start removing elements with `currentChild`. If
* `currentChild` is `elem` it won't be removed.
* @param {Element|null} elem The elemnt to look for.
*
* @private
*/
export function removeDomChildrenUntilElementFound (parent, currentChild, elem) {
while (currentChild !== elem) {
const del = currentChild
currentChild = currentChild.nextSibling
parent.removeChild(del)
}
}

View File

@@ -1,53 +0,0 @@
import Binding from '../Binding.js'
function typeObserver (event) {
const quill = this.target
// Force flush Quill changes.
quill.update('yjs')
this._mutualExclude(function () {
// Apply computed delta.
quill.updateContents(event.delta, 'yjs')
// Force flush Quill changes. Ignore applied changes.
quill.update('yjs')
})
}
function quillObserver (delta) {
this._mutualExclude(() => {
this.type.applyDelta(delta.ops)
})
}
/**
* A Binding that binds a YText type to a Quill editor.
*
* @example
* const quill = new Quill(document.createElement('div'))
* const type = y.define('quill', Y.Text)
* const binding = new Y.QuillBinding(quill, type)
* // Now modifications on the DOM will be reflected in the Type, and the other
* // way around!
*/
export default class QuillBinding extends Binding {
/**
* @param {YText} textType
* @param {Quill} quill
*/
constructor (textType, quill) {
// Binding handles textType as this.type and quill as this.target.
super(textType, quill)
// Set initial value.
quill.setContents(textType.toDelta(), 'yjs')
// Observers are handled by this class.
this._typeObserver = typeObserver.bind(this)
this._quillObserver = quillObserver.bind(this)
textType.observe(this._typeObserver)
quill.on('text-change', this._quillObserver)
}
destroy () {
// Remove everything that is handled by this class.
this.type.unobserve(this._typeObserver)
this.target.off('text-change', this._quillObserver)
super.destroy()
}
}

View File

@@ -1,56 +0,0 @@
import Binding from '../Binding.js'
import simpleDiff from '../../Util/simpleDiff.js'
import { getRelativePosition, fromRelativePosition } from '../../Util/relativePosition.js'
function typeObserver () {
this._mutualExclude(() => {
const textarea = this.target
const textType = this.type
const relativeStart = getRelativePosition(textType, textarea.selectionStart)
const relativeEnd = getRelativePosition(textType, textarea.selectionEnd)
textarea.value = textType.toString()
const start = fromRelativePosition(textType._y, relativeStart)
const end = fromRelativePosition(textType._y, relativeEnd)
textarea.setSelectionRange(start, end)
})
}
function domObserver () {
this._mutualExclude(() => {
let diff = simpleDiff(this.type.toString(), this.target.value)
this.type.delete(diff.pos, diff.remove)
this.type.insert(diff.pos, diff.insert)
})
}
/**
* A binding that binds a YText to a dom textarea.
*
* This binding is automatically destroyed when its parent is deleted.
*
* @example
* const textare = document.createElement('textarea')
* const type = y.define('textarea', Y.Text)
* const binding = new Y.QuillBinding(type, textarea)
*
*/
export default class TextareaBinding extends Binding {
constructor (textType, domTextarea) {
// Binding handles textType as this.type and domTextarea as this.target
super(textType, domTextarea)
// set initial value
domTextarea.value = textType.toString()
// Observers are handled by this class
this._typeObserver = typeObserver.bind(this)
this._domObserver = domObserver.bind(this)
textType.observe(this._typeObserver)
domTextarea.addEventListener('input', this._domObserver)
}
destroy () {
// Remove everything that is handled by this class
this.type.unobserve(this._typeObserver)
this.target.unobserve(this._domObserver)
super.destroy()
}
}

View File

@@ -1,297 +0,0 @@
import BinaryEncoder from './Util/Binary/Encoder.js'
import BinaryDecoder from './Util/Binary/Decoder.js'
import { sendSyncStep1, readSyncStep1 } from './MessageHandler/syncStep1.js'
import { readSyncStep2 } from './MessageHandler/syncStep2.js'
import { integrateRemoteStructs } from './MessageHandler/integrateRemoteStructs.js'
import debug from 'debug'
// TODO: rename Connector
export default class AbstractConnector {
constructor (y, opts) {
this.y = y
this.opts = opts
if (opts.role == null || opts.role === 'master') {
this.role = 'master'
} else if (opts.role === 'slave') {
this.role = 'slave'
} else {
throw new Error("Role must be either 'master' or 'slave'!")
}
this.log = debug('y:connector')
this.logMessage = debug('y:connector-message')
this._forwardAppliedStructs = opts.forwardAppliedOperations || false // TODO: rename
this.role = opts.role
this.connections = new Map()
this.isSynced = false
this.userEventListeners = []
this.whenSyncedListeners = []
this.currentSyncTarget = null
this.debug = opts.debug === true
this.broadcastBuffer = new BinaryEncoder()
this.broadcastBufferSize = 0
this.protocolVersion = 11
this.authInfo = opts.auth || null
this.checkAuth = opts.checkAuth || function () { return Promise.resolve('write') } // default is everyone has write access
if (opts.maxBufferLength == null) {
this.maxBufferLength = -1
} else {
this.maxBufferLength = opts.maxBufferLength
}
}
reconnect () {
this.log('reconnecting..')
}
disconnect () {
this.log('discronnecting..')
this.connections = new Map()
this.isSynced = false
this.currentSyncTarget = null
this.whenSyncedListeners = []
return Promise.resolve()
}
onUserEvent (f) {
this.userEventListeners.push(f)
}
removeUserEventListener (f) {
this.userEventListeners = this.userEventListeners.filter(g => f !== g)
}
userLeft (user) {
if (this.connections.has(user)) {
this.log('%s: User left %s', this.y.userID, user)
this.connections.delete(user)
// check if isSynced event can be sent now
this._setSyncedWith(null)
for (var f of this.userEventListeners) {
f({
action: 'userLeft',
user: user
})
}
}
}
userJoined (user, role, auth) {
if (role == null) {
throw new Error('You must specify the role of the joined user!')
}
if (this.connections.has(user)) {
throw new Error('This user already joined!')
}
this.log('%s: User joined %s', this.y.userID, user)
this.connections.set(user, {
uid: user,
isSynced: false,
role: role,
processAfterAuth: [],
processAfterSync: [],
auth: auth || null,
receivedSyncStep2: false
})
let defer = {}
defer.promise = new Promise(function (resolve) { defer.resolve = resolve })
this.connections.get(user).syncStep2 = defer
for (var f of this.userEventListeners) {
f({
action: 'userJoined',
user: user,
role: role
})
}
this._syncWithUser(user)
}
// Execute a function _when_ we are connected.
// If not connected, wait until connected
whenSynced (f) {
if (this.isSynced) {
f()
} else {
this.whenSyncedListeners.push(f)
}
}
_syncWithUser (userID) {
if (this.role === 'slave') {
return // "The current sync has not finished or this is controlled by a master!"
}
sendSyncStep1(this, userID)
}
_fireIsSyncedListeners () {
if (!this.isSynced) {
this.isSynced = true
// It is safer to remove this!
// call whensynced listeners
for (var f of this.whenSyncedListeners) {
f()
}
this.whenSyncedListeners = []
this.y._setContentReady()
this.y.emit('synced')
}
}
send (uid, buffer) {
const y = this.y
if (!(buffer instanceof ArrayBuffer || buffer instanceof Uint8Array)) {
throw new Error('Expected Message to be an ArrayBuffer or Uint8Array - don\'t use this method to send custom messages')
}
this.log('User%s to User%s: Send \'%y\'', y.userID, uid, buffer)
this.logMessage('User%s to User%s: Send %Y', y.userID, uid, [y, buffer])
}
broadcast (buffer) {
const y = this.y
if (!(buffer instanceof ArrayBuffer || buffer instanceof Uint8Array)) {
throw new Error('Expected Message to be an ArrayBuffer or Uint8Array - don\'t use this method to send custom messages')
}
this.log('User%s: Broadcast \'%y\'', y.userID, buffer)
this.logMessage('User%s: Broadcast: %Y', y.userID, [y, buffer])
}
/*
Buffer operations, and broadcast them when ready.
*/
broadcastStruct (struct) {
const firstContent = this.broadcastBuffer.length === 0
if (firstContent) {
this.broadcastBuffer.writeVarString(this.y.room)
this.broadcastBuffer.writeVarString('update')
this.broadcastBufferSize = 0
this.broadcastBufferSizePos = this.broadcastBuffer.pos
this.broadcastBuffer.writeUint32(0)
}
this.broadcastBufferSize++
struct._toBinary(this.broadcastBuffer)
if (this.maxBufferLength > 0 && this.broadcastBuffer.length > this.maxBufferLength) {
// it is necessary to send the buffer now
// cache the buffer and check if server is responsive
const buffer = this.broadcastBuffer
buffer.setUint32(this.broadcastBufferSizePos, this.broadcastBufferSize)
this.broadcastBuffer = new BinaryEncoder()
this.whenRemoteResponsive().then(() => {
this.broadcast(buffer.createBuffer())
})
} else if (firstContent) {
// send the buffer when all transactions are finished
// (or buffer exceeds maxBufferLength)
setTimeout(() => {
if (this.broadcastBuffer.length > 0) {
const buffer = this.broadcastBuffer
buffer.setUint32(this.broadcastBufferSizePos, this.broadcastBufferSize)
this.broadcast(buffer.createBuffer())
this.broadcastBuffer = new BinaryEncoder()
}
}, 0)
}
}
/*
* Somehow check the responsiveness of the remote clients/server
* Default behavior:
* Wait 100ms before broadcasting the next batch of operations
*
* Only used when maxBufferLength is set
*
*/
whenRemoteResponsive () {
return new Promise(function (resolve) {
setTimeout(resolve, 100)
})
}
/*
You received a raw message, and you know that it is intended for Yjs. Then call this function.
*/
receiveMessage (sender, buffer, skipAuth) {
const y = this.y
const userID = y.userID
skipAuth = skipAuth || false
if (!(buffer instanceof ArrayBuffer || buffer instanceof Uint8Array)) {
return Promise.reject(new Error('Expected Message to be an ArrayBuffer or Uint8Array!'))
}
if (sender === userID) {
return Promise.resolve()
}
let decoder = new BinaryDecoder(buffer)
let encoder = new BinaryEncoder()
let roomname = decoder.readVarString() // read room name
encoder.writeVarString(roomname)
let messageType = decoder.readVarString()
let senderConn = this.connections.get(sender)
this.log('User%s from User%s: Receive \'%s\'', userID, sender, messageType)
this.logMessage('User%s from User%s: Receive %Y', userID, sender, [y, buffer])
if (senderConn == null && !skipAuth) {
throw new Error('Received message from unknown peer!')
}
if (messageType === 'sync step 1' || messageType === 'sync step 2') {
let auth = decoder.readVarUint()
if (senderConn.auth == null) {
senderConn.processAfterAuth.push([messageType, senderConn, decoder, encoder, sender])
// check auth
return this.checkAuth(auth, y, sender).then(authPermissions => {
if (senderConn.auth == null) {
senderConn.auth = authPermissions
y.emit('userAuthenticated', {
user: senderConn.uid,
auth: authPermissions
})
}
let messages = senderConn.processAfterAuth
senderConn.processAfterAuth = []
messages.forEach(m =>
this.computeMessage(m[0], m[1], m[2], m[3], m[4])
)
})
}
}
if ((skipAuth || senderConn.auth != null) && (messageType !== 'update' || senderConn.isSynced)) {
this.computeMessage(messageType, senderConn, decoder, encoder, sender, skipAuth)
} else {
senderConn.processAfterSync.push([messageType, senderConn, decoder, encoder, sender, false])
}
}
computeMessage (messageType, senderConn, decoder, encoder, sender, skipAuth) {
if (messageType === 'sync step 1' && (senderConn.auth === 'write' || senderConn.auth === 'read')) {
// cannot wait for sync step 1 to finish, because we may wait for sync step 2 in sync step 1 (->lock)
readSyncStep1(decoder, encoder, this.y, senderConn, sender)
} else {
const y = this.y
y.transact(function () {
if (messageType === 'sync step 2' && senderConn.auth === 'write') {
readSyncStep2(decoder, encoder, y, senderConn, sender)
} else if (messageType === 'update' && (skipAuth || senderConn.auth === 'write')) {
integrateRemoteStructs(y, decoder)
} else {
throw new Error('Unable to receive message')
}
}, true)
}
}
_setSyncedWith (user) {
if (user != null) {
const userConn = this.connections.get(user)
userConn.isSynced = true
const messages = userConn.processAfterSync
userConn.processAfterSync = []
messages.forEach(m => {
this.computeMessage(m[0], m[1], m[2], m[3], m[4])
})
}
const conns = Array.from(this.connections.values())
if (conns.length > 0 && conns.every(u => u.isSynced)) {
this._fireIsSyncedListeners()
}
}
}

View File

@@ -1,32 +0,0 @@
import { writeStructs } from './syncStep1.js'
import { integrateRemoteStructs } from './integrateRemoteStructs.js'
import { readDeleteSet, writeDeleteSet } from './deleteSet.js'
import BinaryEncoder from '../Util/Binary/Encoder.js'
/**
* Read the Decoder and fill the Yjs instance with data in the decoder.
*
* @param {Y} y The Yjs instance
* @param {BinaryDecoder} decoder The BinaryDecoder to read from.
*/
export function fromBinary (y, decoder) {
y.transact(function () {
integrateRemoteStructs(y, decoder)
readDeleteSet(y, decoder)
})
}
/**
* Encode the Yjs model to binary format.
*
* @param {Y} y The Yjs instance
* @return {BinaryEncoder} The encoder instance that can be transformed
* to ArrayBuffer or Buffer.
*/
export function toBinary (y) {
let encoder = new BinaryEncoder()
writeStructs(y, encoder, new Map())
writeDeleteSet(y, encoder)
return encoder
}

View File

@@ -1,130 +0,0 @@
import { deleteItemRange } from '../Struct/Delete.js'
import ID from '../Util/ID/ID.js'
export function stringifyDeleteSet (y, decoder, strBuilder) {
let dsLength = decoder.readUint32()
for (let i = 0; i < dsLength; i++) {
let user = decoder.readVarUint()
strBuilder.push(' -' + user + ':')
let dvLength = decoder.readVarUint()
for (let j = 0; j < dvLength; j++) {
let from = decoder.readVarUint()
let len = decoder.readVarUint()
let gc = decoder.readUint8() === 1
strBuilder.push(`clock: ${from}, length: ${len}, gc: ${gc}`)
}
}
return strBuilder
}
export function writeDeleteSet (y, encoder) {
let currentUser = null
let currentLength
let lastLenPos
let numberOfUsers = 0
let laterDSLenPus = encoder.pos
encoder.writeUint32(0)
y.ds.iterate(null, null, function (n) {
var user = n._id.user
var clock = n._id.clock
var len = n.len
var gc = n.gc
if (currentUser !== user) {
numberOfUsers++
// a new user was found
if (currentUser !== null) { // happens on first iteration
encoder.setUint32(lastLenPos, currentLength)
}
currentUser = user
encoder.writeVarUint(user)
// pseudo-fill pos
lastLenPos = encoder.pos
encoder.writeUint32(0)
currentLength = 0
}
encoder.writeVarUint(clock)
encoder.writeVarUint(len)
encoder.writeUint8(gc ? 1 : 0)
currentLength++
})
if (currentUser !== null) { // happens on first iteration
encoder.setUint32(lastLenPos, currentLength)
}
encoder.setUint32(laterDSLenPus, numberOfUsers)
}
export function readDeleteSet (y, decoder) {
let dsLength = decoder.readUint32()
for (let i = 0; i < dsLength; i++) {
let user = decoder.readVarUint()
let dv = []
let dvLength = decoder.readUint32()
for (let j = 0; j < dvLength; j++) {
let from = decoder.readVarUint()
let len = decoder.readVarUint()
let gc = decoder.readUint8() === 1
dv.push([from, len, gc])
}
if (dvLength > 0) {
let pos = 0
let d = dv[pos]
let deletions = []
y.ds.iterate(new ID(user, 0), new ID(user, Number.MAX_VALUE), function (n) {
// cases:
// 1. d deletes something to the right of n
// => go to next n (break)
// 2. d deletes something to the left of n
// => create deletions
// => reset d accordingly
// *)=> if d doesn't delete anything anymore, go to next d (continue)
// 3. not 2) and d deletes something that also n deletes
// => reset d so that it doesn't contain n's deletion
// *)=> if d does not delete anything anymore, go to next d (continue)
while (d != null) {
var diff = 0 // describe the diff of length in 1) and 2)
if (n._id.clock + n.len <= d[0]) {
// 1)
break
} else if (d[0] < n._id.clock) {
// 2)
// delete maximum the len of d
// else delete as much as possible
diff = Math.min(n._id.clock - d[0], d[1])
// deleteItemRange(y, user, d[0], diff, true)
deletions.push([user, d[0], diff])
} else {
// 3)
diff = n._id.clock + n.len - d[0] // never null (see 1)
if (d[2] && !n.gc) {
// d marks as gc'd but n does not
// then delete either way
// deleteItemRange(y, user, d[0], Math.min(diff, d[1]), true)
deletions.push([user, d[0], Math.min(diff, d[1])])
}
}
if (d[1] <= diff) {
// d doesn't delete anything anymore
d = dv[++pos]
} else {
d[0] = d[0] + diff // reset pos
d[1] = d[1] - diff // reset length
}
}
})
// TODO: It would be more performant to apply the deletes in the above loop
// Adapt the Tree implementation to support delete while iterating
for (let i = deletions.length - 1; i >= 0; i--) {
const del = deletions[i]
deleteItemRange(y, del[0], del[1], del[2], true)
}
// for the rest.. just apply it
for (; pos < dv.length; pos++) {
d = dv[pos]
deleteItemRange(y, user, d[0], d[1], true)
// deletions.push([user, d[0], d[1], d[2]])
}
}
}
}

View File

@@ -1,109 +0,0 @@
import { getStruct } from '../Util/structReferences.js'
import BinaryDecoder from '../Util/Binary/Decoder.js'
import { logID } from './messageToString.js'
import GC from '../Struct/GC.js'
class MissingEntry {
constructor (decoder, missing, struct) {
this.decoder = decoder
this.missing = missing.length
this.struct = struct
}
}
/**
* @private
* Integrate remote struct
* When a remote struct is integrated, other structs might be ready to ready to
* integrate.
*/
function _integrateRemoteStructHelper (y, struct) {
const id = struct._id
if (id === undefined) {
struct._integrate(y)
} else {
if (y.ss.getState(id.user) > id.clock) {
return
}
if (!y.gcEnabled || struct.constructor === GC || (struct._parent.constructor !== GC && struct._parent._deleted === false)) {
// Is either a GC or Item with an undeleted parent
// save to integrate
struct._integrate(y)
} else {
// Is an Item. parent was deleted.
struct._gc(y)
}
let msu = y._missingStructs.get(id.user)
if (msu != null) {
let clock = id.clock
const finalClock = clock + struct._length
for (;clock < finalClock; clock++) {
const missingStructs = msu.get(clock)
if (missingStructs !== undefined) {
missingStructs.forEach(missingDef => {
missingDef.missing--
if (missingDef.missing === 0) {
const decoder = missingDef.decoder
let oldPos = decoder.pos
let missing = missingDef.struct._fromBinary(y, decoder)
decoder.pos = oldPos
if (missing.length === 0) {
y._readyToIntegrate.push(missingDef.struct)
}
}
})
msu.delete(clock)
}
}
}
}
}
export function stringifyStructs (y, decoder, strBuilder) {
const len = decoder.readUint32()
for (let i = 0; i < len; i++) {
let reference = decoder.readVarUint()
let Constr = getStruct(reference)
let struct = new Constr()
let missing = struct._fromBinary(y, decoder)
let logMessage = ' ' + struct._logString()
if (missing.length > 0) {
logMessage += ' .. missing: ' + missing.map(logID).join(', ')
}
strBuilder.push(logMessage)
}
}
export function integrateRemoteStructs (y, decoder) {
const len = decoder.readUint32()
for (let i = 0; i < len; i++) {
let reference = decoder.readVarUint()
let Constr = getStruct(reference)
let struct = new Constr()
let decoderPos = decoder.pos
let missing = struct._fromBinary(y, decoder)
if (missing.length === 0) {
while (struct != null) {
_integrateRemoteStructHelper(y, struct)
struct = y._readyToIntegrate.shift()
}
} else {
let _decoder = new BinaryDecoder(decoder.uint8arr)
_decoder.pos = decoderPos
let missingEntry = new MissingEntry(_decoder, missing, struct)
let missingStructs = y._missingStructs
for (let i = missing.length - 1; i >= 0; i--) {
let m = missing[i]
if (!missingStructs.has(m.user)) {
missingStructs.set(m.user, new Map())
}
let msu = missingStructs.get(m.user)
if (!msu.has(m.clock)) {
msu.set(m.clock, [])
}
let mArray = msu = msu.get(m.clock)
mArray.push(missingEntry)
}
}
}
}

View File

@@ -1,65 +0,0 @@
import BinaryDecoder from '../Util/Binary/Decoder.js'
import { stringifyStructs } from './integrateRemoteStructs.js'
import { stringifySyncStep1 } from './syncStep1.js'
import { stringifySyncStep2 } from './syncStep2.js'
import ID from '../Util/ID/ID.js'
import RootID from '../Util/ID/RootID.js'
import Y from '../Y.js'
export function messageToString ([y, buffer]) {
let decoder = new BinaryDecoder(buffer)
decoder.readVarString() // read roomname
let type = decoder.readVarString()
let strBuilder = []
strBuilder.push('\n === ' + type + ' ===')
if (type === 'update') {
stringifyStructs(y, decoder, strBuilder)
} else if (type === 'sync step 1') {
stringifySyncStep1(y, decoder, strBuilder)
} else if (type === 'sync step 2') {
stringifySyncStep2(y, decoder, strBuilder)
} else {
strBuilder.push('-- Unknown message type - probably an encoding issue!!!')
}
return strBuilder.join('\n')
}
export function messageToRoomname (buffer) {
let decoder = new BinaryDecoder(buffer)
decoder.readVarString() // roomname
return decoder.readVarString() // messageType
}
export function logID (id) {
if (id !== null && id._id != null) {
id = id._id
}
if (id === null) {
return '()'
} else if (id instanceof ID) {
return `(${id.user},${id.clock})`
} else if (id instanceof RootID) {
return `(${id.name},${id.type})`
} else if (id.constructor === Y) {
return `y`
} else {
throw new Error('This is not a valid ID!')
}
}
/**
* Helper utility to convert an item to a readable format.
*
* @param {String} name The name of the item class (YText, ItemString, ..).
* @param {Item} item The item instance.
* @param {String} [append] Additional information to append to the returned
* string.
* @return {String} A readable string that represents the item object.
*
* @private
*/
export function logItemHelper (name, item, append) {
const left = item._left !== null ? item._left._lastId : null
const origin = item._origin !== null ? item._origin._lastId : null
return `${name}(id:${logID(item._id)},start:${logID(item._start)},left:${logID(left)},origin:${logID(origin)},right:${logID(item._right)},parent:${logID(item._parent)},parentSub:${item._parentSub}${append !== undefined ? ' - ' + append : ''})`
}

View File

@@ -1,23 +0,0 @@
export function readStateSet (decoder) {
let ss = new Map()
let ssLength = decoder.readUint32()
for (let i = 0; i < ssLength; i++) {
let user = decoder.readVarUint()
let clock = decoder.readVarUint()
ss.set(user, clock)
}
return ss
}
export function writeStateSet (y, encoder) {
let lenPosition = encoder.pos
let len = 0
encoder.writeUint32(0)
for (let [user, clock] of y.ss.state) {
encoder.writeVarUint(user)
encoder.writeVarUint(clock)
len++
}
encoder.setUint32(lenPosition, len)
}

View File

@@ -1,83 +0,0 @@
import BinaryEncoder from '../Util/Binary/Encoder.js'
import { readStateSet, writeStateSet } from './stateSet.js'
import { writeDeleteSet } from './deleteSet.js'
import ID from '../Util/ID/ID.js'
import { RootFakeUserID } from '../Util/ID/RootID.js'
export function stringifySyncStep1 (y, decoder, strBuilder) {
let auth = decoder.readVarString()
let protocolVersion = decoder.readVarUint()
strBuilder.push(` - auth: "${auth}"`)
strBuilder.push(` - protocolVersion: ${protocolVersion}`)
// write SS
let ssBuilder = []
let len = decoder.readUint32()
for (let i = 0; i < len; i++) {
let user = decoder.readVarUint()
let clock = decoder.readVarUint()
ssBuilder.push(`(${user}:${clock})`)
}
strBuilder.push(' == SS: ' + ssBuilder.join(','))
}
export function sendSyncStep1 (connector, syncUser) {
let encoder = new BinaryEncoder()
encoder.writeVarString(connector.y.room)
encoder.writeVarString('sync step 1')
encoder.writeVarString(connector.authInfo || '')
encoder.writeVarUint(connector.protocolVersion)
writeStateSet(connector.y, encoder)
connector.send(syncUser, encoder.createBuffer())
}
/**
* @private
* Write all Items that are not not included in ss to
* the encoder object.
*/
export function writeStructs (y, encoder, ss) {
const lenPos = encoder.pos
encoder.writeUint32(0)
let len = 0
for (let user of y.ss.state.keys()) {
let clock = ss.get(user) || 0
if (user !== RootFakeUserID) {
const minBound = new ID(user, clock)
const overlappingLeft = y.os.findPrev(minBound)
const rightID = overlappingLeft === null ? null : overlappingLeft._id
if (rightID !== null && rightID.user === user && rightID.clock + overlappingLeft._length > clock) {
const struct = overlappingLeft._clonePartial(clock - rightID.clock)
struct._toBinary(encoder)
len++
}
y.os.iterate(minBound, new ID(user, Number.MAX_VALUE), function (struct) {
struct._toBinary(encoder)
len++
})
}
}
encoder.setUint32(lenPos, len)
}
export function readSyncStep1 (decoder, encoder, y, senderConn, sender) {
let protocolVersion = decoder.readVarUint()
// check protocol version
if (protocolVersion !== y.connector.protocolVersion) {
console.warn(
`You tried to sync with a Yjs instance that has a different protocol version
(You: ${protocolVersion}, Client: ${protocolVersion}).
`)
y.destroy()
}
// write sync step 2
encoder.writeVarString('sync step 2')
encoder.writeVarString(y.connector.authInfo || '')
const ss = readStateSet(decoder)
writeStructs(y, encoder, ss)
writeDeleteSet(y, encoder)
y.connector.send(senderConn.uid, encoder.createBuffer())
senderConn.receivedSyncStep2 = true
if (y.connector.role === 'slave') {
sendSyncStep1(y.connector, sender)
}
}

View File

@@ -1,28 +0,0 @@
import { stringifyStructs, integrateRemoteStructs } from './integrateRemoteStructs.js'
import { readDeleteSet } from './deleteSet.js'
export function stringifySyncStep2 (y, decoder, strBuilder) {
strBuilder.push(' - auth: ' + decoder.readVarString())
strBuilder.push(' == OS:')
stringifyStructs(y, decoder, strBuilder)
// write DS to string
strBuilder.push(' == DS:')
let len = decoder.readUint32()
for (let i = 0; i < len; i++) {
let user = decoder.readVarUint()
strBuilder.push(` User: ${user}: `)
let len2 = decoder.readUint32()
for (let j = 0; j < len2; j++) {
let from = decoder.readVarUint()
let to = decoder.readVarUint()
let gc = decoder.readUint8() === 1
strBuilder.push(`[${from}, ${to}, ${gc}]`)
}
}
}
export function readSyncStep2 (decoder, encoder, y, senderConn, sender) {
integrateRemoteStructs(y, decoder)
readDeleteSet(y, decoder)
y.connector._setSyncedWith(sender)
}

View File

@@ -1,122 +0,0 @@
import BinaryEncoder from './Util/Binary/Encoder.js'
import BinaryDecoder from './Util/Binary/Decoder.js'
import { toBinary, fromBinary } from './MessageHandler/binaryEncode.js'
import { integrateRemoteStructs } from './MessageHandler/integrateRemoteStructs.js'
import { createMutualExclude } from './Util/mutualExclude.js'
function getFreshCnf () {
let buffer = new BinaryEncoder()
buffer.writeUint32(0)
return {
len: 0,
buffer
}
}
/**
* Abstract persistence class.
*/
export default class AbstractPersistence {
constructor (opts) {
this.opts = opts
this.ys = new Map()
}
_init (y) {
let cnf = this.ys.get(y)
if (cnf === undefined) {
cnf = getFreshCnf()
cnf.mutualExclude = createMutualExclude()
this.ys.set(y, cnf)
return this.init(y).then(() => {
y.on('afterTransaction', (y, transaction) => {
let cnf = this.ys.get(y)
if (cnf.len > 0) {
cnf.buffer.setUint32(0, cnf.len)
this.saveUpdate(y, cnf.buffer.createBuffer(), transaction)
let _cnf = getFreshCnf()
for (let key in _cnf) {
cnf[key] = _cnf[key]
}
}
})
return this.retrieve(y)
}).then(function () {
return Promise.resolve(cnf)
})
} else {
return Promise.resolve(cnf)
}
}
deinit (y) {
this.ys.delete(y)
y.persistence = null
}
destroy () {
this.ys = null
}
/**
* Remove all persisted data that belongs to a room.
* Automatically destroys all Yjs all Yjs instances that persist to
* the room. If `destroyYjsInstances = false` the persistence functionality
* will be removed from the Yjs instances.
*
* ** Must be overwritten! **
*/
removePersistedData (room, destroyYjsInstances = true) {
this.ys.forEach((cnf, y) => {
if (y.room === room) {
if (destroyYjsInstances) {
y.destroy()
} else {
this.deinit(y)
}
}
})
}
/* overwrite */
saveUpdate (buffer) {
}
/**
* Save struct to update buffer.
* saveUpdate is called when transaction ends
*/
saveStruct (y, struct) {
let cnf = this.ys.get(y)
if (cnf !== undefined) {
cnf.mutualExclude(function () {
struct._toBinary(cnf.buffer)
cnf.len++
})
}
}
/* overwrite */
retrieve (y, model, updates) {
let cnf = this.ys.get(y)
if (cnf !== undefined) {
cnf.mutualExclude(function () {
y.transact(function () {
if (model != null) {
fromBinary(y, new BinaryDecoder(new Uint8Array(model)))
}
if (updates != null) {
for (let i = 0; i < updates.length; i++) {
integrateRemoteStructs(y, new BinaryDecoder(new Uint8Array(updates[i])))
}
}
})
y.emit('persistenceReady')
})
}
}
/* overwrite */
persist (y) {
return toBinary(y).createBuffer()
}
}

View File

@@ -1,90 +0,0 @@
import Tree from '../Util/Tree.js'
import ID from '../Util/ID/ID.js'
class DSNode {
constructor (id, len, gc) {
this._id = id
this.len = len
this.gc = gc
}
clone () {
return new DSNode(this._id, this.len, this.gc)
}
}
export default class DeleteStore extends Tree {
logTable () {
const deletes = []
this.iterate(null, null, function (n) {
deletes.push({
user: n._id.user,
clock: n._id.clock,
len: n.len,
gc: n.gc
})
})
console.table(deletes)
}
isDeleted (id) {
var n = this.findWithUpperBound(id)
return n !== null && n._id.user === id.user && id.clock < n._id.clock + n.len
}
mark (id, length, gc) {
if (length === 0) return
// Step 1. Unmark range
const leftD = this.findWithUpperBound(new ID(id.user, id.clock - 1))
// Resize left DSNode if necessary
if (leftD !== null && leftD._id.user === id.user) {
if (leftD._id.clock < id.clock && id.clock < leftD._id.clock + leftD.len) {
// node is overlapping. need to resize
if (id.clock + length < leftD._id.clock + leftD.len) {
// overlaps new mark range and some more
// create another DSNode to the right of new mark
this.put(new DSNode(new ID(id.user, id.clock + length), leftD._id.clock + leftD.len - id.clock - length, leftD.gc))
}
// resize left DSNode
leftD.len = id.clock - leftD._id.clock
} // Otherwise there is no overlapping
}
// Resize right DSNode if necessary
const upper = new ID(id.user, id.clock + length - 1)
const rightD = this.findWithUpperBound(upper)
if (rightD !== null && rightD._id.user === id.user) {
if (rightD._id.clock < id.clock + length && id.clock <= rightD._id.clock && id.clock + length < rightD._id.clock + rightD.len) { // we only consider the case where we resize the node
const d = id.clock + length - rightD._id.clock
rightD._id = new ID(rightD._id.user, rightD._id.clock + d)
rightD.len -= d
}
}
// Now we only have to delete all inner marks
const deleteNodeIds = []
this.iterate(id, upper, m => {
deleteNodeIds.push(m._id)
})
for (let i = deleteNodeIds.length - 1; i >= 0; i--) {
this.delete(deleteNodeIds[i])
}
let newMark = new DSNode(id, length, gc)
// Step 2. Check if we can extend left or right
if (leftD !== null && leftD._id.user === id.user && leftD._id.clock + leftD.len === id.clock && leftD.gc === gc) {
// We can extend left
leftD.len += length
newMark = leftD
}
const rightNext = this.find(new ID(id.user, id.clock + length))
if (rightNext !== null && rightNext._id.user === id.user && id.clock + length === rightNext._id.clock && gc === rightNext.gc) {
// We can merge newMark and rightNext
newMark.len += rightNext.len
this.delete(rightNext._id)
}
if (leftD !== newMark) {
// only put if we didn't extend left
this.put(newMark)
}
}
// TODO: exchange markDeleted for mark()
markDeleted (id, length) {
this.mark(id, length, false)
}
}

View File

@@ -1,94 +0,0 @@
import Tree from '../Util/Tree.js'
import RootID from '../Util/ID/RootID.js'
import { getStruct } from '../Util/structReferences.js'
import { logID } from '../MessageHandler/messageToString.js'
import GC from '../Struct/GC.js'
export default class OperationStore extends Tree {
constructor (y) {
super()
this.y = y
}
logTable () {
const items = []
this.iterate(null, null, function (item) {
if (item.constructor === GC) {
items.push({
id: logID(item),
content: item._length,
deleted: 'GC'
})
} else {
items.push({
id: logID(item),
origin: logID(item._origin === null ? null : item._origin._lastId),
left: logID(item._left === null ? null : item._left._lastId),
right: logID(item._right),
right_origin: logID(item._right_origin),
parent: logID(item._parent),
parentSub: item._parentSub,
deleted: item._deleted,
content: JSON.stringify(item._content)
})
}
})
console.table(items)
}
get (id) {
let struct = this.find(id)
if (struct === null && id instanceof RootID) {
const Constr = getStruct(id.type)
const y = this.y
struct = new Constr()
struct._id = id
struct._parent = y
y.transact(() => {
struct._integrate(y)
})
this.put(struct)
}
return struct
}
// Use getItem for structs with _length > 1
getItem (id) {
var item = this.findWithUpperBound(id)
if (item === null) {
return null
}
const itemID = item._id
if (id.user === itemID.user && id.clock < itemID.clock + item._length) {
return item
} else {
return null
}
}
// Return an insertion such that id is the first element of content
// This function manipulates an item, if necessary
getItemCleanStart (id) {
var ins = this.getItem(id)
if (ins === null || ins._length === 1) {
return ins
}
const insID = ins._id
if (insID.clock === id.clock) {
return ins
} else {
return ins._splitAt(this.y, id.clock - insID.clock)
}
}
// Return an insertion such that id is the last element of content
// This function manipulates an operation, if necessary
getItemCleanEnd (id) {
var ins = this.getItem(id)
if (ins === null || ins._length === 1) {
return ins
}
const insID = ins._id
if (insID.clock + ins._length - 1 === id.clock) {
return ins
} else {
ins._splitAt(this.y, id.clock - insID.clock + 1)
return ins
}
}
}

View File

@@ -1,47 +0,0 @@
import ID from '../Util/ID/ID.js'
export default class StateStore {
constructor (y) {
this.y = y
this.state = new Map()
}
logTable () {
const entries = []
for (let [user, state] of this.state) {
entries.push({
user, state
})
}
console.table(entries)
}
getNextID (len) {
const user = this.y.userID
const state = this.getState(user)
this.setState(user, state + len)
return new ID(user, state)
}
updateRemoteState (struct) {
let user = struct._id.user
let userState = this.state.get(user)
while (struct !== null && struct._id.clock === userState) {
userState += struct._length
struct = this.y.os.get(new ID(user, userState))
}
this.state.set(user, userState)
}
getState (user) {
let state = this.state.get(user)
if (state == null) {
return 0
}
return state
}
setState (user, state) {
// TODO: modify missingi structs here
const beforeState = this.y._transaction.beforeState
if (!beforeState.has(user)) {
beforeState.set(user, this.getState(user))
}
this.state.set(user, state)
}
}

View File

@@ -1,122 +0,0 @@
import { getStructReference } from '../Util/structReferences.js'
import ID from '../Util/ID/ID.js'
import { logID } from '../MessageHandler/messageToString.js'
/**
* @private
* Delete all items in an ID-range
* TODO: implement getItemCleanStartNode for better performance (only one lookup)
*/
export function deleteItemRange (y, user, clock, range, gcChildren) {
const createDelete = y.connector !== null && y.connector._forwardAppliedStructs
let item = y.os.getItemCleanStart(new ID(user, clock))
if (item !== null) {
if (!item._deleted) {
item._splitAt(y, range)
item._delete(y, createDelete, true)
}
let itemLen = item._length
range -= itemLen
clock += itemLen
if (range > 0) {
let node = y.os.findNode(new ID(user, clock))
while (node !== null && node.val !== null && range > 0 && node.val._id.equals(new ID(user, clock))) {
const nodeVal = node.val
if (!nodeVal._deleted) {
nodeVal._splitAt(y, range)
nodeVal._delete(y, createDelete, gcChildren)
}
const nodeLen = nodeVal._length
range -= nodeLen
clock += nodeLen
node = node.next()
}
}
}
}
/**
* @private
* A Delete change is not a real Item, but it provides the same interface as an
* Item. The only difference is that it will not be saved in the ItemStore
* (OperationStore), but instead it is safed in the DeleteStore.
*/
export default class Delete {
constructor () {
this._target = null
this._length = null
}
/**
* @private
* Read the next Item in a Decoder and fill this Item with the read data.
*
* This is called when data is received from a remote peer.
*
* @param {Y} y The Yjs instance that this Item belongs to.
* @param {BinaryDecoder} decoder The decoder object to read data from.
*/
_fromBinary (y, decoder) {
// TODO: set target, and add it to missing if not found
// There is an edge case in p2p networks!
const targetID = decoder.readID()
this._targetID = targetID
this._length = decoder.readVarUint()
if (y.os.getItem(targetID) === null) {
return [targetID]
} else {
return []
}
}
/**
* @private
* Transform the properties of this type to binary and write it to an
* BinaryEncoder.
*
* This is called when this Item is sent to a remote peer.
*
* @param {BinaryEncoder} encoder The encoder to write data to.
*/
_toBinary (encoder) {
encoder.writeUint8(getStructReference(this.constructor))
encoder.writeID(this._targetID)
encoder.writeVarUint(this._length)
}
/**
* @private
* Integrates this Item into the shared structure.
*
* This method actually applies the change to the Yjs instance. In the case of
* Delete it marks the delete target as deleted.
*
* * If created remotely (a remote user deleted something),
* this Delete is applied to all structs in id-range.
* * If created lokally (e.g. when y-array deletes a range of elements),
* this struct is broadcasted only (it is already executed)
*/
_integrate (y, locallyCreated = false) {
if (!locallyCreated) {
// from remote
const id = this._targetID
deleteItemRange(y, id.user, id.clock, this._length, false)
} else if (y.connector !== null) {
// from local
y.connector.broadcastStruct(this)
}
if (y.persistence !== null) {
y.persistence.saveStruct(y, this)
}
}
/**
* Transform this YXml Type to a readable format.
* Useful for logging as all Items and Delete implement this method.
*
* @private
*/
_logString () {
return `Delete - target: ${logID(this._targetID)}, len: ${this._length}`
}
}

View File

@@ -1,94 +0,0 @@
import { getStructReference } from '../Util/structReferences.js'
import { RootFakeUserID } from '../Util/ID/RootID.js'
import ID from '../Util/ID/ID.js'
// TODO should have the same base class as Item
export default class GC {
constructor () {
this._id = null
this._length = 0
}
get _deleted () {
return true
}
_integrate (y) {
const id = this._id
const userState = y.ss.getState(id.user)
if (id.clock === userState) {
y.ss.setState(id.user, id.clock + this._length)
}
y.ds.mark(this._id, this._length, true)
let n = y.os.put(this)
const prev = n.prev().val
if (prev !== null && prev.constructor === GC && prev._id.user === n.val._id.user && prev._id.clock + prev._length === n.val._id.clock) {
// TODO: do merging for all items!
prev._length += n.val._length
y.os.delete(n.val._id)
n = prev
}
if (n.val) {
n = n.val
}
const next = y.os.findNext(n._id)
if (next !== null && next.constructor === GC && next._id.user === n._id.user && next._id.clock === n._id.clock + n._length) {
n._length += next._length
y.os.delete(next._id)
}
if (id.user !== RootFakeUserID) {
if (y.connector !== null && (y.connector._forwardAppliedStructs || id.user === y.userID)) {
y.connector.broadcastStruct(this)
}
if (y.persistence !== null) {
y.persistence.saveStruct(y, this)
}
}
}
/**
* Transform the properties of this type to binary and write it to an
* BinaryEncoder.
*
* This is called when this Item is sent to a remote peer.
*
* @param {BinaryEncoder} encoder The encoder to write data to.
* @private
*/
_toBinary (encoder) {
encoder.writeUint8(getStructReference(this.constructor))
encoder.writeID(this._id)
encoder.writeVarUint(this._length)
}
/**
* Read the next Item in a Decoder and fill this Item with the read data.
*
* This is called when data is received from a remote peer.
*
* @param {Y} y The Yjs instance that this Item belongs to.
* @param {BinaryDecoder} decoder The decoder object to read data from.
* @private
*/
_fromBinary (y, decoder) {
const id = decoder.readID()
this._id = id
this._length = decoder.readVarUint()
const missing = []
if (y.ss.getState(id.user) < id.clock) {
missing.push(new ID(id.user, id.clock - 1))
}
return missing
}
_splitAt () {
return this
}
_clonePartial (diff) {
const gc = new GC()
gc._id = new ID(this._id.user, this._id.clock + diff)
gc._length = this._length - diff
return gc
}
}

View File

@@ -1,527 +0,0 @@
import { getStructReference } from '../Util/structReferences.js'
import ID from '../Util/ID/ID.js'
import { default as RootID, RootFakeUserID } from '../Util/ID/RootID.js'
import Delete from './Delete.js'
import { transactionTypeChanged } from '../Transaction.js'
import GC from './GC.js'
/**
* @private
* Helper utility to split an Item (see {@link Item#_splitAt})
* - copies all properties from a to b
* - connects a to b
* - assigns the correct _id
* - saves b to os
*/
export function splitHelper (y, a, b, diff) {
const aID = a._id
b._id = new ID(aID.user, aID.clock + diff)
b._origin = a
b._left = a
b._right = a._right
if (b._right !== null) {
b._right._left = b
}
b._right_origin = a._right_origin
// do not set a._right_origin, as this will lead to problems when syncing
a._right = b
b._parent = a._parent
b._parentSub = a._parentSub
b._deleted = a._deleted
// now search all relevant items to the right and update origin
// if origin is not it foundOrigins, we don't have to search any longer
let foundOrigins = new Set()
foundOrigins.add(a)
let o = b._right
while (o !== null && foundOrigins.has(o._origin)) {
if (o._origin === a) {
o._origin = b
}
foundOrigins.add(o)
o = o._right
}
y.os.put(b)
if (y._transaction.newTypes.has(a)) {
y._transaction.newTypes.add(b)
} else if (y._transaction.deletedStructs.has(a)) {
y._transaction.deletedStructs.add(b)
}
}
/**
* Abstract class that represents any content.
*/
export default class Item {
constructor () {
/**
* The uniqe identifier of this type.
* @type {ID}
*/
this._id = null
/**
* The item that was originally to the left of this item.
* @type {Item}
*/
this._origin = null
/**
* The item that is currently to the left of this item.
* @type {Item}
*/
this._left = null
/**
* The item that is currently to the right of this item.
* @type {Item}
*/
this._right = null
/**
* The item that was originally to the right of this item.
* @type {Item}
*/
this._right_origin = null
/**
* The parent type.
* @type {Y|YType}
*/
this._parent = null
/**
* If the parent refers to this item with some kind of key (e.g. YMap, the
* key is specified here. The key is then used to refer to the list in which
* to insert this item. If `parentSub = null` type._start is the list in
* which to insert to. Otherwise it is `parent._start`.
* @type {String}
*/
this._parentSub = null
/**
* Whether this item was deleted or not.
* @type {Boolean}
*/
this._deleted = false
/**
* If this type's effect is reundone this type refers to the type that undid
* this operation.
* @type {Item}
*/
this._redone = null
}
/**
* Creates an Item with the same effect as this Item (without position effect)
*
* @private
*/
_copy () {
return new this.constructor()
}
/**
* Redoes the effect of this operation.
*
* @param {Y} y The Yjs instance.
*
* @private
*/
_redo (y) {
if (this._redone !== null) {
return this._redone
}
let struct = this._copy()
let left = this._left
let right = this
let parent = this._parent
// make sure that parent is redone
if (parent._deleted === true && parent._redone === null) {
parent._redo(y)
}
if (parent._redone !== null) {
parent = parent._redone
// find next cloned items
while (left !== null) {
if (left._redone !== null && left._redone._parent === parent) {
left = left._redone
break
}
left = left._left
}
while (right !== null) {
if (right._redone !== null && right._redone._parent === parent) {
right = right._redone
}
right = right._right
}
}
struct._origin = left
struct._left = left
struct._right = right
struct._right_origin = right
struct._parent = parent
struct._parentSub = this._parentSub
struct._integrate(y)
this._redone = struct
return struct
}
/**
* Computes the last content address of this Item.
*
* @private
*/
get _lastId () {
return new ID(this._id.user, this._id.clock + this._length - 1)
}
/**
* Computes the length of this Item.
*
* @private
*/
get _length () {
return 1
}
/**
* Should return false if this Item is some kind of meta information
* (e.g. format information).
*
* * Whether this Item should be addressable via `yarray.get(i)`
* * Whether this Item should be counted when computing yarray.length
*
* @private
*/
get _countable () {
return true
}
/**
* Splits this Item so that another Items can be inserted in-between.
* This must be overwritten if _length > 1
* Returns right part after split
* * diff === 0 => this
* * diff === length => this._right
* * otherwise => split _content and return right part of split
* (see {@link ItemJSON}/{@link ItemString} for implementation)
*
* @private
*/
_splitAt (y, diff) {
if (diff === 0) {
return this
}
return this._right
}
/**
* Mark this Item as deleted.
*
* @param {Y} y The Yjs instance
* @param {boolean} createDelete Whether to propagate a message that this
* Type was deleted.
*
* @private
*/
_delete (y, createDelete = true) {
if (!this._deleted) {
this._deleted = true
y.ds.mark(this._id, this._length, false)
let del = new Delete()
del._targetID = this._id
del._length = this._length
if (createDelete) {
// broadcast and persists Delete
del._integrate(y, true)
} else if (y.persistence !== null) {
// only persist Delete
y.persistence.saveStruct(y, del)
}
transactionTypeChanged(y, this._parent, this._parentSub)
y._transaction.deletedStructs.add(this)
}
}
_gcChildren (y) {}
_gc (y) {
const gc = new GC()
gc._id = this._id
gc._length = this._length
y.os.delete(this._id)
gc._integrate(y)
}
/**
* This is called right before this Item receives any children.
* It can be overwritten to apply pending changes before applying remote changes
*
* @private
*/
_beforeChange () {
// nop
}
/**
* Integrates this Item into the shared structure.
*
* This method actually applies the change to the Yjs instance. In case of
* Item it connects _left and _right to this Item and calls the
* {@link Item#beforeChange} method.
*
* * Integrate the struct so that other types/structs can see it
* * Add this struct to y.os
* * Check if this is struct deleted
*
* @private
*/
_integrate (y) {
y._transaction.newTypes.add(this)
const parent = this._parent
const selfID = this._id
const user = selfID === null ? y.userID : selfID.user
const userState = y.ss.getState(user)
if (selfID === null) {
this._id = y.ss.getNextID(this._length)
} else if (selfID.user === RootFakeUserID) {
// nop
} else if (selfID.clock < userState) {
// already applied..
return []
} else if (selfID.clock === userState) {
y.ss.setState(selfID.user, userState + this._length)
} else {
// missing content from user
throw new Error('Can not apply yet!')
}
if (!parent._deleted && !y._transaction.changedTypes.has(parent) && !y._transaction.newTypes.has(parent)) {
// this is the first time parent is updated
// or this types is new
this._parent._beforeChange()
}
/*
# $this has to find a unique position between origin and the next known character
# case 1: $origin equals $o.origin: the $creator parameter decides if left or right
# let $OL= [o1,o2,o3,o4], whereby $this is to be inserted between o1 and o4
# o2,o3 and o4 origin is 1 (the position of o2)
# there is the case that $this.creator < o2.creator, but o3.creator < $this.creator
# then o2 knows o3. Since on another client $OL could be [o1,o3,o4] the problem is complex
# therefore $this would be always to the right of o3
# case 2: $origin < $o.origin
# if current $this insert_position > $o origin: $this ins
# else $insert_position will not change
# (maybe we encounter case 1 later, then this will be to the right of $o)
# case 3: $origin > $o.origin
# $this insert_position is to the left of $o (forever!)
*/
// handle conflicts
let o
// set o to the first conflicting item
if (this._left !== null) {
o = this._left._right
} else if (this._parentSub !== null) {
o = this._parent._map.get(this._parentSub) || null
} else {
o = this._parent._start
}
let conflictingItems = new Set()
let itemsBeforeOrigin = new Set()
// Let c in conflictingItems, b in itemsBeforeOrigin
// ***{origin}bbbb{this}{c,b}{c,b}{o}***
// Note that conflictingItems is a subset of itemsBeforeOrigin
while (o !== null && o !== this._right) {
itemsBeforeOrigin.add(o)
conflictingItems.add(o)
if (this._origin === o._origin) {
// case 1
if (o._id.user < this._id.user) {
this._left = o
conflictingItems.clear()
}
} else if (itemsBeforeOrigin.has(o._origin)) {
// case 2
if (!conflictingItems.has(o._origin)) {
this._left = o
conflictingItems.clear()
}
} else {
break
}
// TODO: try to use right_origin instead.
// Then you could basically omit conflictingItems!
// Note: you probably can't use right_origin in every case.. only when setting _left
o = o._right
}
// reconnect left/right + update parent map/start if necessary
const parentSub = this._parentSub
if (this._left === null) {
let right
if (parentSub !== null) {
const pmap = parent._map
right = pmap.get(parentSub) || null
pmap.set(parentSub, this)
} else {
right = parent._start
parent._start = this
}
this._right = right
if (right !== null) {
right._left = this
}
} else {
const left = this._left
const right = left._right
this._right = right
left._right = this
if (right !== null) {
right._left = this
}
}
if (parent._deleted) {
this._delete(y, false)
}
y.os.put(this)
transactionTypeChanged(y, parent, parentSub)
if (this._id.user !== RootFakeUserID) {
if (y.connector !== null && (y.connector._forwardAppliedStructs || this._id.user === y.userID)) {
y.connector.broadcastStruct(this)
}
if (y.persistence !== null) {
y.persistence.saveStruct(y, this)
}
}
}
/**
* Transform the properties of this type to binary and write it to an
* BinaryEncoder.
*
* This is called when this Item is sent to a remote peer.
*
* @param {BinaryEncoder} encoder The encoder to write data to.
*
* @private
*/
_toBinary (encoder) {
encoder.writeUint8(getStructReference(this.constructor))
let info = 0
if (this._origin !== null) {
info += 0b1 // origin is defined
}
// TODO: remove
/* no longer send _left
if (this._left !== this._origin) {
info += 0b10 // do not copy origin to left
}
*/
if (this._right_origin !== null) {
info += 0b100
}
if (this._parentSub !== null) {
info += 0b1000
}
encoder.writeUint8(info)
encoder.writeID(this._id)
if (info & 0b1) {
encoder.writeID(this._origin._lastId)
}
// TODO: remove
/* see above
if (info & 0b10) {
encoder.writeID(this._left._lastId)
}
*/
if (info & 0b100) {
encoder.writeID(this._right_origin._id)
}
if ((info & 0b101) === 0) {
// neither origin nor right is defined
encoder.writeID(this._parent._id)
}
if (info & 0b1000) {
encoder.writeVarString(JSON.stringify(this._parentSub))
}
}
/**
* Read the next Item in a Decoder and fill this Item with the read data.
*
* This is called when data is received from a remote peer.
*
* @param {Y} y The Yjs instance that this Item belongs to.
* @param {BinaryDecoder} decoder The decoder object to read data from.
*
* @private
*/
_fromBinary (y, decoder) {
let missing = []
const info = decoder.readUint8()
const id = decoder.readID()
this._id = id
// read origin
if (info & 0b1) {
// origin != null
const originID = decoder.readID()
// we have to query for left again because it might have been split/merged..
const origin = y.os.getItemCleanEnd(originID)
if (origin === null) {
missing.push(originID)
} else {
this._origin = origin
this._left = this._origin
}
}
// read right
if (info & 0b100) {
// right != null
const rightID = decoder.readID()
// we have to query for right again because it might have been split/merged..
const right = y.os.getItemCleanStart(rightID)
if (right === null) {
missing.push(rightID)
} else {
this._right = right
this._right_origin = right
}
}
// read parent
if ((info & 0b101) === 0) {
// neither origin nor right is defined
const parentID = decoder.readID()
// parent does not change, so we don't have to search for it again
if (this._parent === null) {
let parent
if (parentID.constructor === RootID) {
parent = y.os.get(parentID)
} else {
parent = y.os.getItem(parentID)
}
if (parent === null) {
missing.push(parentID)
} else {
this._parent = parent
}
}
} else if (this._parent === null) {
if (this._origin !== null) {
if (this._origin.constructor === GC) {
// if origin is a gc, set parent also gc'd
this._parent = this._origin
} else {
this._parent = this._origin._parent
}
} else if (this._right_origin !== null) {
// if origin is a gc, set parent also gc'd
if (this._right_origin.constructor === GC) {
this._parent = this._right_origin
} else {
this._parent = this._right_origin._parent
}
}
}
if (info & 0b1000) {
// TODO: maybe put this in read parent condition (you can also read parentsub from left/right)
this._parentSub = JSON.parse(decoder.readVarString())
}
if (y.ss.getState(id.user) < id.clock) {
missing.push(new ID(id.user, id.clock - 1))
}
return missing
}
}

View File

@@ -1,35 +0,0 @@
import { default as Item } from './Item.js'
import { logItemHelper } from '../MessageHandler/messageToString.js'
export default class ItemEmbed extends Item {
constructor () {
super()
this.embed = null
}
_copy (undeleteChildren, copyPosition) {
let struct = super._copy(undeleteChildren, copyPosition)
struct.embed = this.embed
return struct
}
get _length () {
return 1
}
_fromBinary (y, decoder) {
const missing = super._fromBinary(y, decoder)
this.embed = JSON.parse(decoder.readVarString())
return missing
}
_toBinary (encoder) {
super._toBinary(encoder)
encoder.writeVarString(JSON.stringify(this.embed))
}
/**
* Transform this YXml Type to a readable format.
* Useful for logging as all Items and Delete implement this method.
*
* @private
*/
_logString () {
return logItemHelper('ItemEmbed', this, `embed:${JSON.stringify(this.embed)}`)
}
}

View File

@@ -1,42 +0,0 @@
import { default as Item } from './Item.js'
import { logItemHelper } from '../MessageHandler/messageToString.js'
export default class ItemFormat extends Item {
constructor () {
super()
this.key = null
this.value = null
}
_copy (undeleteChildren, copyPosition) {
let struct = super._copy(undeleteChildren, copyPosition)
struct.key = this.key
struct.value = this.value
return struct
}
get _length () {
return 1
}
get _countable () {
return false
}
_fromBinary (y, decoder) {
const missing = super._fromBinary(y, decoder)
this.key = decoder.readVarString()
this.value = JSON.parse(decoder.readVarString())
return missing
}
_toBinary (encoder) {
super._toBinary(encoder)
encoder.writeVarString(this.key)
encoder.writeVarString(JSON.stringify(this.value))
}
/**
* Transform this YXml Type to a readable format.
* Useful for logging as all Items and Delete implement this method.
*
* @private
*/
_logString () {
return logItemHelper('ItemFormat', this, `key:${JSON.stringify(this.key)},value:${JSON.stringify(this.value)}`)
}
}

View File

@@ -1,68 +0,0 @@
import { splitHelper, default as Item } from './Item.js'
import { logItemHelper } from '../MessageHandler/messageToString.js'
export default class ItemJSON extends Item {
constructor () {
super()
this._content = null
}
_copy () {
let struct = super._copy()
struct._content = this._content
return struct
}
get _length () {
return this._content.length
}
_fromBinary (y, decoder) {
let missing = super._fromBinary(y, decoder)
let len = decoder.readVarUint()
this._content = new Array(len)
for (let i = 0; i < len; i++) {
const ctnt = decoder.readVarString()
let parsed
if (ctnt === 'undefined') {
parsed = undefined
} else {
parsed = JSON.parse(ctnt)
}
this._content[i] = parsed
}
return missing
}
_toBinary (encoder) {
super._toBinary(encoder)
let len = this._content.length
encoder.writeVarUint(len)
for (let i = 0; i < len; i++) {
let encoded
let content = this._content[i]
if (content === undefined) {
encoded = 'undefined'
} else {
encoded = JSON.stringify(content)
}
encoder.writeVarString(encoded)
}
}
/**
* Transform this YXml Type to a readable format.
* Useful for logging as all Items and Delete implement this method.
*
* @private
*/
_logString () {
return logItemHelper('ItemJSON', this, `content:${JSON.stringify(this._content)}`)
}
_splitAt (y, diff) {
if (diff === 0) {
return this
} else if (diff >= this._length) {
return this._right
}
let item = new ItemJSON()
item._content = this._content.splice(diff)
splitHelper(y, this, item, diff)
return item
}
}

View File

@@ -1,47 +0,0 @@
import { splitHelper, default as Item } from './Item.js'
import { logItemHelper } from '../MessageHandler/messageToString.js'
export default class ItemString extends Item {
constructor () {
super()
this._content = null
}
_copy () {
let struct = super._copy()
struct._content = this._content
return struct
}
get _length () {
return this._content.length
}
_fromBinary (y, decoder) {
let missing = super._fromBinary(y, decoder)
this._content = decoder.readVarString()
return missing
}
_toBinary (encoder) {
super._toBinary(encoder)
encoder.writeVarString(this._content)
}
/**
* Transform this YXml Type to a readable format.
* Useful for logging as all Items and Delete implement this method.
*
* @private
*/
_logString () {
return logItemHelper('ItemString', this, `content:"${this._content}"`)
}
_splitAt (y, diff) {
if (diff === 0) {
return this
} else if (diff >= this._length) {
return this._right
}
let item = new ItemString()
item._content = this._content.slice(diff)
this._content = this._content.slice(0, diff)
splitHelper(y, this, item, diff)
return item
}
}

View File

@@ -1,243 +0,0 @@
import Item from './Item.js'
import EventHandler from '../Util/EventHandler.js'
import ID from '../Util/ID/ID.js'
// restructure children as if they were inserted one after another
function integrateChildren (y, start) {
let right
do {
right = start._right
start._right = null
start._right_origin = null
start._origin = start._left
start._integrate(y)
start = right
} while (right !== null)
}
export function getListItemIDByPosition (type, i) {
let pos = 0
let n = type._start
while (n !== null) {
if (!n._deleted) {
if (pos <= i && i < pos + n._length) {
const id = n._id
return new ID(id.user, id.clock + i - pos)
}
pos++
}
n = n._right
}
}
function gcChildren (y, item) {
while (item !== null) {
item._delete(y, false, true)
item._gc(y)
item = item._right
}
}
/**
* Abstract Yjs Type class
*/
export default class Type extends Item {
constructor () {
super()
this._map = new Map()
this._start = null
this._y = null
this._eventHandler = new EventHandler()
this._deepEventHandler = new EventHandler()
}
/**
* Compute the path from this type to the specified target.
*
* @example
* It should be accessible via `this.get(result[0]).get(result[1])..`
* const path = type.getPathTo(child)
* // assuming `type instanceof YArray`
* console.log(path) // might look like => [2, 'key1']
* child === type.get(path[0]).get(path[1])
*
* @param {YType} type Type target
* @return {Array<string>} Path to the target
*/
getPathTo (type) {
if (type === this) {
return []
}
const path = []
const y = this._y
while (type !== this && type !== y) {
let parent = type._parent
if (type._parentSub !== null) {
path.unshift(type._parentSub)
} else {
// parent is array-ish
for (let [i, child] of parent) {
if (child === type) {
path.unshift(i)
break
}
}
}
type = parent
}
if (type !== this) {
throw new Error('The type is not a child of this node')
}
return path
}
/**
* @private
* Call event listeners with an event. This will also add an event to all
* parents (for `.observeDeep` handlers).
*/
_callEventHandler (transaction, event) {
const changedParentTypes = transaction.changedParentTypes
this._eventHandler.callEventListeners(transaction, event)
let type = this
while (type !== this._y) {
let events = changedParentTypes.get(type)
if (events === undefined) {
events = []
changedParentTypes.set(type, events)
}
events.push(event)
type = type._parent
}
}
/**
* @private
* Helper method to transact if the y instance is available.
*
* TODO: Currently event handlers are not thrown when a type is not registered
* with a Yjs instance.
*/
_transact (f) {
const y = this._y
if (y !== null) {
y.transact(f)
} else {
f(y)
}
}
/**
* Observe all events that are created on this type.
*
* @param {Function} f Observer function
*/
observe (f) {
this._eventHandler.addEventListener(f)
}
/**
* Observe all events that are created by this type and its children.
*
* @param {Function} f Observer function
*/
observeDeep (f) {
this._deepEventHandler.addEventListener(f)
}
/**
* Unregister an observer function.
*
* @param {Function} f Observer function
*/
unobserve (f) {
this._eventHandler.removeEventListener(f)
}
/**
* Unregister an observer function.
*
* @param {Function} f Observer function
*/
unobserveDeep (f) {
this._deepEventHandler.removeEventListener(f)
}
/**
* @private
* Integrate this type into the Yjs instance.
*
* * Save this struct in the os
* * This type is sent to other client
* * Observer functions are fired
*
* @param {Y} y The Yjs instance
*/
_integrate (y) {
super._integrate(y)
this._y = y
// when integrating children we must make sure to
// integrate start
const start = this._start
if (start !== null) {
this._start = null
integrateChildren(y, start)
}
// integrate map children
const map = this._map
this._map = new Map()
for (let t of map.values()) {
// TODO make sure that right elements are deleted!
integrateChildren(y, t)
}
}
_gcChildren (y) {
gcChildren(y, this._start)
this._start = null
this._map.forEach(item => {
gcChildren(y, item)
})
this._map = new Map()
}
_gc (y) {
this._gcChildren(y)
super._gc(y)
}
/**
* @private
* Mark this Item as deleted.
*
* @param {Y} y The Yjs instance
* @param {boolean} createDelete Whether to propagate a message that this
* Type was deleted.
* @param {boolean} [gcChildren=y._hasUndoManager===false] Whether to garbage
* collect the children of this type.
*/
_delete (y, createDelete, gcChildren) {
if (gcChildren === undefined || !y.gcEnabled) {
gcChildren = y._hasUndoManager === false && y.gcEnabled
}
super._delete(y, createDelete, gcChildren)
y._transaction.changedTypes.delete(this)
// delete map types
for (let value of this._map.values()) {
if (value instanceof Item && !value._deleted) {
value._delete(y, false, gcChildren)
}
}
// delete array types
let t = this._start
while (t !== null) {
if (!t._deleted) {
t._delete(y, false, gcChildren)
}
t = t._right
}
if (gcChildren) {
this._gcChildren(y)
}
}
}

View File

@@ -1,78 +0,0 @@
/**
* A transaction is created for every change on the Yjs model. It is possible
* to bundle changes on the Yjs model in a single transaction to
* minimize the number on messages sent and the number of observer calls.
* If possible the user of this library should bundle as many changes as
* possible. Here is an example to illustrate the advantages of bundling:
*
* @example
* const map = y.define('map', YMap)
* // Log content when change is triggered
* map.observe(function () {
* console.log('change triggered')
* })
* // Each change on the map type triggers a log message:
* map.set('a', 0) // => "change triggered"
* map.set('b', 0) // => "change triggered"
* // When put in a transaction, it will trigger the log after the transaction:
* y.transact(function () {
* map.set('a', 1)
* map.set('b', 1)
* }) // => "change triggered"
*
*/
export default class Transaction {
constructor (y) {
/**
* @type {Y} The Yjs instance.
*/
this.y = y
/**
* All new types that are added during a transaction.
* @type {Set<Item>}
*/
this.newTypes = new Set()
/**
* All types that were directly modified (property added or child
* inserted/deleted). New types are not included in this Set.
* Maps from type to parentSubs (`item._parentSub = null` for YArray)
* @type {Set<YType,String>}
*/
this.changedTypes = new Map()
// TODO: rename deletedTypes
/**
* Set of all deleted Types and Structs.
* @type {Set<Item>}
*/
this.deletedStructs = new Set()
/**
* Saves the old state set of the Yjs instance. If a state was modified,
* the original value is saved here.
* @type {Map<Number,Number>}
*/
this.beforeState = new Map()
/**
* Stores the events for the types that observe also child elements.
* It is mainly used by `observeDeep`.
* @type {Map<YType,Array<YEvent>>}
*/
this.changedParentTypes = new Map()
}
}
/**
* @private
*/
export function transactionTypeChanged (y, type, sub) {
if (type !== y && !type._deleted && !y._transaction.newTypes.has(type)) {
const changedTypes = y._transaction.changedTypes
let subs = changedTypes.get(type)
if (subs === undefined) {
// create if it doesn't exist yet
subs = new Set()
changedTypes.set(type, subs)
}
subs.add(sub)
}
}

View File

@@ -1,378 +0,0 @@
import Type from '../../Struct/Type.js'
import ItemJSON from '../../Struct/ItemJSON.js'
import ItemString from '../../Struct/ItemString.js'
import { logID, logItemHelper } from '../../MessageHandler/messageToString.js'
import YEvent from '../../Util/YEvent.js'
/**
* Event that describes the changes on a YArray
*
* @param {YArray} yarray The changed type
* @param {Boolean} remote Whether the changed was caused by a remote peer
* @param {Transaction} transaction The transaction object
*/
export class YArrayEvent extends YEvent {
constructor (yarray, remote, transaction) {
super(yarray)
this.remote = remote
this._transaction = transaction
this._addedElements = null
this._removedElements = null
}
/**
* Child elements that were added in this transaction.
*
* @return {Set}
*/
get addedElements () {
if (this._addedElements === null) {
const target = this.target
const transaction = this._transaction
const addedElements = new Set()
transaction.newTypes.forEach(function (type) {
if (type._parent === target && !transaction.deletedStructs.has(type)) {
addedElements.add(type)
}
})
this._addedElements = addedElements
}
return this._addedElements
}
/**
* Child elements that were removed in this transaction.
*
* @return {Set}
*/
get removedElements () {
if (this._removedElements === null) {
const target = this.target
const transaction = this._transaction
const removedElements = new Set()
transaction.deletedStructs.forEach(function (struct) {
if (struct._parent === target && !transaction.newTypes.has(struct)) {
removedElements.add(struct)
}
})
this._removedElements = removedElements
}
return this._removedElements
}
}
/**
* A shared Array implementation.
*/
export default class YArray extends Type {
/**
* @private
* Creates YArray Event and calls observers.
*/
_callObserver (transaction, parentSubs, remote) {
this._callEventHandler(transaction, new YArrayEvent(this, remote, transaction))
}
/**
* Returns the i-th element from a YArray.
*
* @param {Integer} index The index of the element to return from the YArray
*/
get (index) {
let n = this._start
while (n !== null) {
if (!n._deleted && n._countable) {
if (index < n._length) {
if (n.constructor === ItemJSON || n.constructor === ItemString) {
return n._content[index]
} else {
return n
}
}
index -= n._length
}
n = n._right
}
}
/**
* Transforms this YArray to a JavaScript Array.
*
* @return {Array}
*/
toArray () {
return this.map(c => c)
}
/**
* Transforms this Shared Type to a JSON object.
*
* @return {Array}
*/
toJSON () {
return this.map(c => {
if (c instanceof Type) {
if (c.toJSON !== null) {
return c.toJSON()
} else {
return c.toString()
}
}
return c
})
}
/**
* Returns an Array with the result of calling a provided function on every
* element of this YArray.
*
* @param {Function} f Function that produces an element of the new Array
* @return {Array} A new array with each element being the result of the
* callback function
*/
map (f) {
const res = []
this.forEach((c, i) => {
res.push(f(c, i, this))
})
return res
}
/**
* Executes a provided function on once on overy element of this YArray.
*
* @param {Function} f A function to execute on every element of this YArray.
*/
forEach (f) {
let index = 0
let n = this._start
while (n !== null) {
if (!n._deleted && n._countable) {
if (n instanceof Type) {
f(n, index++, this)
} else {
const content = n._content
const contentLen = content.length
for (let i = 0; i < contentLen; i++) {
index++
f(content[i], index, this)
}
}
}
n = n._right
}
}
/**
* Computes the length of this YArray.
*/
get length () {
let length = 0
let n = this._start
while (n !== null) {
if (!n._deleted && n._countable) {
length += n._length
}
n = n._right
}
return length
}
[Symbol.iterator] () {
return {
next: function () {
while (this._item !== null && (this._item._deleted || this._item._length <= this._itemElement)) {
// item is deleted or itemElement does not exist (is deleted)
this._item = this._item._right
this._itemElement = 0
}
if (this._item === null) {
return {
done: true
}
}
let content
if (this._item instanceof Type) {
content = this._item
} else {
content = this._item._content[this._itemElement++]
}
return {
value: content,
done: false
}
},
_item: this._start,
_itemElement: 0,
_count: 0
}
}
/**
* Deletes elements starting from an index.
*
* @param {Integer} index Index at which to start deleting elements
* @param {Integer} length The number of elements to remove. Defaults to 1.
*/
delete (index, length = 1) {
this._y.transact(() => {
let item = this._start
let count = 0
while (item !== null && length > 0) {
if (!item._deleted && item._countable) {
if (count <= index && index < count + item._length) {
const diffDel = index - count
item = item._splitAt(this._y, diffDel)
item._splitAt(this._y, length)
length -= item._length
item._delete(this._y)
count += diffDel
} else {
count += item._length
}
}
item = item._right
}
})
if (length > 0) {
throw new Error('Delete exceeds the range of the YArray')
}
}
/**
* @private
* Inserts content after an element container.
*
* @param {Item} left The element container to use as a reference.
* @param {Array} content The Array of content to insert (see {@see insert})
*/
insertAfter (left, content) {
this._transact(y => {
let right
if (left === null) {
right = this._start
} else {
right = left._right
}
let prevJsonIns = null
for (let i = 0; i < content.length; i++) {
let c = content[i]
if (typeof c === 'function') {
c = new c() // eslint-disable-line new-cap
}
if (c instanceof Type) {
if (prevJsonIns !== null) {
if (y !== null) {
prevJsonIns._integrate(y)
}
left = prevJsonIns
prevJsonIns = null
}
c._origin = left
c._left = left
c._right = right
c._right_origin = right
c._parent = this
if (y !== null) {
c._integrate(y)
} else if (left === null) {
this._start = c
} else {
left._right = c
}
left = c
} else {
if (prevJsonIns === null) {
prevJsonIns = new ItemJSON()
prevJsonIns._origin = left
prevJsonIns._left = left
prevJsonIns._right = right
prevJsonIns._right_origin = right
prevJsonIns._parent = this
prevJsonIns._content = []
}
prevJsonIns._content.push(c)
}
}
if (prevJsonIns !== null) {
if (y !== null) {
prevJsonIns._integrate(y)
} else if (prevJsonIns._left === null) {
this._start = prevJsonIns
}
}
})
return content
}
/**
* Inserts new content at an index.
*
* Important: This function expects an array of content. Not just a content
* object. The reason for this "weirdness" is that inserting several elements
* is very efficient when it is done as a single operation.
*
* @example
* // Insert character 'a' at position 0
* yarray.insert(0, ['a'])
* // Insert numbers 1, 2 at position 1
* yarray.insert(2, [1, 2])
*
* @param {Integer} index The index to insert content at.
* @param {Array} content The array of content
*/
insert (index, content) {
this._transact(() => {
let left = null
let right = this._start
let count = 0
const y = this._y
while (right !== null) {
const rightLen = right._deleted ? 0 : (right._length - 1)
if (count <= index && index <= count + rightLen) {
const splitDiff = index - count
right = right._splitAt(y, splitDiff)
left = right._left
count += splitDiff
break
}
if (!right._deleted) {
count += right._length
}
left = right
right = right._right
}
if (index > count) {
throw new Error('Index exceeds array range!')
}
this.insertAfter(left, content)
})
}
/**
* Appends content to this YArray.
*
* @param {Array} content Array of content to append.
*/
push (content) {
let n = this._start
let lastUndeleted = null
while (n !== null) {
if (!n._deleted) {
lastUndeleted = n
}
n = n._right
}
this.insertAfter(lastUndeleted, content)
}
/**
* Transform this YXml Type to a readable format.
* Useful for logging as all Items and Delete implement this method.
*
* @private
*/
_logString () {
return logItemHelper('YArray', this, `start:${logID(this._start)}"`)
}
}

View File

@@ -1,175 +0,0 @@
import Type from '../../Struct/Type.js'
import Item from '../../Struct/Item.js'
import ItemJSON from '../../Struct/ItemJSON.js'
import { logItemHelper } from '../../MessageHandler/messageToString.js'
import YEvent from '../../Util/YEvent.js'
/**
* Event that describes the changes on a YMap.
*
* @param {YMap} ymap The YArray that changed.
* @param {Set<any>} subs The keys that changed.
* @param {boolean} remote Whether the change was created by a remote peer.
*/
export class YMapEvent extends YEvent {
constructor (ymap, subs, remote) {
super(ymap)
this.keysChanged = subs
this.remote = remote
}
}
/**
* A shared Map implementation.
*/
export default class YMap extends Type {
/**
* @private
* Creates YMap Event and calls observers.
*/
_callObserver (transaction, parentSubs, remote) {
this._callEventHandler(transaction, new YMapEvent(this, parentSubs, remote))
}
/**
* Transforms this Shared Type to a JSON object.
*
* @return {Object}
*/
toJSON () {
const map = {}
for (let [key, item] of this._map) {
if (!item._deleted) {
let res
if (item instanceof Type) {
if (item.toJSON !== undefined) {
res = item.toJSON()
} else {
res = item.toString()
}
} else {
res = item._content[0]
}
map[key] = res
}
}
return map
}
/**
* Returns the keys for each element in the YMap Type.
*
* @return {Array}
*/
keys () {
// TODO: Should return either Iterator or Set!
let keys = []
for (let [key, value] of this._map) {
if (!value._deleted) {
keys.push(key)
}
}
return keys
}
/**
* Remove a specified element from this YMap.
*
* @param {encodable} key The key of the element to remove.
*/
delete (key) {
this._transact((y) => {
let c = this._map.get(key)
if (y !== null && c !== undefined) {
c._delete(y)
}
})
}
/**
* Adds or updates an element with a specified key and value.
*
* @param {encodable} key The key of the element to add to this YMap.
* @param {encodable | YType} value The value of the element to add to this
* YMap.
*/
set (key, value) {
this._transact(y => {
const old = this._map.get(key) || null
if (old !== null) {
if (
old.constructor === ItemJSON &&
!old._deleted && old._content[0] === value
) {
// Trying to overwrite with same value
// break here
return value
}
if (y !== null) {
old._delete(y)
}
}
let v
if (typeof value === 'function') {
v = new value() // eslint-disable-line new-cap
value = v
} else if (value instanceof Item) {
v = value
} else {
v = new ItemJSON()
v._content = [value]
}
v._right = old
v._right_origin = old
v._parent = this
v._parentSub = key
if (y !== null) {
v._integrate(y)
} else {
this._map.set(key, v)
}
})
return value
}
/**
* Returns a specified element from this YMap.
*
* @param {encodable} key The key of the element to return.
*/
get (key) {
let v = this._map.get(key)
if (v === undefined || v._deleted) {
return undefined
}
if (v instanceof Type) {
return v
} else {
return v._content[v._content.length - 1]
}
}
/**
* Returns a boolean indicating whether the specified key exists or not.
*
* @param {encodable} key The key to test.
*/
has (key) {
let v = this._map.get(key)
if (v === undefined || v._deleted) {
return false
} else {
return true
}
}
/**
* Transform this YXml Type to a readable format.
* Useful for logging as all Items and Delete implement this method.
*
* @private
*/
_logString () {
return logItemHelper('YMap', this, `mapSize:${this._map.size}`)
}
}

Some files were not shown because too many files have changed in this diff Show More