mirror of
https://github.com/misode/misode.github.io.git
synced 2026-04-23 07:10:41 +00:00
Add visualizer view
This commit is contained in:
19
package-lock.json
generated
19
package-lock.json
generated
@@ -5,16 +5,16 @@
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@mcschema/core": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@mcschema/core/-/core-0.6.1.tgz",
|
||||
"integrity": "sha512-9DIrcDw/OLs/SrPWBKK/8Y7JVUP1zu9MZfGv+JUrHahkHGsG7MZEAzPP8xqTWiMino2Z80F2khh2UPZX4zlRAQ=="
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@mcschema/core/-/core-0.6.2.tgz",
|
||||
"integrity": "sha512-L/ga6SSeJ1fzDxXN+kYs0YloFsVKipsK+WrRBtkdGm1PrccYw9jwGalVLneVs/JnlDicu60ExrZvbygV9TECag=="
|
||||
},
|
||||
"@mcschema/java-1.16": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@mcschema/java-1.16/-/java-1.16-0.3.1.tgz",
|
||||
"integrity": "sha512-f9QOtKVSIngJGoBX2enC6cYJvmALzIy0sf7V7HCICYcWkzDj5Nj8uPEfKttpwDYgXC+jBcKI99niK/psP/dRYQ==",
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@mcschema/java-1.16/-/java-1.16-0.3.2.tgz",
|
||||
"integrity": "sha512-wEWcAJdnFy8a6Q33sjub9Qrg21EIBiYYCswQe/kE6SBqHjYx6TsKt7733QKhJHPE71PtlZyGPkkw4+6x//nIiw==",
|
||||
"requires": {
|
||||
"@mcschema/core": "^0.6.1"
|
||||
"@mcschema/core": "^0.6.2"
|
||||
}
|
||||
},
|
||||
"@mcschema/locales": {
|
||||
@@ -4403,6 +4403,11 @@
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
|
||||
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
|
||||
},
|
||||
"simplex-noise": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/simplex-noise/-/simplex-noise-2.4.0.tgz",
|
||||
"integrity": "sha512-OjyDWm/QZjVbMrPxDVi9b2as+SeNn9EBXlrWVRlFW+TSyWMSXouDryXkQN0vf5YP+QZKobrmkvx1eQYPLtuqfw=="
|
||||
},
|
||||
"slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
|
||||
@@ -12,14 +12,15 @@
|
||||
"author": "Misode",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@mcschema/core": "^0.6.1",
|
||||
"@mcschema/core": "^0.6.2",
|
||||
"@mcschema/java-1.16": "^0.3.2",
|
||||
"@mcschema/locales": "^0.1.5",
|
||||
"@mcschema/java-1.16": "^0.3.1",
|
||||
"@types/google.analytics": "0.0.40",
|
||||
"@types/split.js": "^1.4.0",
|
||||
"copy-webpack-plugin": "^6.0.1",
|
||||
"html-webpack-plugin": "^4.3.0",
|
||||
"merge-jsons-webpack-plugin": "^1.0.21",
|
||||
"simplex-noise": "^2.4.0",
|
||||
"split.js": "^1.5.11",
|
||||
"ts-loader": "^7.0.4",
|
||||
"typescript": "^3.9.3",
|
||||
|
||||
@@ -2,14 +2,16 @@ import Split from 'split.js'
|
||||
import {
|
||||
AbstractView,
|
||||
Base,
|
||||
CollectionRegistry,
|
||||
DataModel,
|
||||
locale,
|
||||
LOCALES,
|
||||
ModelPath,
|
||||
SourceView,
|
||||
TreeView,
|
||||
Path,
|
||||
} from '@mcschema/core'
|
||||
import { getCollections, getSchemas } from '@mcschema/java-1.16'
|
||||
import { VisualizerView } from './visualization/VisualizerView'
|
||||
import { RegistryFetcher } from './RegistryFetcher'
|
||||
import { ErrorsView } from './ErrorsView'
|
||||
import config from '../config.json'
|
||||
@@ -61,6 +63,20 @@ const treeViewObserver = (el: HTMLElement) => {
|
||||
})
|
||||
}
|
||||
|
||||
const treeViewNodeInjector = (path: ModelPath, view: TreeView) => {
|
||||
return Object.keys(VisualizerView.visualizers)
|
||||
.map(id => VisualizerView.visualizers[id])
|
||||
.filter(v => path.equals(v.path()))
|
||||
.filter(v => v.active(path.getModel()))
|
||||
.map(v => {
|
||||
const id = view.registerClick(() => {
|
||||
views.visualizer.set(v)
|
||||
})
|
||||
return `<button data-id=${id}>${locale('visualize')} <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zM6.379 5.227A.25.25 0 006 5.442v5.117a.25.25 0 00.379.214l4.264-2.559a.25.25 0 000-.428L6.379 5.227z"></path></svg></button>`
|
||||
})
|
||||
.join('')
|
||||
}
|
||||
|
||||
const fetchLocale = async (id: string) => {
|
||||
const response = await fetch(publicPath + `locales/${id}.json`)
|
||||
LOCALES.register(id, await response.json())
|
||||
@@ -95,18 +111,30 @@ const treeControlsVersionMenu = document.getElementById('tree-controls-version-m
|
||||
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')!
|
||||
|
||||
Split([treeViewEl, sourceViewEl], {
|
||||
sizes: [66, 34]
|
||||
})
|
||||
|
||||
Split([sourceViewOutput, visualizerOutput], {
|
||||
sizes: [60, 40],
|
||||
direction: 'vertical'
|
||||
})
|
||||
|
||||
const dummyModel = new DataModel(Base)
|
||||
|
||||
const views: {[key: string]: AbstractView} = {
|
||||
const views = {
|
||||
'tree': new TreeView(dummyModel, treeViewOutput, {
|
||||
showErrors: true,
|
||||
observer: treeViewObserver
|
||||
observer: treeViewObserver,
|
||||
nodeInjector: treeViewNodeInjector
|
||||
}),
|
||||
'source': new SourceView(dummyModel, sourceViewOutput, {
|
||||
indentation: 2
|
||||
}),
|
||||
'errors': new ErrorsView(dummyModel, errorsViewEl)
|
||||
'errors': new ErrorsView(dummyModel, errorsViewEl),
|
||||
'visualizer': new VisualizerView(dummyModel, visualizerOutput as HTMLCanvasElement)
|
||||
}
|
||||
|
||||
const COLLECTIONS = getCollections()
|
||||
@@ -184,10 +212,6 @@ Promise.all([
|
||||
}
|
||||
}
|
||||
|
||||
Split([treeViewEl, sourceViewEl], {
|
||||
sizes: [66, 34]
|
||||
})
|
||||
|
||||
homeLink.addEventListener('click', evt => {
|
||||
reload(publicPath)
|
||||
})
|
||||
|
||||
36
src/app/visualization/BiomeNoiseVisualizer.ts
Normal file
36
src/app/visualization/BiomeNoiseVisualizer.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import SimplexNoise from 'simplex-noise'
|
||||
import { DataModel, Path } from "@mcschema/core";
|
||||
import { Visualizer } from './VisualizerView';
|
||||
|
||||
export class BiomeNoiseVisualizer implements Visualizer {
|
||||
private noise: SimplexNoise
|
||||
|
||||
constructor() {
|
||||
this.noise = new SimplexNoise()
|
||||
}
|
||||
|
||||
path() {
|
||||
return new Path(['generator', 'biome_source'])
|
||||
}
|
||||
|
||||
active(model: DataModel) {
|
||||
const biomeSource = new Path(['generator', 'biome_source'])
|
||||
return model.get(biomeSource) !== undefined
|
||||
&& model.get(biomeSource.push('type')) === 'minecraft:multi_noise'
|
||||
}
|
||||
|
||||
draw(model: DataModel, img: ImageData) {
|
||||
const biomeSource = model.get(new Path(['generator', 'biome_source']))
|
||||
const data = img.data
|
||||
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.noise.noise2D(x/50, y/50) > 0) ? 0 : 255
|
||||
data[i] = b
|
||||
data[i + 1] = b
|
||||
data[i + 2] = b
|
||||
data[i + 3] = 255
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
src/app/visualization/VisualizerView.ts
Normal file
57
src/app/visualization/VisualizerView.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { AbstractView, DataModel, Path } from "@mcschema/core";
|
||||
import { BiomeNoiseVisualizer } from "./BiomeNoiseVisualizer";
|
||||
|
||||
export interface Visualizer {
|
||||
path(): Path
|
||||
active(model: DataModel): boolean
|
||||
draw(model: DataModel, img: ImageData): void
|
||||
}
|
||||
|
||||
export class VisualizerView extends AbstractView {
|
||||
ctx: CanvasRenderingContext2D
|
||||
visualizer?: Visualizer
|
||||
active: boolean
|
||||
canvas: HTMLElement
|
||||
sourceView: HTMLElement
|
||||
gutter: HTMLElement
|
||||
lastHeight?: string
|
||||
|
||||
constructor(model: DataModel, canvas: HTMLCanvasElement) {
|
||||
super(model)
|
||||
this.ctx = 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
|
||||
}
|
||||
|
||||
invalidated() {
|
||||
if (this.active && this.visualizer && this.visualizer.active(this.model)) {
|
||||
const img = this.ctx.createImageData(200, 100)
|
||||
this.visualizer.draw(this.model, img)
|
||||
this.ctx.putImageData(img, 0, 0)
|
||||
this.canvas.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.gutter.style.display = 'none'
|
||||
this.lastHeight = this.sourceView.style.height
|
||||
this.sourceView.style.height = '100%'
|
||||
this.ctx.clearRect(0, 0, 200, 100)
|
||||
}
|
||||
}
|
||||
|
||||
set(visualizer: Visualizer) {
|
||||
this.active = true
|
||||
this.visualizer = visualizer
|
||||
this.invalidated()
|
||||
}
|
||||
|
||||
static visualizers: {[key: string]: Visualizer} = {
|
||||
'biome-noise': new BiomeNoiseVisualizer()
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,10 @@
|
||||
<span data-i18n="share"></span>
|
||||
</button>
|
||||
</div>
|
||||
<textarea id="source-view-output" spellcheck="false" autocorrect="off" autocapitalize="off"></textarea>
|
||||
<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>
|
||||
</div>
|
||||
<div id="home-view" class="home">
|
||||
<div id="home-generators" class="generators-list"></div>
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
{
|
||||
"title.home": "Data Pack Generators",
|
||||
"title.generator": "%0% Generator",
|
||||
"advancement": "Advancement",
|
||||
"copy": "Copy",
|
||||
"dimension-type": "Dimension Type",
|
||||
"dimension": "Dimension",
|
||||
"download": "Download",
|
||||
"language": "Language",
|
||||
"loot-table": "Loot Table",
|
||||
"predicate": "Predicate",
|
||||
"advancement": "Advancement",
|
||||
"dimension": "Dimension",
|
||||
"dimension-type": "Dimension Type",
|
||||
"reset": "Reset",
|
||||
"share": "Share",
|
||||
"title.generator": "%0% Generator",
|
||||
"title.home": "Data Pack Generators",
|
||||
"visualize": "Visualize",
|
||||
"worldgen/biome": "Biome",
|
||||
"worldgen/carver": "Carver",
|
||||
"worldgen/feature": "Feature",
|
||||
"worldgen/noise-settings": "Noise Settings",
|
||||
"worldgen/processor-list": "Processor List",
|
||||
"worldgen/structure-feature": "Structure Feature",
|
||||
"worldgen/surface-builder": "Surface Builder",
|
||||
"worldgen/processor-list": "Processor List",
|
||||
"worldgen/template-pool": "Template Pool",
|
||||
"language": "Language",
|
||||
"reset": "Reset",
|
||||
"copy": "Copy",
|
||||
"download": "Download",
|
||||
"share": "Share"
|
||||
"worldgen/template-pool": "Template Pool"
|
||||
}
|
||||
|
||||
@@ -152,11 +152,23 @@ body {
|
||||
padding: 1rem;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 50vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.source {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.source-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.source textarea {
|
||||
width: 100%;
|
||||
height: calc(100vh - 56px);
|
||||
/* height: calc(100vh - 56px); */
|
||||
height: 100%;
|
||||
padding: 1.3rem 0.4rem;
|
||||
border: none;
|
||||
white-space: pre;
|
||||
@@ -170,18 +182,13 @@ body {
|
||||
resize: none;
|
||||
background-color: var(--background);
|
||||
color: var(--text);
|
||||
transition:all var(--style-transition);
|
||||
/* transition:all var(--style-transition); */
|
||||
}
|
||||
|
||||
.source textarea::selection {
|
||||
background-color: var(--selection);
|
||||
}
|
||||
|
||||
.tree,
|
||||
.source {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tree-controls,
|
||||
.source-controls {
|
||||
display: flex;
|
||||
@@ -213,12 +220,36 @@ body {
|
||||
right: 17px
|
||||
}
|
||||
|
||||
.gutter {
|
||||
border-color: var(--border) !important;
|
||||
transition: border-color var(--style-transition);
|
||||
}
|
||||
|
||||
.gutter.gutter-vertical {
|
||||
border-top: 2px solid;
|
||||
border-bottom: 2px solid;
|
||||
cursor: ns-resize;
|
||||
}
|
||||
|
||||
.gutter.gutter-horizontal {
|
||||
border-left: 2px solid;
|
||||
float: left;
|
||||
border-right: 2px solid;
|
||||
cursor: ew-resize;
|
||||
border-color: var(--border);
|
||||
transition: border-color var(--style-transition);
|
||||
}
|
||||
|
||||
.source canvas {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
/* position: absolute; */
|
||||
/* bottom: 0; */
|
||||
background-color: var(--nav-faded);
|
||||
display: block;
|
||||
image-rendering: optimizeSpeed;
|
||||
image-rendering: -moz-crisp-edges;
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
image-rendering: -o-crisp-edges;
|
||||
image-rendering: pixelated;
|
||||
-ms-interpolation-mode: nearest-neighbor;
|
||||
}
|
||||
|
||||
.btn {
|
||||
|
||||
@@ -176,8 +176,7 @@ button.remove {
|
||||
border-color: var(--node-remove-border);
|
||||
}
|
||||
|
||||
button.remove svg,
|
||||
button.add svg {
|
||||
.node-header > button svg {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
|
||||
Reference in New Issue
Block a user