├── .babelrc ├── src ├── _entry.js ├── event-emitter.spec.js ├── event-emitter.js ├── iris.worm.spec.js └── iris.worm.js ├── mocha.config ├── .gitignore ├── test.helper.js ├── LICENSE.md ├── webpack.config.js ├── package.json ├── index.html ├── dist ├── index.html ├── bundle.js ├── bundle.min.js ├── bundle.js.map └── bundle.min.js.map └── README.md /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env"] 3 | } -------------------------------------------------------------------------------- /src/_entry.js: -------------------------------------------------------------------------------- 1 | import WORM from './iris.worm'; 2 | 3 | export const Worm = WORM; -------------------------------------------------------------------------------- /mocha.config: -------------------------------------------------------------------------------- 1 | --require test.helper.js 2 | --compilers js:babel-core/register 3 | src/**/*.spec.js -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .idea/ 3 | bower_components/ 4 | node_modules/ 5 | reports/ 6 | mocha.json 7 | npm-debug.log -------------------------------------------------------------------------------- /test.helper.js: -------------------------------------------------------------------------------- 1 | const jsdom = require('jsdom').jsdom; 2 | 3 | global.document = jsdom({ file: 'index.html' }); // ''); 4 | 5 | global.window = document.defaultView; 6 | 7 | global.sinon = require('sinon'); 8 | 9 | global.expect = require('chai').expect; -------------------------------------------------------------------------------- /src/event-emitter.spec.js: -------------------------------------------------------------------------------- 1 | import EventEmitter from './event-emitter'; 2 | 3 | describe('EventEmitter', () => { 4 | 5 | it('acts like the node event emitter', () => { 6 | let spy = sinon.spy(); 7 | let emitter = new EventEmitter(); 8 | 9 | emitter.on('foobar', spy); 10 | emitter.emit('foobar'); 11 | 12 | expect(spy.calledOnce).to.be.true; 13 | }) 14 | }); -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2016-2017 Crown Copyright 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | See the License for the specific language governing permissions and limitations under the License. 10 | -------------------------------------------------------------------------------- /src/event-emitter.js: -------------------------------------------------------------------------------- 1 | export default class EventEmitter { 2 | 3 | constructor(logger) { 4 | this._events = {}; 5 | } 6 | 7 | /** 8 | * Sets a listener for the specified event name. 9 | * 10 | * @public 11 | * @method on 12 | * @param {string} eventName name of the event to listen to. 13 | * @param {function} callback function to call when the event occurs. 14 | */ 15 | on(eventName, callback) { 16 | this._events[eventName] = this._events[eventName] || []; 17 | this._events[eventName].push(callback); 18 | } 19 | 20 | /** 21 | * Sets a listener for the specified event name. 22 | * 23 | * @public 24 | * @method emit 25 | * @param {string} eventName name of the event to emit. 26 | * @param {any} arg1, arg2, arg3 arguments to yield to the functioun 27 | */ 28 | emit(eventName, arg1, arg2, arg3) { 29 | (this._events[eventName] || []).forEach((fn) => { 30 | fn && fn(arg1, arg2, arg3) 31 | }); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | 4 | module.exports = { 5 | 6 | entry: './src/_entry.js', 7 | 8 | watchOptions: { 9 | poll: true 10 | }, 11 | 12 | output: { 13 | path: path.join(__dirname, '/dist'), 14 | filename: `bundle${ process.env.NODE_ENV=='production' ? '.min' : '' }.js`, 15 | library: 'IRISWorm', 16 | libraryTarget: "umd" 17 | }, 18 | 19 | module: { 20 | 21 | rules: [{ 22 | test: /\.js$/, 23 | include: [path.resolve(__dirname, "src")], 24 | use: [{ 25 | loader: 'babel-loader', 26 | query: { 27 | presets: ['env'] 28 | } 29 | }], 30 | 31 | }] 32 | }, 33 | 34 | devServer: { 35 | host: process.env.HOSTNAME || "localhost", 36 | port: process.env.PORT || 8080, 37 | contentBase: path.join(__dirname, '/dist') 38 | }, 39 | 40 | devtool: "source-map", 41 | 42 | plugins: [ 43 | new HtmlWebpackPlugin({ 44 | template: "index.html", 45 | inject: "head" 46 | }) 47 | ] 48 | 49 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iris-worm", 3 | "version": "1.0.0", 4 | "description": "IRIS Worm", 5 | "main": "dist/bundle.js", 6 | "scripts": { 7 | "start": "webpack-dev-server", 8 | "build:dev": "webpack", 9 | "build:prod": "NODE_ENV=production webpack -p", 10 | "bundle": "npm run build:dev && npm run build:prod", 11 | "publish": "npm run bundle && git add dist && git commit -m 'updating dist' && git push", 12 | "test": "mocha --opts mocha.config", 13 | "test:watch": "mocha --opts mocha.config --watch" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "" 18 | }, 19 | "keywords": [ 20 | "iris", 21 | "worm" 22 | ], 23 | "author": "GCHQ", 24 | "license": "Apache-2.0", 25 | "devDependencies": { 26 | "babel-core": "^6.26.3", 27 | "babel-loader": "^7.1.5", 28 | "babel-preset-env": "^1.7.0", 29 | "chai": "^3.5.0", 30 | "html-webpack-plugin": "^3.1.0", 31 | "jsdom": "^13.2.0", 32 | "lodash": "^4.17.11", 33 | "mocha": "^5.2.0", 34 | "mocha-bamboo-reporter": "^1.1.1", 35 | "moment": "^2.24.0", 36 | "sinon": "^1.17.7", 37 | "style-loader": "^0.13.2", 38 | "webpack": "^4.29.3", 39 | "webpack-cli": "^3.2.3", 40 | "webpack-dev-server": "^3.1.14" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/iris.worm.spec.js: -------------------------------------------------------------------------------- 1 | // TODO write some proper tests 2 | import EventEmitter from './event-emitter'; 3 | import Worm from './iris.worm'; 4 | 5 | describe('iris.worm', function () { 6 | 7 | var container, worm; 8 | 9 | beforeEach(function () { 10 | document.body.innerHTML = null; 11 | container = document.createElement('div'); 12 | container.setAttribute('id', 'myDiv'); 13 | document.body.appendChild(container); 14 | worm = new Worm(container); 15 | }); 16 | 17 | describe('Worm()', function () { 18 | it('initializes a new event emitter', function () { 19 | expect(worm._eventEmitter).to.be.instanceOf(EventEmitter); 20 | }); 21 | }); 22 | 23 | describe("#setOption", function () { 24 | it('provides an interface for setting an option value', function () { 25 | var worm = new Worm(container, { 26 | displayHeight: 123 27 | }); 28 | worm.setOption('height', 321); 29 | expect(worm.getOption('height')).to.equal(321); 30 | }); 31 | }); 32 | 33 | describe('#setValue', function () { 34 | it('sets the value', function () { 35 | worm.setValue(99); 36 | expect(worm._value).to.equal(99); 37 | }); 38 | 39 | context('when the value is set higher than the maximum', function () { 40 | it('becomes the maxiumum', function () { 41 | worm.setOption('maxValue', 100); 42 | worm.setValue(101); 43 | expect(worm.getValue()).to.equal(100); 44 | }); 45 | }); 46 | 47 | it('emits an event', function () { 48 | var spy = sinon.spy(); 49 | worm.on('valueChanged', spy); 50 | worm.setValue(123); 51 | expect(spy.called).to.be.true; 52 | }); 53 | 54 | context('when the value is set to minimum', function () { 55 | it('emits a valueBecameMinimum event', function () { 56 | var spy = sinon.spy(); 57 | worm.on('valueBecameMinimum', spy); 58 | worm.setValue(0); 59 | expect(spy.called).to.be.true; 60 | }) 61 | }) 62 | 63 | context('when the value is set to maximum', function () { 64 | it('emits a valueBecameMaximum event', function () { 65 | var spy = sinon.spy(); 66 | worm.on('valueBecameMaximum', spy); 67 | worm.setValue(100); 68 | expect(spy.called).to.be.true; 69 | }) 70 | }) 71 | }); 72 | 73 | describe('#getValue', function () { 74 | it('gets the value', function () { 75 | expect(worm.getValue()).to.equal(worm._value); 76 | }); 77 | }); 78 | 79 | 80 | 81 | }); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | IRIS Worm 7 | 8 | 57 | 58 | 59 | 60 |

IRIS Worm

61 | 62 |
63 |
64 | 65 |
66 | 67 |
68 | 69 | 70 |

71 | 72 | 73 | 74 |

75 | 76 | 77 | 78 |
79 | 80 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | IRIS Worm 7 | 8 | 57 | 58 | 59 | 60 |

IRIS Worm

61 | 62 |
63 |
64 | 65 |
66 | 67 |
68 | 69 | 70 |

71 | 72 | 73 | 74 |

75 | 76 | 77 | 78 |
79 | 80 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Copyright 2016-2017 Crown Copyright 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | # IRIS Worm 16 | 17 | IRIS Worm is a real-time data graphing component. With straight-forward initialisation and a core set of methods, the component is easy to set up and an intuitive and beautiful data visualisation tool. 18 | 19 | ## Features 20 | * Easy Initialisation 21 | * Zero Dependencies 22 | * Built on HTML5 canvas - performant, scalable and fully supported in all major browsers 23 | * Accessibility - using ARIA alert and aria-live tags, screenreaders can read the worm to users 24 | 25 | ## Demo 26 | [Demo on gh-pages](https://gchq.github.io/iris-worm/) 27 | 28 | ## Installation 29 | 30 | We've packaged up all the dependencies into a minified distribution for you so you just need to include it on your page somehow; 31 | 32 | ``` 33 | 34 | ``` 35 | This registers IRIS.Worm in the global scope, allowing you to start using the component. 36 | 37 | ## Accessibility 38 | 39 | It is very important that any applications you make are useable by visually impaired users. The worm is a graphical 40 | interface rendered on to an html canvas, and so will not naturally be parseable by screen readers. The worm provides 41 | an interface to aria live/alert features to get around this, which will broadcast changes to the worm live to screen 42 | readers. Settings follow the standard aria naming convention, so that allows you to set broadcasts to be; 43 | 44 | off - the worm will not broadcast anything. 45 | polite - if the worm changes, it will broadcast the new value when the user is idle (i.e. it won't interrupt them). 46 | assertive - if the worm changes, it will interrupt the user and tell them that the change has occurred (i.e. it will interrupt them). 47 | 48 | You should tailor which option to go for depending on what your use case is. If you have many worms on one page, with data that changes 49 | very frequently, you might be better off disabling the broadcasts and just providing a seperate screen-reader-friendly interface. 50 | 51 | Implementation details can be found in the options section. 52 | 53 | ## Example 54 | 55 | Pass in a containing div and some options, and the worm will set up a canvas element. Then just call the `start()` method 56 | to start the worm. 57 | 58 | ``` 59 | // construct a new instance 60 | var worm = new IRIS.Worm(document.querySelector('#wormCanvas')); 61 | 62 | // Start it 63 | worm.start(); 64 | 65 | // Change the value 66 | worm.setValue(75); 67 | ``` 68 | 69 | ## Options 70 | You can get or set the options for a timeline using the following interface; 71 | ``` 72 | worm.getOption(); 73 | worm.setOption(, ); 74 | ``` 75 | 76 | The options themselves are documented within the code however have been reproduced here for convinience. 77 | 78 | ``` 79 | // The width of the component 80 | width: 600, 81 | 82 | // The height of the component 83 | height: 400, 84 | 85 | // The maximum value that can be set in the component (used for scaling) - 86 | // defaults to 100, meaning that "100" is the "Top of the worm". 87 | maxValue: 100, 88 | 89 | // When a value changes, the worm will accelerate towards that value smoothly 90 | // if smoothMode is set to true, otherwise it will jump straight to it. 91 | smoothMode: true, 92 | 93 | // Color mode: options are: 'greenIsGood', 'greenIsBad', 'monochrome' 94 | colorMode: 'greenIsGood', 95 | 96 | // How quickly the worm accelerates towards its target (NOTE: this value really is only useful if you keep it 97 | // below 1, otherwise you might as well just use smoothMode: false and have it instantly jumping) 98 | acceleration: 0.1, 99 | 100 | // How thick the line is 101 | lineWidth: 5, 102 | 103 | //how insistant the aria-live tag is. Default is polite; 104 | //options are: off, polite, assertive 105 | accessibilityBroadcast: 'polite' 106 | ``` 107 | 108 | ## Events 109 | 110 | The worm emits events that can be subscribed to in order to provide custom behaviour. These events are subscribed to using the following interface; 111 | 112 | ``` 113 | worm.on('valueChanged', function(value) { 114 | console.log("Value changed to " + value); 115 | }); 116 | ``` 117 | Events are as follows 118 | 119 | ``` 120 | valueChanged 121 | valueIncreased 122 | valueDecreased 123 | valueBecameMinimum 124 | valueBecameMaximum 125 | ``` 126 | 127 | ## Public Methods 128 | 129 | ``` 130 | worm.start() 131 | ``` 132 | Starts the worm. 133 | 134 | ``` 135 | worm.stop() 136 | ``` 137 | Stops the worm. 138 | 139 | ``` 140 | worm.setValue(value) 141 | ``` 142 | Sets the current value of the worm. 143 | 144 | ``` 145 | worm.getValue() 146 | ``` 147 | Gets the current value of the worm. 148 | 149 | ``` 150 | worm.on(event, callback) 151 | ``` 152 | Event hook (see "events" section) 153 | -------------------------------------------------------------------------------- /dist/bundle.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.IRISWorm=e():t.IRISWorm=e()}(window,function(){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var a=e[n]={i:n,l:!1,exports:{}};return t[n].call(a.exports,a,a.exports,i),a.l=!0,a.exports}return i.m=t,i.c=e,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var a in t)i.d(n,a,function(e){return t[e]}.bind(null,a));return n},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=0)}([function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Worm=void 0;var n,a=i(1),o=(n=a)&&n.__esModule?n:{default:n};e.Worm=o.default},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n,a=function(){function t(t,e){for(var i=0;i1&&void 0!==arguments[1]?arguments[1]:{};!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this._rootDiv=e,this._options=Object.assign({},t.DEFAULT_OPTIONS,i),this._canvas=document.createElement("canvas"),this._canvas.width=this._options.width,this._canvas.height=this._options.height,this._canvas.className=this.CSS_CONTAINER,this._ctx=this._canvas.getContext("2d"),this._rootDiv.appendChild(this._canvas),this._value=50,this._metaValue=50,this._oldMetaValue=50,this._momentum=0,this._active=!1,"off"!==this._options.accessibilityBroadcast&&(this._fallbackDom=document.createElement("span"),this._fallbackDom.setAttribute("role","alert"),this._fallbackDom.setAttribute("aria-live",this._options.accessibilityBroadcast),this._fallbackDom.setAttribute("style","position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);"),this._rootDiv.appendChild(this._fallbackDom)),this._eventEmitter=new s.default}return a(t,[{key:"NAME",get:function(){}},{key:"VERSION",get:function(){return null}},{key:"CSS_CONTAINER",get:function(){return"irisWorm"}},{key:"MAX_MOMENTUM",get:function(){return 5}}],[{key:"DEFAULT_OPTIONS",get:function(){return{width:600,height:400,maxValue:100,smoothMode:!0,colorMode:"greenIsGood",acceleration:.1,lineWidth:5,accessibilityBroadcast:"polite"}}}]),a(t,[{key:"start",value:function(){this._ctx.lineWidth=this._options.lineWidth,this._active=!0,this._draw()}},{key:"stop",value:function(){this._active=!1}},{key:"_draw",value:function(){this._active&&(requestAnimationFrame(this._draw.bind(this)),this._moveViewport(),this._drawPoint(),this._resolveValues())}},{key:"_resolveValues",value:function(){if(this._options.smoothMode){var t=Math.abs(this._value-this._metaValue);if(t<.1)return this._metaValue=this._value,void(this._momentum=0);this._value=-this.MAX_MOMENTUM&&(this._momentum-=this._options.acceleration),this._value>this._metaValue&&this._momentum<=this.MAX_MOMENTUM&&(this._momentum+=this._options.acceleration),this._metaValue+=this._momentum*t/100,this._oldMetaValue=this._metaValue}else this._oldMetaValue=this._metaValue,this._metaValue=this._value}},{key:"_moveViewport",value:function(){var t=this._ctx.getImageData(1,0,this._options.width-1,this._options.height);this._ctx.putImageData(t,0,0),this._ctx.clearRect(this._options.width-1,0,1,this._options.height),t=null}},{key:"_drawPoint",value:function(){var t,e=255/this._options.height,i=Math.floor(e*this._scaleValue(this._metaValue)),n=255-Math.floor(e*this._scaleValue(this._metaValue));switch(this._options.colorMode){case"monochrome":t="rgb(0,0,0)";break;case"greenIsBad":t="rgb("+n+","+i+",0)";break;case"greenIsGood":default:t="rgb("+i+","+n+",0)"}this._ctx.strokeStyle=t,this._ctx.beginPath(),this._ctx.moveTo(this._options.width,this._scaleValue(this._metaValue)),this._ctx.lineTo(this._options.width-1,this._scaleValue(this._oldMetaValue)),this._ctx.stroke()}},{key:"_scaleValue",value:function(t){var e=this._options.height/this._options.maxValue;return this._options.height-t*e}},{key:"_getName",value:function(){var t=this.NAME;return 0!==this.VERSION.indexOf("<%=")&&(t=this.NAME+" "+this.VERSION),t}},{key:"destroy",value:function(){void 0!==this._canvas&&null!=this._canvas&&(this._canvas.remove(),delete this._canvas)}},{key:"on",value:function(t,e){var i=this;this._eventEmitter.on(t,function(t,n,a){return e.call(i,t,n,a)})}},{key:"setValue",value:function(t){t>this._options.maxValue&&(t=this._options.maxValue),"off"!==this._options.accessibilityBroadcast&&this._fallbackDom&&this._fallbackDom.remove&&(this._fallbackDom.remove(),this._fallbackDom.innerText="worm value is "+t,this._rootDiv.appendChild(this._fallbackDom)),t>this._value&&this._eventEmitter.emit("valueIncreased",this._value,t),t=this._options.maxValue&&this._eventEmitter.emit("valueBecameMaximum",this._value),t<=0&&this._eventEmitter.emit("valueBecameMinimum",this._value),this._value=t,this._momentum=0,this._eventEmitter.emit("valueChanged",this._value)}},{key:"getValue",value:function(){return this._value}},{key:"setOption",value:function(t,e){this._options[t]=e}},{key:"getOption",value:function(t){return this._options[t]}}]),t}();e.default=u},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var i=0;i1&&void 0!==arguments[1]?arguments[1]:{};!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this._rootDiv=e,this._options=Object.assign({},t.DEFAULT_OPTIONS,i),this._canvas=document.createElement("canvas"),this._canvas.width=this._options.width,this._canvas.height=this._options.height,this._canvas.className=this.CSS_CONTAINER,this._ctx=this._canvas.getContext("2d"),this._rootDiv.appendChild(this._canvas),this._value=50,this._metaValue=50,this._oldMetaValue=50,this._momentum=0,this._active=!1,"off"!==this._options.accessibilityBroadcast&&(this._fallbackDom=document.createElement("span"),this._fallbackDom.setAttribute("role","alert"),this._fallbackDom.setAttribute("aria-live",this._options.accessibilityBroadcast),this._fallbackDom.setAttribute("style","position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);"),this._rootDiv.appendChild(this._fallbackDom)),this._eventEmitter=new s.default}return a(t,[{key:"NAME",get:function(){}},{key:"VERSION",get:function(){return null}},{key:"CSS_CONTAINER",get:function(){return"irisWorm"}},{key:"MAX_MOMENTUM",get:function(){return 5}}],[{key:"DEFAULT_OPTIONS",get:function(){return{width:600,height:400,maxValue:100,smoothMode:!0,colorMode:"greenIsGood",acceleration:.1,lineWidth:5,accessibilityBroadcast:"polite"}}}]),a(t,[{key:"start",value:function(){this._ctx.lineWidth=this._options.lineWidth,this._active=!0,this._draw()}},{key:"stop",value:function(){this._active=!1}},{key:"_draw",value:function(){this._active&&(requestAnimationFrame(this._draw.bind(this)),this._moveViewport(),this._drawPoint(),this._resolveValues())}},{key:"_resolveValues",value:function(){if(this._options.smoothMode){var t=Math.abs(this._value-this._metaValue);if(t<.1)return this._metaValue=this._value,void(this._momentum=0);this._value=-this.MAX_MOMENTUM&&(this._momentum-=this._options.acceleration),this._value>this._metaValue&&this._momentum<=this.MAX_MOMENTUM&&(this._momentum+=this._options.acceleration),this._metaValue+=this._momentum*t/100,this._oldMetaValue=this._metaValue}else this._oldMetaValue=this._metaValue,this._metaValue=this._value}},{key:"_moveViewport",value:function(){var t=this._ctx.getImageData(1,0,this._options.width-1,this._options.height);this._ctx.putImageData(t,0,0),this._ctx.clearRect(this._options.width-1,0,1,this._options.height),t=null}},{key:"_drawPoint",value:function(){var t,e=255/this._options.height,i=Math.floor(e*this._scaleValue(this._metaValue)),n=255-Math.floor(e*this._scaleValue(this._metaValue));switch(this._options.colorMode){case"monochrome":t="rgb(0,0,0)";break;case"greenIsBad":t="rgb("+n+","+i+",0)";break;case"greenIsGood":default:t="rgb("+i+","+n+",0)"}this._ctx.strokeStyle=t,this._ctx.beginPath(),this._ctx.moveTo(this._options.width,this._scaleValue(this._metaValue)),this._ctx.lineTo(this._options.width-1,this._scaleValue(this._oldMetaValue)),this._ctx.stroke()}},{key:"_scaleValue",value:function(t){var e=this._options.height/this._options.maxValue;return this._options.height-t*e}},{key:"_getName",value:function(){var t=this.NAME;return 0!==this.VERSION.indexOf("<%=")&&(t=this.NAME+" "+this.VERSION),t}},{key:"destroy",value:function(){void 0!==this._canvas&&null!=this._canvas&&(this._canvas.remove(),delete this._canvas)}},{key:"on",value:function(t,e){var i=this;this._eventEmitter.on(t,function(t,n,a){return e.call(i,t,n,a)})}},{key:"setValue",value:function(t){t>this._options.maxValue&&(t=this._options.maxValue),"off"!==this._options.accessibilityBroadcast&&this._fallbackDom&&this._fallbackDom.remove&&(this._fallbackDom.remove(),this._fallbackDom.innerText="worm value is "+t,this._rootDiv.appendChild(this._fallbackDom)),t>this._value&&this._eventEmitter.emit("valueIncreased",this._value,t),t=this._options.maxValue&&this._eventEmitter.emit("valueBecameMaximum",this._value),t<=0&&this._eventEmitter.emit("valueBecameMinimum",this._value),this._value=t,this._momentum=0,this._eventEmitter.emit("valueChanged",this._value)}},{key:"getValue",value:function(){return this._value}},{key:"setOption",value:function(t,e){this._options[t]=e}},{key:"getOption",value:function(t){return this._options[t]}}]),t}();e.default=u},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){function t(t,e){for(var i=0;i= -this.MAX_MOMENTUM) { 122 | this._momentum -= this._options.acceleration; 123 | } 124 | } 125 | if (this._value > this._metaValue) { 126 | if (this._momentum <= this.MAX_MOMENTUM) { 127 | this._momentum += this._options.acceleration; 128 | } 129 | } 130 | 131 | this._metaValue += (this._momentum * distanceToValue) / 100; 132 | } 133 | this._oldMetaValue = this._metaValue; 134 | } else { 135 | this._oldMetaValue = this._metaValue; 136 | this._metaValue = this._value; 137 | } 138 | 139 | } 140 | 141 | _moveViewport() { 142 | var imageData = this._ctx.getImageData(1, 0, this._options.width - 1, this._options.height); 143 | this._ctx.putImageData(imageData, 0, 0); 144 | this._ctx.clearRect(this._options.width - 1, 0, 1, this._options.height); 145 | 146 | // this thing is known to be leaky so let's force explicit garbage collecion. 147 | imageData = null; 148 | } 149 | 150 | _drawPoint() { 151 | 152 | var colorUnit = (255 / this._options.height); 153 | var bad = Math.floor(colorUnit * this._scaleValue(this._metaValue)); 154 | var good = 255 - Math.floor(colorUnit * this._scaleValue(this._metaValue)); 155 | var color; 156 | 157 | switch (this._options.colorMode) { 158 | case 'monochrome': 159 | color = 'rgb(0,0,0)'; 160 | break; 161 | case 'greenIsBad': 162 | color = 'rgb(' + good + ',' + bad + ',0)'; 163 | break; 164 | case 'greenIsGood': 165 | default: 166 | color = 'rgb(' + bad + ',' + good + ',0)'; 167 | } 168 | 169 | this._ctx.strokeStyle = color; 170 | 171 | this._ctx.beginPath(); 172 | this._ctx.moveTo(this._options.width, this._scaleValue(this._metaValue)); 173 | this._ctx.lineTo(this._options.width - 1, this._scaleValue(this._oldMetaValue)); 174 | this._ctx.stroke(); 175 | } 176 | 177 | _scaleValue(value) { 178 | var scale = this._options.height / this._options.maxValue; 179 | 180 | 181 | return this._options.height - (value * scale); 182 | } 183 | 184 | /** 185 | * Returns the name (and version, if available) of this widget. 186 | * 187 | * @private 188 | * @method _getName 189 | * @returns {string} name (and version, if available) of this widget 190 | */ 191 | _getName() { 192 | var name = this.NAME; 193 | // if we appear to have a version 194 | if (this.VERSION.indexOf('<%=') !== 0) { 195 | name = this.NAME + ' ' + this.VERSION; 196 | } 197 | return name; 198 | } 199 | 200 | /** 201 | * Deconstructor 202 | * 203 | * @public 204 | * @method destroy 205 | */ 206 | destroy() { 207 | if (typeof this._canvas !== 'undefined' && this._canvas != null) { 208 | this._canvas.remove(); 209 | delete this._canvas; 210 | } 211 | } 212 | 213 | 214 | /** 215 | * Hook into a worm event. 216 | * 217 | * @public 218 | * @method on 219 | * @param {string} eventName the event to hook into 220 | * @param {function} callback the callback to run 221 | * @returns {null} 222 | */ 223 | on(eventName, callback) { 224 | var self = this; 225 | this._eventEmitter.on(eventName, (a, b, c) => callback.call(self, a, b, c)); 226 | } 227 | 228 | 229 | /** 230 | * Sets the value 231 | * 232 | * @public 233 | * @method setValue 234 | * @param {number} optionValue value to set the option to 235 | * @returns {null} 236 | */ 237 | setValue(newValue) { 238 | 239 | if (newValue > this._options.maxValue) { 240 | newValue = this._options.maxValue; 241 | } 242 | if (this._options.accessibilityBroadcast !== 'off') { 243 | if (this._fallbackDom && this._fallbackDom.remove) { 244 | this._fallbackDom.remove(); 245 | this._fallbackDom.innerText = 'worm value is ' + newValue; 246 | this._rootDiv.appendChild(this._fallbackDom); 247 | } 248 | } 249 | 250 | if (newValue > this._value) { 251 | this._eventEmitter.emit('valueIncreased', this._value, newValue); 252 | } 253 | if (newValue < this._value) { 254 | this._eventEmitter.emit('valueDecreased', this._value, newValue); 255 | } 256 | if (newValue <= 0) { 257 | this._eventEmitter.emit('valueBecameMinimum', this._value); 258 | } 259 | if (newValue >= this._options.maxValue) { 260 | this._eventEmitter.emit('valueBecameMaximum', this._value); 261 | } 262 | 263 | 264 | if (newValue <= 0) { 265 | this._eventEmitter.emit('valueBecameMinimum', this._value); 266 | } 267 | 268 | this._value = newValue; 269 | this._momentum = 0; 270 | this._eventEmitter.emit('valueChanged', this._value); 271 | } 272 | 273 | /** 274 | * Gets the value 275 | * 276 | * @public 277 | * @method getValue 278 | * @returns {number} the current value 279 | */ 280 | getValue() { 281 | return this._value; 282 | } 283 | 284 | /** 285 | * Sets the value for the specified option. 286 | * 287 | * @public 288 | * @method setOption 289 | * @param {string} optionName name of the option to set a value for 290 | * @param {object} optionValue value to set the option to 291 | * @returns {null} 292 | */ 293 | setOption(optionName, optionValue) { 294 | this._options[optionName] = optionValue; 295 | } 296 | 297 | /** 298 | * Returns the value for the specified option. 299 | * 300 | * @public 301 | * @method getOption 302 | * @param {string} optionName name of the option to retrieve a value for 303 | * @returns {object} the value of the specified option 304 | */ 305 | getOption(optionName) { 306 | return this._options[optionName]; 307 | } 308 | 309 | } 310 | -------------------------------------------------------------------------------- /dist/bundle.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://IRISWorm/webpack/universalModuleDefinition","webpack://IRISWorm/webpack/bootstrap","webpack://IRISWorm/./src/_entry.js","webpack://IRISWorm/./src/iris.worm.js","webpack://IRISWorm/./src/event-emitter.js"],"names":["root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","_iris","Worm","WORM","_eventEmitter","div","options","arguments","length","undefined","_classCallCheck","this","_rootDiv","_options","assign","DEFAULT_OPTIONS","_canvas","document","createElement","width","height","className","CSS_CONTAINER","_ctx","getContext","appendChild","_value","_metaValue","_oldMetaValue","_momentum","_active","accessibilityBroadcast","_fallbackDom","setAttribute","EventEmitter","maxValue","smoothMode","colorMode","acceleration","lineWidth","_draw","requestAnimationFrame","_moveViewport","_drawPoint","_resolveValues","distanceToValue","Math","abs","MAX_MOMENTUM","imageData","getImageData","putImageData","clearRect","color","colorUnit","bad","floor","_scaleValue","good","strokeStyle","beginPath","moveTo","lineTo","stroke","scale","NAME","VERSION","indexOf","remove","eventName","callback","self","on","a","b","newValue","innerText","emit","optionName","optionValue","logger","_events","push","arg1","arg2","arg3","forEach","fn"],"mappings":"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","file":"bundle.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"IRISWorm\"] = factory();\n\telse\n\t\troot[\"IRISWorm\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","import WORM from './iris.worm';\n\nexport const Worm = WORM;","import EventEmitter from './event-emitter';\n\nexport default class Worm {\n\n get NAME() {\n 'IRIS Worm'\n };\n get VERSION() {\n return null\n } // TODO\n get CSS_CONTAINER() {\n return 'irisWorm'\n };\n get MAX_MOMENTUM() {\n return 5\n };\n\n static get DEFAULT_OPTIONS() {\n return {\n // The width of the component\n width: 600,\n\n // The height of the component\n height: 400,\n\n // The maximum value that can be set in the component (used for scaling) -\n // defaults to 100, meaning that \"100\" is the \"Top of the worm\".\n maxValue: 100,\n\n // When a value changes, the worm will accelerate towards that value smoothly\n // if smoothMode is set to true, otherwise it will jump straight to it.\n smoothMode: true,\n\n // Color mode: options are: 'greenIsGood', 'greenIsBad', 'monochrome'\n colorMode: 'greenIsGood',\n\n // How quickly the worm accelerates towards its target (NOTE: this value really is only useful if you keep it\n // below 1, otherwise you might as well just use smoothMode: false and have it instantly jumping)\n acceleration: 0.1,\n\n // How thick the line is\n lineWidth: 5,\n\n //how insistant the aria-live tag is. Default is polite;\n //options are: off, polite, assertive\n accessibilityBroadcast: 'polite'\n }\n };\n\n /**\n * Constructs a new IRIS Worm instance.\n * @class IRIS.Worm\n * @constructor Worm\n * @example\n * new IRIS.Worm(div, options);\n * @param {HTMLDivElement} div the div in which the visualisation will be rendered, e.g. '#map'\n * @param options visualisation options (see 'options' property)\n */\n constructor(div, options = {}) {\n this._rootDiv = div;\n this._options = Object.assign({}, Worm.DEFAULT_OPTIONS, options);\n\n // create canvas and context\n this._canvas = document.createElement('canvas');\n this._canvas.width = this._options.width;\n this._canvas.height = this._options.height;\n this._canvas.className = this.CSS_CONTAINER;\n this._ctx = this._canvas.getContext('2d');\n this._rootDiv.appendChild(this._canvas);\n\n this._value = 50;\n this._metaValue = 50;\n this._oldMetaValue = 50;\n this._momentum = 0.0;\n this._active = false;\n\n //create fallback DOM and add aria roles if the accessibilityBroadcast option isn't disabled\n if (this._options.accessibilityBroadcast !== 'off') {\n this._fallbackDom = document.createElement('span');\n this._fallbackDom.setAttribute('role', 'alert');\n this._fallbackDom.setAttribute('aria-live', this._options.accessibilityBroadcast);\n this._fallbackDom.setAttribute('style', 'position:absolute;width:1px;' + '' +\n 'height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);');\n this._rootDiv.appendChild(this._fallbackDom);\n }\n\n // Events\n this._eventEmitter = new EventEmitter();\n }\n\n start() {\n this._ctx.lineWidth = this._options.lineWidth;\n this._active = true;\n this._draw();\n }\n\n stop() {\n this._active = false;\n }\n\n _draw() {\n if (this._active) {\n requestAnimationFrame(this._draw.bind(this));\n this._moveViewport();\n this._drawPoint();\n this._resolveValues();\n }\n }\n\n _resolveValues() {\n\n if (this._options.smoothMode) {\n var distanceToValue = Math.abs(this._value - this._metaValue);\n\n if (distanceToValue < 0.1) {\n this._metaValue = this._value;\n this._momentum = 0;\n return;\n } else {\n if (this._value < this._metaValue) {\n if (this._momentum >= -this.MAX_MOMENTUM) {\n this._momentum -= this._options.acceleration;\n }\n }\n if (this._value > this._metaValue) {\n if (this._momentum <= this.MAX_MOMENTUM) {\n this._momentum += this._options.acceleration;\n }\n }\n\n this._metaValue += (this._momentum * distanceToValue) / 100;\n }\n this._oldMetaValue = this._metaValue;\n } else {\n this._oldMetaValue = this._metaValue;\n this._metaValue = this._value;\n }\n\n }\n\n _moveViewport() {\n var imageData = this._ctx.getImageData(1, 0, this._options.width - 1, this._options.height);\n this._ctx.putImageData(imageData, 0, 0);\n this._ctx.clearRect(this._options.width - 1, 0, 1, this._options.height);\n\n // this thing is known to be leaky so let's force explicit garbage collecion.\n imageData = null;\n }\n\n _drawPoint() {\n\n var colorUnit = (255 / this._options.height);\n var bad = Math.floor(colorUnit * this._scaleValue(this._metaValue));\n var good = 255 - Math.floor(colorUnit * this._scaleValue(this._metaValue));\n var color;\n\n switch (this._options.colorMode) {\n case 'monochrome':\n color = 'rgb(0,0,0)';\n break;\n case 'greenIsBad':\n color = 'rgb(' + good + ',' + bad + ',0)';\n break;\n case 'greenIsGood':\n default:\n color = 'rgb(' + bad + ',' + good + ',0)';\n }\n\n this._ctx.strokeStyle = color;\n\n this._ctx.beginPath();\n this._ctx.moveTo(this._options.width, this._scaleValue(this._metaValue));\n this._ctx.lineTo(this._options.width - 1, this._scaleValue(this._oldMetaValue));\n this._ctx.stroke();\n }\n\n _scaleValue(value) {\n var scale = this._options.height / this._options.maxValue;\n\n\n return this._options.height - (value * scale);\n }\n\n /**\n * Returns the name (and version, if available) of this widget.\n *\n * @private\n * @method _getName\n * @returns {string} name (and version, if available) of this widget\n */\n _getName() {\n var name = this.NAME;\n // if we appear to have a version\n if (this.VERSION.indexOf('<%=') !== 0) {\n name = this.NAME + ' ' + this.VERSION;\n }\n return name;\n }\n\n /**\n * Deconstructor\n *\n * @public\n * @method destroy\n */\n destroy() {\n if (typeof this._canvas !== 'undefined' && this._canvas != null) {\n this._canvas.remove();\n delete this._canvas;\n }\n }\n\n\n /**\n * Hook into a worm event.\n *\n * @public\n * @method on\n * @param {string} eventName the event to hook into\n * @param {function} callback the callback to run\n * @returns {null}\n */\n on(eventName, callback) {\n var self = this;\n this._eventEmitter.on(eventName, (a, b, c) => callback.call(self, a, b, c));\n }\n\n\n /**\n * Sets the value\n *\n * @public\n * @method setValue\n * @param {number} optionValue value to set the option to\n * @returns {null}\n */\n setValue(newValue) {\n\n if (newValue > this._options.maxValue) {\n newValue = this._options.maxValue;\n }\n if (this._options.accessibilityBroadcast !== 'off') {\n if (this._fallbackDom && this._fallbackDom.remove) {\n this._fallbackDom.remove();\n this._fallbackDom.innerText = 'worm value is ' + newValue;\n this._rootDiv.appendChild(this._fallbackDom);\n }\n }\n\n if (newValue > this._value) {\n this._eventEmitter.emit('valueIncreased', this._value, newValue);\n }\n if (newValue < this._value) {\n this._eventEmitter.emit('valueDecreased', this._value, newValue);\n }\n if (newValue <= 0) {\n this._eventEmitter.emit('valueBecameMinimum', this._value);\n }\n if (newValue >= this._options.maxValue) {\n this._eventEmitter.emit('valueBecameMaximum', this._value);\n }\n\n\n if (newValue <= 0) {\n this._eventEmitter.emit('valueBecameMinimum', this._value);\n }\n\n this._value = newValue;\n this._momentum = 0;\n this._eventEmitter.emit('valueChanged', this._value);\n }\n\n /**\n * Gets the value\n *\n * @public\n * @method getValue\n * @returns {number} the current value\n */\n getValue() {\n return this._value;\n }\n\n /**\n * Sets the value for the specified option.\n *\n * @public\n * @method setOption\n * @param {string} optionName name of the option to set a value for\n * @param {object} optionValue value to set the option to\n * @returns {null}\n */\n setOption(optionName, optionValue) {\n this._options[optionName] = optionValue;\n }\n\n /**\n * Returns the value for the specified option.\n *\n * @public\n * @method getOption\n * @param {string} optionName name of the option to retrieve a value for\n * @returns {object} the value of the specified option\n */\n getOption(optionName) {\n return this._options[optionName];\n }\n\n}\n","export default class EventEmitter {\n\n constructor(logger) {\n this._events = {};\n }\n\n /**\n * Sets a listener for the specified event name.\n *\n * @public\n * @method on\n * @param {string} eventName name of the event to listen to.\n * @param {function} callback function to call when the event occurs.\n */\n on(eventName, callback) {\n this._events[eventName] = this._events[eventName] || [];\n this._events[eventName].push(callback);\n }\n\n /**\n * Sets a listener for the specified event name.\n *\n * @public\n * @method emit\n * @param {string} eventName name of the event to emit.\n * @param {any} arg1, arg2, arg3 arguments to yield to the functioun\n */\n emit(eventName, arg1, arg2, arg3) {\n (this._events[eventName] || []).forEach((fn) => {\n fn && fn(arg1, arg2, arg3)\n });\n }\n\n}"],"sourceRoot":""} -------------------------------------------------------------------------------- /dist/bundle.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://IRISWorm/webpack/universalModuleDefinition","webpack://IRISWorm/webpack/bootstrap","webpack://IRISWorm/./src/_entry.js","webpack://IRISWorm/./src/iris.worm.js","webpack://IRISWorm/./src/event-emitter.js"],"names":["root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","_iris","Worm","WORM","_eventEmitter","div","options","arguments","length","undefined","_classCallCheck","this","_rootDiv","_options","assign","DEFAULT_OPTIONS","_canvas","document","createElement","width","height","className","CSS_CONTAINER","_ctx","getContext","appendChild","_value","_metaValue","_oldMetaValue","_momentum","_active","accessibilityBroadcast","_fallbackDom","setAttribute","EventEmitter","maxValue","smoothMode","colorMode","acceleration","lineWidth","_draw","requestAnimationFrame","_moveViewport","_drawPoint","_resolveValues","distanceToValue","Math","abs","MAX_MOMENTUM","imageData","getImageData","putImageData","clearRect","color","colorUnit","bad","floor","_scaleValue","good","strokeStyle","beginPath","moveTo","lineTo","stroke","scale","NAME","VERSION","indexOf","remove","eventName","callback","self","on","a","b","newValue","innerText","emit","optionName","optionValue","logger","_events","push","arg1","arg2","arg3","forEach","fn"],"mappings":"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","file":"bundle.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"IRISWorm\"] = factory();\n\telse\n\t\troot[\"IRISWorm\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","import WORM from './iris.worm';\n\nexport const Worm = WORM;","import EventEmitter from './event-emitter';\n\nexport default class Worm {\n\n get NAME() {\n 'IRIS Worm'\n };\n get VERSION() {\n return null\n } // TODO\n get CSS_CONTAINER() {\n return 'irisWorm'\n };\n get MAX_MOMENTUM() {\n return 5\n };\n\n static get DEFAULT_OPTIONS() {\n return {\n // The width of the component\n width: 600,\n\n // The height of the component\n height: 400,\n\n // The maximum value that can be set in the component (used for scaling) -\n // defaults to 100, meaning that \"100\" is the \"Top of the worm\".\n maxValue: 100,\n\n // When a value changes, the worm will accelerate towards that value smoothly\n // if smoothMode is set to true, otherwise it will jump straight to it.\n smoothMode: true,\n\n // Color mode: options are: 'greenIsGood', 'greenIsBad', 'monochrome'\n colorMode: 'greenIsGood',\n\n // How quickly the worm accelerates towards its target (NOTE: this value really is only useful if you keep it\n // below 1, otherwise you might as well just use smoothMode: false and have it instantly jumping)\n acceleration: 0.1,\n\n // How thick the line is\n lineWidth: 5,\n\n //how insistant the aria-live tag is. Default is polite;\n //options are: off, polite, assertive\n accessibilityBroadcast: 'polite'\n }\n };\n\n /**\n * Constructs a new IRIS Worm instance.\n * @class IRIS.Worm\n * @constructor Worm\n * @example\n * new IRIS.Worm(div, options);\n * @param {HTMLDivElement} div the div in which the visualisation will be rendered, e.g. '#map'\n * @param options visualisation options (see 'options' property)\n */\n constructor(div, options = {}) {\n this._rootDiv = div;\n this._options = Object.assign({}, Worm.DEFAULT_OPTIONS, options);\n\n // create canvas and context\n this._canvas = document.createElement('canvas');\n this._canvas.width = this._options.width;\n this._canvas.height = this._options.height;\n this._canvas.className = this.CSS_CONTAINER;\n this._ctx = this._canvas.getContext('2d');\n this._rootDiv.appendChild(this._canvas);\n\n this._value = 50;\n this._metaValue = 50;\n this._oldMetaValue = 50;\n this._momentum = 0.0;\n this._active = false;\n\n //create fallback DOM and add aria roles if the accessibilityBroadcast option isn't disabled\n if (this._options.accessibilityBroadcast !== 'off') {\n this._fallbackDom = document.createElement('span');\n this._fallbackDom.setAttribute('role', 'alert');\n this._fallbackDom.setAttribute('aria-live', this._options.accessibilityBroadcast);\n this._fallbackDom.setAttribute('style', 'position:absolute;width:1px;' + '' +\n 'height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);');\n this._rootDiv.appendChild(this._fallbackDom);\n }\n\n // Events\n this._eventEmitter = new EventEmitter();\n }\n\n start() {\n this._ctx.lineWidth = this._options.lineWidth;\n this._active = true;\n this._draw();\n }\n\n stop() {\n this._active = false;\n }\n\n _draw() {\n if (this._active) {\n requestAnimationFrame(this._draw.bind(this));\n this._moveViewport();\n this._drawPoint();\n this._resolveValues();\n }\n }\n\n _resolveValues() {\n\n if (this._options.smoothMode) {\n var distanceToValue = Math.abs(this._value - this._metaValue);\n\n if (distanceToValue < 0.1) {\n this._metaValue = this._value;\n this._momentum = 0;\n return;\n } else {\n if (this._value < this._metaValue) {\n if (this._momentum >= -this.MAX_MOMENTUM) {\n this._momentum -= this._options.acceleration;\n }\n }\n if (this._value > this._metaValue) {\n if (this._momentum <= this.MAX_MOMENTUM) {\n this._momentum += this._options.acceleration;\n }\n }\n\n this._metaValue += (this._momentum * distanceToValue) / 100;\n }\n this._oldMetaValue = this._metaValue;\n } else {\n this._oldMetaValue = this._metaValue;\n this._metaValue = this._value;\n }\n\n }\n\n _moveViewport() {\n var imageData = this._ctx.getImageData(1, 0, this._options.width - 1, this._options.height);\n this._ctx.putImageData(imageData, 0, 0);\n this._ctx.clearRect(this._options.width - 1, 0, 1, this._options.height);\n\n // this thing is known to be leaky so let's force explicit garbage collecion.\n imageData = null;\n }\n\n _drawPoint() {\n\n var colorUnit = (255 / this._options.height);\n var bad = Math.floor(colorUnit * this._scaleValue(this._metaValue));\n var good = 255 - Math.floor(colorUnit * this._scaleValue(this._metaValue));\n var color;\n\n switch (this._options.colorMode) {\n case 'monochrome':\n color = 'rgb(0,0,0)';\n break;\n case 'greenIsBad':\n color = 'rgb(' + good + ',' + bad + ',0)';\n break;\n case 'greenIsGood':\n default:\n color = 'rgb(' + bad + ',' + good + ',0)';\n }\n\n this._ctx.strokeStyle = color;\n\n this._ctx.beginPath();\n this._ctx.moveTo(this._options.width, this._scaleValue(this._metaValue));\n this._ctx.lineTo(this._options.width - 1, this._scaleValue(this._oldMetaValue));\n this._ctx.stroke();\n }\n\n _scaleValue(value) {\n var scale = this._options.height / this._options.maxValue;\n\n\n return this._options.height - (value * scale);\n }\n\n /**\n * Returns the name (and version, if available) of this widget.\n *\n * @private\n * @method _getName\n * @returns {string} name (and version, if available) of this widget\n */\n _getName() {\n var name = this.NAME;\n // if we appear to have a version\n if (this.VERSION.indexOf('<%=') !== 0) {\n name = this.NAME + ' ' + this.VERSION;\n }\n return name;\n }\n\n /**\n * Deconstructor\n *\n * @public\n * @method destroy\n */\n destroy() {\n if (typeof this._canvas !== 'undefined' && this._canvas != null) {\n this._canvas.remove();\n delete this._canvas;\n }\n }\n\n\n /**\n * Hook into a worm event.\n *\n * @public\n * @method on\n * @param {string} eventName the event to hook into\n * @param {function} callback the callback to run\n * @returns {null}\n */\n on(eventName, callback) {\n var self = this;\n this._eventEmitter.on(eventName, (a, b, c) => callback.call(self, a, b, c));\n }\n\n\n /**\n * Sets the value\n *\n * @public\n * @method setValue\n * @param {number} optionValue value to set the option to\n * @returns {null}\n */\n setValue(newValue) {\n\n if (newValue > this._options.maxValue) {\n newValue = this._options.maxValue;\n }\n if (this._options.accessibilityBroadcast !== 'off') {\n if (this._fallbackDom && this._fallbackDom.remove) {\n this._fallbackDom.remove();\n this._fallbackDom.innerText = 'worm value is ' + newValue;\n this._rootDiv.appendChild(this._fallbackDom);\n }\n }\n\n if (newValue > this._value) {\n this._eventEmitter.emit('valueIncreased', this._value, newValue);\n }\n if (newValue < this._value) {\n this._eventEmitter.emit('valueDecreased', this._value, newValue);\n }\n if (newValue <= 0) {\n this._eventEmitter.emit('valueBecameMinimum', this._value);\n }\n if (newValue >= this._options.maxValue) {\n this._eventEmitter.emit('valueBecameMaximum', this._value);\n }\n\n\n if (newValue <= 0) {\n this._eventEmitter.emit('valueBecameMinimum', this._value);\n }\n\n this._value = newValue;\n this._momentum = 0;\n this._eventEmitter.emit('valueChanged', this._value);\n }\n\n /**\n * Gets the value\n *\n * @public\n * @method getValue\n * @returns {number} the current value\n */\n getValue() {\n return this._value;\n }\n\n /**\n * Sets the value for the specified option.\n *\n * @public\n * @method setOption\n * @param {string} optionName name of the option to set a value for\n * @param {object} optionValue value to set the option to\n * @returns {null}\n */\n setOption(optionName, optionValue) {\n this._options[optionName] = optionValue;\n }\n\n /**\n * Returns the value for the specified option.\n *\n * @public\n * @method getOption\n * @param {string} optionName name of the option to retrieve a value for\n * @returns {object} the value of the specified option\n */\n getOption(optionName) {\n return this._options[optionName];\n }\n\n}\n","export default class EventEmitter {\n\n constructor(logger) {\n this._events = {};\n }\n\n /**\n * Sets a listener for the specified event name.\n *\n * @public\n * @method on\n * @param {string} eventName name of the event to listen to.\n * @param {function} callback function to call when the event occurs.\n */\n on(eventName, callback) {\n this._events[eventName] = this._events[eventName] || [];\n this._events[eventName].push(callback);\n }\n\n /**\n * Sets a listener for the specified event name.\n *\n * @public\n * @method emit\n * @param {string} eventName name of the event to emit.\n * @param {any} arg1, arg2, arg3 arguments to yield to the functioun\n */\n emit(eventName, arg1, arg2, arg3) {\n (this._events[eventName] || []).forEach((fn) => {\n fn && fn(arg1, arg2, arg3)\n });\n }\n\n}"],"sourceRoot":""} --------------------------------------------------------------------------------