├── .babelrc ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── bell.m4a ├── bell.ogg ├── dist ├── core │ ├── tick.core.amd.js │ ├── tick.core.commonjs.js │ ├── tick.core.css │ ├── tick.core.global.js │ ├── tick.core.global.min.js │ ├── tick.core.jquery.js │ ├── tick.core.jquery.min.js │ ├── tick.core.kickstart.js │ ├── tick.core.kickstart.min.js │ ├── tick.core.min.css │ ├── tick.core.module.js │ └── tick.core.polyfill.js ├── font-highres │ ├── tick.font.highres.amd.js │ ├── tick.font.highres.commonjs.js │ ├── tick.font.highres.global.js │ ├── tick.font.highres.global.min.js │ ├── tick.font.highres.jquery.js │ ├── tick.font.highres.jquery.min.js │ └── tick.font.highres.module.js ├── font-lowres │ ├── tick.font.lowres.amd.js │ ├── tick.font.lowres.commonjs.js │ ├── tick.font.lowres.global.js │ ├── tick.font.lowres.global.min.js │ ├── tick.font.lowres.jquery.js │ ├── tick.font.lowres.jquery.min.js │ └── tick.font.lowres.module.js ├── view-boom │ ├── tick.view.boom.amd.js │ ├── tick.view.boom.commonjs.js │ ├── tick.view.boom.css │ ├── tick.view.boom.global.js │ ├── tick.view.boom.global.min.js │ ├── tick.view.boom.jquery.js │ ├── tick.view.boom.jquery.min.js │ ├── tick.view.boom.min.css │ └── tick.view.boom.module.js ├── view-dots │ ├── tick.view.dots.amd.js │ ├── tick.view.dots.commonjs.js │ ├── tick.view.dots.css │ ├── tick.view.dots.global.js │ ├── tick.view.dots.global.min.js │ ├── tick.view.dots.jquery.js │ ├── tick.view.dots.jquery.min.js │ ├── tick.view.dots.min.css │ └── tick.view.dots.module.js ├── view-line │ ├── tick.view.line.amd.js │ ├── tick.view.line.commonjs.js │ ├── tick.view.line.css │ ├── tick.view.line.global.js │ ├── tick.view.line.global.min.js │ ├── tick.view.line.jquery.js │ ├── tick.view.line.jquery.min.js │ ├── tick.view.line.min.css │ └── tick.view.line.module.js └── view-swap │ ├── tick.view.swap.amd.js │ ├── tick.view.swap.commonjs.js │ ├── tick.view.swap.css │ ├── tick.view.swap.global.js │ ├── tick.view.swap.global.min.js │ ├── tick.view.swap.jquery.js │ ├── tick.view.swap.jquery.min.js │ ├── tick.view.swap.min.css │ └── tick.view.swap.module.js ├── dots.gif ├── example └── index.html ├── gulpfile.babel.js ├── inline-svg └── index.js ├── line.gif ├── package-lock.json ├── package.json ├── src ├── core │ ├── js │ │ ├── Tick.js │ │ ├── TickDOM.js │ │ ├── animate.js │ │ ├── canvas.js │ │ ├── count.js │ │ ├── date.js │ │ ├── dom.js │ │ ├── easing.js │ │ ├── extensions │ │ │ └── index.js │ │ ├── index.js │ │ ├── parser.js │ │ ├── scheduler.js │ │ ├── style.js │ │ ├── support.js │ │ ├── timer.js │ │ ├── transform │ │ │ ├── abs.js │ │ │ ├── add.js │ │ │ ├── arrive.js │ │ │ ├── ascii.js │ │ │ ├── ceil.js │ │ │ ├── char.js │ │ │ ├── delay.js │ │ │ ├── divide.js │ │ │ ├── duration.js │ │ │ ├── floor.js │ │ │ ├── format.js │ │ │ ├── fraction.js │ │ │ ├── index.js │ │ │ ├── input.js │ │ │ ├── keys.js │ │ │ ├── limit.js │ │ │ ├── lower.js │ │ │ ├── map.js │ │ │ ├── modulus.js │ │ │ ├── multiply.js │ │ │ ├── number.js │ │ │ ├── pad.js │ │ │ ├── percentage.js │ │ │ ├── plural.js │ │ │ ├── preset.js │ │ │ ├── replace.js │ │ │ ├── reverse.js │ │ │ ├── rotate.js │ │ │ ├── round.js │ │ │ ├── split.js │ │ │ ├── spring.js │ │ │ ├── step.js │ │ │ ├── substring.js │ │ │ ├── subtract.js │ │ │ ├── transform.js │ │ │ ├── tween.js │ │ │ ├── upper.js │ │ │ └── value.js │ │ ├── transitions.js │ │ ├── transitions │ │ │ ├── crossfade.js │ │ │ ├── revolve.js │ │ │ ├── swap.js │ │ │ └── zoom.js │ │ ├── utils.js │ │ ├── utils │ │ │ ├── capitalizeFirstLetter.js │ │ │ ├── clone.js │ │ │ ├── lowercaseFirstLetter.js │ │ │ ├── merge.js │ │ │ ├── toBoolean.js │ │ │ └── trim.js │ │ └── view │ │ │ ├── destroyer.js │ │ │ ├── drawer.js │ │ │ ├── grouper.js │ │ │ ├── index.js │ │ │ ├── repeater.js │ │ │ ├── resizer.js │ │ │ ├── root.js │ │ │ ├── rooter.js │ │ │ ├── styler.js │ │ │ ├── transitioner.js │ │ │ └── updater.js │ └── sass │ │ ├── index.scss │ │ └── modules │ │ └── _layout.scss ├── extensions │ ├── extension.amd.js │ ├── extension.commonjs.js │ ├── extension.global.js │ ├── extension.jquery.js │ ├── extension.module.js │ ├── font │ │ ├── highres │ │ │ └── js │ │ │ │ └── index.js │ │ └── lowres │ │ │ └── js │ │ │ └── index.js │ └── view │ │ ├── boom │ │ ├── js │ │ │ └── index.js │ │ └── sass │ │ │ └── index.scss │ │ ├── dots │ │ ├── js │ │ │ └── index.js │ │ └── sass │ │ │ ├── index.scss │ │ │ └── modules │ │ │ ├── _default.scss │ │ │ └── _layout.scss │ │ ├── line │ │ ├── js │ │ │ ├── bar.js │ │ │ ├── canvas.js │ │ │ ├── index.js │ │ │ └── ring.js │ │ └── sass │ │ │ ├── index.scss │ │ │ └── modules │ │ │ ├── _default.scss │ │ │ └── _layout.scss │ │ └── swap │ │ ├── js │ │ └── index.js │ │ └── sass │ │ ├── index.scss │ │ └── modules │ │ ├── _default.scss │ │ └── _layout.scss ├── polyfill │ ├── Array.fill.js │ ├── Array.find.js │ ├── Array.from.js │ ├── Array.includes.js │ ├── Object.assign.js │ └── Object.keys.js ├── shared │ ├── cache.js │ └── utils.js ├── variants │ ├── tick.core.amd.js │ ├── tick.core.commonjs.js │ ├── tick.core.global.js │ ├── tick.core.jquery.js │ ├── tick.core.kickstart.js │ └── tick.core.module.js └── wrapper │ ├── core.intro.js │ ├── core.outro.js │ ├── extension.intro.js │ ├── extension.outro.js │ ├── poly.intro.js │ └── poly.outro.js ├── swap.gif └── test ├── diff.test.js ├── drawing.html ├── parser.test.js ├── schedule.test.js └── style.test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015" 4 | ] 5 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v16.14 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/**/* -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 4, 4 | "printWidth": 100, 5 | "singleQuote": true, 6 | "semi": true 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 PQINA | Rik Schennink 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tick Counter 2 | 3 | A ticker for declaritive building of countdowns and counters. 4 | 5 | Supports: 6 | 7 | - Counting towards a date 8 | - Counting up from a date 9 | - Scheduling multiple intervals 10 | - Polling a value from a server 11 | - Presenting a simple value 12 | 13 | Some examples: 14 | 15 | ![](./dots.gif) 16 | 17 | ![](./swap.gif) 18 | 19 | ![](./line.gif) 20 | 21 | You can also use Tick to create [Flip counters](https://pqina.nl/flip/) 22 | 23 | Made with ❤ By [Rik Schennink](https://twitter.com/rikschennink/) 24 | 25 | 26 | ## Docs 27 | 28 | Information on how to customize Tick and use the Tick API can be found on the [product website](https://pqina.nl/tick/). 29 | 30 | See index below: 31 | 32 | - [Base](https://pqina.nl/tick/#tick) 33 | - [Layouts](https://pqina.nl/tick/#layouts) 34 | - [Views](https://pqina.nl/tick/#views) 35 | - [Text](https://pqina.nl/tick/#text) 36 | - [Swap](https://pqina.nl/tick/#swap) 37 | - [Flip](https://pqina.nl/tick/#flip) 38 | - [Dots](https://pqina.nl/tick/#dots) 39 | - [Line](https://pqina.nl/tick/#line) 40 | - [Boom](https://pqina.nl/tick/#boom) 41 | - [Transforms](https://pqina.nl/tick/#value-transforms) 42 | - [Transitions](https://pqina.nl/tick/#transitions) 43 | 44 | ### Install from NPM 45 | 46 | ``` 47 | npm i @pqina/tick --save 48 | ``` 49 | 50 | ```js 51 | import Tick from '@pqina/tick'; 52 | 53 | console.log(Tick); 54 | // logs {supported: true, options: {…}, helper: {…}, data: {…}, DOM: {…}, …} 55 | ``` 56 | 57 | ## Quick Introduction 58 | 59 | Building Tick Counters is very similar to building with Legos. Open the [example implementation](./example), clear the existing example, and follow along. 60 | 61 | Start with the base `.tick` block: 62 | 63 | ```html 64 |
65 | 66 |
67 | ``` 68 | 69 | We haven't yet entered a value so we won't see anything on the screen. 70 | 71 | Let's do that now, add a value using the `data-value` attribute. 72 | 73 | ```html 74 |
76 | 77 |
78 | ``` 79 | 80 | Tick now automatically adds a plain `"text"` view to present our value. 81 | 82 | We can also present strings instead of numbers. 83 | 84 | ```html 85 |
87 | 88 |
99 | 100 | 101 | 102 | 103 | ``` 104 | 105 | It does not show the set progress. Maybe it's because there's no room to render our **line** view. We'll replace the `span` element with a `div` to make it stretch the entire width of the demo area. 106 | 107 | ```html 108 |
110 | 111 |
112 | 113 |
114 | ``` 115 | 116 | That wasn't it. 117 | 118 | We don't see anything because **line** doesn't know its maximum value and therefor cannot determine what progress to show. We have to feed line a a value between `0` and `1`, where `0` is empty and `1` is full. 119 | 120 | We can do this by telling it the maximum value. We'll add a [transform](http://pqina.nl/tick/#value-transforms) that calculates the value between `0` and `1` for a value in a certain range (in this case 0 and 100). 121 | 122 | ```html 123 |
125 | 126 |
127 | 128 |
129 | ``` 130 | 131 | There we go! We put in a value of 50 and the **fraction** transform turns it into **0.5** 132 | 133 | Let's update our counter each second so we can see the progress bar fill up. Bind a function to the `data-did-init` callback. We'll limit its value to a 100. 134 | 135 | We'll also add a nice animation using the `spring` transform. See how we can pipe values from one transform to the other. 136 | 137 | ```html 138 |
141 | 142 |
143 | 144 |
145 | 163 | ``` 164 | 165 | There you have it, a simple progress bar build with Tick. 166 | 167 | [Read the documentation](https://pqina.nl/tick/) to take a deep dive into what's possible with Tick. 168 | 169 | 170 | ## License 171 | 172 | MIT License, Enjoy! 173 | -------------------------------------------------------------------------------- /bell.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pqina/tick/a3df2420753980cfe82a3af90ceab93a89419e9f/bell.m4a -------------------------------------------------------------------------------- /bell.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pqina/tick/a3df2420753980cfe82a3af90ceab93a89419e9f/bell.ogg -------------------------------------------------------------------------------- /dist/core/tick.core.min.css: -------------------------------------------------------------------------------- 1 | /* 2 | * @pqina/tick v1.8.3 - Counters Made Easy 3 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 4 | */ 5 | .tick{box-sizing:border-box;-webkit-user-select:none;-ms-user-select:none;user-select:none;cursor:default;position:relative;z-index:1;line-height:1.4}.tick *{box-sizing:inherit}.tick [data-view]{max-width:100%}.tick span[data-view]{display:inline-block}.tick .tick-credits{position:absolute;right:0;bottom:0;opacity:.4;text-decoration:none;font-size:11px;color:inherit}.tick [data-layout~=pad]{margin:-.25em}.tick [data-layout~=pad]>*{margin:.25em}.tick [data-layout~=horizontal]{display:-ms-flexbox;display:flex;-ms-flex-direction:row;flex-direction:row;-ms-flex-pack:center;justify-content:center}.tick [data-layout~=horizontal][data-layout~=baseline]{-ms-flex-align:baseline;align-items:baseline}.tick [data-layout~=horizontal][data-layout~=center]{-ms-flex-pack:center;justify-content:center}.tick [data-layout~=horizontal][data-layout~=right]{-ms-flex-pack:end;justify-content:flex-end}.tick [data-layout~=horizontal][data-layout~=left]{-ms-flex-pack:start;justify-content:flex-start}.tick [data-layout~=horizontal][data-layout~=fill],.tick [data-layout~=horizontal][data-layout~=stretch]{-ms-flex-line-pack:stretch;align-content:stretch;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.tick [data-layout~=horizontal][data-layout~=fill]>*,.tick [data-layout~=horizontal][data-layout~=stretch]>*{-ms-flex:1 0 0px;flex:1 0 0;width:100%}.tick [data-layout~=horizontal][data-layout~=multi-line]{-ms-flex-wrap:wrap;flex-wrap:wrap}.tick [data-layout~=horizontal][data-layout~=fit]{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-ms-flex-line-pack:center;align-content:center;white-space:nowrap;-ms-flex-pack:start;justify-content:flex-start}.tick [data-layout~=vertical]{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:center;align-items:center}.tick [data-layout~=vertical][data-layout~=top]{-ms-flex-pack:start;justify-content:flex-start}.tick [data-layout~=vertical][data-layout~=bottom]{-ms-flex-pack:end;justify-content:flex-end;min-height:100%}.tick [data-layout~=vertical][data-layout~=middle]{-ms-flex-pack:center;justify-content:center;min-height:100%}.tick [data-layout~=vertical][data-layout~=left]{-ms-flex-align:start;align-items:flex-start}.tick [data-layout~=vertical][data-layout~=right]{-ms-flex-align:end;align-items:flex-end}.tick [data-layout~=vertical][data-layout~=center]{text-align:center}.tick [data-layout~=vertical][data-layout~=fill],.tick [data-layout~=vertical][data-layout~=stretch]{-ms-flex-align:stretch;align-items:stretch;min-height:100%}.tick [data-layout~=vertical][data-layout~=fill]>*,.tick [data-layout~=vertical][data-layout~=stretch]>*{-ms-flex:1 0 0px;flex:1 0 0}.tick [data-layout~=vertical]>*+*{margin-top:.5em}.tick [data-layout~=overlay]{position:relative}.tick [data-layout~=overlay]>*{margin:0}.tick [data-layout~=overlay][data-layout~=center]{text-align:center}.tick [data-layout~=overlay][data-layout~=left]{text-align:left}.tick [data-layout~=overlay][data-layout~=right]{text-align:right}.tick [data-layout~=overlay]>[data-overlay=fill],.tick [data-layout~=overlay]>[data-overlay=stretch]{position:absolute;left:0;right:0;top:0;bottom:0}.tick [data-layout~=overlay]>[data-overlay=center]{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;position:absolute;left:0;right:0;top:0;bottom:0} -------------------------------------------------------------------------------- /dist/font-highres/tick.font.highres.global.min.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | !function(i,t){"use strict";i.Tick||(i.Tick=[]),i.Tick.push(["font","highres",function(){if(!i)var i={};return i.exports=function(){return{" ":[[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]],"?":[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,1,0,0]],"!":[[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,1,0,0]],"-":[[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,1,1,1,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]],"+":[[0,0,0,0,0],[0,0,1,0,0],[0,0,1,0,0],[1,1,1,1,1],[0,0,1,0,0],[0,0,1,0,0],[0,0,0,0,0]],".":[[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0]],",":[[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0],[0,1,1,0,0]],"%":[[1,1,0,0,0],[1,1,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,1,1],[0,0,0,1,1]],$:[[0,0,1,0,0],[0,1,1,1,1],[1,0,1,0,0],[0,1,1,1,0],[0,0,1,0,1],[1,1,1,1,0],[0,0,1,0,0]],"€":[[0,0,1,0,0],[0,1,1,1,1],[1,0,1,0,0],[0,1,1,1,0],[0,0,1,0,1],[1,1,1,1,0],[0,0,1,0,0]],"&":[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0],[1,0,1,0,0],[1,0,0,1,0],[0,1,1,0,1]],"@":[[0,1,1,1,0],[1,0,0,0,1],[1,0,1,1,1],[1,0,1,0,1],[1,0,1,1,0],[1,0,0,0,0],[0,1,1,1,1]],":":[[0,0,0,0,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0],[0,0,0,0,0]],";":[[0,0,0,0,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0],[0,1,1,0,0]],0:[[0,1,1,1,0],[1,0,0,1,1],[1,0,1,0,1],[1,1,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],1:[[0,0,0,1,0],[0,0,1,1,0],[0,1,0,1,0],[0,0,0,1,0],[0,0,0,1,0],[0,0,0,1,0],[0,0,0,1,0]],2:[[0,1,1,1,0],[1,0,0,0,1],[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,1,1,1,1]],3:[[0,1,1,1,0],[1,0,0,0,1],[0,0,0,0,1],[0,0,1,1,0],[0,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],4:[[0,0,0,1,0],[0,0,1,1,0],[0,1,0,1,0],[1,0,0,1,0],[1,1,1,1,1],[0,0,0,1,0],[0,0,0,1,0]],5:[[1,1,1,1,1],[1,0,0,0,0],[1,1,1,1,0],[0,0,0,0,1],[0,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],6:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,0],[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],7:[[1,1,1,1,1],[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[0,1,0,0,0],[0,1,0,0,0]],8:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],9:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,1],[0,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],A:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,1],[1,0,0,0,1],[1,0,0,0,1]],B:[[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,0]],C:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,1],[0,1,1,1,0]],D:[[1,1,1,0,0],[1,0,0,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,1,0],[1,1,1,0,0]],E:[[1,1,1,1,1],[1,0,0,0,0],[1,0,0,0,0],[1,1,1,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,1,1,1,1]],F:[[1,1,1,1,1],[1,0,0,0,0],[1,0,0,0,0],[1,1,1,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0]],G:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,0],[1,0,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],H:[[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1]],I:[[0,1,1,1,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,1,1,1,0]],J:[[0,1,1,1,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[1,0,1,0,0],[0,1,1,0,0]],K:[[1,0,0,0,1],[1,0,0,0,1],[1,0,0,1,0],[1,1,1,0,0],[1,0,0,1,0],[1,0,0,0,1],[1,0,0,0,1]],L:[[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,1,1,1,1]],M:[[1,0,0,0,1],[1,1,0,1,1],[1,0,1,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1]],N:[[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,0,0,1],[1,0,1,0,1],[1,0,0,1,1],[1,0,0,0,1]],O:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],P:[[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0]],Q:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,1,1],[0,1,1,1,1]],R:[[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1]],S:[[0,1,1,1,1],[1,0,0,0,0],[1,0,0,0,0],[0,1,1,1,0],[0,0,0,0,1],[0,0,0,0,1],[1,1,1,1,0]],T:[[1,1,1,1,1],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0]],U:[[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],V:[[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,0,1,0],[0,0,1,0,0]],W:[[1,0,0,0,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,1,0,1],[1,0,1,0,1],[1,1,0,1,1],[1,0,0,0,1]],X:[[1,0,0,0,1],[1,0,0,0,1],[0,1,0,1,0],[0,0,1,0,0],[0,1,0,1,0],[1,0,0,0,1],[1,0,0,0,1]],Y:[[1,0,0,0,1],[1,0,0,0,1],[0,1,0,1,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0]],Z:[[1,1,1,1,1],[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,0,0],[1,1,1,1,1]]}},i.exports.identifier={name:"highres",type:"font"},i.exports}()])}(window); -------------------------------------------------------------------------------- /dist/font-highres/tick.font.highres.jquery.min.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | !function(t){"use strict";t&&(t.tick||(t.tick=[]),t.tick.push(["font","highres",function(){if(!t)var t={};return t.exports=function(){return{" ":[[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]],"?":[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,1,0,0]],"!":[[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,1,0,0]],"-":[[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,1,1,1,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]],"+":[[0,0,0,0,0],[0,0,1,0,0],[0,0,1,0,0],[1,1,1,1,1],[0,0,1,0,0],[0,0,1,0,0],[0,0,0,0,0]],".":[[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0]],",":[[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0],[0,1,1,0,0]],"%":[[1,1,0,0,0],[1,1,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,1,1],[0,0,0,1,1]],$:[[0,0,1,0,0],[0,1,1,1,1],[1,0,1,0,0],[0,1,1,1,0],[0,0,1,0,1],[1,1,1,1,0],[0,0,1,0,0]],"€":[[0,0,1,0,0],[0,1,1,1,1],[1,0,1,0,0],[0,1,1,1,0],[0,0,1,0,1],[1,1,1,1,0],[0,0,1,0,0]],"&":[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0],[1,0,1,0,0],[1,0,0,1,0],[0,1,1,0,1]],"@":[[0,1,1,1,0],[1,0,0,0,1],[1,0,1,1,1],[1,0,1,0,1],[1,0,1,1,0],[1,0,0,0,0],[0,1,1,1,1]],":":[[0,0,0,0,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0],[0,0,0,0,0]],";":[[0,0,0,0,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0],[0,1,1,0,0]],0:[[0,1,1,1,0],[1,0,0,1,1],[1,0,1,0,1],[1,1,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],1:[[0,0,0,1,0],[0,0,1,1,0],[0,1,0,1,0],[0,0,0,1,0],[0,0,0,1,0],[0,0,0,1,0],[0,0,0,1,0]],2:[[0,1,1,1,0],[1,0,0,0,1],[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,1,1,1,1]],3:[[0,1,1,1,0],[1,0,0,0,1],[0,0,0,0,1],[0,0,1,1,0],[0,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],4:[[0,0,0,1,0],[0,0,1,1,0],[0,1,0,1,0],[1,0,0,1,0],[1,1,1,1,1],[0,0,0,1,0],[0,0,0,1,0]],5:[[1,1,1,1,1],[1,0,0,0,0],[1,1,1,1,0],[0,0,0,0,1],[0,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],6:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,0],[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],7:[[1,1,1,1,1],[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[0,1,0,0,0],[0,1,0,0,0]],8:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],9:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,1],[0,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],A:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,1],[1,0,0,0,1],[1,0,0,0,1]],B:[[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,0]],C:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,1],[0,1,1,1,0]],D:[[1,1,1,0,0],[1,0,0,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,1,0],[1,1,1,0,0]],E:[[1,1,1,1,1],[1,0,0,0,0],[1,0,0,0,0],[1,1,1,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,1,1,1,1]],F:[[1,1,1,1,1],[1,0,0,0,0],[1,0,0,0,0],[1,1,1,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0]],G:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,0],[1,0,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],H:[[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1]],I:[[0,1,1,1,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,1,1,1,0]],J:[[0,1,1,1,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[1,0,1,0,0],[0,1,1,0,0]],K:[[1,0,0,0,1],[1,0,0,0,1],[1,0,0,1,0],[1,1,1,0,0],[1,0,0,1,0],[1,0,0,0,1],[1,0,0,0,1]],L:[[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0],[1,1,1,1,1]],M:[[1,0,0,0,1],[1,1,0,1,1],[1,0,1,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1]],N:[[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,0,0,1],[1,0,1,0,1],[1,0,0,1,1],[1,0,0,0,1]],O:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],P:[[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,0],[1,0,0,0,0],[1,0,0,0,0],[1,0,0,0,0]],Q:[[0,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,1,1],[0,1,1,1,1]],R:[[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,0],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1]],S:[[0,1,1,1,1],[1,0,0,0,0],[1,0,0,0,0],[0,1,1,1,0],[0,0,0,0,1],[0,0,0,0,1],[1,1,1,1,0]],T:[[1,1,1,1,1],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0]],U:[[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,1,1,0]],V:[[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[0,1,0,1,0],[0,0,1,0,0]],W:[[1,0,0,0,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,1,0,1],[1,0,1,0,1],[1,1,0,1,1],[1,0,0,0,1]],X:[[1,0,0,0,1],[1,0,0,0,1],[0,1,0,1,0],[0,0,1,0,0],[0,1,0,1,0],[1,0,0,0,1],[1,0,0,0,1]],Y:[[1,0,0,0,1],[1,0,0,0,1],[0,1,0,1,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0],[0,0,1,0,0]],Z:[[1,1,1,1,1],[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0],[1,0,0,0,0],[1,1,1,1,1]]}},t.exports.identifier={name:"highres",type:"font"},t.exports}()]))}(window.jQuery); -------------------------------------------------------------------------------- /dist/font-lowres/tick.font.lowres.amd.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | define(function() { 8 | if (!module) { 9 | var module = {}; 10 | } 11 | 'use strict'; 12 | 13 | module.exports = function () { 14 | return { 15 | 16 | // Special Characters 17 | ' ': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]], 18 | '?': [[1, 1, 1], [0, 0, 1], [0, 1, 0], [0, 0, 0], [0, 1, 0]], 19 | '!': [[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0]], 20 | '-': [[0, 0, 0], [0, 0, 0], [1, 1, 1], [0, 0, 0], [0, 0, 0]], 21 | '+': [[0, 0, 0], [0, 1, 0], [1, 1, 1], [0, 1, 0], [0, 0, 0]], 22 | '.': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 1, 0]], 23 | ',': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 1, 0], [1, 1, 0]], 24 | '%': [[1, 0, 1], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 0, 1]], 25 | '$': [[0, 1, 1], [1, 1, 0], [0, 1, 0], [0, 1, 1], [1, 1, 0]], 26 | '€': [[0, 1, 1], [1, 0, 0], [1, 1, 1], [1, 1, 0], [0, 1, 1]], 27 | '&': [[0, 1, 0], [1, 0, 1], [0, 1, 0], [1, 0, 1], [0, 1, 1]], 28 | '@': [[1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 0], [1, 1, 1]], 29 | ':': [[0, 0, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0], [0, 0, 0]], 30 | ';': [[0, 0, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0], [1, 1, 0]], 31 | 32 | // Numeric 33 | '0': [[1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1]], 34 | '1': [[0, 1, 0], [1, 1, 0], [0, 1, 0], [0, 1, 0], [1, 1, 1]], 35 | '2': [[1, 1, 1], [0, 0, 1], [1, 1, 1], [1, 0, 0], [1, 1, 1]], 36 | '3': [[1, 1, 1], [0, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 37 | '4': [[1, 0, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [0, 0, 1]], 38 | '5': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 39 | '6': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 1], [1, 1, 1]], 40 | '7': [[1, 1, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1]], 41 | '8': [[1, 1, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 1, 1]], 42 | '9': [[1, 1, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 43 | 44 | // Alphabetic 45 | 'A': [[0, 1, 0], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1]], 46 | 'B': [[1, 1, 0], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 1, 0]], 47 | 'C': [[0, 1, 1], [1, 0, 0], [1, 0, 0], [1, 0, 0], [0, 1, 1]], 48 | 'D': [[1, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 0]], 49 | 'E': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 0], [1, 1, 1]], 50 | 'F': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 0], [1, 0, 0]], 51 | 'G': [[0, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 1], [0, 1, 1]], 52 | 'H': [[1, 0, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1]], 53 | 'I': [[1, 1, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0], [1, 1, 1]], 54 | 'J': [[0, 0, 1], [0, 0, 1], [0, 0, 1], [1, 0, 1], [0, 1, 0]], 55 | 'K': [[1, 0, 1], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 0, 1]], 56 | 'L': [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 1, 1]], 57 | 'M': [[1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1]], 58 | 'N': [[1, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1]], 59 | 'O': [[0, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [0, 1, 0]], 60 | 'P': [[1, 1, 0], [1, 0, 1], [1, 1, 1], [1, 0, 0], [1, 0, 0]], 61 | 'Q': [[0, 1, 0], [1, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]], 62 | 'R': [[1, 1, 0], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 0, 1]], 63 | 'S': [[0, 1, 1], [1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0]], 64 | 'T': [[1, 1, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]], 65 | 'U': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1]], 66 | 'V': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [0, 1, 0], [0, 1, 0]], 67 | 'W': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1]], 68 | 'X': [[1, 0, 1], [1, 0, 1], [0, 1, 0], [1, 0, 1], [1, 0, 1]], 69 | 'Y': [[1, 0, 1], [1, 0, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0]], 70 | 'Z': [[1, 1, 1], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 1, 1]] 71 | }; 72 | }; 73 | 74 | module.exports.identifier = { 75 | name:'lowres', 76 | type:'font' 77 | }; 78 | return module.exports; 79 | }); -------------------------------------------------------------------------------- /dist/font-lowres/tick.font.lowres.commonjs.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | module.exports = (function() { 8 | if (!module) { 9 | var module = {}; 10 | } 11 | 'use strict'; 12 | 13 | module.exports = function () { 14 | return { 15 | 16 | // Special Characters 17 | ' ': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]], 18 | '?': [[1, 1, 1], [0, 0, 1], [0, 1, 0], [0, 0, 0], [0, 1, 0]], 19 | '!': [[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0]], 20 | '-': [[0, 0, 0], [0, 0, 0], [1, 1, 1], [0, 0, 0], [0, 0, 0]], 21 | '+': [[0, 0, 0], [0, 1, 0], [1, 1, 1], [0, 1, 0], [0, 0, 0]], 22 | '.': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 1, 0]], 23 | ',': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 1, 0], [1, 1, 0]], 24 | '%': [[1, 0, 1], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 0, 1]], 25 | '$': [[0, 1, 1], [1, 1, 0], [0, 1, 0], [0, 1, 1], [1, 1, 0]], 26 | '€': [[0, 1, 1], [1, 0, 0], [1, 1, 1], [1, 1, 0], [0, 1, 1]], 27 | '&': [[0, 1, 0], [1, 0, 1], [0, 1, 0], [1, 0, 1], [0, 1, 1]], 28 | '@': [[1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 0], [1, 1, 1]], 29 | ':': [[0, 0, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0], [0, 0, 0]], 30 | ';': [[0, 0, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0], [1, 1, 0]], 31 | 32 | // Numeric 33 | '0': [[1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1]], 34 | '1': [[0, 1, 0], [1, 1, 0], [0, 1, 0], [0, 1, 0], [1, 1, 1]], 35 | '2': [[1, 1, 1], [0, 0, 1], [1, 1, 1], [1, 0, 0], [1, 1, 1]], 36 | '3': [[1, 1, 1], [0, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 37 | '4': [[1, 0, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [0, 0, 1]], 38 | '5': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 39 | '6': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 1], [1, 1, 1]], 40 | '7': [[1, 1, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1]], 41 | '8': [[1, 1, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 1, 1]], 42 | '9': [[1, 1, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 43 | 44 | // Alphabetic 45 | 'A': [[0, 1, 0], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1]], 46 | 'B': [[1, 1, 0], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 1, 0]], 47 | 'C': [[0, 1, 1], [1, 0, 0], [1, 0, 0], [1, 0, 0], [0, 1, 1]], 48 | 'D': [[1, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 0]], 49 | 'E': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 0], [1, 1, 1]], 50 | 'F': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 0], [1, 0, 0]], 51 | 'G': [[0, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 1], [0, 1, 1]], 52 | 'H': [[1, 0, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1]], 53 | 'I': [[1, 1, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0], [1, 1, 1]], 54 | 'J': [[0, 0, 1], [0, 0, 1], [0, 0, 1], [1, 0, 1], [0, 1, 0]], 55 | 'K': [[1, 0, 1], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 0, 1]], 56 | 'L': [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 1, 1]], 57 | 'M': [[1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1]], 58 | 'N': [[1, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1]], 59 | 'O': [[0, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [0, 1, 0]], 60 | 'P': [[1, 1, 0], [1, 0, 1], [1, 1, 1], [1, 0, 0], [1, 0, 0]], 61 | 'Q': [[0, 1, 0], [1, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]], 62 | 'R': [[1, 1, 0], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 0, 1]], 63 | 'S': [[0, 1, 1], [1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0]], 64 | 'T': [[1, 1, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]], 65 | 'U': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1]], 66 | 'V': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [0, 1, 0], [0, 1, 0]], 67 | 'W': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1]], 68 | 'X': [[1, 0, 1], [1, 0, 1], [0, 1, 0], [1, 0, 1], [1, 0, 1]], 69 | 'Y': [[1, 0, 1], [1, 0, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0]], 70 | 'Z': [[1, 1, 1], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 1, 1]] 71 | }; 72 | }; 73 | 74 | module.exports.identifier = { 75 | name:'lowres', 76 | type:'font' 77 | }; 78 | return module.exports; 79 | }()); -------------------------------------------------------------------------------- /dist/font-lowres/tick.font.lowres.global.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | (function(root, undefined) { 8 | 'use strict'; 9 | 10 | // only create tick extensions queue if not already available 11 | if (!root.Tick) { 12 | root.Tick = []; 13 | } 14 | 15 | // add this extension 16 | root.Tick.push(['font', 'lowres', (function() { 17 | if (!module) { 18 | var module = {}; 19 | } 20 | 'use strict'; 21 | 22 | module.exports = function () { 23 | return { 24 | 25 | // Special Characters 26 | ' ': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]], 27 | '?': [[1, 1, 1], [0, 0, 1], [0, 1, 0], [0, 0, 0], [0, 1, 0]], 28 | '!': [[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0]], 29 | '-': [[0, 0, 0], [0, 0, 0], [1, 1, 1], [0, 0, 0], [0, 0, 0]], 30 | '+': [[0, 0, 0], [0, 1, 0], [1, 1, 1], [0, 1, 0], [0, 0, 0]], 31 | '.': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 1, 0]], 32 | ',': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 1, 0], [1, 1, 0]], 33 | '%': [[1, 0, 1], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 0, 1]], 34 | '$': [[0, 1, 1], [1, 1, 0], [0, 1, 0], [0, 1, 1], [1, 1, 0]], 35 | '€': [[0, 1, 1], [1, 0, 0], [1, 1, 1], [1, 1, 0], [0, 1, 1]], 36 | '&': [[0, 1, 0], [1, 0, 1], [0, 1, 0], [1, 0, 1], [0, 1, 1]], 37 | '@': [[1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 0], [1, 1, 1]], 38 | ':': [[0, 0, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0], [0, 0, 0]], 39 | ';': [[0, 0, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0], [1, 1, 0]], 40 | 41 | // Numeric 42 | '0': [[1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1]], 43 | '1': [[0, 1, 0], [1, 1, 0], [0, 1, 0], [0, 1, 0], [1, 1, 1]], 44 | '2': [[1, 1, 1], [0, 0, 1], [1, 1, 1], [1, 0, 0], [1, 1, 1]], 45 | '3': [[1, 1, 1], [0, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 46 | '4': [[1, 0, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [0, 0, 1]], 47 | '5': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 48 | '6': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 1], [1, 1, 1]], 49 | '7': [[1, 1, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1]], 50 | '8': [[1, 1, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 1, 1]], 51 | '9': [[1, 1, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 52 | 53 | // Alphabetic 54 | 'A': [[0, 1, 0], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1]], 55 | 'B': [[1, 1, 0], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 1, 0]], 56 | 'C': [[0, 1, 1], [1, 0, 0], [1, 0, 0], [1, 0, 0], [0, 1, 1]], 57 | 'D': [[1, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 0]], 58 | 'E': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 0], [1, 1, 1]], 59 | 'F': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 0], [1, 0, 0]], 60 | 'G': [[0, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 1], [0, 1, 1]], 61 | 'H': [[1, 0, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1]], 62 | 'I': [[1, 1, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0], [1, 1, 1]], 63 | 'J': [[0, 0, 1], [0, 0, 1], [0, 0, 1], [1, 0, 1], [0, 1, 0]], 64 | 'K': [[1, 0, 1], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 0, 1]], 65 | 'L': [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 1, 1]], 66 | 'M': [[1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1]], 67 | 'N': [[1, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1]], 68 | 'O': [[0, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [0, 1, 0]], 69 | 'P': [[1, 1, 0], [1, 0, 1], [1, 1, 1], [1, 0, 0], [1, 0, 0]], 70 | 'Q': [[0, 1, 0], [1, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]], 71 | 'R': [[1, 1, 0], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 0, 1]], 72 | 'S': [[0, 1, 1], [1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0]], 73 | 'T': [[1, 1, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]], 74 | 'U': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1]], 75 | 'V': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [0, 1, 0], [0, 1, 0]], 76 | 'W': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1]], 77 | 'X': [[1, 0, 1], [1, 0, 1], [0, 1, 0], [1, 0, 1], [1, 0, 1]], 78 | 'Y': [[1, 0, 1], [1, 0, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0]], 79 | 'Z': [[1, 1, 1], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 1, 1]] 80 | }; 81 | }; 82 | 83 | module.exports.identifier = { 84 | name:'lowres', 85 | type:'font' 86 | }; 87 | return module.exports; 88 | }())]); 89 | 90 | }(window)); -------------------------------------------------------------------------------- /dist/font-lowres/tick.font.lowres.global.min.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | !function(t,n){"use strict";t.Tick||(t.Tick=[]),t.Tick.push(["font","lowres",function(){if(!t)var t={};return t.exports=function(){return{" ":[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],"?":[[1,1,1],[0,0,1],[0,1,0],[0,0,0],[0,1,0]],"!":[[0,1,0],[0,1,0],[0,1,0],[0,0,0],[0,1,0]],"-":[[0,0,0],[0,0,0],[1,1,1],[0,0,0],[0,0,0]],"+":[[0,0,0],[0,1,0],[1,1,1],[0,1,0],[0,0,0]],".":[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,1,0]],",":[[0,0,0],[0,0,0],[0,0,0],[0,1,0],[1,1,0]],"%":[[1,0,1],[0,0,1],[0,1,0],[1,0,0],[1,0,1]],$:[[0,1,1],[1,1,0],[0,1,0],[0,1,1],[1,1,0]],"€":[[0,1,1],[1,0,0],[1,1,1],[1,1,0],[0,1,1]],"&":[[0,1,0],[1,0,1],[0,1,0],[1,0,1],[0,1,1]],"@":[[1,1,1],[1,0,1],[1,0,1],[1,0,0],[1,1,1]],":":[[0,0,0],[0,1,0],[0,0,0],[0,1,0],[0,0,0]],";":[[0,0,0],[0,1,0],[0,0,0],[0,1,0],[1,1,0]],0:[[1,1,1],[1,0,1],[1,0,1],[1,0,1],[1,1,1]],1:[[0,1,0],[1,1,0],[0,1,0],[0,1,0],[1,1,1]],2:[[1,1,1],[0,0,1],[1,1,1],[1,0,0],[1,1,1]],3:[[1,1,1],[0,0,1],[1,1,1],[0,0,1],[1,1,1]],4:[[1,0,1],[1,0,1],[1,1,1],[0,0,1],[0,0,1]],5:[[1,1,1],[1,0,0],[1,1,1],[0,0,1],[1,1,1]],6:[[1,1,1],[1,0,0],[1,1,1],[1,0,1],[1,1,1]],7:[[1,1,1],[0,0,1],[0,0,1],[0,0,1],[0,0,1]],8:[[1,1,1],[1,0,1],[1,1,1],[1,0,1],[1,1,1]],9:[[1,1,1],[1,0,1],[1,1,1],[0,0,1],[1,1,1]],A:[[0,1,0],[1,0,1],[1,1,1],[1,0,1],[1,0,1]],B:[[1,1,0],[1,0,1],[1,1,0],[1,0,1],[1,1,0]],C:[[0,1,1],[1,0,0],[1,0,0],[1,0,0],[0,1,1]],D:[[1,1,0],[1,0,1],[1,0,1],[1,0,1],[1,1,0]],E:[[1,1,1],[1,0,0],[1,1,1],[1,0,0],[1,1,1]],F:[[1,1,1],[1,0,0],[1,1,1],[1,0,0],[1,0,0]],G:[[0,1,1],[1,0,0],[1,1,1],[1,0,1],[0,1,1]],H:[[1,0,1],[1,0,1],[1,1,1],[1,0,1],[1,0,1]],I:[[1,1,1],[0,1,0],[0,1,0],[0,1,0],[1,1,1]],J:[[0,0,1],[0,0,1],[0,0,1],[1,0,1],[0,1,0]],K:[[1,0,1],[1,0,1],[1,1,0],[1,0,1],[1,0,1]],L:[[1,0,0],[1,0,0],[1,0,0],[1,0,0],[1,1,1]],M:[[1,0,1],[1,1,1],[1,0,1],[1,0,1],[1,0,1]],N:[[1,1,0],[1,0,1],[1,0,1],[1,0,1],[1,0,1]],O:[[0,1,0],[1,0,1],[1,0,1],[1,0,1],[0,1,0]],P:[[1,1,0],[1,0,1],[1,1,1],[1,0,0],[1,0,0]],Q:[[0,1,0],[1,0,1],[1,0,1],[1,1,1],[0,1,1]],R:[[1,1,0],[1,0,1],[1,1,0],[1,0,1],[1,0,1]],S:[[0,1,1],[1,0,0],[0,1,0],[0,0,1],[1,1,0]],T:[[1,1,1],[0,1,0],[0,1,0],[0,1,0],[0,1,0]],U:[[1,0,1],[1,0,1],[1,0,1],[1,0,1],[1,1,1]],V:[[1,0,1],[1,0,1],[1,0,1],[0,1,0],[0,1,0]],W:[[1,0,1],[1,0,1],[1,0,1],[1,1,1],[1,0,1]],X:[[1,0,1],[1,0,1],[0,1,0],[1,0,1],[1,0,1]],Y:[[1,0,1],[1,0,1],[0,1,0],[0,1,0],[0,1,0]],Z:[[1,1,1],[0,0,1],[0,1,0],[1,0,0],[1,1,1]]}},t.exports.identifier={name:"lowres",type:"font"},t.exports}()])}(window); -------------------------------------------------------------------------------- /dist/font-lowres/tick.font.lowres.jquery.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | (function($) { 8 | 'use strict'; 9 | 10 | if (!$) { return; } 11 | 12 | // only create tick extensions queue if not already available 13 | if (!$.tick) { 14 | $.tick = []; 15 | } 16 | 17 | // add this extension 18 | $.tick.push(['font', 'lowres', (function() { 19 | if (!module) { 20 | var module = {}; 21 | } 22 | 'use strict'; 23 | 24 | module.exports = function () { 25 | return { 26 | 27 | // Special Characters 28 | ' ': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]], 29 | '?': [[1, 1, 1], [0, 0, 1], [0, 1, 0], [0, 0, 0], [0, 1, 0]], 30 | '!': [[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0]], 31 | '-': [[0, 0, 0], [0, 0, 0], [1, 1, 1], [0, 0, 0], [0, 0, 0]], 32 | '+': [[0, 0, 0], [0, 1, 0], [1, 1, 1], [0, 1, 0], [0, 0, 0]], 33 | '.': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 1, 0]], 34 | ',': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 1, 0], [1, 1, 0]], 35 | '%': [[1, 0, 1], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 0, 1]], 36 | '$': [[0, 1, 1], [1, 1, 0], [0, 1, 0], [0, 1, 1], [1, 1, 0]], 37 | '€': [[0, 1, 1], [1, 0, 0], [1, 1, 1], [1, 1, 0], [0, 1, 1]], 38 | '&': [[0, 1, 0], [1, 0, 1], [0, 1, 0], [1, 0, 1], [0, 1, 1]], 39 | '@': [[1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 0], [1, 1, 1]], 40 | ':': [[0, 0, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0], [0, 0, 0]], 41 | ';': [[0, 0, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0], [1, 1, 0]], 42 | 43 | // Numeric 44 | '0': [[1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1]], 45 | '1': [[0, 1, 0], [1, 1, 0], [0, 1, 0], [0, 1, 0], [1, 1, 1]], 46 | '2': [[1, 1, 1], [0, 0, 1], [1, 1, 1], [1, 0, 0], [1, 1, 1]], 47 | '3': [[1, 1, 1], [0, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 48 | '4': [[1, 0, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [0, 0, 1]], 49 | '5': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 50 | '6': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 1], [1, 1, 1]], 51 | '7': [[1, 1, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1]], 52 | '8': [[1, 1, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 1, 1]], 53 | '9': [[1, 1, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 54 | 55 | // Alphabetic 56 | 'A': [[0, 1, 0], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1]], 57 | 'B': [[1, 1, 0], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 1, 0]], 58 | 'C': [[0, 1, 1], [1, 0, 0], [1, 0, 0], [1, 0, 0], [0, 1, 1]], 59 | 'D': [[1, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 0]], 60 | 'E': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 0], [1, 1, 1]], 61 | 'F': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 0], [1, 0, 0]], 62 | 'G': [[0, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 1], [0, 1, 1]], 63 | 'H': [[1, 0, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1]], 64 | 'I': [[1, 1, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0], [1, 1, 1]], 65 | 'J': [[0, 0, 1], [0, 0, 1], [0, 0, 1], [1, 0, 1], [0, 1, 0]], 66 | 'K': [[1, 0, 1], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 0, 1]], 67 | 'L': [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 1, 1]], 68 | 'M': [[1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1]], 69 | 'N': [[1, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1]], 70 | 'O': [[0, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [0, 1, 0]], 71 | 'P': [[1, 1, 0], [1, 0, 1], [1, 1, 1], [1, 0, 0], [1, 0, 0]], 72 | 'Q': [[0, 1, 0], [1, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]], 73 | 'R': [[1, 1, 0], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 0, 1]], 74 | 'S': [[0, 1, 1], [1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0]], 75 | 'T': [[1, 1, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]], 76 | 'U': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1]], 77 | 'V': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [0, 1, 0], [0, 1, 0]], 78 | 'W': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1]], 79 | 'X': [[1, 0, 1], [1, 0, 1], [0, 1, 0], [1, 0, 1], [1, 0, 1]], 80 | 'Y': [[1, 0, 1], [1, 0, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0]], 81 | 'Z': [[1, 1, 1], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 1, 1]] 82 | }; 83 | }; 84 | 85 | module.exports.identifier = { 86 | name:'lowres', 87 | type:'font' 88 | }; 89 | return module.exports; 90 | }())]); 91 | 92 | }(window.jQuery)); -------------------------------------------------------------------------------- /dist/font-lowres/tick.font.lowres.jquery.min.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | !function(t){"use strict";t&&(t.tick||(t.tick=[]),t.tick.push(["font","lowres",function(){if(!t)var t={};return t.exports=function(){return{" ":[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],"?":[[1,1,1],[0,0,1],[0,1,0],[0,0,0],[0,1,0]],"!":[[0,1,0],[0,1,0],[0,1,0],[0,0,0],[0,1,0]],"-":[[0,0,0],[0,0,0],[1,1,1],[0,0,0],[0,0,0]],"+":[[0,0,0],[0,1,0],[1,1,1],[0,1,0],[0,0,0]],".":[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,1,0]],",":[[0,0,0],[0,0,0],[0,0,0],[0,1,0],[1,1,0]],"%":[[1,0,1],[0,0,1],[0,1,0],[1,0,0],[1,0,1]],$:[[0,1,1],[1,1,0],[0,1,0],[0,1,1],[1,1,0]],"€":[[0,1,1],[1,0,0],[1,1,1],[1,1,0],[0,1,1]],"&":[[0,1,0],[1,0,1],[0,1,0],[1,0,1],[0,1,1]],"@":[[1,1,1],[1,0,1],[1,0,1],[1,0,0],[1,1,1]],":":[[0,0,0],[0,1,0],[0,0,0],[0,1,0],[0,0,0]],";":[[0,0,0],[0,1,0],[0,0,0],[0,1,0],[1,1,0]],0:[[1,1,1],[1,0,1],[1,0,1],[1,0,1],[1,1,1]],1:[[0,1,0],[1,1,0],[0,1,0],[0,1,0],[1,1,1]],2:[[1,1,1],[0,0,1],[1,1,1],[1,0,0],[1,1,1]],3:[[1,1,1],[0,0,1],[1,1,1],[0,0,1],[1,1,1]],4:[[1,0,1],[1,0,1],[1,1,1],[0,0,1],[0,0,1]],5:[[1,1,1],[1,0,0],[1,1,1],[0,0,1],[1,1,1]],6:[[1,1,1],[1,0,0],[1,1,1],[1,0,1],[1,1,1]],7:[[1,1,1],[0,0,1],[0,0,1],[0,0,1],[0,0,1]],8:[[1,1,1],[1,0,1],[1,1,1],[1,0,1],[1,1,1]],9:[[1,1,1],[1,0,1],[1,1,1],[0,0,1],[1,1,1]],A:[[0,1,0],[1,0,1],[1,1,1],[1,0,1],[1,0,1]],B:[[1,1,0],[1,0,1],[1,1,0],[1,0,1],[1,1,0]],C:[[0,1,1],[1,0,0],[1,0,0],[1,0,0],[0,1,1]],D:[[1,1,0],[1,0,1],[1,0,1],[1,0,1],[1,1,0]],E:[[1,1,1],[1,0,0],[1,1,1],[1,0,0],[1,1,1]],F:[[1,1,1],[1,0,0],[1,1,1],[1,0,0],[1,0,0]],G:[[0,1,1],[1,0,0],[1,1,1],[1,0,1],[0,1,1]],H:[[1,0,1],[1,0,1],[1,1,1],[1,0,1],[1,0,1]],I:[[1,1,1],[0,1,0],[0,1,0],[0,1,0],[1,1,1]],J:[[0,0,1],[0,0,1],[0,0,1],[1,0,1],[0,1,0]],K:[[1,0,1],[1,0,1],[1,1,0],[1,0,1],[1,0,1]],L:[[1,0,0],[1,0,0],[1,0,0],[1,0,0],[1,1,1]],M:[[1,0,1],[1,1,1],[1,0,1],[1,0,1],[1,0,1]],N:[[1,1,0],[1,0,1],[1,0,1],[1,0,1],[1,0,1]],O:[[0,1,0],[1,0,1],[1,0,1],[1,0,1],[0,1,0]],P:[[1,1,0],[1,0,1],[1,1,1],[1,0,0],[1,0,0]],Q:[[0,1,0],[1,0,1],[1,0,1],[1,1,1],[0,1,1]],R:[[1,1,0],[1,0,1],[1,1,0],[1,0,1],[1,0,1]],S:[[0,1,1],[1,0,0],[0,1,0],[0,0,1],[1,1,0]],T:[[1,1,1],[0,1,0],[0,1,0],[0,1,0],[0,1,0]],U:[[1,0,1],[1,0,1],[1,0,1],[1,0,1],[1,1,1]],V:[[1,0,1],[1,0,1],[1,0,1],[0,1,0],[0,1,0]],W:[[1,0,1],[1,0,1],[1,0,1],[1,1,1],[1,0,1]],X:[[1,0,1],[1,0,1],[0,1,0],[1,0,1],[1,0,1]],Y:[[1,0,1],[1,0,1],[0,1,0],[0,1,0],[0,1,0]],Z:[[1,1,1],[0,0,1],[0,1,0],[1,0,0],[1,1,1]]}},t.exports.identifier={name:"lowres",type:"font"},t.exports}()]))}(window.jQuery); -------------------------------------------------------------------------------- /dist/font-lowres/tick.font.lowres.module.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | export default typeof window !== 'undefined' ? (function() { 8 | if (!module) { 9 | var module = {}; 10 | } 11 | 'use strict'; 12 | 13 | module.exports = function () { 14 | return { 15 | 16 | // Special Characters 17 | ' ': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]], 18 | '?': [[1, 1, 1], [0, 0, 1], [0, 1, 0], [0, 0, 0], [0, 1, 0]], 19 | '!': [[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0]], 20 | '-': [[0, 0, 0], [0, 0, 0], [1, 1, 1], [0, 0, 0], [0, 0, 0]], 21 | '+': [[0, 0, 0], [0, 1, 0], [1, 1, 1], [0, 1, 0], [0, 0, 0]], 22 | '.': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 1, 0]], 23 | ',': [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 1, 0], [1, 1, 0]], 24 | '%': [[1, 0, 1], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 0, 1]], 25 | '$': [[0, 1, 1], [1, 1, 0], [0, 1, 0], [0, 1, 1], [1, 1, 0]], 26 | '€': [[0, 1, 1], [1, 0, 0], [1, 1, 1], [1, 1, 0], [0, 1, 1]], 27 | '&': [[0, 1, 0], [1, 0, 1], [0, 1, 0], [1, 0, 1], [0, 1, 1]], 28 | '@': [[1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 0], [1, 1, 1]], 29 | ':': [[0, 0, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0], [0, 0, 0]], 30 | ';': [[0, 0, 0], [0, 1, 0], [0, 0, 0], [0, 1, 0], [1, 1, 0]], 31 | 32 | // Numeric 33 | '0': [[1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1]], 34 | '1': [[0, 1, 0], [1, 1, 0], [0, 1, 0], [0, 1, 0], [1, 1, 1]], 35 | '2': [[1, 1, 1], [0, 0, 1], [1, 1, 1], [1, 0, 0], [1, 1, 1]], 36 | '3': [[1, 1, 1], [0, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 37 | '4': [[1, 0, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [0, 0, 1]], 38 | '5': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 39 | '6': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 1], [1, 1, 1]], 40 | '7': [[1, 1, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1]], 41 | '8': [[1, 1, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 1, 1]], 42 | '9': [[1, 1, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]], 43 | 44 | // Alphabetic 45 | 'A': [[0, 1, 0], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1]], 46 | 'B': [[1, 1, 0], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 1, 0]], 47 | 'C': [[0, 1, 1], [1, 0, 0], [1, 0, 0], [1, 0, 0], [0, 1, 1]], 48 | 'D': [[1, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 0]], 49 | 'E': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 0], [1, 1, 1]], 50 | 'F': [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 0], [1, 0, 0]], 51 | 'G': [[0, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 1], [0, 1, 1]], 52 | 'H': [[1, 0, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1]], 53 | 'I': [[1, 1, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0], [1, 1, 1]], 54 | 'J': [[0, 0, 1], [0, 0, 1], [0, 0, 1], [1, 0, 1], [0, 1, 0]], 55 | 'K': [[1, 0, 1], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 0, 1]], 56 | 'L': [[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 1, 1]], 57 | 'M': [[1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1]], 58 | 'N': [[1, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1]], 59 | 'O': [[0, 1, 0], [1, 0, 1], [1, 0, 1], [1, 0, 1], [0, 1, 0]], 60 | 'P': [[1, 1, 0], [1, 0, 1], [1, 1, 1], [1, 0, 0], [1, 0, 0]], 61 | 'Q': [[0, 1, 0], [1, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]], 62 | 'R': [[1, 1, 0], [1, 0, 1], [1, 1, 0], [1, 0, 1], [1, 0, 1]], 63 | 'S': [[0, 1, 1], [1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 1, 0]], 64 | 'T': [[1, 1, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]], 65 | 'U': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1]], 66 | 'V': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [0, 1, 0], [0, 1, 0]], 67 | 'W': [[1, 0, 1], [1, 0, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1]], 68 | 'X': [[1, 0, 1], [1, 0, 1], [0, 1, 0], [1, 0, 1], [1, 0, 1]], 69 | 'Y': [[1, 0, 1], [1, 0, 1], [0, 1, 0], [0, 1, 0], [0, 1, 0]], 70 | 'Z': [[1, 1, 1], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 1, 1]] 71 | }; 72 | }; 73 | 74 | module.exports.identifier = { 75 | name:'lowres', 76 | type:'font' 77 | }; 78 | return module.exports; 79 | }()) : null; -------------------------------------------------------------------------------- /dist/view-boom/tick.view.boom.amd.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | define(function() { 8 | if (!module) { 9 | var module = {}; 10 | } 11 | 'use strict'; 12 | 13 | var index = (function () { 14 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : API, 15 | request = _ref.Data.request, 16 | performance = _ref.Date.performance, 17 | _ref$View = _ref.View, 18 | rooter = _ref$View.rooter, 19 | destroyer = _ref$View.destroyer, 20 | drawer = _ref$View.drawer, 21 | updater = _ref$View.updater, 22 | styler = _ref$View.styler; 23 | 24 | var AudioContext = typeof window !== 'undefined' ? window.AudioContext || window.webkitAudioContext : null; 25 | var context = AudioContext ? new AudioContext() : null; 26 | 27 | var getBuffer = function getBuffer(context, data, cb) { 28 | context.decodeAudioData(data, function (buffer) { 29 | cb(buffer); 30 | }); 31 | }; 32 | 33 | var preload = function preload(context, files, cb) { 34 | (Array.isArray(files) ? files : [files]).forEach(function (file) { 35 | // load source files 36 | request(file, function (res) { 37 | // handle success response 38 | getBuffer(context, res, cb); 39 | }, function (err) { 40 | // handle error 41 | }, function (xhr) { 42 | // dress up xhr 43 | xhr.responseType = 'arraybuffer'; 44 | }); 45 | }); 46 | }; 47 | 48 | var createSound = function createSound(context, buffer) { 49 | var source = context.createBufferSource(); 50 | source.buffer = buffer; 51 | return source; 52 | }; 53 | 54 | var draw = function draw(state) { 55 | if (!context || state.style.sample === null || !state.style.sample.length) { 56 | return; 57 | } 58 | 59 | if (!state.audioLoaded) { 60 | // create volume node 61 | state.volume = context.createGain(); 62 | state.volume.connect(context.destination); 63 | 64 | // load audio 65 | preload(context, state.style.sample, function (buffer) { 66 | if (!buffer || state.buffer) { 67 | return; 68 | } 69 | state.buffer = buffer; 70 | state.audioLoaded = true; 71 | }); 72 | 73 | // don't play sounds on first draw 74 | return; 75 | } 76 | 77 | // don't play sound if value has not changed 78 | if (state.value === state.lastValue) { 79 | return; 80 | } 81 | 82 | // play sound 83 | var sound = createSound(context, state.buffer); 84 | sound.connect(state.volume); 85 | state.volume.gain.value = state.style.volume; 86 | 87 | var currentDraw = performance(); 88 | var dist = currentDraw - state.lastDraw; 89 | if (dist < state.style.pitchThreshold) { 90 | state.currentPitch = Math.min(state.style.pitchMax, state.currentPitch + state.style.pitchStep); 91 | } else { 92 | state.currentPitch = 1; 93 | } 94 | state.lastDraw = currentDraw; 95 | sound.playbackRate.value = state.currentPitch; 96 | sound.start(context.currentTime); 97 | 98 | // remember this value 99 | state.lastValue = state.value; 100 | }; 101 | 102 | return function (root) { 103 | var state = { 104 | audioLoaded: false, 105 | buffer: null, 106 | lastDraw: 0, 107 | currentPitch: 1, 108 | volume: null, 109 | lastValue: null 110 | }; 111 | 112 | return Object.assign({}, rooter(state, root, 'boom'), updater(state), styler(state, { 113 | sample: null, 114 | volume: 0.5, // range from 0 to 1, 115 | pitchThreshold: 1000, 116 | pitchStep: 0.05, 117 | pitchMax: 1.35 118 | }), destroyer(state), drawer(state, draw)); 119 | }; 120 | }); 121 | 122 | module.exports = index; 123 | 124 | module.exports.identifier = { 125 | name:'boom', 126 | type:'view' 127 | }; 128 | return module.exports; 129 | }); -------------------------------------------------------------------------------- /dist/view-boom/tick.view.boom.commonjs.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | module.exports = (function() { 8 | if (!module) { 9 | var module = {}; 10 | } 11 | 'use strict'; 12 | 13 | var index = (function () { 14 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : API, 15 | request = _ref.Data.request, 16 | performance = _ref.Date.performance, 17 | _ref$View = _ref.View, 18 | rooter = _ref$View.rooter, 19 | destroyer = _ref$View.destroyer, 20 | drawer = _ref$View.drawer, 21 | updater = _ref$View.updater, 22 | styler = _ref$View.styler; 23 | 24 | var AudioContext = typeof window !== 'undefined' ? window.AudioContext || window.webkitAudioContext : null; 25 | var context = AudioContext ? new AudioContext() : null; 26 | 27 | var getBuffer = function getBuffer(context, data, cb) { 28 | context.decodeAudioData(data, function (buffer) { 29 | cb(buffer); 30 | }); 31 | }; 32 | 33 | var preload = function preload(context, files, cb) { 34 | (Array.isArray(files) ? files : [files]).forEach(function (file) { 35 | // load source files 36 | request(file, function (res) { 37 | // handle success response 38 | getBuffer(context, res, cb); 39 | }, function (err) { 40 | // handle error 41 | }, function (xhr) { 42 | // dress up xhr 43 | xhr.responseType = 'arraybuffer'; 44 | }); 45 | }); 46 | }; 47 | 48 | var createSound = function createSound(context, buffer) { 49 | var source = context.createBufferSource(); 50 | source.buffer = buffer; 51 | return source; 52 | }; 53 | 54 | var draw = function draw(state) { 55 | if (!context || state.style.sample === null || !state.style.sample.length) { 56 | return; 57 | } 58 | 59 | if (!state.audioLoaded) { 60 | // create volume node 61 | state.volume = context.createGain(); 62 | state.volume.connect(context.destination); 63 | 64 | // load audio 65 | preload(context, state.style.sample, function (buffer) { 66 | if (!buffer || state.buffer) { 67 | return; 68 | } 69 | state.buffer = buffer; 70 | state.audioLoaded = true; 71 | }); 72 | 73 | // don't play sounds on first draw 74 | return; 75 | } 76 | 77 | // don't play sound if value has not changed 78 | if (state.value === state.lastValue) { 79 | return; 80 | } 81 | 82 | // play sound 83 | var sound = createSound(context, state.buffer); 84 | sound.connect(state.volume); 85 | state.volume.gain.value = state.style.volume; 86 | 87 | var currentDraw = performance(); 88 | var dist = currentDraw - state.lastDraw; 89 | if (dist < state.style.pitchThreshold) { 90 | state.currentPitch = Math.min(state.style.pitchMax, state.currentPitch + state.style.pitchStep); 91 | } else { 92 | state.currentPitch = 1; 93 | } 94 | state.lastDraw = currentDraw; 95 | sound.playbackRate.value = state.currentPitch; 96 | sound.start(context.currentTime); 97 | 98 | // remember this value 99 | state.lastValue = state.value; 100 | }; 101 | 102 | return function (root) { 103 | var state = { 104 | audioLoaded: false, 105 | buffer: null, 106 | lastDraw: 0, 107 | currentPitch: 1, 108 | volume: null, 109 | lastValue: null 110 | }; 111 | 112 | return Object.assign({}, rooter(state, root, 'boom'), updater(state), styler(state, { 113 | sample: null, 114 | volume: 0.5, // range from 0 to 1, 115 | pitchThreshold: 1000, 116 | pitchStep: 0.05, 117 | pitchMax: 1.35 118 | }), destroyer(state), drawer(state, draw)); 119 | }; 120 | }); 121 | 122 | module.exports = index; 123 | 124 | module.exports.identifier = { 125 | name:'boom', 126 | type:'view' 127 | }; 128 | return module.exports; 129 | }()); -------------------------------------------------------------------------------- /dist/view-boom/tick.view.boom.css: -------------------------------------------------------------------------------- 1 | /* 2 | * @pqina/tick v1.8.3 - Counters Made Easy 3 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 4 | */ 5 | [data-view='boom'], 6 | .tick-audio { 7 | display: none; } 8 | -------------------------------------------------------------------------------- /dist/view-boom/tick.view.boom.global.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | (function(root, undefined) { 8 | 'use strict'; 9 | 10 | // only create tick extensions queue if not already available 11 | if (!root.Tick) { 12 | root.Tick = []; 13 | } 14 | 15 | // add this extension 16 | root.Tick.push(['view', 'boom', (function() { 17 | if (!module) { 18 | var module = {}; 19 | } 20 | 'use strict'; 21 | 22 | var index = (function () { 23 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : API, 24 | request = _ref.Data.request, 25 | performance = _ref.Date.performance, 26 | _ref$View = _ref.View, 27 | rooter = _ref$View.rooter, 28 | destroyer = _ref$View.destroyer, 29 | drawer = _ref$View.drawer, 30 | updater = _ref$View.updater, 31 | styler = _ref$View.styler; 32 | 33 | var AudioContext = typeof window !== 'undefined' ? window.AudioContext || window.webkitAudioContext : null; 34 | var context = AudioContext ? new AudioContext() : null; 35 | 36 | var getBuffer = function getBuffer(context, data, cb) { 37 | context.decodeAudioData(data, function (buffer) { 38 | cb(buffer); 39 | }); 40 | }; 41 | 42 | var preload = function preload(context, files, cb) { 43 | (Array.isArray(files) ? files : [files]).forEach(function (file) { 44 | // load source files 45 | request(file, function (res) { 46 | // handle success response 47 | getBuffer(context, res, cb); 48 | }, function (err) { 49 | // handle error 50 | }, function (xhr) { 51 | // dress up xhr 52 | xhr.responseType = 'arraybuffer'; 53 | }); 54 | }); 55 | }; 56 | 57 | var createSound = function createSound(context, buffer) { 58 | var source = context.createBufferSource(); 59 | source.buffer = buffer; 60 | return source; 61 | }; 62 | 63 | var draw = function draw(state) { 64 | if (!context || state.style.sample === null || !state.style.sample.length) { 65 | return; 66 | } 67 | 68 | if (!state.audioLoaded) { 69 | // create volume node 70 | state.volume = context.createGain(); 71 | state.volume.connect(context.destination); 72 | 73 | // load audio 74 | preload(context, state.style.sample, function (buffer) { 75 | if (!buffer || state.buffer) { 76 | return; 77 | } 78 | state.buffer = buffer; 79 | state.audioLoaded = true; 80 | }); 81 | 82 | // don't play sounds on first draw 83 | return; 84 | } 85 | 86 | // don't play sound if value has not changed 87 | if (state.value === state.lastValue) { 88 | return; 89 | } 90 | 91 | // play sound 92 | var sound = createSound(context, state.buffer); 93 | sound.connect(state.volume); 94 | state.volume.gain.value = state.style.volume; 95 | 96 | var currentDraw = performance(); 97 | var dist = currentDraw - state.lastDraw; 98 | if (dist < state.style.pitchThreshold) { 99 | state.currentPitch = Math.min(state.style.pitchMax, state.currentPitch + state.style.pitchStep); 100 | } else { 101 | state.currentPitch = 1; 102 | } 103 | state.lastDraw = currentDraw; 104 | sound.playbackRate.value = state.currentPitch; 105 | sound.start(context.currentTime); 106 | 107 | // remember this value 108 | state.lastValue = state.value; 109 | }; 110 | 111 | return function (root) { 112 | var state = { 113 | audioLoaded: false, 114 | buffer: null, 115 | lastDraw: 0, 116 | currentPitch: 1, 117 | volume: null, 118 | lastValue: null 119 | }; 120 | 121 | return Object.assign({}, rooter(state, root, 'boom'), updater(state), styler(state, { 122 | sample: null, 123 | volume: 0.5, // range from 0 to 1, 124 | pitchThreshold: 1000, 125 | pitchStep: 0.05, 126 | pitchMax: 1.35 127 | }), destroyer(state), drawer(state, draw)); 128 | }; 129 | }); 130 | 131 | module.exports = index; 132 | 133 | module.exports.identifier = { 134 | name:'boom', 135 | type:'view' 136 | }; 137 | return module.exports; 138 | }())]); 139 | 140 | }(window)); -------------------------------------------------------------------------------- /dist/view-boom/tick.view.boom.global.min.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | !function(e,t){"use strict";e.Tick||(e.Tick=[]),e.Tick.push(["view","boom",function(){if(!e)var e={};var n=function(){var e=arguments.length>0&&arguments[0]!==t?arguments[0]:API,n=e.Data.request,r=e.Date.performance,u=e.View,a=u.rooter,i=u.destroyer,o=u.drawer,l=u.updater,c=u.styler,f="undefined"!=typeof window?window.AudioContext||window.webkitAudioContext:null,s=f?new f:null,d=function(e,t,n){e.decodeAudioData(t,function(e){n(e)})},p=function(e,t,r){(Array.isArray(t)?t:[t]).forEach(function(t){n(t,function(t){d(e,t,r)},function(e){},function(e){e.responseType="arraybuffer"})})},v=function(e,t){var n=e.createBufferSource();return n.buffer=t,n},h=function(e){if(s&&null!==e.style.sample&&e.style.sample.length){if(!e.audioLoaded)return e.volume=s.createGain(),e.volume.connect(s.destination),void p(s,e.style.sample,function(t){t&&!e.buffer&&(e.buffer=t,e.audioLoaded=!0)});if(e.value!==e.lastValue){var t=v(s,e.buffer);t.connect(e.volume),e.volume.gain.value=e.style.volume;var n=r(),u=n-e.lastDraw;u 0 && arguments[0] !== undefined ? arguments[0] : API, 26 | request = _ref.Data.request, 27 | performance = _ref.Date.performance, 28 | _ref$View = _ref.View, 29 | rooter = _ref$View.rooter, 30 | destroyer = _ref$View.destroyer, 31 | drawer = _ref$View.drawer, 32 | updater = _ref$View.updater, 33 | styler = _ref$View.styler; 34 | 35 | var AudioContext = typeof window !== 'undefined' ? window.AudioContext || window.webkitAudioContext : null; 36 | var context = AudioContext ? new AudioContext() : null; 37 | 38 | var getBuffer = function getBuffer(context, data, cb) { 39 | context.decodeAudioData(data, function (buffer) { 40 | cb(buffer); 41 | }); 42 | }; 43 | 44 | var preload = function preload(context, files, cb) { 45 | (Array.isArray(files) ? files : [files]).forEach(function (file) { 46 | // load source files 47 | request(file, function (res) { 48 | // handle success response 49 | getBuffer(context, res, cb); 50 | }, function (err) { 51 | // handle error 52 | }, function (xhr) { 53 | // dress up xhr 54 | xhr.responseType = 'arraybuffer'; 55 | }); 56 | }); 57 | }; 58 | 59 | var createSound = function createSound(context, buffer) { 60 | var source = context.createBufferSource(); 61 | source.buffer = buffer; 62 | return source; 63 | }; 64 | 65 | var draw = function draw(state) { 66 | if (!context || state.style.sample === null || !state.style.sample.length) { 67 | return; 68 | } 69 | 70 | if (!state.audioLoaded) { 71 | // create volume node 72 | state.volume = context.createGain(); 73 | state.volume.connect(context.destination); 74 | 75 | // load audio 76 | preload(context, state.style.sample, function (buffer) { 77 | if (!buffer || state.buffer) { 78 | return; 79 | } 80 | state.buffer = buffer; 81 | state.audioLoaded = true; 82 | }); 83 | 84 | // don't play sounds on first draw 85 | return; 86 | } 87 | 88 | // don't play sound if value has not changed 89 | if (state.value === state.lastValue) { 90 | return; 91 | } 92 | 93 | // play sound 94 | var sound = createSound(context, state.buffer); 95 | sound.connect(state.volume); 96 | state.volume.gain.value = state.style.volume; 97 | 98 | var currentDraw = performance(); 99 | var dist = currentDraw - state.lastDraw; 100 | if (dist < state.style.pitchThreshold) { 101 | state.currentPitch = Math.min(state.style.pitchMax, state.currentPitch + state.style.pitchStep); 102 | } else { 103 | state.currentPitch = 1; 104 | } 105 | state.lastDraw = currentDraw; 106 | sound.playbackRate.value = state.currentPitch; 107 | sound.start(context.currentTime); 108 | 109 | // remember this value 110 | state.lastValue = state.value; 111 | }; 112 | 113 | return function (root) { 114 | var state = { 115 | audioLoaded: false, 116 | buffer: null, 117 | lastDraw: 0, 118 | currentPitch: 1, 119 | volume: null, 120 | lastValue: null 121 | }; 122 | 123 | return Object.assign({}, rooter(state, root, 'boom'), updater(state), styler(state, { 124 | sample: null, 125 | volume: 0.5, // range from 0 to 1, 126 | pitchThreshold: 1000, 127 | pitchStep: 0.05, 128 | pitchMax: 1.35 129 | }), destroyer(state), drawer(state, draw)); 130 | }; 131 | }); 132 | 133 | module.exports = index; 134 | 135 | module.exports.identifier = { 136 | name:'boom', 137 | type:'view' 138 | }; 139 | return module.exports; 140 | }())]); 141 | 142 | }(window.jQuery)); -------------------------------------------------------------------------------- /dist/view-boom/tick.view.boom.jquery.min.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | !function(e){"use strict";e&&(e.tick||(e.tick=[]),e.tick.push(["view","boom",function(){if(!e)var e={};var t=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:API,t=e.Data.request,n=e.Date.performance,r=e.View,u=r.rooter,i=r.destroyer,o=r.drawer,a=r.updater,l=r.styler,c="undefined"!=typeof window?window.AudioContext||window.webkitAudioContext:null,f=c?new c:null,s=function(e,t,n){e.decodeAudioData(t,function(e){n(e)})},d=function(e,n,r){(Array.isArray(n)?n:[n]).forEach(function(n){t(n,function(t){s(e,t,r)},function(e){},function(e){e.responseType="arraybuffer"})})},p=function(e,t){var n=e.createBufferSource();return n.buffer=t,n},v=function(e){if(f&&null!==e.style.sample&&e.style.sample.length){if(!e.audioLoaded)return e.volume=f.createGain(),e.volume.connect(f.destination),void d(f,e.style.sample,function(t){t&&!e.buffer&&(e.buffer=t,e.audioLoaded=!0)});if(e.value!==e.lastValue){var t=p(f,e.buffer);t.connect(e.volume),e.volume.gain.value=e.style.volume;var r=n(),u=r-e.lastDraw;u 0 && arguments[0] !== undefined ? arguments[0] : API, 15 | request = _ref.Data.request, 16 | performance = _ref.Date.performance, 17 | _ref$View = _ref.View, 18 | rooter = _ref$View.rooter, 19 | destroyer = _ref$View.destroyer, 20 | drawer = _ref$View.drawer, 21 | updater = _ref$View.updater, 22 | styler = _ref$View.styler; 23 | 24 | var AudioContext = typeof window !== 'undefined' ? window.AudioContext || window.webkitAudioContext : null; 25 | var context = AudioContext ? new AudioContext() : null; 26 | 27 | var getBuffer = function getBuffer(context, data, cb) { 28 | context.decodeAudioData(data, function (buffer) { 29 | cb(buffer); 30 | }); 31 | }; 32 | 33 | var preload = function preload(context, files, cb) { 34 | (Array.isArray(files) ? files : [files]).forEach(function (file) { 35 | // load source files 36 | request(file, function (res) { 37 | // handle success response 38 | getBuffer(context, res, cb); 39 | }, function (err) { 40 | // handle error 41 | }, function (xhr) { 42 | // dress up xhr 43 | xhr.responseType = 'arraybuffer'; 44 | }); 45 | }); 46 | }; 47 | 48 | var createSound = function createSound(context, buffer) { 49 | var source = context.createBufferSource(); 50 | source.buffer = buffer; 51 | return source; 52 | }; 53 | 54 | var draw = function draw(state) { 55 | if (!context || state.style.sample === null || !state.style.sample.length) { 56 | return; 57 | } 58 | 59 | if (!state.audioLoaded) { 60 | // create volume node 61 | state.volume = context.createGain(); 62 | state.volume.connect(context.destination); 63 | 64 | // load audio 65 | preload(context, state.style.sample, function (buffer) { 66 | if (!buffer || state.buffer) { 67 | return; 68 | } 69 | state.buffer = buffer; 70 | state.audioLoaded = true; 71 | }); 72 | 73 | // don't play sounds on first draw 74 | return; 75 | } 76 | 77 | // don't play sound if value has not changed 78 | if (state.value === state.lastValue) { 79 | return; 80 | } 81 | 82 | // play sound 83 | var sound = createSound(context, state.buffer); 84 | sound.connect(state.volume); 85 | state.volume.gain.value = state.style.volume; 86 | 87 | var currentDraw = performance(); 88 | var dist = currentDraw - state.lastDraw; 89 | if (dist < state.style.pitchThreshold) { 90 | state.currentPitch = Math.min(state.style.pitchMax, state.currentPitch + state.style.pitchStep); 91 | } else { 92 | state.currentPitch = 1; 93 | } 94 | state.lastDraw = currentDraw; 95 | sound.playbackRate.value = state.currentPitch; 96 | sound.start(context.currentTime); 97 | 98 | // remember this value 99 | state.lastValue = state.value; 100 | }; 101 | 102 | return function (root) { 103 | var state = { 104 | audioLoaded: false, 105 | buffer: null, 106 | lastDraw: 0, 107 | currentPitch: 1, 108 | volume: null, 109 | lastValue: null 110 | }; 111 | 112 | return Object.assign({}, rooter(state, root, 'boom'), updater(state), styler(state, { 113 | sample: null, 114 | volume: 0.5, // range from 0 to 1, 115 | pitchThreshold: 1000, 116 | pitchStep: 0.05, 117 | pitchMax: 1.35 118 | }), destroyer(state), drawer(state, draw)); 119 | }; 120 | }); 121 | 122 | module.exports = index; 123 | 124 | module.exports.identifier = { 125 | name:'boom', 126 | type:'view' 127 | }; 128 | return module.exports; 129 | }()) : null; -------------------------------------------------------------------------------- /dist/view-dots/tick.view.dots.css: -------------------------------------------------------------------------------- 1 | /* 2 | * @pqina/tick v1.8.3 - Counters Made Easy 3 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 4 | */ 5 | .tick-dots { 6 | vertical-align: middle; 7 | white-space: nowrap; } 8 | .tick-dots .tick-dots-display { 9 | display: -webkit-box; 10 | display: -webkit-flex; 11 | display: -ms-flexbox; 12 | display: flex; 13 | -webkit-box-orient: horizontal; 14 | -webkit-box-direction: normal; 15 | -webkit-flex-direction: row; 16 | -ms-flex-direction: row; 17 | flex-direction: row; 18 | -webkit-flex-wrap: nowrap; 19 | -ms-flex-wrap: nowrap; 20 | flex-wrap: nowrap; 21 | -webkit-box-pack: center; 22 | -webkit-justify-content: center; 23 | -ms-flex-pack: center; 24 | justify-content: center; } 25 | .tick-dots .tick-dots-character > div { 26 | line-height: 0; } 27 | .tick-dots .tick-dots-character > div > div { 28 | display: inline-block; 29 | -webkit-perspective: 4em; 30 | perspective: 4em; 31 | vertical-align: top; } 32 | .tick-dots .tick-dots-dot { 33 | display: block; 34 | outline: 1px solid transparent; } 35 | .tick-dots[data-style*='square'] .tick-dots-dot { 36 | border-radius: 0 !important; } 37 | .tick-dots[data-style*='round'] .tick-dots-dot, 38 | .tick-dots[data-style*='circle'] .tick-dots-dot { 39 | border-radius: 9999px !important; } 40 | 41 | .tick-dots-character { 42 | margin: 0 .25em; } 43 | 44 | .tick-dots-dot { 45 | width: 5px; 46 | height: 5px; 47 | margin: 1px; 48 | background-color: currentColor; 49 | border-radius: 2px; } 50 | -------------------------------------------------------------------------------- /dist/view-dots/tick.view.dots.global.min.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | !function(t,n){"use strict";t.Tick||(t.Tick=[]),t.Tick.push(["view","dots",function(){if(!t)var t={};var r={},e=function(t,n){var e=n.toString();return r[e]||(r[e]={}),r[e][t]||(r[e][t]=n(t)),r[e][t]},a=function(t){return"rgba("+t.map(function(t,n){return n<3?Math.round(255*t):t}).join(",")+")"},i=function(t,n,r){return t.map(function(t,e){return t+(n[e]-t)*r})},o=function(t){var n=t.match(/[.\d]+/g).map(function(t,n){return n<3?parseFloat(t)/255:parseFloat(t)});return 4===n.length?n:n.concat([1])},l=function(t,n){var r=0,l=t.length-1,s=t[0],u=t[t.length-1];s.offset&&s.offset>0&&t.unshift({offset:0,value:s.value}),u.offset&&u.offset<1&&t.push({offset:1,value:u.value});var f=t.map(function(t,n){return r=t.offset||Math.max(n/l,r),{offset:r,value:e(t.value,o).concat()}}),c=f.reduce(function(t,r,e){var a=r.value;if(0===e)t.push(a);else if(e>0)for(var o=t[t.length-1],l=(t.length-1)/n,s=Math.round(n*(r.offset-l)),u=1;u<=s;u++)t.push(i(o,a,u/s));return t},[]);return c.map(a)},s=function(){var t=arguments.length>0&&arguments[0]!==n?arguments[0]:API,r=t.DOM,e=t.Extension,a=t.View,i=a.rooter,o=a.destroyer,s=a.drawer,u=a.updater,f=a.styler,c=function(t){var n=t[0];return{width:n[0].length,height:n.length}},d=function(t){if(!t.a)for(var n=65,r=97,e=122,a=0,i=e-r;a<=i;a++)t[String.fromCharCode(r+a)]=t[String.fromCharCode(n+a)];return t},h=function(t,n,r){r?(t.skipToTransitionInEnd(n),n.setAttribute("data-enabled","true")):(t.skipToTransitionOutEnd(n),n.setAttribute("data-enabled","false")),n.setAttribute("data-initialised","true")},v=function(t,n,r){r?t.transitionIn(n):t.transitionOut(n)},p=function(t,n,r,e){setTimeout(function(){v(t,n,r)},e)},g=function(t,n){var r="true"===t.enabled;return n!==r},y=function(t,n,r){for(var e=0,a=0,i=n.length,o=n[0].length;a0;)t.removeChild(t.firstChild),n--},w=function(t,n,r){for(var e="",a=0;a";for(var i=0;i';e+=""}return'
'+e+"
"},M=function(t,n,r,e){for(var a=c(r),i=a.width,o=a.height,l=0;l0?M(t.display,i,t.font,t.colorMatrix):T(t.display,Math.abs(i)),t.slots=b(t.display));var o=t.isInitialValue(),l=0,s=0,u="right"===t.style.align?n.split("").reverse():n.split(""),f=t.style.characterUpdateDelay+t.style.dotUpdateDelay>0?p:v;u.map(function(n,r){return t.current[r]===n?null:n}).forEach(function(r,e){null!==r&&y(t.font[r]||t.font[" "],t.slots["right"===t.style.align?n.length-e-1:e],function(n,r){var a=n.dataset;"false"===a.initialised&&(h(t,n,!!o&&r),o)||g(a,r)&&(a.enabled=r?"true":"false",l++,s=t.style.characterUpdateDelay*e+t.style.dotUpdateDelay*l,f(t,n,r,s))})}),t.current=u.concat()};return function(t){var n={current:[],display:null,font:null,colorMatrix:null,size:null,slots:[]};return Object.assign({},i(n,t,"dots"),u(n),f(n,{color:"auto",font:"highres",shape:"auto",align:"right",dotUpdateDelay:10,characterUpdateDelay:0,transition:[{name:"crossfade",duration:500}],transitionIn:[],transitionOut:[]}),s(n,x),o(n))}};return t.exports=s,t.exports.identifier={name:"dots",type:"view"},t.exports}()])}(window); -------------------------------------------------------------------------------- /dist/view-dots/tick.view.dots.jquery.min.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | !function(t){"use strict";t&&(t.tick||(t.tick=[]),t.tick.push(["view","dots",function(){if(!t)var t={};var n={},r=function(t,r){var e=r.toString();return n[e]||(n[e]={}),n[e][t]||(n[e][t]=r(t)),n[e][t]},e=function(t){return"rgba("+t.map(function(t,n){return n<3?Math.round(255*t):t}).join(",")+")"},a=function(t,n,r){return t.map(function(t,e){return t+(n[e]-t)*r})},i=function(t){var n=t.match(/[.\d]+/g).map(function(t,n){return n<3?parseFloat(t)/255:parseFloat(t)});return 4===n.length?n:n.concat([1])},o=function(t,n){var o=0,l=t.length-1,s=t[0],u=t[t.length-1];s.offset&&s.offset>0&&t.unshift({offset:0,value:s.value}),u.offset&&u.offset<1&&t.push({offset:1,value:u.value});var f=t.map(function(t,n){return o=t.offset||Math.max(n/l,o),{offset:o,value:r(t.value,i).concat()}}),d=f.reduce(function(t,r,e){var i=r.value;if(0===e)t.push(i);else if(e>0)for(var o=t[t.length-1],l=(t.length-1)/n,s=Math.round(n*(r.offset-l)),u=1;u<=s;u++)t.push(a(o,i,u/s));return t},[]);return d.map(e)},l=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:API,n=t.DOM,r=t.Extension,e=t.View,a=e.rooter,i=e.destroyer,l=e.drawer,s=e.updater,u=e.styler,f=function(t){var n=t[0];return{width:n[0].length,height:n.length}},d=function(t){if(!t.a)for(var n=65,r=97,e=122,a=0,i=e-r;a<=i;a++)t[String.fromCharCode(r+a)]=t[String.fromCharCode(n+a)];return t},c=function(t,n,r){r?(t.skipToTransitionInEnd(n),n.setAttribute("data-enabled","true")):(t.skipToTransitionOutEnd(n),n.setAttribute("data-enabled","false")),n.setAttribute("data-initialised","true")},h=function(t,n,r){r?t.transitionIn(n):t.transitionOut(n)},v=function(t,n,r,e){setTimeout(function(){h(t,n,r)},e)},p=function(t,n){var r="true"===t.enabled;return n!==r},g=function(t,n,r){for(var e=0,a=0,i=n.length,o=n[0].length;a0;)t.removeChild(t.firstChild),n--},w=function(t,n,r){for(var e="",a=0;a";for(var i=0;i';e+=""}return'
'+e+"
"},M=function(t,n,r,e){for(var a=f(r),i=a.width,o=a.height,l=0;l0?M(t.display,i,t.font,t.colorMatrix):b(t.display,Math.abs(i)),t.slots=m(t.display));var o=t.isInitialValue(),l=0,s=0,u="right"===t.style.align?e.split("").reverse():e.split(""),y=t.style.characterUpdateDelay+t.style.dotUpdateDelay>0?v:h;u.map(function(n,r){return t.current[r]===n?null:n}).forEach(function(n,r){null!==n&&g(t.font[n]||t.font[" "],t.slots["right"===t.style.align?e.length-r-1:r],function(n,e){var a=n.dataset;"false"===a.initialised&&(c(t,n,!!o&&e),o)||p(a,e)&&(a.enabled=e?"true":"false",l++,s=t.style.characterUpdateDelay*r+t.style.dotUpdateDelay*l,y(t,n,e,s))})}),t.current=u.concat()};return function(t){var n={current:[],display:null,font:null,colorMatrix:null,size:null,slots:[]};return Object.assign({},a(n,t,"dots"),s(n),u(n,{color:"auto",font:"highres",shape:"auto",align:"right",dotUpdateDelay:10,characterUpdateDelay:0,transition:[{name:"crossfade",duration:500}],transitionIn:[],transitionOut:[]}),l(n,x),i(n))}};return t.exports=l,t.exports.identifier={name:"dots",type:"view"},t.exports}()]))}(window.jQuery); -------------------------------------------------------------------------------- /dist/view-dots/tick.view.dots.min.css: -------------------------------------------------------------------------------- 1 | /* 2 | * @pqina/tick v1.8.3 - Counters Made Easy 3 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 4 | */ 5 | .tick-dots{vertical-align:middle;white-space:nowrap}.tick-dots .tick-dots-display{display:-ms-flexbox;display:flex;-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-ms-flex-pack:center;justify-content:center}.tick-dots .tick-dots-character>div{line-height:0}.tick-dots .tick-dots-character>div>div{display:inline-block;perspective:4em;vertical-align:top}.tick-dots .tick-dots-dot{display:block;outline:1px solid transparent}.tick-dots[data-style*=square] .tick-dots-dot{border-radius:0!important}.tick-dots[data-style*=circle] .tick-dots-dot,.tick-dots[data-style*=round] .tick-dots-dot{border-radius:9999px!important}.tick-dots-character{margin:0 .25em}.tick-dots-dot{width:5px;height:5px;margin:1px;background-color:currentColor;border-radius:2px} -------------------------------------------------------------------------------- /dist/view-line/tick.view.line.css: -------------------------------------------------------------------------------- 1 | /* 2 | * @pqina/tick v1.8.3 - Counters Made Easy 3 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 4 | */ 5 | /** 6 | * Bar 7 | */ 8 | .tick-line-rail { 9 | display: block; 10 | overflow: hidden; 11 | position: relative; 12 | -webkit-transform: translateZ(0); 13 | transform: translateZ(0); } 14 | 15 | .tick-line-fill { 16 | position: absolute; 17 | height: 100%; 18 | width: 100%; 19 | -webkit-backface-visibility: hidden; 20 | backface-visibility: hidden; } 21 | 22 | .tick-line[data-style*='round'] .tick-line-fill, 23 | .tick-line[data-style*='round'] .tick-line-rail { 24 | border-radius: 9999px; } 25 | 26 | .tick :not([data-style*='vertical']) .tick-line-rail { 27 | min-width: 2em; 28 | min-height: .125em; } 29 | .tick :not([data-style*='vertical']) .tick-line-rail .tick-line-fill { 30 | left: -100%; 31 | top: 0; } 32 | 33 | .tick [data-style*='vertical'] .tick-line-rail { 34 | display: inline-block; 35 | vertical-align: top; 36 | min-height: 2em; 37 | min-width: .125em; } 38 | .tick [data-style*='vertical'] .tick-line-rail .tick-line-fill { 39 | left: 0; 40 | top: 100%; } 41 | 42 | /** 43 | * Ring default styles 44 | */ 45 | .tick-line { 46 | z-index: -1; } 47 | .tick-line > canvas { 48 | display: block; 49 | width: 100%; 50 | max-width: 100%; } 51 | 52 | .tick-line-rail { 53 | background-color: #eee; } 54 | 55 | .tick-line-fill { 56 | background-color: currentColor; } 57 | -------------------------------------------------------------------------------- /dist/view-line/tick.view.line.min.css: -------------------------------------------------------------------------------- 1 | /* 2 | * @pqina/tick v1.8.3 - Counters Made Easy 3 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 4 | */ 5 | .tick-line-rail{display:block;overflow:hidden;position:relative;transform:translateZ(0)}.tick-line-fill{position:absolute;height:100%;width:100%;backface-visibility:hidden}.tick-line[data-style*=round] .tick-line-fill,.tick-line[data-style*=round] .tick-line-rail{border-radius:9999px}.tick :not([data-style*=vertical]) .tick-line-rail{min-width:2em;min-height:.125em}.tick :not([data-style*=vertical]) .tick-line-rail .tick-line-fill{left:-100%;top:0}.tick [data-style*=vertical] .tick-line-rail{display:inline-block;vertical-align:top;min-height:2em;min-width:.125em}.tick [data-style*=vertical] .tick-line-rail .tick-line-fill{left:0;top:100%}.tick-line{z-index:-1}.tick-line>canvas{display:block;width:100%;max-width:100%}.tick-line-rail{background-color:#eee}.tick-line-fill{background-color:currentColor} -------------------------------------------------------------------------------- /dist/view-swap/tick.view.swap.amd.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | define(function() { 8 | if (!module) { 9 | var module = {}; 10 | } 11 | 'use strict'; 12 | 13 | var index = (function () { 14 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : API, 15 | DOM = _ref.DOM, 16 | _ref$View = _ref.View, 17 | rooter = _ref$View.rooter, 18 | destroyer = _ref$View.destroyer, 19 | drawer = _ref$View.drawer, 20 | updater = _ref$View.updater, 21 | styler = _ref$View.styler; 22 | 23 | var draw = function draw(state) { 24 | 25 | if (!state.spacer) { 26 | 27 | // remove initial content 28 | state.root.textContent = ''; 29 | 30 | state.spacer = DOM.create('span', 'tick-swap-spacer'); 31 | state.root.appendChild(state.spacer); 32 | } 33 | 34 | // set value 35 | state.spacer.textContent = state.value; 36 | 37 | // remove finished transitions 38 | state.textTransitions = state.textTransitions.filter(function (textTransition) { 39 | return !textTransition.hidden; 40 | }); 41 | 42 | var currentText = state.textTransitions[state.textTransitions.length - 1]; 43 | 44 | // get current value 45 | var currentValue = currentText ? currentText.value : 0; 46 | 47 | // calculate animation direction 48 | var direction = state.style.transitionDirection === 'detect' ? state.value - currentValue : state.style.transitionDirection === 'reverse' ? -1 : 1; 49 | 50 | // hide all previous transitions 51 | state.textTransitions.forEach(function (textTransition) { 52 | textTransition.hide(direction); 53 | }); 54 | 55 | // create animation 56 | var nextText = createTextTransition(state.value, state.transitionIn, state.transitionOut); 57 | nextText.appendTo(state.root); 58 | 59 | if (state.isInitialValue()) { 60 | nextText.showNow(); 61 | } else { 62 | nextText.show(direction); 63 | } 64 | 65 | state.textTransitions.push(nextText); 66 | }; 67 | 68 | var createTextTransition = function createTextTransition(text, transitionIn, transitionOut) { 69 | 70 | var state = { 71 | shouldHide: false, 72 | hiding: false, 73 | hidden: false, 74 | shown: false, 75 | value: text 76 | }; 77 | 78 | var root = DOM.create('span', 'tick-swap-transition'); 79 | root.textContent = text; 80 | root.dataset.value = text; 81 | 82 | var api = { 83 | showNow: function showNow() { 84 | state.shown = true; 85 | }, 86 | show: function show(direction) { 87 | 88 | // animate into view 89 | 90 | (direction > 0 ? transitionIn : transitionOut)(state.root, direction, function () { 91 | 92 | // done, test if should hide 93 | state.shown = true; 94 | 95 | // hide immidiately if the hide method has been called earlier 96 | if (state.shouldHide) { 97 | api.hide(direction); 98 | } 99 | }); 100 | }, 101 | hide: function hide(direction) { 102 | 103 | // already hiding 104 | if (state.hiding || state.hidden) { 105 | return; 106 | } 107 | 108 | // should be hidden when shown 109 | state.shouldHide = true; 110 | 111 | // are we shown yet? 112 | if (!state.shown) { 113 | return; 114 | } 115 | 116 | // already hiding 117 | state.hiding = true; 118 | 119 | // yes we are, let's hide immidiately 120 | (direction > 0 ? transitionOut : transitionIn)(state.root, direction, function () { 121 | 122 | // no longer hiding 123 | state.hiding = false; 124 | 125 | // clean up 126 | state.hidden = true; 127 | 128 | // remove from DOM 129 | state.root.parentNode.removeChild(state.root); 130 | }); 131 | } 132 | }; 133 | 134 | Object.defineProperty(api, 'value', { 135 | get: function get() { 136 | return state.value; 137 | } 138 | }); 139 | 140 | return Object.assign(api, rooter(state, root)); 141 | }; 142 | 143 | return function (root) { 144 | 145 | var state = { 146 | spacer: null, 147 | textTransitions: [] 148 | }; 149 | 150 | return Object.assign({}, rooter(state, root, 'swap'), updater(state), styler(state, { 151 | transition: [{ name: 'crossfade' }], 152 | transitionIn: [], 153 | transitionOut: [], 154 | transitionDirection: 'forward' // 'forward', 'reverse', 'detect' 155 | }), drawer(state, draw), destroyer(state)); 156 | }; 157 | }); 158 | 159 | module.exports = index; 160 | 161 | module.exports.identifier = { 162 | name:'swap', 163 | type:'view' 164 | }; 165 | return module.exports; 166 | }); -------------------------------------------------------------------------------- /dist/view-swap/tick.view.swap.commonjs.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | module.exports = (function() { 8 | if (!module) { 9 | var module = {}; 10 | } 11 | 'use strict'; 12 | 13 | var index = (function () { 14 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : API, 15 | DOM = _ref.DOM, 16 | _ref$View = _ref.View, 17 | rooter = _ref$View.rooter, 18 | destroyer = _ref$View.destroyer, 19 | drawer = _ref$View.drawer, 20 | updater = _ref$View.updater, 21 | styler = _ref$View.styler; 22 | 23 | var draw = function draw(state) { 24 | 25 | if (!state.spacer) { 26 | 27 | // remove initial content 28 | state.root.textContent = ''; 29 | 30 | state.spacer = DOM.create('span', 'tick-swap-spacer'); 31 | state.root.appendChild(state.spacer); 32 | } 33 | 34 | // set value 35 | state.spacer.textContent = state.value; 36 | 37 | // remove finished transitions 38 | state.textTransitions = state.textTransitions.filter(function (textTransition) { 39 | return !textTransition.hidden; 40 | }); 41 | 42 | var currentText = state.textTransitions[state.textTransitions.length - 1]; 43 | 44 | // get current value 45 | var currentValue = currentText ? currentText.value : 0; 46 | 47 | // calculate animation direction 48 | var direction = state.style.transitionDirection === 'detect' ? state.value - currentValue : state.style.transitionDirection === 'reverse' ? -1 : 1; 49 | 50 | // hide all previous transitions 51 | state.textTransitions.forEach(function (textTransition) { 52 | textTransition.hide(direction); 53 | }); 54 | 55 | // create animation 56 | var nextText = createTextTransition(state.value, state.transitionIn, state.transitionOut); 57 | nextText.appendTo(state.root); 58 | 59 | if (state.isInitialValue()) { 60 | nextText.showNow(); 61 | } else { 62 | nextText.show(direction); 63 | } 64 | 65 | state.textTransitions.push(nextText); 66 | }; 67 | 68 | var createTextTransition = function createTextTransition(text, transitionIn, transitionOut) { 69 | 70 | var state = { 71 | shouldHide: false, 72 | hiding: false, 73 | hidden: false, 74 | shown: false, 75 | value: text 76 | }; 77 | 78 | var root = DOM.create('span', 'tick-swap-transition'); 79 | root.textContent = text; 80 | root.dataset.value = text; 81 | 82 | var api = { 83 | showNow: function showNow() { 84 | state.shown = true; 85 | }, 86 | show: function show(direction) { 87 | 88 | // animate into view 89 | 90 | (direction > 0 ? transitionIn : transitionOut)(state.root, direction, function () { 91 | 92 | // done, test if should hide 93 | state.shown = true; 94 | 95 | // hide immidiately if the hide method has been called earlier 96 | if (state.shouldHide) { 97 | api.hide(direction); 98 | } 99 | }); 100 | }, 101 | hide: function hide(direction) { 102 | 103 | // already hiding 104 | if (state.hiding || state.hidden) { 105 | return; 106 | } 107 | 108 | // should be hidden when shown 109 | state.shouldHide = true; 110 | 111 | // are we shown yet? 112 | if (!state.shown) { 113 | return; 114 | } 115 | 116 | // already hiding 117 | state.hiding = true; 118 | 119 | // yes we are, let's hide immidiately 120 | (direction > 0 ? transitionOut : transitionIn)(state.root, direction, function () { 121 | 122 | // no longer hiding 123 | state.hiding = false; 124 | 125 | // clean up 126 | state.hidden = true; 127 | 128 | // remove from DOM 129 | state.root.parentNode.removeChild(state.root); 130 | }); 131 | } 132 | }; 133 | 134 | Object.defineProperty(api, 'value', { 135 | get: function get() { 136 | return state.value; 137 | } 138 | }); 139 | 140 | return Object.assign(api, rooter(state, root)); 141 | }; 142 | 143 | return function (root) { 144 | 145 | var state = { 146 | spacer: null, 147 | textTransitions: [] 148 | }; 149 | 150 | return Object.assign({}, rooter(state, root, 'swap'), updater(state), styler(state, { 151 | transition: [{ name: 'crossfade' }], 152 | transitionIn: [], 153 | transitionOut: [], 154 | transitionDirection: 'forward' // 'forward', 'reverse', 'detect' 155 | }), drawer(state, draw), destroyer(state)); 156 | }; 157 | }); 158 | 159 | module.exports = index; 160 | 161 | module.exports.identifier = { 162 | name:'swap', 163 | type:'view' 164 | }; 165 | return module.exports; 166 | }()); -------------------------------------------------------------------------------- /dist/view-swap/tick.view.swap.css: -------------------------------------------------------------------------------- 1 | /* 2 | * @pqina/tick v1.8.3 - Counters Made Easy 3 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 4 | */ 5 | .tick-swap { 6 | position: relative; } 7 | .tick-swap[data-style*='transition'] { 8 | -webkit-perspective: 4em; 9 | perspective: 4em; 10 | -webkit-transform-style: preserve-3d; 11 | transform-style: preserve-3d; } 12 | .tick-swap .tick-swap-spacer { 13 | position: relative; 14 | display: block; 15 | white-space: pre; 16 | visibility: hidden; } 17 | .tick-swap .tick-swap-transition, 18 | .tick-swap .tick-swap-spacer { 19 | -webkit-backface-visibility: hidden; 20 | backface-visibility: hidden; } 21 | .tick-swap .tick-swap-transition { 22 | position: absolute; 23 | top: 0; 24 | left: 0; 25 | width: 100%; 26 | height: 100%; 27 | z-index: 2; } 28 | 29 | .tick-swap[data-style*='transition'] { 30 | min-width: 1ex; 31 | text-align: center; } 32 | -------------------------------------------------------------------------------- /dist/view-swap/tick.view.swap.global.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | (function(root, undefined) { 8 | 'use strict'; 9 | 10 | // only create tick extensions queue if not already available 11 | if (!root.Tick) { 12 | root.Tick = []; 13 | } 14 | 15 | // add this extension 16 | root.Tick.push(['view', 'swap', (function() { 17 | if (!module) { 18 | var module = {}; 19 | } 20 | 'use strict'; 21 | 22 | var index = (function () { 23 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : API, 24 | DOM = _ref.DOM, 25 | _ref$View = _ref.View, 26 | rooter = _ref$View.rooter, 27 | destroyer = _ref$View.destroyer, 28 | drawer = _ref$View.drawer, 29 | updater = _ref$View.updater, 30 | styler = _ref$View.styler; 31 | 32 | var draw = function draw(state) { 33 | 34 | if (!state.spacer) { 35 | 36 | // remove initial content 37 | state.root.textContent = ''; 38 | 39 | state.spacer = DOM.create('span', 'tick-swap-spacer'); 40 | state.root.appendChild(state.spacer); 41 | } 42 | 43 | // set value 44 | state.spacer.textContent = state.value; 45 | 46 | // remove finished transitions 47 | state.textTransitions = state.textTransitions.filter(function (textTransition) { 48 | return !textTransition.hidden; 49 | }); 50 | 51 | var currentText = state.textTransitions[state.textTransitions.length - 1]; 52 | 53 | // get current value 54 | var currentValue = currentText ? currentText.value : 0; 55 | 56 | // calculate animation direction 57 | var direction = state.style.transitionDirection === 'detect' ? state.value - currentValue : state.style.transitionDirection === 'reverse' ? -1 : 1; 58 | 59 | // hide all previous transitions 60 | state.textTransitions.forEach(function (textTransition) { 61 | textTransition.hide(direction); 62 | }); 63 | 64 | // create animation 65 | var nextText = createTextTransition(state.value, state.transitionIn, state.transitionOut); 66 | nextText.appendTo(state.root); 67 | 68 | if (state.isInitialValue()) { 69 | nextText.showNow(); 70 | } else { 71 | nextText.show(direction); 72 | } 73 | 74 | state.textTransitions.push(nextText); 75 | }; 76 | 77 | var createTextTransition = function createTextTransition(text, transitionIn, transitionOut) { 78 | 79 | var state = { 80 | shouldHide: false, 81 | hiding: false, 82 | hidden: false, 83 | shown: false, 84 | value: text 85 | }; 86 | 87 | var root = DOM.create('span', 'tick-swap-transition'); 88 | root.textContent = text; 89 | root.dataset.value = text; 90 | 91 | var api = { 92 | showNow: function showNow() { 93 | state.shown = true; 94 | }, 95 | show: function show(direction) { 96 | 97 | // animate into view 98 | 99 | (direction > 0 ? transitionIn : transitionOut)(state.root, direction, function () { 100 | 101 | // done, test if should hide 102 | state.shown = true; 103 | 104 | // hide immidiately if the hide method has been called earlier 105 | if (state.shouldHide) { 106 | api.hide(direction); 107 | } 108 | }); 109 | }, 110 | hide: function hide(direction) { 111 | 112 | // already hiding 113 | if (state.hiding || state.hidden) { 114 | return; 115 | } 116 | 117 | // should be hidden when shown 118 | state.shouldHide = true; 119 | 120 | // are we shown yet? 121 | if (!state.shown) { 122 | return; 123 | } 124 | 125 | // already hiding 126 | state.hiding = true; 127 | 128 | // yes we are, let's hide immidiately 129 | (direction > 0 ? transitionOut : transitionIn)(state.root, direction, function () { 130 | 131 | // no longer hiding 132 | state.hiding = false; 133 | 134 | // clean up 135 | state.hidden = true; 136 | 137 | // remove from DOM 138 | state.root.parentNode.removeChild(state.root); 139 | }); 140 | } 141 | }; 142 | 143 | Object.defineProperty(api, 'value', { 144 | get: function get() { 145 | return state.value; 146 | } 147 | }); 148 | 149 | return Object.assign(api, rooter(state, root)); 150 | }; 151 | 152 | return function (root) { 153 | 154 | var state = { 155 | spacer: null, 156 | textTransitions: [] 157 | }; 158 | 159 | return Object.assign({}, rooter(state, root, 'swap'), updater(state), styler(state, { 160 | transition: [{ name: 'crossfade' }], 161 | transitionIn: [], 162 | transitionOut: [], 163 | transitionDirection: 'forward' // 'forward', 'reverse', 'detect' 164 | }), drawer(state, draw), destroyer(state)); 165 | }; 166 | }); 167 | 168 | module.exports = index; 169 | 170 | module.exports.identifier = { 171 | name:'swap', 172 | type:'view' 173 | }; 174 | return module.exports; 175 | }())]); 176 | 177 | }(window)); -------------------------------------------------------------------------------- /dist/view-swap/tick.view.swap.global.min.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | !function(t,n){"use strict";t.Tick||(t.Tick=[]),t.Tick.push(["view","swap",function(){if(!t)var t={};var e=function(){var t=arguments.length>0&&arguments[0]!==n?arguments[0]:API,e=t.DOM,i=t.View,r=i.rooter,o=i.destroyer,s=i.drawer,a=i.updater,u=i.styler,c=function(t){t.spacer||(t.root.textContent="",t.spacer=e.create("span","tick-swap-spacer"),t.root.appendChild(t.spacer)),t.spacer.textContent=t.value,t.textTransitions=t.textTransitions.filter(function(t){return!t.hidden});var n=t.textTransitions[t.textTransitions.length-1],i=n?n.value:0,r="detect"===t.style.transitionDirection?t.value-i:"reverse"===t.style.transitionDirection?-1:1;t.textTransitions.forEach(function(t){t.hide(r)});var o=d(t.value,t.transitionIn,t.transitionOut);o.appendTo(t.root),t.isInitialValue()?o.showNow():o.show(r),t.textTransitions.push(o)},d=function(t,n,i){var o={shouldHide:!1,hiding:!1,hidden:!1,shown:!1,value:t},s=e.create("span","tick-swap-transition");s.textContent=t,s.dataset.value=t;var a={showNow:function(){o.shown=!0},show:function(t){(t>0?n:i)(o.root,t,function(){o.shown=!0,o.shouldHide&&a.hide(t)})},hide:function(t){o.hiding||o.hidden||(o.shouldHide=!0,o.shown&&(o.hiding=!0,(t>0?i:n)(o.root,t,function(){o.hiding=!1,o.hidden=!0,o.root.parentNode.removeChild(o.root)})))}};return Object.defineProperty(a,"value",{get:function(){return o.value}}),Object.assign(a,r(o,s))};return function(t){var n={spacer:null,textTransitions:[]};return Object.assign({},r(n,t,"swap"),a(n),u(n,{transition:[{name:"crossfade"}],transitionIn:[],transitionOut:[],transitionDirection:"forward"}),s(n,c),o(n))}};return t.exports=e,t.exports.identifier={name:"swap",type:"view"},t.exports}()])}(window); -------------------------------------------------------------------------------- /dist/view-swap/tick.view.swap.jquery.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | (function($) { 8 | 'use strict'; 9 | 10 | if (!$) { return; } 11 | 12 | // only create tick extensions queue if not already available 13 | if (!$.tick) { 14 | $.tick = []; 15 | } 16 | 17 | // add this extension 18 | $.tick.push(['view', 'swap', (function() { 19 | if (!module) { 20 | var module = {}; 21 | } 22 | 'use strict'; 23 | 24 | var index = (function () { 25 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : API, 26 | DOM = _ref.DOM, 27 | _ref$View = _ref.View, 28 | rooter = _ref$View.rooter, 29 | destroyer = _ref$View.destroyer, 30 | drawer = _ref$View.drawer, 31 | updater = _ref$View.updater, 32 | styler = _ref$View.styler; 33 | 34 | var draw = function draw(state) { 35 | 36 | if (!state.spacer) { 37 | 38 | // remove initial content 39 | state.root.textContent = ''; 40 | 41 | state.spacer = DOM.create('span', 'tick-swap-spacer'); 42 | state.root.appendChild(state.spacer); 43 | } 44 | 45 | // set value 46 | state.spacer.textContent = state.value; 47 | 48 | // remove finished transitions 49 | state.textTransitions = state.textTransitions.filter(function (textTransition) { 50 | return !textTransition.hidden; 51 | }); 52 | 53 | var currentText = state.textTransitions[state.textTransitions.length - 1]; 54 | 55 | // get current value 56 | var currentValue = currentText ? currentText.value : 0; 57 | 58 | // calculate animation direction 59 | var direction = state.style.transitionDirection === 'detect' ? state.value - currentValue : state.style.transitionDirection === 'reverse' ? -1 : 1; 60 | 61 | // hide all previous transitions 62 | state.textTransitions.forEach(function (textTransition) { 63 | textTransition.hide(direction); 64 | }); 65 | 66 | // create animation 67 | var nextText = createTextTransition(state.value, state.transitionIn, state.transitionOut); 68 | nextText.appendTo(state.root); 69 | 70 | if (state.isInitialValue()) { 71 | nextText.showNow(); 72 | } else { 73 | nextText.show(direction); 74 | } 75 | 76 | state.textTransitions.push(nextText); 77 | }; 78 | 79 | var createTextTransition = function createTextTransition(text, transitionIn, transitionOut) { 80 | 81 | var state = { 82 | shouldHide: false, 83 | hiding: false, 84 | hidden: false, 85 | shown: false, 86 | value: text 87 | }; 88 | 89 | var root = DOM.create('span', 'tick-swap-transition'); 90 | root.textContent = text; 91 | root.dataset.value = text; 92 | 93 | var api = { 94 | showNow: function showNow() { 95 | state.shown = true; 96 | }, 97 | show: function show(direction) { 98 | 99 | // animate into view 100 | 101 | (direction > 0 ? transitionIn : transitionOut)(state.root, direction, function () { 102 | 103 | // done, test if should hide 104 | state.shown = true; 105 | 106 | // hide immidiately if the hide method has been called earlier 107 | if (state.shouldHide) { 108 | api.hide(direction); 109 | } 110 | }); 111 | }, 112 | hide: function hide(direction) { 113 | 114 | // already hiding 115 | if (state.hiding || state.hidden) { 116 | return; 117 | } 118 | 119 | // should be hidden when shown 120 | state.shouldHide = true; 121 | 122 | // are we shown yet? 123 | if (!state.shown) { 124 | return; 125 | } 126 | 127 | // already hiding 128 | state.hiding = true; 129 | 130 | // yes we are, let's hide immidiately 131 | (direction > 0 ? transitionOut : transitionIn)(state.root, direction, function () { 132 | 133 | // no longer hiding 134 | state.hiding = false; 135 | 136 | // clean up 137 | state.hidden = true; 138 | 139 | // remove from DOM 140 | state.root.parentNode.removeChild(state.root); 141 | }); 142 | } 143 | }; 144 | 145 | Object.defineProperty(api, 'value', { 146 | get: function get() { 147 | return state.value; 148 | } 149 | }); 150 | 151 | return Object.assign(api, rooter(state, root)); 152 | }; 153 | 154 | return function (root) { 155 | 156 | var state = { 157 | spacer: null, 158 | textTransitions: [] 159 | }; 160 | 161 | return Object.assign({}, rooter(state, root, 'swap'), updater(state), styler(state, { 162 | transition: [{ name: 'crossfade' }], 163 | transitionIn: [], 164 | transitionOut: [], 165 | transitionDirection: 'forward' // 'forward', 'reverse', 'detect' 166 | }), drawer(state, draw), destroyer(state)); 167 | }; 168 | }); 169 | 170 | module.exports = index; 171 | 172 | module.exports.identifier = { 173 | name:'swap', 174 | type:'view' 175 | }; 176 | return module.exports; 177 | }())]); 178 | 179 | }(window.jQuery)); -------------------------------------------------------------------------------- /dist/view-swap/tick.view.swap.jquery.min.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | !function(t){"use strict";t&&(t.tick||(t.tick=[]),t.tick.push(["view","swap",function(){if(!t)var t={};var n=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:API,n=t.DOM,e=t.View,i=e.rooter,r=e.destroyer,o=e.drawer,s=e.updater,a=e.styler,u=function(t){t.spacer||(t.root.textContent="",t.spacer=n.create("span","tick-swap-spacer"),t.root.appendChild(t.spacer)),t.spacer.textContent=t.value,t.textTransitions=t.textTransitions.filter(function(t){return!t.hidden});var e=t.textTransitions[t.textTransitions.length-1],i=e?e.value:0,r="detect"===t.style.transitionDirection?t.value-i:"reverse"===t.style.transitionDirection?-1:1;t.textTransitions.forEach(function(t){t.hide(r)});var o=c(t.value,t.transitionIn,t.transitionOut);o.appendTo(t.root),t.isInitialValue()?o.showNow():o.show(r),t.textTransitions.push(o)},c=function(t,e,r){var o={shouldHide:!1,hiding:!1,hidden:!1,shown:!1,value:t},s=n.create("span","tick-swap-transition");s.textContent=t,s.dataset.value=t;var a={showNow:function(){o.shown=!0},show:function(t){(t>0?e:r)(o.root,t,function(){o.shown=!0,o.shouldHide&&a.hide(t)})},hide:function(t){o.hiding||o.hidden||(o.shouldHide=!0,o.shown&&(o.hiding=!0,(t>0?r:e)(o.root,t,function(){o.hiding=!1,o.hidden=!0,o.root.parentNode.removeChild(o.root)})))}};return Object.defineProperty(a,"value",{get:function(){return o.value}}),Object.assign(a,i(o,s))};return function(t){var n={spacer:null,textTransitions:[]};return Object.assign({},i(n,t,"swap"),s(n),a(n,{transition:[{name:"crossfade"}],transitionIn:[],transitionOut:[],transitionDirection:"forward"}),o(n,u),r(n))}};return t.exports=n,t.exports.identifier={name:"swap",type:"view"},t.exports}()]))}(window.jQuery); -------------------------------------------------------------------------------- /dist/view-swap/tick.view.swap.min.css: -------------------------------------------------------------------------------- 1 | /* 2 | * @pqina/tick v1.8.3 - Counters Made Easy 3 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 4 | */ 5 | .tick-swap{position:relative}.tick-swap[data-style*=transition]{perspective:4em;transform-style:preserve-3d}.tick-swap .tick-swap-spacer{position:relative;display:block;white-space:pre;visibility:hidden}.tick-swap .tick-swap-spacer,.tick-swap .tick-swap-transition{backface-visibility:hidden}.tick-swap .tick-swap-transition{position:absolute;top:0;left:0;width:100%;height:100%;z-index:2}.tick-swap[data-style*=transition]{min-width:1ex;text-align:center} -------------------------------------------------------------------------------- /dist/view-swap/tick.view.swap.module.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | /* 4 | * @pqina/tick v1.8.3 - Counters Made Easy 5 | * Copyright (c) 2024 PQINA - https://github.com/pqina/tick/ 6 | */ 7 | export default typeof window !== 'undefined' ? (function() { 8 | if (!module) { 9 | var module = {}; 10 | } 11 | 'use strict'; 12 | 13 | var index = (function () { 14 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : API, 15 | DOM = _ref.DOM, 16 | _ref$View = _ref.View, 17 | rooter = _ref$View.rooter, 18 | destroyer = _ref$View.destroyer, 19 | drawer = _ref$View.drawer, 20 | updater = _ref$View.updater, 21 | styler = _ref$View.styler; 22 | 23 | var draw = function draw(state) { 24 | 25 | if (!state.spacer) { 26 | 27 | // remove initial content 28 | state.root.textContent = ''; 29 | 30 | state.spacer = DOM.create('span', 'tick-swap-spacer'); 31 | state.root.appendChild(state.spacer); 32 | } 33 | 34 | // set value 35 | state.spacer.textContent = state.value; 36 | 37 | // remove finished transitions 38 | state.textTransitions = state.textTransitions.filter(function (textTransition) { 39 | return !textTransition.hidden; 40 | }); 41 | 42 | var currentText = state.textTransitions[state.textTransitions.length - 1]; 43 | 44 | // get current value 45 | var currentValue = currentText ? currentText.value : 0; 46 | 47 | // calculate animation direction 48 | var direction = state.style.transitionDirection === 'detect' ? state.value - currentValue : state.style.transitionDirection === 'reverse' ? -1 : 1; 49 | 50 | // hide all previous transitions 51 | state.textTransitions.forEach(function (textTransition) { 52 | textTransition.hide(direction); 53 | }); 54 | 55 | // create animation 56 | var nextText = createTextTransition(state.value, state.transitionIn, state.transitionOut); 57 | nextText.appendTo(state.root); 58 | 59 | if (state.isInitialValue()) { 60 | nextText.showNow(); 61 | } else { 62 | nextText.show(direction); 63 | } 64 | 65 | state.textTransitions.push(nextText); 66 | }; 67 | 68 | var createTextTransition = function createTextTransition(text, transitionIn, transitionOut) { 69 | 70 | var state = { 71 | shouldHide: false, 72 | hiding: false, 73 | hidden: false, 74 | shown: false, 75 | value: text 76 | }; 77 | 78 | var root = DOM.create('span', 'tick-swap-transition'); 79 | root.textContent = text; 80 | root.dataset.value = text; 81 | 82 | var api = { 83 | showNow: function showNow() { 84 | state.shown = true; 85 | }, 86 | show: function show(direction) { 87 | 88 | // animate into view 89 | 90 | (direction > 0 ? transitionIn : transitionOut)(state.root, direction, function () { 91 | 92 | // done, test if should hide 93 | state.shown = true; 94 | 95 | // hide immidiately if the hide method has been called earlier 96 | if (state.shouldHide) { 97 | api.hide(direction); 98 | } 99 | }); 100 | }, 101 | hide: function hide(direction) { 102 | 103 | // already hiding 104 | if (state.hiding || state.hidden) { 105 | return; 106 | } 107 | 108 | // should be hidden when shown 109 | state.shouldHide = true; 110 | 111 | // are we shown yet? 112 | if (!state.shown) { 113 | return; 114 | } 115 | 116 | // already hiding 117 | state.hiding = true; 118 | 119 | // yes we are, let's hide immidiately 120 | (direction > 0 ? transitionOut : transitionIn)(state.root, direction, function () { 121 | 122 | // no longer hiding 123 | state.hiding = false; 124 | 125 | // clean up 126 | state.hidden = true; 127 | 128 | // remove from DOM 129 | state.root.parentNode.removeChild(state.root); 130 | }); 131 | } 132 | }; 133 | 134 | Object.defineProperty(api, 'value', { 135 | get: function get() { 136 | return state.value; 137 | } 138 | }); 139 | 140 | return Object.assign(api, rooter(state, root)); 141 | }; 142 | 143 | return function (root) { 144 | 145 | var state = { 146 | spacer: null, 147 | textTransitions: [] 148 | }; 149 | 150 | return Object.assign({}, rooter(state, root, 'swap'), updater(state), styler(state, { 151 | transition: [{ name: 'crossfade' }], 152 | transitionIn: [], 153 | transitionOut: [], 154 | transitionDirection: 'forward' // 'forward', 'reverse', 'detect' 155 | }), drawer(state, draw), destroyer(state)); 156 | }; 157 | }); 158 | 159 | module.exports = index; 160 | 161 | module.exports.identifier = { 162 | name:'swap', 163 | type:'view' 164 | }; 165 | return module.exports; 166 | }()) : null; -------------------------------------------------------------------------------- /dots.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pqina/tick/a3df2420753980cfe82a3af90ceab93a89419e9f/dots.gif -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tick Example Preset 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 38 | 39 |
40 |
45 |
46 |
51 | 52 |
53 | 54 | 55 |
56 |
57 |
58 | 59 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /inline-svg/index.js: -------------------------------------------------------------------------------- 1 | var through = require('through2'); 2 | var gutil = require('gulp-util'); 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | var mime = require('mime'); 6 | 7 | module.exports = function (givenImagesPath) { 8 | function inlineSVG (file, enc, callback) { 9 | var imagesPath; 10 | 11 | if (!givenImagesPath) { 12 | imagesPath = path.dirname(file.path); 13 | } else { 14 | imagesPath = path.join(path.dirname(file.path), givenImagesPath); 15 | if (path.resolve(givenImagesPath) === path.normalize(givenImagesPath)) { 16 | imagesPath = givenImagesPath; 17 | } 18 | } 19 | 20 | // Do nothing if no contents 21 | if (file.isNull()) { 22 | this.push(file); 23 | return callback(); 24 | } 25 | 26 | if (file.isStream()) { 27 | // accepting streams is optional 28 | this.emit('error', new gutil.PluginError('gulp-inline-svg', 'Stream content is not supported')); 29 | return callback(); 30 | } 31 | 32 | function inline (inlineExpr, quotedPath) { 33 | 34 | var imagePath = quotedPath.replace(/['"]/g, ''); 35 | 36 | try { 37 | var fileData = fs.readFileSync(path.join(imagesPath, imagePath)); 38 | } 39 | catch (e) { 40 | gutil.log(gutil.colors.yellow('gulp-inline-svg'), 'Referenced file not found: ' + path.join(imagesPath, imagePath)); 41 | return inlineExpr; 42 | } 43 | 44 | var fileData = new Buffer(fileData).toString(); 45 | 46 | // replace double with single quotes 47 | fileData = fileData.replace(/"/g, "'"); 48 | 49 | // replace < 50 | fileData = fileData.replace(/ 53 | fileData = fileData.replace(/>/g, "%3E"); 54 | 55 | // replace # 56 | fileData = fileData.replace(/#/g, "%23"); 57 | 58 | var fileMime = mime.lookup(imagePath); 59 | 60 | return 'url("data:' + fileMime + ';charset=utf-8,' + fileData + '")'; 61 | } 62 | 63 | // check if file.contents is a `Buffer` 64 | if (file.isBuffer()) { 65 | 66 | var content = String(file.contents).replace(/url\(([^\)]+)\)/g, inline); 67 | file.contents = new Buffer(content); 68 | 69 | this.push(file); 70 | } 71 | 72 | return callback(); 73 | } 74 | 75 | return through.obj(inlineSVG); 76 | }; -------------------------------------------------------------------------------- /line.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pqina/tick/a3df2420753980cfe82a3af90ceab93a89419e9f/line.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pqina/tick", 3 | "version": "1.8.3", 4 | "description": "Counters Made Easy", 5 | "homepage": "https://github.com/pqina/tick/", 6 | "main": "dist/core/tick.core.module.js", 7 | "repository": "pqina/tick", 8 | "keywords": [ 9 | "javascript", 10 | "countdown", 11 | "countup", 12 | "event", 13 | "clock", 14 | "animated" 15 | ], 16 | "scripts": { 17 | "build": "gulp build", 18 | "test": "./node_modules/.bin/mocha --compilers js:babel-core/register" 19 | }, 20 | "files": [ 21 | "dist", 22 | "tick" 23 | ], 24 | "author": { 25 | "name": "PQINA", 26 | "url": "https://pqina.nl/" 27 | }, 28 | "license": "MIT", 29 | "devDependencies": { 30 | "autoprefixer": "^6.0.3", 31 | "babel": "^6.5.2", 32 | "babel-cli": "^6.18.0", 33 | "babel-core": "^6.11.4", 34 | "babel-plugin-external-helpers": "^6.18.0", 35 | "babel-plugin-transform-object-rest-spread": "^6.20.2", 36 | "babel-preset-es2015": "^6.18.0", 37 | "babel-preset-es2015-rollup": "^1.2.0", 38 | "babel-preset-stage-2": "^6.18.0", 39 | "babel-register": "^6.9.0", 40 | "browser-sync": "^2.18.2", 41 | "chai": "^3.5.0", 42 | "cssnano": "^3.6.2", 43 | "gulp": "^3.9.1", 44 | "gulp-clean": "^0.3.2", 45 | "gulp-concat": "^2.6.0", 46 | "gulp-cssnano": "^2.1.2", 47 | "gulp-data": "^1.2.1", 48 | "gulp-eslint": "^2.0.0", 49 | "gulp-flatten": "^0.3.1", 50 | "gulp-header": "^1.2.2", 51 | "gulp-highlight": "^1.0.0", 52 | "gulp-markdown": "^1.2.0", 53 | "gulp-mocha": "^2.2.0", 54 | "gulp-mocha-phantomjs": "^0.11.0", 55 | "gulp-nunjucks-api": "^0.6.7", 56 | "gulp-postcss": "^6.0.0", 57 | "gulp-rename": "^1.2.2", 58 | "gulp-replace": "^0.5.4", 59 | "gulp-rollup": "^2.5.1", 60 | "gulp-sass": "^5.1.0", 61 | "gulp-size": "^1.2.3", 62 | "gulp-sourcemaps": "^1.6.0", 63 | "gulp-uglify": "^1.5.4", 64 | "gulp-util": "^3.0.6", 65 | "gulp-wrap": "^0.11.0", 66 | "gulp-zip": "^3.2.0", 67 | "highlight.js": "^9.2.0", 68 | "jsdom": "^6.1.0", 69 | "jspm": "^0.17.0-beta.22", 70 | "marked": "^0.3.5", 71 | "mocha": "^2.5.3", 72 | "node-sass": "^9.0.0", 73 | "postcss-inline-svg": "^1.4.0", 74 | "requirejs": "^2.2.0", 75 | "restify": "^4.1.1", 76 | "rollup-plugin-babel": "^2.7.1", 77 | "rollup-plugin-includepaths": "^0.1.5", 78 | "rollup-plugin-node-resolve": "^2.0.0", 79 | "rollup-stream": "^1.18.0", 80 | "run-sequence": "^1.2.2", 81 | "through2": "^2.0.1", 82 | "vinyl-buffer": "^1.0.0", 83 | "vinyl-ftp": "^0.4.5", 84 | "vinyl-source-stream": "^1.1.0" 85 | }, 86 | "overrides": { 87 | "graceful-fs": "^4.2.11" 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/core/js/canvas.js: -------------------------------------------------------------------------------- 1 | import { VENDOR_PREFIX } from './dom'; 2 | 3 | export const getBackingStoreRatio = (ctx) => { 4 | return ctx[`${ VENDOR_PREFIX }BackingStorePixelRatio`] || ctx.backingStorePixelRatio || 1; 5 | }; 6 | 7 | export const getDevicePixelRatio = () => { 8 | return window.devicePixelRatio || 1; 9 | }; 10 | 11 | export const clearCanvas = (canvas) => { 12 | const ctx = canvas.getContext('2d'); 13 | ctx.clearRect(0, 0, canvas.width, canvas.height); 14 | }; -------------------------------------------------------------------------------- /src/core/js/dom.js: -------------------------------------------------------------------------------- 1 | export const VENDOR_PREFIX = typeof document === 'undefined' ? null : (function(){ 2 | const VENDORS = ['webkit', 'Moz', 'ms', 'O']; 3 | let i = 0; 4 | let l = VENDORS.length; 5 | let transform; 6 | let elementStyle = document.createElement('div').style; 7 | for (;i { 17 | let textNode = node.childNodes[0]; 18 | if (!textNode) { 19 | textNode = document.createTextNode(value); 20 | node.appendChild(textNode); 21 | } 22 | else if (value !== textNode.nodeValue) { 23 | textNode.nodeValue = value; 24 | } 25 | } 26 | 27 | export const create = (name, className) => { 28 | const el = document.createElement(name); 29 | if (className) { 30 | el.className = className; 31 | } 32 | return el; 33 | }; 34 | 35 | export const observeAttributes = (element, attributes, cb) => { 36 | const observer = new MutationObserver((mutations) => { 37 | attributes.forEach(attr => { 38 | if (mutations.filter(mutation => attributes.includes(mutation.attributeName)).length) { 39 | cb(element.getAttribute(attr)); 40 | } 41 | }); 42 | }); 43 | observer.observe(element, { attributes:true }); 44 | return observer; 45 | }; 46 | 47 | export const isHTMLElement = (value) => { 48 | return value instanceof HTMLElement; 49 | }; 50 | 51 | /** 52 | * Element Transform Origin 53 | * @param element 54 | * @param value 55 | */ 56 | export const setTransformOrigin = (element, value) => { 57 | element.style.transformOrigin = value; 58 | }; 59 | 60 | /** 61 | * Element Transforms 62 | * @param element 63 | * @param name 64 | * @param value 65 | * @param unit 66 | */ 67 | export const setTransform = (element, name, value, unit = '') => { 68 | 69 | if (!element.transforms) { 70 | element.transforms = []; 71 | } 72 | 73 | const t = element.transforms.find(t => t.name === name); 74 | if (t) { 75 | t.value = value; 76 | } 77 | else { 78 | element.transforms.push({ name, value, unit }); 79 | } 80 | 81 | setTransformStyle(element, element.transforms); 82 | }; 83 | 84 | const setTransformStyle = (element, transforms) => { 85 | element.style.transform = transforms.map(t => `${ t.name }(${ t.value }${ t.unit })`).join(' '); 86 | }; 87 | 88 | export const isVisible = (element) => { 89 | 90 | const elementRect = element.getBoundingClientRect(); 91 | 92 | // is above top of the page 93 | if (elementRect.bottom < 0) { 94 | return false; 95 | } 96 | 97 | // is below bottom of page 98 | if (elementRect.top > window.scrollY + window.innerHeight) { 99 | return false; 100 | } 101 | 102 | return true; 103 | 104 | }; -------------------------------------------------------------------------------- /src/core/js/extensions/index.js: -------------------------------------------------------------------------------- 1 | import { keysToList } from '../utils'; 2 | 3 | // Available extension types 4 | export const ExtensionType = { 5 | FONT:'font', 6 | VIEW:'view', 7 | TRANSFORM:'transform', 8 | EASING_FUNCTION:'easing-function', 9 | TRANSITION:'transition' 10 | }; 11 | 12 | // Registered extension collection 13 | const Extensions = {}; 14 | Extensions[ExtensionType.FONT] = {}; 15 | Extensions[ExtensionType.VIEW] = {}; 16 | Extensions[ExtensionType.TRANSFORM] = {}; 17 | Extensions[ExtensionType.EASING_FUNCTION] = {}; 18 | Extensions[ExtensionType.TRANSITION] = {}; 19 | 20 | /** 21 | * Adds multiple extensions in one go 22 | * @param type 23 | * @param extensions 24 | * @returns {null} 25 | */ 26 | export const addExtensions = (type, extensions) => { 27 | 28 | // type does not exist 29 | if (!Extensions[type]) { 30 | return null; 31 | } 32 | 33 | for (let name in extensions) { 34 | 35 | if (!extensions.hasOwnProperty(name)) { continue; } 36 | 37 | // name already exists 38 | if (Extensions[type][name]) { 39 | return null; 40 | } 41 | 42 | // register 43 | Extensions[type][name] = extensions[name]; 44 | } 45 | }; 46 | 47 | /** 48 | * Adds an extension function by type 49 | * @param type 50 | * @param name 51 | * @param fn 52 | * @returns {null} 53 | */ 54 | export const addExtension = (type, name, fn) => { 55 | 56 | // type does not exist 57 | if (!Extensions[type]) { 58 | throw `Can't add extension with type of "${ type }", "${ type }" is not a valid extension type. The following types are valid: ${ keysToList(Extensions) }`; 59 | } 60 | 61 | // if is invalid name 62 | if (!/^[-a-z]+$/.test(name)) { 63 | throw `Can't add extension with name "${ name }", "${ name }" is contains invalid characters. Only lowercase alphabetical characters and dashes are allowed.`; 64 | } 65 | 66 | // name in type already exists 67 | if (Extensions[type][name]) { 68 | throw `Can't add extension with name "${ name }", "${ name }" is already added.`; 69 | } 70 | 71 | // add 72 | Extensions[type][name] = fn; 73 | }; 74 | 75 | /** 76 | * Returns an extension function by name and type 77 | * @param type 78 | * @param name 79 | * @returns {*} 80 | */ 81 | export const getExtension = (type, name) => { 82 | 83 | // type does not exist 84 | if (!Extensions[type]) { 85 | throw `Can't get extension with type of "${ type }", "${ type }" is not a valid extension type. The following types are available: ${ keysToList(Extensions) }`; 86 | } 87 | 88 | // name in type does not exist 89 | if (!Extensions[type][name]) { 90 | throw `Can't get extension with name "${ name }", "${ name }" is not available. The following extensions are available: ${ keysToList(Extensions[type]) }`; 91 | } 92 | 93 | return Extensions[type][name]; 94 | }; -------------------------------------------------------------------------------- /src/core/js/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Helper methods for building the API 3 | */ 4 | import { create, destroy, parse, find, setConstant, setPreset } from './TickDOM'; 5 | import { addExtension, ExtensionType } from './extensions/index'; 6 | import { request, dashesToCamels } from './utils'; 7 | import { setTimer } from './timer'; 8 | import { dateFromISO, duration, now, isDate } from './date'; 9 | import { countdownAmount, countdownDuration, countUpDuration, countScheduled } from './count'; 10 | import support from './support'; 11 | 12 | /** 13 | * We wan't to be sure Rollup includes these collections in the output packages so that's why they are referenced here 14 | */ 15 | import { Transforms } from './transform/index'; 16 | import { EasingFunctions } from './easing'; 17 | import { Transitions } from './transitions'; 18 | import { Views } from './view/index'; 19 | 20 | const API = { 21 | 22 | /** 23 | * Quick way to detect if Tick is supported 24 | */ 25 | supported: support(), 26 | 27 | // options 28 | options:{ 29 | setConstant, 30 | setPreset 31 | }, 32 | 33 | /** 34 | * Helper Methods 35 | */ 36 | helper:{ 37 | 38 | // Starts an interval and calls callback method on each tick 39 | interval: setTimer, 40 | 41 | // Returns current time or date object based on ISO 42 | date: (iso) => iso ? dateFromISO(iso) : now(), 43 | 44 | // Returns duration in milliseconds or duration between two dates 45 | duration 46 | }, 47 | 48 | /** 49 | * Data Access 50 | */ 51 | data:{ 52 | 53 | // Request data from a url 54 | request, 55 | 56 | // Poll a URL for data with a set interval 57 | poll: (url, cb, interval = 60000) => { 58 | return setTimer(() => { 59 | request(url, cb); 60 | }, interval); 61 | } 62 | 63 | }, 64 | 65 | /** 66 | * DOM Operations 67 | */ 68 | DOM:{ 69 | 70 | // Create a new ticker 71 | create, 72 | 73 | // Destroy an existing ticker 74 | destroy, 75 | 76 | // Parse a piece of the DOM for tickers 77 | parse, 78 | 79 | // Find a specific ticker by DOM node 80 | find 81 | 82 | }, 83 | 84 | count:{ 85 | down: (...args) => { 86 | 87 | // if is `amount` and `unit type`, 10 seconds 88 | if (typeof args[0] === 'number' && typeof args[1] === 'string') { 89 | const value = args[0]; 90 | const units = args[1].toLowerCase(); 91 | args.shift(); 92 | args[0] = duration(value, units); 93 | args[1] = args[1] || {}; 94 | args[1].units = units; 95 | return countdownAmount(...args); 96 | } 97 | 98 | // is date or iso string 99 | if (typeof args[0] === 'string' || isDate(args[0])) { 100 | return countdownDuration(...args); 101 | } 102 | 103 | return null; 104 | }, 105 | up: countUpDuration, 106 | schedule: countScheduled 107 | }, 108 | 109 | 110 | /** 111 | * Public method to extend Tick functionality 112 | */ 113 | plugin:{ 114 | add:(type, name, fn) => { 115 | if (typeof type === 'function') { 116 | const extension = type; 117 | return addExtension( 118 | extension.identifier.type, 119 | extension.identifier.name, 120 | extension 121 | ); 122 | } 123 | return addExtension(type, name, fn); 124 | } 125 | } 126 | 127 | }; 128 | 129 | // expose shortcut methods 130 | for (let type in ExtensionType) { 131 | if (!ExtensionType.hasOwnProperty(type)) { continue; } 132 | API.plugin[dashesToCamels('add-' + ExtensionType[type])] = (name, fn) => { 133 | addExtension(ExtensionType[type], name, fn); 134 | } 135 | } 136 | 137 | export default API; -------------------------------------------------------------------------------- /src/core/js/parser.js: -------------------------------------------------------------------------------- 1 | const arrow = (str, i) => str[i] === '-' && str[i+1] === '>'; 2 | 3 | const string = (c) => c === "'" || c === '"'; 4 | 5 | const comma = (c) => c === ','; 6 | 7 | const opener = (c) => c === '('; 8 | 9 | const closer = (c) => c === ')'; 10 | 11 | const value = (v) => v.trim().length !== 0; 12 | 13 | const add = (r, v) => r.push(v.trim()); 14 | 15 | const token = (r, v) => { 16 | if (value(v)) { 17 | add(r, v); 18 | return ''; 19 | } 20 | return v; 21 | }; 22 | 23 | const chain = (chain, output) => { 24 | if (chain.length) { 25 | output.push(chain.length > 1 ? chain.concat() : chain[0]); 26 | } 27 | return []; 28 | }; 29 | 30 | const parse = (i, str, result) => { 31 | 32 | let v = ''; 33 | let fns = []; 34 | let quote = null; 35 | let hitArrow = false; 36 | 37 | while (i < str.length) { 38 | 39 | // character reference 40 | let c = str[i]; 41 | 42 | // enter level 43 | if (opener(c)) { 44 | 45 | hitArrow = false; 46 | let fn = [v.trim()]; 47 | 48 | i = parse(i + 1, str, fn); 49 | c = str[i]; 50 | 51 | fns.push(fn); 52 | v = ''; 53 | } 54 | 55 | // exit level 56 | else if (closer(c)) { 57 | 58 | if (hitArrow && v.trim().length) { 59 | fns.push([v.trim()]); 60 | v = ''; 61 | hitArrow = false; 62 | } 63 | 64 | if (value(v)) { 65 | add(fns, v); 66 | } 67 | 68 | fns = chain(fns, result); 69 | 70 | return i+1; 71 | } 72 | 73 | // function names or arguments 74 | else { 75 | 76 | // we're in a string 77 | // as long as the exit has not been found add to value 78 | if (quote !== null && c !== quote) { 79 | 80 | // accept any value 81 | v += c; 82 | 83 | } 84 | // we've found the string exit 85 | else if (c === quote) { 86 | 87 | fns.push(v); 88 | v = ''; 89 | 90 | quote = null; 91 | } 92 | // we're not in a string and we found a string opener 93 | else if (string(c)) { 94 | v = ''; 95 | quote = c; 96 | } 97 | 98 | else { 99 | 100 | // we're not in a string 101 | 102 | // we've found an arrow 103 | if (arrow(str, i)) { 104 | 105 | hitArrow = true; 106 | 107 | // we might have finished a function without parenthesis 108 | if (v.trim().length) { 109 | fns.push([v.trim()]); 110 | v = ''; 111 | } 112 | 113 | // skip two additional characters because arrow is of length 2 114 | i+=2; 115 | } 116 | // we've reached an argument separator 117 | else if (comma(c)) { 118 | 119 | if (hitArrow && v.trim().length) { 120 | fns.push([v.trim()]); 121 | v = ''; 122 | hitArrow = false; 123 | } 124 | 125 | fns = chain(fns, result); 126 | 127 | // add possible previous token 128 | v = token(result, v); 129 | 130 | } 131 | else { 132 | v += c; 133 | } 134 | 135 | } 136 | 137 | // next character 138 | i++; 139 | } 140 | } 141 | 142 | if ((hitArrow && v.trim().length) || 143 | (!hitArrow && v.trim().length && !fns.length)) { 144 | fns.push([v.trim()]); 145 | v = ''; 146 | } 147 | 148 | chain(fns, result); 149 | 150 | // add final token 151 | token(result, v); 152 | 153 | return i; 154 | }; 155 | 156 | export const parseTransformChain = string => { 157 | let result = []; 158 | parse(0, string, result); 159 | return result; 160 | }; -------------------------------------------------------------------------------- /src/core/js/support.js: -------------------------------------------------------------------------------- 1 | export default () => { 2 | 3 | const w = window; 4 | if (typeof w === 'undefined') { 5 | return false; 6 | } 7 | 8 | // test if can use CSS supports feature detection 9 | const canSupport = w.CSS && w.CSS.supports; 10 | 11 | // test if is IE 11 12 | // does not support CSS.supports but does support transforms without prefix 13 | const isIE11 = !!w.MSInputMethodContext && !!document.documentMode; 14 | 15 | // test if has transform support 16 | // we ignore the custom Opera implementation 17 | const canTransform = canSupport && CSS.supports('transform','translateX(0)'); 18 | 19 | // can we use mutation observer and request animation frame 20 | const features = ['MutationObserver', 'requestAnimationFrame']; 21 | 22 | // test if is supported 23 | return isIE11 || (canSupport && canTransform && !!features.filter(p => p in w).length); 24 | } -------------------------------------------------------------------------------- /src/core/js/transform/abs.js: -------------------------------------------------------------------------------- 1 | export default () => (value, cb) => cb(Math.abs(value)); -------------------------------------------------------------------------------- /src/core/js/transform/add.js: -------------------------------------------------------------------------------- 1 | export default (amount) => (value, cb) => cb(value + amount); -------------------------------------------------------------------------------- /src/core/js/transform/arrive.js: -------------------------------------------------------------------------------- 1 | import { createTranslator } from '../animate'; 2 | 3 | export default ( 4 | maxVelocity, 5 | friction, 6 | resetToBegin = false, 7 | catchUp = true 8 | ) => { 9 | let initial = null; 10 | let previous = null; 11 | let translator = null; 12 | let current = null; 13 | 14 | return (value, cb) => { 15 | value = parseFloat(value); 16 | 17 | if (initial === null) { 18 | initial = value; 19 | cb(value); 20 | return; 21 | } 22 | 23 | if (resetToBegin && previous !== null && initial === value) { 24 | translator.cancel(); 25 | translator = null; 26 | } 27 | 28 | if ( 29 | catchUp && 30 | previous !== null && 31 | value - translator.getPosition() > 1 32 | ) { 33 | translator.cancel(); 34 | translator = null; 35 | previous = null; 36 | initial = value; 37 | cb(value); 38 | return; 39 | } 40 | 41 | if (!translator) { 42 | translator = createTranslator('arrive', maxVelocity, friction); 43 | translator.update(cb, initial, value); 44 | } else { 45 | translator.update(cb, value); 46 | } 47 | 48 | previous = value; 49 | }; 50 | }; 51 | -------------------------------------------------------------------------------- /src/core/js/transform/ascii.js: -------------------------------------------------------------------------------- 1 | export default () => (value, cb) => cb((value + '').charCodeAt(0)) -------------------------------------------------------------------------------- /src/core/js/transform/ceil.js: -------------------------------------------------------------------------------- 1 | export default () => (value, cb) => cb(Math.ceil(value)); -------------------------------------------------------------------------------- /src/core/js/transform/char.js: -------------------------------------------------------------------------------- 1 | export default (filter, replacement = '') => { 2 | 3 | const regex = filter ? new RegExp(`[^${filter}]`, 'g') : null; 4 | 5 | return (value, cb) => { 6 | let char = String.fromCharCode(value); 7 | if (regex) { 8 | char = char.replace(regex, replacement); 9 | } 10 | cb(char); 11 | } 12 | 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/core/js/transform/delay.js: -------------------------------------------------------------------------------- 1 | import { copyArray, random, shuffle, range } from '../utils'; 2 | 3 | /** 4 | * @param order { String } - order of flipping > random | ltr | rtl (default) 5 | * @param min { Number } - min random delay 6 | * @param max { Number } - max random delay 7 | */ 8 | export default (order = 'rtl', min = 50, max = 50) => { 9 | 10 | let current = null; 11 | 12 | return (value, cb) => { 13 | 14 | // if no current value, set current value and -> exit 15 | if (!current) { 16 | current = copyArray(value); 17 | cb(copyArray(current)); 18 | return; 19 | } 20 | 21 | current = order === 'rtl' ? current.slice(current.length - value.length, current.length) : current.slice(0, value.length); 22 | 23 | let indexes = range(value.length); 24 | 25 | if (order === 'random') { 26 | shuffle(indexes); 27 | } 28 | 29 | if (order === 'rtl') { 30 | indexes.reverse(); 31 | } 32 | 33 | const update = () => { 34 | flip(indexes.shift(), current, value, cb); 35 | if (indexes.length) { 36 | setTimeout(update, random(min, max)); 37 | } 38 | }; 39 | 40 | update(); 41 | } 42 | } 43 | 44 | const flip = (index, current, next, cb) => { 45 | current[index] = next[index]; 46 | cb(copyArray(current)); 47 | }; 48 | -------------------------------------------------------------------------------- /src/core/js/transform/divide.js: -------------------------------------------------------------------------------- 1 | export default (amount) => (value, cb) => cb(value / amount); -------------------------------------------------------------------------------- /src/core/js/transform/duration.js: -------------------------------------------------------------------------------- 1 | import { timeDuration } from '../date'; 2 | 3 | /** 4 | * milliseconds duration 5 | * @param format 6 | * @returns {function(*=, *)} 7 | */ 8 | export default (...format) => (value, cb) => cb(timeDuration(value, format)); -------------------------------------------------------------------------------- /src/core/js/transform/floor.js: -------------------------------------------------------------------------------- 1 | export default () => (value, cb) => cb(Math.floor(value)); -------------------------------------------------------------------------------- /src/core/js/transform/format.js: -------------------------------------------------------------------------------- 1 | export default (template) => (value, cb) => cb(template.replace(/\$0/gi, value)); -------------------------------------------------------------------------------- /src/core/js/transform/fraction.js: -------------------------------------------------------------------------------- 1 | export default (min = 0, max = 100) => (value, cb) => cb((parseFloat(value) - min) / (max - min)); -------------------------------------------------------------------------------- /src/core/js/transform/index.js: -------------------------------------------------------------------------------- 1 | import { ExtensionType, addExtensions } from '../extensions/index'; 2 | 3 | import transform from './transform'; 4 | import pad from './pad'; 5 | import ascii from './ascii'; 6 | import add from './add'; 7 | import abs from './abs'; 8 | import value from './value'; 9 | import modulus from './modulus'; 10 | import subtract from './subtract'; 11 | import replace from './replace'; 12 | import round from './round'; 13 | import floor from './floor'; 14 | import ceil from './ceil'; 15 | import fraction from './fraction'; 16 | import multiply from './multiply'; 17 | import divide from './divide'; 18 | import format from './format'; 19 | import split from './split'; 20 | import plural from './plural'; 21 | import limit from './limit'; 22 | import reverse from './reverse'; 23 | import arrive from './arrive'; 24 | import spring from './spring'; 25 | import delay from './delay'; 26 | import number from './number'; 27 | import percentage from './percentage'; 28 | import step from './step'; 29 | import upper from './upper'; 30 | import lower from './lower'; 31 | import duration from './duration'; 32 | import keys from './keys'; 33 | import map from './map'; 34 | import rotate from './rotate'; 35 | import input from './input'; 36 | import substring from './substring'; 37 | import tween from './tween'; 38 | import preset from './preset'; 39 | import char from './char'; 40 | 41 | export const Transforms = { 42 | ascii, 43 | char, 44 | tween, 45 | value, 46 | input, 47 | rotate, 48 | map, 49 | transform, 50 | upper, 51 | lower, 52 | abs, 53 | add, 54 | subtract, 55 | modulus, 56 | pad, 57 | number, 58 | replace, 59 | round, 60 | ceil, 61 | floor, 62 | fraction, 63 | percentage, 64 | multiply, 65 | divide, 66 | split, 67 | format, 68 | plural, 69 | limit, 70 | reverse, 71 | arrive, 72 | spring, 73 | delay, 74 | step, 75 | keys, 76 | duration, 77 | substring, 78 | preset 79 | }; 80 | 81 | addExtensions(ExtensionType.TRANSFORM, Transforms); -------------------------------------------------------------------------------- /src/core/js/transform/input.js: -------------------------------------------------------------------------------- 1 | export default () => (value, cb) => cb(value); -------------------------------------------------------------------------------- /src/core/js/transform/keys.js: -------------------------------------------------------------------------------- 1 | export default (...keys) => { 2 | return (value, cb) => { 3 | const output = {}; 4 | value.forEach((v,i) => { 5 | output[keys[i]] = v; 6 | }); 7 | cb(output); 8 | } 9 | } -------------------------------------------------------------------------------- /src/core/js/transform/limit.js: -------------------------------------------------------------------------------- 1 | export default (min = 0, max = 1) => (value, cb) => cb(Math.min(Math.max(value, min), max)); -------------------------------------------------------------------------------- /src/core/js/transform/lower.js: -------------------------------------------------------------------------------- 1 | export default () => (value, cb) => cb((value + '').toLowerCase()); -------------------------------------------------------------------------------- /src/core/js/transform/map.js: -------------------------------------------------------------------------------- 1 | export default (transform) => (value, cb) => { 2 | 3 | const output = []; 4 | const input = value; 5 | 6 | input.forEach((v, vi) => { 7 | 8 | transform(v, (out) => { 9 | 10 | output[vi] = out; 11 | 12 | if (vi === input.length - 1) { 13 | cb(output.concat()); 14 | } 15 | 16 | }); 17 | 18 | }); 19 | 20 | 21 | } -------------------------------------------------------------------------------- /src/core/js/transform/modulus.js: -------------------------------------------------------------------------------- 1 | export default (amount) => (value, cb) => cb(value % amount); -------------------------------------------------------------------------------- /src/core/js/transform/multiply.js: -------------------------------------------------------------------------------- 1 | export default (amount) => (value, cb) => cb(value * amount); -------------------------------------------------------------------------------- /src/core/js/transform/number.js: -------------------------------------------------------------------------------- 1 | export default (decimalsSeparator = '.', thousandsSeparator = ',', decimals = 2) => (value, cb) => { 2 | cb( 3 | (value < 0 ? '-' : '') + parseFloat(Math.abs(value)) 4 | .toFixed(decimals) 5 | .replace(/./g, (c, i ,a) => { 6 | if (c === '.') { 7 | return decimalsSeparator; 8 | } 9 | return i && ((a.length - i) % 3 === 0) ? thousandsSeparator + c : c 10 | }) 11 | ); 12 | } -------------------------------------------------------------------------------- /src/core/js/transform/pad.js: -------------------------------------------------------------------------------- 1 | export default (padding = '', side = 'left') => (value, cb) => 2 | cb( 3 | padding.length > ('' + value).length ? 4 | side === 'left' ? 5 | ('' + padding + value).slice(-padding.length) : 6 | ('' + value + padding).substring(0, padding.length) : value 7 | ) 8 | -------------------------------------------------------------------------------- /src/core/js/transform/percentage.js: -------------------------------------------------------------------------------- 1 | import fraction from './fraction'; 2 | export default (min = 0, max = 100) => { 3 | const f = fraction(min, max); 4 | return (value, cb) => { 5 | f(value, (value) => { 6 | cb(value * 100) 7 | }); 8 | } 9 | } -------------------------------------------------------------------------------- /src/core/js/transform/plural.js: -------------------------------------------------------------------------------- 1 | export default (single, plural) => (value, cb) => cb(value === 1 ? single : plural); -------------------------------------------------------------------------------- /src/core/js/transform/preset.js: -------------------------------------------------------------------------------- 1 | export default (...presets) => (value, cb, instance) => cb(value.map((v, index) => instance.getPreset(presets[index])(v, instance.getConstants(), instance))); -------------------------------------------------------------------------------- /src/core/js/transform/replace.js: -------------------------------------------------------------------------------- 1 | export default (needle, replacement) => (string, cb) => cb((string + '').replace(new RegExp(needle === '.' ? '\\' + needle : needle,'g'), replacement)) -------------------------------------------------------------------------------- /src/core/js/transform/reverse.js: -------------------------------------------------------------------------------- 1 | export default () => (value, cb) => cb((Array.isArray(value) ? value.reverse() : (value + '').split('').reverse().join(''))); -------------------------------------------------------------------------------- /src/core/js/transform/rotate.js: -------------------------------------------------------------------------------- 1 | export default (...transforms) => (value, cb) => { 2 | 3 | const input = Array.isArray(value) ? value : [value]; 4 | const output = []; 5 | const totalTransforms = transforms.length; 6 | 7 | input.forEach((v,i)=> { 8 | 9 | transforms[i % totalTransforms](v, (out) => { 10 | 11 | output[i] = out; 12 | if (i === input.length - 1) { 13 | cb(output); 14 | } 15 | 16 | }) 17 | }); 18 | 19 | } -------------------------------------------------------------------------------- /src/core/js/transform/round.js: -------------------------------------------------------------------------------- 1 | export default (decimals = 0) => (value, cb) => cb(decimals ? value.toFixed(decimals) : Math.round(value)); -------------------------------------------------------------------------------- /src/core/js/transform/split.js: -------------------------------------------------------------------------------- 1 | export default (character = '') => (string, cb) => cb((string + '').split(character)); -------------------------------------------------------------------------------- /src/core/js/transform/spring.js: -------------------------------------------------------------------------------- 1 | import { createTranslator } from '../animate'; 2 | 3 | export default (stiffness, damping, mass) => { 4 | 5 | let current = null; 6 | let translator = null; 7 | 8 | return (value, cb) => { 9 | 10 | value = parseFloat(value); 11 | 12 | if (current === null) { 13 | current = value; 14 | cb(value); 15 | return; 16 | } 17 | 18 | if (!translator) { 19 | translator = createTranslator('spring', stiffness, damping, mass); 20 | translator.update(cb, current, value); 21 | } 22 | else { 23 | translator.update(cb, value); 24 | } 25 | 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /src/core/js/transform/step.js: -------------------------------------------------------------------------------- 1 | import { createTranslator } from '../animate'; 2 | 3 | export default (velocity) => { 4 | 5 | let initial = null; 6 | let previous = null; 7 | let translator = null; 8 | 9 | return (value, cb) => { 10 | 11 | value = parseFloat(value); 12 | 13 | if (initial === null) { 14 | initial = value; 15 | cb(value); 16 | return; 17 | } 18 | 19 | if (previous !== null && initial === value) { 20 | translator.cancel(); 21 | translator = null; 22 | } 23 | 24 | if (!translator) { 25 | translator = createTranslator('step', velocity); 26 | translator.update(cb, initial, value); 27 | } 28 | else { 29 | translator.update(cb, value); 30 | } 31 | 32 | previous = value; 33 | 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/core/js/transform/substring.js: -------------------------------------------------------------------------------- 1 | export default (from, to) => (value, cb) => cb((value + '').substring(from, to)); -------------------------------------------------------------------------------- /src/core/js/transform/subtract.js: -------------------------------------------------------------------------------- 1 | export default (amount) => (value, cb) => cb(value - amount); -------------------------------------------------------------------------------- /src/core/js/transform/transform.js: -------------------------------------------------------------------------------- 1 | export default (...transforms) => (value, cb) => { 2 | 3 | const output = []; 4 | const input = value; 5 | 6 | transforms.forEach((t, i) => { 7 | 8 | t(input, (out) => { 9 | 10 | output[i] = out; 11 | 12 | if (i === transforms.length - 1) { 13 | cb(output.length === 1 ? output[0] : output); 14 | } 15 | 16 | }); 17 | 18 | }); 19 | 20 | } -------------------------------------------------------------------------------- /src/core/js/transform/tween.js: -------------------------------------------------------------------------------- 1 | import { animate } from '../animate'; 2 | import { ExtensionType, getExtension } from '../extensions/index'; 3 | import { toDuration } from '../style'; 4 | 5 | export default (duration, ease = 'ease-linear', delay) => { 6 | 7 | duration = toDuration(duration); 8 | 9 | const easeFn = getExtension(ExtensionType.EASING_FUNCTION, ease); 10 | let cancel = null; 11 | let previous = null; 12 | 13 | return (value, cb) => { 14 | 15 | value = parseFloat(value); 16 | 17 | if (cancel) { 18 | cancel(); 19 | } 20 | 21 | // force value if 22 | // - no previous value defined 23 | // - is same value 24 | // - distance between from and to is too large 25 | if (previous === null || 26 | value === previous) { 27 | previous = value; 28 | cb(value); 29 | return; 30 | } 31 | 32 | const to = value; 33 | const from = previous; 34 | const dist = to - from; 35 | 36 | cancel = animate((p) => { 37 | cb(from + (p * dist)); 38 | }, () => { 39 | cancel = null; 40 | }, duration, easeFn, delay); 41 | 42 | previous = value; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /src/core/js/transform/upper.js: -------------------------------------------------------------------------------- 1 | export default () => (value, cb) => cb((value + '').toUpperCase()); -------------------------------------------------------------------------------- /src/core/js/transform/value.js: -------------------------------------------------------------------------------- 1 | export default (staticValue) => (value, cb) => cb(staticValue); -------------------------------------------------------------------------------- /src/core/js/transitions.js: -------------------------------------------------------------------------------- 1 | import { setTransform } from './dom'; 2 | import { toCSSValue } from './utils'; 3 | import cache from '../../shared/cache'; 4 | 5 | import { easeInOutQuad, } from './easing'; 6 | import { ExtensionType, addExtensions } from './extensions/index'; 7 | 8 | const Translation = { 9 | 'x':'translateX', 10 | 'y':'translateY', 11 | 'z':'translateZ' 12 | }; 13 | 14 | const Rotation = { 15 | 'x':'rotateX', 16 | 'y':'rotateY', 17 | 'z':'rotateZ' 18 | }; 19 | 20 | const Scalar = { 21 | 'both':'scale', 22 | 'x':'scaleX', 23 | 'y':'scaleY' 24 | }; 25 | 26 | 27 | /** 28 | * Helper methods 29 | */ 30 | const between = (from, to, p) => { 31 | return from + ((to - from) * p); 32 | }; 33 | 34 | 35 | /** 36 | * Single Element transitions 37 | */ 38 | const fade = (element, p, direction, ease = easeInOutQuad, from = 0, to = 1) => { 39 | if (direction < 0) { 40 | [from, to] = [to, from]; 41 | } 42 | element.style.opacity = between(from, to, ease(p)); 43 | }; 44 | 45 | const move = (element, p, direction, ease = easeInOutQuad, from = '0', to = '100%', axis = 'y') => { 46 | if (direction < 0) { 47 | [from, to] = [to, from]; 48 | } 49 | const f = cache(from, toCSSValue); 50 | const t = cache(to, toCSSValue); 51 | setTransform( 52 | element, 53 | Translation[axis], 54 | between(f.value, t.value, ease(p)), 55 | f.units || t.units 56 | ); 57 | }; 58 | 59 | const rotate = (element, p, direction, ease = easeInOutQuad, from = '0', to = '90deg', axis = 'x') => { 60 | if (direction < 0) { 61 | [from, to] = [to, from]; 62 | } 63 | const f = cache(from, toCSSValue); 64 | const t = cache(to, toCSSValue); 65 | setTransform( 66 | element, 67 | Rotation[axis], 68 | between(f.value, t.value, ease(p)), 69 | f.units || t.units 70 | ); 71 | }; 72 | 73 | const scale = (element, p, direction, ease = easeInOutQuad, from = 0, to = 1, axis = 'both') => { 74 | if (direction < 0) { 75 | [from, to] = [to, from]; 76 | } 77 | setTransform( 78 | element, 79 | Scalar[axis], 80 | between(from, to, ease(p)) 81 | ); 82 | }; 83 | 84 | /** 85 | * Composed 86 | */ 87 | import crossfade from './transitions/crossfade'; 88 | import swap from './transitions/swap'; 89 | import revolve from './transitions/revolve'; 90 | import zoom from './transitions/zoom'; 91 | 92 | /** 93 | * Available transitions 94 | */ 95 | export const Transitions = { 96 | fade, 97 | move, 98 | rotate, 99 | scale, 100 | 101 | // composed transitions 102 | crossfade, 103 | swap, 104 | revolve, 105 | zoom 106 | }; 107 | 108 | addExtensions(ExtensionType.TRANSITION, Transitions); -------------------------------------------------------------------------------- /src/core/js/transitions/crossfade.js: -------------------------------------------------------------------------------- 1 | import { toDuration } from '../style'; 2 | 3 | export default (speed = 1, delayIn, delayOut) => { 4 | return { 5 | intro:[{ name:'fade', parameters:[0,1], duration:1000 * speed, delay:toDuration(delayIn) }], 6 | outro:[{ name:'fade', parameters:[1,0], duration:1000 * speed, delay:toDuration(delayOut) }] 7 | } 8 | }; -------------------------------------------------------------------------------- /src/core/js/transitions/revolve.js: -------------------------------------------------------------------------------- 1 | import { toDuration } from '../style'; 2 | 3 | export default (axis = 'y', distance = 1, speed = 1, delayIn, delayOut) => { 4 | return { 5 | intro:[{ 6 | name:'rotate', 7 | parameters:[`${ -distance * 90 }deg`, '0deg', axis], 8 | duration:1000 * speed, 9 | delay:toDuration(delayIn) 10 | }], 11 | outro:[{ 12 | name:'rotate', 13 | parameters:['0deg', `${ distance * 90 }deg`, axis], 14 | duration:1000 * speed, 15 | delay:toDuration(delayOut) 16 | }] 17 | } 18 | }; -------------------------------------------------------------------------------- /src/core/js/transitions/swap.js: -------------------------------------------------------------------------------- 1 | import { toDuration } from '../style'; 2 | 3 | export default (axis = 'y', distance = 1, speed = 1, delayIn, delayOut) => { 4 | return { 5 | intro:[{ 6 | name:'move', 7 | parameters:[`${ -distance * 100 }`,'0%', axis], 8 | duration:1000 * speed, 9 | delay:toDuration(delayIn) 10 | }], 11 | outro:[{ 12 | name:'move', 13 | parameters:['0%',`${ distance * 100 }`, axis], 14 | duration:1000 * speed, 15 | delay:toDuration(delayOut) 16 | }] 17 | } 18 | }; -------------------------------------------------------------------------------- /src/core/js/transitions/zoom.js: -------------------------------------------------------------------------------- 1 | import { toDuration } from '../style'; 2 | 3 | export default (offset = 0, speed = 1, delayIn, delayOut) => { 4 | return { 5 | intro:[{ 6 | name:'scale', 7 | parameters:[offset, 1], 8 | duration:1000 * speed, 9 | delay:toDuration(delayIn) 10 | }], 11 | outro:[{ 12 | name:'scale', 13 | parameters:[1, offset], 14 | duration:1000 * speed, 15 | delay:toDuration(delayOut) 16 | }] 17 | } 18 | }; -------------------------------------------------------------------------------- /src/core/js/utils/capitalizeFirstLetter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param string { string } 3 | */ 4 | export const capitalizeFirstLetter = (string) => string.charAt(0).toUpperCase() + string.slice(1); -------------------------------------------------------------------------------- /src/core/js/utils/clone.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param obj { object } 3 | */ 4 | export const clone = (obj) => { 5 | if (typeof obj === 'object' && obj !== null) { 6 | return JSON.parse(JSON.stringify(obj)); 7 | } 8 | return obj; 9 | }; -------------------------------------------------------------------------------- /src/core/js/utils/lowercaseFirstLetter.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @param string { string } 4 | */ 5 | export const lowercaseFirstLetter = (string) => string.charAt(0).toLowerCase() + string.slice(1); 6 | -------------------------------------------------------------------------------- /src/core/js/utils/merge.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param a { object } 3 | * @param b { object } 4 | */ 5 | export const mergeObjects = (a, b = {}) => { 6 | 7 | let key; 8 | const obj = {}; 9 | 10 | for (key in a) { 11 | if (!a.hasOwnProperty(key)) { 12 | continue; 13 | } 14 | obj[key] = typeof b[key] === 'undefined' ? a[key] : b[key]; 15 | } 16 | 17 | return obj; 18 | }; -------------------------------------------------------------------------------- /src/core/js/utils/toBoolean.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param value { * } 3 | */ 4 | export const toBoolean = (value) => typeof value === 'string' ? value === 'true' : value; 5 | -------------------------------------------------------------------------------- /src/core/js/utils/trim.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param string { string } 3 | */ 4 | export const trim = string => string.trim(); -------------------------------------------------------------------------------- /src/core/js/view/destroyer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Destroyer 3 | * @param state 4 | */ 5 | export default (state) => { 6 | 7 | return { 8 | destroy:() => { 9 | 10 | state.destroyed = true; 11 | 12 | if (state.frame) { 13 | cancelAnimationFrame(state.frame); 14 | } 15 | 16 | if (state.styleObserver) { 17 | state.styleObserver.disconnect(); 18 | } 19 | 20 | if (state.didResizeWindow) { 21 | window.removeEventListener('resize', state.didResizeWindow); 22 | } 23 | 24 | if (state.root && state.root.parentNode) { 25 | state.root.parentNode.removeChild(state.root); 26 | } 27 | 28 | } 29 | } 30 | 31 | }; -------------------------------------------------------------------------------- /src/core/js/view/drawer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Drawer 3 | * @param state 4 | * @param draw 5 | * @param present 6 | * @param drawViews 7 | */ 8 | export default (state, draw, drawViews, present) => { 9 | return { 10 | draw: () => { 11 | // not dirty, might need to draw subviews 12 | if (!state.dirty) { 13 | if (drawViews) { 14 | // draw sub views 15 | const redrawn = drawViews(state); 16 | if (redrawn) { 17 | // let's fit it! (if necessary) 18 | fit(state); 19 | } 20 | } 21 | return false; 22 | } 23 | 24 | // draw everything 25 | draw(state, present); 26 | 27 | // let's fit this view (if necessary) 28 | fit(state); 29 | 30 | // no longer dirty 31 | state.dirty = false; 32 | 33 | return true; 34 | }, 35 | }; 36 | }; 37 | 38 | const fit = (state) => { 39 | if (!state.fit) { 40 | // nope 41 | if (!state.root || !(state.root.getAttribute('data-layout') || '').match(/fit/)) { 42 | state.fit = false; 43 | return; 44 | } 45 | 46 | // create fit info object 47 | const style = window.getComputedStyle(state.root, null); 48 | 49 | state.fit = true; 50 | state.fitInfo = { 51 | currentFontSize: parseInt(style.getPropertyValue('font-size'), 10), 52 | }; 53 | } 54 | 55 | // get available width from parent node 56 | state.fitInfo.availableWidth = state.root.parentNode.clientWidth; 57 | 58 | // the space our target element uses 59 | state.fitInfo.currentWidth = state.root.scrollWidth; 60 | 61 | // let's calculate the new font size 62 | const newFontSize = Math.min( 63 | Math.max( 64 | 4, 65 | (state.fitInfo.availableWidth / state.fitInfo.currentWidth) * 66 | state.fitInfo.currentFontSize 67 | ), 68 | 1024 69 | ); 70 | 71 | // size has not changed enough? 72 | const dist = Math.abs(newFontSize - state.fitInfo.currentFontSize); 73 | 74 | // prevents flickering on firefox / safari / ie by not redrawing tiny font size changes 75 | if (dist <= 1) return; 76 | 77 | state.fitInfo.currentFontSize = newFontSize; 78 | 79 | state.root.style.fontSize = state.fitInfo.currentFontSize + 'px'; 80 | 81 | // redraw once more to quickly create better fit 82 | if (state.fitInfo.currentWidth / state.fitInfo.availableWidth < 0.5) { 83 | requestAnimationFrame(() => fit(state)); 84 | } 85 | }; 86 | -------------------------------------------------------------------------------- /src/core/js/view/grouper.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Grouper 3 | * @param state 4 | * @param definition 5 | */ 6 | export default (state, definition) => { 7 | 8 | state.definition = definition; 9 | 10 | return { 11 | setDefinition:(definition) => { 12 | state.definition = definition; 13 | } 14 | }; 15 | 16 | }; 17 | -------------------------------------------------------------------------------- /src/core/js/view/index.js: -------------------------------------------------------------------------------- 1 | import createRoot from './root'; 2 | import createRepeater from './repeater'; 3 | 4 | /** 5 | * View Composers 6 | */ 7 | import rooter from './rooter'; 8 | import drawer from './drawer'; 9 | import updater from './updater'; 10 | import styler from './styler'; 11 | import grouper from './grouper'; 12 | import resizer from './resizer'; 13 | import destroyer from './destroyer'; 14 | 15 | /** 16 | * API Utilities 17 | */ 18 | import { toPixels, toColor } from '../style'; 19 | import { request, now } from '../utils'; 20 | import { text, create, setTransform, isVisible } from '../dom'; 21 | import { clearCanvas, getDevicePixelRatio, getBackingStoreRatio } from '../canvas'; 22 | import { animate } from '../animate'; 23 | import { ExtensionType, getExtension, addExtensions } from '../extensions/index'; 24 | 25 | 26 | /** 27 | * Add default text view 28 | */ 29 | export const Views = { 30 | 'text':() => (root) => { 31 | 32 | const state = {}; 33 | 34 | const draw = (state) => { 35 | state.root.setAttribute('data-value', state.value); 36 | text(state.root, state.value); 37 | }; 38 | 39 | return Object.assign( 40 | {}, 41 | rooter(state, root, 'text'), 42 | updater(state), 43 | drawer(state, draw), 44 | destroyer(state) 45 | ); 46 | } 47 | 48 | }; 49 | 50 | addExtensions(ExtensionType.VIEW, Views); 51 | 52 | 53 | /** 54 | * Internal API for use by views 55 | */ 56 | const API = () => ({ 57 | Extension:{ 58 | Type: ExtensionType, 59 | getExtension 60 | }, 61 | Utils: { 62 | toPixels, 63 | toColor 64 | }, 65 | Canvas: { 66 | clear: clearCanvas, 67 | getDevicePixelRatio, 68 | getBackingStoreRatio 69 | }, 70 | DOM: { 71 | visible: isVisible, 72 | create, 73 | transform: setTransform 74 | }, 75 | Animation: { 76 | animate 77 | }, 78 | Data: { 79 | request, 80 | }, 81 | Date: { 82 | performance: now 83 | }, 84 | View: { 85 | rooter, 86 | drawer, 87 | updater, 88 | styler, 89 | grouper, 90 | resizer, 91 | destroyer 92 | } 93 | }); 94 | 95 | 96 | /** 97 | * Base view definitions 98 | */ 99 | export const createPresenterRoot = (root, definition, presentDefinition) => createRoot(root, definition, presentDefinition); 100 | 101 | export const createPresenterRepeater = (root, definition, presentDefinition) => createRepeater(root, definition, presentDefinition); 102 | 103 | export const createPresenterView = (name, root, style) => { 104 | const view = getExtension(ExtensionType.VIEW, name); 105 | return view ? view(API())(root, style) : null; 106 | }; -------------------------------------------------------------------------------- /src/core/js/view/repeater.js: -------------------------------------------------------------------------------- 1 | import destroyer from './destroyer'; 2 | import rooter from './rooter'; 3 | import grouper from './grouper'; 4 | import drawer from './drawer'; 5 | import updater from './updater'; 6 | 7 | import { cloneDefinition, copyArray } from '../utils'; 8 | 9 | const draw = (state, present, ready) => { 10 | 11 | // if value is not in form of array force to array 12 | const value = copyArray(Array.isArray(state.value) ? state.value : (state.value + '').split('')); 13 | 14 | // if we're aligned to the right we will append items differently so view updating is less jumpy 15 | if (state.align === 'right') { 16 | value.reverse(); 17 | } 18 | 19 | // clean up presenters if too much presenters 20 | if (state.definitions.length > value.length) { 21 | while(state.definitions.length > value.length) { 22 | const def = state.definitions.pop(); 23 | def.presenter.destroy(); 24 | } 25 | } 26 | 27 | // setup presenters 28 | value.forEach((value, index) => { 29 | 30 | let def = state.definitions[index]; 31 | if (!def) { 32 | def = state.definitions[index] = cloneDefinition(state.definition); 33 | state.update = present(def); 34 | def.presenter.appendTo(state.root, state.align === 'right' ? 'first' : 'last'); 35 | } 36 | 37 | }); 38 | 39 | // let's update all subs (possibly sets dirty flag) 40 | value.forEach( 41 | (value, index) => state.update(state.definitions[index], value) 42 | ); 43 | 44 | state.views = value; 45 | 46 | // also draw subviews 47 | drawViews(state); 48 | }; 49 | 50 | const drawViews = (state) => { 51 | 52 | let redrawn = false; 53 | state.views.forEach((view, index) => { 54 | if (state.definitions[index].presenter.draw()) { 55 | redrawn = true; 56 | } 57 | }); 58 | return redrawn; 59 | 60 | }; 61 | 62 | export default (root, definition, present) => { 63 | 64 | const state = { 65 | definitions:[] 66 | }; 67 | 68 | 69 | return Object.assign( 70 | {}, 71 | rooter(state, root), 72 | updater(state), 73 | grouper(state, definition), 74 | drawer(state, draw, drawViews, present), 75 | destroyer(state) 76 | ); 77 | 78 | } -------------------------------------------------------------------------------- /src/core/js/view/resizer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Resizer 3 | * @param state 4 | */ 5 | export default (state) => { 6 | 7 | state.didResizeWindow = () => { 8 | state.dirty = true; 9 | }; 10 | 11 | window.addEventListener('resize', state.didResizeWindow); 12 | 13 | }; -------------------------------------------------------------------------------- /src/core/js/view/root.js: -------------------------------------------------------------------------------- 1 | import destroyer from './destroyer'; 2 | import rooter from './rooter'; 3 | import grouper from './grouper'; 4 | import drawer from './drawer'; 5 | import updater from './updater'; 6 | import resizer from './resizer'; 7 | 8 | import { clone } from '../utils'; 9 | 10 | const draw = (state, present) => { 11 | const views = (state.definition || []).concat(); 12 | 13 | if (state.align === 'right') { 14 | views.reverse(); 15 | } 16 | 17 | const value = Array.isArray(state.value) 18 | ? state.value.concat() 19 | : typeof state.value === 'object' 20 | ? clone(state.value) 21 | : state.value; 22 | 23 | views.forEach((view) => { 24 | if (!view.presenter) { 25 | state.update = present(view); 26 | if (!view.presenter) { 27 | return; 28 | } 29 | view.presenter.appendTo(state.root); 30 | } 31 | }); 32 | 33 | views 34 | .filter((view) => view.presenter !== undefined) 35 | .forEach((view) => { 36 | if (Array.isArray(value) && state.valueMapping) { 37 | // if set to indexes divide values over views, else (must be "none") just pass array 38 | state.update( 39 | view, 40 | state.valueMapping === 'indexes' 41 | ? state.align === 'right' 42 | ? value.pop() 43 | : value.shift() 44 | : value 45 | ); 46 | } else if (view.key && value[view.key] !== undefined) { 47 | // view expects a key so value should be object 48 | state.update(view, value[view.key]); 49 | } else { 50 | // just pass on value to all sub views 51 | state.update(view, value); 52 | } 53 | }); 54 | 55 | state.views = views; 56 | 57 | // also draw subviews 58 | drawViews(state); 59 | }; 60 | 61 | const drawViews = (state) => { 62 | let redrawn = false; 63 | state.views 64 | .filter((view) => view.presenter !== undefined) 65 | .forEach((view) => { 66 | if (view.presenter.draw()) { 67 | redrawn = true; 68 | } 69 | }); 70 | return redrawn; 71 | }; 72 | 73 | export default (root, definition, present) => { 74 | const state = { 75 | valueMapping: null, // "none" or "indexes" 76 | }; 77 | 78 | if (root && root.dataset.valueMapping) { 79 | const allowed = ['none', 'indexes']; 80 | const mapping = root.dataset.valueMapping; 81 | state.valueMapping = allowed.indexOf(mapping) !== -1 ? mapping : null; 82 | } 83 | 84 | return Object.assign( 85 | {}, 86 | rooter(state, root), 87 | resizer(state), 88 | updater(state), 89 | grouper(state, definition), 90 | drawer(state, draw, drawViews, present), 91 | destroyer(state) 92 | ); 93 | }; 94 | -------------------------------------------------------------------------------- /src/core/js/view/rooter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Rooter 3 | * @param state 4 | * @param root 5 | * @param name 6 | */ 7 | export default (state, root = document.createElement('span'), name = null) => { 8 | 9 | state.root = root; 10 | state.aligned = null; 11 | state.destroyed = false; 12 | 13 | if (root && name) { 14 | state.root.classList.add(`tick-${name}`); 15 | state.root.setAttribute('data-view', name); 16 | } 17 | 18 | if (root && root.dataset.layout) { 19 | state.align = (root.dataset.layout.match(/left|right|center/) || [])[0] || 'left'; 20 | } 21 | 22 | return { 23 | 24 | appendTo:(element, location = 'last') => { 25 | 26 | // if no root or already attached -> exit 27 | if (!state.root || (state.root && state.root.parentNode)) {return;} 28 | 29 | if (location === 'last') { 30 | // place before last text node if found 31 | if (element.childNodes.length && element.childNodes[element.childNodes.length-1].nodeType === Node.TEXT_NODE) { 32 | element.insertBefore(state.root, element.childNodes[element.childNodes.length-1]); 33 | } 34 | else { 35 | // else just append 36 | element.appendChild(state.root); 37 | } 38 | return; 39 | } 40 | 41 | if (location === 'first') { 42 | // no elements and no text 43 | if (element.childNodes.length === 0) { 44 | element.appendChild(state.root); 45 | } 46 | // no elements but does contain text 47 | else if (element.children.length === 0 && element.childNodes.length) { 48 | element.insertBefore(state.root, element.childNodes[element.childNodes.length - 1]); 49 | } 50 | // elements! 51 | else { 52 | element.insertBefore(state.root, element.children[0]); 53 | } 54 | } 55 | 56 | if (typeof location !== 'string') { 57 | element.insertBefore(state.root, location); 58 | } 59 | 60 | } 61 | 62 | }; 63 | 64 | }; -------------------------------------------------------------------------------- /src/core/js/view/styler.js: -------------------------------------------------------------------------------- 1 | import { observeAttributes } from '../dom'; 2 | import { mergeObjects, clone } from '../utils'; 3 | import { toStyles } from '../style'; 4 | import { getComposedTransitionActs, createTransitioner } from './transitioner'; 5 | 6 | /** 7 | * Styler 8 | * @param state 9 | * @param base 10 | */ 11 | export default (state, base = {}) => { 12 | 13 | // styles that were last applied to the element 14 | state.lastAppliedStyles = null; 15 | 16 | // set default style 17 | updateStyles(state, base, state.root.dataset.style); 18 | 19 | // setup observer, will observe style attribute so can restyle when changed 20 | state.styleObserver = observeAttributes(state.root, ['data-style'], (string) => { 21 | updateStyles(state, base, string); 22 | }); 23 | 24 | // adds style setter 25 | return { 26 | setStyle:(css) => { 27 | updateStyles(state, base, css); 28 | } 29 | } 30 | 31 | }; 32 | 33 | const updateStyles = (state, base, css) => { 34 | 35 | // don't update if is same 36 | if (state.lastAppliedStyles === css) { 37 | return; 38 | } 39 | 40 | // remember these styles 41 | state.lastAppliedStyles = css; 42 | 43 | state.style = css ? mergeObjects(base, toStyles(css)) : base; 44 | 45 | let intro = []; 46 | let outro = []; 47 | 48 | if (state.style.transitionIn && state.style.transitionIn.length) { 49 | intro = state.style.transitionIn; 50 | outro = state.style.transitionOut; 51 | } 52 | else if (state.style.transition && state.style.transition !== 'none') { 53 | 54 | state.style.transition.forEach(transition => { 55 | const acts = getComposedTransitionActs(transition); 56 | intro = intro.concat(acts.intro); 57 | outro = outro.concat(acts.outro); 58 | }); 59 | 60 | } 61 | 62 | if (intro && outro) { 63 | state.transitionIn = createTransitioner(intro); 64 | state.transitionOut = createTransitioner(outro); 65 | 66 | state.skipToTransitionInEnd = createTransitioner(intro.map(clearTiming)); 67 | state.skipToTransitionOutEnd = createTransitioner(outro.map(clearTiming)); 68 | } 69 | 70 | state.dirty = true; 71 | }; 72 | 73 | const clearTiming = t => { 74 | const tn = clone(t); 75 | tn.duration = 0; 76 | tn.delay = 0; 77 | return tn; 78 | }; -------------------------------------------------------------------------------- /src/core/js/view/transitioner.js: -------------------------------------------------------------------------------- 1 | import { interpolate } from '../animate'; 2 | import { setTransformOrigin, isHTMLElement } from '../dom'; 3 | import { ExtensionType, getExtension } from '../extensions/index'; 4 | 5 | /** 6 | * Returns a function that applies the transitions to the given element 7 | * @param transitions 8 | * @returns {function(*)} 9 | */ 10 | export const createTransitioner = (transitions) => { 11 | 12 | const transitioners = transitions.map(t => { 13 | return createDurationTransitioner( 14 | createTransition(t.name, t.parameters, t.ease), 15 | t.origin, t.duration, t.delay 16 | ); 17 | }); 18 | 19 | return (element, direction, complete) => { 20 | 21 | // don't run animations when no element is supplied 22 | if (!isHTMLElement(element)) { 23 | return false; 24 | } 25 | 26 | let count = transitioners.length; 27 | transitioners.forEach(transitioner => { 28 | transitioner(element, direction, () => { 29 | count--; 30 | if (!count && complete) { 31 | complete(element); 32 | } 33 | }); 34 | }); 35 | 36 | } 37 | 38 | }; 39 | 40 | const createTransition = (name, parameters, ease) => { 41 | const easing = ease ? getExtension(ExtensionType.EASING_FUNCTION, ease) : ease; 42 | const transition = getExtension(ExtensionType.TRANSITION, name); 43 | return (element, direction, p) => { 44 | transition(element, p, direction, easing, ...parameters); 45 | } 46 | }; 47 | 48 | const createDurationTransitioner = (transition, origin = '50% 50% 0', duration = 500, delay) => { 49 | 50 | return (element, direction = 1, complete) => { 51 | 52 | // set transform origin 53 | setTransformOrigin(element, origin); 54 | 55 | // run animation 56 | interpolate(p => { 57 | transition(element, direction, p); 58 | }, complete, duration, delay); 59 | 60 | }; 61 | 62 | }; 63 | 64 | export const getComposedTransitionActs = (transition) => { 65 | return getExtension(ExtensionType.TRANSITION, transition.name)(...(transition.parameters || [])); 66 | }; -------------------------------------------------------------------------------- /src/core/js/view/updater.js: -------------------------------------------------------------------------------- 1 | import { equal } from '../utils'; 2 | 3 | export default (state) => { 4 | 5 | state.dirty = true; 6 | state.value = null; 7 | state.valueUpdateCount = 0; 8 | state.isInitialValue = () => { 9 | return state.valueUpdateCount <= 1; 10 | }; 11 | 12 | return { 13 | reset: () => { 14 | state.dirty = true; 15 | state.value = null; 16 | state.valueUpdateCount = 0; 17 | }, 18 | update:(value) => { 19 | 20 | // don't update on same value 21 | if (equal(state.value, value)) { 22 | return; 23 | } 24 | 25 | state.value = value; 26 | state.valueUpdateCount++; 27 | state.dirty = true; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/core/sass/index.scss: -------------------------------------------------------------------------------- 1 | .tick { 2 | box-sizing: border-box; 3 | * { 4 | box-sizing: inherit; 5 | } 6 | 7 | user-select: none; 8 | cursor: default; 9 | position: relative; 10 | z-index: 1; 11 | line-height: 1.4; 12 | 13 | [data-view] { 14 | max-width: 100%; 15 | } 16 | 17 | span[data-view] { 18 | display: inline-block; 19 | } 20 | 21 | // credits 22 | .tick-credits { 23 | position: absolute; 24 | right: 0; 25 | bottom: 0; 26 | opacity: 0.4; 27 | text-decoration: none; 28 | font-size: 11px; 29 | color: inherit; 30 | } 31 | 32 | // layout 33 | @import 'modules/layout'; 34 | } 35 | -------------------------------------------------------------------------------- /src/core/sass/modules/_layout.scss: -------------------------------------------------------------------------------- 1 | [data-layout~='pad'] { 2 | margin:-.25em; 3 | >* { 4 | margin:.25em; 5 | } 6 | } 7 | 8 | [data-layout~='horizontal'] { 9 | 10 | display:flex; 11 | flex-direction:row; 12 | justify-content:center; 13 | 14 | &[data-layout~='baseline'] { 15 | align-items:baseline; 16 | } 17 | 18 | &[data-layout~='center'] { 19 | justify-content:center; 20 | } 21 | 22 | &[data-layout~='right'] { 23 | justify-content:flex-end; 24 | } 25 | 26 | &[data-layout~='left'] { 27 | justify-content:flex-start; 28 | } 29 | 30 | &[data-layout~='stretch'], 31 | &[data-layout~='fill'] { 32 | align-content:stretch; 33 | flex-wrap:nowrap; 34 | >* { 35 | flex: 1 0 0; 36 | } 37 | 38 | // IE 11 fixes 39 | >* { 40 | width:100% 41 | } 42 | } 43 | 44 | &[data-layout~='multi-line'] { 45 | flex-wrap:wrap; 46 | } 47 | 48 | &[data-layout~='fit'] { 49 | display:inline-flex; 50 | flex-wrap:nowrap; 51 | align-content:center; 52 | white-space:nowrap; 53 | justify-content:flex-start; 54 | } 55 | } 56 | 57 | [data-layout~='vertical'] { 58 | display:flex; 59 | flex-direction:column; 60 | align-items:center; 61 | 62 | &[data-layout~='top'] { 63 | justify-content:flex-start; 64 | } 65 | 66 | &[data-layout~='bottom'] { 67 | justify-content:flex-end; 68 | min-height:100%; 69 | } 70 | 71 | &[data-layout~='middle'] { 72 | justify-content:center; 73 | min-height:100%; 74 | } 75 | 76 | &[data-layout~='left'] { 77 | align-items:flex-start; 78 | } 79 | 80 | &[data-layout~='right'] { 81 | align-items:flex-end; 82 | } 83 | 84 | &[data-layout~='center'] { 85 | text-align:center; 86 | } 87 | 88 | &[data-layout~='stretch'], 89 | &[data-layout~='fill'] { 90 | align-items:stretch; 91 | min-height:100%; 92 | >* { 93 | flex: 1 0 0; 94 | } 95 | } 96 | 97 | >*+* { 98 | margin-top:.5em; 99 | } 100 | } 101 | 102 | [data-layout~='overlay'] { 103 | 104 | position:relative; 105 | 106 | > * { 107 | margin:0; 108 | } 109 | 110 | &[data-layout~='center'] { 111 | text-align:center; 112 | } 113 | 114 | &[data-layout~='left'] { 115 | text-align:left; 116 | } 117 | 118 | &[data-layout~='right'] { 119 | text-align:right; 120 | } 121 | 122 | >[data-overlay='stretch'], 123 | >[data-overlay='fill'] { 124 | position:absolute; 125 | left:0; 126 | right:0; 127 | top:0; 128 | bottom:0; 129 | } 130 | 131 | >[data-overlay='center'] { 132 | display:flex; 133 | align-items: center; 134 | justify-content: center; 135 | position:absolute; 136 | left:0; 137 | right:0; 138 | top:0; 139 | bottom:0; 140 | } 141 | } -------------------------------------------------------------------------------- /src/extensions/extension.amd.js: -------------------------------------------------------------------------------- 1 | define(__LIB__); -------------------------------------------------------------------------------- /src/extensions/extension.commonjs.js: -------------------------------------------------------------------------------- 1 | module.exports = (__LIB__()); -------------------------------------------------------------------------------- /src/extensions/extension.global.js: -------------------------------------------------------------------------------- 1 | (function(root, undefined) { 2 | 'use strict'; 3 | 4 | // only create tick extensions queue if not already available 5 | if (!root.Tick) { 6 | root.Tick = []; 7 | } 8 | 9 | // add this extension 10 | root.Tick.push(['__TYPE__', '__NAME__', (__LIB__())]); 11 | 12 | }(window)); -------------------------------------------------------------------------------- /src/extensions/extension.jquery.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 'use strict'; 3 | 4 | if (!$) { return; } 5 | 6 | // only create tick extensions queue if not already available 7 | if (!$.tick) { 8 | $.tick = []; 9 | } 10 | 11 | // add this extension 12 | $.tick.push(['__TYPE__', '__NAME__', (__LIB__())]); 13 | 14 | }(window.jQuery)); -------------------------------------------------------------------------------- /src/extensions/extension.module.js: -------------------------------------------------------------------------------- 1 | export default typeof window !== 'undefined' ? (__LIB__()) : null; -------------------------------------------------------------------------------- /src/extensions/view/boom/js/index.js: -------------------------------------------------------------------------------- 1 | export default ({ 2 | Data: { request }, 3 | Date: { performance }, 4 | View: { rooter, destroyer, drawer, updater, styler } 5 | } = API) => { 6 | const AudioContext = 7 | typeof window !== 'undefined' 8 | ? window.AudioContext || window.webkitAudioContext 9 | : null; 10 | const context = AudioContext ? new AudioContext() : null; 11 | 12 | const getBuffer = (context, data, cb) => { 13 | context.decodeAudioData(data, function(buffer) { 14 | cb(buffer); 15 | }); 16 | }; 17 | 18 | const preload = (context, files, cb) => { 19 | (Array.isArray(files) ? files : [files]).forEach(file => { 20 | // load source files 21 | request( 22 | file, 23 | res => { 24 | // handle success response 25 | getBuffer(context, res, cb); 26 | }, 27 | err => { 28 | // handle error 29 | }, 30 | xhr => { 31 | // dress up xhr 32 | xhr.responseType = 'arraybuffer'; 33 | } 34 | ); 35 | }); 36 | }; 37 | 38 | const createSound = (context, buffer) => { 39 | const source = context.createBufferSource(); 40 | source.buffer = buffer; 41 | return source; 42 | }; 43 | 44 | const draw = state => { 45 | if ( 46 | !context || 47 | state.style.sample === null || 48 | !state.style.sample.length 49 | ) { 50 | return; 51 | } 52 | 53 | if (!state.audioLoaded) { 54 | // create volume node 55 | state.volume = context.createGain(); 56 | state.volume.connect(context.destination); 57 | 58 | // load audio 59 | preload(context, state.style.sample, buffer => { 60 | if (!buffer || state.buffer) { 61 | return; 62 | } 63 | state.buffer = buffer; 64 | state.audioLoaded = true; 65 | }); 66 | 67 | // don't play sounds on first draw 68 | return; 69 | } 70 | 71 | // don't play sound if value has not changed 72 | if (state.value === state.lastValue) { 73 | return; 74 | } 75 | 76 | // play sound 77 | const sound = createSound(context, state.buffer); 78 | sound.connect(state.volume); 79 | state.volume.gain.value = state.style.volume; 80 | 81 | const currentDraw = performance(); 82 | const dist = currentDraw - state.lastDraw; 83 | if (dist < state.style.pitchThreshold) { 84 | state.currentPitch = Math.min( 85 | state.style.pitchMax, 86 | state.currentPitch + state.style.pitchStep 87 | ); 88 | } else { 89 | state.currentPitch = 1; 90 | } 91 | state.lastDraw = currentDraw; 92 | sound.playbackRate.value = state.currentPitch; 93 | sound.start(context.currentTime); 94 | 95 | // remember this value 96 | state.lastValue = state.value; 97 | }; 98 | 99 | return root => { 100 | const state = { 101 | audioLoaded: false, 102 | buffer: null, 103 | lastDraw: 0, 104 | currentPitch: 1, 105 | volume: null, 106 | lastValue: null 107 | }; 108 | 109 | return Object.assign( 110 | {}, 111 | rooter(state, root, 'boom'), 112 | updater(state), 113 | styler(state, { 114 | sample: null, 115 | volume: 0.5, // range from 0 to 1, 116 | pitchThreshold: 1000, 117 | pitchStep: 0.05, 118 | pitchMax: 1.35 119 | }), 120 | destroyer(state), 121 | drawer(state, draw) 122 | ); 123 | }; 124 | }; 125 | -------------------------------------------------------------------------------- /src/extensions/view/boom/sass/index.scss: -------------------------------------------------------------------------------- 1 | [data-view='boom'], 2 | .tick-audio { 3 | display:none; 4 | } -------------------------------------------------------------------------------- /src/extensions/view/dots/sass/index.scss: -------------------------------------------------------------------------------- 1 | @import './modules/layout'; 2 | @import './modules/default'; -------------------------------------------------------------------------------- /src/extensions/view/dots/sass/modules/_default.scss: -------------------------------------------------------------------------------- 1 | .tick-dots-character { 2 | margin:0 .25em; 3 | } 4 | 5 | .tick-dots-dot { 6 | width:5px; 7 | height:5px; 8 | margin:1px; 9 | background-color:currentColor; 10 | border-radius:2px; 11 | } -------------------------------------------------------------------------------- /src/extensions/view/dots/sass/modules/_layout.scss: -------------------------------------------------------------------------------- 1 | .tick-dots { 2 | 3 | vertical-align:middle; 4 | white-space:nowrap; 5 | 6 | .tick-dots-display { 7 | display:flex; 8 | flex-direction:row; 9 | flex-wrap:nowrap; 10 | justify-content:center; 11 | } 12 | 13 | .tick-dots-character > div { 14 | line-height:0; 15 | } 16 | 17 | .tick-dots-character > div > div { 18 | display:inline-block; 19 | perspective:4em; 20 | vertical-align:top; 21 | } 22 | 23 | .tick-dots-dot { 24 | display:block; 25 | outline:1px solid transparent; 26 | } 27 | 28 | &[data-style*='square'] .tick-dots-dot { 29 | border-radius:0 !important; 30 | } 31 | 32 | &[data-style*='round'] .tick-dots-dot, 33 | &[data-style*='circle'] .tick-dots-dot { 34 | border-radius:9999px !important; 35 | } 36 | } -------------------------------------------------------------------------------- /src/extensions/view/line/js/bar.js: -------------------------------------------------------------------------------- 1 | export default ({ 2 | DOM, 3 | View:{ rooter, destroyer, drawer, updater, styler } } = API) => { 4 | 5 | const draw = (state) => { 6 | 7 | // initial draw 8 | if (!state.rail) { 9 | state.rail = DOM.create('span','tick-line-rail'); 10 | state.fill = DOM.create('span','tick-line-fill'); 11 | state.rail.appendChild(state.fill); 12 | state.root.appendChild(state.rail); 13 | } 14 | 15 | // update style of bar 16 | if (state.style.fillColor) { 17 | state.fill.style.backgroundColor = state.style.fillColor; 18 | } 19 | 20 | if (state.style.railColor) { 21 | state.rail.style.backgroundColor = state.style.railColor; 22 | } 23 | 24 | // update bar 25 | DOM.transform( 26 | state.fill, 27 | state.style.orientation === 'horizontal' ? 'translateX' : 'translateY', 28 | state.style.flip ? 29 | // flipped 30 | -100 + (state.style.orientation === 'horizontal' ? 1 : -1) * state.value * 100 : 31 | 32 | // normal 33 | (state.style.orientation === 'horizontal' ? 1 : -1) * state.value * 100, 34 | '%' 35 | ); 36 | 37 | }; 38 | 39 | return (root) => { 40 | 41 | const state = { 42 | rail: null, 43 | fill: null 44 | }; 45 | 46 | return Object.assign( 47 | {}, 48 | rooter(state, root, 'line'), 49 | updater(state), 50 | styler(state, { 51 | flip: false, // true 52 | fillColor: null, // color, { colors: ['red', 'blue'], type: 'horizontal' } 53 | railColor: null, // color, { colors: ['red', 'blue'], type: 'follow' } 54 | capStyle: 'auto', // auto is set by CSS, round, square, butt 55 | orientation: 'horizontal' // vertical 56 | }), 57 | drawer(state, draw), 58 | destroyer(state) 59 | ); 60 | 61 | }; 62 | }; -------------------------------------------------------------------------------- /src/extensions/view/line/js/index.js: -------------------------------------------------------------------------------- 1 | import createBar from './bar'; 2 | import createRing from './ring'; 3 | 4 | export default (API) => (root) => /shape:\s*(?:ring|circle)/.test(root.dataset.style) ? createRing(API)(root) : createBar(API)(root); -------------------------------------------------------------------------------- /src/extensions/view/line/sass/index.scss: -------------------------------------------------------------------------------- 1 | @import './modules/layout'; 2 | @import './modules/default'; -------------------------------------------------------------------------------- /src/extensions/view/line/sass/modules/_default.scss: -------------------------------------------------------------------------------- 1 | .tick-line-rail { 2 | background-color:#eee; 3 | } 4 | 5 | .tick-line-fill { 6 | background-color:currentColor; 7 | } -------------------------------------------------------------------------------- /src/extensions/view/line/sass/modules/_layout.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Bar 3 | */ 4 | .tick-line-rail { 5 | display:block; 6 | overflow:hidden; 7 | position:relative; 8 | transform:translateZ(0); 9 | } 10 | 11 | .tick-line-fill { 12 | position:absolute; 13 | height:100%; 14 | width:100%; 15 | backface-visibility:hidden; 16 | } 17 | 18 | .tick-line[data-style*='round'] { 19 | .tick-line-fill, 20 | .tick-line-rail { 21 | border-radius:9999px; 22 | } 23 | } 24 | 25 | .tick :not([data-style*='vertical']) .tick-line-rail { 26 | min-width:2em; 27 | min-height:.125em; 28 | .tick-line-fill { 29 | left:-100%; 30 | top:0; 31 | } 32 | } 33 | 34 | .tick [data-style*='vertical'] .tick-line-rail { 35 | display:inline-block; 36 | vertical-align:top; 37 | min-height:2em; 38 | min-width:.125em; 39 | .tick-line-fill { 40 | left:0; 41 | top:100%; 42 | } 43 | } 44 | 45 | /** 46 | * Ring default styles 47 | */ 48 | .tick-line { 49 | z-index:-1; 50 | > canvas { 51 | display:block; 52 | width:100%; // enforces initial render size but is overwritten inline when drawn 53 | max-width:100%; // enforces size after initial draw 54 | } 55 | } -------------------------------------------------------------------------------- /src/extensions/view/swap/js/index.js: -------------------------------------------------------------------------------- 1 | export default ({ 2 | DOM, 3 | View:{ rooter, destroyer, drawer, updater, styler } } = API) => { 4 | 5 | 6 | const draw = (state) => { 7 | 8 | if (!state.spacer) { 9 | 10 | // remove initial content 11 | state.root.textContent = ''; 12 | 13 | state.spacer = DOM.create('span', 'tick-swap-spacer'); 14 | state.root.appendChild(state.spacer); 15 | } 16 | 17 | // set value 18 | state.spacer.textContent = state.value; 19 | 20 | // remove finished transitions 21 | state.textTransitions = state.textTransitions.filter(textTransition => !textTransition.hidden); 22 | 23 | const currentText = state.textTransitions[state.textTransitions.length - 1]; 24 | 25 | // get current value 26 | const currentValue = currentText ? currentText.value : 0; 27 | 28 | // calculate animation direction 29 | const direction = state.style.transitionDirection === 'detect' ? state.value - currentValue : state.style.transitionDirection === 'reverse' ? -1 : 1; 30 | 31 | // hide all previous transitions 32 | state.textTransitions.forEach(textTransition => { 33 | textTransition.hide(direction); 34 | }); 35 | 36 | // create animation 37 | const nextText = createTextTransition(state.value, state.transitionIn, state.transitionOut); 38 | nextText.appendTo(state.root); 39 | 40 | if (state.isInitialValue()) { 41 | nextText.showNow(); 42 | } 43 | else { 44 | nextText.show(direction); 45 | } 46 | 47 | state.textTransitions.push(nextText); 48 | }; 49 | 50 | 51 | const createTextTransition = (text, transitionIn, transitionOut) => { 52 | 53 | const state = { 54 | shouldHide:false, 55 | hiding:false, 56 | hidden:false, 57 | shown:false, 58 | value:text 59 | }; 60 | 61 | const root = DOM.create('span', 'tick-swap-transition'); 62 | root.textContent = text; 63 | root.dataset.value = text; 64 | 65 | const api = { 66 | showNow:() => { 67 | state.shown = true; 68 | }, 69 | show:(direction) => { 70 | 71 | // animate into view 72 | 73 | (direction > 0 ? transitionIn : transitionOut)(state.root, direction, () => { 74 | 75 | // done, test if should hide 76 | state.shown = true; 77 | 78 | // hide immidiately if the hide method has been called earlier 79 | if (state.shouldHide) { 80 | api.hide(direction); 81 | } 82 | }); 83 | 84 | }, 85 | hide:(direction) => { 86 | 87 | // already hiding 88 | if (state.hiding || state.hidden) { 89 | return; 90 | } 91 | 92 | // should be hidden when shown 93 | state.shouldHide = true; 94 | 95 | // are we shown yet? 96 | if (!state.shown) { 97 | return; 98 | } 99 | 100 | // already hiding 101 | state.hiding = true; 102 | 103 | // yes we are, let's hide immidiately 104 | (direction > 0 ? transitionOut : transitionIn)(state.root, direction, () => { 105 | 106 | // no longer hiding 107 | state.hiding = false; 108 | 109 | // clean up 110 | state.hidden = true; 111 | 112 | // remove from DOM 113 | state.root.parentNode.removeChild(state.root); 114 | 115 | }) 116 | 117 | } 118 | }; 119 | 120 | Object.defineProperty(api, 'value', { 121 | get: function () { 122 | return state.value; 123 | } 124 | }); 125 | 126 | return Object.assign( 127 | api, 128 | rooter(state, root) 129 | ); 130 | }; 131 | 132 | return (root) => { 133 | 134 | const state = { 135 | spacer:null, 136 | textTransitions:[] 137 | }; 138 | 139 | 140 | return Object.assign( 141 | {}, 142 | rooter(state, root, 'swap'), 143 | updater(state), 144 | styler(state, { 145 | transition:[{ name: 'crossfade' }], 146 | transitionIn:[], 147 | transitionOut:[], 148 | transitionDirection:'forward' // 'forward', 'reverse', 'detect' 149 | }), 150 | drawer(state, draw), 151 | destroyer(state) 152 | ); 153 | 154 | }; 155 | 156 | }; -------------------------------------------------------------------------------- /src/extensions/view/swap/sass/index.scss: -------------------------------------------------------------------------------- 1 | @import './modules/layout'; 2 | @import './modules/default'; -------------------------------------------------------------------------------- /src/extensions/view/swap/sass/modules/_default.scss: -------------------------------------------------------------------------------- 1 | .tick-swap[data-style*='transition'] { 2 | // prevents width changes when animating between empty space and characters 3 | min-width:1ex; 4 | text-align:center; 5 | } 6 | -------------------------------------------------------------------------------- /src/extensions/view/swap/sass/modules/_layout.scss: -------------------------------------------------------------------------------- 1 | .tick-swap { 2 | 3 | position:relative; 4 | 5 | // set default perspective when doing animations 6 | // makes 3d animations have a bit more depth 7 | &[data-style*='transition'] { 8 | perspective:4em; 9 | transform-style:preserve-3d; 10 | } 11 | 12 | .tick-swap-spacer { 13 | position:relative; 14 | display:block; 15 | white-space:pre; 16 | visibility:hidden; 17 | } 18 | 19 | .tick-swap-transition, 20 | .tick-swap-spacer { 21 | backface-visibility:hidden; 22 | } 23 | 24 | .tick-swap-transition { 25 | position:absolute; 26 | top:0; 27 | left:0; 28 | width:100%; 29 | height:100%; 30 | z-index:2; 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /src/polyfill/Array.fill.js: -------------------------------------------------------------------------------- 1 | 2 | if (!Array.prototype.fill) { 3 | Object.defineProperty(Array.prototype, 'fill', { 4 | value: function(value) { 5 | 6 | // Steps 1-2. 7 | if (this == null) { 8 | throw new TypeError('this is null or not defined'); 9 | } 10 | 11 | var O = Object(this); 12 | 13 | // Steps 3-5. 14 | var len = O.length >>> 0; 15 | 16 | // Steps 6-7. 17 | var start = arguments[1]; 18 | var relativeStart = start >> 0; 19 | 20 | // Step 8. 21 | var k = relativeStart < 0 ? 22 | Math.max(len + relativeStart, 0) : 23 | Math.min(relativeStart, len); 24 | 25 | // Steps 9-10. 26 | var end = arguments[2]; 27 | var relativeEnd = end === undefined ? 28 | len : end >> 0; 29 | 30 | // Step 11. 31 | var final = relativeEnd < 0 ? 32 | Math.max(len + relativeEnd, 0) : 33 | Math.min(relativeEnd, len); 34 | 35 | // Step 12. 36 | while (k < final) { 37 | O[k] = value; 38 | k++; 39 | } 40 | 41 | // Step 13. 42 | return O; 43 | } 44 | }); 45 | } -------------------------------------------------------------------------------- /src/polyfill/Array.find.js: -------------------------------------------------------------------------------- 1 | 2 | if (!Array.prototype.find) { 3 | Object.defineProperty(Array.prototype, 'find', { 4 | value: function (predicate) { 5 | if (this == null) { 6 | throw new TypeError('Array.prototype.find called on null or undefined'); 7 | } 8 | if (typeof predicate !== 'function') { 9 | throw new TypeError('predicate must be a function'); 10 | } 11 | var list = Object(this); 12 | var length = list.length >>> 0; 13 | var thisArg = arguments[1]; 14 | 15 | for (var i = 0; i !== length; i++) { 16 | if (predicate.call(thisArg, this[i], i, list)) { 17 | return this[i]; 18 | } 19 | } 20 | return undefined; 21 | } 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /src/polyfill/Array.from.js: -------------------------------------------------------------------------------- 1 | // Production steps of ECMA-262, Edition 6, 22.1.2.1 2 | if (!Array.from) { 3 | Array.from = (function () { 4 | var toStr = Object.prototype.toString; 5 | var isCallable = function (fn) { 6 | return typeof fn === 'function' || toStr.call(fn) === '[object Function]'; 7 | }; 8 | var toInteger = function (value) { 9 | var number = Number(value); 10 | if (isNaN(number)) { return 0; } 11 | if (number === 0 || !isFinite(number)) { return number; } 12 | return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number)); 13 | }; 14 | var maxSafeInteger = Math.pow(2, 53) - 1; 15 | var toLength = function (value) { 16 | var len = toInteger(value); 17 | return Math.min(Math.max(len, 0), maxSafeInteger); 18 | }; 19 | 20 | // The length property of the from method is 1. 21 | return function from(arrayLike/*, mapFn, thisArg */) { 22 | // 1. Let C be the this value. 23 | var C = this; 24 | 25 | // 2. Let items be ToObject(arrayLike). 26 | var items = Object(arrayLike); 27 | 28 | // 3. ReturnIfAbrupt(items). 29 | if (arrayLike == null) { 30 | throw new TypeError("Array.from requires an array-like object - not null or undefined"); 31 | } 32 | 33 | // 4. If mapfn is undefined, then let mapping be false. 34 | var mapFn = arguments.length > 1 ? arguments[1] : void undefined; 35 | var T; 36 | if (typeof mapFn !== 'undefined') { 37 | // 5. else 38 | // 5. a If IsCallable(mapfn) is false, throw a TypeError exception. 39 | if (!isCallable(mapFn)) { 40 | throw new TypeError('Array.from: when provided, the second argument must be a function'); 41 | } 42 | 43 | // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined. 44 | if (arguments.length > 2) { 45 | T = arguments[2]; 46 | } 47 | } 48 | 49 | // 10. Let lenValue be Get(items, "length"). 50 | // 11. Let len be ToLength(lenValue). 51 | var len = toLength(items.length); 52 | 53 | // 13. If IsConstructor(C) is true, then 54 | // 13. a. Let A be the result of calling the [[Construct]] internal method 55 | // of C with an argument list containing the single item len. 56 | // 14. a. Else, Let A be ArrayCreate(len). 57 | var A = isCallable(C) ? Object(new C(len)) : new Array(len); 58 | 59 | // 16. Let k be 0. 60 | var k = 0; 61 | // 17. Repeat, while k < len… (also steps a - h) 62 | var kValue; 63 | while (k < len) { 64 | kValue = items[k]; 65 | if (mapFn) { 66 | A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k); 67 | } else { 68 | A[k] = kValue; 69 | } 70 | k += 1; 71 | } 72 | // 18. Let putStatus be Put(A, "length", len, true). 73 | A.length = len; 74 | // 20. Return A. 75 | return A; 76 | }; 77 | }()); 78 | } 79 | -------------------------------------------------------------------------------- /src/polyfill/Array.includes.js: -------------------------------------------------------------------------------- 1 | 2 | Array.prototype.includes = Array.prototype.includes||function(searchElement , fromIndex) { 3 | if (!this) { 4 | throw new TypeError('Array.prototype.includes called on null or undefined'); 5 | } 6 | 7 | if (fromIndex===undefined){ 8 | var i = this.length; 9 | while(i--){ 10 | if (this[i]===searchElement){return true} 11 | } 12 | } else { 13 | var i = fromIndex, len=this.length; 14 | while(i++!==len){ // Addittion on hardware will perform as fast as, if not faster than subtraction 15 | if (this[i]===searchElement){return true} 16 | } 17 | } 18 | return false; 19 | }; 20 | -------------------------------------------------------------------------------- /src/polyfill/Object.assign.js: -------------------------------------------------------------------------------- 1 | // These polyfills are required for using Tick on IE 11 2 | if (typeof Object.assign != 'function') { 3 | Object.assign = function (target, varArgs) { // .length of function is 2 4 | if (target == null) { // TypeError if undefined or null 5 | throw new TypeError('Cannot convert undefined or null to object'); 6 | } 7 | 8 | var to = Object(target); 9 | 10 | for (var index = 1; index < arguments.length; index++) { 11 | var nextSource = arguments[index]; 12 | 13 | if (nextSource != null) { // Skip over if undefined or null 14 | for (var nextKey in nextSource) { 15 | // Avoid bugs when hasOwnProperty is shadowed 16 | if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 17 | to[nextKey] = nextSource[nextKey]; 18 | } 19 | } 20 | } 21 | } 22 | return to; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /src/polyfill/Object.keys.js: -------------------------------------------------------------------------------- 1 | 2 | // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys 3 | if (!Object.keys) { 4 | Object.keys = (function() { 5 | var hasOwnProperty = Object.prototype.hasOwnProperty, 6 | hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'), 7 | dontEnums = [ 8 | 'toString', 9 | 'toLocaleString', 10 | 'valueOf', 11 | 'hasOwnProperty', 12 | 'isPrototypeOf', 13 | 'propertyIsEnumerable', 14 | 'constructor' 15 | ], 16 | dontEnumsLength = dontEnums.length; 17 | 18 | return function(obj) { 19 | if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { 20 | throw new TypeError('Object.keys called on non-object'); 21 | } 22 | 23 | var result = [], prop, i; 24 | 25 | for (prop in obj) { 26 | if (hasOwnProperty.call(obj, prop)) { 27 | result.push(prop); 28 | } 29 | } 30 | 31 | if (hasDontEnumBug) { 32 | for (i = 0; i < dontEnumsLength; i++) { 33 | if (hasOwnProperty.call(obj, dontEnums[i])) { 34 | result.push(dontEnums[i]); 35 | } 36 | } 37 | } 38 | return result; 39 | }; 40 | }()); 41 | } 42 | -------------------------------------------------------------------------------- /src/shared/cache.js: -------------------------------------------------------------------------------- 1 | const CACHE = {}; 2 | 3 | export default (value, fn) => { 4 | const fns = fn.toString(); 5 | if (!CACHE[fns]) { 6 | CACHE[fns] = {}; 7 | } 8 | if (!CACHE[fns][value]) { 9 | CACHE[fns][value] = fn(value); 10 | } 11 | return CACHE[fns][value]; 12 | } -------------------------------------------------------------------------------- /src/shared/utils.js: -------------------------------------------------------------------------------- 1 | import cache from './cache'; 2 | 3 | const toRGBAColor = (c) => { 4 | return `rgba(${ c.map((v,i) => i < 3 ? Math.round(v * 255) : v).join(',') })` 5 | }; 6 | 7 | const interpolateColor = (a, b, p) => { 8 | return a.map((v, i) => v + ((b[i] - v) * p)); 9 | }; 10 | 11 | const toColorList = (color) => { 12 | const c = color 13 | .match(/[.\d]+/g) 14 | .map((value, index) => index < 3 ? parseFloat(value) / 255 : parseFloat(value)); 15 | return c.length === 4 ? c : c.concat([1]); 16 | }; 17 | 18 | export const getColorRangeForColors = (colors, precision) => { 19 | 20 | let colorOffset = 0; 21 | const count = colors.length - 1; 22 | const colorFirst = colors[0]; 23 | const colorLast = colors[colors.length-1]; 24 | 25 | if (colorFirst.offset && colorFirst.offset > 0) { 26 | colors.unshift({ 27 | offset: 0, 28 | value: colorFirst.value 29 | }) 30 | } 31 | 32 | if (colorLast.offset && colorLast.offset < 1) { 33 | colors.push({ 34 | offset: 1, 35 | value: colorLast.value 36 | }); 37 | } 38 | 39 | const input = colors 40 | .map((color, index) => { 41 | 42 | colorOffset = color.offset || Math.max(index / count, colorOffset); 43 | 44 | return { 45 | offset: colorOffset, 46 | // copy color as array so we don't modify cache value 47 | value: cache(color.value, toColorList).concat() 48 | } 49 | }); 50 | 51 | const output = input.reduce((output, color, index) => { 52 | 53 | // color to interpolate towards 54 | const targetColor = color.value; 55 | 56 | // add first color 57 | if (index === 0) { 58 | output.push(targetColor); 59 | } 60 | // interpolate to this color from last color 61 | else if (index > 0) { 62 | 63 | const previousColor = output[output.length - 1]; 64 | const previousOffset = (output.length - 1) / precision; 65 | 66 | const steps = Math.round(precision * (color.offset - previousOffset)); 67 | 68 | let i = 1; // skip previous color (it's already in array) 69 | for(;i<=steps;i++) { 70 | output.push(interpolateColor(previousColor, targetColor, i / steps)); 71 | } 72 | 73 | } 74 | 75 | return output; 76 | 77 | },[]); 78 | 79 | return output.map(toRGBAColor); 80 | }; -------------------------------------------------------------------------------- /src/variants/tick.core.amd.js: -------------------------------------------------------------------------------- 1 | define(__LIB__); -------------------------------------------------------------------------------- /src/variants/tick.core.commonjs.js: -------------------------------------------------------------------------------- 1 | module.exports = (__LIB__()); -------------------------------------------------------------------------------- /src/variants/tick.core.global.js: -------------------------------------------------------------------------------- 1 | (function(root, plugins, undefined){ 2 | 'use strict'; 3 | 4 | // private library reference 5 | var Tick = (__LIB__()); 6 | 7 | (function(){ 8 | 9 | // convert array to params 10 | function add(arr) { 11 | Tick.plugin.add.apply(null, arr); 12 | } 13 | 14 | // create fake push method for new extensions 15 | Tick.push = add; 16 | 17 | // loop over already pushed extensions and add to Tick 18 | plugins.forEach(add); 19 | 20 | // expose globally (overwriting extension array) 21 | root.Tick = Tick; 22 | 23 | }()); 24 | 25 | }(window, window.Tick || [])); -------------------------------------------------------------------------------- /src/variants/tick.core.jquery.js: -------------------------------------------------------------------------------- 1 | (function($, plugins, undefined){ 2 | 'use strict'; 3 | 4 | // if no jquery, stop here 5 | if (!$) { return; } 6 | 7 | // library reference 8 | var Tick = (__LIB__()); 9 | 10 | (function(){ 11 | 12 | // helpers 13 | function argsToArray(args) { 14 | return Array.prototype.slice.call(args); 15 | } 16 | 17 | function isConstructor(parameters) { 18 | return typeof parameters[0] === 'object' || parameters.length === 0; 19 | } 20 | 21 | function isGetter(tick, method) { 22 | var descriptor = Object.getOwnPropertyDescriptor(tick.prototype, method); 23 | return descriptor ? typeof descriptor.get !== 'undefined' : false; 24 | } 25 | 26 | function isSetter(tick, method) { 27 | var descriptor = Object.getOwnPropertyDescriptor(tick.prototype, method); 28 | return descriptor ? typeof descriptor.set !== 'undefined' : false; 29 | } 30 | 31 | function isMethod(tick, method) { 32 | return typeof tick[method] === 'function'; 33 | } 34 | 35 | // plugin 36 | $.fn.tick = function() { 37 | 38 | // get arguments as array 39 | var parameters = argsToArray(arguments); 40 | 41 | // is method 42 | if (isConstructor(parameters)) { 43 | return this.each(function(){ 44 | return Tick.DOM.create(this, parameters[0]); 45 | }); 46 | } 47 | else { 48 | var method = parameters.shift(); 49 | 50 | if (Tick.DOM[method]) { 51 | return this.each(function(){ 52 | return Tick.DOM[method](this, parameters[0]); 53 | }); 54 | } 55 | else { 56 | 57 | var results = []; 58 | // is instance API 59 | this.each(function(){ 60 | 61 | var tick = Tick.DOM.find(this); 62 | if (!tick) { 63 | return null; 64 | } 65 | switch(method) { 66 | case 'value': 67 | if (parameters.length === 1) { 68 | results.push(tick[method] = parameters[0]); 69 | } 70 | else { 71 | results.push(tick[method]); 72 | } 73 | break; 74 | case 'root': 75 | results.push(tick.root); 76 | break; 77 | default: 78 | return null; 79 | } 80 | 81 | }); 82 | return results; 83 | } 84 | 85 | } 86 | 87 | }; 88 | 89 | // convert array to params 90 | function add(arr) { 91 | Tick.plugin.add.apply(null, arr); 92 | } 93 | 94 | // loop over already pushed extensions and add to Tick 95 | plugins.forEach(add); 96 | 97 | // public static api 98 | $.tick = { 99 | 100 | // register extension 101 | push: add, 102 | plugin: Tick.plugin, 103 | 104 | // method 105 | data:Tick.data, 106 | helper:Tick.helper, 107 | count:Tick.count, 108 | supported: Tick.supported 109 | 110 | }; 111 | 112 | }()); 113 | 114 | }(window.jQuery, window.jQuery ? window.jQuery.tick || [] : [])); -------------------------------------------------------------------------------- /src/variants/tick.core.kickstart.js: -------------------------------------------------------------------------------- 1 | (function(root, plugins, undefined) { 2 | 'use strict'; 3 | 4 | // Cut the mustard for really old browsers 5 | if (!root || !('MutationObserver' in root) || !('requestAnimationFrame' in root)) { 6 | return; 7 | } 8 | 9 | // private library reference 10 | var Tick = (__LIB__()); 11 | 12 | (function() { 13 | 14 | // convert array to params 15 | function add(arr) { 16 | Tick.plugin.add.apply(null, arr); 17 | } 18 | 19 | // create fake push method for new extensions 20 | Tick.push = add; 21 | 22 | // loop over already pushed extensions and add to Tick 23 | plugins.forEach(add); 24 | 25 | // expose globally (overwriting extension array) 26 | root.Tick = Tick; 27 | 28 | /** 29 | * Auto parses document for Tick elements 30 | */ 31 | function kick() { 32 | Tick.DOM.parse(document); 33 | } 34 | 35 | if (document.readyState !== 'loading') { 36 | // make sure kick is called async (same as when called on DOMContentLoaded) 37 | setTimeout(function(){ 38 | kick(); 39 | },0) 40 | } 41 | else { 42 | document.addEventListener('DOMContentLoaded', kick); 43 | } 44 | 45 | }()); 46 | 47 | }(window, window.Tick || [])); -------------------------------------------------------------------------------- /src/variants/tick.core.module.js: -------------------------------------------------------------------------------- 1 | export default typeof window !== 'undefined' ? (__LIB__()) : null; -------------------------------------------------------------------------------- /src/wrapper/core.intro.js: -------------------------------------------------------------------------------- 1 | function() { 2 | if (!module) { 3 | var module = {}; 4 | } -------------------------------------------------------------------------------- /src/wrapper/core.outro.js: -------------------------------------------------------------------------------- 1 | return module.exports; 2 | } -------------------------------------------------------------------------------- /src/wrapper/extension.intro.js: -------------------------------------------------------------------------------- 1 | function() { 2 | if (!module) { 3 | var module = {}; 4 | } -------------------------------------------------------------------------------- /src/wrapper/extension.outro.js: -------------------------------------------------------------------------------- 1 | module.exports.identifier = { 2 | name:'__NAME__', 3 | type:'__TYPE__' 4 | }; 5 | return module.exports; 6 | } -------------------------------------------------------------------------------- /src/wrapper/poly.intro.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; -------------------------------------------------------------------------------- /src/wrapper/poly.outro.js: -------------------------------------------------------------------------------- 1 | }()); -------------------------------------------------------------------------------- /swap.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pqina/tick/a3df2420753980cfe82a3af90ceab93a89419e9f/swap.gif -------------------------------------------------------------------------------- /test/drawing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Drawing 8 | 9 | 10 | 11 | 12 | 21 | 22 | 23 | 24 | 25 |
28 |
29 |
30 | 31 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /test/parser.test.js: -------------------------------------------------------------------------------- 1 | // Import chai. 2 | const chai = require('chai'); 3 | const path = require('path'); 4 | const expect = chai.expect; 5 | 6 | chai.expect(); 7 | 8 | // Import the Rectangle class. 9 | let Parser = require(path.join(__dirname, '../src/core/js/', 'parser')); 10 | 11 | describe('Transform Chain Parser', () => { 12 | 13 | describe('parseTransformChain', () => { 14 | [ 15 | { 16 | input: 'foo()', 17 | output: [['foo']] 18 | }, 19 | { 20 | input: 'foo', 21 | output: [['foo']] 22 | }, 23 | { 24 | input: 'foo(a)', 25 | output: [['foo', 'a']] 26 | }, 27 | { 28 | input: 'foo(\'a\')', 29 | output: [['foo', 'a']] 30 | }, 31 | { 32 | input: 'foo("\'a\'")', 33 | output: [['foo', '\'a\'']] 34 | }, 35 | { 36 | input: 'foo(\'a, b\')', 37 | output: [['foo', 'a, b']] 38 | }, 39 | { 40 | input: 'foo(a, b)', 41 | output: [['foo', 'a', 'b']] 42 | }, 43 | { 44 | input: 'foo() -> bar()', 45 | output: [[['foo'],['bar']]] 46 | }, 47 | { 48 | input: 'foo -> bar', 49 | output: [[['foo'],['bar']]] 50 | }, 51 | { 52 | input: 'foo() -> bar(), baz()', 53 | output: [[['foo'],['bar']],['baz']] 54 | }, 55 | { 56 | input: 'foo -> bar, baz', 57 | output: [[['foo'],['bar']],['baz']] 58 | }, 59 | { 60 | input: 'foo(bar() -> baz())', 61 | output: [['foo',[['bar'],['baz']]]] 62 | }, 63 | { 64 | input: 'foo(bar -> baz)', 65 | output: [['foo',[['bar'],['baz']]]] 66 | }, 67 | { 68 | input: 'foo() -> bar(baz(a, b), boz())', 69 | output: [[['foo'],['bar',['baz','a','b'],['boz']]]] 70 | }, 71 | { 72 | input: 'foo() -> bar(baz(foo() -> bar()), boz())', 73 | output: [[['foo'],['bar',['baz',[['foo'],['bar']]],['boz']]]] 74 | } 75 | ].forEach(chain => { 76 | 77 | it(`should parse "${ chain.input }"`, () => { 78 | const result = Parser.parseTransformChain(chain.input); 79 | if (result === null || chain.output === null) { 80 | expect(result).to.equal(chain.output); 81 | } 82 | else { 83 | expect(result).to.deep.equal(chain.output); 84 | } 85 | }) 86 | 87 | }); 88 | 89 | }); 90 | 91 | 92 | }); -------------------------------------------------------------------------------- /test/style.test.js: -------------------------------------------------------------------------------- 1 | // Import chai. 2 | const chai = require('chai'); 3 | const path = require('path'); 4 | const expect = chai.expect; 5 | 6 | chai.expect(); 7 | 8 | // Import the Rectangle class. 9 | let Style = require(path.join(__dirname, '../src/core/js/', 'style')); 10 | 11 | describe('Style Parser', () => { 12 | 13 | describe('Generic', () => { 14 | 15 | it('should parse property', () => { 16 | 17 | const styles = Style.toStyles('foo:bar'); 18 | expect(styles.foo).to.equal('bar'); 19 | 20 | }); 21 | 22 | }); 23 | 24 | describe('Transitions', () => { 25 | 26 | it('should parse transition name', () => { 27 | 28 | const styles = Style.toStyles('transition:move'); 29 | expect(styles.transition[0].name).to.equal('move') 30 | 31 | }); 32 | 33 | it('should parse transition name parameters', () => { 34 | 35 | const styles = Style.toStyles('transition:move(0, 1, horizontal)'); 36 | expect(styles.transition[0].parameters).to.include.members([0, 1, 'horizontal']) 37 | 38 | }); 39 | 40 | it('should parse transition duration in milliseconds', () => { 41 | 42 | const styles = Style.toStyles('transition:move 500ms'); 43 | expect(styles.transition[0].duration).to.equal(500); 44 | 45 | }); 46 | 47 | it('should parse transition duration in seconds', () => { 48 | 49 | const styles = Style.toStyles('transition:move 5s'); 50 | expect(styles.transition[0].duration).to.equal(5000); 51 | 52 | }); 53 | 54 | it('should parse transition duration in fractions of seconds', () => { 55 | 56 | const styles = Style.toStyles('transition:move .5s'); 57 | expect(styles.transition[0].duration).to.equal(500); 58 | 59 | }); 60 | 61 | it('should parse transition ease', () => { 62 | 63 | const styles = Style.toStyles('transition:move .5s ease-out-quad'); 64 | expect(styles.transition[0].ease).to.equal('ease-out-quad'); 65 | 66 | }); 67 | 68 | it('should parse transition delay', () => { 69 | 70 | const styles = Style.toStyles('transition:move .5s ease-out-quad 500ms'); 71 | expect(styles.transition[0].delay).to.equal(500); 72 | 73 | }); 74 | 75 | it('should parse transition origin', () => { 76 | 77 | const styles = Style.toStyles('transition:move origin(top left) .5s ease-out-quad 500ms'); 78 | expect(styles.transition[0].origin).to.equal('top left'); 79 | 80 | }); 81 | 82 | }); 83 | 84 | }); --------------------------------------------------------------------------------