Created
February 16, 2021 13:07
-
-
Save 0xf0f0f0/b6768474e9ad2ce6ffce75e4d3483096 to your computer and use it in GitHub Desktop.
editor-runner
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* eslint-disable */ | |
| import dat from 'dat.gui'; | |
| class Editor { | |
| get bg() { | |
| return 'data:image/png;base64,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'; | |
| } | |
| get defaultPallete() { | |
| return { | |
| color1: '#fff000', | |
| color2: '#fff0ff', | |
| color3: '#f000ff', | |
| }; | |
| } | |
| get defaultMapProps() { | |
| return { | |
| tileSize: 32, | |
| mapWidth: 10, | |
| mapHeight: 10, | |
| colPadding: 0, | |
| rowPadding: 0, | |
| }; | |
| } | |
| constructor(onThreeSceneUpdateCB = () => {}, pallete = defaultPallete, mapProps = {}) { | |
| const props = { | |
| ...this.defaultMapProps, | |
| ...mapProps, | |
| }; | |
| Object.keys(props).forEach((key) => { | |
| this[key] = props[key]; | |
| }); | |
| this.pallete = pallete; | |
| this.eraserEnabled = false; | |
| this.fillColor = '#ffff00'; | |
| this.srcTile = null; | |
| this.mapData = []; | |
| this.canvas = null; | |
| this.ctx = null; | |
| this.pathPoints = []; | |
| this.onThreeSceneUpdateCB = onThreeSceneUpdateCB; | |
| window.addEventListener('click', (e) => this.onClick(e)); | |
| } | |
| init() { | |
| const div = this.wrapper = document.createElement('div'); | |
| div.style = 'pointer-events: all; top: 0; overflow: scroll; position: fixed; z-index: 90; overflow-x: scroll; width: 320px; height: 640px;'; | |
| const canvas = this.canvas = document.createElement('canvas'); | |
| canvas.id = 'roadEditor'; | |
| canvas.style = `background-position: left top; background-repeat: repeat; background-image: url(${this.bg}); position: absolute; max-width: initial;`; | |
| canvas.width = this.mapWidth * this.tileSize; | |
| canvas.height = this.mapHeight * this.tileSize; | |
| div.appendChild(canvas); | |
| document.body.appendChild(div); | |
| this.ctx = canvas.getContext('2d'); | |
| const input = this.input = document.createElement('input'); | |
| input.id = 'uploadInput'; | |
| input.type = 'file'; | |
| input.style = 'visibility:hidden'; | |
| document.body.appendChild(input); | |
| input.addEventListener('change', this.uploadMapAndBuild.bind(this)); | |
| this.initGUI(); | |
| } | |
| initGUI() { | |
| const editor = this; | |
| const editorInterface = { | |
| tileSize: editor.tileSize, | |
| mapWidth: editor.mapWidth, | |
| mapHeight: editor.mapHeight, | |
| rowPadding: editor.rowPadding, | |
| colPadding: editor.colPadding, | |
| eraser: () => editor.enableEraser(true), | |
| buildMap: () => editor.buildMap(), | |
| clearCanvas: () => editor.clearMap(), | |
| downloadMap: () => editor.downloadMap('editor_map.js'), | |
| uploadMap: () => document.getElementById('uploadInput').click(), | |
| }; | |
| const gui = this.gui = new dat.GUI({ | |
| name: 'Editor GUI', | |
| id: 'editor', | |
| }); | |
| this.gui.domElement.id = 'editor_gui'; | |
| const mapOptionsFolder = this.mapOptionsFolder = gui.addFolder('Map_Options'); | |
| mapOptionsFolder.add(editorInterface, 'tileSize', editorInterface.tileSize, editorInterface.tileSize); | |
| mapOptionsFolder.add(editorInterface, 'mapWidth', 0, 100).onChange((e) => { | |
| editor.mapWidth = Math.round(e); | |
| editor.rebuildCanvas(); | |
| }); | |
| mapOptionsFolder.add(editorInterface, 'mapHeight', 0, 300).onChange((e) => { | |
| editor.mapHeight = Math.round(e); | |
| editor.rebuildCanvas(); | |
| }); | |
| mapOptionsFolder.add(editorInterface, 'rowPadding', -300, 300, 0.00001).onChange((e) => { | |
| editor.rowPadding = e; | |
| }); | |
| mapOptionsFolder.add(editorInterface, 'colPadding', -300, 300, 0.00001).onChange((e) => { | |
| editor.colPadding = e; | |
| }); | |
| const typesOptionsFolder = gui.addFolder('Types'); | |
| Object.keys(this.pallete) | |
| .forEach((key) => { | |
| typesOptionsFolder.add({ [key]: () => {} }, key).onChange(() => { | |
| editor.setupFillColor(key); | |
| }); | |
| }); | |
| const pointsFolder = gui.addFolder('Points'); | |
| pointsFolder.add({ addPoint: () => {} }, 'addPoint'); | |
| const toolsFolder = gui.addFolder('Tools'); | |
| toolsFolder.add(editorInterface, 'eraser').name('Eraser'); | |
| toolsFolder.add(editorInterface, 'buildMap').name('Build'); | |
| toolsFolder.add(editorInterface, 'clearCanvas').name('Clear Map'); | |
| toolsFolder.add(editorInterface, 'downloadMap').name('Dowload'); | |
| toolsFolder.add(editorInterface, 'uploadMap').name('Upload'); | |
| } | |
| rebuildCanvas() { | |
| const { mapHeight, mapWidth, tileSize, canvas } = this; | |
| canvas.width = mapWidth * tileSize; | |
| canvas.height = mapHeight * tileSize; | |
| } | |
| getTile(e) { | |
| const row = e.layerX / this.tileSize | 0; | |
| const col = e.layerY / this.tileSize | 0; | |
| return { row, col }; | |
| } | |
| setTile(row, col) { | |
| const { tileSize, ctx } = this; | |
| if (this.eraserEnabled) { | |
| ctx.clearRect(row * tileSize, col * tileSize, tileSize, tileSize); | |
| } else if (this.fillColor) { | |
| ctx.clearRect(row * tileSize, col * tileSize, tileSize, tileSize); | |
| ctx.beginPath(); | |
| ctx.fillStyle = this.fillColor; | |
| ctx.rect(row * tileSize, col * tileSize, tileSize, tileSize); | |
| ctx.fill(); | |
| ctx.closePath(); | |
| } | |
| } | |
| buildMap(updateThreeScene = true) { | |
| const { mapWidth, mapHeight } = this; | |
| this.mapData = []; | |
| const checkColor = (color) => color[0] === 0 && color[1] === 0 && color[2] === 0 | |
| && color[3] === 0; | |
| const convertRBGtoHEX = (rgba) => `#${((1 << 24) + (parseInt(rgba[0]) << 16) + (parseInt(rgba[1]) << 8) + parseInt(rgba[2])).toString(16).slice(1)}`; | |
| const getTypeByColor = (color) => { | |
| const c = convertRBGtoHEX(color); | |
| const t = Object.keys(this.pallete).find((key) => this.pallete[key] === c); | |
| if (t) return t; | |
| return null; | |
| }; | |
| for (let i = 0; i < mapWidth; i++) { | |
| for (let j = 0; j < mapHeight; j++) { | |
| const color = this.getColor(i, j); | |
| if (!checkColor(color.data)) { | |
| this.mapData.push({ | |
| type: getTypeByColor(color.data), | |
| i, | |
| j, | |
| }); | |
| } | |
| } | |
| } | |
| if (updateThreeScene) { | |
| this.updateThreeScene(this.mapData, { | |
| mapWidth: this.mapWidth, | |
| mapHeight: this.mapHeight, | |
| colsGap: this.colPadding, | |
| rowsGap: this.rowPadding, | |
| }); | |
| } | |
| } | |
| uploadMapAndBuild() { | |
| const reader = new FileReader(); | |
| reader.onload = (responce) => { | |
| const { result } = responce.target; | |
| const map = JSON.parse(result); | |
| this.drawMap(map); | |
| }; | |
| reader.readAsText(this.input.files[this.input.files.length - 1]); | |
| } | |
| drawMap({ mapWidth, mapHeight, rowPadding, colPadding, map }) { | |
| const { mapOptionsFolder } = this; | |
| const mapWC = mapOptionsFolder.__controllers[1]; | |
| const mapHC = mapOptionsFolder.__controllers[2]; | |
| const rowPC = mapOptionsFolder.__controllers[3]; | |
| const colPC = mapOptionsFolder.__controllers[4]; | |
| mapWC.setValue(mapWidth); | |
| mapHC.setValue(mapHeight); | |
| rowPC.setValue(rowPadding); | |
| colPC.setValue(colPadding); | |
| map.forEach(({ type, i, j }) => { | |
| this.setupFillColor(type); | |
| this.setTile(i, j); | |
| }); | |
| this.buildMap(true); | |
| } | |
| clearMap() { | |
| const r = confirm('Are u sure?'); | |
| if (r) { | |
| this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); | |
| this.mapData = []; | |
| } | |
| } | |
| updateThreeScene(map = this.mapData) { | |
| this.onThreeSceneUpdateCB(map, { | |
| rowsGap: this.rowPadding, | |
| colsGap: this.colPadding, | |
| mapWidth: this.mapWidth, | |
| }); | |
| } | |
| getColor(i, j) { | |
| const row = i * this.tileSize + this.tileSize / 2; | |
| const col = j * this.tileSize + this.tileSize / 2; | |
| return this.ctx.getImageData(row, col, 1, 1); | |
| } | |
| downloadMap(filename) { | |
| this.buildMap(false); | |
| const m = this.mapData.sort((a, b) => { | |
| if (a.type < b.type) { return -1; } | |
| if (a.type > b.type) { return 1; } | |
| return 0; | |
| }); | |
| const map = { | |
| map: m, | |
| mapWidth: this.mapWidth, | |
| mapHeight: this.mapHeight, | |
| rowPadding: this.rowPadding, | |
| colPadding: this.colPadding, | |
| }; | |
| const blob = new Blob([JSON.stringify(map)], { type: 'text/csv' }); | |
| if (window.navigator.msSaveOrOpenBlob) { | |
| window.navigator.msSaveBlob(blob, filename); | |
| } else { | |
| const elem = window.document.createElement('a'); | |
| elem.href = window.URL.createObjectURL(blob); | |
| elem.download = filename; | |
| document.body.appendChild(elem); | |
| elem.click(); | |
| document.body.removeChild(elem); | |
| } | |
| } | |
| enableEraser(value) { | |
| this.eraserEnabled = value; | |
| if (value) { | |
| this.fillColor = null; | |
| } | |
| } | |
| setupFillColor(color) { | |
| if (this.pallete[color]) { | |
| this.fillColor = this.pallete[color]; | |
| this.enableEraser(false); | |
| } | |
| } | |
| onClick(e) { | |
| if (e.target.id === this.canvas.id) { | |
| const { row, col } = this.getTile(e); | |
| this.setTile(row, col); | |
| } | |
| const qs = document.querySelectorAll('#editor_gui > ul')[0]; | |
| if (qs.className === 'closed' && !this.isClosed) { | |
| this.wrapper.style.visibility = 'hidden'; | |
| this.isClosed = true; | |
| } else if (this.isClosed) { | |
| this.isClosed = false; | |
| this.wrapper.style.visibility = 'visible'; | |
| } | |
| } | |
| } | |
| export default Editor; | |
| // init | |
| // this.editor = new Editor((map, props) => { | |
| // this.objectsCreator.createMap({ | |
| // map, ...props | |
| // }); | |
| // }, { | |
| // hammer: '#fff000', | |
| // gems: '#fff00f', | |
| // mult: '#00ff00', | |
| // trap: '#444000', | |
| // gear: '#945300', | |
| // gear_r: '#300300', | |
| // }, { | |
| // mapWidth: 5, | |
| // mapHeight: 100, | |
| // rowPadding: 3, | |
| // colPadding: .01 | |
| // }); | |
| // this.editor.init(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment