=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 |
--------------------------------------------------------------------------------