├── .gitignore
├── LICENSE
├── README.md
├── demo
├── canvas.html
├── css
│ ├── demo.css
│ ├── demoStyles.css
│ └── demoStyles.scss
├── images
│ ├── demo.png
│ ├── ebi1.png
│ ├── ikura1.png
│ ├── negitoro.png
│ ├── nori.png
│ ├── rice1.png
│ ├── rice2.png
│ ├── salmon1.png
│ ├── salmon2.png
│ ├── wasabi1.png
│ ├── wasabi2.png
│ ├── wasabi3.png
│ └── wasabi4.png
├── index.html
└── js
│ ├── demo.js
│ ├── pt-core.min.js
│ └── sushi.js
├── dist
├── module
│ └── roll.js
├── roll.js
├── roll.js.map
└── roll.min.js
├── gulpfile.js
├── package.json
└── src
├── roll.js
└── roll_standalone.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .sass-cache
2 | node_modules
3 | .idea
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # roll.js
2 |
3 | 
4 |
5 | A little js library (~8kb min, 3kb gzip, no dependencies) to help you keep track of position, scrolling, and pagination.
6 | Nothing too fancy, but since I couldn't find a suitable library for these purposes, I made one for a friend and myself and you too!
7 | Ping me [@williamngan](http://twitter.com/williamngan) if you have questions or comments.
8 |
9 | ## Demo
10 | Here's a **[DOM scrolling demo](http://williamngan.github.io/roll/demo/index.html)** (with some weird iPhone paintings :satisfied:)
11 |
12 | Here's a **[Canvas demo](http://williamngan.github.io/roll/demo/canvas.html)**
13 |
14 | ## Basic Usage
15 |
16 | Simply create a new instance, specifying the viewport size (500px in this example).
17 |
18 | `var roll = new Roll( 500 );`
19 |
20 | Next, add a couple of *steps* to the roll instance. You may use the static helper `Roll.chunk( stepSize, padding )` to create a step object.
21 |
22 | ```javascript
23 | roll.addStep( Roll.chunk(500, 20) ); // Add a step of 500px with 20px padding
24 | roll.addStep( Roll.chunk(700, 20) ); // Add a step of 700px with 20px padding
25 | ```
26 |
27 | When the pane is moved, usually via the function `roll.move( position )`,
28 | the roll instance will emit a `roll` event and possibly a `step` event.
29 | You can listen to these events in the usual manner. (see [EventEmitter docs](https://nodejs.org/api/events.html) ). For example,
30 | ```javascript
31 | roll.on( "roll", function(step, currProgress, currPosition, totalProgress) {
32 | // implement your logic here
33 | })
34 |
35 | roll.on( "step", function(curr, last) {
36 | // implement your logic here
37 | })
38 | ```
39 |
40 | ## DOM Usage
41 |
42 | A common usage is to keep track of scrolling in a DOM element, and then do pagination or animation based on scroll position.
43 |
44 | There are a couple of static helpers to simplify this task. First, create a `roll` instance using `Roll.DOM( viewportID, scrollpaneID, stepsID, stepClass, padding)`. For example,
45 |
46 | ```javascript
47 | var roll = Roll.DOM("#viewport", "#pane", "#steps", ".step", 100 );
48 | ```
49 |
50 | The html structure for a *scrolling slideshow* may look like this. Also see a [sample css](https://github.com/williamngan/roll/blob/master/demo/css/demo.css) that corresponds to that html.
51 |
52 | ```html
53 |
54 |
55 |
Hello
56 |
World
57 |
How's it going
58 |
59 |
62 |
63 | ```
64 |
65 | Then this will keep track of vertical scrolling in the #viewport DOM element. You can then listen for the `roll` and `step` events as shown in Basic Usage, and implement your own logic.
66 |
67 | One more thing: `Roll.stepHandler(...)` is a helper to go through a slideshow with `step` event. It will add css classes to the `.step` elements based on which step is in view.
68 |
69 | ```javascript
70 | roll.on( "step", Roll.stepHandler( roll, views, "prev", "next", "curr", true ) );
71 | ```
72 |
73 | In the above snippet, `roll` is the roll instance, `views` is an array of the .step DOM elements, and `"prev", "next" "curr"` are css class names to assign to previous, next, and current step elements.
74 |
75 | A good way to get started is to take a look at the demos above, and then check out the source code in [demo folder](https://github.com/williamngan/roll/tree/master/demo).
76 |
77 | ## Compiling
78 |
79 | This library is written in javascript ES6 and compiled with Babel. If you want to change the source code and rebuild, simply `npm install` to get the dev dependencies,
80 | and then run `gulp` to watch and build.
81 |
82 | ## NPM
83 | [https://www.npmjs.com/package/rolljs](https://www.npmjs.com/package/rolljs)
84 |
--------------------------------------------------------------------------------
/demo/canvas.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
Using roll.js in html canvas.
47 |
← Move the mouse around on the canvas to start.
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
59 |
60 |
138 |
139 |
140 |
--------------------------------------------------------------------------------
/demo/css/demo.css:
--------------------------------------------------------------------------------
1 | /**
2 | This is a sample css file scrolling DOM elements using roll.js.
3 | The DOM structure usually looks like this
4 |
5 |
6 |
7 |
One
8 |
Two
9 |
Three
10 |
etc...
11 |
12 |
15 |
16 | */
17 |
18 |
19 | html, body {
20 | /* optional */
21 | overflow: hidden;
22 | }
23 |
24 | #roll {
25 |
26 | position: relative;
27 | width: 500px;
28 | height: 500px;
29 |
30 | /*
31 | Roll's size can also be defined by absolute positions.
32 | position: absolute;
33 | top: 0; bottom: 0; left: 0; right: 0;
34 | */
35 | }
36 |
37 |
38 | /* this is the viewport container */
39 | #wrapper {
40 | overflow: auto;
41 | width: 100%;
42 | height: 100%;
43 | position: relative;
44 |
45 | }
46 |
47 |
48 | /* this is the full size scrolling pane */
49 | #pane {}
50 |
51 |
52 | /* this is a container for the steps */
53 | #steps {
54 | position: absolute;
55 | overflow: hidden;
56 | top: 0;
57 | left: 0;
58 | width: 100%;
59 | height: 100%;
60 | }
61 |
62 |
63 | /* the step class */
64 | .step {
65 | width: 100%;
66 | height: 100%;
67 |
68 | position: absolute;
69 | top: 100%;
70 | left: 0;
71 |
72 | /* optional transition */
73 | transition: top .5s;
74 | }
75 |
76 |
77 | /* what's the styles for previous steps */
78 | .step.prev {
79 | top: -100%;
80 | }
81 |
82 |
83 | /* what's the styles for next steps */
84 | .step.next {
85 | top: 100%;
86 | }
87 |
88 |
89 | /* what's the styles for current steps */
90 | .step.curr {
91 | top: 0;
92 | }
93 |
--------------------------------------------------------------------------------
/demo/css/demoStyles.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | overflow: hidden;
3 | margin: 0;
4 | font: 10px/1.5 "Montserrat", sans-serif; }
5 |
6 | #menu {
7 | position: absolute;
8 | padding: 30px;
9 | top: 0;
10 | left: 0;
11 | width: 300px;
12 | bottom: 0;
13 | box-sizing: border-box;
14 | background: rgba(255, 255, 255, 0.1); }
15 |
16 | #progress {
17 | position: absolute;
18 | top: 0;
19 | left: 300px;
20 | width: 1px;
21 | height: 0;
22 | background: #ff0; }
23 |
24 | h1 {
25 | font-size: 5em;
26 | margin: 0 0 20px;
27 | color: #fff; }
28 |
29 | p {
30 | font-size: 1.2em;
31 | color: #fff; }
32 | p.field {
33 | line-height: 20px;
34 | clear: right; }
35 | p.field span {
36 | display: inline-block;
37 | margin-right: 10px; }
38 | p.field .label {
39 | opacity: .65; }
40 | p.field .value {
41 | font-weight: bold;
42 | font-size: 18px;
43 | float: right; }
44 |
45 | hr {
46 | border: none;
47 | border-bottom: 1px dotted rgba(255, 255, 255, 0.1);
48 | margin: 30px 0; }
49 |
50 | a {
51 | display: inline-block;
52 | color: #ff0;
53 | border-bottom: 1px solid rgba(255, 255, 0, 0);
54 | text-decoration: none; }
55 | a:hover {
56 | border-bottom-color: yellow; }
57 |
58 | #roll {
59 | background: #5CD;
60 | position: absolute;
61 | top: 0;
62 | left: 0px;
63 | bottom: 0;
64 | right: 0;
65 | width: auto;
66 | height: auto; }
67 |
68 | .step {
69 | color: #fff;
70 | opacity: 1;
71 | transition: top .5s, opacity .5s; }
72 | .step h1 {
73 | top: 30px;
74 | right: 30px;
75 | font-size: 40vh;
76 | width: 100%;
77 | text-align: right;
78 | position: absolute;
79 | color: rgba(0, 0, 0, 0.1);
80 | line-height: 1;
81 | letter-spacing: -0.03em; }
82 |
83 | .step.prev, .step.next {
84 | opacity: 0; }
85 |
--------------------------------------------------------------------------------
/demo/css/demoStyles.scss:
--------------------------------------------------------------------------------
1 | html, body {
2 | overflow: hidden;
3 | margin: 0;
4 |
5 | font: 10px/1.5 "Montserrat", sans-serif;
6 | }
7 |
8 | #menu {
9 | position: absolute;
10 | padding: 30px;
11 | top: 0; left: 0; width: 300px; bottom: 0;
12 | box-sizing: border-box;
13 | background: rgba(255,255,255,.1);
14 | }
15 |
16 | #progress {
17 | position: absolute;
18 | top: 0; left: 300px;
19 | width: 1px; height: 0;
20 | background: #ff0;
21 | }
22 |
23 | h1 {
24 | font-size: 5em;
25 | margin: 0 0 20px;
26 | color: #fff;
27 | }
28 | p {
29 | font-size: 1.2em;
30 | color: #fff;
31 |
32 | &.field {
33 | line-height: 20px;
34 | span {
35 | display: inline-block;
36 | margin-right: 10px;
37 | }
38 | .label {
39 | opacity: .65;
40 | }
41 | .value {
42 | font-weight: bold;
43 | font-size: 18px;
44 | float: right;
45 | }
46 |
47 | clear: right;
48 | }
49 | }
50 |
51 | hr {
52 | border: none;
53 | border-bottom: 1px dotted rgba(255,255,255,.1);
54 | margin: 30px 0;
55 | }
56 | a {
57 | display: inline-block;
58 | color: #ff0;
59 | border-bottom: 1px solid rgba(255,255,0,0);
60 | text-decoration: none;
61 |
62 | &:hover {
63 | border-bottom-color: rgba(255,255,0,1);
64 | }
65 | }
66 |
67 |
68 | #roll {
69 | background: #5CD;
70 |
71 | position: absolute;
72 | top: 0; left: 0px; bottom: 0; right: 0;
73 | width: auto; height: auto;
74 | }
75 |
76 | #wrapper {
77 |
78 | }
79 |
80 |
81 | #pane {
82 |
83 | }
84 |
85 | #steps {
86 |
87 | }
88 |
89 | .step {
90 | color: #fff;
91 | opacity: 1;
92 | transition: top .5s, opacity .5s;
93 |
94 | h1 {
95 | top: 30px;
96 | right: 30px;
97 | font-size: 40vh;
98 | width: 100%;
99 | text-align: right;
100 | position: absolute;
101 | color: rgba(0,0,0,.1);
102 | line-height: 1;
103 | letter-spacing: -0.03em;
104 | }
105 | }
106 |
107 | .step.prev, .step.next {
108 | opacity: 0;
109 | }
--------------------------------------------------------------------------------
/demo/images/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/williamngan/roll/f06ecb159a4a1c1dc631c6a13e067e89ae0902df/demo/images/demo.png
--------------------------------------------------------------------------------
/demo/images/ebi1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/williamngan/roll/f06ecb159a4a1c1dc631c6a13e067e89ae0902df/demo/images/ebi1.png
--------------------------------------------------------------------------------
/demo/images/ikura1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/williamngan/roll/f06ecb159a4a1c1dc631c6a13e067e89ae0902df/demo/images/ikura1.png
--------------------------------------------------------------------------------
/demo/images/negitoro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/williamngan/roll/f06ecb159a4a1c1dc631c6a13e067e89ae0902df/demo/images/negitoro.png
--------------------------------------------------------------------------------
/demo/images/nori.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/williamngan/roll/f06ecb159a4a1c1dc631c6a13e067e89ae0902df/demo/images/nori.png
--------------------------------------------------------------------------------
/demo/images/rice1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/williamngan/roll/f06ecb159a4a1c1dc631c6a13e067e89ae0902df/demo/images/rice1.png
--------------------------------------------------------------------------------
/demo/images/rice2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/williamngan/roll/f06ecb159a4a1c1dc631c6a13e067e89ae0902df/demo/images/rice2.png
--------------------------------------------------------------------------------
/demo/images/salmon1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/williamngan/roll/f06ecb159a4a1c1dc631c6a13e067e89ae0902df/demo/images/salmon1.png
--------------------------------------------------------------------------------
/demo/images/salmon2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/williamngan/roll/f06ecb159a4a1c1dc631c6a13e067e89ae0902df/demo/images/salmon2.png
--------------------------------------------------------------------------------
/demo/images/wasabi1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/williamngan/roll/f06ecb159a4a1c1dc631c6a13e067e89ae0902df/demo/images/wasabi1.png
--------------------------------------------------------------------------------
/demo/images/wasabi2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/williamngan/roll/f06ecb159a4a1c1dc631c6a13e067e89ae0902df/demo/images/wasabi2.png
--------------------------------------------------------------------------------
/demo/images/wasabi3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/williamngan/roll/f06ecb159a4a1c1dc631c6a13e067e89ae0902df/demo/images/wasabi3.png
--------------------------------------------------------------------------------
/demo/images/wasabi4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/williamngan/roll/f06ecb159a4a1c1dc631c6a13e067e89ae0902df/demo/images/wasabi4.png
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Roll.js Demos
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
1
24 |
2
25 |
3
26 |
4
27 |
5
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/demo/js/demo.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | // initiate roll
4 | var roll = Roll.DOM( "#wrapper", "#pane", "#steps", ".step", 100 );
5 |
6 | var views = document.querySelectorAll( ".step" );
7 | views[0].className = "step curr"; // set first step's class name as "curr"
8 |
9 |
10 | // define how you want to track the elements as you scroll
11 | function track() {
12 |
13 | // vendor prefix for old browsers
14 | function _vendor( elem, prop, val ) {
15 | var vs = ["webkit", "Webkit", "Moz", "ms"];
16 | for (var i=0; i= 0) ? "Step "+(step+1) : "(padding)";
27 |
28 | var vals = {
29 | numSteps: roll.steps.length,
30 | viewportHeight: roll.getViewportHeight(),
31 | paneHeight: roll.getHeight(),
32 | currStep: curr,
33 | currPos: position + "px",
34 | currStepProgress: Math.floor( stepProgress * 100 ) + "%",
35 | totalProgress: Math.floor( totalProgress * 100) + "%"
36 | };
37 |
38 | for (var k in vals) {
39 | var el = document.querySelector("#"+k);
40 | if (el) {
41 | el.textContent = vals[k];
42 | }
43 | }
44 |
45 | if (step >= 0) {
46 | var currStep = document.querySelector( "#s" + step );
47 | var ings = currStep.querySelectorAll( ".ingredient" );
48 | for (var i = 0; i < ings.length; i++) {
49 | var ang1 = parseInt( ings[i].getAttribute( "data-angle" ) );
50 | var ang2 = parseInt( ings[i].getAttribute( "data-rotate" ) );
51 | //var tm = "rotate(" + (ang1 + (stepProgress*0.2) * ang2 ) + "deg) scale(" + (0.25 + totalProgress * 0.5) + ")";
52 | var tm = "scale(" + (0.25 + totalProgress * 0.5) + ") translate(0, "+Math.floor(-ang1*stepProgress*3)+"px)";
53 | ings[i].style.transform = tm;
54 | _vendor( ings[i], "Transform", tm );
55 | }
56 | }
57 |
58 | var progress = document.querySelector("#progress");
59 | progress.style.height = Math.floor(roll.getViewportHeight() * totalProgress) + "px";
60 |
61 | });
62 | }
63 |
64 | // start tracking
65 | track();
66 |
67 | // a global function to scroll to a specific step in the roll instance.
68 | window.goto = function(index) {
69 | var viewport = document.querySelector( "#wrapper" );
70 | roll.scroll(index, viewport);
71 | };
72 |
73 |
74 | // re-initiate roll when resized
75 | window.addEventListener("resize", function(evt) {
76 | roll = Roll.DOM( "#wrapper", "#pane", "#steps", ".step", 100 );
77 | track();
78 | goto(0);
79 | });
80 |
81 | goto(0);
82 |
83 | })();
--------------------------------------------------------------------------------
/demo/js/pt-core.min.js:
--------------------------------------------------------------------------------
1 | var CanvasSpace,Circle,Color,Const,Curve,DOMSpace,Form,Grid,Line,Matrix,Pair,Particle,ParticleSystem,Point,PointSet,Rectangle,Space,Timer,Triangle,Util,Vector,extend=function(t,i){function e(){this.constructor=t}for(var n in i)hasProp.call(i,n)&&(t[n]=i[n]);return e.prototype=i.prototype,t.prototype=new e,t.__super__=i.prototype,t},hasProp={}.hasOwnProperty,slice=[].slice;Const=function(){function t(){}return t.xy="xy",t.yz="yz",t.xz="xz",t.xyz="xyz",t.identical=-1,t.right=3,t.bottom_right=4,t.bottom=5,t.bottom_left=6,t.left=7,t.top_left=0,t.top=1,t.top_right=2,t.sideLabels=["identical","right","bottom right","bottom","bottom left","left","top left","top","top right"],t.epsilon=1e-4,t.pi=Math.PI,t.two_pi=6.283185307179586,t.half_pi=1.5707963267948966,t.quarter_pi=.7853981633974483,t.one_degree=.017453292519943295,t.rad_to_deg=57.29577951308232,t.deg_to_rad=.017453292519943295,t.gravity=9.81,t.newton=.10197,t.gaussian=.3989422804014327,t}(),this.Const=Const,Matrix=function(){function t(){}return t.rotateAnchor2D=function(t,i,e){var n,s,r;return null==e&&(e=Const.xy),n=i.get2D(e),s=Math.cos(t),r=Math.sin(t),[s,r,0,-r,s,0,n.x*(1-s)+n.y*r,n.y*(1-s)-n.x*r,1]},t.reflectAnchor2D=function(t,i){var e,n,s,r;return null==i&&(i=Const.xy),s=t.intercept(i),e=2*Math.atan(s.slope),n=Math.cos(e),r=Math.sin(e),[n,r,0,r,-n,0,-s.yi*r,s.yi+s.yi*n,1]},t.shearAnchor2D=function(t,i,e,n){var s,r,o;return null==n&&(n=Const.xy),s=e.get2D(n),r=Math.tan(t),o=Math.tan(i),[1,r,0,o,1,0,-s.y*o,-s.x*r,1]},t.scaleAnchor2D=function(t,i,e,n){var s;return null==n&&(n=Const.xy),s=e.get2D(n),[t,0,0,0,i,0,-s.x*t+s.x,-s.y*i+s.y,1]},t.scale2D=function(t,i){return[t,0,0,0,i,0,0,0,1]},t.shear2D=function(t,i){return[1,Math.tan(t),0,Math.tan(i),1,0,0,0,1]},t.rotate2D=function(t,i){return[t,i,0,-i,t,0,0,0,1]},t.translate2D=function(t,i){return[1,0,0,0,1,0,t,i,1]},t.transform2D=function(t,i,e,n){var s,r,o;return null==e&&(e=Const.xy),null==n&&(n=!1),s=t.get2D(e),r=s.x*i[0]+s.y*i[3]+i[6],o=s.x*i[1]+s.y*i[4]+i[7],s.x=r,s.y=o,s=s.get2D(e,!0),n?s:(t.set(s),t)},t}(),this.Matrix=Matrix,Util=function(){function t(){}return t.toRadian=function(t){return t*Const.deg_to_rad},t.toDegree=function(t){return t*Const.rad_to_deg},t.toHexColor=function(t){var i;return i=Math.floor(t).toString(16),1===i.length?"0"+i:i},t.toRGBColor=function(t,i,e){var n,s,r;return null==i&&(i=!1),null==e&&(e=1),"#"===t[0]&&(t=t.substr(1)),3===t.length?(r=parseInt(t[0]+t[0],16),s=parseInt(t[1]+t[1],16),n=parseInt(t[2]+t[2],16)):t.length>=6?(r=parseInt(t[0]+t[1],16),s=parseInt(t[2]+t[3],16),n=parseInt(t[4]+t[5],16)):(r=0,s=0,n=0),i?"rgba("+r+","+s+","+n+","+e+")":[r,s,n,e]},t.bound=function(t,i,e){var n,s;return null==e&&(e=!1),n=t%i,s=i/2,n>s?n-=i:-s>n&&(n+=i),e&&0>n?n+i:n},t.boundAngle=function(i,e){return t.bound(i,360,e)},t.boundRadian=function(i,e){return t.bound(i,Const.two_pi,e)},t.boundingBox=function(t,i){var e,n,s,r,o;for(null==i&&(i=!1),r=new Point(Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY),s=new Point(Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY),e=0,n=t.length;n>e;e++)o=t[e],o.xs.x&&(s.x=o.x),o.y>s.y&&(s.y=o.y),i&&(o.zs.z&&(s.z=o.z));return new Rectangle(r).to(s)},t.lerp=function(t,i,e){return(1-e)*t+e*i},t.centroid=function(t){var i,e,n,s;for(i=new Vector,e=0,n=t.length;n>e;e++)s=t[e],i.add(s);return i.divide(t.length)},t.same=function(t,i,e){return null==e&&(e=Const.epsilon),Math.abs(t-i)=Math.min(i,e)&&t<=Math.max(i,e)},t.randomRange=function(t,i){var e;return null==i&&(i=0),e=t>i?t-i:i-t,t+Math.random()*e},t.mixin=function(t,i){var e,n;for(e in i)n=i[e],i.hasOwnProperty(e)&&(t.prototype[e]=i[e]);return t},t.extend=function(t,i){return t.prototype=Object.create(i.prototype),t.prototype.constructor=t,t},t.clonePoints=function(t){var i,e,n,s;for(s=[],i=0,e=t.length;e>i;i++)n=t[i],s.push(n.clone());return s},t.contextRotateOrigin=function(t,i,e,n,s){var r,o;return null==n&&(n=!1),o=i.size(),n||(n=o.$multiply(.5),n.add(i)),s&&(r=s.size(),Form.rect(t,s),t.clip()),t.translate(n.x,n.y),t.rotate(e),t.translate(-n.x,-n.y)},t.sinCosTable=function(){var t,i,e,n;for(t=[],n=[],i=e=0;360>=e;i=e+=1)t[i]=Math.cos(i*Math.PI/180),n[i]=Math.sin(i*Math.PI/180);return{sin:n,cos:t}},t.chance=function(t){return Math.random()=this.duration?this._time=Date.now():void 0},t.prototype.setEasing=function(t){return this._ease=t},t.prototype.check=function(){var t;return t=Math.min(Date.now()-this._time,this.duration),this._ease(t,0,1,this.duration)},t.prototype.track=function(t){var i;return clearInterval(this._intervalID),this.start(!0),i=this,this._intervalID=setInterval(function(){var e;return e=i.check(),t(e),e>=1?clearInterval(i._intervalID):void 0},25),this._intervalID},t}(),this.Timer=Timer,Space=function(){function t(t){null==t&&(t="space"),this.id=t,this.size=new Vector,this.center=new Vector,this._timePrev=0,this._timeDiff=0,this._timeEnd=-1,this.items={},this._animID=-1,this._animCount=0,this._animPause=!1,this._refresh=!0}return t.prototype.refresh=function(t){return this._refresh=t,this},t.prototype.render=function(t){return this},t.prototype.resize=function(t,i){},t.prototype.clear=function(){},t.prototype.add=function(t){var i;if(null==t.animate||"function"!=typeof t.animate)throw"a player object for Space.add must define animate()";return i=this._animCount++,this.items[i]=t,t.animateID=i,null!=t.onSpaceResize&&t.onSpaceResize(this.size.x,this.size.y),this},t.prototype.remove=function(t){return delete this.items[t.animateID],this},t.prototype.removeAll=function(){return this.items={},this},t.prototype.play=function(t){var i;if(null==t&&(t=0),this._animID=requestAnimationFrame(function(t){return function(i){return t.play(i)}}(this)),!this._animPause){this._timeDiff=t-this._timePrev;try{this._playItems(t)}catch(e){throw i=e,cancelAnimationFrame(this._animID),console.error(i.stack),i}return this._timePrev=t,this}},t.prototype._playItems=function(t){var i,e,n;this._refresh&&this.clear(),e=this.items;for(i in e)n=e[i],n.animate(t,this._timeDiff,this.ctx);return this._timeEnd>=0&&t>this._timeEnd&&cancelAnimationFrame(this._animID),this},t.prototype.pause=function(t){return null==t&&(t=!1),this._animPause=t?!this._animPause:!0,this},t.prototype.resume=function(){return this._animPause=!1,this},t.prototype.stop=function(t){return null==t&&(t=0),this._timeEnd=t,this},t.prototype.playTime=function(t){return null==t&&(t=5e3),this.play(),this.stop(t)},t}(),this.Space=Space,CanvasSpace=function(t){function i(t,e,n){null==t&&(t="pt_space"),null==e&&(e=!1),null==n&&(n="2d"),i.__super__.constructor.apply(this,arguments),this.space=document.querySelector("#"+this.id),this.appended=!0,this.space||(this.space=document.createElement("canvas"),this.space.setAttribute("id",this.id),this.appended=!1),this._mdown=!1,this._mdrag=!1,this.bgcolor=e,this.ctx=this.space.getContext(n)}return extend(i,t),i.prototype.display=function(t,i){var e,n;if(null==t&&(t="#pt"),!this.appended){if(e=document.querySelector(t),n=e.getBoundingClientRect(),!e)throw"Cannot add canvas to element "+t;this.resize(n.width,n.height),window.addEventListener("resize",function(t){return n=e.getBoundingClientRect(),this.resize(n.width,n.height,t)}.bind(this)),this.space.parentNode!==e&&e.appendChild(this.space),this.appended=!0,setTimeout(function(){return this.space.dispatchEvent(new Event("ready")),i?i(n.width,n.height,this.space):void 0}.bind(this))}return this},i.prototype.resize=function(t,i,e){var n,s,r;this.size.set(t,i),this.center=new Vector(t/2,i/2),this.space.setAttribute("width",Math.floor(t)),this.space.setAttribute("height",Math.floor(i)),r=this.items;for(n in r)s=r[n],null!=s.onSpaceResize&&s.onSpaceResize(t,i,e);return this.render(this.ctx),this},i.prototype.clear=function(t){var i;return t&&(this.bgcolor=t),i=this.ctx.fillStyle,this.bgcolor?(this.ctx.fillStyle=this.bgcolor,this.ctx.fillRect(0,0,this.size.x,this.size.y)):this.ctx.clearRect(0,0,this.size.x,this.size.y),this.ctx.fillStyle=i,this},i.prototype.animate=function(t){var i,e,n;this.ctx.save(),this._refresh&&this.clear(),e=this.items;for(i in e)n=e[i],n.animate(t,this._timeDiff,this.ctx);return this._timeEnd>=0&&t>this._timeEnd&&cancelAnimationFrame(this._animID),this.ctx.restore(),this},i.prototype.bindCanvas=function(t,i){return this.space.addEventListener(t,i)},i.prototype.bindMouse=function(t){return null==t&&(t=!0),t?(this.space.addEventListener("mousedown",this._mouseDown.bind(this)),this.space.addEventListener("mouseup",this._mouseUp.bind(this)),this.space.addEventListener("mouseover",this._mouseOver.bind(this)),this.space.addEventListener("mouseout",this._mouseOut.bind(this)),this.space.addEventListener("mousemove",this._mouseMove.bind(this))):(this.space.removeEventListener("mousedown",this._mouseDown.bind(this)),this.space.removeEventListener("mouseup",this._mouseUp.bind(this)),this.space.removeEventListener("mouseover",this._mouseOver.bind(this)),this.space.removeEventListener("mouseout",this._mouseOut.bind(this)),this.space.removeEventListener("mousemove",this._mouseMove.bind(this)))},i.prototype._mouseAction=function(t,i){var e,n,s,r,o,h;r=this.items,o=[];for(e in r)h=r[e],n=i.offsetX||i.layerX,s=i.offsetY||i.layerY,o.push(null!=h.onMouseAction?h.onMouseAction(t,n,s,i):void 0);return o},i.prototype._mouseDown=function(t){return this._mouseAction("down",t),this._mdown=!0},i.prototype._mouseUp=function(t){return this._mouseAction("up",t),this._mdrag&&this._mouseAction("drop",t),this._mdown=!1,this._mdrag=!1},i.prototype._mouseMove=function(t){return this._mouseAction("move",t),this._mdown?(this._mdrag=!0,this._mouseAction("drag",t)):void 0},i.prototype._mouseOver=function(t){return this._mouseAction("over",t)},i.prototype._mouseOut=function(t){return this._mouseAction("out",t),this._mdrag&&this._mouseAction("drop",t),this._mdrag=!1},i}(Space),this.CanvasSpace=CanvasSpace,DOMSpace=function(t){function i(t,e,n){null==t&&(t="pt_space"),null==e&&(e=!1),null==n&&(n="html"),i.__super__.constructor.apply(this,arguments),this.space=document.querySelector("#"+this.id),this.css={width:"100%",height:"100%"},this.appended=!0,this.space||this._createSpaceElement(),this._mdown=!1,this._mdrag=!1,this.bgcolor=e,this.ctx={}}return extend(i,t),i.prototype._createSpaceElement=function(){return this.space=document.createElement("div"),this.space.setAttribute("id",this.id),this.appended=!1},i.prototype.setCSS=function(t,i,e){return null==e&&(e=!1),this.css[t]=e?i+"px":i,this},i.prototype.updateCSS=function(){var t,i,e,n;i=this.css,e=[];for(t in i)n=i[t],e.push(this.space.style[t]=n);return e},i.prototype.display=function(t,i){var e,n;if(null==t&&(t="#pt"),!this.appended){if(e=document.querySelector(t),n=e.getBoundingClientRect(),!e)throw"Cannot add canvas to element "+t;this.resize(n.width,n.height),window.addEventListener("resize",function(t){return n=e.getBoundingClientRect(),this.resize(n.width,n.height,t)}.bind(this)),this.space.parentNode!==e&&e.appendChild(this.space),this.appended=!0,setTimeout(function(){return this.space.dispatchEvent(new Event("ready")),i?i(n.width,n.height,this.space):void 0}.bind(this))}return this},i.prototype.resize=function(t,i,e){var n,s,r;this.size.set(t,i),this.center=new Vector(t/2,i/2),r=this.items;for(n in r)s=r[n],null!=s.onSpaceResize&&s.onSpaceResize(t,i,e);return this},i.prototype.clear=function(){return this.space.innerHML=""},i.prototype.animate=function(t){var i,e,n;e=this.items;for(i in e)n=e[i],n.animate(t,this._timeDiff,this.ctx);return this._timeEnd>=0&&t>this._timeEnd&&cancelAnimationFrame(this._animID),this},i.prototype.bindCanvas=function(t,i){return this.space.addEventListener(t,i)},i.prototype.bindMouse=function(t){return null==t&&(t=!0),t?(this.space.addEventListener("mousedown",this._mouseDown.bind(this)),this.space.addEventListener("mouseup",this._mouseUp.bind(this)),this.space.addEventListener("mouseover",this._mouseOver.bind(this)),this.space.addEventListener("mouseout",this._mouseOut.bind(this)),this.space.addEventListener("mousemove",this._mouseMove.bind(this))):(this.space.removeEventListener("mousedown",this._mouseDown.bind(this)),this.space.removeEventListener("mouseup",this._mouseUp.bind(this)),this.space.removeEventListener("mouseover",this._mouseOver.bind(this)),this.space.removeEventListener("mouseout",this._mouseOut.bind(this)),this.space.removeEventListener("mousemove",this._mouseMove.bind(this)))},i.prototype._mouseAction=function(t,i){var e,n,s,r,o,h;r=this.items,o=[];for(e in r)h=r[e],n=i.offsetX||i.layerX,s=i.offsetY||i.layerY,o.push(null!=h.onMouseAction?h.onMouseAction(t,n,s,i):void 0);return o},i.prototype._mouseDown=function(t){return this._mouseAction("down",t),this._mdown=!0},i.prototype._mouseUp=function(t){return this._mouseAction("up",t),this._mdrag&&this._mouseAction("drop",t),this._mdown=!1,this._mdrag=!1},i.prototype._mouseMove=function(t){return this._mouseAction("move",t),this._mdown?(this._mdrag=!0,this._mouseAction("drag",t)):void 0},i.prototype._mouseOver=function(t){return this._mouseAction("over",t)},i.prototype._mouseOut=function(t){return this._mouseAction("out",t),this._mdrag&&this._mouseAction("drop",t),this._mdrag=!1},i.attr=function(t,i){var e,n,s;n=[];for(e in i)s=i[e],n.push(t.setAttribute(e,s));return n},i.css=function(t){var i,e,n;e="";for(i in t)n=t[i],n&&(e+=i+": "+n+"; ");return e},i}(Space),this.DOMSpace=DOMSpace,Form=function(){function t(t){this.cc=t.ctx,this.cc.fillStyle="#999",this.cc.strokeStyle="#666",this.cc.lineWidth=1,this.cc.font="11px sans-serif",this.filled=!0,this.stroked=!0,this.fontSize=11,this.fontFace="sans-serif"}return t.context=function(t){var i,e;if(e=document.getElementById(t),i=e&&e.getContext?e.getContext("2d"):!1,!i)throw"Cannot initiate canvas 2d context";return i},t.line=function(t,i){if(!i.p1)throw i.toString()+" is not a Pair";return t.beginPath(),t.moveTo(i.x,i.y),t.lineTo(i.p1.x,i.p1.y),t.stroke()},t.lines=function(i,e){var n,s,r,o;for(o=[],n=0,s=e.length;s>n;n++)r=e[n],o.push(t.line(i,r));return o},t.rect=function(t,i,e,n){if(null==e&&(e=!0),null==n&&(n=!1),!i.p1)throw""+(i.toString()===!a(Pair));return t.beginPath(),t.moveTo(i.x,i.y),t.lineTo(i.x,i.p1.y),t.lineTo(i.p1.x,i.p1.y),t.lineTo(i.p1.x,i.y),t.closePath(),n&&t.stroke(),e?t.fill():void 0},t.circle=function(t,i,e,n){null==e&&(e=!0),null==n&&(n=!1),t.beginPath(),t.arc(i.x,i.y,i.radius,0,Const.two_pi,!1),e&&t.fill(),n&&t.stroke()},t.triangle=function(t,i,e,n){null==e&&(e=!0),null==n&&(n=!1),t.beginPath(),t.moveTo(i.x,i.y),t.lineTo(i.p1.x,i.p1.y),t.lineTo(i.p2.x,i.p2.y),t.closePath(),e&&t.fill(),n&&t.stroke()},t.point=function(t,i,e,n,s,r){var o,h,u,a;return null==e&&(e=2),null==n&&(n=!0),null==s&&(s=!1),null==r&&(r=!1),r?(t.beginPath(),t.arc(i.x,i.y,e,0,Const.two_pi,!1)):(o=i.x-e,u=i.y-e,h=i.x+e,a=i.y+e,t.beginPath(),t.moveTo(o,u),t.lineTo(o,a),t.lineTo(h,a),t.lineTo(h,u),t.closePath()),n&&t.fill(),s&&t.stroke(),i},t.points=function(i,e,n,s,r,o){var h,u,a,p;for(null==n&&(n=2),null==s&&(s=!0),null==r&&(r=!1),null==o&&(o=!1),p=[],h=0,u=e.length;u>h;h++)a=e[h],p.push(t.point(i,a,n,s,r,o));return p},t.polygon=function(t,i,e,n,s){var r,o,h;if(null==e&&(e=!0),null==n&&(n=!0),null==s&&(s=!0),!(i.length<=1)){for(t.beginPath(),t.moveTo(i[0].x,i[0].y),r=o=1,h=i.length;h>o;r=o+=1)t.lineTo(i[r].x,i[r].y);e&&t.closePath(),n&&t.fill(),s&&t.stroke()}},t.curve=function(i,e){return t.polygon(i,e,!1,!1,!0)},t.text=function(t,i,e,n){return t.fillText(e,i.x,i.y,n)},t.prototype.fill=function(t){return this.cc.fillStyle=t?t:"transparent",this.filled=!!t,this},t.prototype.stroke=function(t,i,e){return this.cc.strokeStyle=t?t:"transparent",this.stroked=!!t,i&&(this.cc.lineWidth=i),e&&(this.cc.lineJoin=e),this},t.prototype.font=function(t,i){return null==i&&(i=this.fontFace),this.fontSize=t,this.cc.font=t+"px "+i,this},t.prototype.draw=function(t){return this.sketch(t)},t.prototype.sketch=function(i){return i.floor(),i instanceof Circle?t.circle(this.cc,i,this.filled,this.stroked):i instanceof Rectangle?t.rect(this.cc,i,this.filled,this.stroked):i instanceof Triangle?t.triangle(this.cc,i,this.filled,this.stroked):i instanceof Line||i instanceof Pair?t.line(this.cc,i):i instanceof PointSet?t.polygon(this.cc,i.points):(i instanceof Vector||i instanceof Point)&&t.point(this.cc,i),this},t.prototype.point=function(i,e,n){return null==e&&(e=2),null==n&&(n=!1),t.point(this.cc,i,e,this.filled,this.stroked,n),this},t.prototype.points=function(i,e,n){return null==e&&(e=2),null==n&&(n=!1),t.points(this.cc,i,e,this.filled,this.stroked,n),this},t.prototype.line=function(i){return t.line(this.cc,i),this},t.prototype.lines=function(i){return t.lines(this.cc,i),this},t.prototype.rect=function(i){return t.rect(this.cc,i,this.filled,this.stroked),this},t.prototype.circle=function(i){return t.circle(this.cc,i,this.filled,this.stroked),this},t.prototype.triangle=function(i){return t.triangle(this.cc,i,this.filled,this.stroked),this},t.prototype.polygon=function(i,e){return t.polygon(this.cc,i,e,this.filled,this.stroked),this},t.prototype.curve=function(i){return t.curve(this.cc,i),this},t.prototype.text=function(t,i,e,n,s){var r;return null==e&&(e=1e3),r=new Vector(t),n&&r.add(n,0),s&&r.add(0,s),this.cc.fillText(i,r.x,r.y,e),this},t}(),this.Form=Form,Point=function(){function t(i){this.copy(t.get(arguments))}return t.get=function(t){return t.length>0?"object"==typeof t[0]?t[0]instanceof Array||t[0].length>0?{x:t[0][0]||0,y:t[0][1]||0,z:t[0][2]||0}:{x:t[0].x||0,y:t[0].y||0,z:t[0].z||0}:{x:t[0]||0,y:t[1]||0,z:t[2]||0}:{x:0,y:0,z:0}},t.prototype.quadrant=function(t,i){return null==i&&(i=Const.epsilon),t.near(this)?Const.identical:Math.abs(t.x-this.x)this.x?Const.top_right:t.ythis.y&&t.x1?t:t[0]},i.prototype.add=function(t){var i;return"number"==typeof arguments[0]&&1===arguments.length?(this.x+=arguments[0],this.y+=arguments[0],this.z+=arguments[0]):(i=Point.get(arguments),this.x+=i.x,this.y+=i.y,this.z+=i.z),this},i.prototype.$add=function(t){var e;return e=this._getArgs(arguments),new i(this).add(e)},i.prototype.subtract=function(t){var i;return"number"==typeof arguments[0]&&1===arguments.length?(this.x-=arguments[0],this.y-=arguments[0],this.z-=arguments[0]):(i=Point.get(arguments),this.x-=i.x,this.y-=i.y,this.z-=i.z),this},i.prototype.$subtract=function(t){var e;return e=this._getArgs(arguments),new i(this).subtract(e)},i.prototype.multiply=function(t){var i;return 1===arguments.length&&("number"==typeof arguments[0]||"object"==typeof arguments[0]&&1===arguments[0].length)?(this.x*=arguments[0],this.y*=arguments[0],this.z*=arguments[0]):(i=Point.get(arguments),this.x*=i.x,this.y*=i.y,this.z*=i.z),this},i.prototype.$multiply=function(t){var e;return e=this._getArgs(arguments),new i(this).multiply(e)},i.prototype.divide=function(t){var i;return 1===arguments.length&&("number"==typeof arguments[0]||"object"==typeof arguments[0]&&1===arguments[0].length)?(this.x/=arguments[0],this.y/=arguments[0],this.z/=arguments[0]):(i=Point.get(arguments),this.x/=i.x,this.y/=i.y,this.z/=i.z),this},i.prototype.$divide=function(t){var e;return e=this._getArgs(arguments),new i(this).divide(e)},i.prototype.op=function(){var t,i,e,n,s,r;for(n=arguments[0],t=2<=arguments.length?slice.call(arguments,1):[],r=this.toArray(),i=0,e=r.length;e>i;i++)s=r[i],s[n].apply(s,t);return this},i.prototype.$op=function(){var t,i,e,n,s,r,o;for(s=arguments[0],t=2<=arguments.length?slice.call(arguments,1):[],i=this.clone(),o=i.toArray(),e=0,n=o.length;n>e;e++)r=o[e],r[s].apply(r,t);return i},i.prototype.angle=function(t){var i,e;return 0===arguments.length?Math.atan2(this.y,this.x):("string"==typeof arguments[0]?(i=arguments[0],e=arguments.length>1?this.$subtract(arguments[1]).multiply(-1):void 0):(e=this.$subtract(arguments[0]).multiply(-1),i=!1),e&&!i?Math.atan2(e.y,e.x):i===Const.xy?e?Math.atan2(e.y,e.x):Math.atan2(this.y,this.x):i===Const.yz?e?Math.atan2(e.z,e.y):Math.atan2(this.z,this.y):i===Const.xz?e?Math.atan2(e.z,e.x):Math.atan2(this.z,this.x):void 0)},i.prototype.angleBetween=function(t,i){return null==i&&(i=Const.xy),Util.boundRadian(this.angle(i),!0)-Util.boundRadian(t.angle(i),!0)},i.prototype.magnitude=function(t){var i,e,n,s,r,o;return n={x:this.x*this.x,y:this.y*this.y,z:this.z*this.z},o=arguments.length>=1&&!arguments[arguments.length-1],i=o?function(t){return t}:Math.sqrt,0===arguments.length?i(n.x+n.y+n.z):("string"==typeof arguments[0]?(e=arguments[0],r=arguments.length>1&&arguments[1]?this.$subtract(arguments[1]):void 0):(r=this.$subtract(arguments[0]),e=!1),s=r?{x:r.x*r.x,y:r.y*r.y,z:r.z*r.z}:n,r&&!e?i(s.x+s.y+s.z):e===Const.xy?i(s.x+s.y):e===Const.yz?i(s.y+s.z):e===Const.xz?i(s.x+s.z):void 0)},i.prototype.distance=function(t,i){return null==i&&(i=Const.xy),this.magnitude(i,t)},i.prototype.normalize=function(){return this.set(this.$normalize()),this},i.prototype.$normalize=function(){var t;return t=this.magnitude(),0===t?new i:new i(this.x/t,this.y/t,this.z/t)},i.prototype.abs=function(){return this.x=Math.abs(this.x),this.y=Math.abs(this.y),this.z=Math.abs(this.z),this},i.prototype.dot=function(t,i){return null==i&&(i=Const.xyz),i===Const.xyz?this.x*t.x+this.y*t.y+this.z*t.z:i===Const.xy?this.x*t.x+this.y*t.y:i===Const.yz?this.y*t.y+this.z*t.z:i===Const.xz?this.x*t.x+this.z*t.z:this.x*t.x+this.y*t.y+this.z*t.z},i.prototype.projection=function(t,e){var n,s,r,o;return null==e&&(e=Const.xyz),o=t.magnitude(),n=this.$normalize(),s=new i(t.x/o,t.y/o,t.z/o),r=n.dot(s,e),n.$multiply(o*r)},i.prototype.cross=function(t){return new i(this.y*t.z-this.z*t.y,this.z*t.x-this.x*t.z,this.x*t.y-this.y*t.x)},i.prototype.bisect=function(t,i){return null==i&&(i=!1),i?this.$add(t).divide(2):this.$normalize().add(t.$normalize()).divide(2)},i.prototype.perpendicular=function(t){switch(null==t&&(t=Const.xy),t){case Const.xy:return[new i(-this.y,this.x,this.z),new i(this.y,-this.x,this.z)];case Const.yz:return[new i(this.x,-this.z,this.y),new i(this.x,this.z,-this.y)];case Const.xz:return[new i(-this.z,this.y,this.x),new i(this.z,-this.y,this.x)];default:return[new i(-this.y,this.x,this.z),new i(this.y,-this.x,this.z)]}},i.prototype.isPerpendicular=function(t,i){return null==i&&(i=Const.xyz),0===this.dot(t,i)},i.prototype.surfaceNormal=function(t){return this.cross(t).normalize(!0)},i.prototype.moveTo=function(t){var i,e,n,s,r,o;for(o=Point.get(arguments),i=this.$subtract(o),r=this.toArray(),e=0,n=r.length;n>e;e++)s=r[e],s.subtract(i);return this},i.prototype.moveBy=function(t){var i,e,n,s,r;for(i=Point.get(arguments),r=this.toArray(),e=0,n=r.length;n>e;e++)s=r[e],s.add(i);return this},i.prototype.rotate2D=function(t,i,e){var n,s,r,o,h;for(null==e&&(e=Const.xy),i||(i=new Point(0,0,0)),r=Matrix.rotateAnchor2D(t,i,e),h=this.toArray(),n=0,s=h.length;s>n;n++)o=h[n],Matrix.transform2D(o,r,e);return this},i.prototype.reflect2D=function(t,i){var e,n,s,r,o;for(null==i&&(i=Const.xy),s=Matrix.reflectAnchor2D(t,i),o=this.toArray(),e=0,n=o.length;n>e;e++)r=o[e],Matrix.transform2D(r,s,i);return this},i.prototype.scale2D=function(t,i,e,n){var s,r,o,h,u;for(null==n&&(n=Const.xy),e||(e=new Point(0,0,0)),o=Matrix.scaleAnchor2D(t,i,e,n),u=this.toArray(),s=0,r=u.length;r>s;s++)h=u[s],Matrix.transform2D(h,o,n);return this},i.prototype.shear2D=function(t,i,e,n){var s,r,o,h,u;for(null==n&&(n=Const.xy),e||(e=new Point(0,0,0)),o=Matrix.shearAnchor2D(t,i,e,n),u=this.toArray(),s=0,r=u.length;r>s;s++)h=u[s],Matrix.transform2D(h,o,n);return this},i.prototype.clone=function(){return new i(this)},i.prototype.toString=function(){return"Vector "+this.x+", "+this.y+", "+this.z},i}(Point),this.Vector=Vector,Color=function(t){function i(t){i.__super__.constructor.apply(this,arguments),this.alpha=arguments.length>=4?Math.min(1,Math.max(arguments[3],0)):1,this.mode=arguments.length>=5?arguments[4]:"rgb"}return extend(i,t),i.XYZ={D65:{x:95.047,y:100,z:108.883}},i.parseHex=function(t,e){var n,s;return null==e&&(e=!1),0===t.indexOf("#")&&(t=t.substr(1)),3===t.length&&(t=""+t[0]+t[0]+t[1]+t[1]+t[2]+t[2]),8===t.length&&(this.alpha=1&t.substr(6),t=t.substring(0,6)),n=parseInt(t,16),s=[n>>16,n>>8&255,255&n],e?new i(s[0],s[1],s[2]):s},i.prototype.setMode=function(t){if(t=t.toLowerCase(),t!==this.mode){switch(this.mode){case"hsl":this.copy(Point.get(i.HSLtoRGB(this.x,this.y,this.z)));break;case"hsb":this.copy(Point.get(i.HSBtoRGB(this.x,this.y,this.z)));break;case"lab":this.copy(Point.get(i.LABtoRGB(this.x,this.y,this.z)));break;case"lch":this.copy(Point.get(i.LCHtoRGB(this.x,this.y,this.z)));break;case"xyz":this.copy(Point.get(i.XYZtoRGB(this.x,this.y,this.z)))}switch(t){case"hsl":this.copy(Point.get(i.RGBtoHSL(this.x,this.y,this.z)));break;case"hsb":this.copy(Point.get(i.RGBtoHSB(this.x,this.y,this.z)));break;case"lab":this.copy(Point.get(i.RGBtoLAB(this.x,this.y,this.z)));break;case"lch":this.copy(Point.get(i.RGBtoLCH(this.x,this.y,this.z)));break;case"xyz":this.copy(Point.get(i.RGBtoXYZ(this.x,this.y,this.z)))}}return this.mode=t,this},i.prototype.hex=function(){var t,i,e,n;return"rgb"===this.mode&&this.floor(),i=this.values("rgb"!==this.mode),t=function(t){return t=t.toString(16),t.length<2?"0"+t:t},e=function(){var e,s,r;for(r=[],e=0,s=i.length;s>e;e++)n=i[e],r.push(t(n));return r}(),"#"+e[0]+e[1]+e[2]},i.prototype.rgb=function(){var t;return"rgb"===this.mode&&this.floor(),t=this.values("rgb"!==this.mode),"rgb("+t[0]+", "+t[1]+", "+t[2]+")"},i.prototype.rgba=function(){var t;return"rgb"===this.mode&&this.floor(),t=this.values("rgb"!==this.mode),"rgba("+t[0]+", "+t[1]+", "+t[2]+", "+this.alpha+")"},i.prototype.values=function(t){var e,n;if(null==t&&(t=!1),e=[this.x,this.y,this.z],t&&"rgb"!==this.mode)switch(this.mode){case"hsl":e=i.HSLtoRGB(this.x,this.y,this.z);break;case"hsb":e=i.HSBtoRGB(this.x,this.y,this.z);break;case"lab":e=i.LABtoRGB(this.x,this.y,this.z);break;case"lch":e=i.LCHtoRGB(this.x,this.y,this.z);break;case"xyz":e=i.XYZtoRGB(this.x,this.y,this.z)}return function(){var t,i,s;for(s=[],t=0,i=e.length;i>t;t++)n=e[t],s.push(Math.floor(n));return s}()},i.RGBtoHSL=function(t,i,e,n,s){var r,o,h,u,a,p;if(n||(t/=255,i/=255,e/=255),u=Math.max(t,i,e),a=Math.min(t,i,e),o=(u+a)/2,p=o,h=o,u===a)o=0,p=0;else switch(r=u-a,p=h>.5?r/(2-u-a):r/(u+a),u){case t:o=(i-e)/r+(e>i?6:0);break;case i:o=(e-t)/r+2;break;case e:o=(t-i)/r+4;break;default:o=0}return s?[o/60,p,h]:[60*o,p,h]},i.HSLtoRGB=function(t,i,e,n,s){var r,o,h,u,a,p;return 0===i?s?[1,1,1]:[255,255,255]:(n||(t/=360),a=.5>=e?e*(1+i):e+i-e*i,u=2*e-a,h=function(t,i,e){return 0>e?e+=1:e>1&&(e-=1),1>6*e?t+(i-t)*e*6:1>2*e?i:2>3*e?t+(i-t)*(2/3-e)*6:t},p=h(u,a,t+1/3),o=h(u,a,t),r=h(u,a,t-1/3),s?[p,o,r]:[255*p,255*o,255*r])},i.RGBtoHSB=function(t,i,e,n,s){var r,o,h,u,a,p;if(n||(t/=255,i/=255,e/=255),h=Math.max(t,i,e),u=Math.min(t,i,e),r=h-u,a=0===h?0:r/h,p=h,h===u)o=0;else switch(h){case t:o=(i-e)/r+(e>i?6:0);break;case i:o=(e-t)/r+2;break;case e:o=(t-i)/r+4;break;default:o=0}return s?[o/60,a,p]:[60*o,a,p]},i.HSBtoRGB=function(t,i,e,n,s){var r,o,h,u,a,p;switch(n||(t/=360),o=Math.floor(6*t),r=6*t-o,h=e*(1-i),u=e*(1-r*i),p=e*(1-(1-r)*i),o%6){case 0:a=[e,p,h];break;case 1:a=[u,e,h];break;case 2:a=[h,e,p];break;case 3:a=[h,u,e];break;case 4:a=[p,h,e];break;case 5:a=[e,h,u];break;default:a=[0,0,0]}return s?a:[255*a[0],255*a[1],255*a[2]]},i.RGBtoLAB=function(t,e,n,s,r){var o;return s&&(t*=255,e*=255,n*=255),o=i.RGBtoXYZ(t,e,n),i.XYZtoLAB(o[0],o[1],o[2])},i.LABtoRGB=function(t,e,n,s,r){var o,h;return s&&(t*=100,e=127*(e-.5),n=127*(n-.5)),h=i.LABtoXYZ(t,e,n),o=i.XYZtoRGB(h[0],h[1],h[2]),r?[o[0]/255,o[1]/255,o[2]/255]:o},i.RGBtoLCH=function(t,e,n,s,r){var o,h;return s&&(t*=255,e*=255,n*=255),o=i.RGBtoLAB(t,e,n),h=i.LABtoLCH(o[0],o[1],o[2]),r?[h[0]/100,h[1]/100,h[2]/360]:h},i.LCHtoRGB=function(t,e,n,s,r){var o,h,u;return s&&(t*=100,e*=100,n*=360),o=i.LCHtoLAB(t,e,n),u=i.LABtoXYZ(o[0],o[1],o[2]),h=i.XYZtoRGB(u[0],u[1],u[2]),r?[h[0]/255,h[1]/255,h[2]/255]:h},i.XYZtoRGB=function(t,i,e,n,s){var r,o,h,u,a;for(n||(t/=100,i/=100,e/=100),a=[3.2404542*t+-1.5371385*i+e*-.4985314,t*-.969266+1.8760108*i+.041556*e,.0556434*t+i*-.2040259+1.0572252*e],o=h=0,u=a.length;u>h;o=++h)r=a[o],a[o]=0>r?0:Math.min(1,r>.0031308?1.055*Math.pow(r,1/2.4)-.055:12.92*r);return s?a:[Math.round(255*a[0]),Math.round(255*a[1]),Math.round(255*a[2])]},i.RGBtoXYZ=function(t,i,e,n,s){return n||(t/=255,i/=255,e/=255),t=t>.04045?Math.pow((t+.055)/1.055,2.4):t/12.92,i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92,e=e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92,s||(t=100*t,i=100*i,e=100*e),[.4124564*t+.3575761*i+.1804375*e,.2126729*t+.7151522*i+.072175*e,.0193339*t+.119192*i+.9503041*e]},i.XYZtoLAB=function(t,e,n){var s,r;return t/=i.XYZ.D65.x,e/=i.XYZ.D65.y,n/=i.XYZ.D65.z,s=function(t){return t>.008856?Math.pow(t,1/3):7.787*t+16/116},r=s(e),[116*r-16,500*(s(t)-r),200*(r-s(n))]},i.LABtoXYZ=function(t,e,n){var s,r,o,h,u;return h=(t+16)/116,r=e/500+h,u=h-n/200,s=function(t){var i;return i=Math.pow(t,3),i>.008856?i:(t-16/116)/7.787},o=[Math.min(i.XYZ.D65.x,i.XYZ.D65.x*s(r)),Math.min(i.XYZ.D65.y,i.XYZ.D65.y*s(h)),Math.min(i.XYZ.D65.y,i.XYZ.D65.z*s(u))]},i.XYZtoLUV=function(t,e,n){var s,r,o,h,u;return h=4*t/(t+15*e+3*n),u=9*e/(t+15*e+3*n),e/=100,e=e>.008856?Math.pow(e,1/3):7.787*e+16/116,r=4*i.XYZ.D65.x/(i.XYZ.D65.x+15*i.XYZ.D65.y+3*i.XYZ.D65.z),o=9*i.XYZ.D65.y/(i.XYZ.D65.x+15*i.XYZ.D65.y+3*i.XYZ.D65.z),s=116*e-16,[s,13*s*(h-r),13*s*(u-o)]},i.LUVtoXYZ=function(t,e,n){var s,r,o,h,u;return u=(t+16)/116,s=u*u*u,u=s>.008856?s:(u-16/116)/7.787,r=4*i.XYZ.D65.x/(i.XYZ.D65.x+15*i.XYZ.D65.y+3*i.XYZ.D65.z),
2 | o=9*i.XYZ.D65.y/(i.XYZ.D65.x+15*i.XYZ.D65.y+3*i.XYZ.D65.z),e=e/(13*t)+r,n=n/(13*t)+o,u=100*u,h=-9*u*e/((e-4)*n-e*n),[h,u,(9*u-15*n*u-n*h)/(3*n)]},i.LABtoLCH=function(t,i,e){var n;return n=Math.atan2(e,i),n=n>0?180*n/Math.PI:360-180*Math.abs(n)/Math.PI,[t,Math.sqrt(i*i+e*e),n]},i.LCHtoLAB=function(t,i,e){var n;return n=Math.PI*e/180,[t,Math.cos(n)*i,Math.sin(n)*i]},i.LUVtoLCH=function(t,i,e){return LABtoLCH(t,i,e)},i.LCHtoLUV=function(t,i,e){return LCHtoLAB(t,i,e)},i}(Vector),this.Color=Color,Circle=function(t){function i(){i.__super__.constructor.apply(this,arguments),this.radius=null!=arguments[3]?arguments[3]:0}return extend(i,t),i.prototype.setRadius=function(t){return this.radius=t,this},i.prototype.intersectPoint=function(t){var i,e;return e=new Vector(Point.get(arguments)),i=e.$subtract(this),i.x*i.x+i.y*i.yo?i?[]:!1:i?(h=Math.sqrt(o),y=-a+h,f=-a-h,p=new Point(t.x-r.x*y,t.y-r.y*y),c=new Point(t.x-r.x*f,t.y-r.y*f),0===o?[p]:[p,c]):!0)},i.prototype.intersectLine=function(t,i){var e,n,s,r,o,h;if(null==i&&(i=!0),h=this.intersectPath(t),h&&h.length>0){for(o=[],e=t.bounds(),n=0,s=h.length;s>n;n++)if(r=h[n],Rectangle.contain(r,e,e.p1)){if(!i)return!0;o.push(r)}return i?o:o.length>0}return i?[]:!1},i.prototype.intersectLines=function(t,i){return null==i&&(i=!0),Line.intersectLines(this,t,i)},i.prototype.intersectCircle=function(t,i){var e,n,s,r,o,h,u,a;return null==i&&(i=!0),h=t.$subtract(this),o=h.magnitude(!1),r=Math.sqrt(o),n=this.radius*this.radius,s=t.radius*t.radius,r>this.radius+t.radius?i?[]:!1:r0):t instanceof Point?(n=t.$subtract(this),n.x*n.x+n.y*n.y0;)e=Math.min(i,this.frame_ms),this.integrate(s/1e3,e/1e3),i-=e,s+=e,n.push(this.life.age++);return n},i.prototype.integrate=function(t,i){return this.integrateRK4(t,i)},i.prototype.forces=function(t,i){return{force:new Vector}},i.prototype.impulse=function(t){return this.momentum.add(t),this.velocity=this.momentum.$divide(this.mass)},i.prototype._evaluate=function(t,i,e){var n,s;return null==i&&(i=0),null==e&&(e=!1),s=0!==i&&e?{position:this.$add(e.velocity.$multiply(i)),momentum:this.momentum.$add(e.force.$multiply(i))}:{position:new Vector(this),momentum:new Vector(this.momentum)},s.velocity=s.momentum.$divide(this.mass),n=this.forces(s,t+i),{velocity:s.velocity,force:n.force}},i.prototype.integrateRK4=function(t,i){var e,n,s,r,o;return e=function(t,i,e,n){var s;return s=new Vector((t.x+2*(i.x+e.x)+n.x)/6,(t.y+2*(i.y+e.y)+n.y)/6,(t.z+2*(i.z+e.z)+n.z)/6)},n=this._evaluate(t,0),s=this._evaluate(t,.5*i,n),r=this._evaluate(t,.5*i,s),o=this._evaluate(t,i,r),this.add(e(n.velocity,s.velocity,r.velocity,o.velocity)),this.momentum.add(e(n.force,s.force,r.force,o.force))},i.prototype.integrateEuler=function(t,i){var e;return e=this.forces({position:new Vector(this),momentum:new Vector(this.momentum)},t+i),this.add(this.velocity),this.momentum.add(e.force),this.velocity=this.momentum.$divide(this.mass)},i.prototype.collideLine2d=function(t,i){var e,n,s,r,o,h,u,a,p,c,l,y,f,m,d,g,x,v,z,_;if(null==i&&(i=!0),o=new Vector(this),r=Math.abs(t.getDistanceFromPoint(o)),n=Math.abs(r)t.p1.x?(this.x-this.radiust.p1.x&&(this.x=t.p1.x-this.radius),this.velocity.x*=-1,this.momentum=this.velocity.$multiply(this.mass),!0):this.y-this.radiust.p1.y?(this.y-this.radiust.p1.y&&(this.y=t.p1.y-this.radius),this.velocity.y*=-1,this.momentum=this.velocity.$multiply(this.mass),!0):!1},i.prototype.collideParticle2d=function(t){return this.hasIntersect(t)?i.collideParticle2d(this,t,!0):!1},i.collideParticle2d=function(t,i,e,n){var s,r,o,h,u,a,p,c,l,y,f,m,d,g,x,v,z;return null==e&&(e=!0),null==n&&(n=!0),y=t.$subtract(i).normalize(),d=new Vector(-y.y,y.x),h=y.dot(t.velocity),u=d.dot(t.velocity),a=y.dot(i.velocity),p=d.dot(i.velocity),s=(h*(t.mass-i.mass)+2*i.mass*a)/(t.mass+i.mass),r=(a*(i.mass-t.mass)+2*t.mass*h)/(t.mass+i.mass),g=y.$multiply(s),x=d.$multiply(u),v=y.$multiply(r),z=d.$multiply(p),f=g.$add(x),m=v.$add(z),n&&(c=t.magnitude(i),co;s=++o)p=c[s],p.life.complete?n.push(s):p.life.active&&p.animate(t,i,e);if(n.length>0){for(l=[],a=0,u=n.length;u>a;a++)r=n[a],l.push(this.particles.splice(r,1));return l}},t}(),this.ParticleSystem=ParticleSystem,Pair=function(t){function i(){i.__super__.constructor.apply(this,arguments),this.p1=new Vector(this.x,this.y,this.z),4===arguments.length?(this.z=0,this.p1.set(arguments[2],arguments[3])):6===arguments.length&&this.p1.set(arguments[3],arguments[4],arguments[5])}return extend(i,t),i.prototype.to=function(){return this.p1=new Vector(Point.get(arguments)),this},i.prototype.getAt=function(t){return 1===t||"p1"===t?this.p1:this},i.prototype.$getAt=function(t){return new Vector(this.getAt(t))},i.prototype.relative=function(){return this.p1.add(this),this},i.prototype.$relative=function(){return this.$add(this.p1)},i.prototype.bounds=function(){return new i(this.$min(this.p1)).to(this.$max(this.p1))},i.prototype.withinBounds=function(t,i){var e,n;return i?(e=this.get2D(i),n=this.p1.get2D(i),e.x===n.x?t.y>=Math.min(e.y,n.y)&&t.y<=Math.max(e.y,n.y):e.y===n.y?t.x>=Math.min(e.x,n.x)&&t.x<=Math.max(e.x,n.x):t.x>=Math.min(e.x,n.x)&&t.y>=Math.min(e.y,n.y)&&t.x<=Math.max(e.x,n.x)&&t.y<=Math.max(e.y,n.y)):t.x>=Math.min(this.x,this.p1.x)&&t.y>=Math.min(this.y,this.p1.y)&&t.z>=Math.min(this.z,this.p1.z)&&t.x<=Math.max(this.x,this.p1.x)&&t.y<=Math.max(this.y,this.p1.y)&&t.z<=Math.max(this.z,this.p1.z)},i.prototype.interpolate=function(t,i){var e;return null==i&&(i=!1),e=i?this.$relative():this.p1,new Vector((1-t)*this.x+t*e.x,(1-t)*this.y+t*e.y,(1-t)*this.z+t*e.z)},i.prototype.midpoint=function(){return this.interpolate(.5)},i.prototype.direction=function(t){return t?this.$subtract(this.p1):this.p1.$subtract(this)},i.prototype.size=function(){return arguments.length>0?(this.p1=this.$add(Point.get(arguments)),this):this.p1.$subtract(this).abs()},i.prototype.length=function(t){var i,e,n,s;return null==t&&(t=!0),s=this.z-this.p1.z,n=this.y-this.p1.y,e=this.x-this.p1.x,i=e*e+n*n+s*s,t?Math.sqrt(i):i},i.prototype.collinear=function(t){return(this.p1.x-this.x)*(t.y-this.y)-(t.x-this.x)*(this.p1.y-this.y)},i.prototype.resetBounds=function(){var t;return t=this.$min(this.p1),this.p1.set(this.$max(this.p1)),this.set(t),this},i.prototype.equal=function(t){return null==t&&(t=!1),arguments[0]instanceof i?i.__super__.equal.call(this,arguments[0])&&this.p1.equal(arguments[0].p1):i.__super__.equal.apply(this,arguments)},i.prototype.clone=function(){var t;return t=new i(this),t.to(this.p1.clone()),t},i.prototype.floor=function(){return i.__super__.floor.apply(this,arguments),this.p1.floor()},i.prototype.toString=function(){return"Pair of vectors from ("+this.x+", "+this.y+", "+this.z+") to ("+this.p1.x+", "+this.p1.y+", "+this.p1.z+")"},i.prototype.toArray=function(){return[this,this.p1]},i}(Vector),this.Pair=Pair,Line=function(t){function i(){i.__super__.constructor.apply(this,arguments)}return extend(i,t),i.slope=function(t,i,e){var n,s;return null==e&&(e=Const.xy),n=t.get2D(e),s=i.get2D(e),s.x-n.x===0?!1:(s.y-n.y)/(s.x-n.x)},i.intercept=function(t,i,e){var n,s,r,o;return null==e&&(e=Const.xy),r=t.get2D(e),o=i.get2D(e),o.x-r.x===0?!1:(s=(o.y-r.y)/(o.x-r.x),n=r.y-s*r.x,{slope:s,yi:n,xi:0===s?!1:-n/s})},i.isPerpendicularLine=function(t,e,n){var s,r;return null==n&&(n=Const.xy),s=i.slope(t,t.p1,n),r=i.slope(e,e.p1,n),s===!1?0===r:r===!1?0===s:s*r===-1},i.prototype.slope=function(t){return null==t&&(t=Const.xy),i.slope(this,this.p1,t)},i.prototype.intercept=function(t){return null==t&&(t=Const.xy),i.intercept(this,this.p1,t)},i.prototype.getPerpendicular=function(t,e,n,s){var r,o,h;return null==e&&(e=10),null==n&&(n=!1),null==s&&(s=Const.xy),o=this.direction().normalize().perpendicular(s),h=n?o[1]:o[0],r=new i(this.interpolate(t)),r.to(h.multiply(e).add(r)),r},i.prototype.getDistanceFromPoint=function(t){var i,e;return e=this.$subtract(this.p1),i=new Vector(-e.y,e.x).normalize(),this.$subtract(t).dot(i)},i.prototype.getPerpendicularFromPoint=function(t,i){var e;return null==i&&(i=!0),e=this.p1.$subtract(this).projection(t.$subtract(this)),i?e.add(this):e},i.prototype.intersectPath=function(t,i){var e,n,s,r,o,h,u;return null==i&&(i=Const.xy),e=this.intercept(i),n=t.intercept(i),r=this.get2D(i),s=t.get2D(i),e===!1?n===!1?!1:(u=-n.slope*(s.x-r.x)+s.y,i===Const.xy?new Vector(r.x,u):new Vector(r.x,u).get2D(i,!0)):n===!1?(u=-e.slope*(r.x-s.x)+r.y,new Vector(s.x,u)):n.slope!==e.slope?(o=(e.slope*r.x-n.slope*s.x+s.y-r.y)/(e.slope-n.slope),h=e.slope*(o-r.x)+r.y,i===Const.xy?new Vector(o,h):new Vector(o,h).get2D(i,!0)):e.yi===n.yi?null:!1},i.prototype.intersectLine=function(t,i){var e;return null==i&&(i=Const.xy),e=this.intersectPath(t,i),e&&this.withinBounds(e,i)&&t.withinBounds(e,i)?e:null===e?null:!1},i.intersectLines=function(t,i,e){var n,s,r,o,h,u,a;if(null==e&&(e=!0),!t.intersectLine)throw"No intersectLine function found in "+t.toString();a=[];for(n in i)if(h=i[n],s=t.intersectLine(h,e)){if(!e)return!0;if(s.length>0)for(r=0,o=s.length;o>r;r++)u=s[r],a.push(u)}return e?a:!1},i.prototype.intersectGridLine=function(t,i,e){var n,s,r,o;if(null==i&&(i=!1),null==e&&(e=Const.xy),n=this.get2D(e),s=this.p1.get2D(e),r=t.get2D(e),o=t.p1.get2D(e),s.x-n.x===0){if(o.y-r.y===0&&Util.within(n.x,r.x,o.x)&&(i||Util.within(r.y,n.y,s.y)))return new Vector(n.x,r.y)}else{if(s.y-n.y!==0)return!1;if(o.x-r.x===0&&Util.within(n.y,r.y,o.y)&&(i||Util.within(r.x,n.x,s.x)))return new Vector(r.x,n.y)}},i.prototype.subpoints=function(t){var i,e,n,s;for(n=[],s=i=0,e=t;e>=0?e>=i:i>=e;s=e>=0?++i:--i)n.push(this.interpolate(s/t));return n},i.prototype.clone=function(t){return new i(this).to(this.p1)},i}(Pair),this.Line=Line,Rectangle=function(t){function i(){i.__super__.constructor.apply(this,arguments),this.center=new Vector}return extend(i,t),i.contain=function(t,i,e){return t.x>=i.x&&t.x<=e.x&&t.y>=i.y&&t.y<=e.y&&t.z>=i.z&&t.z<=e.z},i.prototype.toString=function(){var t;return t=this.size(),"Rectangle x1 "+this.x+", y1 "+this.y+", z1 "+this.z+", x2 "+this.p1.x+", y2 "+this.p1.y+", z2 "+this.p1.z+", width "+t.x+", height "+t.y},i.prototype.toPointSet=function(){var t;return t=this.corners(),new PointSet(this).to([t.topRight,t.bottomRight,t.bottomLeft,t.topLeft])},i.prototype.to=function(t){return this.p1=new Vector(Point.get(arguments)),this.resetBounds(),this.center=this.midpoint(),this},i.prototype.setCenter=function(t){var i;return 0===arguments.length?void(this.center=this.midpoint()):(i=this.size().$divide(2),this.center.set(Point.get(arguments)),this.set(this.center.$subtract(i)),this.p1.set(this.center.$add(i)),this)},i.prototype.resizeTo=function(){return this.p1=new Vector(Point.get(arguments)),this.relative(),this.center=this.midpoint(),this},i.prototype.resizeCenterTo=function(){var t;return t=new Vector(Point.get(arguments)).divide(2),this.set(this.center.$subtract(t)),this.p1.set(this.center.$add(t)),this},i.prototype.enclose=function(t){return this.set(this.$min(t)),this.p1.set(this.p1.$max(t.p1)),this.center=this.midpoint(),this},i.prototype.$enclose=function(t){return this.clone().enclose(t)},i.prototype.isEnclosed=function(t){var i,e;return i=this.$subtract(t).multiply(this.p1.$subtract(t.p1)),e=this.size().subtract(t.size()),i.x<=0&&i.y<=0&&i.z<=0&&e.x*e.y>=0},i.prototype.isLarger=function(t){var i,e;return i=this.size(),e=t.size(),i.x*i.y>e.x*e.y},i.prototype.intersectPoint=function(){var t;return t=Point.get(arguments),t.x>=this.x&&t.x<=this.p1.x&&t.y>=this.y&&t.y<=this.p1.y&&t.z>=this.z&&t.z<=this.p1.z},i.prototype.intersectPath=function(t,i){var e,n,s,r,o,h;for(null==i&&(i=!0),h=this.sides(),r=[],e=0,n=h.length;n>e;e++)if(o=h[e],s=o.intersectPath(t),s&&this.intersectPoint(s)){if(!i)return!0;r.push(s)}return i?r:!1},i.prototype.intersectLine=function(t,i){var e,n,s,r,o,h,u,a,p;if(null==i&&(i=!0),e=this.intersectPoint(t),n=this.intersectPoint(t.p1),e&&n&&i)return[];if(!e&&!n&&(r=t.bounds(),!this.intersectRectangle(r,!1)))return i?[]:!1;for(p=this.sides(),u=[],s=0,o=p.length;o>s;s++)if(a=p[s],h=t.intersectLine(a)){if(!i)return!0;u.push(h)}return i?u:!1},i.prototype.intersectLines=function(t,i){return null==i&&(i=!0),Line.intersectLines(this,t,i)},i.prototype.intersectRectangle=function(t,i){var e,n,s,r,o,h,u,a,p,c,l,y,f,m;if(null==i&&(i=!0),y=this.p1.x>=t.x&&this.x<=t.p1.x,f=this.p1.y>=t.y&&this.y<=t.p1.y,m=this.p1.z>=t.z&&this.z<=t.p1.z,e=y&&f&&m,!i)return e;if(this.isEnclosed(t))return i?[]:!0;if(!e)return[];for(c=this.sides(),l=t.sides(),u=[],n=0,s=c.length;s>n;n++)for(a=c[n],o=0,r=l.length;r>o;o++)p=l[o],h=a.intersectGridLine(p),h&&u.push(h);return u},i.prototype.hasIntersect=function(t,e){return null==e&&(e=!1),t instanceof Circle?t.intersectLines(this.sides(),e):t instanceof i?this.intersectRectangle(t,e):t instanceof PointSet||t instanceof Triangle?this.intersectLines(t.sides(),e):t instanceof Pair?this.intersectLine(t,e):t instanceof Point?i.contain(t,this,this.p1):e?[]:!1},i.prototype.corners=function(){return{topLeft:new Vector(Math.min(this.x,this.p1.x),Math.min(this.y,this.p1.y),Math.max(this.z,this.p1.z)),topRight:new Vector(Math.max(this.x,this.p1.x),Math.min(this.y,this.p1.y),Math.min(this.z,this.p1.z)),bottomLeft:new Vector(Math.min(this.x,this.p1.x),Math.max(this.y,this.p1.y),Math.max(this.z,this.p1.z)),bottomRight:new Vector(Math.max(this.x,this.p1.x),Math.max(this.y,this.p1.y),Math.min(this.z,this.p1.z))}},i.prototype.sides=function(){var t;return t=this.corners(),[new Line(t.topLeft).to(t.topRight),new Line(t.topRight).to(t.bottomRight),new Line(t.bottomRight).to(t.bottomLeft),new Line(t.bottomLeft).to(t.topLeft)]},i.prototype.quadrants=function(){var t;return t=this.corners(),{topLeft:new this.__proto__.constructor(t.topLeft).to(this.center),topRight:new this.__proto__.constructor(t.topRight).to(this.center),bottomLeft:new this.__proto__.constructor(t.bottomLeft).to(this.center),bottomRight:new this.__proto__.constructor(t.bottomRight).to(this.center)}},i.prototype.clone=function(){var t;return t=new i(this).to(this.p1),t.to(this.p1.clone()),t},i}(Pair),this.Rectangle=Rectangle,Grid=function(t){function i(){i.__super__.constructor.apply(this,arguments),this.cell={type:"fix-fix",size:new Vector},this.rows=0,this.columns=0,this.layout=[],this.cellCallback=null}return extend(i,t),i.prototype.toString=function(){var t;return t=this.size(),"Grid width "+t.x+", height "+t.y+", columns "+this.columns+", rows "+this.rows+", "+("cell ("+this.cell.size.x+", "+this.cell.size.y+"), type "+this.cell.type)},i.prototype.init=function(t,i,e,n){var s;return null==e&&(e="fix"),null==n&&(n="fix"),s=this.size(),this.cell.type=e+"-"+n,this.rows=i,this.columns=t,"stretch"===e?(this.cell.size.x=s.x/t,this.columns=t):"flex"===e?(this.columns=Math.round(s.x/t),this.cell.size.x=s.x/this.columns):(this.cell.size.x=t,this.columns=Math.floor(s.x/this.cell.size.x)),"stretch"===n?(this.cell.size.y=s.y/i,this.rows=i):"flex"===n?(this.rows=Math.round(s.y/i),this.cell.size.y=s.y/this.rows):(this.cell.size.y=i,this.rows=Math.floor(s.y/this.cell.size.y)),this},i.prototype.generate=function(t){return"function"==typeof t&&(this.cellCallback=t),this},i.prototype.create=function(){var t,i,e,n,s,r,o,h,u;if(!this.cellCallback)return this;for(t=n=0,h=this.columns;h>=0?h>n:n>h;t=h>=0?++n:--n)for(o=s=0,u=this.rows;u>=0?u>s:s>u;o=u>=0?++s:--s)i=this.cell.size.clone(),r=this.$add(i.$multiply(t,o)),e=this.layout.length>0&&this.layout[0].length>0?1===this.layout[o][t]:!1,this.cellCallback(i,r,o,t,this.cell.type,e);return this},i.prototype.getCellSize=function(){return this.cell.size.clone()},i.prototype.cellToRectangle=function(t,i,e){var n;return null==e&&(e=!1),e||t>=0&&t=0&&i=0?r>e:e>r;s=r>=0?++e:--e)for(this.layout[s]=[],i=n=0,o=this.columns;o>=0?o>n:n>o;i=o>=0?++n:--n)this.layout[s][i]=0,t&&t(this,s,i);return this},i.prototype.occupy=function(t,i,e,n,s){var r,o,h,u,a,p;if(null==s&&(s=!0),this.rows<=0||this.columns<=0)return this;for(this.layout.length<1&&this.resetLayout(),r=o=0,a=e;a>=0?a>o:o>a;r=a>=0?++o:--o)for(u=h=0,p=n;p>=0?p>h:h>p;u=p>=0?++h:--h)this.layout[Math.min(this.layout.length-1,i+u)][t+r]=s?1:0;return this},i.prototype.canFit=function(t,i,e,n){var s,r,o,h,u,a,p,c,l;for(o=h=a=i,p=Math.min(this.rows,i+n);p>=a?p>h:h>p;o=p>=a?++h:--h)for(r=u=c=t,l=Math.min(this.columns,t+e);l>=c?l>u:u>l;r=l>=c?++u:--u)if(s=this.layout[o][r],null!=s&&s>0)return!1;return!0},i.prototype.fit=function(t,i){var e,n,s,r,o,h,u,a,p,c,l;for(r=Math.min(t,this.columns),h=a=0,c=this.rows;c>=0?c>a:a>c;h=c>=0?++a:--a)for(s=r,u=0,o=p=0,l=this.columns;l>=0?l>p:p>l;o=l>=0?++p:--p)if(n=this.layout[h][o],null!=n&&n>0)u++,s=r;else if(s--,0>=s)return this.occupy(u,h,r,i),e=new Rectangle(this.$add(this.cell.size.$multiply(u,h))),e.resizeTo(this.cell.size.$multiply(r,i)),{row:h,column:u,columnSize:r,rowSize:i,bound:e};return!1},i.prototype.neighbors=function(t,i){var e,n,s,r,o;for(o=[[t-1,i-1],[t,i-1],[t+1,i-1],[t+1,i],[t+1,i+1],[t,i+1],[t-1,i+1],[t-1,i]],r=[],e=0,n=o.length;n>e;e++)s=o[e],r.push(s[0]>=0&&s[0]=0&&s[1]t;t++)e=n[t],s+=e.x+","+e.y+","+e.z+", ";return s+" ]"},i.prototype.toArray=function(){return this.points.slice()},i.prototype.to=function(t){var i,e,n,s;if(arguments.length>0)if(Array.isArray(arguments[0])&&arguments[0].length>0&&"object"==typeof arguments[0][0])for(s=arguments[0],i=0,e=s.length;e>i;i++)n=s[i],this.points.push(new Vector(n));else this.points.push(new Vector(Point.get(arguments)));return this},i.prototype.getAt=function(t){return this.points[Math.min(this.points.length-1,Math.max(0,t))]},i.prototype.$getAt=function(t){return new Vector(this.getAt(t))},i.prototype.setAt=function(t,i){return this.points[t]=i,this},i.prototype.count=function(){return this.points.length},i.prototype.connectFromAnchor=function(t){var i,e,n,s;if(arguments.length>0)if(Array.isArray(arguments[0])&&arguments[0].length>0)for(s=arguments[0],i=0,e=s.length;e>i;i++)n=s[i],this.points.push(this.$add(n));else this.points.push(this.$add(Point.get(arguments)));return this},i.prototype.disconnect=function(t){return null==t&&(t=-1),this.points=0>t?this.points.slice(0,this.points.length+t):this.points.slice(t+1),this},i.prototype.sides=function(t){var i,e,n,s,r,o;for(null==t&&(t=!0),e=null,o=[],r=this.points,i=0,n=r.length;n>i;i++)s=r[i],e&&o.push(new Line(e).to(s)),e=s;return this.points.length>1&&t&&o.push(new Line(e).to(this.points[0])),o},i.prototype.angles=function(t){var i,e,n,s,r,o;for(null==t&&(t=Const.xy),i=[],e=n=1,s=this.points.length-1;s>n;e=n+=1)r=this.points[e-1].$subtract(this.points[e]),o=this.points[e+1].$subtract(this.points[e]),i.push({p0:this.points[e-1],p1:this.points[e],p2:this.points[e+1],angle:r.angleBetween(o)});return i},i.prototype.bounds=function(){return Util.boundingBox(this.points)},i.prototype.centroid=function(){return Util.centroid(this.points)},i.prototype.convexHull=function(t){var i,e,n,s,r;if(null==t&&(t=!0),this.points.length<3)return[];for(t?(r=this.points.slice(),r.sort(function(t,i){return t.x-i.x})):r=this.points,n=function(t,i,e){return(i.x-t.x)*(e.y-t.y)-(e.x-t.x)*(i.y-t.y)>0},i=[],n(r[0],r[1],r[2])?(i.push(r[0]),i.push(r[1])):(i.push(r[1]),i.push(r[0])),i.unshift(r[2]),i.push(r[2]),e=3;e=i;n=i+=1)s=n/t,r.push([s,s*s,s*s*s]);return r},i.prototype.controlPoints=function(t,i){var e,n,s,r,o;return null==t&&(t=0),null==i&&(i=!1),e=function(t){return function(i){var e;return e=i=n;e=n+=1)o.push(this.catmullRomPoint(a[e],i));for(s=0;s=r;e=r+=1)o.push(this.catmullRomPoint(a[e],i));s++}return o},i.prototype.catmullRomPoint=function(t,i){var e,n,s,r,o,h,u,a,p,c;return o=t[0],h=t[1],u=t[2],e=-.5*u+h-.5*o,n=1.5*u-2.5*h+1,s=-1.5*u+2*h+.5*o,r=.5*u-.5*h,a=e*i.p0.x+n*i.p1.x+s*i.p2.x+r*i.p3.x,p=e*i.p0.y+n*i.p1.y+s*i.p2.y+r*i.p3.y,c=this.is3D?e*i.p0.z+n*i.p1.z+s*i.p2.z+r*i.p3.z:0,new Point(a,p,c)},i.prototype.cardinal=function(t,i){var e,n,s,r,o,h,u,a,p;if(null==t&&(t=10),null==i&&(i=.5),this.points.length<2)return[];for(h=[],p=this._getSteps(t),e=this.controlPoints(0,!0),n=s=0,u=t;u>=s;n=s+=1)h.push(this.cardinalPoint(p[n],e,i));for(r=0;r=o;n=o+=1)h.push(this.cardinalPoint(p[n],e,i));r++}return h},i.prototype.cardinalPoint=function(t,i,e){var n,s,r,o,h,u,a,p,c,l,y,f;return null==e&&(e=.5),a=t[0],p=t[1],c=t[2],n=e*(-1*c+2*p-a),s=e*(-1*c+p),r=2*c-3*p+1,o=e*(c-2*p+a),h=-2*c+3*p,u=e*(c-p),l=i.p0.x*n+i.p1.x*s+r*i.p1.x+i.p2.x*o+h*i.p2.x+i.p3.x*u,y=i.p0.y*n+i.p1.y*s+r*i.p1.y+i.p2.y*o+h*i.p2.y+i.p3.y*u,f=this.is3D?i.p0.z*n+i.p1.z*s+r*i.p1.z+i.p2.z*o+h*i.p2.z+i.p3.z*u:0,new Point(l,y,f)},i.prototype.bezier=function(t){var i,e,n,s,r,o,h;if(null==t&&(t=10),this.points.length<4)return[];for(r=[],h=this._getSteps(t),s=0;s<=this.points.length-3;)if(i=this.controlPoints(s)){for(e=n=0,o=t;o>=n;e=n+=1)r.push(this.bezierPoint(h[e],i));s+=3}return r},i.prototype.bezierPoint=function(t,i){var e,n,s,r,o,h,u,a,p,c;return o=t[0],h=t[1],u=t[2],e=-1*u+3*h-3*o+1,n=3*u-6*h+3*o,s=-3*u+3*h,r=u,a=e*i.p0.x+n*i.p1.x+s*i.p2.x+r*i.p3.x,p=e*i.p0.y+n*i.p1.y+s*i.p2.y+r*i.p3.y,c=this.is3D?e*i.p0.z+n*i.p1.z+s*i.p2.z+r*i.p3.z:0,new Point(a,p,c)},i.prototype.bspline=function(t,i){var e,n,s,r,o,h,u,a,p;if(null==t&&(t=10),null==i&&(i=!1),this.points.length<2)return[];for(h=[],p=this._getSteps(t),r=0;r=o;n=o+=1)h.push(this.bsplineTensionPoint(p[n],e,i));else for(n=s=0,u=t;u>=s;n=s+=1)h.push(this.bsplinePoint(p[n],e));r++}return h},i.prototype.bsplinePoint=function(t,i){var e,n,s,r,o,h,u,a,p,c;return o=t[0],h=t[1],u=t[2],e=-.16666666666*u+.5*h-.5*o+.16666666666,n=.5*u-h+.66666666666,s=-.5*u+.5*h+.5*o+.16666666666,r=.16666666666*u,a=e*i.p0.x+n*i.p1.x+s*i.p2.x+r*i.p3.x,p=e*i.p0.y+n*i.p1.y+s*i.p2.y+r*i.p3.y,c=this.is3D?e*i.p0.z+n*i.p1.z+s*i.p2.z+r*i.p3.z:0,new Point(a,p,c)},i.prototype.bsplineTensionPoint=function(t,i,e){var n,s,r,o,h,u,a,p,c,l,y,f;return null==e&&(e=1),a=t[0],p=t[1],c=t[2],n=e*(-.16666666666*c+.5*p-.5*a+.16666666666),s=e*(-1.5*c+2*p-.33333333333),r=2*c-3*p+1,o=e*(1.5*c-2.5*p+.5*a+.16666666666),h=-2*c+3*p,u=.16666666666*e*c,l=n*i.p0.x+s*i.p1.x+r*i.p1.x+o*i.p2.x+h*i.p2.x+u*i.p3.x,y=n*i.p0.y+s*i.p1.y+r*i.p1.y+o*i.p2.y+h*i.p2.y+u*i.p3.y,f=this.is3D?n*i.p0.z+s*i.p1.z+r*i.p1.y+o*i.p2.z+h*i.p2.z+u*i.p3.z:0,new Point(l,y,f)},i}(PointSet),this.Curve=Curve,Triangle=function(t){function i(){i.__super__.constructor.apply(this,arguments),this.p1=new Vector(this.x-1,this.y-1,this.z),this.p2=new Vector(this.x+1,this.y+1,this.z)}return extend(i,t),i.prototype.to=function(t){return arguments.length>0&&("object"==typeof arguments[0]&&2===arguments.length?(this.p1.set(arguments[0]),this.p2.set(arguments[1])):arguments.length<6?(this.p1.set([arguments[0],arguments[1]]),this.p2.set([arguments[2],arguments[3]])):(this.p1.set([arguments[0],arguments[1],arguments[2]]),this.p2.set([arguments[3],arguments[4],arguments[5]]))),this},i.prototype.toArray=function(){return[this,this.p1,this.p2]},i.prototype.toString=function(){return"Triangle ("+this.x+", "+this.y+", "+this.z+"), ("+this.p1.x+", "+this.p1.y+", "+this.p1.z+"), ("+this.p2.x+", "+this.p2.y+", "+this.p2.z+")"},i.prototype.getAt=function(t){return 1===t||"p1"===t?this.p1:2===t||"p2"===t?this.p2:this},i.prototype.$getAt=function(t){return new Vector(this.getAt(t))},i.prototype.toPointSet=function(){var t;return t=new Vector(this),new PointSet(t).to([t,this.p1,this.p2])},i.prototype.sides=function(){return[new Line(this).to(this.p1),new Line(this.p1).to(this.p2),new Line(this.p2).to(this)]},i.prototype.angles=function(t){var i;return null==t&&(t=Const.xy),i=[this.p2.$subtract(this).angleBetween(this.p1.$subtract(this),t),this.$subtract(this.p1).angleBetween(this.p2.$subtract(this.p1),t)],i.push(Math.PI-i[0]-i[1]),i},i.prototype.medial=function(){var t,e,n;return n=this.sides(),t=function(){var t,i,s;for(s=[],t=0,i=n.length;i>t;t++)e=n[t],s.push(e.midpoint());return s}(),new i(t[0]).to(t[1],t[2])},i.prototype.perimeter=function(){var t,i;return i=this.sides(),t=[i[0].length(),i[1].length(),i[2].length()],{sides:i,value:t[0]+t[1]+t[2],lengths:t}},i.prototype.area=function(){var t,i;return i=this.perimeter(),t=i.value/2,{value:Math.sqrt(t*(t-i.lengths[0])*(t-i.lengths[1])*(t-i.lengths[2])),perimeter:i}},i.prototype.oppositeSide=function(t){return"p1"===t?new Line(this).to(this.p2):"p2"===t?new Line(this).to(this.p1):new Line(this.p1).to(this.p2)},i.prototype.adjacentSides=function(t){return"p1"===t?[new Line(this.p1).to(this),new Line(this.p1).to(this.p2)]:"p2"===t?[new Line(this.p2).to(this),new Line(this.p2).to(this.p1)]:[new Line(this).to(this.p1),new Line(this).to(this.p2)]},i.prototype.bisector=function(t,i,e){var n,s,r;return null==i&&(i=!1),null==e&&(e=100),n=this.adjacentSides(t),r=new Vector(n[0]),n[0].moveTo(0,0),n[1].moveTo(0,0),s=n[0].p1.bisect(n[1].p1),i?new Line(r).to(s.multiply(e).add(r)):s},i.prototype.altitude=function(t){return"p1"===t||"p2"===t?new Line(this[t]).to(this.oppositeSide(t).getPerpendicularFromPoint(this[t])):new Line(this).to(this.oppositeSide().getPerpendicularFromPoint(this))},i.prototype.centroid=function(){var t,i,e;return t=this.$divide(3),i=this.p1.$divide(3),e=this.p2.$divide(3),new Vector(t.x+i.x+e.x,t.y+i.y+e.y,t.z+i.z+e.z)},i.prototype.orthocenter=function(){var t,i;return t=this.altitude(),i=this.altitude("p1"),t.intersectPath(i,Const.xyz)},i.prototype.incenter=function(){var t,i;return t=this.bisector("p0",!0),i=this.bisector("p1",!0),t.intersectPath(i,Const.xyz)},i.prototype.incircle=function(){var t,i,e;return i=this.incenter(),t=this.area(),e=2*t.value/t.perimeter.value,new Circle(i).setRadius(e)},i.prototype.circumcenter=function(){var t,i;return t=this.medial(),i=[new Line(t).to(this.$subtract(t).perpendicular()[0].$add(t)),new Line(t.p1).to(this.p1.$subtract(t.p1).perpendicular()[0].$add(t.p1)),new Line(t.p2).to(this.p2.$subtract(t.p2).perpendicular()[0].$add(t.p2))],{center:i[0].intersectPath(i[1],Const.xyz),bisectors:i}},i.prototype.circumcircle=function(){var t,i;return t=this.circumcenter(),i=this.magnitude(t.center),new Circle(t.center).setRadius(i)},i.prototype.intersectPoint=function(t){var i,e,n;return n=this.sides(),i=function(){var i,s,r;for(r=[],i=0,s=n.length;s>i;i++)e=n[i],r.push(e.collinear(t)>0);return r}(),i[0]===i[1]&&i[1]===i[2]},i.prototype.intersectPath=function(t,i,e){var n,s,r,o,h,u;for(null==i&&(i=!0),null==e&&(e=Const.xy),u=this.sides(),o=[],n=0,s=u.length;s>n;n++)if(h=u[n],r=h.intersectPath(t),r&&h.withinBounds(r,e)){if(!i)return!0;o.push(r)}return i?o:!1},i.prototype.intersectLine=function(t,i,e){var n,s,r,o,h;for(null==i&&(i=!0),null==e&&(e=Const.xy),n=this.intersectPath(t,!0,e),h=[],s=0,r=n.length;r>s;s++)if(o=n[s],t.withinBounds(o)){if(!i)return!0;h.push(o)}return i?h:!1},i.prototype.intersectLines=function(t,i){return null==i&&(i=!0),Line.intersectLines(this,t,i)},i.prototype.intersectPath3D=function(t,i){var e,n,s,r,o,h,u,a,p,c,l;return s=this.p1.$subtract(this),r=this.p2.$subtract(this),n=t.direction().normalize(),h=n.cross(r),e=s.dot(h),e>-Const.epsilon&&ec||c>1?!1:(u=p.cross(s),l=n.dot(u)*o,0>l||l>1?!1:(a=r.dot(u)*o,a>Const.epsilon?i?[c,l,a]:!0:!1)))},i.prototype.intersectRectangle=function(t,i){
3 | return null==i&&(i=!0),t.intersectLines(this.sides(),i)},i.prototype.intersectCircle=function(t,i){return null==i&&(i=!0),t.intersectLines(this.sides(),i)},i.prototype.intersectTriangle=function(t,i){return null==i&&(i=!0),t.intersectLines(this.sides(),i)},i.prototype.clone=function(){return new i(this).to(this.p1,this.p2)},i}(Vector),this.Triangle=Triangle;
--------------------------------------------------------------------------------
/demo/js/sushi.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var stuff =[
4 | {name: "salmon1", w: 360, h: 245},
5 | {name: "salmon2", w: 362, h: 432},
6 | {name: "rice1", w: 317, h: 358},
7 | {name: "rice2", w: 318, h: 200},
8 | {name: "wasabi1", w: 88, h: 101},
9 | //{name: "wasabi2", w: 108, h: 55},
10 | //{name: "wasabi3", w: 108, h: 90},
11 | //{name: "negitoro", w: 418, h: 438},
12 | {name: "ebi1", w: 322, h: 729},
13 | {name: "ikura1", w: 382, h: 400}
14 | ];
15 |
16 |
17 | function getIngredients() {
18 | var ings = [];
19 | for (var i=0; i<6; i++) {
20 | var dice = Math.floor(Math.random()*stuff.length);
21 | ings.push( stuff[dice] );
22 | }
23 | return ings;
24 | }
25 |
26 |
27 | function _vendor( elem, prop, val ) {
28 | var vs = ["webkit", "Webkit", "Moz", "ms"];
29 | for (var i=0; i 0) {
66 | var last = this.steps[this.steps.length - 1];
67 | d = last.p2 + last.pad;
68 | }
69 |
70 | // append new steps
71 | for (var i = 0; i < s.length; i++) {
72 | s[i].p1 = d;
73 | s[i].p2 = s[i].p1 + s[i].size;
74 | d = s[i].p2 + s[i].pad;
75 | this.steps.push(s[i]);
76 | }
77 |
78 | // recalculate pane size
79 | this.getHeight(true);
80 |
81 | return this;
82 | }
83 |
84 | /**
85 | * Get step by index
86 | * @param index
87 | */
88 | }, {
89 | key: "getStepAt",
90 | value: function getStepAt(index) {
91 | return this.steps[Math.max(0, Math.min(this.steps.length - 1, index))];
92 | }
93 |
94 | /**
95 | * Calculate and return current step. When padding > 0, step will be -1 when current progress is on the padding area. This allows you to check progress against padding.
96 | * @returns {number}
97 | */
98 | }, {
99 | key: "getStep",
100 | value: function getStep() {
101 | for (var i = 0; i < this.steps.length; i++) {
102 | var st = this.steps[i];
103 | if (st.p1 >= -this.viewportSize && st.p2 <= st.size) {
104 | this.current = i;
105 | return i;
106 | }
107 | }
108 | return -1;
109 | }
110 |
111 | /**
112 | * Get current progress within the current step
113 | * @returns 0-1 if step.pad is 0. Otherwise it will range from negative to positive.
114 | */
115 | }, {
116 | key: "getStepProgress",
117 | value: function getStepProgress() {
118 | var curr = this.steps[this.current];
119 | return 1 - curr.p2 / curr.size;
120 | }
121 |
122 | /**
123 | * Get current position
124 | * @returns {number|*}
125 | */
126 | }, {
127 | key: "getPosition",
128 | value: function getPosition() {
129 | return this.pos;
130 | }
131 |
132 | /**
133 | * Get total height of the pane (including padding)
134 | * @returns {*}
135 | */
136 | }, {
137 | key: "getHeight",
138 | value: function getHeight() {
139 | var recalc = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
140 |
141 | if (recalc) this.paneSize = this.steps.reduce(function (a, b) {
142 | return a + b.size + b.pad;
143 | }, 0);
144 | return this.paneSize;
145 | }
146 |
147 | /**
148 | * Get viewport's height (same as this.viewportSize)
149 | * @returns {*}
150 | */
151 | }, {
152 | key: "getViewportHeight",
153 | value: function getViewportHeight() {
154 | return this.viewportSize;
155 | }
156 |
157 | /**
158 | * Move the roll. This will emit two events `roll(step, currProgress, currPosition, totalProgress)` and `step(curr, last)`
159 | * @param pos new position
160 | * @returns {Roll}
161 | */
162 | }, {
163 | key: "move",
164 | value: function move(pos) {
165 | var last = this.pos;
166 | this.pos = -pos;
167 | var diff = this.pos - last;
168 |
169 | for (var i = 0; i < this.steps.length; i++) {
170 | var s = this.steps[i];
171 | s.p1 += diff;
172 | s.p2 = s.p1 + s.size;
173 | }
174 |
175 | var curr = this.getStep();
176 | var progress = this.getStepProgress();
177 | this.emit("roll", curr, progress, pos, pos / (this.paneSize - this.viewportSize));
178 |
179 | if (curr != this.last && curr >= 0) {
180 | this.emit("step", curr, this.last, this.viewportSize);
181 | this.last = curr;
182 | }
183 |
184 | return this;
185 | }
186 |
187 | /**
188 | * Animated scrolling a DOM element
189 | * @param index step index
190 | * @param scrollPane a DOM element with scrolling (overflow-y).
191 | * @param speed optional speed of animated scroll. Defaults to 0.1. Larger is faster
192 | * @param isVertical optional boolean to indicate horizontal or vertical scroll
193 | */
194 | }, {
195 | key: "scroll",
196 | value: function scroll(index, scrollPane) {
197 | var _this = this;
198 |
199 | var speed = arguments.length <= 2 || arguments[2] === undefined ? 0.1 : arguments[2];
200 | var isVertical = arguments.length <= 3 || arguments[3] === undefined ? true : arguments[3];
201 |
202 | if (!scrollPane || scrollPane.scrollTop == null) throw "scrollPane parameter requires a DOM element with scrollTop property";
203 | clearInterval(this.movingInterval);
204 | var _temp = Number.NEGATIVE_INFINITY;
205 | var dir = isVertical ? "scrollTop" : "scrollLeft";
206 |
207 | this.movingInterval = setInterval(function () {
208 | var target = _this.getStepAt(index);
209 | var d = (target.p1 + target.size / 4) * speed;
210 | scrollPane[dir] += d;
211 | if (Math.abs(d) < 1 || _temp === scrollPane[dir]) clearInterval(_this.movingInterval);
212 | _temp = scrollPane[dir];
213 | }, 17);
214 | }
215 |
216 | /**
217 | * A convenient static function to create a step object
218 | * @param size chunk size
219 | * @param pad optional padding (default to 0)
220 | * @returns {{p1: number, p2: *, size: *, pad: number}}
221 | */
222 | }], [{
223 | key: "chunk",
224 | value: function chunk(size) {
225 | var pad = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1];
226 |
227 | return {
228 | p1: 0,
229 | p2: size,
230 | size: size,
231 | pad: pad
232 | };
233 | }
234 |
235 | /**
236 | * A convenient static function to compare a step with current step, and transform it to a name
237 | * @param step the step to check
238 | * @param currStep current step
239 | * @param prev optional class name for step is < currStep. Defaults to "prev"
240 | * @param next optional class name for step is > currStep. Defaults to "next"
241 | * @param match optional class name for step = currStep. Defaults to "curr"
242 | * @returns {string}
243 | */
244 | }, {
245 | key: "stepName",
246 | value: function stepName(step, currStep) {
247 | var prev = arguments.length <= 2 || arguments[2] === undefined ? "prev" : arguments[2];
248 | var next = arguments.length <= 3 || arguments[3] === undefined ? "next" : arguments[3];
249 | var match = arguments.length <= 4 || arguments[4] === undefined ? "curr" : arguments[4];
250 |
251 | return step === currStep ? match : step < currStep ? prev : next;
252 | }
253 |
254 | /**
255 | * Static helper to get a handle function for Roll's "step" event. The handler function will add class names to each step element based on current step value.
256 | * @param roll a Roll instance
257 | * @param views a list of DOM elements which are the steps
258 | * @param prev optional class name for step is < currStep. Defaults to "prev"
259 | * @param next optional class name for step is > currStep. Defaults to "next"
260 | * @param match optional class name for step = currStep. Defaults to "curr"
261 | * @returns {Function}
262 | */
263 | }, {
264 | key: "stepHandler",
265 | value: function stepHandler(roll, views) {
266 | var prev = arguments.length <= 2 || arguments[2] === undefined ? "prev" : arguments[2];
267 | var next = arguments.length <= 3 || arguments[3] === undefined ? "next" : arguments[3];
268 | var match = arguments.length <= 4 || arguments[4] === undefined ? "curr" : arguments[4];
269 | var trackTopPos = arguments.length <= 5 || arguments[5] === undefined ? false : arguments[5];
270 |
271 | return function (curr, last, viewportHeight) {
272 | for (var i = 0; i < roll.steps.length; i++) {
273 | var cls = Roll.stepName(i, curr, prev, next, match);
274 | views[i].className = "step " + cls;
275 |
276 | // if steps have different sizes, recalc top position and set style
277 | if (trackTopPos) {
278 | var p = cls === prev ? roll.steps[i].size * -1 : cls === next ? viewportHeight : 0;
279 | views[i].style.top = p + "px";
280 | }
281 | }
282 | };
283 | }
284 |
285 | /**
286 | * Static method to create a Roll instance with DOM elements
287 | * @param viewPortID id of viewport element, which is the parent of the viewPane. eg, "#viewport"
288 | * @param viewPaneID id of view pane element, eg, "#pane"
289 | * @param viewBox id of view box element, which is the parent the viewClass elements. eg, "#steps"
290 | * @param viewClass id of each step or slide element, eg, ".step"
291 | * @param pad optional padding between steps. Defaults to 0.
292 | * @returns the roll instance which you can listen for "step" and "roll" event via `roll.on(...)`
293 | */
294 | }, {
295 | key: "DOM",
296 | value: function DOM(viewPortID, viewPaneID, viewBoxID, viewClass) {
297 | var pad = arguments.length <= 4 || arguments[4] === undefined ? 0 : arguments[4];
298 |
299 | var viewport = document.querySelector(viewPortID);
300 | var viewpane = viewport.querySelector(viewPaneID);
301 | var viewbox = document.querySelector(viewBoxID);
302 | var views = viewbox.querySelectorAll(viewClass);
303 |
304 | if (!viewport || !viewpane) throw "Cannot find " + viewPortID + " or " + viewPaneID + " element id.";
305 | if (!viewClass) throw "Cannot find " + viewClass + " element class name";
306 |
307 | // create roll instance based on viewport element height
308 | var roll = new Roll(viewport.getBoundingClientRect().height);
309 |
310 | // add each viewClass element as a step
311 | for (var i = 0; i < views.length; i++) {
312 | var rect = views[i].getBoundingClientRect();
313 | roll.addStep(Roll.chunk(rect.height, pad));
314 | }
315 |
316 | // update viewpane height based on steps
317 | viewpane.style.height = roll.getHeight() + "px";
318 |
319 | // update viewbox width to account for scrollbar
320 | viewbox.style.width = viewpane.getBoundingClientRect().width + "px";
321 |
322 | // track scroll
323 | viewport.addEventListener("scroll", function (evt) {
324 | roll.move(viewport.scrollTop);
325 | });
326 |
327 | return roll;
328 | }
329 | }]);
330 |
331 | return Roll;
332 | })(EventEmitter);
333 |
334 | exports["default"] = Roll;
335 |
336 | if (window) window.Roll = Roll;
337 | module.exports = exports["default"];
--------------------------------------------------------------------------------
/dist/roll.js:
--------------------------------------------------------------------------------
1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0 && this._events[type].length > m) {
142 | this._events[type].warned = true;
143 | console.error('(node) warning: possible EventEmitter memory ' +
144 | 'leak detected. %d listeners added. ' +
145 | 'Use emitter.setMaxListeners() to increase limit.',
146 | this._events[type].length);
147 | if (typeof console.trace === 'function') {
148 | // not supported in IE 10
149 | console.trace();
150 | }
151 | }
152 | }
153 |
154 | return this;
155 | };
156 |
157 | EventEmitter.prototype.on = EventEmitter.prototype.addListener;
158 |
159 | EventEmitter.prototype.once = function(type, listener) {
160 | if (!isFunction(listener))
161 | throw TypeError('listener must be a function');
162 |
163 | var fired = false;
164 |
165 | function g() {
166 | this.removeListener(type, g);
167 |
168 | if (!fired) {
169 | fired = true;
170 | listener.apply(this, arguments);
171 | }
172 | }
173 |
174 | g.listener = listener;
175 | this.on(type, g);
176 |
177 | return this;
178 | };
179 |
180 | // emits a 'removeListener' event iff the listener was removed
181 | EventEmitter.prototype.removeListener = function(type, listener) {
182 | var list, position, length, i;
183 |
184 | if (!isFunction(listener))
185 | throw TypeError('listener must be a function');
186 |
187 | if (!this._events || !this._events[type])
188 | return this;
189 |
190 | list = this._events[type];
191 | length = list.length;
192 | position = -1;
193 |
194 | if (list === listener ||
195 | (isFunction(list.listener) && list.listener === listener)) {
196 | delete this._events[type];
197 | if (this._events.removeListener)
198 | this.emit('removeListener', type, listener);
199 |
200 | } else if (isObject(list)) {
201 | for (i = length; i-- > 0;) {
202 | if (list[i] === listener ||
203 | (list[i].listener && list[i].listener === listener)) {
204 | position = i;
205 | break;
206 | }
207 | }
208 |
209 | if (position < 0)
210 | return this;
211 |
212 | if (list.length === 1) {
213 | list.length = 0;
214 | delete this._events[type];
215 | } else {
216 | list.splice(position, 1);
217 | }
218 |
219 | if (this._events.removeListener)
220 | this.emit('removeListener', type, listener);
221 | }
222 |
223 | return this;
224 | };
225 |
226 | EventEmitter.prototype.removeAllListeners = function(type) {
227 | var key, listeners;
228 |
229 | if (!this._events)
230 | return this;
231 |
232 | // not listening for removeListener, no need to emit
233 | if (!this._events.removeListener) {
234 | if (arguments.length === 0)
235 | this._events = {};
236 | else if (this._events[type])
237 | delete this._events[type];
238 | return this;
239 | }
240 |
241 | // emit removeListener for all listeners on all events
242 | if (arguments.length === 0) {
243 | for (key in this._events) {
244 | if (key === 'removeListener') continue;
245 | this.removeAllListeners(key);
246 | }
247 | this.removeAllListeners('removeListener');
248 | this._events = {};
249 | return this;
250 | }
251 |
252 | listeners = this._events[type];
253 |
254 | if (isFunction(listeners)) {
255 | this.removeListener(type, listeners);
256 | } else {
257 | // LIFO order
258 | while (listeners.length)
259 | this.removeListener(type, listeners[listeners.length - 1]);
260 | }
261 | delete this._events[type];
262 |
263 | return this;
264 | };
265 |
266 | EventEmitter.prototype.listeners = function(type) {
267 | var ret;
268 | if (!this._events || !this._events[type])
269 | ret = [];
270 | else if (isFunction(this._events[type]))
271 | ret = [this._events[type]];
272 | else
273 | ret = this._events[type].slice();
274 | return ret;
275 | };
276 |
277 | EventEmitter.listenerCount = function(emitter, type) {
278 | var ret;
279 | if (!emitter._events || !emitter._events[type])
280 | ret = 0;
281 | else if (isFunction(emitter._events[type]))
282 | ret = 1;
283 | else
284 | ret = emitter._events[type].length;
285 | return ret;
286 | };
287 |
288 | function isFunction(arg) {
289 | return typeof arg === 'function';
290 | }
291 |
292 | function isNumber(arg) {
293 | return typeof arg === 'number';
294 | }
295 |
296 | function isObject(arg) {
297 | return typeof arg === 'object' && arg !== null;
298 | }
299 |
300 | function isUndefined(arg) {
301 | return arg === void 0;
302 | }
303 |
304 | },{}],2:[function(require,module,exports){
305 | "use strict";
306 |
307 | Object.defineProperty(exports, "__esModule", {
308 | value: true
309 | });
310 |
311 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
312 |
313 | var _get = function get(_x13, _x14, _x15) { var _again = true; _function: while (_again) { var object = _x13, property = _x14, receiver = _x15; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x13 = parent; _x14 = property; _x15 = receiver; _again = true; continue _function; } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
314 |
315 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
316 |
317 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
318 |
319 | var EventEmitter = require('events').EventEmitter;
320 |
321 | /**
322 | * Roll simply keep tracks of steps' positions inside a viewport.
323 | * Apart from the static helper functions and the `scroll` function, a roll instance doesn't depend on DOM manipulation.
324 | * That means you can use a Roll instance in contexts other than DOM.
325 | */
326 |
327 | var Roll = (function (_EventEmitter) {
328 | _inherits(Roll, _EventEmitter);
329 |
330 | /**
331 | * Create a new Roll.
332 | * @param viewSize viewport size (single dimension)
333 | */
334 |
335 | function Roll(viewSize) {
336 | _classCallCheck(this, Roll);
337 |
338 | _get(Object.getPrototypeOf(Roll.prototype), "constructor", this).call(this);
339 |
340 | this.viewportSize = viewSize;
341 | this.paneSize = 0;
342 |
343 | // store the steps object {y1, y2, size, pad}, See Roll.chunk
344 | this.steps = [];
345 |
346 | this.pos = 0; // current position
347 | this.current = 0; // current step
348 | this.last = -1; // last step
349 |
350 | this.movingInterval = -1;
351 | }
352 |
353 | /**
354 | * Add a step object. You can also use Roll.chunk() static helper function to create a step object easily.
355 | * @param s an object with {p1, p2, size, pad} properties, or an array of steps object
356 | * @returns {Roll}
357 | */
358 |
359 | _createClass(Roll, [{
360 | key: "addStep",
361 | value: function addStep(s) {
362 |
363 | if (!Array.isArray(s)) {
364 | s = [s];
365 | }
366 |
367 | // get last recorded step
368 | var d = s[0].p1;
369 | if (this.steps.length > 0) {
370 | var last = this.steps[this.steps.length - 1];
371 | d = last.p2 + last.pad;
372 | }
373 |
374 | // append new steps
375 | for (var i = 0; i < s.length; i++) {
376 | s[i].p1 = d;
377 | s[i].p2 = s[i].p1 + s[i].size;
378 | d = s[i].p2 + s[i].pad;
379 | this.steps.push(s[i]);
380 | }
381 |
382 | // recalculate pane size
383 | this.getHeight(true);
384 |
385 | return this;
386 | }
387 |
388 | /**
389 | * Get step by index
390 | * @param index
391 | */
392 | }, {
393 | key: "getStepAt",
394 | value: function getStepAt(index) {
395 | return this.steps[Math.max(0, Math.min(this.steps.length - 1, index))];
396 | }
397 |
398 | /**
399 | * Calculate and return current step. When padding > 0, step will be -1 when current progress is on the padding area. This allows you to check progress against padding.
400 | * @returns {number}
401 | */
402 | }, {
403 | key: "getStep",
404 | value: function getStep() {
405 | for (var i = 0; i < this.steps.length; i++) {
406 | var st = this.steps[i];
407 | if (st.p1 >= -this.viewportSize && st.p2 <= st.size) {
408 | this.current = i;
409 | return i;
410 | }
411 | }
412 | return -1;
413 | }
414 |
415 | /**
416 | * Get current progress within the current step
417 | * @returns 0-1 if step.pad is 0. Otherwise it will range from negative to positive.
418 | */
419 | }, {
420 | key: "getStepProgress",
421 | value: function getStepProgress() {
422 | var curr = this.steps[this.current];
423 | return 1 - curr.p2 / curr.size;
424 | }
425 |
426 | /**
427 | * Get current position
428 | * @returns {number|*}
429 | */
430 | }, {
431 | key: "getPosition",
432 | value: function getPosition() {
433 | return this.pos;
434 | }
435 |
436 | /**
437 | * Get total height of the pane (including padding)
438 | * @returns {*}
439 | */
440 | }, {
441 | key: "getHeight",
442 | value: function getHeight() {
443 | var recalc = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
444 |
445 | if (recalc) this.paneSize = this.steps.reduce(function (a, b) {
446 | return a + b.size + b.pad;
447 | }, 0);
448 | return this.paneSize;
449 | }
450 |
451 | /**
452 | * Get viewport's height (same as this.viewportSize)
453 | * @returns {*}
454 | */
455 | }, {
456 | key: "getViewportHeight",
457 | value: function getViewportHeight() {
458 | return this.viewportSize;
459 | }
460 |
461 | /**
462 | * Move the roll. This will emit two events `roll(step, currProgress, currPosition, totalProgress)` and `step(curr, last)`
463 | * @param pos new position
464 | * @returns {Roll}
465 | */
466 | }, {
467 | key: "move",
468 | value: function move(pos) {
469 | var last = this.pos;
470 | this.pos = -pos;
471 | var diff = this.pos - last;
472 |
473 | for (var i = 0; i < this.steps.length; i++) {
474 | var s = this.steps[i];
475 | s.p1 += diff;
476 | s.p2 = s.p1 + s.size;
477 | }
478 |
479 | var curr = this.getStep();
480 | var progress = this.getStepProgress();
481 | this.emit("roll", curr, progress, pos, pos / (this.paneSize - this.viewportSize));
482 |
483 | if (curr != this.last && curr >= 0) {
484 | this.emit("step", curr, this.last, this.viewportSize);
485 | this.last = curr;
486 | }
487 |
488 | return this;
489 | }
490 |
491 | /**
492 | * Animated scrolling a DOM element
493 | * @param index step index
494 | * @param scrollPane a DOM element with scrolling (overflow-y).
495 | * @param speed optional speed of animated scroll. Defaults to 0.1. Larger is faster
496 | * @param isVertical optional boolean to indicate horizontal or vertical scroll
497 | */
498 | }, {
499 | key: "scroll",
500 | value: function scroll(index, scrollPane) {
501 | var _this = this;
502 |
503 | var speed = arguments.length <= 2 || arguments[2] === undefined ? 0.1 : arguments[2];
504 | var isVertical = arguments.length <= 3 || arguments[3] === undefined ? true : arguments[3];
505 |
506 | if (!scrollPane || scrollPane.scrollTop == null) throw "scrollPane parameter requires a DOM element with scrollTop property";
507 | clearInterval(this.movingInterval);
508 | var _temp = Number.NEGATIVE_INFINITY;
509 | var dir = isVertical ? "scrollTop" : "scrollLeft";
510 |
511 | this.movingInterval = setInterval(function () {
512 | var target = _this.getStepAt(index);
513 | var d = (target.p1 + target.size / 4) * speed;
514 | scrollPane[dir] += d;
515 | if (Math.abs(d) < 1 || _temp === scrollPane[dir]) clearInterval(_this.movingInterval);
516 | _temp = scrollPane[dir];
517 | }, 17);
518 | }
519 |
520 | /**
521 | * A convenient static function to create a step object
522 | * @param size chunk size
523 | * @param pad optional padding (default to 0)
524 | * @returns {{p1: number, p2: *, size: *, pad: number}}
525 | */
526 | }], [{
527 | key: "chunk",
528 | value: function chunk(size) {
529 | var pad = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1];
530 |
531 | return {
532 | p1: 0,
533 | p2: size,
534 | size: size,
535 | pad: pad
536 | };
537 | }
538 |
539 | /**
540 | * A convenient static function to compare a step with current step, and transform it to a name
541 | * @param step the step to check
542 | * @param currStep current step
543 | * @param prev optional class name for step is < currStep. Defaults to "prev"
544 | * @param next optional class name for step is > currStep. Defaults to "next"
545 | * @param match optional class name for step = currStep. Defaults to "curr"
546 | * @returns {string}
547 | */
548 | }, {
549 | key: "stepName",
550 | value: function stepName(step, currStep) {
551 | var prev = arguments.length <= 2 || arguments[2] === undefined ? "prev" : arguments[2];
552 | var next = arguments.length <= 3 || arguments[3] === undefined ? "next" : arguments[3];
553 | var match = arguments.length <= 4 || arguments[4] === undefined ? "curr" : arguments[4];
554 |
555 | return step === currStep ? match : step < currStep ? prev : next;
556 | }
557 |
558 | /**
559 | * Static helper to get a handle function for Roll's "step" event. The handler function will add class names to each step element based on current step value.
560 | * @param roll a Roll instance
561 | * @param views a list of DOM elements which are the steps
562 | * @param prev optional class name for step is < currStep. Defaults to "prev"
563 | * @param next optional class name for step is > currStep. Defaults to "next"
564 | * @param match optional class name for step = currStep. Defaults to "curr"
565 | * @returns {Function}
566 | */
567 | }, {
568 | key: "stepHandler",
569 | value: function stepHandler(roll, views) {
570 | var prev = arguments.length <= 2 || arguments[2] === undefined ? "prev" : arguments[2];
571 | var next = arguments.length <= 3 || arguments[3] === undefined ? "next" : arguments[3];
572 | var match = arguments.length <= 4 || arguments[4] === undefined ? "curr" : arguments[4];
573 | var trackTopPos = arguments.length <= 5 || arguments[5] === undefined ? false : arguments[5];
574 |
575 | return function (curr, last, viewportHeight) {
576 | for (var i = 0; i < roll.steps.length; i++) {
577 | var cls = Roll.stepName(i, curr, prev, next, match);
578 | views[i].className = "step " + cls;
579 |
580 | // if steps have different sizes, recalc top position and set style
581 | if (trackTopPos) {
582 | var p = cls === prev ? roll.steps[i].size * -1 : cls === next ? viewportHeight : 0;
583 | views[i].style.top = p + "px";
584 | }
585 | }
586 | };
587 | }
588 |
589 | /**
590 | * Static method to create a Roll instance with DOM elements
591 | * @param viewPortID id of viewport element, which is the parent of the viewPane. eg, "#viewport"
592 | * @param viewPaneID id of view pane element, eg, "#pane"
593 | * @param viewBox id of view box element, which is the parent the viewClass elements. eg, "#steps"
594 | * @param viewClass id of each step or slide element, eg, ".step"
595 | * @param pad optional padding between steps. Defaults to 0.
596 | * @returns the roll instance which you can listen for "step" and "roll" event via `roll.on(...)`
597 | */
598 | }, {
599 | key: "DOM",
600 | value: function DOM(viewPortID, viewPaneID, viewBoxID, viewClass) {
601 | var pad = arguments.length <= 4 || arguments[4] === undefined ? 0 : arguments[4];
602 |
603 | var viewport = document.querySelector(viewPortID);
604 | var viewpane = viewport.querySelector(viewPaneID);
605 | var viewbox = document.querySelector(viewBoxID);
606 | var views = viewbox.querySelectorAll(viewClass);
607 |
608 | if (!viewport || !viewpane) throw "Cannot find " + viewPortID + " or " + viewPaneID + " element id.";
609 | if (!viewClass) throw "Cannot find " + viewClass + " element class name";
610 |
611 | // create roll instance based on viewport element height
612 | var roll = new Roll(viewport.getBoundingClientRect().height);
613 |
614 | // add each viewClass element as a step
615 | for (var i = 0; i < views.length; i++) {
616 | var rect = views[i].getBoundingClientRect();
617 | roll.addStep(Roll.chunk(rect.height, pad));
618 | }
619 |
620 | // update viewpane height based on steps
621 | viewpane.style.height = roll.getHeight() + "px";
622 |
623 | // update viewbox width to account for scrollbar
624 | viewbox.style.width = viewpane.getBoundingClientRect().width + "px";
625 |
626 | // track scroll
627 | viewport.addEventListener("scroll", function (evt) {
628 | roll.move(viewport.scrollTop);
629 | });
630 |
631 | return roll;
632 | }
633 | }]);
634 |
635 | return Roll;
636 | })(EventEmitter);
637 |
638 | exports["default"] = Roll;
639 | module.exports = exports["default"];
640 |
641 | },{"events":1}],3:[function(require,module,exports){
642 | "use strict";
643 |
644 | var Roll = require("./roll.js");
645 |
646 | if (window) window.Roll = Roll;
647 |
648 | },{"./roll.js":2}]},{},[3])
649 |
650 |
651 | //# sourceMappingURL=roll.js.map
652 |
--------------------------------------------------------------------------------
/dist/roll.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["node_modules/browserify/node_modules/browser-pack/_prelude.js","node_modules/browserify/node_modules/events/events.js","src/roll.js","src/roll_standalone.js"],"names":[],"mappings":"AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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","file":"roll.js","sourceRoot":"/source/","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o 0 && this._events[type].length > m) {\n this._events[type].warned = true;\n console.error('(node) warning: possible EventEmitter memory ' +\n 'leak detected. %d listeners added. ' +\n 'Use emitter.setMaxListeners() to increase limit.',\n this._events[type].length);\n if (typeof console.trace === 'function') {\n // not supported in IE 10\n console.trace();\n }\n }\n }\n\n return this;\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.once = function(type, listener) {\n if (!isFunction(listener))\n throw TypeError('listener must be a function');\n\n var fired = false;\n\n function g() {\n this.removeListener(type, g);\n\n if (!fired) {\n fired = true;\n listener.apply(this, arguments);\n }\n }\n\n g.listener = listener;\n this.on(type, g);\n\n return this;\n};\n\n// emits a 'removeListener' event iff the listener was removed\nEventEmitter.prototype.removeListener = function(type, listener) {\n var list, position, length, i;\n\n if (!isFunction(listener))\n throw TypeError('listener must be a function');\n\n if (!this._events || !this._events[type])\n return this;\n\n list = this._events[type];\n length = list.length;\n position = -1;\n\n if (list === listener ||\n (isFunction(list.listener) && list.listener === listener)) {\n delete this._events[type];\n if (this._events.removeListener)\n this.emit('removeListener', type, listener);\n\n } else if (isObject(list)) {\n for (i = length; i-- > 0;) {\n if (list[i] === listener ||\n (list[i].listener && list[i].listener === listener)) {\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (list.length === 1) {\n list.length = 0;\n delete this._events[type];\n } else {\n list.splice(position, 1);\n }\n\n if (this._events.removeListener)\n this.emit('removeListener', type, listener);\n }\n\n return this;\n};\n\nEventEmitter.prototype.removeAllListeners = function(type) {\n var key, listeners;\n\n if (!this._events)\n return this;\n\n // not listening for removeListener, no need to emit\n if (!this._events.removeListener) {\n if (arguments.length === 0)\n this._events = {};\n else if (this._events[type])\n delete this._events[type];\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n for (key in this._events) {\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = {};\n return this;\n }\n\n listeners = this._events[type];\n\n if (isFunction(listeners)) {\n this.removeListener(type, listeners);\n } else {\n // LIFO order\n while (listeners.length)\n this.removeListener(type, listeners[listeners.length - 1]);\n }\n delete this._events[type];\n\n return this;\n};\n\nEventEmitter.prototype.listeners = function(type) {\n var ret;\n if (!this._events || !this._events[type])\n ret = [];\n else if (isFunction(this._events[type]))\n ret = [this._events[type]];\n else\n ret = this._events[type].slice();\n return ret;\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n var ret;\n if (!emitter._events || !emitter._events[type])\n ret = 0;\n else if (isFunction(emitter._events[type]))\n ret = 1;\n else\n ret = emitter._events[type].length;\n return ret;\n};\n\nfunction isFunction(arg) {\n return typeof arg === 'function';\n}\n\nfunction isNumber(arg) {\n return typeof arg === 'number';\n}\n\nfunction isObject(arg) {\n return typeof arg === 'object' && arg !== null;\n}\n\nfunction isUndefined(arg) {\n return arg === void 0;\n}\n","var EventEmitter = require('events').EventEmitter;\r\n\r\n/**\r\n * Roll simply keep tracks of steps' positions inside a viewport.\r\n * Apart from the static helper functions and the `scroll` function, a roll instance doesn't depend on DOM manipulation.\r\n * That means you can use a Roll instance in contexts other than DOM.\r\n */\r\nexport default class Roll extends EventEmitter {\r\n\r\n /**\r\n * Create a new Roll.\r\n * @param viewSize viewport size (single dimension)\r\n */\r\n constructor( viewSize ) {\r\n super();\r\n\r\n this.viewportSize = viewSize;\r\n this.paneSize = 0;\r\n\r\n // store the steps object {y1, y2, size, pad}, See Roll.chunk\r\n this.steps = [];\r\n\r\n this.pos = 0; // current position\r\n this.current = 0; // current step\r\n this.last = -1; // last step\r\n\r\n this.movingInterval = -1;\r\n }\r\n\r\n\r\n /**\r\n * Add a step object. You can also use Roll.chunk() static helper function to create a step object easily.\r\n * @param s an object with {p1, p2, size, pad} properties, or an array of steps object\r\n * @returns {Roll}\r\n */\r\n addStep(s) {\r\n\r\n if (!Array.isArray(s)) {\r\n s = [s];\r\n }\r\n\r\n // get last recorded step\r\n var d = s[0].p1;\r\n if (this.steps.length > 0 ) {\r\n var last = this.steps[this.steps.length-1];\r\n d = last.p2 + last.pad;\r\n }\r\n\r\n // append new steps\r\n for (var i=0; i 0, step will be -1 when current progress is on the padding area. This allows you to check progress against padding.\r\n * @returns {number}\r\n */\r\n getStep() {\r\n for (var i=0; i= -this.viewportSize && st.p2 <= st.size ) {\r\n this.current = i;\r\n return i;\r\n }\r\n }\r\n return -1;\r\n }\r\n\r\n /**\r\n * Get current progress within the current step\r\n * @returns 0-1 if step.pad is 0. Otherwise it will range from negative to positive.\r\n */\r\n getStepProgress() {\r\n var curr = this.steps[ this.current ];\r\n return 1 - (curr.p2 / curr.size);\r\n }\r\n\r\n\r\n /**\r\n * Get current position\r\n * @returns {number|*}\r\n */\r\n getPosition() {\r\n return this.pos;\r\n }\r\n\r\n /**\r\n * Get total height of the pane (including padding)\r\n * @returns {*}\r\n */\r\n getHeight( recalc = false ) {\r\n if (recalc ) this.paneSize = this.steps.reduce( (a,b) => a+b.size+b.pad, 0 );\r\n return this.paneSize;\r\n }\r\n\r\n /**\r\n * Get viewport's height (same as this.viewportSize)\r\n * @returns {*}\r\n */\r\n getViewportHeight() {\r\n return this.viewportSize;\r\n }\r\n\r\n\r\n /**\r\n * Move the roll. This will emit two events `roll(step, currProgress, currPosition, totalProgress)` and `step(curr, last)`\r\n * @param pos new position\r\n * @returns {Roll}\r\n */\r\n move( pos ) {\r\n var last = this.pos;\r\n this.pos = -pos;\r\n var diff = this.pos - last;\r\n\r\n for (var i=0; i= 0) {\r\n this.emit(\"step\", curr, this.last, this.viewportSize );\r\n this.last = curr;\r\n }\r\n\r\n return this;\r\n }\r\n\r\n\r\n /**\r\n * Animated scrolling a DOM element\r\n * @param index step index\r\n * @param scrollPane a DOM element with scrolling (overflow-y).\r\n * @param speed optional speed of animated scroll. Defaults to 0.1. Larger is faster\r\n * @param isVertical optional boolean to indicate horizontal or vertical scroll\r\n */\r\n scroll( index, scrollPane, speed=0.1, isVertical=true) {\r\n if (!scrollPane || scrollPane.scrollTop == null) throw \"scrollPane parameter requires a DOM element with scrollTop property\";\r\n clearInterval( this.movingInterval );\r\n var _temp = Number.NEGATIVE_INFINITY;\r\n var dir = (isVertical) ? \"scrollTop\" : \"scrollLeft\";\r\n\r\n this.movingInterval = setInterval( () => {\r\n var target = this.getStepAt(index);\r\n var d = (target.p1 + target.size/4) * speed;\r\n scrollPane[dir] += d;\r\n if (Math.abs(d)<1 || _temp === scrollPane[dir]) clearInterval(this.movingInterval);\r\n _temp = scrollPane[dir];\r\n }, 17);\r\n }\r\n\r\n\r\n /**\r\n * A convenient static function to create a step object\r\n * @param size chunk size\r\n * @param pad optional padding (default to 0)\r\n * @returns {{p1: number, p2: *, size: *, pad: number}}\r\n */\r\n static chunk( size, pad=0) {\r\n return {\r\n p1: 0,\r\n p2: size,\r\n size: size,\r\n pad: pad\r\n }\r\n }\r\n\r\n\r\n /**\r\n * A convenient static function to compare a step with current step, and transform it to a name\r\n * @param step the step to check\r\n * @param currStep current step\r\n * @param prev optional class name for step is < currStep. Defaults to \"prev\"\r\n * @param next optional class name for step is > currStep. Defaults to \"next\"\r\n * @param match optional class name for step = currStep. Defaults to \"curr\"\r\n * @returns {string}\r\n */\r\n static stepName( step, currStep, prev=\"prev\", next=\"next\", match=\"curr\") {\r\n return (step === currStep) ? match : ( (step < currStep) ? prev : next );\r\n }\r\n\r\n\r\n /**\r\n * Static helper to get a handle function for Roll's \"step\" event. The handler function will add class names to each step element based on current step value.\r\n * @param roll a Roll instance\r\n * @param views a list of DOM elements which are the steps\r\n * @param prev optional class name for step is < currStep. Defaults to \"prev\"\r\n * @param next optional class name for step is > currStep. Defaults to \"next\"\r\n * @param match optional class name for step = currStep. Defaults to \"curr\"\r\n * @returns {Function}\r\n */\r\n static stepHandler( roll, views, prev=\"prev\", next=\"next\", match=\"curr\", trackTopPos=false) {\r\n return function ( curr, last, viewportHeight ) {\r\n for (var i = 0; i < roll.steps.length; i++) {\r\n var cls = Roll.stepName( i, curr, prev, next, match );\r\n views[i].className = \"step \" + cls;\r\n\r\n // if steps have different sizes, recalc top position and set style\r\n if (trackTopPos) {\r\n var p = (cls===prev) ? roll.steps[i].size * -1 : ((cls===next) ? viewportHeight : 0);\r\n views[i].style.top = p+\"px\";\r\n }\r\n }\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Static method to create a Roll instance with DOM elements\r\n * @param viewPortID id of viewport element, which is the parent of the viewPane. eg, \"#viewport\"\r\n * @param viewPaneID id of view pane element, eg, \"#pane\"\r\n * @param viewBox id of view box element, which is the parent the viewClass elements. eg, \"#steps\"\r\n * @param viewClass id of each step or slide element, eg, \".step\"\r\n * @param pad optional padding between steps. Defaults to 0.\r\n * @returns the roll instance which you can listen for \"step\" and \"roll\" event via `roll.on(...)`\r\n */\r\n static DOM( viewPortID, viewPaneID, viewBoxID, viewClass, pad=0 ) {\r\n\r\n var viewport = document.querySelector( viewPortID );\r\n var viewpane = viewport.querySelector( viewPaneID );\r\n var viewbox = document.querySelector( viewBoxID );\r\n var views = viewbox.querySelectorAll( viewClass );\r\n\r\n if (!viewport || !viewpane) throw `Cannot find ${viewPortID} or ${viewPaneID} element id.`\r\n if (!viewClass) throw `Cannot find ${viewClass} element class name`;\r\n\r\n // create roll instance based on viewport element height\r\n var roll = new Roll( viewport.getBoundingClientRect().height );\r\n\r\n // add each viewClass element as a step\r\n for (var i = 0; i < views.length; i++) {\r\n var rect = views[i].getBoundingClientRect();\r\n roll.addStep( Roll.chunk( rect.height, pad ) );\r\n }\r\n\r\n // update viewpane height based on steps\r\n viewpane.style.height = roll.getHeight()+\"px\";\r\n\r\n // update viewbox width to account for scrollbar\r\n viewbox.style.width = viewpane.getBoundingClientRect().width+\"px\";\r\n\r\n // track scroll\r\n viewport.addEventListener(\"scroll\", function(evt) {\r\n roll.move( viewport.scrollTop );\r\n });\r\n\r\n return roll;\r\n }\r\n\r\n}\r\n","var Roll = require(\"./roll.js\");\r\n\r\nif (window) window.Roll = Roll;\r\n\r\n"]}
--------------------------------------------------------------------------------
/dist/roll.min.js:
--------------------------------------------------------------------------------
1 | !function e(t,r,n){function s(o,u){if(!r[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var h=new Error("Cannot find module '"+o+"'");throw h.code="MODULE_NOT_FOUND",h}var l=r[o]={exports:{}};t[o][0].call(l.exports,function(e){var r=t[o][1][e];return s(r?r:e)},l,l.exports,e,t,r,n)}return r[o].exports}for(var i="function"==typeof require&&require,o=0;oe||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},n.prototype.emit=function(e){var t,r,n,i,a,h;if(this._events||(this._events={}),"error"===e&&(!this._events.error||o(this._events.error)&&!this._events.error.length)){if(t=arguments[1],t instanceof Error)throw t;throw TypeError('Uncaught, unspecified "error" event.')}if(r=this._events[e],u(r))return!1;if(s(r))switch(arguments.length){case 1:r.call(this);break;case 2:r.call(this,arguments[1]);break;case 3:r.call(this,arguments[1],arguments[2]);break;default:for(n=arguments.length,i=new Array(n-1),a=1;n>a;a++)i[a-1]=arguments[a];r.apply(this,i)}else if(o(r)){for(n=arguments.length,i=new Array(n-1),a=1;n>a;a++)i[a-1]=arguments[a];for(h=r.slice(),n=h.length,a=0;n>a;a++)h[a].apply(this,i)}return!0},n.prototype.addListener=function(e,t){var r;if(!s(t))throw TypeError("listener must be a function");if(this._events||(this._events={}),this._events.newListener&&this.emit("newListener",e,s(t.listener)?t.listener:t),this._events[e]?o(this._events[e])?this._events[e].push(t):this._events[e]=[this._events[e],t]:this._events[e]=t,o(this._events[e])&&!this._events[e].warned){var r;r=u(this._maxListeners)?n.defaultMaxListeners:this._maxListeners,r&&r>0&&this._events[e].length>r&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace())}return this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(e,t){function r(){this.removeListener(e,r),n||(n=!0,t.apply(this,arguments))}if(!s(t))throw TypeError("listener must be a function");var n=!1;return r.listener=t,this.on(e,r),this},n.prototype.removeListener=function(e,t){var r,n,i,u;if(!s(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(r=this._events[e],i=r.length,n=-1,r===t||s(r.listener)&&r.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(o(r)){for(u=i;u-->0;)if(r[u]===t||r[u].listener&&r[u].listener===t){n=u;break}if(0>n)return this;1===r.length?(r.length=0,delete this._events[e]):r.splice(n,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},n.prototype.removeAllListeners=function(e){var t,r;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r=this._events[e],s(r))this.removeListener(e,r);else for(;r.length;)this.removeListener(e,r[r.length-1]);return delete this._events[e],this},n.prototype.listeners=function(e){var t;return t=this._events&&this._events[e]?s(this._events[e])?[this._events[e]]:this._events[e].slice():[]},n.listenerCount=function(e,t){var r;return r=e._events&&e._events[t]?s(e._events[t])?1:e._events[t].length:0}},{}],2:[function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(r,"__esModule",{value:!0});var i=function(){function e(e,t){for(var r=0;r0){var r=this.steps[this.steps.length-1];t=r.p2+r.pad}for(var n=0;n=-this.viewportSize&&t.p2<=t.size)return this.current=e,e}return-1}},{key:"getStepProgress",value:function(){var e=this.steps[this.current];return 1-e.p2/e.size}},{key:"getPosition",value:function(){return this.pos}},{key:"getHeight",value:function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0];return e&&(this.paneSize=this.steps.reduce(function(e,t){return e+t.size+t.pad},0)),this.paneSize}},{key:"getViewportHeight",value:function(){return this.viewportSize}},{key:"move",value:function(e){var t=this.pos;this.pos=-e;for(var r=this.pos-t,n=0;n=0&&(this.emit("step",i,this.last,this.viewportSize),this.last=i),this}},{key:"scroll",value:function(e,t){var r=this,n=arguments.length<=2||void 0===arguments[2]?.1:arguments[2],s=arguments.length<=3||void 0===arguments[3]?!0:arguments[3];if(!t||null==t.scrollTop)throw"scrollPane parameter requires a DOM element with scrollTop property";clearInterval(this.movingInterval);var i=Number.NEGATIVE_INFINITY,o=s?"scrollTop":"scrollLeft";this.movingInterval=setInterval(function(){var s=r.getStepAt(e),u=(s.p1+s.size/4)*n;t[o]+=u,(Math.abs(u)<1||i===t[o])&&clearInterval(r.movingInterval),i=t[o]},17)}}],[{key:"chunk",value:function(e){var t=arguments.length<=1||void 0===arguments[1]?0:arguments[1];return{p1:0,p2:e,size:e,pad:t}}},{key:"stepName",value:function(e,t){var r=arguments.length<=2||void 0===arguments[2]?"prev":arguments[2],n=arguments.length<=3||void 0===arguments[3]?"next":arguments[3],s=arguments.length<=4||void 0===arguments[4]?"curr":arguments[4];return e===t?s:t>e?r:n}},{key:"stepHandler",value:function(e,r){var n=arguments.length<=2||void 0===arguments[2]?"prev":arguments[2],s=arguments.length<=3||void 0===arguments[3]?"next":arguments[3],i=arguments.length<=4||void 0===arguments[4]?"curr":arguments[4],o=arguments.length<=5||void 0===arguments[5]?!1:arguments[5];return function(u,a,h){for(var l=0;l bundling...');
51 | rebundle();
52 | });
53 | }
54 |
55 | rebundle();
56 | }
57 |
58 | function watch() {
59 | return compile(true);
60 | }
61 |
62 |
63 | gulp.task('min', function() {
64 | return gulp.src( "./dist/roll.js" )
65 | .pipe( rename('roll.min.js') )
66 | .pipe( uglify() )
67 | .pipe( gulp.dest( "./dist" ) )
68 |
69 | });
70 |
71 | gulp.task('module', function () {
72 | return gulp.src('./src/roll.js')
73 | .pipe(gulpbabel())
74 | .pipe(gulp.dest('./dist/module'));
75 | });
76 |
77 | gulp.task('build', function() { return compile(); });
78 | gulp.task('watch', function() { return watch(); });
79 |
80 | gulp.task('default', ['watch']);
81 |
82 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rolljs",
3 | "version": "0.1.2",
4 | "description": "A simple library to track scroll movements.",
5 | "author": "William Ngan",
6 | "devDependencies": {
7 | "event-stream": "^3.3.0",
8 | "gulp": "^3.8.10",
9 | "gulp-util": "^3.0.1",
10 | "gulp-concat": "^2.4.3",
11 | "gulp-rename": "^1.2.0",
12 | "gulp-insert": "^0.4.0",
13 | "gulp-uglify": "^1.0.2",
14 | "gulp-sourcemaps": "^1.5.2",
15 | "gulp-babel": "^5.2.0",
16 | "browserify": "^11.1.0",
17 | "vinyl-source-stream": "^1.1.0",
18 | "vinyl-buffer": "^1.0.0",
19 | "watchify": "^3.4.0",
20 | "babelify": "6.3.0",
21 | "events": "^1.1.0"
22 | },
23 | "main": "dist/module/roll.js",
24 | "directories": {
25 | "doc": "docs",
26 | "test": "test"
27 | },
28 | "dependencies": {},
29 | "scripts": {
30 | "test": "echo \"Error: no test specified\" && exit 1"
31 | },
32 | "repository": {
33 | "type": "git",
34 | "url": "https://github.com/williamngan/roll.git"
35 | },
36 | "keywords": [
37 | "animation",
38 | "scroll",
39 | "ui"
40 | ],
41 | "license": "Apache",
42 | "bugs": {
43 | "url": "https://github.com/williamngan/roll/issues"
44 | },
45 | "homepage": "https://github.com/williamngan/roll"
46 | }
47 |
--------------------------------------------------------------------------------
/src/roll.js:
--------------------------------------------------------------------------------
1 | var EventEmitter = require('events').EventEmitter;
2 |
3 | /**
4 | * Roll simply keep tracks of steps' positions inside a viewport.
5 | * Apart from the static helper functions and the `scroll` function, a roll instance doesn't depend on DOM manipulation.
6 | * That means you can use a Roll instance in contexts other than DOM.
7 | */
8 | export default class Roll extends EventEmitter {
9 |
10 | /**
11 | * Create a new Roll.
12 | * @param viewSize viewport size (single dimension)
13 | */
14 | constructor( viewSize ) {
15 | super();
16 |
17 | this.viewportSize = viewSize;
18 | this.paneSize = 0;
19 |
20 | // store the steps object {y1, y2, size, pad}, See Roll.chunk
21 | this.steps = [];
22 |
23 | this.pos = 0; // current position
24 | this.current = 0; // current step
25 | this.last = -1; // last step
26 |
27 | this.movingInterval = -1;
28 | }
29 |
30 |
31 | /**
32 | * Add a step object. You can also use Roll.chunk() static helper function to create a step object easily.
33 | * @param s an object with {p1, p2, size, pad} properties, or an array of steps object
34 | * @returns {Roll}
35 | */
36 | addStep(s) {
37 |
38 | if (!Array.isArray(s)) {
39 | s = [s];
40 | }
41 |
42 | // get last recorded step
43 | var d = s[0].p1;
44 | if (this.steps.length > 0 ) {
45 | var last = this.steps[this.steps.length-1];
46 | d = last.p2 + last.pad;
47 | }
48 |
49 | // append new steps
50 | for (var i=0; i 0, step will be -1 when current progress is on the padding area. This allows you to check progress against padding.
75 | * @returns {number}
76 | */
77 | getStep() {
78 | for (var i=0; i= -this.viewportSize && st.p2 <= st.size ) {
81 | this.current = i;
82 | return i;
83 | }
84 | }
85 | return -1;
86 | }
87 |
88 | /**
89 | * Get current progress within the current step
90 | * @returns 0-1 if step.pad is 0. Otherwise it will range from negative to positive.
91 | */
92 | getStepProgress() {
93 | var curr = this.steps[ this.current ];
94 | return 1 - (curr.p2 / curr.size);
95 | }
96 |
97 |
98 | /**
99 | * Get current position
100 | * @returns {number|*}
101 | */
102 | getPosition() {
103 | return this.pos;
104 | }
105 |
106 | /**
107 | * Get total height of the pane (including padding)
108 | * @returns {*}
109 | */
110 | getHeight( recalc = false ) {
111 | if (recalc ) this.paneSize = this.steps.reduce( (a,b) => a+b.size+b.pad, 0 );
112 | return this.paneSize;
113 | }
114 |
115 | /**
116 | * Get viewport's height (same as this.viewportSize)
117 | * @returns {*}
118 | */
119 | getViewportHeight() {
120 | return this.viewportSize;
121 | }
122 |
123 |
124 | /**
125 | * Move the roll. This will emit two events `roll(step, currProgress, currPosition, totalProgress)` and `step(curr, last)`
126 | * @param pos new position
127 | * @returns {Roll}
128 | */
129 | move( pos ) {
130 | var last = this.pos;
131 | this.pos = -pos;
132 | var diff = this.pos - last;
133 |
134 | for (var i=0; i= 0) {
145 | this.emit("step", curr, this.last, this.viewportSize );
146 | this.last = curr;
147 | }
148 |
149 | return this;
150 | }
151 |
152 |
153 | /**
154 | * Animated scrolling a DOM element
155 | * @param index step index
156 | * @param scrollPane a DOM element with scrolling (overflow-y).
157 | * @param speed optional speed of animated scroll. Defaults to 0.1. Larger is faster
158 | * @param isVertical optional boolean to indicate horizontal or vertical scroll
159 | */
160 | scroll( index, scrollPane, speed=0.1, isVertical=true) {
161 | if (!scrollPane || scrollPane.scrollTop == null) throw "scrollPane parameter requires a DOM element with scrollTop property";
162 | clearInterval( this.movingInterval );
163 | var _temp = Number.NEGATIVE_INFINITY;
164 | var dir = (isVertical) ? "scrollTop" : "scrollLeft";
165 |
166 | this.movingInterval = setInterval( () => {
167 | var target = this.getStepAt(index);
168 | var d = (target.p1 + target.size/4) * speed;
169 | scrollPane[dir] += d;
170 | if (Math.abs(d)<1 || _temp === scrollPane[dir]) clearInterval(this.movingInterval);
171 | _temp = scrollPane[dir];
172 | }, 17);
173 | }
174 |
175 |
176 | /**
177 | * A convenient static function to create a step object
178 | * @param size chunk size
179 | * @param pad optional padding (default to 0)
180 | * @returns {{p1: number, p2: *, size: *, pad: number}}
181 | */
182 | static chunk( size, pad=0) {
183 | return {
184 | p1: 0,
185 | p2: size,
186 | size: size,
187 | pad: pad
188 | }
189 | }
190 |
191 |
192 | /**
193 | * A convenient static function to compare a step with current step, and transform it to a name
194 | * @param step the step to check
195 | * @param currStep current step
196 | * @param prev optional class name for step is < currStep. Defaults to "prev"
197 | * @param next optional class name for step is > currStep. Defaults to "next"
198 | * @param match optional class name for step = currStep. Defaults to "curr"
199 | * @returns {string}
200 | */
201 | static stepName( step, currStep, prev="prev", next="next", match="curr") {
202 | return (step === currStep) ? match : ( (step < currStep) ? prev : next );
203 | }
204 |
205 |
206 | /**
207 | * Static helper to get a handle function for Roll's "step" event. The handler function will add class names to each step element based on current step value.
208 | * @param roll a Roll instance
209 | * @param views a list of DOM elements which are the steps
210 | * @param prev optional class name for step is < currStep. Defaults to "prev"
211 | * @param next optional class name for step is > currStep. Defaults to "next"
212 | * @param match optional class name for step = currStep. Defaults to "curr"
213 | * @returns {Function}
214 | */
215 | static stepHandler( roll, views, prev="prev", next="next", match="curr", trackTopPos=false) {
216 | return function ( curr, last, viewportHeight ) {
217 | for (var i = 0; i < roll.steps.length; i++) {
218 | var cls = Roll.stepName( i, curr, prev, next, match );
219 | views[i].className = "step " + cls;
220 |
221 | // if steps have different sizes, recalc top position and set style
222 | if (trackTopPos) {
223 | var p = (cls===prev) ? roll.steps[i].size * -1 : ((cls===next) ? viewportHeight : 0);
224 | views[i].style.top = p+"px";
225 | }
226 | }
227 | }
228 | }
229 |
230 |
231 | /**
232 | * Static method to create a Roll instance with DOM elements
233 | * @param viewPortID id of viewport element, which is the parent of the viewPane. eg, "#viewport"
234 | * @param viewPaneID id of view pane element, eg, "#pane"
235 | * @param viewBox id of view box element, which is the parent the viewClass elements. eg, "#steps"
236 | * @param viewClass id of each step or slide element, eg, ".step"
237 | * @param pad optional padding between steps. Defaults to 0.
238 | * @returns the roll instance which you can listen for "step" and "roll" event via `roll.on(...)`
239 | */
240 | static DOM( viewPortID, viewPaneID, viewBoxID, viewClass, pad=0 ) {
241 |
242 | var viewport = document.querySelector( viewPortID );
243 | var viewpane = viewport.querySelector( viewPaneID );
244 | var viewbox = document.querySelector( viewBoxID );
245 | var views = viewbox.querySelectorAll( viewClass );
246 |
247 | if (!viewport || !viewpane) throw `Cannot find ${viewPortID} or ${viewPaneID} element id.`
248 | if (!viewClass) throw `Cannot find ${viewClass} element class name`;
249 |
250 | // create roll instance based on viewport element height
251 | var roll = new Roll( viewport.getBoundingClientRect().height );
252 |
253 | // add each viewClass element as a step
254 | for (var i = 0; i < views.length; i++) {
255 | var rect = views[i].getBoundingClientRect();
256 | roll.addStep( Roll.chunk( rect.height, pad ) );
257 | }
258 |
259 | // update viewpane height based on steps
260 | viewpane.style.height = roll.getHeight()+"px";
261 |
262 | // update viewbox width to account for scrollbar
263 | viewbox.style.width = viewpane.getBoundingClientRect().width+"px";
264 |
265 | // track scroll
266 | viewport.addEventListener("scroll", function(evt) {
267 | roll.move( viewport.scrollTop );
268 | });
269 |
270 | return roll;
271 | }
272 |
273 | }
274 |
--------------------------------------------------------------------------------
/src/roll_standalone.js:
--------------------------------------------------------------------------------
1 | var Roll = require("./roll.js");
2 |
3 | if (window) window.Roll = Roll;
4 |
5 |
--------------------------------------------------------------------------------