mirror of
https://github.com/misode/misode.github.io.git
synced 2026-04-23 07:10:41 +00:00
Add zooming the biome noise visualization
This commit is contained in:
@@ -120,13 +120,13 @@ const treeControlsMenu = document.getElementById('tree-controls-menu')!
|
||||
const treeControlsReset = document.getElementById('tree-controls-reset')!
|
||||
const treeControlsUndo = document.getElementById('tree-controls-undo')!
|
||||
const treeControlsRedo = document.getElementById('tree-controls-redo')!
|
||||
const visualizerOutput = document.getElementById('visualizer-output')!
|
||||
const visualizerContent = document.getElementById('visualizer-content')!
|
||||
|
||||
Split([treeViewEl, sourceViewEl], {
|
||||
sizes: [66, 34]
|
||||
})
|
||||
|
||||
Split([sourceViewOutput, visualizerOutput], {
|
||||
Split([sourceViewOutput, visualizerContent], {
|
||||
sizes: [60, 40],
|
||||
direction: 'vertical'
|
||||
})
|
||||
@@ -143,7 +143,7 @@ const views = {
|
||||
indentation: 2
|
||||
}),
|
||||
'errors': new ErrorsView(dummyModel, errorsViewEl),
|
||||
'visualizer': new VisualizerView(dummyModel, visualizerOutput as HTMLCanvasElement)
|
||||
'visualizer': new VisualizerView(dummyModel, visualizerContent)
|
||||
}
|
||||
|
||||
const COLLECTIONS = getCollections()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import SimplexNoise from 'simplex-noise'
|
||||
import { DataModel, Path, ModelPath } from "@mcschema/core"
|
||||
import { Visualizer } from './Visualizer'
|
||||
import { VisualizerView } from './VisualizerView'
|
||||
|
||||
|
||||
export class BiomeNoiseVisualizer extends Visualizer {
|
||||
@@ -8,6 +9,7 @@ export class BiomeNoiseVisualizer extends Visualizer {
|
||||
private noise: SimplexNoise[]
|
||||
private offsetX: number = 0
|
||||
private offsetY: number = 0
|
||||
private viewScale: number = 0
|
||||
private biomeColors: {[id: string]: number[]} = {}
|
||||
|
||||
constructor() {
|
||||
@@ -26,10 +28,13 @@ export class BiomeNoiseVisualizer extends Visualizer {
|
||||
|
||||
draw(model: DataModel, img: ImageData) {
|
||||
const data = img.data
|
||||
const s = (2 ** this.viewScale)
|
||||
for (let x = 0; x < 200; x += 1) {
|
||||
for (let y = 0; y < 100; y += 1) {
|
||||
const i = (y * (img.width * 4)) + (x * 4)
|
||||
const b = this.closestBiome(x, y)
|
||||
const xx = (x - this.offsetX) * s - 100 * s
|
||||
const yy = (y- this.offsetY) * s - 50 * s
|
||||
const b = this.closestBiome(xx, yy)
|
||||
const color = this.getBiomeColor(b)
|
||||
data[i] = color[0]
|
||||
data[i + 1] = color[1]
|
||||
@@ -39,9 +44,21 @@ export class BiomeNoiseVisualizer extends Visualizer {
|
||||
}
|
||||
}
|
||||
|
||||
onDrag(from: number[], to: number[]) {
|
||||
this.offsetX += to[0] - from[0]
|
||||
this.offsetY += to[1] - from[1]
|
||||
onDrag(fromX: number, fromY: number, toX: number, toY: number) {
|
||||
this.offsetX += toX - fromX
|
||||
this.offsetY += toY - fromY
|
||||
}
|
||||
|
||||
addControls(el: HTMLElement, view: VisualizerView) {
|
||||
el.insertAdjacentHTML('beforeend', `<button class="btn" id="visualizer-controls-toggle"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 2a.75.75 0 01.75.75v4.5h4.5a.75.75 0 010 1.5h-4.5v4.5a.75.75 0 01-1.5 0v-4.5h-4.5a.75.75 0 010-1.5h4.5v-4.5A.75.75 0 018 2z"></path></svg></button><button class="btn" id="visualizer-controls-toggle"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2 8a.75.75 0 01.75-.75h10.5a.75.75 0 010 1.5H2.75A.75.75 0 012 8z"></path></svg></button>`)
|
||||
el.childNodes[0].addEventListener('click', () => {
|
||||
this.viewScale -= 0.5
|
||||
view.redraw()
|
||||
})
|
||||
el.childNodes[1].addEventListener('click', () => {
|
||||
this.viewScale += 0.5
|
||||
view.redraw()
|
||||
})
|
||||
}
|
||||
|
||||
private closestBiome(x: number, y: number): string {
|
||||
@@ -71,7 +88,7 @@ export class BiomeNoiseVisualizer extends Visualizer {
|
||||
let n = 0
|
||||
let scale = 2**config.firstOctave
|
||||
for (let i = 0; i < config.amplitudes.length; i++) {
|
||||
n += this.noise[index].noise2D((x - this.offsetX)*scale, (y- this.offsetY)*scale + i)
|
||||
n += this.noise[index].noise2D(x * scale, y * scale + i)
|
||||
* config.amplitudes[i] / (2**scale)
|
||||
scale *= 2
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ export class NoiseSettingsVisualizer extends Visualizer {
|
||||
}
|
||||
}
|
||||
|
||||
onDrag(from: number[], to: number[]) {
|
||||
this.offsetX += (to[0] - from[0])
|
||||
onDrag(fromX: number, fromY: number, toX: number, toY: number) {
|
||||
this.offsetX += toX - fromX
|
||||
}
|
||||
|
||||
private getColor(densities: number[], y: number): number {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { DataModel, ModelPath } from "@mcschema/core"
|
||||
import { VisualizerView } from "./VisualizerView"
|
||||
|
||||
export abstract class Visualizer {
|
||||
state: any
|
||||
@@ -11,5 +12,7 @@ export abstract class Visualizer {
|
||||
abstract active(path: ModelPath): boolean
|
||||
abstract draw(model: DataModel, img: ImageData): void
|
||||
|
||||
onDrag(from: number[], to: number[]): void {}
|
||||
onDrag(fromX: number, fromY: number, toX: number, toY: number): void {}
|
||||
|
||||
addControls(el: HTMLElement, view: VisualizerView): void {}
|
||||
}
|
||||
|
||||
@@ -8,37 +8,47 @@ export class VisualizerView extends AbstractView {
|
||||
visualizer?: Visualizer
|
||||
active: boolean
|
||||
path?: ModelPath
|
||||
canvas: HTMLElement
|
||||
el: HTMLElement
|
||||
canvas: HTMLCanvasElement
|
||||
sourceView: HTMLElement
|
||||
gutter: HTMLElement
|
||||
controls: HTMLElement
|
||||
lastHeight?: string
|
||||
dragStart?: number[]
|
||||
|
||||
constructor(model: DataModel, canvas: HTMLCanvasElement) {
|
||||
constructor(model: DataModel, el: HTMLElement) {
|
||||
super(model)
|
||||
this.ctx = canvas.getContext('2d')!
|
||||
this.el = el
|
||||
this.canvas = el.querySelector('canvas') as HTMLCanvasElement
|
||||
this.ctx = this.canvas.getContext('2d')!
|
||||
this.active = false
|
||||
this.canvas = canvas
|
||||
this.gutter = canvas.parentElement!.querySelector('.gutter') as HTMLElement
|
||||
this.sourceView = canvas.parentElement!.getElementsByTagName('textarea')[0] as HTMLElement
|
||||
this.gutter = el.parentElement!.querySelector('.gutter') as HTMLElement
|
||||
this.sourceView = el.parentElement!.getElementsByTagName('textarea')[0] as HTMLElement
|
||||
this.controls = el.querySelector('.visualizer-controls') as HTMLElement
|
||||
|
||||
canvas.addEventListener('mousedown', evt => {
|
||||
this.canvas.addEventListener('mousedown', evt => {
|
||||
this.dragStart = [evt.offsetX, evt.offsetY]
|
||||
})
|
||||
canvas.addEventListener('mousemove', evt => {
|
||||
this.canvas.addEventListener('mousemove', evt => {
|
||||
if (this.dragStart === undefined) return
|
||||
if (this.visualizer?.onDrag) {
|
||||
this.visualizer.onDrag(this.dragStart, [evt.offsetX, evt.offsetY])
|
||||
this.visualizer.state = {}
|
||||
this.invalidated()
|
||||
this.visualizer.onDrag(this.dragStart[0], this.dragStart[1], evt.offsetX, evt.offsetY)
|
||||
this.redraw()
|
||||
}
|
||||
this.dragStart = [evt.offsetX, evt.offsetY]
|
||||
})
|
||||
canvas.addEventListener('mouseup', evt => {
|
||||
this.canvas.addEventListener('mouseup', evt => {
|
||||
this.dragStart = undefined
|
||||
})
|
||||
}
|
||||
|
||||
redraw() {
|
||||
if (this.active && this.visualizer) {
|
||||
this.visualizer.state = {}
|
||||
this.invalidated()
|
||||
}
|
||||
}
|
||||
|
||||
invalidated() {
|
||||
this.path = this.path?.withModel(this.model)
|
||||
let newState: any
|
||||
@@ -51,14 +61,14 @@ export class VisualizerView extends AbstractView {
|
||||
this.visualizer.draw(this.model, img)
|
||||
this.ctx.putImageData(img, 0, 0)
|
||||
}
|
||||
this.canvas.style.display = 'block'
|
||||
this.el.style.display = 'block'
|
||||
this.gutter.style.display = 'block'
|
||||
if (this.lastHeight) {
|
||||
this.sourceView.style.height = this.lastHeight
|
||||
this.lastHeight = undefined
|
||||
}
|
||||
} else {
|
||||
this.canvas.style.display = 'none'
|
||||
this.el.style.display = 'none'
|
||||
this.gutter.style.display = 'none'
|
||||
this.lastHeight = this.sourceView.style.height
|
||||
this.sourceView.style.height = '100%'
|
||||
@@ -70,7 +80,9 @@ export class VisualizerView extends AbstractView {
|
||||
this.visualizer = visualizer
|
||||
this.path = path
|
||||
this.visualizer.state = undefined
|
||||
this.invalidated()
|
||||
this.controls.innerHTML = ''
|
||||
this.visualizer.addControls(this.controls, this)
|
||||
this.redraw()
|
||||
}
|
||||
|
||||
static visualizers: Visualizer[] = [
|
||||
|
||||
@@ -94,7 +94,10 @@
|
||||
</div>
|
||||
<div class="source-content">
|
||||
<textarea id="source-view-output" spellcheck="false" autocorrect="off" autocapitalize="off"></textarea>
|
||||
<canvas width="200" height="100" id="visualizer-output"></canvas>
|
||||
<div class="visualizer-content" id="visualizer-content">
|
||||
<div class="visualizer-controls" id="visualizer-controls"></div>
|
||||
<canvas width="200" height="100" id="visualizer-output"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="home-view" class="home">
|
||||
|
||||
@@ -193,7 +193,8 @@ body {
|
||||
}
|
||||
|
||||
.tree-controls,
|
||||
.source-controls {
|
||||
.source-controls,
|
||||
.visualizer-controls {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
position: absolute;
|
||||
@@ -203,7 +204,8 @@ body {
|
||||
}
|
||||
|
||||
.tree-controls .btn:not(:first-child),
|
||||
.source-controls .btn:not(:first-child) {
|
||||
.source-controls .btn:not(:first-child),
|
||||
.visualizer-controls .btn:not(:first-child) {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
@@ -235,11 +237,19 @@ body {
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
.source canvas {
|
||||
.visualizer-content {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
/* position: absolute; */
|
||||
/* bottom: 0; */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.visualizer-controls {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.visualizer-content canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--nav-faded);
|
||||
display: block;
|
||||
cursor: grab;
|
||||
|
||||
Reference in New Issue
Block a user