├── .gitignore ├── LICENSE ├── README.md ├── index.html ├── params.json ├── src ├── assets │ └── cave.png ├── game.js ├── index.html ├── lib │ ├── cellautoVoronoi.js │ ├── highlight.pack.js │ ├── phaser.js │ └── rhill-voronoi-core.min.js └── plugin │ ├── PhaserIslandjsPlugin.js │ └── perlin.js └── stylesheets ├── github-light.css ├── github.css ├── normalize.css └── stylesheet.css /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 luckylooke 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Phaser island.js plugin 2 | Phaser.io plugin for procedural generation and rendering island maps based on island.js (https://github.com/lebesnec/island.js) 3 | 4 | # What I have done 5 | I mostly just refactor render functions to get rid of paper.js dependency (phaser framework has own rendering system). I also added seed as config parameter so you can get same islands by it. I have also created [modified version](https://gist.github.com/luckylooke/85b0aa072ad8e95f2cef) of [cellauto.js](https://sanojian.github.io/cellauto/) to support polygonal enviroment. 6 | 7 | # Plans 8 | Creating a game to show use of the plugin! :) 9 | 10 | Collaboration welcomed! 11 | 12 | #WEB with DEMO 13 | [link: luckylooke.github.io/phaser-islandjs-plugin](http://luckylooke.github.io/phaser-islandjs-plugin) 14 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Phaser-islandjs-plugin by luckylooke 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 23 | 24 |
25 | 26 |

Island map generator in JavaScript, using a Voronoi graph and perlin noise provided as Phaser.io plugin.

27 | 35 | 36 |

Dependencies

37 | 38 | 46 | 47 |

DEMO

48 | 49 |

Reload page to see another generated island.

50 | 51 |
52 | 53 |
54 | 55 | 56 |
57 | 58 | 59 |

Usage

60 | 61 |

Dependency files and plugin file need to be loaded before main game code

62 | 63 |

 64 |   <script src="lib/phaser.js"></script>
 65 |   <script src="lib/rhill-voronoi-core.min.js"></script>
 66 |   <script src="plugin/perlin.js"></script>
 67 |   <script src="plugin/PhaserIslandjsPlugin.js"></script>
 68 |   <script src="game.js"></script>
 69 | 
70 | 71 | 72 |

You need hidden canvas in your page for creating perlin noise

73 | 74 |

 75 |   <canvas id="perlin" hidden="true"></canvas>
 76 | 
77 | 78 |

In your game create function

79 | 80 |

 81 |   var island = this.game.plugins.add(Phaser.Plugin.Island, {
 82 |     // custom settings
 83 |     width: 500,
 84 |     height: 500,
 85 |     perlinWidth: 256,
 86 |     perlinHeight: 256,
 87 |     allowDebug: false, // if set to true, you can click on the map to enter "debug" mode. Warning : debug mode is slow to initialize, set to false for faster rendering.
 88 |     nbSites: 10000, // numbers of voronoi cell
 89 |     sitesDistribution: 'hexagon', // distribution of the site of the voronoi graph : random, square or hexagon
 90 |     sitesRandomisation: 80, // will move each site in a random way (in %), for the square or hexagon distribution to look more random
 91 |     nbGraphRelaxation: 0, // nb of time we apply the relaxation algo to the voronoi graph (slow !), for the random distribution to look less random
 92 |     cliffsThreshold: 0.15,
 93 |     lakesThreshold: 0.005, // lake elevation will increase by this value (* the river size) when a new river end inside
 94 |     nbRivers: (10000 / 200),
 95 |     maxRiversSize: 4,
 96 |     // seed: 168165168, // randomization can be seeded
 97 |     shadeOcean: true
 98 |   });
 99 |   
100 |   // You can change colors before rendering
101 |   island.DISPLAY_COLORS.OCEAN = '#4488ff';
102 |   
103 |   // Start rendering
104 |   island.renderNow();
105 | 
106 | 107 | 108 |

DEMO - debug=true

109 | 110 |

Try to click on the map, you will get extra debug info from cell.

111 | 112 |
113 | 114 |
115 | 116 |
117 | 118 |

Used code for debuged DEMO

119 | 120 |

121 |   function create(){
122 |     var island = this.game.plugins.add(Phaser.Plugin.Island, {
123 |           nbSites: 100,
124 |           perlinWidth: this.game.width/2,
125 |           perlinHeight: this.game.height/2,
126 |           allowDebug: true
127 |       });
128 |       island.renderNow();
129 |       this.game.input.onDown.add(function click(pointer) {
130 |         island.renderSite(island.cellIdFromPoint(pointer.x, pointer.y));
131 |       });
132 |   }
133 |   
134 |   var game = new Phaser.Game(window.innerWidth, window.innerHeight, Phaser.AUTO, 'phaser-game-debugger', {create: create});
135 | 
136 | 137 | 138 |

DEMO - cellular automata

139 | 140 |

141 | Would you like to cellular automata on island map cells? Good news, 142 | I have rewritten cellauto.js lib by Jonas Olmstead 143 | to cellautoVoronoi.js version which can be used here. 144 | You can click on cave icon in first demo above to see it in action. I have used cave example from cellauto.js demo page. 145 | Every click is one step. If you want to restart example, just reload page. 146 |

147 | 148 |

Used code for cave demo

149 | 150 |

151 |     function preload(){
152 |     this.load.image('cave', 'src/assets/cave.png');
153 |   }
154 |   function create(){
155 |     var island = this.game.plugins.add(Phaser.Plugin.Island, {
156 |       // custom settings
157 |         perlinWidth: this.game.width/2,
158 |         perlinHeight: this.game.height/2
159 |     });
160 |     // island.DISPLAY_COLORS.OCEAN = '#4444ff';
161 |     island.renderNow();
162 |     
163 |     function example_caves() {
164 |   
165 |     	var cells = island.diagram.cells,
166 |     	  world = new CAVWorld(cells);
167 |     
168 |     	world.registerCellType('wall', {
169 |     		process: function (cellVoronoi) {
170 |     		  var neighbors = cellVoronoi.neighborsCache || island.getNeighbors(cellVoronoi.site.voronoiId),
171 |     		    surrounding  = this.countSurroundingCellsWithValue(neighbors, 'wasOpen');
172 |    
173 |     			this.open = (this.wasOpen && surrounding >= 3) || surrounding >= 5;
174 |     		},
175 |     		reset: function () {
176 |     			this.wasOpen = this.open;
177 |     		}
178 |     	}, function () {
179 |     		//init
180 |     		this.open = Math.random() > 0.40;
181 |     	});
182 |     
183 |     	world.initialize([
184 |     		{ name: 'wall', distribution: 100 }
185 |     	]);
186 |     
187 |     	return world;
188 |     }
189 |     
190 |     var test = example_caves();
191 |     
192 |     var testBtnFn = function() {
193 |       test.step();
194 |       console.log('testBtnFn');
195 |       for (var i = 0; i < test.voronoiCells.length; i++) {
196 |         var cell = test.voronoiCells[i],
197 |           ctx = island.debugLayer.ctx,
198 |           borders = cell.bordersCache || island.getBorders(cell.site.voronoiId),
199 |           bLength = borders.length, y;
200 |           
201 |         ctx.fillStyle = cell.ca.open ? '#fff' : '#000';
202 |         ctx.beginPath();
203 |         ctx.moveTo(borders[0].x,borders[0].y);
204 |         for (y = 1; y < bLength; y++) {
205 |           ctx.lineTo(borders[y].x,borders[y].y);
206 |         }
207 |         ctx.closePath();
208 |         ctx.fill();
209 |       }
210 |       island.debugLayer.dirty = true;
211 |     };
212 |     
213 |     var button = this.game.add.button(95, 400, 'cave', testBtnFn, this, 2, 1, 0);
214 |       button.fixedToCamera = true;
215 |       button.cameraOffset.setTo(10, 30);
216 |     }
217 |     
218 |   new Phaser.Game(window.innerWidth, window.innerHeight, Phaser.AUTO, 'phaser-game', {create: create, preload:preload});
219 | 
220 | 221 | 222 | 227 | 228 |
229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 251 | 252 | 253 | 254 | 255 | -------------------------------------------------------------------------------- /params.json: -------------------------------------------------------------------------------- 1 | {"name":"Phaser-islandjs-plugin","tagline":"Phaser.io plugin for procedural generation and rendering island maps based on island.js (https://github.com/lebesnec/island.js)","body":"### Welcome to GitHub Pages.\r\nThis automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here using GitHub Flavored Markdown, select a template crafted by a designer, and publish. After your page is generated, you can check out the new branch:\r\n\r\n```\r\n$ cd your_repo_root/repo_name\r\n$ git fetch origin\r\n$ git checkout gh-pages\r\n```\r\n\r\nIf you're using the GitHub for Mac, simply sync your repository and you'll see the new branch.\r\n\r\n### Designer Templates\r\nWe've crafted some handsome templates for you to use. Go ahead and continue to layouts to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved if it remained markdown format.\r\n\r\n### Rather Drive Stick?\r\nIf you prefer to not use the automatic generator, push a branch named `gh-pages` to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator written by our own Tom Preston-Werner. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.\r\n\r\n### Authors and Contributors\r\nYou can @mention a GitHub username to generate a link to their profile. The resulting `` element will link to the contributor's GitHub Profile. For example: In 2007, Chris Wanstrath (@defunkt), PJ Hyett (@pjhyett), and Tom Preston-Werner (@mojombo) founded GitHub.\r\n\r\n### Support or Contact\r\nHaving trouble with Pages? Check out the documentation at https://help.github.com/pages or contact support@github.com and we’ll help you sort it out.\r\n","google":"UA-63917744-1","note":"Don't delete this file! It's used internally to help with page regeneration."} -------------------------------------------------------------------------------- /src/assets/cave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luckylooke/phaser-islandjs-plugin/ab78563438cda7bfe999ae50256b3f61acd1285b/src/assets/cave.png -------------------------------------------------------------------------------- /src/game.js: -------------------------------------------------------------------------------- 1 | 2 | /* global Phaser CAVWorld */ 3 | window.onload = function () { 4 | function preload(){ 5 | this.load.image('cave', 'src/assets/cave.png'); 6 | } 7 | function create(){ 8 | var island = this.game.plugins.add(Phaser.Plugin.Island, { 9 | // custom settings 10 | perlinWidth: this.game.width/2, 11 | perlinHeight: this.game.height/2, 12 | nbSites: 3000, 13 | }); 14 | // island.DISPLAY_COLORS.OCEAN = '#4444ff'; 15 | island.renderNow(); 16 | 17 | function example_caves() { 18 | 19 | var cells = island.diagram.cells, 20 | world = new CAVWorld(cells); 21 | 22 | world.registerCellType('wall', { 23 | process: function (cellVoronoi) { 24 | var neighbors = cellVoronoi.neighborsCache || island.getNeighbors(cellVoronoi.site.voronoiId), 25 | surrounding = this.countSurroundingCellsWithValue(neighbors, 'wasOpen'); 26 | 27 | this.open = (this.wasOpen && surrounding >= 3) || surrounding >= 5; 28 | }, 29 | reset: function () { 30 | this.wasOpen = this.open; 31 | } 32 | }, function () { 33 | //init 34 | this.open = Math.random() > 0.40; 35 | }); 36 | 37 | world.initialize([ 38 | { name: 'wall', distribution: 100 } 39 | ]); 40 | 41 | return world; 42 | } 43 | 44 | var test = example_caves(); 45 | 46 | var testBtnFn = function() { 47 | test.step(); 48 | console.log('testBtnFn'); 49 | for (var i = 0; i < test.voronoiCells.length; i++) { 50 | var cell = test.voronoiCells[i], 51 | ctx = island.debugLayer.ctx, 52 | borders = cell.bordersCache || island.getBorders(cell.site.voronoiId), 53 | bLength = borders.length, y; 54 | 55 | ctx.fillStyle = cell.ca.open ? '#fff' : '#000'; 56 | ctx.beginPath(); 57 | ctx.moveTo(borders[0].x,borders[0].y); 58 | for (y = 1; y < bLength; y++) { 59 | ctx.lineTo(borders[y].x,borders[y].y); 60 | } 61 | ctx.closePath(); 62 | ctx.fill(); 63 | } 64 | island.debugLayer.dirty = true; 65 | }; 66 | 67 | var button = this.game.add.button(95, 400, 'cave', testBtnFn, this, 2, 1, 0); 68 | button.fixedToCamera = true; 69 | button.cameraOffset.setTo(10, 30); 70 | } 71 | 72 | new Phaser.Game(window.innerWidth, window.innerHeight, Phaser.AUTO, 'phaser-game', {create: create, preload:preload}); 73 | 74 | function create2(){ 75 | var island = this.game.plugins.add(Phaser.Plugin.Island, { 76 | nbSites: 100, 77 | perlinWidth: this.game.width/2, 78 | perlinHeight: this.game.height/2, 79 | // seed: 168165168, 80 | allowDebug: true 81 | }); 82 | island.renderNow(); 83 | this.game.input.onDown.add(function click(pointer) { 84 | island.renderSite(island.cellIdFromPoint(pointer.x, pointer.y)); 85 | }); 86 | } 87 | 88 | new Phaser.Game(window.innerWidth, window.innerHeight, Phaser.AUTO, 'phaser-game-debugger', {create: create2}); 89 | }; 90 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Phaser game 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/lib/cellautoVoronoi.js: -------------------------------------------------------------------------------- 1 | // http://sanojian.github.io/cellauto/ 2 | 3 | function CellAutoVoronoiCell(index) { 4 | this.index = index; 5 | this.delays = []; 6 | } 7 | 8 | CellAutoVoronoiCell.prototype.process = function(neighbors) { 9 | return; 10 | }; 11 | CellAutoVoronoiCell.prototype.countSurroundingCellsWithValue = function(neighbors, value) { 12 | var surrounding = 0; 13 | for (var i = 0; i < neighbors.length; i++) { 14 | if (neighbors[i].ca && (neighbors[i].ca[value] || neighbors[i].ca[value] === 0)) { 15 | surrounding++; 16 | } 17 | } 18 | return surrounding; 19 | }; 20 | 21 | CellAutoVoronoiCell.prototype.getSurroundingCellsAverageValue = function(neighbors, value) { 22 | var summed = 0.0; 23 | for (var i = 0; i < neighbors.length; i++) { 24 | if (neighbors[i].ca && neighbors[i].ca[value]) { 25 | summed += neighbors[i].ca[value]; 26 | } 27 | } 28 | return summed / neighbors.length;//cnt; 29 | }; 30 | 31 | CellAutoVoronoiCell.prototype.delay = function(numSteps, fn) { 32 | this.delays.push({ steps: numSteps, action: fn }); 33 | }; 34 | 35 | CellAutoVoronoiCell.prototype.reset = function(neighbors) { 36 | return; 37 | }; 38 | 39 | function CAVWorld(voronoiCells, options) { 40 | 41 | this.options = options; 42 | this.voronoiCells = voronoiCells; 43 | this.cellsLength = voronoiCells.length; 44 | this.randomGenerator = Math.random; 45 | 46 | this.step = function() { 47 | for (var x=0; x b.distribution ? 1 : -1; 72 | }); 73 | 74 | var totalDist = 0; 75 | // add all distributions together 76 | for (var i=0; i/gm,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0==t.index}function a(e){return/no-?highlight|plain|text/.test(e)}function i(e){var n,t,r,i=e.className+" ";if(i+=e.parentNode?e.parentNode.className:"",t=/\blang(?:uage)?-([\w-]+)\b/.exec(i))return E(t[1])?t[1]:"no-highlight";for(i=i.split(/\s+/),n=0,r=i.length;r>n;n++)if(E(i[n])||a(i[n]))return i[n]}function o(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3==i.nodeType?a+=i.nodeValue.length:1==i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!=r[0].offset?e[0].offset"}function u(e){f+=""}function c(e){("start"==e.event?o:u)(e.node)}for(var s=0,f="",l=[];e.length||r.length;){var g=i();if(f+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g==e){l.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g==e&&g.length&&g[0].offset==s);l.reverse().forEach(o)}else"start"==g[0].event?l.push(g[0].node):l.pop(),c(g.splice(0,1)[0])}return f+n(a.substr(s))}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):Object.keys(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\b\w+\b/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),void 0===a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(o(e,n))}):s.push("self"==e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var f=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=f.length?t(f.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e,n){for(var t=0;t";return i+=e+'">',i+n+o}function p(){if(!L.k)return n(y);var e="",t=0;L.lR.lastIndex=0;for(var r=L.lR.exec(y);r;){e+=n(y.substr(t,r.index-t));var a=g(L,r);a?(B+=a[1],e+=h(a[0],n(r[0]))):e+=n(r[0]),t=L.lR.lastIndex,r=L.lR.exec(y)}return e+n(y.substr(t))}function d(){var e="string"==typeof L.sL;if(e&&!x[L.sL])return n(y);var t=e?f(L.sL,y,!0,M[L.sL]):l(y,L.sL.length?L.sL:void 0);return L.r>0&&(B+=t.r),e&&(M[L.sL]=t.top),h(t.language,t.value,!1,!0)}function b(){return void 0!==L.sL?d():p()}function v(e,t){var r=e.cN?h(e.cN,"",!0):"";e.rB?(k+=r,y=""):e.eB?(k+=n(t)+r,y=""):(k+=r,y=t),L=Object.create(e,{parent:{value:L}})}function m(e,t){if(y+=e,void 0===t)return k+=b(),0;var r=o(t,L);if(r)return k+=b(),v(r,t),r.rB?0:t.length;var a=u(L,t);if(a){var i=L;i.rE||i.eE||(y+=t),k+=b();do L.cN&&(k+=""),B+=L.r,L=L.parent;while(L!=a.parent);return i.eE&&(k+=n(t)),y="",a.starts&&v(a.starts,""),i.rE?0:t.length}if(c(t,L))throw new Error('Illegal lexeme "'+t+'" for mode "'+(L.cN||"")+'"');return y+=t,t.length||1}var N=E(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var R,L=i||N,M={},k="";for(R=L;R!=N;R=R.parent)R.cN&&(k=h(R.cN,"",!0)+k);var y="",B=0;try{for(var C,j,I=0;;){if(L.t.lastIndex=I,C=L.t.exec(t),!C)break;j=m(t.substr(I,C.index-I),C[0]),I=C.index+j}for(m(t.substr(I)),R=L;R.parent;R=R.parent)R.cN&&(k+="");return{r:B,value:k,language:e,top:L}}catch(O){if(-1!=O.message.indexOf("Illegal"))return{r:0,value:n(t)};throw O}}function l(e,t){t=t||w.languages||Object.keys(x);var r={r:0,value:n(e)},a=r;return t.forEach(function(n){if(E(n)){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}}),a.language&&(r.second_best=a),r}function g(e){return w.tabReplace&&(e=e.replace(/^((<[^>]+>|\t)+)/gm,function(e,n){return n.replace(/\t/g,w.tabReplace)})),w.useBR&&(e=e.replace(/\n/g,"
")),e}function h(e,n,t){var r=n?R[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function p(e){var n=i(e);if(!a(n)){var t;w.useBR?(t=document.createElementNS("http://www.w3.org/1999/xhtml","div"),t.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):t=e;var r=t.textContent,o=n?f(n,r,!0):l(r),s=u(t);if(s.length){var p=document.createElementNS("http://www.w3.org/1999/xhtml","div");p.innerHTML=o.value,o.value=c(s,u(p),r)}o.value=g(o.value),e.innerHTML=o.value,e.className=h(e.className,n,o.language),e.result={language:o.language,re:o.r},o.second_best&&(e.second_best={language:o.second_best.language,re:o.second_best.r})}}function d(e){w=o(w,e)}function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll("pre code");Array.prototype.forEach.call(e,p)}}function v(){addEventListener("DOMContentLoaded",b,!1),addEventListener("load",b,!1)}function m(n,t){var r=x[n]=t(e);r.aliases&&r.aliases.forEach(function(e){R[e]=n})}function N(){return Object.keys(x)}function E(e){return x[e]||x[R[e]]}var w={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},x={},R={};return e.highlight=f,e.highlightAuto=l,e.fixMarkup=g,e.highlightBlock=p,e.configure=d,e.initHighlighting=b,e.initHighlightingOnLoad=v,e.registerLanguage=m,e.listLanguages=N,e.getLanguage=E,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",a={cN:"function",b:c+"\\(",rB:!0,eE:!0,e:"\\("},r={cN:"rule",b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{cN:"value",eW:!0,eE:!0,c:[a,e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,r,{cN:"id",b:/\#[A-Za-z0-9_-]+/},{cN:"class",b:/\.[A-Za-z0-9_-]+/},{cN:"attr_selector",b:/\[/,e:/\]/,i:"$"},{cN:"pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"']+/},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[a,e.ASM,e.QSM,e.CSSNM]}]},{cN:"tag",b:c,r:0},{cN:"rules",b:"{",e:"}",i:/\S/,c:[e.CBCM,r]}]}});hljs.registerLanguage("http",function(t){return{aliases:["https"],i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:!0,e:"$",c:[{cN:"string",b:" ",e:" ",eB:!0,eE:!0}]},{cN:"attribute",b:"^\\w",e:": ",eE:!0,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:[],eW:!0}}]}});hljs.registerLanguage("javascript",function(e){return{aliases:["js"],k:{keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},c:[{cN:"pi",r:10,b:/^\s*['"]use (strict|asm)['"]/},e.ASM,e.QSM,{cN:"string",b:"`",e:"`",c:[e.BE,{cN:"subst",b:"\\$\\{",e:"\\}"}]},e.CLCM,e.CBCM,{cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b:/\s*[);\]]/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:[e.CLCM,e.CBCM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+e.IR,r:0},{bK:"import",e:"[;$]",k:"import from as",c:[e.ASM,e.QSM]},{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]}],i:/#/}});hljs.registerLanguage("xml",function(t){var s="[A-Za-z0-9\\._:-]+",c={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php"},e={eW:!0,i:/]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xsl","plist"],cI:!0,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},t.C("",{r:10}),{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[e],starts:{e:"",rE:!0,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[e],starts:{e:"",rE:!0,sL:["actionscript","javascript","handlebars"]}},c,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:/[^ \/><\n\t]+/,r:0},e]}]}}); -------------------------------------------------------------------------------- /src/lib/rhill-voronoi-core.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Copyright (C) 2010-2013 Raymond Hill: https://github.com/gorhill/Javascript-Voronoi 3 | MIT License: See https://github.com/gorhill/Javascript-Voronoi/LICENSE.md 4 | */ 5 | ; 6 | function Voronoi(){this.vertices=null;this.edges=null;this.cells=null;this.toRecycle=null;this.beachsectionJunkyard=[];this.circleEventJunkyard=[]; 7 | this.vertexJunkyard=[];this.edgeJunkyard=[];this.cellJunkyard=[]}Voronoi.prototype.reset=function(){if(!this.beachline){this.beachline=new this.RBTree() 8 | }if(this.beachline.root){var a=this.beachline.getFirst(this.beachline.root);while(a){this.beachsectionJunkyard.push(a);a=a.rbNext 9 | }}this.beachline.root=null;if(!this.circleEvents){this.circleEvents=new this.RBTree()}this.circleEvents.root=this.firstCircleEvent=null; 10 | this.vertices=[];this.edges=[];this.cells=[]};Voronoi.prototype.sqrt=Math.sqrt;Voronoi.prototype.abs=Math.abs;Voronoi.prototype.ε=Voronoi.ε=1e-9; 11 | Voronoi.prototype.invε=Voronoi.invε=1/Voronoi.ε;Voronoi.prototype.equalWithEpsilon=function(d,c){return this.abs(d-c)<1e-9 12 | };Voronoi.prototype.greaterThanWithEpsilon=function(d,c){return d-c>1e-9};Voronoi.prototype.greaterThanOrEqualWithEpsilon=function(d,c){return c-d<1e-9 13 | };Voronoi.prototype.lessThanWithEpsilon=function(d,c){return c-d>1e-9};Voronoi.prototype.lessThanOrEqualWithEpsilon=function(d,c){return d-c<1e-9 14 | };Voronoi.prototype.RBTree=function(){this.root=null};Voronoi.prototype.RBTree.prototype.rbInsertSuccessor=function(e,a){var d; 15 | if(e){a.rbPrevious=e;a.rbNext=e.rbNext;if(e.rbNext){e.rbNext.rbPrevious=a}e.rbNext=a;if(e.rbRight){e=e.rbRight;while(e.rbLeft){e=e.rbLeft 16 | }e.rbLeft=a}else{e.rbRight=a}d=e}else{if(this.root){e=this.getFirst(this.root);a.rbPrevious=null;a.rbNext=e;e.rbPrevious=a; 17 | e.rbLeft=a;d=e}else{a.rbPrevious=a.rbNext=null;this.root=a;d=null}}a.rbLeft=a.rbRight=null;a.rbParent=d;a.rbRed=true;var c,b; 18 | e=a;while(d&&d.rbRed){c=d.rbParent;if(d===c.rbLeft){b=c.rbRight;if(b&&b.rbRed){d.rbRed=b.rbRed=false;c.rbRed=true;e=c}else{if(e===d.rbRight){this.rbRotateLeft(d); 19 | e=d;d=e.rbParent}d.rbRed=false;c.rbRed=true;this.rbRotateRight(c)}}else{b=c.rbLeft;if(b&&b.rbRed){d.rbRed=b.rbRed=false;c.rbRed=true; 20 | e=c}else{if(e===d.rbLeft){this.rbRotateRight(d);e=d;d=e.rbParent}d.rbRed=false;c.rbRed=true;this.rbRotateLeft(c)}}d=e.rbParent 21 | }this.root.rbRed=false};Voronoi.prototype.RBTree.prototype.rbRemoveNode=function(f){if(f.rbNext){f.rbNext.rbPrevious=f.rbPrevious 22 | }if(f.rbPrevious){f.rbPrevious.rbNext=f.rbNext}f.rbNext=f.rbPrevious=null;var e=f.rbParent,g=f.rbLeft,b=f.rbRight,d;if(!g){d=b 23 | }else{if(!b){d=g}else{d=this.getFirst(b)}}if(e){if(e.rbLeft===f){e.rbLeft=d}else{e.rbRight=d}}else{this.root=d}var a;if(g&&b){a=d.rbRed; 24 | d.rbRed=f.rbRed;d.rbLeft=g;g.rbParent=d;if(d!==b){e=d.rbParent;d.rbParent=f.rbParent;f=d.rbRight;e.rbLeft=f;d.rbRight=b;b.rbParent=d 25 | }else{d.rbParent=e;e=d;f=d.rbRight}}else{a=f.rbRed;f=d}if(f){f.rbParent=e}if(a){return}if(f&&f.rbRed){f.rbRed=false;return 26 | }var c;do{if(f===this.root){break}if(f===e.rbLeft){c=e.rbRight;if(c.rbRed){c.rbRed=false;e.rbRed=true;this.rbRotateLeft(e); 27 | c=e.rbRight}if((c.rbLeft&&c.rbLeft.rbRed)||(c.rbRight&&c.rbRight.rbRed)){if(!c.rbRight||!c.rbRight.rbRed){c.rbLeft.rbRed=false; 28 | c.rbRed=true;this.rbRotateRight(c);c=e.rbRight}c.rbRed=e.rbRed;e.rbRed=c.rbRight.rbRed=false;this.rbRotateLeft(e);f=this.root; 29 | break}}else{c=e.rbLeft;if(c.rbRed){c.rbRed=false;e.rbRed=true;this.rbRotateRight(e);c=e.rbLeft}if((c.rbLeft&&c.rbLeft.rbRed)||(c.rbRight&&c.rbRight.rbRed)){if(!c.rbLeft||!c.rbLeft.rbRed){c.rbRight.rbRed=false; 30 | c.rbRed=true;this.rbRotateLeft(c);c=e.rbLeft}c.rbRed=e.rbRed;e.rbRed=c.rbLeft.rbRed=false;this.rbRotateRight(e);f=this.root; 31 | break}}c.rbRed=true;f=e;e=e.rbParent}while(!f.rbRed);if(f){f.rbRed=false}};Voronoi.prototype.RBTree.prototype.rbRotateLeft=function(b){var d=b,c=b.rbRight,a=d.rbParent; 32 | if(a){if(a.rbLeft===d){a.rbLeft=c}else{a.rbRight=c}}else{this.root=c}c.rbParent=a;d.rbParent=c;d.rbRight=c.rbLeft;if(d.rbRight){d.rbRight.rbParent=d 33 | }c.rbLeft=d};Voronoi.prototype.RBTree.prototype.rbRotateRight=function(b){var d=b,c=b.rbLeft,a=d.rbParent;if(a){if(a.rbLeft===d){a.rbLeft=c 34 | }else{a.rbRight=c}}else{this.root=c}c.rbParent=a;d.rbParent=c;d.rbLeft=c.rbRight;if(d.rbLeft){d.rbLeft.rbParent=d}c.rbRight=d 35 | };Voronoi.prototype.RBTree.prototype.getFirst=function(a){while(a.rbLeft){a=a.rbLeft}return a};Voronoi.prototype.RBTree.prototype.getLast=function(a){while(a.rbRight){a=a.rbRight 36 | }return a};Voronoi.prototype.Diagram=function(a){this.site=a};Voronoi.prototype.Cell=function(a){this.site=a;this.halfedges=[]; 37 | this.closeMe=false};Voronoi.prototype.Cell.prototype.init=function(a){this.site=a;this.halfedges=[];this.closeMe=false;return this 38 | };Voronoi.prototype.createCell=function(b){var a=this.cellJunkyard.pop();if(a){return a.init(b)}return new this.Cell(b)}; 39 | Voronoi.prototype.Cell.prototype.prepareHalfedges=function(){var a=this.halfedges,b=a.length,c;while(b--){c=a[b].edge;if(!c.vb||!c.va){a.splice(b,1) 40 | }}a.sort(function(e,d){return d.angle-e.angle});return a.length};Voronoi.prototype.Cell.prototype.getNeighborIds=function(){var a=[],b=this.halfedges.length,c; 41 | while(b--){c=this.halfedges[b].edge;if(c.lSite!==null&&c.lSite.voronoiId!=this.site.voronoiId){a.push(c.lSite.voronoiId)}else{if(c.rSite!==null&&c.rSite.voronoiId!=this.site.voronoiId){a.push(c.rSite.voronoiId) 42 | }}}return a};Voronoi.prototype.Cell.prototype.getBbox=function(){var i=this.halfedges,d=i.length,a=Infinity,g=Infinity,c=-Infinity,b=-Infinity,h,f,e; 43 | while(d--){h=i[d].getStartpoint();f=h.x;e=h.y;if(fc){c=f}if(e>b){b=e}}return{x:a,y:g,width:c-a,height:b-g} 44 | };Voronoi.prototype.Cell.prototype.pointIntersection=function(a,h){var b=this.halfedges,c=b.length,f,g,e,d;while(c--){f=b[c]; 45 | g=f.getStartpoint();e=f.getEndpoint();d=(h-g.y)*(e.x-g.x)-(a-g.x)*(e.y-g.y);if(!d){return 0}if(d>0){return -1}}return 1}; 46 | Voronoi.prototype.Vertex=function(a,b){this.x=a;this.y=b};Voronoi.prototype.Edge=function(b,a){this.lSite=b;this.rSite=a; 47 | this.va=this.vb=null};Voronoi.prototype.Halfedge=function(d,e,a){this.site=e;this.edge=d;if(a){this.angle=Math.atan2(a.y-e.y,a.x-e.x) 48 | }else{var c=d.va,b=d.vb;this.angle=d.lSite===e?Math.atan2(b.x-c.x,c.y-b.y):Math.atan2(c.x-b.x,b.y-c.y)}};Voronoi.prototype.createHalfedge=function(b,c,a){return new this.Halfedge(b,c,a) 49 | };Voronoi.prototype.Halfedge.prototype.getStartpoint=function(){return this.edge.lSite===this.site?this.edge.va:this.edge.vb 50 | };Voronoi.prototype.Halfedge.prototype.getEndpoint=function(){return this.edge.lSite===this.site?this.edge.vb:this.edge.va 51 | };Voronoi.prototype.createVertex=function(a,c){var b=this.vertexJunkyard.pop();if(!b){b=new this.Vertex(a,c)}else{b.x=a;b.y=c 52 | }this.vertices.push(b);return b};Voronoi.prototype.createEdge=function(e,a,d,b){var c=this.edgeJunkyard.pop();if(!c){c=new this.Edge(e,a) 53 | }else{c.lSite=e;c.rSite=a;c.va=c.vb=null}this.edges.push(c);if(d){this.setEdgeStartpoint(c,e,a,d)}if(b){this.setEdgeEndpoint(c,e,a,b) 54 | }this.cells[e.voronoiId].halfedges.push(this.createHalfedge(c,e,a));this.cells[a.voronoiId].halfedges.push(this.createHalfedge(c,a,e)); 55 | return c};Voronoi.prototype.createBorderEdge=function(d,c,a){var b=this.edgeJunkyard.pop();if(!b){b=new this.Edge(d,null) 56 | }else{b.lSite=d;b.rSite=null}b.va=c;b.vb=a;this.edges.push(b);return b};Voronoi.prototype.setEdgeStartpoint=function(b,d,a,c){if(!b.va&&!b.vb){b.va=c; 57 | b.lSite=d;b.rSite=a}else{if(b.lSite===a){b.vb=c}else{b.va=c}}};Voronoi.prototype.setEdgeEndpoint=function(b,d,a,c){this.setEdgeStartpoint(b,a,d,c) 58 | };Voronoi.prototype.Beachsection=function(){};Voronoi.prototype.createBeachsection=function(a){var b=this.beachsectionJunkyard.pop(); 59 | if(!b){b=new this.Beachsection()}b.site=a;return b};Voronoi.prototype.leftBreakPoint=function(e,f){var a=e.site,m=a.x,l=a.y,k=l-f; 60 | if(!k){return m}var n=e.rbPrevious;if(!n){return -Infinity}a=n.site;var h=a.x,g=a.y,d=g-f;if(!d){return h}var c=h-m,j=1/k-1/d,i=c/d; 61 | if(j){return(-i+this.sqrt(i*i-2*j*(c*c/(-2*d)-g+d/2+l-k/2)))/j+m}return(m+h)/2};Voronoi.prototype.rightBreakPoint=function(b,c){var d=b.rbNext; 62 | if(d){return this.leftBreakPoint(d,c)}var a=b.site;return a.y===c?a.x:Infinity};Voronoi.prototype.detachBeachsection=function(a){this.detachCircleEvent(a); 63 | this.beachline.rbRemoveNode(a);this.beachsectionJunkyard.push(a)};Voronoi.prototype.removeBeachsection=function(b){var a=b.circleEvent,j=a.x,h=a.ycenter,e=this.createVertex(j,h),f=b.rbPrevious,d=b.rbNext,l=[b],g=Math.abs; 64 | this.detachBeachsection(b);var m=f;while(m.circleEvent&&g(j-m.circleEvent.x)<1e-9&&g(h-m.circleEvent.ycenter)<1e-9){f=m.rbPrevious; 65 | l.unshift(m);this.detachBeachsection(m);m=f}l.unshift(m);this.detachCircleEvent(m);var c=d;while(c.circleEvent&&g(j-c.circleEvent.x)<1e-9&&g(h-c.circleEvent.ycenter)<1e-9){d=c.rbNext; 66 | l.push(c);this.detachBeachsection(c);c=d}l.push(c);this.detachCircleEvent(c);var k=l.length,i;for(i=1;i1e-9){o=o.rbLeft}else{q=j-this.rightBreakPoint(o,n);if(q>1e-9){if(!o.rbRight){p=o; 70 | break}o=o.rbRight}else{if(v>-1e-9){p=o.rbPrevious;m=o}else{if(q>-1e-9){p=o;m=o.rbNext}else{p=m=o}}break}}}var e=this.createBeachsection(l); 71 | this.beachline.rbInsertSuccessor(p,e);if(!p&&!m){return}if(p===m){this.detachCircleEvent(p);m=this.createBeachsection(p.site); 72 | this.beachline.rbInsertSuccessor(e,m);e.edge=m.edge=this.createEdge(p.site,e.site);this.attachCircleEvent(p);this.attachCircleEvent(m); 73 | return}if(p&&!m){e.edge=this.createEdge(p.site,e.site);return}if(p!==m){this.detachCircleEvent(p);this.detachCircleEvent(m); 74 | var h=p.site,k=h.x,i=h.y,t=l.x-k,r=l.y-i,a=m.site,c=a.x-k,b=a.y-i,u=2*(t*b-r*c),g=t*t+r*r,f=c*c+b*b,s=this.createVertex((b*g-r*f)/u+k,(t*f-c*g)/u+i); 75 | this.setEdgeStartpoint(m.edge,h,a,s);e.edge=this.createEdge(h,l,undefined,s);m.edge=this.createEdge(l,a,undefined,s);this.attachCircleEvent(p); 76 | this.attachCircleEvent(m);return}};Voronoi.prototype.CircleEvent=function(){this.arc=null;this.rbLeft=null;this.rbNext=null; 77 | this.rbParent=null;this.rbPrevious=null;this.rbRed=false;this.rbRight=null;this.site=null;this.x=this.y=this.ycenter=0};Voronoi.prototype.attachCircleEvent=function(i){var r=i.rbPrevious,o=i.rbNext; 78 | if(!r||!o){return}var k=r.site,u=i.site,c=o.site;if(k===c){return}var t=u.x,s=u.y,n=k.x-t,l=k.y-s,f=c.x-t,e=c.y-s;var v=2*(n*e-l*f); 79 | if(v>=-2e-12){return}var h=n*n+l*l,g=f*f+e*e,m=(e*h-l*g)/v,j=(n*g-f*h)/v,b=j+s;var q=this.circleEventJunkyard.pop();if(!q){q=new this.CircleEvent() 80 | }q.arc=i;q.site=u;q.x=m+t;q.y=b+this.sqrt(m*m+j*j);q.ycenter=b;i.circleEvent=q;var a=null,p=this.circleEvents.root;while(p){if(q.y=n){return false 86 | }if(i>k){if(!c||c.y=d){return false}}b=this.createVertex(g,d)}else{if(!c||c.y>d){c=this.createVertex(g,d) 87 | }else{if(c.y1){if(i>k){if(!c||c.y=d){return false}}b=this.createVertex((d-q)/m,d)}else{if(!c||c.y>d){c=this.createVertex((d-q)/m,d)}else{if(c.y=n){return false}}b=this.createVertex(n,m*n+q) 90 | }else{if(!c||c.x>n){c=this.createVertex(n,m*n+q)}else{if(c.x0){if(a>e){return false}if(a>f){f=a 93 | }}}c=i.xr-b;if(k===0&&c<0){return false}a=c/k;if(k<0){if(a>e){return false}if(a>f){f=a}}else{if(k>0){if(a0){if(a>e){return false 95 | }if(a>f){f=a}}}c=i.yb-l;if(j===0&&c<0){return false}a=c/j;if(j<0){if(a>e){return false}if(a>f){f=a}}else{if(j>0){if(a0){d.va=this.createVertex(b+f*k,l+f*j)}if(e<1){d.vb=this.createVertex(b+e*k,l+e*j)}if(f>0||e<1){this.cells[d.lSite.voronoiId].closeMe=true; 97 | this.cells[d.rSite.voronoiId].closeMe=true}return true};Voronoi.prototype.clipEdges=function(e){var a=this.edges,d=a.length,c,b=Math.abs; 98 | while(d--){c=a[d];if(!this.connectEdge(c,e)||!this.clipEdge(c,e)||(b(c.va.x-c.vb.x)<1e-9&&b(c.va.y-c.vb.y)<1e-9)){c.va=c.vb=null; 99 | a.splice(d,1)}}};Voronoi.prototype.closeCells=function(p){var g=p.xl,d=p.xr,m=p.yt,j=p.yb,q=this.cells,a=q.length,n,e,o,c,b,l,k,i,f,h=Math.abs; 100 | while(a--){n=q[a];if(!n.prepareHalfedges()){continue}if(!n.closeMe){continue}o=n.halfedges;c=o.length;e=0;while(e=1e-9||h(l.y-i.y)>=1e-9){switch(true){case this.equalWithEpsilon(l.x,g)&&this.lessThanWithEpsilon(l.y,j):f=this.equalWithEpsilon(i.x,g); 102 | k=this.createVertex(g,f?i.y:j);b=this.createBorderEdge(n.site,l,k);e++;o.splice(e,0,this.createHalfedge(b,n.site,null));c++; 103 | if(f){break}l=k;case this.equalWithEpsilon(l.y,j)&&this.lessThanWithEpsilon(l.x,d):f=this.equalWithEpsilon(i.y,j);k=this.createVertex(f?i.x:d,j); 104 | b=this.createBorderEdge(n.site,l,k);e++;o.splice(e,0,this.createHalfedge(b,n.site,null));c++;if(f){break}l=k;case this.equalWithEpsilon(l.x,d)&&this.greaterThanWithEpsilon(l.y,m):f=this.equalWithEpsilon(i.x,d); 105 | k=this.createVertex(d,f?i.y:m);b=this.createBorderEdge(n.site,l,k);e++;o.splice(e,0,this.createHalfedge(b,n.site,null));c++; 106 | if(f){break}l=k;case this.equalWithEpsilon(l.y,m)&&this.greaterThanWithEpsilon(l.x,g):f=this.equalWithEpsilon(i.y,m);k=this.createVertex(f?i.x:g,m); 107 | b=this.createBorderEdge(n.site,l,k);e++;o.splice(e,0,this.createHalfedge(b,n.site,null));c++;if(f){break}l=k;f=this.equalWithEpsilon(i.x,g); 108 | k=this.createVertex(g,f?i.y:j);b=this.createBorderEdge(n.site,l,k);e++;o.splice(e,0,this.createHalfedge(b,n.site,null));c++; 109 | if(f){break}l=k;f=this.equalWithEpsilon(i.y,j);k=this.createVertex(f?i.x:d,j);b=this.createBorderEdge(n.site,l,k);e++;o.splice(e,0,this.createHalfedge(b,n.site,null)); 110 | c++;if(f){break}l=k;f=this.equalWithEpsilon(i.x,d);k=this.createVertex(d,f?i.y:m);b=this.createBorderEdge(n.site,l,k);e++; 111 | o.splice(e,0,this.createHalfedge(b,n.site,null));c++;if(f){break}default:throw"Voronoi.closeCells() > this makes no sense!" 112 | }}e++}n.closeMe=false}};Voronoi.prototype.quantizeSites=function(c){var b=this.ε,d=c.length,a;while(d--){a=c[d];a.x=Math.floor(a.x/b)*b; 113 | a.y=Math.floor(a.y/b)*b}};Voronoi.prototype.recycle=function(a){if(a){if(a instanceof this.Diagram){this.toRecycle=a}else{throw"Voronoi.recycleDiagram() > Need a Diagram object." 114 | }}};Voronoi.prototype.compute=function(i,j){var d=new Date();this.reset();if(this.toRecycle){this.vertexJunkyard=this.vertexJunkyard.concat(this.toRecycle.vertices); 115 | this.edgeJunkyard=this.edgeJunkyard.concat(this.toRecycle.edges);this.cellJunkyard=this.cellJunkyard.concat(this.toRecycle.cells); 116 | this.toRecycle=null}var h=i.slice(0);h.sort(function(n,m){var o=m.y-n.y;if(o){return o}return m.x-n.x});var b=h.pop(),l=0,f,e,k=this.cells,a; 117 | for(;;){a=this.firstCircleEvent;if(b&&(!a||b.y this.config.width) { 126 | x = (y % 2 == 1 || this.config.sitesDistribution == 'square' ? 0 : 0.5); 127 | y = y + 1; 128 | } 129 | } 130 | } 131 | this.compute(sites); 132 | for (var i = 0; i < this.config.nbGraphRelaxation; i++) { 133 | this.relaxSites(); 134 | } 135 | }; 136 | 137 | isl.compute = function (sites) { 138 | this.sites = sites; 139 | this.voronoi.recycle(this.diagram); 140 | this.bbox = {xl: 0, xr: this.config.width, yt: 0, yb: this.config.height}; 141 | this.diagram = this.voronoi.compute(sites, this.bbox); 142 | }; 143 | 144 | isl.relaxSites = function () { 145 | var rnd = this.getRandomGenerator(this.config.seed); 146 | if (!this.diagram) { 147 | return; 148 | } 149 | var cells = this.diagram.cells, 150 | iCell = cells.length, 151 | cell, 152 | site, sites = [], 153 | rn, dist; 154 | var p = 1 / iCell * 0.1; 155 | while (iCell--) { 156 | cell = cells[iCell]; 157 | rn = rnd.frac(); 158 | // probability of apoptosis 159 | if (rn < p) { 160 | continue; 161 | } 162 | site = this.cellCentroid(cell); 163 | dist = this.distance(site, cell.site); 164 | // don't relax too fast 165 | if (dist > 2) { 166 | site.x = (site.x + cell.site.x) / 2; 167 | site.y = (site.y + cell.site.y) / 2; 168 | } 169 | // probability of mytosis 170 | if (rn > (1 - p)) { 171 | dist /= 2; 172 | sites.push({ 173 | x: site.x + (site.x - cell.site.x) / dist, 174 | y: site.y + (site.y - cell.site.y) / dist 175 | }); 176 | } 177 | sites.push(site); 178 | } 179 | this.compute(sites); 180 | }; 181 | 182 | isl.cellArea = function (cell) { 183 | var area = 0, 184 | halfedges = cell.halfedges, 185 | iHalfedge = halfedges.length, 186 | halfedge, 187 | p1, p2; 188 | while (iHalfedge--) { 189 | halfedge = halfedges[iHalfedge]; 190 | p1 = halfedge.getStartpoint(); 191 | p2 = halfedge.getEndpoint(); 192 | area += p1.x * p2.y; 193 | area -= p1.y * p2.x; 194 | } 195 | area /= 2; 196 | return area; 197 | }; 198 | 199 | isl.cellCentroid = function (cell) { 200 | var x = 0, 201 | y = 0, 202 | halfedges = cell.halfedges, 203 | iHalfedge = halfedges.length, 204 | halfedge, 205 | v, p1, p2; 206 | while (iHalfedge--) { 207 | halfedge = halfedges[iHalfedge]; 208 | p1 = halfedge.getStartpoint(); 209 | p2 = halfedge.getEndpoint(); 210 | v = p1.x * p2.y - p2.x * p1.y; 211 | x += (p1.x + p2.x) * v; 212 | y += (p1.y + p2.y) * v; 213 | } 214 | v = this.cellArea(cell) * 6; 215 | return { 216 | x: x / v, 217 | y: y / v 218 | }; 219 | }; 220 | 221 | isl.assignOceanCoastAndLand = function() { 222 | // water 223 | var queue = new Array(); 224 | for (var i = 0; i < this.diagram.cells.length; i++) { 225 | var cell = this.diagram.cells[i]; 226 | cell.elevation = this.getElevation(cell.site); 227 | cell.water = (cell.elevation <= 0); 228 | for (var j = 0; j < cell.halfedges.length; j++) { 229 | var hedge = cell.halfedges[j]; 230 | // border 231 | if (hedge.edge.rSite == null) { 232 | cell.border = true; 233 | cell.ocean = true; 234 | cell.water = true; 235 | if (cell.elevation > 0) { 236 | cell.elevation = 0; 237 | } 238 | queue.push(cell); 239 | } 240 | } 241 | } 242 | 243 | // ocean 244 | while (queue.length > 0) { 245 | cell = queue.shift(); 246 | var neighbors = cell.getNeighborIds(); 247 | for (var i = 0; i < neighbors.length; i++) { 248 | var nId = neighbors[i]; 249 | var neighbor = this.diagram.cells[nId]; 250 | if (neighbor.water && !neighbor.ocean) { 251 | neighbor.ocean = true; 252 | queue.push(neighbor); 253 | } 254 | } 255 | } 256 | 257 | // coast 258 | for (var i = 0; i < this.diagram.cells.length; i++) { 259 | cell = this.diagram.cells[i]; 260 | var numOcean = 0; 261 | neighbors = cell.getNeighborIds(); 262 | for (var j = 0; j < neighbors.length; j++) { 263 | nId = neighbors[j]; 264 | neighbor = this.diagram.cells[nId]; 265 | if (neighbor.ocean) { 266 | numOcean++; 267 | } 268 | } 269 | cell.coast = (numOcean > 0) && (!cell.water); 270 | cell.beach = (cell.coast && cell.elevation < this.config.cliffsThreshold); 271 | } 272 | 273 | // cliff 274 | for (var i = 0; i < this.diagram.edges.length; i++) { 275 | var edge = this.diagram.edges[i]; 276 | if (edge.lSite != null && edge.rSite != null) { 277 | var lCell = this.diagram.cells[edge.lSite.voronoiId]; 278 | var rCell = this.diagram.cells[edge.rSite.voronoiId]; 279 | edge.cliff = (!(lCell.water && rCell.water) && (Math.abs(this.getRealElevation(lCell) - this.getRealElevation(rCell)) >= this.config.cliffsThreshold)); 280 | } 281 | } 282 | }; 283 | 284 | isl.assignRivers = function() { 285 | var rnd = this.getRandomGenerator(this.config.seed); 286 | for (var i = 0; i < this.config.nbRivers;) { 287 | var cell = this.diagram.cells[rnd.integerInRange(0, this.diagram.cells.length - 1)]; 288 | if (!cell.coast) { 289 | if (this.setAsRiver(cell, 1)) { 290 | cell.source = true; 291 | i++; 292 | } 293 | } 294 | } 295 | }; 296 | 297 | isl.setAsRiver = function(cell, size) { 298 | if (!cell.water && !cell.river) { 299 | cell.river = true; 300 | cell.riverSize = size; 301 | var lowerCell = null; 302 | var neighbors = cell.getNeighborIds(); 303 | // we choose the lowest neighbour cell : 304 | for (var j = 0; j < neighbors.length; j++) { 305 | var nId = neighbors[j]; 306 | var neighbor = this.diagram.cells[nId]; 307 | if (lowerCell == null || neighbor.elevation < lowerCell.elevation) { 308 | lowerCell = neighbor; 309 | } 310 | } 311 | if (lowerCell.elevation < cell.elevation) { 312 | // we continue the river to the next lowest cell : 313 | this.setAsRiver(lowerCell, size); 314 | cell.nextRiver = lowerCell; 315 | } else { 316 | // we are in a hole, so we create a lake : 317 | cell.water = true; 318 | this.fillLake(cell); 319 | } 320 | } else if (cell.water && !cell.ocean) { 321 | // we ended in a lake, the water level rise : 322 | cell.lakeElevation = this.getRealElevation(cell) + (this.config.lakesThreshold * size); 323 | this.fillLake(cell); 324 | } else if (cell.river) { 325 | // we ended in another river, the river size increase : 326 | cell.riverSize ++; 327 | var nextRiver = cell.nextRiver; 328 | while (nextRiver) { 329 | nextRiver.riverSize ++; 330 | nextRiver = nextRiver.nextRiver; 331 | } 332 | } 333 | 334 | return cell.river; 335 | }; 336 | 337 | isl.fillLake = function(cell) { 338 | // if the lake has an exit river he can not longer be filled 339 | if (cell.exitRiver == null) { 340 | var exitRiver = null; 341 | var exitSource = null; 342 | var lake = new Array(); 343 | var queue = new Array(); 344 | queue.push(cell); 345 | 346 | while (queue.length > 0) { 347 | var c = queue.shift(); 348 | lake.push(c); 349 | var neighbors = c.getNeighborIds(); 350 | for (var i = 0; i < neighbors.length; i++) { 351 | var nId = neighbors[i]; 352 | var neighbor = this.diagram.cells[nId]; 353 | 354 | if (neighbor.water && !neighbor.ocean) { // water cell from the same lake 355 | if (neighbor.lakeElevation == null || neighbor.lakeElevation < c.lakeElevation) { 356 | neighbor.lakeElevation = c.lakeElevation; 357 | queue.push(neighbor); 358 | } 359 | } else { // ground cell adjacent to the lake 360 | if (c.elevation < neighbor.elevation) { 361 | if (neighbor.elevation - c.lakeElevation < 0) { 362 | // we fill the ground with water 363 | neighbor.water = true; 364 | neighbor.lakeElevation = c.lakeElevation; 365 | queue.push(neighbor); 366 | } 367 | } else { 368 | //neighbor.source = true; 369 | // we found an new exit for the lake : 370 | if (exitRiver == null || exitRiver.elevation > neighbor.elevation) { 371 | exitSource = c; 372 | exitRiver = neighbor; 373 | } 374 | } 375 | } 376 | } 377 | } 378 | 379 | if (exitRiver != null) { 380 | // we start the exit river : 381 | exitSource.river = true; 382 | exitSource.nextRiver = exitRiver; 383 | this.setAsRiver(exitRiver, 2); 384 | // we mark all the lake as having an exit river : 385 | while (lake.length > 0) { 386 | c = lake.shift(); 387 | c.exitRiver = exitRiver; 388 | } 389 | } 390 | } 391 | }; 392 | 393 | // Calculate moisture. Freshwater sources spread moisture: rivers and lakes (not ocean). 394 | isl.assignMoisture = function() { 395 | var queue = new Array(); 396 | // lake and river 397 | for (var i = 0; i < this.diagram.cells.length; i++) { 398 | var cell = this.diagram.cells[i]; 399 | if ((cell.water || cell.river) && !cell.ocean) { 400 | cell.moisture = (cell.water ? 1 : 0.9); 401 | if (!cell.ocean) { 402 | queue.push(cell); 403 | } 404 | } 405 | } 406 | 407 | while (queue.length > 0) { 408 | cell = queue.shift(); 409 | var neighbors = cell.getNeighborIds(); 410 | for (var i = 0; i < neighbors.length; i++) { 411 | var nId = neighbors[i]; 412 | var neighbor = this.diagram.cells[nId]; 413 | var newMoisture = cell.moisture * 0.9; 414 | if (neighbor.moisture == null || newMoisture > neighbor.moisture) { 415 | neighbor.moisture = newMoisture; 416 | queue.push(neighbor); 417 | } 418 | } 419 | } 420 | 421 | // ocean 422 | for (var i = 0; i < this.diagram.cells.length; i++) { 423 | cell = this.diagram.cells[i]; 424 | if (cell.ocean) { 425 | cell.moisture = 1; 426 | } 427 | } 428 | }; 429 | 430 | isl.assignBiomes = function() { 431 | for (var i = 0; i < this.diagram.cells.length; i++) { 432 | var cell = this.diagram.cells[i]; 433 | cell.biome = this.getBiome(cell); 434 | } 435 | }; 436 | 437 | isl.getBiome = function (cell) { 438 | if (cell.ocean) { 439 | return 'OCEAN'; 440 | } else if (cell.water) { 441 | if (this.getRealElevation(cell) < 0.05) return 'MARSH'; 442 | if (this.getRealElevation(cell) > 0.4) return 'ICE'; 443 | return 'LAKE'; 444 | } else if (cell.beach) { 445 | return 'BEACH'; 446 | } else if (cell.elevation > 0.4) { 447 | if (cell.moisture > 0.50) return 'SNOW'; 448 | else if (cell.moisture > 0.33) return 'TUNDRA'; 449 | else if (cell.moisture > 0.16) return 'BARE'; 450 | else return 'SCORCHED'; 451 | } else if (cell.elevation > 0.3) { 452 | if (cell.moisture > 0.66) return 'TAIGA'; 453 | else if (cell.moisture > 0.33) return 'SHRUBLAND'; 454 | else return 'TEMPERATE_DESERT'; 455 | } else if (cell.elevation > 0.15) { 456 | if (cell.moisture > 0.83) return 'TEMPERATE_RAIN_FOREST'; 457 | else if (cell.moisture > 0.50) return 'TEMPERATE_DECIDUOUS_FOREST'; 458 | else if (cell.moisture > 0.16) return 'GRASSLAND'; 459 | else return 'TEMPERATE_DESERT'; 460 | } else { 461 | if (cell.moisture > 0.66) return 'TROPICAL_RAIN_FOREST'; 462 | else if (cell.moisture > 0.33) return 'TROPICAL_SEASONAL_FOREST'; 463 | else if (cell.moisture > 0.16) return 'GRASSLAND'; 464 | else return 'SUBTROPICAL_DESERT'; 465 | } 466 | }; 467 | 468 | // The Perlin-based island combines perlin noise with the radius 469 | isl.getElevation = function (point) { 470 | var x = 2 * (point.x / this.config.width - 0.5); 471 | var y = 2 * (point.y / this.config.height - 0.5); 472 | var distance = Math.sqrt(x * x + y * y); 473 | var c = this.getPerlinValue(point); 474 | 475 | return c - distance; 476 | //return c - (0.3 + 0.3 * distance * distance); 477 | }; 478 | 479 | isl.getPerlinValue = function(point) { 480 | var x = ((point.x / this.config.width) * this.perlin.width) | 0; 481 | var y = ((point.y / this.config.height) * this.perlin.height) | 0; 482 | var pos = (x + y * this.perlin.width) * 4; 483 | var data = this.perlin.data; 484 | var val = data[pos + 0] << 16 | data[pos + 1] << 8 | data[pos + 2]; // rgb to hex 485 | 486 | return (val & 0xff) / 255.0; 487 | }; 488 | 489 | isl.getRealElevation = function(cell) { 490 | if (cell.water && cell.lakeElevation != null) { 491 | return cell.lakeElevation; 492 | } else if (cell.water && cell.elevation < 0) { 493 | return 0; 494 | } else { 495 | return cell.elevation; 496 | } 497 | }; 498 | 499 | isl.renderNow = function () { 500 | if (!this.diagram) { 501 | return; 502 | } 503 | 504 | this.renderCells(); 505 | this.renderRivers(); 506 | 507 | if (this.config.allowDebug) { 508 | this.renderEdges(); 509 | this.renderSites(); 510 | this.debugLayer.sprite = this.game.add.sprite(0, 0, this.debugLayer); 511 | } 512 | 513 | }; 514 | 515 | isl.renderCells = function() { 516 | var ctx = this.cellsLayer.ctx; 517 | 518 | for (var cellid in this.diagram.cells) { 519 | var cell = this.diagram.cells[cellid]; 520 | var color = this.pgetCellColor(cell); 521 | 522 | ctx.lineWidth = 1; 523 | ctx.strokeStyle = color; 524 | ctx.fillStyle = color; 525 | var start = cell.halfedges[0].getStartpoint(); 526 | ctx.beginPath(); 527 | ctx.moveTo(start.x, start.y); 528 | for (var iHalfedge = 0; iHalfedge < cell.halfedges.length; iHalfedge++) { 529 | var halfEdge = cell.halfedges[iHalfedge]; 530 | var end = halfEdge.getEndpoint(); 531 | ctx.lineTo(end.x, end.y); 532 | } 533 | ctx.closePath(); 534 | ctx.stroke(); 535 | ctx.fill(); 536 | } 537 | this.cellsLayer.sprite = this.game.add.sprite(0, 0, this.cellsLayer); 538 | }; 539 | 540 | isl.renderRivers = function() { 541 | // TODO: river made from arcs 542 | var ctx = this.riversLayer.ctx, 543 | riverColor = Phaser.Color.hexToColor(this.DISPLAY_COLORS.RIVER); 544 | if (this.config.allowDebug) { 545 | var ctx2 = this.debugLayer.ctx, 546 | sourceColor = this.DISPLAY_COLORS.SOURCE; 547 | } 548 | for (var cellid in this.diagram.cells) { 549 | var cell = this.diagram.cells[cellid]; 550 | if (cell.nextRiver) { 551 | ctx.beginPath(); 552 | ctx.lineWidth = Math.min(cell.riverSize, this.config.maxRiversSize); 553 | var shade = parseInt(this.getShade(cell)*120, 10); 554 | ctx.strokeStyle = Phaser.Color.RGBtoString(riverColor.r-shade, riverColor.g-shade, riverColor.b-shade, riverColor.a, '#'); 555 | if (cell.water) { 556 | ctx.moveTo(cell.site.x + (cell.nextRiver.site.x - cell.site.x) / 2, cell.site.y + (cell.nextRiver.site.y - cell.site.y) / 2); 557 | } else { 558 | ctx.moveTo(cell.site.x, cell.site.y); 559 | } 560 | if (cell.nextRiver && !cell.nextRiver.water) { 561 | ctx.lineTo(cell.nextRiver.site.x, cell.nextRiver.site.y); 562 | } else { 563 | ctx.lineTo(cell.site.x + (cell.nextRiver.site.x - cell.site.x) / 2, cell.site.y + (cell.nextRiver.site.y - cell.site.y) / 2); 564 | } 565 | ctx.stroke(); 566 | } 567 | 568 | // source : 569 | if (this.config.allowDebug && cell.source) { 570 | ctx2.beginPath(); 571 | ctx2.fillStyle = sourceColor; 572 | ctx2.arc(cell.site.x,cell.site.y,3,0,2*Math.PI); 573 | ctx2.fill(); 574 | } 575 | } 576 | this.riversLayer.sprite = this.game.add.sprite(0, 0, this.riversLayer); 577 | }; 578 | 579 | isl.renderEdges = function() { 580 | var ctx = this.debugLayer.ctx, 581 | edges = this.diagram.edges, 582 | iEdge = edges.length, 583 | edge, v; 584 | while (iEdge--) { 585 | edge = edges[iEdge]; 586 | ctx.beginPath(); 587 | 588 | if (edge.cliff) { 589 | ctx.lineWidth = 3; 590 | ctx.lineCap = 'round'; 591 | ctx.strokeStyle = this.DISPLAY_COLORS.CLIFF; 592 | } else { 593 | ctx.lineWidth = 1; 594 | ctx.strokeStyle = '#000'; 595 | } 596 | v = edge.va; 597 | ctx.moveTo(v.x, v.y); 598 | v = edge.vb; 599 | ctx.lineTo(v.x, v.y); 600 | ctx.stroke(); 601 | } 602 | }; 603 | 604 | isl.renderSites = function() { 605 | // sites : 606 | var sites = this.sites, 607 | iSite = sites.length, 608 | ctx = this.debugLayer.ctx, 609 | site; 610 | 611 | ctx.fillStyle = '#0f0'; 612 | while (iSite--) { 613 | site = sites[iSite]; 614 | ctx.beginPath(); 615 | ctx.arc(site.x,site.y,1,0,2*Math.PI); 616 | ctx.fill(); 617 | } 618 | 619 | var iCells = this.diagram.cells.length; 620 | 621 | ctx.font="8px"; 622 | ctx.fillStyle = '#f00'; 623 | // values : 624 | for (var i = 0; i < iCells; i++) { 625 | var cell = this.diagram.cells[i]; 626 | ctx.fillText(Math.ceil(this.getRealElevation(cell) * 100),cell.site.x,cell.site.y); 627 | } 628 | }; 629 | 630 | isl.renderSite = function(index) { 631 | var cell = this.diagram.cells[index], 632 | he = cell.halfedges, 633 | layer = this.debugLayer, 634 | ctx = layer.ctx, 635 | point; 636 | 637 | ctx.font="8px"; 638 | ctx.fillStyle = '#ff0'; 639 | 640 | ctx.beginPath(); 641 | ctx.arc(cell.site.x,cell.site.y,2,0,2*Math.PI); 642 | ctx.fill(); 643 | 644 | for (var i = 0; i < he.length; i++) { 645 | ctx.fillStyle = '#ff0'; 646 | point = he[i].edge.lSite; 647 | ctx.fillText('L'+i,point.x-8,point.y-8); 648 | point = he[i].edge.rSite; 649 | if(point){ 650 | ctx.fillText('R'+i,point.x+8,point.y+8); 651 | } 652 | 653 | ctx.fillStyle = '#0f0'; 654 | point = he[i].getEndpoint(); 655 | ctx.beginPath(); 656 | ctx.arc(point.x,point.y,1,0,2*Math.PI); 657 | ctx.fill(); 658 | ctx.fillText('E'+i,point.x-8,point.y-8); 659 | point = he[i].getStartpoint(); 660 | ctx.beginPath(); 661 | ctx.arc(point.x,point.y,1,0,2*Math.PI); 662 | ctx.fill(); 663 | ctx.fillText('S'+i,point.x+8,point.y+8); 664 | } 665 | 666 | layer.dirty = true; 667 | layer.render(); 668 | }; 669 | 670 | isl.getNeighbors = function(index) { 671 | var cells = this.diagram.cells, 672 | cell = cells[index], 673 | neighbors = [], 674 | neighborsIds = cell.getNeighborIds(), 675 | nLength = neighborsIds.length; 676 | 677 | for (var i = nLength; i--; ) { 678 | neighbors.push(cells[neighborsIds[i]]); 679 | } 680 | 681 | cell.neighborsCache = neighbors; 682 | return neighbors; 683 | }; 684 | 685 | isl.getBorders = function(index) { 686 | var cell = this.diagram.cells[index], 687 | he = cell.halfedges, 688 | borders = []; 689 | 690 | for (var i = 0; i < he.length; i++) { 691 | borders.push(he[i].getStartpoint()); 692 | } 693 | 694 | cell.bordersCache = borders; 695 | return borders; 696 | }; 697 | 698 | isl.cellArea = function(cell) { 699 | var area = 0, 700 | halfedges = cell.halfedges, 701 | iHalfedge = halfedges.length, 702 | halfedge, 703 | p1, p2; 704 | while (iHalfedge--) { 705 | halfedge = halfedges[iHalfedge]; 706 | p1 = halfedge.getStartpoint(); 707 | p2 = halfedge.getEndpoint(); 708 | area += p1.x * p2.y; 709 | area -= p1.y * p2.x; 710 | } 711 | area /= 2; 712 | cell.areaCache = area; 713 | return area; 714 | }; 715 | 716 | isl.cellCentroid = function(cell) { 717 | var x = 0, y = 0, 718 | halfedges = cell.halfedges, 719 | iHalfedge = halfedges.length, 720 | halfedge, 721 | v, p1, p2; 722 | while (iHalfedge--) { 723 | halfedge = halfedges[iHalfedge]; 724 | p1 = halfedge.getStartpoint(); 725 | p2 = halfedge.getEndpoint(); 726 | v = p1.x*p2.y - p2.x*p1.y; 727 | x += (p1.x+p2.x) * v; 728 | y += (p1.y+p2.y) * v; 729 | } 730 | v = this.cellArea(cell) * 6; 731 | cell.centroidCache = {x:x/v,y:y/v}; 732 | return cell.centroidCache; 733 | }; 734 | 735 | isl.getCellColor = function(cell) { 736 | return this.DISPLAY_COLORS[cell && cell.biome || 'OCEAN']; 737 | }; 738 | 739 | isl.pgetCellColor = function(cell) { 740 | 741 | // TODO: better color shading via: http://stackoverflow.com/a/22825467/861615 742 | 743 | var c = Phaser.Color.hexToColor(this.DISPLAY_COLORS[cell.biome]), 744 | shade = parseInt(this.getShade(cell)*120, 10); 745 | c = Phaser.Color.RGBtoString(c.r-shade, c.g-shade, c.b-shade, c.a, '#'); 746 | return c; 747 | }; 748 | 749 | isl.getShade = function(cell) { 750 | if (this.config.shading == 0) { 751 | return 0; 752 | 753 | } else if (cell.ocean) { 754 | return (this.config.shadeOcean ? - cell.elevation : 0); 755 | 756 | } else if (cell.water) { 757 | return 0; 758 | 759 | } else { 760 | var lowerCell = null; 761 | var upperCell = null; 762 | var neighbors = cell.getNeighborIds(); 763 | for (var j = 0; j < neighbors.length; j++) { 764 | var nId = neighbors[j]; 765 | var neighbor = this.diagram.cells[nId]; 766 | if (lowerCell == null || neighbor.elevation < lowerCell.elevation) { 767 | lowerCell = neighbor; 768 | } 769 | if (upperCell == null || neighbor.elevation > upperCell.elevation) { 770 | upperCell = neighbor; 771 | } 772 | } 773 | 774 | var angleRadian = Math.atan2(upperCell.site.x - lowerCell.site.x, upperCell.site.y - lowerCell.site.y); 775 | var angleDegree = angleRadian * (180 / Math.PI); 776 | var diffElevation = (this.getRealElevation(upperCell) - this.getRealElevation(lowerCell)); 777 | 778 | if (diffElevation + this.config.shading < 1) { 779 | diffElevation = diffElevation + this.config.shading; 780 | } 781 | 782 | return ((Math.abs(angleDegree) / 180) * diffElevation); 783 | } 784 | }; 785 | 786 | isl.toggleDebug = function() { 787 | // TODO: Finish this toggling 788 | this.debug = !this.debug; 789 | // this.debugLayer.visible = this.debug; 790 | }; 791 | 792 | isl.distance = function(a, b) { 793 | var dx = a.x - b.x, 794 | dy = a.y - b.y; 795 | return Math.sqrt(dx * dx + dy * dy); 796 | }; 797 | 798 | isl.cellFromPoint = function(x,y,id){ 799 | // We build the treemap on-demand 800 | if (!this.treemap) { 801 | this.treemap = this.buildTreemap(); 802 | } 803 | // Get the Voronoi cells from the tree map given x,y 804 | var items = this.treemap.retrieve({body:{x:x,y:y,right:x+1,bottom:y+1}}), 805 | iItem = items.length, 806 | cells = this.diagram.cells, 807 | cell, cellid, candidate; // candidate is second chance to find some cell 808 | while (iItem--) { 809 | cellid = items[iItem].cellid; 810 | cell = cells[cellid]; 811 | if (cell.pointIntersection(x,y) > 0) { 812 | return id ? cellid : cell; 813 | }else if(cell.pointIntersection(x+1,y+1) > 0){ 814 | candidate = id ? cellid : cell; 815 | } 816 | } 817 | return candidate; 818 | }; 819 | 820 | isl.cellIdFromPoint = function(x, y, notId) { 821 | return isl.cellFromPoint.call(this, x, y, !notId); 822 | }; 823 | 824 | isl.buildTreemap = function() { 825 | // new QuadTree(x, y, width, height, maxObjects, maxLevels, level) 826 | var treemap = new Phaser.QuadTree( 827 | this.bbox.xl, 828 | this.bbox.yt, 829 | this.bbox.xr-this.bbox.xl, 830 | this.bbox.yb-this.bbox.yt, 831 | 10 832 | ), 833 | cells = this.diagram.cells, 834 | iCell = cells.length, 835 | cbox; 836 | while (iCell--) { 837 | // https://github.com/photonstorm/phaser/issues/1854 838 | cbox = cells[iCell].getBbox(); 839 | cbox.right = parseInt(cbox.x + cbox.width, 10); 840 | cbox.bottom = parseInt(cbox.y + cbox.height, 10); 841 | cbox.x = parseInt(cbox.x, 10); 842 | cbox.y = parseInt(cbox.y, 10); 843 | cbox.cellid = iCell; 844 | treemap.insert(cbox); 845 | } 846 | return treemap; 847 | }; 848 | 849 | isl.getRandomGenerator = function(seed) { 850 | if(seed){ 851 | seed = Array.isArray(seed) ? seed : [seed]; 852 | } 853 | return new Phaser.RandomDataGenerator(seed); 854 | }; 855 | })(Voronoi, perlinNoise, Phaser); -------------------------------------------------------------------------------- /src/plugin/perlin.js: -------------------------------------------------------------------------------- 1 | // Ported from Stefan Gustavson's java implementation 2 | // http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf 3 | // Sean McCullough banksean@gmail.com 4 | 5 | var SimplexNoise = function(gen) { 6 | this.rand = gen; 7 | this.grad3 = [ 8 | [1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0], 9 | [1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1], 10 | [0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1] 11 | ]; 12 | 13 | this.simplex = [ 14 | [0,1,2,3],[0,1,3,2],[0,0,0,0],[0,2,3,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,2,3,0], 15 | [0,2,1,3],[0,0,0,0],[0,3,1,2],[0,3,2,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,3,2,0], 16 | [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], 17 | [1,2,0,3],[0,0,0,0],[1,3,0,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,3,0,1],[2,3,1,0], 18 | [1,0,2,3],[1,0,3,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,0,3,1],[0,0,0,0],[2,1,3,0], 19 | [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], 20 | [2,0,1,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,0,1,2],[3,0,2,1],[0,0,0,0],[3,1,2,0], 21 | [2,1,0,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,1,0,2],[0,0,0,0],[3,2,0,1],[3,2,1,0] 22 | ]; 23 | }; 24 | 25 | SimplexNoise.prototype.setSeed = function(seed) { 26 | this.p = []; 27 | this.rand.seed = seed; 28 | 29 | for (var i=0; i<256; i++) { 30 | this.p[i] = Math.floor(this.rand.nextRange(0, 255)); 31 | } 32 | 33 | this.perm = []; 34 | for(var i=0; i<512; i++) { 35 | this.perm[i]=this.p[i & 255]; 36 | } 37 | } 38 | 39 | SimplexNoise.prototype.dot = function(g, x, y) { 40 | return g[0]*x + g[1]*y; 41 | }; 42 | 43 | SimplexNoise.prototype.noise = function(xin, yin) { 44 | var n0, n1, n2; 45 | 46 | var F2 = 0.5*(Math.sqrt(3.0)-1.0); 47 | var s = (xin+yin)*F2; 48 | var i = Math.floor(xin+s); 49 | var j = Math.floor(yin+s); 50 | var G2 = (3.0-Math.sqrt(3.0))/6.0; 51 | var t = (i+j)*G2; 52 | var X0 = i-t; 53 | var Y0 = j-t; 54 | var x0 = xin-X0; 55 | var y0 = yin-Y0; 56 | 57 | var i1, j1; 58 | if(x0>y0) {i1=1; j1=0;} 59 | else {i1=0; j1=1;} 60 | 61 | var x1 = x0 - i1 + G2; 62 | var y1 = y0 - j1 + G2; 63 | var x2 = x0 - 1.0 + 2.0 * G2; 64 | var y2 = y0 - 1.0 + 2.0 * G2; 65 | 66 | var ii = i & 255; 67 | var jj = j & 255; 68 | var gi0 = this.perm[ii+this.perm[jj]] % 12; 69 | var gi1 = this.perm[ii+i1+this.perm[jj+j1]] % 12; 70 | var gi2 = this.perm[ii+1+this.perm[jj+1]] % 12; 71 | 72 | var t0 = 0.5 - x0*x0-y0*y0; 73 | if(t0<0) n0 = 0.0; 74 | else { 75 | t0 *= t0; 76 | n0 = t0 * t0 * this.dot(this.grad3[gi0], x0, y0); 77 | } 78 | var t1 = 0.5 - x1*x1-y1*y1; 79 | if(t1<0) n1 = 0.0; 80 | else { 81 | t1 *= t1; 82 | n1 = t1 * t1 * this.dot(this.grad3[gi1], x1, y1); 83 | } 84 | var t2 = 0.5 - x2*x2-y2*y2; 85 | if(t2<0) n2 = 0.0; 86 | else { 87 | t2 *= t2; 88 | n2 = t2 * t2 * this.dot(this.grad3[gi2], x2, y2); 89 | } 90 | 91 | return 70.0 * (n0 + n1 + n2); 92 | }; 93 | 94 | // Park-Miller-Carta Pseudo-Random Number Generator 95 | /* global Phaser */ 96 | function PRNG(seed) { 97 | var rnd = new Phaser.RandomDataGenerator(Array.isArray(seed) ? seed : [seed]); 98 | this.seed = rnd.frac() || 1; 99 | this.next = function() { return (this.gen() / 2147483647); }; 100 | this.nextRange = function(min, max) { return min + ((max - min) * this.next()) }; 101 | this.gen = function() { return this.seed = (this.seed * 16807) % 2147483647; }; 102 | }; 103 | 104 | function perlinNoise(canvas, baseX, baseY, seed) { 105 | var rand = new PRNG(seed); 106 | var ctx = canvas.getContext('2d'); 107 | var imagedata = ctx.createImageData(canvas.width, canvas.height); 108 | var data = imagedata.data; 109 | 110 | var simplexR = new SimplexNoise(rand); 111 | simplexR.setSeed(seed); 112 | 113 | var simplexG = new SimplexNoise(rand); 114 | simplexG.setSeed(seed + 1); 115 | 116 | var simplexB = new SimplexNoise(rand); 117 | simplexB.setSeed(seed + 2); 118 | 119 | var pos, cr, cg, cb, gray; 120 | for (var y = 0; y < canvas.height; y ++) { 121 | for (var x = 0; x < canvas.width; x ++) { 122 | pos = (x + y * canvas.width) * 4; 123 | 124 | cr = Math.floor(((simplexR.noise(x / baseX, y / baseY) + 1) * 0.5) * 255); 125 | cg = Math.floor(((simplexG.noise(x / baseX, y / baseY) + 1) * 0.5) * 255); 126 | cb = Math.floor(((simplexB.noise(x / baseX, y / baseY) + 1) * 0.5) * 255); 127 | 128 | gray = (cr + cg + cb) / 3; 129 | 130 | data[pos + 0] = gray; 131 | data[pos + 1] = gray; 132 | data[pos + 2] = gray; 133 | data[pos + 3] = 255; 134 | } 135 | } 136 | 137 | ctx.putImageData(imagedata, 0, 0); 138 | return imagedata; 139 | }; -------------------------------------------------------------------------------- /stylesheets/github-light.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 GitHub Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | */ 17 | 18 | .pl-c /* comment */ { 19 | color: #969896; 20 | } 21 | 22 | .pl-c1 /* constant, markup.raw, meta.diff.header, meta.module-reference, meta.property-name, support, support.constant, support.variable, variable.other.constant */, 23 | .pl-s .pl-v /* string variable */ { 24 | color: #0086b3; 25 | } 26 | 27 | .pl-e /* entity */, 28 | .pl-en /* entity.name */ { 29 | color: #795da3; 30 | } 31 | 32 | .pl-s .pl-s1 /* string source */, 33 | .pl-smi /* storage.modifier.import, storage.modifier.package, storage.type.java, variable.other, variable.parameter.function */ { 34 | color: #333; 35 | } 36 | 37 | .pl-ent /* entity.name.tag */ { 38 | color: #63a35c; 39 | } 40 | 41 | .pl-k /* keyword, storage, storage.type */ { 42 | color: #a71d5d; 43 | } 44 | 45 | .pl-pds /* punctuation.definition.string, string.regexp.character-class */, 46 | .pl-s /* string */, 47 | .pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */, 48 | .pl-sr /* string.regexp */, 49 | .pl-sr .pl-cce /* string.regexp constant.character.escape */, 50 | .pl-sr .pl-sra /* string.regexp string.regexp.arbitrary-repitition */, 51 | .pl-sr .pl-sre /* string.regexp source.ruby.embedded */ { 52 | color: #183691; 53 | } 54 | 55 | .pl-v /* variable */ { 56 | color: #ed6a43; 57 | } 58 | 59 | .pl-id /* invalid.deprecated */ { 60 | color: #b52a1d; 61 | } 62 | 63 | .pl-ii /* invalid.illegal */ { 64 | background-color: #b52a1d; 65 | color: #f8f8f8; 66 | } 67 | 68 | .pl-sr .pl-cce /* string.regexp constant.character.escape */ { 69 | color: #63a35c; 70 | font-weight: bold; 71 | } 72 | 73 | .pl-ml /* markup.list */ { 74 | color: #693a17; 75 | } 76 | 77 | .pl-mh /* markup.heading */, 78 | .pl-mh .pl-en /* markup.heading entity.name */, 79 | .pl-ms /* meta.separator */ { 80 | color: #1d3e81; 81 | font-weight: bold; 82 | } 83 | 84 | .pl-mq /* markup.quote */ { 85 | color: #008080; 86 | } 87 | 88 | .pl-mi /* markup.italic */ { 89 | color: #333; 90 | font-style: italic; 91 | } 92 | 93 | .pl-mb /* markup.bold */ { 94 | color: #333; 95 | font-weight: bold; 96 | } 97 | 98 | .pl-md /* markup.deleted, meta.diff.header.from-file */ { 99 | background-color: #ffecec; 100 | color: #bd2c00; 101 | } 102 | 103 | .pl-mi1 /* markup.inserted, meta.diff.header.to-file */ { 104 | background-color: #eaffea; 105 | color: #55a532; 106 | } 107 | 108 | .pl-mdr /* meta.diff.range */ { 109 | color: #795da3; 110 | font-weight: bold; 111 | } 112 | 113 | .pl-mo /* meta.output */ { 114 | color: #1d3e81; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /stylesheets/github.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | github.com style (c) Vasily Polovnyov 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 0.5em; 11 | color: #333; 12 | background: #f8f8f8; 13 | -webkit-text-size-adjust: none; 14 | } 15 | 16 | .hljs-comment, 17 | .diff .hljs-header { 18 | color: #998; 19 | font-style: italic; 20 | } 21 | 22 | .hljs-keyword, 23 | .css .rule .hljs-keyword, 24 | .hljs-winutils, 25 | .nginx .hljs-title, 26 | .hljs-subst, 27 | .hljs-request, 28 | .hljs-status { 29 | color: #333; 30 | font-weight: bold; 31 | } 32 | 33 | .hljs-number, 34 | .hljs-hexcolor, 35 | .ruby .hljs-constant { 36 | color: #008080; 37 | } 38 | 39 | .hljs-string, 40 | .hljs-tag .hljs-value, 41 | .hljs-doctag, 42 | .tex .hljs-formula { 43 | color: #d14; 44 | } 45 | 46 | .hljs-title, 47 | .hljs-id, 48 | .scss .hljs-preprocessor { 49 | color: #900; 50 | font-weight: bold; 51 | } 52 | 53 | .hljs-list .hljs-keyword, 54 | .hljs-subst { 55 | font-weight: normal; 56 | } 57 | 58 | .hljs-class .hljs-title, 59 | .hljs-type, 60 | .vhdl .hljs-literal, 61 | .tex .hljs-command { 62 | color: #458; 63 | font-weight: bold; 64 | } 65 | 66 | .hljs-tag, 67 | .hljs-tag .hljs-title, 68 | .hljs-rule .hljs-property, 69 | .django .hljs-tag .hljs-keyword { 70 | color: #000080; 71 | font-weight: normal; 72 | } 73 | 74 | .hljs-attribute, 75 | .hljs-variable, 76 | .lisp .hljs-body, 77 | .hljs-name { 78 | color: #008080; 79 | } 80 | 81 | .hljs-regexp { 82 | color: #009926; 83 | } 84 | 85 | .hljs-symbol, 86 | .ruby .hljs-symbol .hljs-string, 87 | .lisp .hljs-keyword, 88 | .clojure .hljs-keyword, 89 | .scheme .hljs-keyword, 90 | .tex .hljs-special, 91 | .hljs-prompt { 92 | color: #990073; 93 | } 94 | 95 | .hljs-built_in { 96 | color: #0086b3; 97 | } 98 | 99 | .hljs-preprocessor, 100 | .hljs-pragma, 101 | .hljs-pi, 102 | .hljs-doctype, 103 | .hljs-shebang, 104 | .hljs-cdata { 105 | color: #999; 106 | font-weight: bold; 107 | } 108 | 109 | .hljs-deletion { 110 | background: #fdd; 111 | } 112 | 113 | .hljs-addition { 114 | background: #dfd; 115 | } 116 | 117 | .diff .hljs-change { 118 | background: #0086b3; 119 | } 120 | 121 | .hljs-chunk { 122 | color: #aaa; 123 | } 124 | -------------------------------------------------------------------------------- /stylesheets/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | * and Firefox. 30 | * Correct `block` display not defined for `main` in IE 11. 31 | */ 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | /** 50 | * 1. Correct `inline-block` display not defined in IE 8/9. 51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | */ 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; /* 1 */ 59 | vertical-align: baseline; /* 2 */ 60 | } 61 | 62 | /** 63 | * Prevent modern browsers from displaying `audio` without controls. 64 | * Remove excess height in iOS 5 devices. 65 | */ 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | /** 73 | * Address `[hidden]` styling not present in IE 8/9/10. 74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 | */ 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | /* Links 83 | ========================================================================== */ 84 | 85 | /** 86 | * Remove the gray background color from active links in IE 10. 87 | */ 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | /** 94 | * Improve readability when focused and also mouse hovered in all browsers. 95 | */ 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | /* Text-level semantics 103 | ========================================================================== */ 104 | 105 | /** 106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | */ 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | /** 114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | */ 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | /** 123 | * Address styling not present in Safari and Chrome. 124 | */ 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | /** 131 | * Address variable `h1` font-size and margin within `section` and `article` 132 | * contexts in Firefox 4+, Safari, and Chrome. 133 | */ 134 | 135 | h1 { 136 | font-size: 2em; 137 | margin: 0.67em 0; 138 | } 139 | 140 | /** 141 | * Address styling not present in IE 8/9. 142 | */ 143 | 144 | mark { 145 | background: #ff0; 146 | color: #000; 147 | } 148 | 149 | /** 150 | * Address inconsistent and variable font size in all browsers. 151 | */ 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | /** 158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | */ 160 | 161 | sub, 162 | sup { 163 | font-size: 75%; 164 | line-height: 0; 165 | position: relative; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | /* Embedded content 178 | ========================================================================== */ 179 | 180 | /** 181 | * Remove border when inside `a` element in IE 8/9/10. 182 | */ 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | /** 189 | * Correct overflow not hidden in IE 9/10/11. 190 | */ 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | /* Grouping content 197 | ========================================================================== */ 198 | 199 | /** 200 | * Address margin not present in IE 8/9 and Safari. 201 | */ 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | /** 208 | * Address differences between Firefox and other browsers. 209 | */ 210 | 211 | hr { 212 | box-sizing: content-box; 213 | height: 0; 214 | } 215 | 216 | /** 217 | * Contain overflow in all browsers. 218 | */ 219 | 220 | pre { 221 | overflow: auto; 222 | } 223 | 224 | /** 225 | * Address odd `em`-unit font size rendering in all browsers. 226 | */ 227 | 228 | code, 229 | kbd, 230 | pre, 231 | samp { 232 | font-family: monospace, monospace; 233 | font-size: 1em; 234 | } 235 | 236 | /* Forms 237 | ========================================================================== */ 238 | 239 | /** 240 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 241 | * styling of `select`, unless a `border` property is set. 242 | */ 243 | 244 | /** 245 | * 1. Correct color not being inherited. 246 | * Known issue: affects color of disabled elements. 247 | * 2. Correct font properties not being inherited. 248 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 249 | */ 250 | 251 | button, 252 | input, 253 | optgroup, 254 | select, 255 | textarea { 256 | color: inherit; /* 1 */ 257 | font: inherit; /* 2 */ 258 | margin: 0; /* 3 */ 259 | } 260 | 261 | /** 262 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 263 | */ 264 | 265 | button { 266 | overflow: visible; 267 | } 268 | 269 | /** 270 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 271 | * All other form control elements do not inherit `text-transform` values. 272 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 273 | * Correct `select` style inheritance in Firefox. 274 | */ 275 | 276 | button, 277 | select { 278 | text-transform: none; 279 | } 280 | 281 | /** 282 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 283 | * and `video` controls. 284 | * 2. Correct inability to style clickable `input` types in iOS. 285 | * 3. Improve usability and consistency of cursor style between image-type 286 | * `input` and others. 287 | */ 288 | 289 | button, 290 | html input[type="button"], /* 1 */ 291 | input[type="reset"], 292 | input[type="submit"] { 293 | -webkit-appearance: button; /* 2 */ 294 | cursor: pointer; /* 3 */ 295 | } 296 | 297 | /** 298 | * Re-set default cursor for disabled elements. 299 | */ 300 | 301 | button[disabled], 302 | html input[disabled] { 303 | cursor: default; 304 | } 305 | 306 | /** 307 | * Remove inner padding and border in Firefox 4+. 308 | */ 309 | 310 | button::-moz-focus-inner, 311 | input::-moz-focus-inner { 312 | border: 0; 313 | padding: 0; 314 | } 315 | 316 | /** 317 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 318 | * the UA stylesheet. 319 | */ 320 | 321 | input { 322 | line-height: normal; 323 | } 324 | 325 | /** 326 | * It's recommended that you don't attempt to style these elements. 327 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 328 | * 329 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 330 | * 2. Remove excess padding in IE 8/9/10. 331 | */ 332 | 333 | input[type="checkbox"], 334 | input[type="radio"] { 335 | box-sizing: border-box; /* 1 */ 336 | padding: 0; /* 2 */ 337 | } 338 | 339 | /** 340 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 341 | * `font-size` values of the `input`, it causes the cursor style of the 342 | * decrement button to change from `default` to `text`. 343 | */ 344 | 345 | input[type="number"]::-webkit-inner-spin-button, 346 | input[type="number"]::-webkit-outer-spin-button { 347 | height: auto; 348 | } 349 | 350 | /** 351 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 352 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 353 | * (include `-moz` to future-proof). 354 | */ 355 | 356 | input[type="search"] { 357 | -webkit-appearance: textfield; /* 1 */ /* 2 */ 358 | box-sizing: content-box; 359 | } 360 | 361 | /** 362 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 363 | * Safari (but not Chrome) clips the cancel button when the search input has 364 | * padding (and `textfield` appearance). 365 | */ 366 | 367 | input[type="search"]::-webkit-search-cancel-button, 368 | input[type="search"]::-webkit-search-decoration { 369 | -webkit-appearance: none; 370 | } 371 | 372 | /** 373 | * Define consistent border, margin, and padding. 374 | */ 375 | 376 | fieldset { 377 | border: 1px solid #c0c0c0; 378 | margin: 0 2px; 379 | padding: 0.35em 0.625em 0.75em; 380 | } 381 | 382 | /** 383 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 384 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 385 | */ 386 | 387 | legend { 388 | border: 0; /* 1 */ 389 | padding: 0; /* 2 */ 390 | } 391 | 392 | /** 393 | * Remove default vertical scrollbar in IE 8/9/10/11. 394 | */ 395 | 396 | textarea { 397 | overflow: auto; 398 | } 399 | 400 | /** 401 | * Don't inherit the `font-weight` (applied by a rule above). 402 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 403 | */ 404 | 405 | optgroup { 406 | font-weight: bold; 407 | } 408 | 409 | /* Tables 410 | ========================================================================== */ 411 | 412 | /** 413 | * Remove most spacing between table cells. 414 | */ 415 | 416 | table { 417 | border-collapse: collapse; 418 | border-spacing: 0; 419 | } 420 | 421 | td, 422 | th { 423 | padding: 0; 424 | } 425 | -------------------------------------------------------------------------------- /stylesheets/stylesheet.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; } 3 | 4 | body { 5 | padding: 0; 6 | margin: 0; 7 | font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 8 | font-size: 16px; 9 | line-height: 1.5; 10 | color: #606c71; } 11 | 12 | a { 13 | color: #1e6bb8; 14 | text-decoration: none; } 15 | a:hover { 16 | text-decoration: underline; } 17 | 18 | .btn { 19 | display: inline-block; 20 | margin-bottom: 1rem; 21 | color: rgba(255, 255, 255, 0.7); 22 | background-color: rgba(255, 255, 255, 0.08); 23 | border-color: rgba(255, 255, 255, 0.2); 24 | border-style: solid; 25 | border-width: 1px; 26 | border-radius: 0.3rem; 27 | transition: color 0.2s, background-color 0.2s, border-color 0.2s; } 28 | .btn + .btn { 29 | margin-left: 1rem; } 30 | 31 | .btn:hover { 32 | color: rgba(255, 255, 255, 0.8); 33 | text-decoration: none; 34 | background-color: rgba(255, 255, 255, 0.2); 35 | border-color: rgba(255, 255, 255, 0.3); } 36 | 37 | @media screen and (min-width: 64em) { 38 | .btn { 39 | padding: 0.75rem 1rem; } } 40 | 41 | @media screen and (min-width: 42em) and (max-width: 64em) { 42 | .btn { 43 | padding: 0.6rem 0.9rem; 44 | font-size: 0.9rem; } } 45 | 46 | @media screen and (max-width: 42em) { 47 | .btn { 48 | display: block; 49 | width: 100%; 50 | padding: 0.75rem; 51 | font-size: 0.9rem; } 52 | .btn + .btn { 53 | margin-top: 1rem; 54 | margin-left: 0; } } 55 | 56 | .page-header { 57 | color: #fff; 58 | text-align: center; 59 | background-color: #159957; 60 | background-image: linear-gradient(120deg, #155799, #159957); } 61 | 62 | .page-header a { 63 | color: #fff; 64 | text-decoration: none; 65 | } 66 | 67 | @media screen and (min-width: 64em) { 68 | .page-header { 69 | padding: 5rem 6rem; } } 70 | 71 | @media screen and (min-width: 42em) and (max-width: 64em) { 72 | .page-header { 73 | padding: 3rem 4rem; } } 74 | 75 | @media screen and (max-width: 42em) { 76 | .page-header { 77 | padding: 2rem 1rem; } } 78 | 79 | .project-name { 80 | margin-top: 0; 81 | margin-bottom: 0.1rem; } 82 | 83 | @media screen and (min-width: 64em) { 84 | .project-name { 85 | font-size: 3.25rem; } } 86 | 87 | @media screen and (min-width: 42em) and (max-width: 64em) { 88 | .project-name { 89 | font-size: 2.25rem; } } 90 | 91 | @media screen and (max-width: 42em) { 92 | .project-name { 93 | font-size: 1.75rem; } } 94 | 95 | .project-tagline { 96 | margin-bottom: 2rem; 97 | font-weight: normal; 98 | opacity: 0.7; } 99 | 100 | @media screen and (min-width: 64em) { 101 | .project-tagline { 102 | font-size: 1.25rem; } } 103 | 104 | @media screen and (min-width: 42em) and (max-width: 64em) { 105 | .project-tagline { 106 | font-size: 1.15rem; } } 107 | 108 | @media screen and (max-width: 42em) { 109 | .project-tagline { 110 | font-size: 1rem; } } 111 | 112 | .main-content :first-child { 113 | margin-top: 0; } 114 | .main-content img { 115 | max-width: 100%; } 116 | .main-content h1, .main-content h2, .main-content h3, .main-content h4, .main-content h5, .main-content h6 { 117 | margin-top: 2rem; 118 | margin-bottom: 1rem; 119 | font-weight: normal; 120 | color: #159957; } 121 | .main-content p { 122 | margin-bottom: 1em; } 123 | .main-content code { 124 | padding: 2px 4px; 125 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; 126 | font-size: 0.9rem; 127 | color: #383e41; 128 | background-color: #f3f6fa; 129 | border-radius: 0.3rem; } 130 | .main-content pre { 131 | padding: 0.8rem; 132 | margin-top: 0; 133 | margin-bottom: 1rem; 134 | font: 1rem Consolas, "Liberation Mono", Menlo, Courier, monospace; 135 | color: #567482; 136 | word-wrap: normal; 137 | background-color: #f3f6fa; 138 | border: solid 1px #dce6f0; 139 | border-radius: 0.3rem; } 140 | .main-content pre > code { 141 | padding: 0; 142 | margin: 0; 143 | font-size: 0.9rem; 144 | color: #567482; 145 | word-break: normal; 146 | white-space: pre; 147 | background: transparent; 148 | border: 0; } 149 | .main-content .highlight { 150 | margin-bottom: 1rem; } 151 | .main-content .highlight pre { 152 | margin-bottom: 0; 153 | word-break: normal; } 154 | .main-content .highlight pre, .main-content pre { 155 | padding: 0.8rem; 156 | overflow: auto; 157 | font-size: 0.9rem; 158 | line-height: 1.45; 159 | border-radius: 0.3rem; } 160 | .main-content pre code, .main-content pre tt { 161 | display: inline; 162 | max-width: initial; 163 | padding: 0; 164 | margin: 0; 165 | overflow: initial; 166 | line-height: inherit; 167 | word-wrap: normal; 168 | background-color: transparent; 169 | border: 0; } 170 | .main-content pre code:before, .main-content pre code:after, .main-content pre tt:before, .main-content pre tt:after { 171 | content: normal; } 172 | .main-content ul, .main-content ol { 173 | margin-top: 0; } 174 | .main-content blockquote { 175 | padding: 0 1rem; 176 | margin-left: 0; 177 | color: #819198; 178 | border-left: 0.3rem solid #dce6f0; } 179 | .main-content blockquote > :first-child { 180 | margin-top: 0; } 181 | .main-content blockquote > :last-child { 182 | margin-bottom: 0; } 183 | .main-content table { 184 | display: block; 185 | width: 100%; 186 | overflow: auto; 187 | word-break: normal; 188 | word-break: keep-all; } 189 | .main-content table th { 190 | font-weight: bold; } 191 | .main-content table th, .main-content table td { 192 | padding: 0.5rem 1rem; 193 | border: 1px solid #e9ebec; } 194 | .main-content dl { 195 | padding: 0; } 196 | .main-content dl dt { 197 | padding: 0; 198 | margin-top: 1rem; 199 | font-size: 1rem; 200 | font-weight: bold; } 201 | .main-content dl dd { 202 | padding: 0; 203 | margin-bottom: 1rem; } 204 | .main-content hr { 205 | height: 2px; 206 | padding: 0; 207 | margin: 1rem 0; 208 | background-color: #eff0f1; 209 | border: 0; } 210 | 211 | @media screen and (min-width: 64em) { 212 | .main-content { 213 | max-width: 64rem; 214 | padding: 2rem 6rem; 215 | margin: 0 auto; 216 | font-size: 1.1rem; } } 217 | 218 | @media screen and (min-width: 42em) and (max-width: 64em) { 219 | .main-content { 220 | padding: 2rem 4rem; 221 | font-size: 1.1rem; } } 222 | 223 | @media screen and (max-width: 42em) { 224 | .main-content { 225 | padding: 2rem 1rem; 226 | font-size: 1rem; } } 227 | 228 | .site-footer { 229 | padding-top: 2rem; 230 | margin-top: 2rem; 231 | border-top: solid 1px #eff0f1; } 232 | 233 | .site-footer-owner { 234 | display: block; 235 | font-weight: bold; } 236 | 237 | .site-footer-credits { 238 | color: #819198; } 239 | 240 | @media screen and (min-width: 64em) { 241 | .site-footer { 242 | font-size: 1rem; } } 243 | 244 | @media screen and (min-width: 42em) and (max-width: 64em) { 245 | .site-footer { 246 | font-size: 1rem; } } 247 | 248 | @media screen and (max-width: 42em) { 249 | .site-footer { 250 | font-size: 0.9rem; } } 251 | --------------------------------------------------------------------------------