2023-10-20 13:31:23 +02:00
"use strict" ;
2023-10-20 14:03:45 +02:00
2023-10-21 14:19:42 +02:00
// Default values for the min. and max. Y of biomes
2023-10-20 14:39:49 +02:00
const MIN _Y _DEFAULT = - 31000
const MAX _Y _DEFAULT = 31000
2023-10-21 14:19:42 +02:00
// Draw a grid line every GRID_STEP units
const GRID _STEP = 10
2023-10-21 19:26:24 +02:00
// Distance from the point's center in which a point can
// be selected by clicking on it
const POINT _SELECT _DISTANCE = 25
2023-10-21 02:18:29 +02:00
// Symbol for storing the biome ID in site objects
// for the Voronoi script
const biomeIDSymbol = Symbol ( "Biome ID" ) ;
2023-10-21 13:59:19 +02:00
// Colors
2023-10-20 13:31:23 +02:00
const pointColor = "#913636" ;
const pointColorSelected = "#e19696" ;
const edgeColor = "#0f2c2e" ;
const gridColor = "#00000040" ;
2023-10-20 17:30:05 +02:00
const clearColor = "#ecddba" ;
2023-10-21 13:59:19 +02:00
const cellColorNeutral = "#888888" ;
2023-10-20 13:31:23 +02:00
const cellColors = [
"#64988e" ,
"#3d7085" ,
"#345644" ,
"#6b7f5c" ,
2023-10-21 12:08:24 +02:00
"#868750" ,
"#a7822c" ,
"#a06e38" ,
2023-10-20 13:31:23 +02:00
"#ad5f52" ,
"#692f11" ,
"#89542f" ,
"#796e63" ,
"#a17d5e" ,
2023-10-21 12:08:24 +02:00
"#5a3f20" ,
"#836299" ,
2023-10-20 13:31:23 +02:00
] ;
2023-10-21 17:12:43 +02:00
// Min. and max. mathematically possible values for heat and humidity
2023-10-21 17:55:32 +02:00
let limit _heat _min , limit _heat _max ;
let limit _humidity _min , limit _humidity _max ;
2023-10-21 17:12:43 +02:00
// Draw area. Slightly larger than the value area to avoid
// ugly edge rendering problems
const DRAW _OFFSET = 10
2023-10-21 17:55:32 +02:00
let draw _heat _min , draw _heat _max ;
let draw _humidity _min , draw _humidity _max ;
2023-10-21 17:12:43 +02:00
// The point that is considered the middle of heat/humidity;
// mathematically this value is the most probable.
2023-10-21 17:55:32 +02:00
let midpoint _heat ;
let midpoint _humidity ;
2023-10-21 17:12:43 +02:00
// Biome noise settings
const NOISE _OFFSET _DEFAULT = 50 ;
const NOISE _SCALE _DEFAULT = 50 ;
const NOISE _PERSISTENCE _DEFAULT = 0.5 ;
const NOISE _OCTAVES _DEFAULT = 3 ;
const NOISE _ABSVALUE _DEFAULT = false ;
2023-10-21 17:55:32 +02:00
let noises = {
heat : {
offset : NOISE _OFFSET _DEFAULT ,
scale : NOISE _SCALE _DEFAULT ,
octaves : NOISE _OCTAVES _DEFAULT ,
persistence : NOISE _PERSISTENCE _DEFAULT ,
absvalue : NOISE _ABSVALUE _DEFAULT ,
} ,
humidity : {
offset : NOISE _OFFSET _DEFAULT ,
scale : NOISE _SCALE _DEFAULT ,
octaves : NOISE _OCTAVES _DEFAULT ,
persistence : NOISE _PERSISTENCE _DEFAULT ,
absvalue : NOISE _ABSVALUE _DEFAULT ,
} ,
} ;
function updateAreaVarsFor ( noiseType ) {
let noise = noises [ noiseType ] ;
let is _absolute = noise . absvalue === true
2023-10-21 17:12:43 +02:00
// Calculate min. and max. possible values
// Octaves
let [ o _min , o _max ] = [ 0 , 0 ]
2023-10-21 17:55:32 +02:00
for ( let o = 1 ; o <= noise . octaves ; o ++ ) {
2023-10-21 17:12:43 +02:00
let exp = o - 1
// Calculate the two possible extreme values
// with the octave value being either at 1 or -1.
2023-10-21 17:55:32 +02:00
let limit1 = ( 1 * noise . persistence * * exp )
2023-10-21 17:12:43 +02:00
let limit2
if ( ! is _absolute ) {
2023-10-21 17:55:32 +02:00
limit2 = ( - 1 * noise . persistence * * exp )
2023-10-21 17:12:43 +02:00
} else {
// If absvalue is set, one of the
// limits is always 0 because we
// can't get lower.
limit2 = 0
}
// To add to the maximum, pick the higher value
if ( limit1 > limit2 ) {
o _max = o _max + limit1
} else {
o _max = o _max + limit2
}
// To add to the minimum, pick the LOWER value
if ( limit1 > limit2 ) {
o _min = o _min + limit2
} else {
o _min = o _min + limit1
}
}
// Add offset and scale to min/max value (final step)
2023-10-21 17:55:32 +02:00
let min _value = noise . offset + noise . scale * o _min
let max _value = noise . offset + noise . scale * o _max
2023-10-21 17:12:43 +02:00
// Bring the 2 values in the correct order
// (min_value might be bigger for negative scale)
if ( min _value > max _value ) {
[ min _value , max _value ] = [ max _value , min _value ]
}
// Update globals
2023-10-21 17:55:32 +02:00
let limit _min = min _value ;
let limit _max = max _value ;
let draw _min = limit _min - DRAW _OFFSET
let draw _max = limit _max + DRAW _OFFSET
let midpoint = min _value + ( max _value - min _value ) / 2
if ( noiseType === "heat" ) {
limit _heat _min = limit _min ;
limit _heat _max = limit _max ;
draw _heat _min = draw _min ;
draw _heat _max = draw _max ;
midpoint _heat = midpoint ;
} else if ( noiseType === "humidity" ) {
limit _humidity _min = limit _min ;
limit _humidity _max = limit _max ;
draw _humidity _min = draw _min ;
draw _humidity _max = draw _max ;
midpoint _humidity = midpoint ;
} else {
console . log ( "ERROR! updateAreaVars() called with wrong noise_type!" )
}
}
function updateAreaVars ( ) {
updateAreaVarsFor ( "heat" ) ;
updateAreaVarsFor ( "humidity" ) ;
2023-10-21 17:12:43 +02:00
// Update element
2023-10-21 23:04:38 +02:00
rangeDisplay . innerHTML = "heat range: <span class='statHeat'>[" + ( + limit _heat _min ) + ", " + ( + limit _heat _max ) + "]</span>; " +
"humidity range: <span class='statHumidity'>[" + ( + limit _humidity _min ) + ", " + ( + limit _humidity _max ) + "]</span>" ;
2023-10-21 17:12:43 +02:00
}
updateAreaVars ( ) ;
2023-10-21 13:59:19 +02:00
// If true, point names are shown in diagram
let showNames = true ;
// If true, points are shown in diagram
let showPoints = true ;
// If true, cells are colorized in diagram
let showCellColors = true ;
// If true, show the grid in the diagram
let showGrid = true ;
2023-10-21 17:12:43 +02:00
// Set to true if the draw canvas currently shows an error message
let drawError = false ;
2023-10-21 13:59:19 +02:00
let lastBiomeID = 0 ;
let biomePoints = [ ] ;
function addBiome ( biomeDef ) {
biomeDef . id = lastBiomeID ;
biomePoints . push ( biomeDef ) ;
lastBiomeID ++ ;
}
// Add a default biome at the midpoint
2023-10-21 17:55:32 +02:00
addBiome ( { name : generateBiomeName ( midpoint _heat , midpoint _humidity ) , heat : midpoint _heat , humidity : midpoint _humidity , min _y : MIN _Y _DEFAULT , max _y : MAX _Y _DEFAULT } )
2023-10-21 13:59:19 +02:00
function getViewY ( ) {
if ( ! inputViewY ) {
return 0 ;
}
return inputViewY . value ;
}
2023-10-20 16:31:11 +02:00
// returns the biome point by its given ID
// or null if it couldn't be found
function getBiomeByID ( id ) {
for ( let b = 0 ; b < biomePoints . length ; b ++ ) {
let biome = biomePoints [ b ] ;
if ( biome . id === id ) {
return biome ;
}
2023-10-20 13:31:23 +02:00
}
2023-10-20 16:31:11 +02:00
return null ;
}
// Returns a biome name for displaying it, based on heat and humidity values.
function generateBiomeName ( heat , humidity ) {
return "(" + heat + "," + humidity + ")" ;
2023-10-20 13:31:23 +02:00
}
function biomePointToVoronoiPoint ( point ) {
2023-10-21 02:18:29 +02:00
// Apart from x and y, we also add the biome ID to the Voronoi point
// so we can re-identify to which biome it belongs to when the
// object is returned from the Voronoi script output.
let newPoint = { x : point . heat , y : point . humidity , [ biomeIDSymbol ] : point . id }
2023-10-20 13:31:23 +02:00
return newPoint ;
}
function voronoiPointToBiomePoint ( point ) {
2023-10-21 02:18:29 +02:00
let newPoint = { heat : point . x , humidity : point . y , id : point [ biomeIDSymbol ] }
2023-10-20 13:31:23 +02:00
return newPoint ;
}
2023-10-21 11:35:22 +02:00
function putPointName ( context , point ) {
2023-10-22 12:40:01 +02:00
let he = point . heat
let hu = point . humidity
if ( he < limit _heat _min || he > limit _heat _max || hu < limit _humidity _min || hu > limit _humidity _max ) {
2023-10-21 11:35:22 +02:00
return ;
}
2023-10-22 12:40:01 +02:00
let [ x , y ] = biomeCoordsToCanvasPixelCoords ( he , hu ) ;
let w = voronoiCanvas . width ;
let h = voronoiCanvas . height ;
if ( x > w / 2 ) {
2023-10-21 11:35:22 +02:00
context . textAlign = "right" ;
2023-10-22 12:40:01 +02:00
x = x - 5 ;
2023-10-21 11:35:22 +02:00
} else {
context . textAlign = "left" ;
2023-10-22 12:40:01 +02:00
x = x + 5 ;
2023-10-21 11:35:22 +02:00
}
2023-10-22 12:40:01 +02:00
if ( y < h / 2 ) {
2023-10-21 12:08:24 +02:00
context . textBaseline = "top" ;
} else {
context . textBaseline = "alphabetic" ;
}
2023-10-22 12:40:01 +02:00
context . font = "120% sans-serif"
2023-10-21 11:35:22 +02:00
context . fillText ( point . name , x , y ) ;
}
2023-10-20 13:31:23 +02:00
function putPoint ( context , point ) {
2023-10-22 12:40:01 +02:00
const ARROW _SIZE _SIDE = 7 ;
const ARROW _SIZE _CORNER = 9 ;
let he = point . heat
let hu = point . humidity
let [ x , y ] = biomeCoordsToCanvasPixelCoords ( he , hu ) ;
let w = voronoiCanvas . width ;
let h = voronoiCanvas . height ;
let [ limit _x _min , limit _y _min ] = biomeCoordsToCanvasPixelCoords ( limit _heat _min , limit _humidity _min ) ;
let [ limit _x _max , limit _y _max ] = biomeCoordsToCanvasPixelCoords ( limit _heat _max , limit _humidity _max ) ;
2023-10-20 15:23:44 +02:00
// Point is out of bounds: Draw an arrow at the border
2023-10-22 12:40:01 +02:00
if ( he < limit _heat _min || he > limit _heat _max || hu < limit _humidity _min || hu > limit _humidity _max ) {
2023-10-20 15:23:44 +02:00
context . beginPath ( ) ;
// top left corner
2023-10-22 12:40:01 +02:00
if ( he < limit _heat _min && hu < limit _humidity _min ) {
context . moveTo ( limit _x _min , limit _x _min ) ;
context . lineTo ( limit _x _min + ARROW _SIZE _CORNER , limit _y _min ) ;
context . lineTo ( limit _x _min , limit _y _min + ARROW _SIZE _CORNER ) ;
2023-10-20 15:23:44 +02:00
context . closePath ( ) ;
context . fill ( ) ;
// top right corner
2023-10-22 12:40:01 +02:00
} else if ( he > limit _heat _max && hu < limit _humidity _min ) {
context . moveTo ( limit _x _max , limit _y _min ) ;
context . lineTo ( limit _x _max - ARROW _SIZE _CORNER , limit _y _min ) ;
context . lineTo ( limit _x _max , limit _y _min + ARROW _SIZE _CORNER ) ;
2023-10-20 15:23:44 +02:00
context . closePath ( ) ;
context . fill ( ) ;
// bottom left corner
2023-10-22 12:40:01 +02:00
} else if ( he < limit _heat _min && hu > limit _humidity _max ) {
context . moveTo ( limit _x _min , limit _y _max ) ;
context . lineTo ( limit _x _min + ARROW _SIZE _CORNER , limit _y _max ) ;
context . lineTo ( limit _x _min , limit _y _max - ARROW _SIZE _CORNER ) ;
2023-10-20 15:23:44 +02:00
context . closePath ( ) ;
context . fill ( ) ;
// top right corner
2023-10-22 12:40:01 +02:00
} else if ( he > limit _heat _max && hu > limit _humidity _max ) {
context . moveTo ( limit _x _max , limit _y _max ) ;
context . lineTo ( limit _x _max - ARROW _SIZE _CORNER , limit _y _max ) ;
context . lineTo ( limit _x _max , limit _y _max - ARROW _SIZE _CORNER ) ;
2023-10-20 15:23:44 +02:00
context . closePath ( ) ;
context . fill ( ) ;
// left side
2023-10-22 12:40:01 +02:00
} else if ( he < limit _heat _min ) {
context . moveTo ( limit _x _min , y ) ;
context . lineTo ( limit _x _min + ARROW _SIZE _SIDE , y + ARROW _SIZE _SIDE ) ;
context . lineTo ( limit _x _min + ARROW _SIZE _SIDE , y - ARROW _SIZE _SIDE ) ;
2023-10-20 15:23:44 +02:00
context . closePath ( ) ;
context . fill ( ) ;
// right side
2023-10-22 12:40:01 +02:00
} else if ( he > limit _heat _max ) {
context . moveTo ( limit _x _max , y ) ;
context . lineTo ( limit _x _max - ARROW _SIZE _SIDE , y + ARROW _SIZE _SIDE ) ;
context . lineTo ( limit _x _max - ARROW _SIZE _SIDE , y - ARROW _SIZE _SIDE ) ;
2023-10-20 15:23:44 +02:00
context . closePath ( ) ;
context . fill ( ) ;
// top side
2023-10-22 12:40:01 +02:00
} else if ( hu < limit _humidity _min ) {
context . moveTo ( x , limit _y _min ) ;
context . lineTo ( x - ARROW _SIZE _SIDE , limit _y _min + ARROW _SIZE _SIDE ) ;
context . lineTo ( x + ARROW _SIZE _SIDE , limit _y _min + ARROW _SIZE _SIDE ) ;
2023-10-20 15:23:44 +02:00
context . closePath ( ) ;
context . fill ( ) ;
// bottom side
2023-10-22 12:40:01 +02:00
} else if ( hu > limit _humidity _max ) {
context . moveTo ( x , limit _y _max ) ;
context . lineTo ( x - ARROW _SIZE _SIDE , limit _y _max - ARROW _SIZE _SIDE ) ;
context . lineTo ( x + ARROW _SIZE _SIDE , limit _y _max - ARROW _SIZE _SIDE ) ;
2023-10-20 15:23:44 +02:00
context . closePath ( ) ;
context . fill ( ) ;
}
// Point is in bounds: Draw a dot
} else {
context . beginPath ( ) ;
context . moveTo ( 0 , 0 ) ;
2023-10-22 12:40:01 +02:00
context . arc ( x , y , 5 , 0 , Math . PI * 2 ) ;
2023-10-20 15:23:44 +02:00
context . closePath ( ) ;
context . fill ( ) ;
}
2023-10-20 13:31:23 +02:00
} ;
function putGrid ( context ) {
2023-10-22 12:40:01 +02:00
let [ limit _x _min , limit _y _min ] = biomeCoordsToCanvasPixelCoords ( limit _heat _min , limit _humidity _min ) ;
let [ limit _x _max , limit _y _max ] = biomeCoordsToCanvasPixelCoords ( limit _heat _max , limit _humidity _max ) ;
context . lineWidth = 2 ;
2023-10-20 13:31:23 +02:00
context . strokeStyle = gridColor ;
2023-10-22 12:40:01 +02:00
for ( let he = 0 ; he <= limit _heat _max ; he += GRID _STEP ) {
let [ x , _ ] = biomeCoordsToCanvasPixelCoords ( he , 0 ) ;
2023-10-20 13:31:23 +02:00
context . beginPath ( ) ;
2023-10-22 12:40:01 +02:00
context . moveTo ( x , limit _y _min ) ;
context . lineTo ( x , limit _y _max ) ;
2023-10-20 13:31:23 +02:00
context . stroke ( ) ;
}
2023-10-22 12:40:01 +02:00
for ( let he = - GRID _STEP ; he >= limit _heat _min ; he -= GRID _STEP ) {
let [ x , _ ] = biomeCoordsToCanvasPixelCoords ( he , 0 ) ;
2023-10-20 13:31:23 +02:00
context . beginPath ( ) ;
2023-10-22 12:40:01 +02:00
context . moveTo ( x , limit _y _min ) ;
context . lineTo ( x , limit _y _max ) ;
2023-10-20 13:31:23 +02:00
context . stroke ( ) ;
}
2023-10-22 12:40:01 +02:00
for ( let hu = 0 ; hu <= limit _humidity _max ; hu += GRID _STEP ) {
let [ _ , y ] = biomeCoordsToCanvasPixelCoords ( 0 , hu ) ;
2023-10-20 13:31:23 +02:00
context . beginPath ( ) ;
2023-10-22 12:40:01 +02:00
context . moveTo ( limit _x _min , y ) ;
context . lineTo ( limit _x _max , y ) ;
2023-10-20 13:31:23 +02:00
context . stroke ( ) ;
}
2023-10-22 12:40:01 +02:00
for ( let hu = - GRID _STEP ; hu >= limit _humidity _min ; hu -= GRID _STEP ) {
let [ _ , y ] = biomeCoordsToCanvasPixelCoords ( 0 , hu ) ;
2023-10-20 13:31:23 +02:00
context . beginPath ( ) ;
2023-10-22 12:40:01 +02:00
context . moveTo ( limit _x _min , y ) ;
context . lineTo ( limit _x _max , y ) ;
2023-10-20 13:31:23 +02:00
context . stroke ( ) ;
}
}
// Cache diagram object for performance boost
let cachedVoronoiDiagram = null ;
2023-10-20 17:22:48 +02:00
function getVoronoiDiagram ( points , recalculate ) {
2023-10-20 13:31:23 +02:00
if ( ( cachedVoronoiDiagram === null ) || recalculate ) {
2023-10-21 17:55:32 +02:00
let vbbox = { xl : limit _heat _min , xr : limit _heat _max , yt : limit _humidity _min , yb : limit _humidity _max } ;
2023-10-20 13:31:23 +02:00
let sites = [ ]
2023-10-20 17:22:48 +02:00
for ( let p of points ) {
2023-10-20 13:31:23 +02:00
sites . push ( biomePointToVoronoiPoint ( p ) ) ;
}
let voronoi = new Voronoi ( ) ;
let diagram = null ;
if ( cachedVoronoiDiagram && recalculate ) {
diagram = cachedVoronoiDiagram ;
// This should improve performance
voronoi . recycle ( diagram ) ;
}
diagram = voronoi . compute ( sites , vbbox ) ;
cachedVoronoiDiagram = diagram ;
return diagram ;
} else {
return cachedVoronoiDiagram ;
}
}
function getDrawContext ( ) {
let canvas = document . getElementById ( "voronoiCanvas" ) ;
2023-10-21 21:24:58 +02:00
if ( canvas . getContext ) {
return canvas . getContext ( "2d" ) ;
} else {
return null ;
}
2023-10-20 13:31:23 +02:00
}
2023-10-21 17:12:43 +02:00
// Clear draw area
function clear ( context ) {
if ( ! context ) {
context = getDrawContext ( ) ;
2023-10-21 21:24:58 +02:00
if ( ! context ) {
return false ;
}
2023-10-21 17:12:43 +02:00
}
context . fillStyle = clearColor ;
2023-10-22 12:40:01 +02:00
context . fillRect ( - DRAW _OFFSET , - DRAW _OFFSET , voronoiCanvas . width + DRAW _OFFSET , voronoiCanvas . height + DRAW _OFFSET ) ;
2023-10-21 21:24:58 +02:00
return true ;
2023-10-21 17:12:43 +02:00
}
2023-10-20 22:03:15 +02:00
function getRenderedPoints ( y ) {
2023-10-20 17:22:48 +02:00
let points = [ ] ;
for ( let p = 0 ; p < biomePoints . length ; p ++ ) {
let point = biomePoints [ p ] ;
if ( y >= point . min _y && y <= point . max _y ) {
points . push ( point ) ;
}
}
2023-10-20 22:03:15 +02:00
return points ;
}
2023-10-21 17:12:43 +02:00
2023-10-21 19:26:24 +02:00
function getBiomeIDFromHTMLElement ( elem ) {
let strID = elem . id ;
if ( strID && strID . startsWith ( "biome_list_element_" ) ) {
let slice = strID . slice ( 19 ) ;
if ( slice ) {
return + slice ;
}
}
return null ;
}
function getSelectedBiomeIDAndElement ( ) {
if ( biomeSelector . selectedIndex === - 1 ) {
return [ null , null ] ;
}
let elem = biomeSelector . options [ biomeSelector . selectedIndex ] ;
let biomeID = getBiomeIDFromHTMLElement ( elem ) ;
if ( biomeID !== null ) {
return [ biomeID , elem ] ;
}
return [ null , null ] ;
}
2023-10-20 22:03:15 +02:00
function draw ( y , recalculate ) {
let context = getDrawContext ( ) ;
2023-10-22 12:40:01 +02:00
let w = voronoiCanvas . width ;
let h = voronoiCanvas . height ;
// shorter function name (for "convert")
let conv = biomeCoordsToCanvasPixelCoords
2023-10-21 21:24:58 +02:00
if ( ! context ) {
if ( ! voronoiCanvas . hidden ) {
voronoiCanvas . hidden = true ;
2023-10-21 21:35:20 +02:00
coordinateDisplay . hidden = true ;
altitudeDisplay . hidden = true ;
2023-10-21 23:04:38 +02:00
rangeDisplay . hidden = true ;
2023-10-21 21:24:58 +02:00
configDiv . hidden = true ;
errorMessage . innerText = "ERROR: Could not get the canvas context which means this tool won't work for you. Maybe your browser does not support the HTML canvas element properly." ;
}
return false ;
}
2023-10-21 17:12:43 +02:00
clear ( context ) ;
// Render a special message if the value range is tiny
2023-10-21 17:55:32 +02:00
if ( ( limit _heat _max - limit _heat _min < 0.01 ) || ( limit _humidity _max - limit _humidity _min < 0.01 ) ) {
2023-10-21 17:12:43 +02:00
context . textAlign = "center" ;
context . fillStyle = "black" ;
context . textBaseline = "middle" ;
context . font = "200% sans-serif" ;
let msg = "Value range is too small." ;
2023-10-22 12:40:01 +02:00
context . fillText ( msg , w / 2 , h / 2 ) ;
2023-10-21 17:12:43 +02:00
drawError = true ;
2023-10-21 21:35:20 +02:00
updateAltitudeText ( ) ;
2023-10-21 21:24:58 +02:00
return true ;
2023-10-21 17:12:43 +02:00
}
2023-10-20 22:03:15 +02:00
let points = getRenderedPoints ( y ) ;
2023-10-21 17:12:43 +02:00
// Render a special message if there are no biomes
if ( points . length === 0 ) {
context . textAlign = "center" ;
context . fillStyle = "black" ;
context . textBaseline = "middle" ;
context . font = "200% sans-serif" ;
let msg ;
if ( biomePoints . length === 0 ) {
msg = "No biomes." ;
} else {
2023-10-21 23:04:38 +02:00
msg = "No biomes in this Y altitude." ;
2023-10-21 17:12:43 +02:00
}
2023-10-22 12:40:01 +02:00
context . fillText ( msg , w / 2 , h / 2 ) ;
2023-10-21 17:12:43 +02:00
drawError = true ;
2023-10-21 21:35:20 +02:00
updateAltitudeText ( ) ;
2023-10-21 21:24:58 +02:00
return true ;
2023-10-21 17:12:43 +02:00
}
drawError = false ;
2023-10-21 21:35:20 +02:00
updateAltitudeText ( ) ;
2023-10-21 17:12:43 +02:00
2023-10-20 17:22:48 +02:00
let diagram = getVoronoiDiagram ( points , recalculate ) ;
2023-10-20 16:31:11 +02:00
// Render cell colors
2023-10-21 13:59:19 +02:00
if ( showCellColors ) {
let colors = cellColors ;
for ( let c = 0 ; c < diagram . cells . length ; c ++ ) {
let cell = diagram . cells [ c ] ;
// We use the biomeID to select a color
let biomeID = cell . site [ biomeIDSymbol ] ;
// This works because the biome ID is a number
let ccol = biomeID % cellColors . length ;
context . fillStyle = cellColors [ ccol ] ;
context . beginPath ( ) ;
for ( let h = 0 ; h < cell . halfedges . length ; h ++ ) {
let halfedge = cell . halfedges [ h ]
let start = halfedge . getStartpoint ( )
let end = halfedge . getEndpoint ( )
2023-10-22 12:40:01 +02:00
let [ cx1 , cy1 ] = conv ( start . x , start . y ) ;
let [ cx2 , cy2 ] = conv ( end . x , end . y ) ;
2023-10-21 13:59:19 +02:00
if ( h === 0 ) {
2023-10-22 12:40:01 +02:00
context . moveTo ( cx1 , cy1 ) ;
2023-10-21 13:59:19 +02:00
} else {
2023-10-22 12:40:01 +02:00
context . lineTo ( cx1 , cy1 ) ;
2023-10-21 13:59:19 +02:00
}
2023-10-22 12:40:01 +02:00
context . lineTo ( cx2 , cy2 ) ;
2023-10-20 13:31:23 +02:00
}
2023-10-21 13:59:19 +02:00
context . closePath ( ) ;
context . fill ( ) ;
2023-10-20 13:31:23 +02:00
}
2023-10-21 13:59:19 +02:00
// If there's only 1 cell, we have to manually colorize it because
// the Voronoi script doesn't return that area in this special case.
if ( points . length === 1 && diagram . cells . length === 1 ) {
// 1 cell means the whole area is filled
context . fillStyle = colors [ points [ 0 ] . id % colors . length ] ;
2023-10-22 12:40:01 +02:00
context . fillRect ( - DRAW _OFFSET , - DRAW _OFFSET , w + DRAW _OFFSET , h + DRAW _OFFSET ) ;
2023-10-21 13:59:19 +02:00
}
} else {
// Use a "neutral" background color for the whole area if cell colors are disabled
context . fillStyle = cellColorNeutral ;
2023-10-22 12:40:01 +02:00
context . fillRect ( - DRAW _OFFSET , - DRAW _OFFSET , w + DRAW _OFFSET , h + DRAW _OFFSET ) ;
2023-10-20 13:31:23 +02:00
}
2023-10-20 17:24:06 +02:00
if ( points . length > 0 ) {
2023-10-21 14:19:42 +02:00
if ( showGrid ) {
2023-10-21 13:59:19 +02:00
putGrid ( context ) ;
}
2023-10-20 17:24:06 +02:00
}
2023-10-20 13:31:23 +02:00
2023-10-20 16:31:11 +02:00
// Render Voronoi cell edges
2023-10-22 12:40:01 +02:00
context . lineWidth = 2.5 ;
2023-10-20 13:31:23 +02:00
for ( let e = 0 ; e < diagram . edges . length ; e ++ ) {
let edge = diagram . edges [ e ] ;
2023-10-20 15:32:14 +02:00
if ( edge . rSite === null ) {
context . strokeStyle = "transparent" ;
} else {
context . strokeStyle = edgeColor ;
}
2023-10-22 12:40:01 +02:00
let [ eax , eay ] = conv ( edge . va . x , edge . va . y ) ;
let [ ebx , eby ] = conv ( edge . vb . x , edge . vb . y ) ;
2023-10-20 13:31:23 +02:00
context . beginPath ( ) ;
2023-10-22 12:40:01 +02:00
context . moveTo ( eax , eay ) ;
context . lineTo ( ebx , eby ) ;
2023-10-20 13:31:23 +02:00
context . closePath ( ) ;
context . stroke ( ) ;
}
2023-10-21 19:26:24 +02:00
let [ selElemID , _ ] = getSelectedBiomeIDAndElement ( ) ;
2023-10-20 20:11:00 +02:00
2023-10-20 16:31:11 +02:00
// Render biome points
2023-10-21 13:59:19 +02:00
if ( showPoints ) {
for ( let point of points ) {
let pointID = point . id ;
// Highlight selected point
if ( selElemID !== null && pointID === selElemID ) {
context . fillStyle = pointColorSelected ;
} else {
context . fillStyle = pointColor ;
}
putPoint ( context , point ) ;
2023-10-20 13:31:23 +02:00
}
2023-10-21 13:59:19 +02:00
}
if ( showNames ) {
// Render biome point names
for ( let point of points ) {
let pointID = point . id ;
// Highlight selected point
if ( selElemID !== null && pointID === selElemID ) {
context . fillStyle = "#FF8888FF" ;
} else {
context . fillStyle = "#FFFFFFAA" ;
}
putPointName ( context , point ) ;
2023-10-21 12:08:24 +02:00
}
2023-10-20 13:31:23 +02:00
}
2023-10-21 21:24:58 +02:00
return true ;
2023-10-20 13:31:23 +02:00
}
function rewriteBiomeSelector ( ) {
biomeSelector . innerHTML = "" ;
for ( let b = 0 ; b < biomePoints . length ; b ++ ) {
let num = b + 1 ;
let newElem = document . createElement ( "option" ) ;
newElem . value = num ;
2023-10-20 20:11:00 +02:00
newElem . id = "biome_list_element_" + biomePoints [ b ] . id ;
2023-10-20 13:44:37 +02:00
let newElemText = document . createTextNode ( biomePoints [ b ] . name ) ;
2023-10-20 13:31:23 +02:00
newElem . append ( newElemText ) ;
biomeSelector . append ( newElem ) ;
}
}
2023-10-20 14:03:45 +02:00
function updateWidgetStates ( ) {
if ( biomePoints . length === 0 || biomeSelector . selectedIndex === - 1 ) {
removeBiomeButton . disabled = "disabled" ;
inputHeat . disabled = "disabled" ;
inputHumidity . disabled = "disabled" ;
2023-10-20 16:12:20 +02:00
inputMinY . disabled = "disabled" ;
inputMaxY . disabled = "disabled" ;
2023-10-20 14:03:45 +02:00
} else {
removeBiomeButton . disabled = "" ;
inputHeat . disabled = "" ;
inputHumidity . disabled = "" ;
2023-10-20 16:12:20 +02:00
inputMinY . disabled = "" ;
inputMaxY . disabled = "" ;
2023-10-20 14:18:22 +02:00
if ( biomeSelector . selectedIndex !== - 1 ) {
let selected = biomeSelector . options [ biomeSelector . selectedIndex ] ;
let point = biomePoints [ biomeSelector . selectedIndex ] ;
inputHeat . value = point . heat ;
inputHumidity . value = point . humidity ;
inputMinY . value = point . min _y ;
inputMaxY . value = point . max _y ;
}
2023-10-20 14:03:45 +02:00
}
2023-10-21 17:55:32 +02:00
inputNoiseHeatOffset . value = noises . heat . offset ;
inputNoiseHeatScale . value = noises . heat . scale ;
inputNoiseHeatOctaves . value = noises . heat . octaves ;
inputNoiseHeatPersistence . value = noises . heat . persistence ;
inputNoiseHumidityOffset . value = noises . humidity . offset ;
inputNoiseHumidityScale . value = noises . humidity . scale ;
inputNoiseHumidityOctaves . value = noises . humidity . octaves ;
inputNoiseHumidityPersistence . value = noises . humidity . persistence ;
2023-10-20 14:03:45 +02:00
}
2023-10-20 13:31:23 +02:00
biomeSelector . onchange = function ( ) {
2023-10-20 17:22:48 +02:00
draw ( getViewY ( ) , false ) ;
2023-10-20 14:03:45 +02:00
if ( biomeSelector . selectedIndex !== - 1 ) {
let selected = biomeSelector . options [ biomeSelector . selectedIndex ] ;
let point = biomePoints [ biomeSelector . selectedIndex ] ;
inputHeat . value = point . heat ;
inputHumidity . value = point . humidity ;
2023-10-20 14:18:22 +02:00
inputMinY . value = point . min _y ;
inputMaxY . value = point . max _y ;
2023-10-20 14:03:45 +02:00
}
updateWidgetStates ( ) ;
2023-10-20 13:31:23 +02:00
}
2023-10-20 14:18:22 +02:00
function onChangeBiomeValueWidget ( pointField , value ) {
if ( value === null ) {
return ;
}
if ( biomeSelector . selectedIndex === - 1 ) {
return ;
}
let selected = biomeSelector . options [ biomeSelector . selectedIndex ] ;
if ( selected === null ) {
return ;
}
let point = biomePoints [ biomeSelector . selectedIndex ] ;
2023-10-21 17:12:43 +02:00
point [ pointField ] = value ;
2023-10-20 14:18:22 +02:00
point . name = generateBiomeName ( point . heat , point . humidity ) ;
selected . innerText = point . name ;
2023-10-20 17:22:48 +02:00
draw ( getViewY ( ) , true ) ;
2023-10-20 14:18:22 +02:00
}
2023-10-21 21:00:51 +02:00
inputHeat . oninput = function ( ) {
2023-10-21 17:12:43 +02:00
onChangeBiomeValueWidget ( "heat" , + this . value ) ;
2023-10-20 14:18:22 +02:00
}
2023-10-21 21:00:51 +02:00
inputHumidity . oninput = function ( ) {
2023-10-21 17:12:43 +02:00
onChangeBiomeValueWidget ( "humidity" , + this . value ) ;
2023-10-20 14:18:22 +02:00
}
2023-10-21 21:00:51 +02:00
inputMinY . oninput = function ( ) {
2023-10-21 17:12:43 +02:00
onChangeBiomeValueWidget ( "min_y" , + this . value ) ;
2023-10-20 16:12:20 +02:00
}
2023-10-21 21:00:51 +02:00
inputMaxY . oninput = function ( ) {
2023-10-21 17:12:43 +02:00
onChangeBiomeValueWidget ( "max_y" , + this . value ) ;
2023-10-20 16:12:20 +02:00
}
2023-10-21 21:00:51 +02:00
inputViewY . oninput = function ( ) {
2023-10-20 17:22:48 +02:00
draw ( getViewY ( ) , true ) ;
2023-10-21 21:35:20 +02:00
updateAltitudeText ( ) ;
}
function updateAltitudeText ( ) {
2023-10-21 23:04:38 +02:00
altitudeDisplay . innerHTML = "showing diagram for altitude Y=<span class='statAltitude'>" + inputViewY . value + "</span>" ;
2023-10-20 17:22:48 +02:00
}
2023-10-20 14:18:22 +02:00
2023-10-20 13:31:23 +02:00
addBiomeButton . onclick = function ( ) {
2023-10-21 17:55:32 +02:00
let he = Math . round ( limit _heat _min + Math . random ( ) * ( limit _heat _max - limit _heat _min ) ) ;
let hu = Math . round ( limit _humidity _min + Math . random ( ) * ( limit _humidity _max - limit _humidity _min ) ) ;
2023-10-20 13:44:37 +02:00
let newPoint = {
2023-10-20 16:31:11 +02:00
id : lastBiomeID ,
2023-10-20 13:44:37 +02:00
name : generateBiomeName ( he , hu ) ,
heat : he ,
2023-10-21 17:55:32 +02:00
humidity : hu ,
2023-10-20 14:03:45 +02:00
min _y : MIN _Y _DEFAULT ,
max _y : MAX _Y _DEFAULT ,
2023-10-20 13:44:37 +02:00
} ;
biomePoints . push ( newPoint ) ;
2023-10-20 13:31:23 +02:00
let num = biomePoints . length
let newElem = document . createElement ( "option" ) ;
2023-10-20 17:22:48 +02:00
newElem . id = "biome_list_element_" + lastBiomeID ;
2023-10-20 13:31:23 +02:00
newElem . value = "" + num ;
2023-10-20 16:31:11 +02:00
2023-10-20 13:44:37 +02:00
let newElemText = document . createTextNode ( newPoint . name ) ;
2023-10-20 13:31:23 +02:00
newElem . append ( newElemText ) ;
biomeSelector . append ( newElem ) ;
newElem . selected = "selected" ;
2023-10-20 17:22:48 +02:00
draw ( getViewY ( ) , true ) ;
2023-10-20 14:03:45 +02:00
updateWidgetStates ( ) ;
2023-10-20 16:31:11 +02:00
lastBiomeID ++ ;
2023-10-20 13:31:23 +02:00
}
removeBiomeButton . onclick = function ( ) {
if ( biomeSelector . selectedOptions . length === 0 ) {
return ;
}
let firstIndex = null ;
for ( let o = 0 ; o < biomeSelector . selectedOptions . length ; o ++ ) {
let opt = biomeSelector . selectedOptions [ o ]
let index = opt . index
if ( firstIndex === null ) {
firstIndex = index ;
}
biomePoints . splice ( index , 1 ) ;
opt . remove ( ) ;
}
if ( firstIndex !== null && biomePoints . length > 0 ) {
let newIndex = firstIndex - 1 ;
if ( newIndex < 0 ) {
newIndex = 0 ;
}
biomeSelector . options [ newIndex ] . selected = "selected" ;
}
2023-10-20 17:22:48 +02:00
draw ( getViewY ( ) , true ) ;
2023-10-20 14:03:45 +02:00
updateWidgetStates ( ) ;
2023-10-20 13:31:23 +02:00
}
2023-10-20 16:31:11 +02:00
2023-10-20 22:03:15 +02:00
function selectPoint ( point ) {
for ( let elem of biomeSelector . options ) {
let strID = elem . id ;
let elemID = null ;
2023-10-21 19:26:24 +02:00
let biomeID = getBiomeIDFromHTMLElement ( elem ) ;
if ( biomeID !== null ) {
if ( point . id === biomeID ) {
2023-10-21 00:57:25 +02:00
if ( elem . selected ) {
2023-10-21 19:26:24 +02:00
return [ true , true ] ;
2023-10-21 00:57:25 +02:00
}
2023-10-20 22:03:15 +02:00
elem . selected = "selected" ;
draw ( getViewY ( ) , true ) ;
updateWidgetStates ( ) ;
2023-10-21 00:57:25 +02:00
return [ true , false ] ;
2023-10-20 22:03:15 +02:00
}
}
}
2023-10-21 00:57:25 +02:00
return [ false , false ] ;
}
function getDistance ( x1 , y1 , x2 , y2 ) {
return Math . sqrt ( ( x2 - x1 ) * * 2 + ( y2 - y1 ) * * 2 ) ;
2023-10-20 22:03:15 +02:00
}
2023-10-21 01:55:49 +02:00
function canvasPixelCoordsToBiomeCoords ( x , y ) {
2023-10-21 17:55:32 +02:00
let w = ( voronoiCanvas . width / ( limit _heat _max - limit _heat _min ) ) ;
let h = ( voronoiCanvas . height / ( limit _humidity _max - limit _humidity _min ) ) ;
let heat = Math . round ( ( x + limit _heat _min * w ) / w ) ;
2023-10-22 12:53:47 +02:00
// This also flips the Y axis
let humidity = limit _humidity _min + ( limit _humidity _max - ( Math . round ( ( y + limit _humidity _min * h ) / h ) ) ) ;
2023-10-21 01:55:49 +02:00
return [ heat , humidity ] ;
}
function biomeCoordsToCanvasPixelCoords ( heat , humidity ) {
2023-10-21 17:55:32 +02:00
let w = ( voronoiCanvas . width / ( limit _heat _max - limit _heat _min ) ) ;
let h = ( voronoiCanvas . height / ( limit _humidity _max - limit _humidity _min ) ) ;
let pixelX = heat * w - limit _heat _min * w ;
2023-10-22 12:53:47 +02:00
// This also flips the Y axis
let pixelY = voronoiCanvas . height - ( humidity * h - limit _humidity _min * h ) ;
2023-10-21 01:55:49 +02:00
return [ pixelX , pixelY ] ;
}
2023-10-20 22:03:15 +02:00
function getNearestPointFromCanvasPos ( x , y , maxDist ) {
let nearestPoint = null ;
let nearestDist = null ;
let points = getRenderedPoints ( getViewY ( ) ) ;
for ( let i = 0 ; i < points . length ; i ++ ) {
let point = points [ i ] ;
2023-10-21 01:55:49 +02:00
let [ pixelX , pixelY ] = biomeCoordsToCanvasPixelCoords ( point . heat , point . humidity ) ;
let dist = getDistance ( x , y , pixelX , pixelY ) ;
2023-10-20 22:03:15 +02:00
if ( nearestPoint === null ) {
nearestPoint = point ;
nearestDist = dist ;
} else if ( dist < nearestDist ) {
nearestPoint = point ;
nearestDist = dist ;
}
}
if ( nearestDist < maxDist ) {
return nearestPoint ;
} else {
return null ;
}
}
let mouseIsDown = false ;
2023-10-21 00:57:25 +02:00
let dragDropPointID = null ;
2023-10-21 01:08:35 +02:00
function updatePointWhenDragged ( pointID ) {
2023-10-21 17:12:43 +02:00
if ( pointID !== null && ! drawError ) {
2023-10-21 00:57:25 +02:00
let selectedPoint = null ;
let points = getRenderedPoints ( getViewY ( ) ) ;
for ( let i = 0 ; i < points . length ; i ++ ) {
if ( points [ i ] . id === dragDropPointID ) {
selectedPoint = points [ i ] ;
2023-10-21 01:55:49 +02:00
let [ newHeat , newHumidity ] = canvasPixelCoordsToBiomeCoords ( event . offsetX , event . offsetY ) ;
2023-10-21 00:57:25 +02:00
selectedPoint . heat = newHeat ;
selectedPoint . humidity = newHumidity ;
2023-10-21 01:08:35 +02:00
selectedPoint . name = generateBiomeName ( newHeat , newHumidity ) ;
2023-10-21 00:57:25 +02:00
draw ( getViewY ( ) , true ) ;
updateWidgetStates ( ) ;
2023-10-21 19:26:24 +02:00
let [ elemID , elem ] = getSelectedBiomeIDAndElement ( ) ;
if ( elemID !== null && points [ i ] . id === elemID ) {
elem . innerText = selectedPoint . name ;
break ;
2023-10-21 01:08:35 +02:00
}
return ;
2023-10-21 00:57:25 +02:00
}
}
}
2023-10-21 01:08:35 +02:00
}
2023-10-21 17:12:43 +02:00
function updateCoordinateDisplay ( pixelX , pixelY ) {
// show coordinates
let [ heat , humidity ] = canvasPixelCoordsToBiomeCoords ( pixelX , pixelY ) ;
if ( ! drawError ) {
2023-10-21 23:04:38 +02:00
let html = "cursor coordinates: heat=<span class='statHeat'>" + heat + "</span>; humidity=<span class='statHumidity'>" + humidity + "</span>" ;
2023-10-21 17:12:43 +02:00
coordinateDisplay . innerHTML = html ;
} else {
coordinateDisplay . innerHTML = " " ;
}
}
2023-10-21 19:26:24 +02:00
function updateDragDropCursorStatus ( ) {
if ( drawError || ! showPoints ) {
voronoiCanvas . style . cursor = "auto" ;
return
}
let nearest = getNearestPointFromCanvasPos ( event . offsetX , event . offsetY , POINT _SELECT _DISTANCE ) ;
if ( nearest !== null ) {
let [ id , elem ] = getSelectedBiomeIDAndElement ( ) ;
if ( id !== null && nearest . id === id ) {
voronoiCanvas . style . cursor = "grab" ;
} else {
voronoiCanvas . style . cursor = "crosshair" ;
}
} else {
voronoiCanvas . style . cursor = "auto" ;
}
}
2023-10-21 01:08:35 +02:00
voronoiCanvas . onmousemove = function ( event ) {
2023-10-21 01:48:45 +02:00
// drag-n-drop
2023-10-21 01:08:35 +02:00
if ( mouseIsDown ) {
updatePointWhenDragged ( dragDropPointID ) ;
}
2023-10-21 17:12:43 +02:00
updateCoordinateDisplay ( event . offsetX , event . offsetY ) ;
2023-10-21 19:26:24 +02:00
updateDragDropCursorStatus ( ) ;
2023-10-21 01:55:49 +02:00
}
voronoiCanvas . onmouseenter = function ( event ) {
2023-10-21 17:12:43 +02:00
updateCoordinateDisplay ( event . offsetX , event . offsetY ) ;
2023-10-21 19:26:24 +02:00
updateDragDropCursorStatus ( ) ;
2023-10-21 01:08:35 +02:00
}
2023-10-21 01:55:49 +02:00
2023-10-21 01:08:35 +02:00
voronoiCanvas . onmousedown = function ( event ) {
2023-10-21 01:48:45 +02:00
// select point by clicking.
// initiate drag-n-drop if already selected.
2023-10-21 01:08:35 +02:00
mouseIsDown = true ;
2023-10-21 13:59:19 +02:00
if ( ! showPoints ) {
// Points need to be shown for drag-n-drop to work
return ;
}
2023-10-21 19:26:24 +02:00
let nearest = getNearestPointFromCanvasPos ( event . offsetX , event . offsetY , POINT _SELECT _DISTANCE ) ;
2023-10-21 01:08:35 +02:00
if ( nearest !== null ) {
let success , alreadySelected
[ success , alreadySelected ] = selectPoint ( nearest ) ;
if ( alreadySelected ) {
dragDropPointID = nearest . id ;
}
2023-10-21 19:26:24 +02:00
updateDragDropCursorStatus ( ) ;
2023-10-21 01:08:35 +02:00
}
}
voronoiCanvas . onmouseup = function ( event ) {
2023-10-21 01:48:45 +02:00
// end drag-n-drop
2023-10-21 01:08:35 +02:00
updatePointWhenDragged ( dragDropPointID ) ;
mouseIsDown = false ;
2023-10-21 00:57:25 +02:00
dragDropPointID = null ;
2023-10-20 22:03:15 +02:00
}
voronoiCanvas . onmouseleave = function ( ) {
2023-10-21 01:48:45 +02:00
// end drag-n-drop
2023-10-20 22:03:15 +02:00
mouseIsDown = false ;
2023-10-21 00:57:25 +02:00
dragDropPointID = null ;
2023-10-21 01:48:45 +02:00
coordinateDisplay . innerHTML = " " ;
2023-10-20 22:03:15 +02:00
}
2023-10-21 13:59:19 +02:00
inputCheckboxNames . onchange = function ( ) {
showNames = this . checked ;
draw ( getViewY ( ) , true ) ;
}
inputCheckboxPoints . onchange = function ( ) {
showPoints = this . checked ;
draw ( getViewY ( ) , true ) ;
}
inputCheckboxCellColors . onchange = function ( ) {
showCellColors = this . checked ;
draw ( getViewY ( ) , true ) ;
}
inputCheckboxGrid . onchange = function ( ) {
showGrid = this . checked ;
draw ( getViewY ( ) , true ) ;
}
2023-10-21 21:00:51 +02:00
inputNoiseHeatScale . oninput = function ( ) {
2023-10-21 17:55:32 +02:00
noises . heat . scale = + this . value ;
clear ( ) ;
updateAreaVars ( ) ;
draw ( getViewY ( ) , true ) ;
}
2023-10-21 21:00:51 +02:00
inputNoiseHeatOffset . oninput = function ( ) {
2023-10-21 17:55:32 +02:00
noises . heat . offset = + this . value ;
clear ( ) ;
updateAreaVars ( ) ;
draw ( getViewY ( ) , true ) ;
}
2023-10-21 21:00:51 +02:00
inputNoiseHeatPersistence . oninput = function ( ) {
2023-10-21 17:55:32 +02:00
noises . heat . persistence = + this . value ;
2023-10-21 17:12:43 +02:00
clear ( ) ;
updateAreaVars ( ) ;
draw ( getViewY ( ) , true ) ;
}
2023-10-21 21:00:51 +02:00
inputNoiseHeatOctaves . oninput = function ( ) {
2023-10-21 17:55:32 +02:00
noises . heat . octaves = + this . value ;
2023-10-21 17:12:43 +02:00
clear ( ) ;
updateAreaVars ( ) ;
draw ( getViewY ( ) , true ) ;
}
2023-10-21 21:00:51 +02:00
inputNoiseHumidityScale . oninput = function ( ) {
2023-10-21 17:55:32 +02:00
noises . humidity . scale = + this . value ;
2023-10-21 17:12:43 +02:00
clear ( ) ;
updateAreaVars ( ) ;
draw ( getViewY ( ) , true ) ;
}
2023-10-21 21:00:51 +02:00
inputNoiseHumidityOffset . oninput = function ( ) {
2023-10-21 17:55:32 +02:00
noises . humidity . offset = + this . value ;
clear ( ) ;
updateAreaVars ( ) ;
draw ( getViewY ( ) , true ) ;
}
2023-10-21 21:00:51 +02:00
inputNoiseHumidityPersistence . oninput = function ( ) {
2023-10-21 17:55:32 +02:00
noises . humidity . persistence = + this . value ;
clear ( ) ;
updateAreaVars ( ) ;
draw ( getViewY ( ) , true ) ;
}
2023-10-21 21:00:51 +02:00
inputNoiseHumidityOctaves . oninput = function ( ) {
2023-10-21 17:55:32 +02:00
noises . humidity . octaves = + this . value ;
2023-10-21 17:12:43 +02:00
clear ( ) ;
updateAreaVars ( ) ;
draw ( getViewY ( ) , true ) ;
}
inputNoiseReset . onclick = function ( ) {
2023-10-21 17:55:32 +02:00
noises . heat . offset = NOISE _OFFSET _DEFAULT ;
noises . heat . scale = NOISE _SCALE _DEFAULT ;
noises . heat . octaves = NOISE _OCTAVES _DEFAULT ;
noises . heat . persistence = NOISE _PERSISTENCE _DEFAULT ;
noises . heat . absvalue = NOISE _ABSVALUE _DEFAULT ;
inputNoiseHeatOffset . value = noises . heat . offset ;
inputNoiseHeatScale . value = noises . heat . scale ;
inputNoiseHeatOctaves . value = noises . heat . octaves ;
inputNoiseHeatPersistence . value = noises . heat . persistence ;
noises . humidity . offset = NOISE _OFFSET _DEFAULT ;
noises . humidity . scale = NOISE _SCALE _DEFAULT ;
noises . humidity . octaves = NOISE _OCTAVES _DEFAULT ;
noises . humidity . persistence = NOISE _PERSISTENCE _DEFAULT ;
noises . humidity . absvalue = NOISE _ABSVALUE _DEFAULT ;
inputNoiseHumidityOffset . value = noises . humidity . offset ;
inputNoiseHumidityScale . value = noises . humidity . scale ;
inputNoiseHumidityOctaves . value = noises . humidity . octaves ;
inputNoiseHumidityPersistence . value = noises . humidity . persistence ;
2023-10-21 17:12:43 +02:00
clear ( ) ;
updateAreaVars ( ) ;
draw ( getViewY ( ) , true ) ;
}
2023-10-21 13:59:19 +02:00
function checkboxVarsInit ( ) {
showNames = inputCheckboxNames . checked ;
showPoints = inputCheckboxPoints . checked ;
showCellColors = inputCheckboxCellColors . checked ;
showGrid = inputCheckboxGrid . checked ;
}
2023-10-20 16:31:11 +02:00
2023-10-22 02:11:36 +02:00
function toggleConfigSectionDisplay ( headerLink , container ) {
if ( container . style . display !== "none" ) {
headerLink . innerText = "▶" ;
container . style . display = "none" ;
} else {
headerLink . innerText = "▼" ;
container . style . display = "block" ;
}
}
biomeConfigHeaderLink . onclick = function ( ) {
toggleConfigSectionDisplay ( this , biomeConfigContainer ) ;
}
viewConfigHeaderLink . onclick = function ( ) {
toggleConfigSectionDisplay ( this , viewConfigContainer ) ;
}
noiseConfigHeaderLink . onclick = function ( ) {
toggleConfigSectionDisplay ( this , noiseConfigContainer ) ;
}
2023-10-23 01:46:24 +02:00
function unhideContent ( ) {
mainContentContainer . hidden = false ;
noscriptContainer . hidden = true ;
}
2023-10-21 13:59:19 +02:00
window . addEventListener ( "load" , checkboxVarsInit ) ;
2023-10-20 17:22:48 +02:00
window . addEventListener ( "load" , function ( ) {
draw ( getViewY ( ) , true ) ;
} )
2023-10-20 16:31:11 +02:00
window . addEventListener ( "load" , rewriteBiomeSelector ) ;
window . addEventListener ( "load" , updateWidgetStates ) ;
2023-10-21 21:35:20 +02:00
window . addEventListener ( "load" , updateAltitudeText ) ;
2023-10-23 01:46:24 +02:00
window . addEventListener ( "load" , unhideContent ) ;