2023-10-20 13:31:23 +02:00
|
|
|
"use strict";
|
2023-10-20 14:03:45 +02:00
|
|
|
|
2023-10-20 14:39:49 +02:00
|
|
|
const MIN_Y_DEFAULT = -31000
|
|
|
|
const MAX_Y_DEFAULT = 31000
|
|
|
|
const LIMIT_MIN = -37.5
|
|
|
|
const LIMIT_MAX = 137.5
|
|
|
|
const DRAW_MIN = LIMIT_MIN - 10
|
|
|
|
const DRAW_MAX = LIMIT_MAX + 10
|
|
|
|
const GRID_STEP = 10
|
|
|
|
|
2023-10-20 16:31:11 +02:00
|
|
|
let lastBiomeID = 0;
|
2023-10-20 14:03:45 +02:00
|
|
|
|
2023-10-20 13:31:23 +02:00
|
|
|
let biomePoints = [
|
2023-10-20 16:31:11 +02:00
|
|
|
{id: 0, name: generateBiomeName(50, 50), heat:50, humidity:50, min_y: MIN_Y_DEFAULT, max_y: MAX_Y_DEFAULT},
|
2023-10-20 13:31:23 +02:00
|
|
|
];
|
2023-10-20 16:31:11 +02:00
|
|
|
lastBiomeID++;
|
2023-10-20 13:31:23 +02:00
|
|
|
|
2023-10-20 17:22:48 +02:00
|
|
|
function getViewY() {
|
|
|
|
if (!inputViewY) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return inputViewY.value;
|
|
|
|
}
|
|
|
|
|
2023-10-20 13:31:23 +02:00
|
|
|
// FOREST-16 palette, plus black
|
|
|
|
const pointColor = "#913636";
|
|
|
|
const pointColorSelected = "#e19696";
|
|
|
|
const edgeColor = "#0f2c2e";
|
|
|
|
const gridColor = "#00000040";
|
|
|
|
const axisColor = "#000000";
|
|
|
|
const cellColors = [
|
|
|
|
"#64988e",
|
|
|
|
"#3d7085",
|
|
|
|
"#345644",
|
|
|
|
"#6b7f5c",
|
|
|
|
"#b0b17c",
|
|
|
|
"#e1c584",
|
|
|
|
"#c89660",
|
|
|
|
"#ad5f52",
|
|
|
|
"#692f11",
|
|
|
|
"#89542f",
|
|
|
|
"#796e63",
|
|
|
|
"#a17d5e",
|
|
|
|
"#b4a18f",
|
|
|
|
"#ecddba",
|
|
|
|
];
|
|
|
|
|
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) {
|
|
|
|
let newPoint = { x: point.heat, y: point.humidity }
|
|
|
|
return newPoint;
|
|
|
|
}
|
|
|
|
function voronoiPointToBiomePoint(point) {
|
|
|
|
let newPoint = { heat: point.x, humidity: point.y }
|
|
|
|
return newPoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
function putPoint(context, point) {
|
2023-10-20 15:23:44 +02:00
|
|
|
const ARROW_SIZE_SIDE = 2.25;
|
|
|
|
const ARROW_SIZE_CORNER = 2.5;
|
|
|
|
let x = point.heat
|
|
|
|
let y = point.humidity
|
|
|
|
// Point is out of bounds: Draw an arrow at the border
|
|
|
|
if (x < LIMIT_MIN || x > LIMIT_MAX || y < LIMIT_MIN || y > LIMIT_MAX) {
|
|
|
|
context.beginPath();
|
|
|
|
// top left corner
|
|
|
|
if (x < LIMIT_MIN && y < LIMIT_MIN) {
|
|
|
|
context.moveTo(LIMIT_MIN, LIMIT_MIN);
|
|
|
|
context.lineTo(LIMIT_MIN + ARROW_SIZE_CORNER, LIMIT_MIN);
|
|
|
|
context.lineTo(LIMIT_MIN, LIMIT_MIN + ARROW_SIZE_CORNER);
|
|
|
|
context.closePath();
|
|
|
|
context.fill();
|
|
|
|
// top right corner
|
|
|
|
} else if (x > LIMIT_MAX && y < LIMIT_MIN) {
|
|
|
|
context.moveTo(LIMIT_MAX, LIMIT_MIN);
|
|
|
|
context.lineTo(LIMIT_MAX - ARROW_SIZE_CORNER, LIMIT_MIN);
|
|
|
|
context.lineTo(LIMIT_MAX, LIMIT_MIN + ARROW_SIZE_CORNER);
|
|
|
|
context.closePath();
|
|
|
|
context.fill();
|
|
|
|
// bottom left corner
|
|
|
|
} else if (x < LIMIT_MIN && y > LIMIT_MAX) {
|
|
|
|
context.moveTo(LIMIT_MIN, LIMIT_MAX);
|
|
|
|
context.lineTo(LIMIT_MIN + ARROW_SIZE_CORNER, LIMIT_MAX);
|
|
|
|
context.lineTo(LIMIT_MIN, LIMIT_MAX - ARROW_SIZE_CORNER);
|
|
|
|
context.closePath();
|
|
|
|
context.fill();
|
|
|
|
// top right corner
|
|
|
|
} else if (x > LIMIT_MAX && y > LIMIT_MAX) {
|
|
|
|
context.moveTo(LIMIT_MAX, LIMIT_MAX);
|
|
|
|
context.lineTo(LIMIT_MAX - ARROW_SIZE_CORNER, LIMIT_MAX);
|
|
|
|
context.lineTo(LIMIT_MAX, LIMIT_MAX - ARROW_SIZE_CORNER);
|
|
|
|
context.closePath();
|
|
|
|
context.fill();
|
|
|
|
// left side
|
|
|
|
} else if (x < LIMIT_MIN) {
|
|
|
|
context.moveTo(LIMIT_MIN, y);
|
|
|
|
context.lineTo(LIMIT_MIN + ARROW_SIZE_SIDE, y + ARROW_SIZE_SIDE);
|
|
|
|
context.lineTo(LIMIT_MIN + ARROW_SIZE_SIDE, y - ARROW_SIZE_SIDE);
|
|
|
|
context.closePath();
|
|
|
|
context.fill();
|
|
|
|
// right side
|
|
|
|
} else if (x > LIMIT_MAX) {
|
|
|
|
context.moveTo(LIMIT_MAX, y);
|
|
|
|
context.lineTo(LIMIT_MAX - ARROW_SIZE_SIDE, y + ARROW_SIZE_SIDE);
|
|
|
|
context.lineTo(LIMIT_MAX - ARROW_SIZE_SIDE, y - ARROW_SIZE_SIDE);
|
|
|
|
context.closePath();
|
|
|
|
context.fill();
|
|
|
|
// top side
|
|
|
|
} else if (y < LIMIT_MIN) {
|
|
|
|
context.moveTo(x, LIMIT_MIN);
|
|
|
|
context.lineTo(x - ARROW_SIZE_SIDE, LIMIT_MIN + ARROW_SIZE_SIDE);
|
|
|
|
context.lineTo(x + ARROW_SIZE_SIDE, LIMIT_MIN + ARROW_SIZE_SIDE);
|
|
|
|
context.closePath();
|
|
|
|
context.fill();
|
|
|
|
// bottom side
|
|
|
|
} else if (y > LIMIT_MAX) {
|
|
|
|
context.moveTo(x, LIMIT_MAX);
|
|
|
|
context.lineTo(x - ARROW_SIZE_SIDE, LIMIT_MAX - ARROW_SIZE_SIDE);
|
|
|
|
context.lineTo(x + ARROW_SIZE_SIDE, LIMIT_MAX - ARROW_SIZE_SIDE);
|
|
|
|
context.closePath();
|
|
|
|
context.fill();
|
|
|
|
}
|
|
|
|
// Point is in bounds: Draw a dot
|
|
|
|
} else {
|
|
|
|
context.beginPath();
|
|
|
|
context.moveTo(0, 0);
|
|
|
|
context.arc(x, y, 2, 0, Math.PI * 2);
|
|
|
|
context.closePath();
|
|
|
|
context.fill();
|
|
|
|
}
|
2023-10-20 13:31:23 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
function putGrid(context) {
|
|
|
|
context.lineWidth = 0.5;
|
|
|
|
context.strokeStyle = gridColor;
|
|
|
|
for (let x=0; x<=LIMIT_MAX; x+=GRID_STEP) {
|
|
|
|
context.beginPath();
|
|
|
|
context.moveTo(x, LIMIT_MIN);
|
|
|
|
context.lineTo(x, LIMIT_MAX);
|
|
|
|
context.stroke();
|
|
|
|
}
|
|
|
|
for (let x=-GRID_STEP; x>=LIMIT_MIN; x-=GRID_STEP) {
|
|
|
|
context.beginPath();
|
|
|
|
context.moveTo(x, LIMIT_MIN);
|
|
|
|
context.lineTo(x, LIMIT_MAX);
|
|
|
|
context.stroke();
|
|
|
|
}
|
|
|
|
for (let y=0; y<=LIMIT_MAX; y+=GRID_STEP) {
|
|
|
|
context.beginPath();
|
|
|
|
context.moveTo(LIMIT_MIN, y);
|
|
|
|
context.lineTo(LIMIT_MAX, y);
|
|
|
|
context.stroke();
|
|
|
|
}
|
|
|
|
for (let y=-GRID_STEP; y>=LIMIT_MIN; y-=GRID_STEP) {
|
|
|
|
context.beginPath();
|
|
|
|
context.moveTo(LIMIT_MIN, y);
|
|
|
|
context.lineTo(LIMIT_MAX, y);
|
|
|
|
context.stroke();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function putAxes(context) {
|
|
|
|
context.lineWidth = 0.75;
|
|
|
|
// heat axis (horizontal)
|
|
|
|
context.beginPath();
|
|
|
|
context.moveTo(LIMIT_MIN,0)
|
|
|
|
context.lineTo(LIMIT_MAX,0)
|
|
|
|
context.closePath();
|
|
|
|
context.stroke();
|
|
|
|
|
|
|
|
// humidity axis ()
|
|
|
|
context.beginPath();
|
|
|
|
context.moveTo(0,LIMIT_MIN)
|
|
|
|
context.lineTo(0,LIMIT_MAX)
|
|
|
|
context.closePath();
|
|
|
|
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-20 15:32:14 +02:00
|
|
|
let vbbox = {xl: LIMIT_MIN, xr: LIMIT_MAX, yt: LIMIT_MIN, yb: LIMIT_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");
|
|
|
|
// TODO: Check for getContext support of browser
|
2023-10-20 16:31:11 +02:00
|
|
|
return canvas.getContext("2d");
|
2023-10-20 13:31:23 +02:00
|
|
|
}
|
|
|
|
function drawInit() {
|
|
|
|
let context = getDrawContext();
|
|
|
|
context.scale(voronoiCanvas.width/(LIMIT_MAX-LIMIT_MIN), voronoiCanvas.height/(LIMIT_MAX-LIMIT_MIN));
|
|
|
|
context.translate(-LIMIT_MIN, -LIMIT_MIN);
|
|
|
|
}
|
2023-10-20 17:22:48 +02:00
|
|
|
function draw(y, recalculate) {
|
2023-10-20 13:31:23 +02:00
|
|
|
let context = getDrawContext();
|
2023-10-20 16:31:11 +02:00
|
|
|
// Clear draw area
|
2023-10-20 13:31:23 +02:00
|
|
|
context.fillStyle = "#FFFFFF";
|
|
|
|
context.fillRect(DRAW_MIN, DRAW_MIN, DRAW_MAX-DRAW_MIN, DRAW_MAX-DRAW_MIN);
|
2023-10-20 16:31:11 +02:00
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let diagram = getVoronoiDiagram(points, recalculate);
|
2023-10-20 16:31:11 +02:00
|
|
|
|
|
|
|
// Render cell colors
|
2023-10-20 13:31:23 +02:00
|
|
|
let colors = cellColors;
|
|
|
|
for (let c=0; c<diagram.cells.length; c++) {
|
|
|
|
let cell = diagram.cells[c]
|
|
|
|
let ccol = c % colors.length;
|
|
|
|
context.fillStyle = colors[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()
|
|
|
|
if (h === 0) {
|
|
|
|
context.moveTo(start.x, start.y);
|
|
|
|
} else {
|
|
|
|
context.lineTo(start.x, start.y);
|
|
|
|
}
|
|
|
|
context.lineTo(end.x, end.y);
|
|
|
|
}
|
|
|
|
context.closePath();
|
|
|
|
context.fill();
|
|
|
|
}
|
2023-10-20 16:31:11 +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.
|
2023-10-20 17:22:48 +02:00
|
|
|
if (points.length === 1 && diagram.cells.length === 1) {
|
2023-10-20 16:31:11 +02:00
|
|
|
// 1 cell means the whole area is filled
|
2023-10-20 13:31:23 +02:00
|
|
|
context.fillStyle = colors[0];
|
|
|
|
context.fillRect(DRAW_MIN, DRAW_MIN, DRAW_MAX-DRAW_MIN, DRAW_MAX-DRAW_MIN);
|
|
|
|
}
|
|
|
|
|
2023-10-20 17:24:06 +02:00
|
|
|
if (points.length > 0) {
|
|
|
|
//putAxes(context);
|
|
|
|
putGrid(context);
|
|
|
|
}
|
2023-10-20 13:31:23 +02:00
|
|
|
|
2023-10-20 16:31:11 +02:00
|
|
|
// Render Voronoi cell edges
|
2023-10-20 13:31:23 +02:00
|
|
|
context.lineWidth = 2;
|
|
|
|
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-20 13:31:23 +02:00
|
|
|
context.beginPath();
|
|
|
|
context.moveTo(edge.va.x, edge.va.y);
|
|
|
|
context.lineTo(edge.vb.x, edge.vb.y);
|
|
|
|
context.closePath();
|
|
|
|
context.stroke();
|
|
|
|
}
|
|
|
|
|
2023-10-20 16:31:11 +02:00
|
|
|
// Render biome points
|
2023-10-20 17:22:48 +02:00
|
|
|
for (let p=0; p<points.length; p++) {
|
2023-10-20 13:31:23 +02:00
|
|
|
if (p === biomeSelector.selectedIndex) {
|
|
|
|
context.fillStyle = pointColorSelected;
|
|
|
|
} else {
|
|
|
|
context.fillStyle = pointColor;
|
|
|
|
}
|
2023-10-20 17:22:48 +02:00
|
|
|
putPoint(context, points[p]);
|
2023-10-20 13:31:23 +02:00
|
|
|
}
|
|
|
|
|
2023-10-20 16:31:11 +02:00
|
|
|
// Render a special message if there are no biomes
|
2023-10-20 17:22:48 +02:00
|
|
|
if (points.length === 0) {
|
2023-10-20 14:03:45 +02:00
|
|
|
context.textAlign = "center";
|
|
|
|
context.fillStyle = "black";
|
|
|
|
context.textBaseline = "middle";
|
|
|
|
context.fillText("No biomes.", 50, 50);
|
|
|
|
}
|
|
|
|
|
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 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-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];
|
|
|
|
point[pointField] = +value;
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
inputHeat.onchange = function() {
|
|
|
|
onChangeBiomeValueWidget("heat", this.value);
|
|
|
|
}
|
|
|
|
inputHumidity.onchange = function() {
|
|
|
|
onChangeBiomeValueWidget("humidity", this.value);
|
|
|
|
}
|
2023-10-20 16:12:20 +02:00
|
|
|
inputMinY.onchange = function() {
|
|
|
|
onChangeBiomeValueWidget("min_y", this.value);
|
|
|
|
}
|
|
|
|
inputMaxY.onchange = function() {
|
|
|
|
onChangeBiomeValueWidget("max_y", this.value);
|
|
|
|
}
|
2023-10-20 17:22:48 +02:00
|
|
|
inputViewY.onchange = function() {
|
|
|
|
draw(getViewY(), true);
|
|
|
|
}
|
2023-10-20 14:18:22 +02:00
|
|
|
|
2023-10-20 13:31:23 +02:00
|
|
|
addBiomeButton.onclick = function() {
|
|
|
|
let he = Math.round(Math.random()*100);
|
|
|
|
let hu = Math.round(Math.random()*100);
|
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-20 14:03:45 +02:00
|
|
|
min_y: MIN_Y_DEFAULT,
|
|
|
|
max_y: MAX_Y_DEFAULT,
|
2023-10-20 13:44:37 +02:00
|
|
|
humidity: hu,
|
|
|
|
};
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
window.addEventListener("load", drawInit);
|
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);
|