JSFiddle - React, Tailwind, and code Playground

by Gwyn Milcote

HTML

<h1>sheet maker</h1>

<p>upload your sprite files. select a sprite from the list, click on the canvas to move the sprite around, or edit the number inputs. download the image as PNG and get JSON position/size data for all sprites.</p>
<p>you can come back and edit an existing sheet by pasting JSON and uploading the sheet image; it will be cut into pieces again.</p>

<div id='canvas-container'>
    <canvas id='sheet-canvas'></canvas>
</div>

Add a sprite: <input type='file' id='upload-sprite'> <button id='upload-sprite-btn'>Upload</button>

<div id='sprite-list'>No sprites yet.</div>

<hr>

<button id='export-btn'>Export</button> - Copy this JSON and save it somewhere. Save the image below.
<br>
<textarea id='export-json'></textarea>
<br>
<canvas id='export-canvas'></canvas>

<hr>

<button id='import-btn'>Import</button> - Paste JSON code in here, choose sheet image to upload, then click button.
<br>
<textarea id='import-json'></textarea>
<br>
Sheet: <input type='file' id='upload-sheet'> <!--<button id='upload-sheet-btn'>Upload</button>-->

CSS

div, canvas, button, input {
    box-sizing: border-box;
}

#canvas-container {
    width: 100%;
    background-color: silver;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 20px;
    margin: 20px auto;
    /*text-align: center;*/
}
#sheet-canvas {
    box-shadow: 0 0 0 1px grey;
}

#sprite-list {
    width: 100%;
    max-width: 800px;
    background-color: silver;
    margin: 20px auto;
    padding: 5px;
}
#sprite-list table {
    width: 100%;
    border-collapse: collapse;
}
#sprite-list table th {
    padding: 3px 5px;
    background-color: #eee;
    border: 1px solid grey;
}
#sprite-list table td {
    padding: 3px 5px;
    border: 1px solid grey;
}

#sprite-list input {
    width: 50px;
}

/* tr */
#sprite-list .sprite {
    padding: 3px 5px;
    background-color: #fff;
}
#sprite-list .sprite:hover {
    cursor: pointer;
    background-color: #eee;
    border: 1px darkgray;
}
#sprite-list .selected-sprite {
    background-color: lightgreen !important;
    /*border: 1px solid green !imortant;*/
}
#sprite-list .selected-sprite td {
    /*background-color: lightgreen !important;*/
    border: 1px solid green !imortant;
}

JavaScript

class SheetMaker {

    constructor(){
        this.canvas = document.getElementById("sheet-canvas");
        this.ctx = this.canvas.getContext("2d");
        this.canvas.width = 200;
        this.canvas.height = 200;
        
        this.sprites = [];
        this.images = {};
        this.selectedSprite = false;
        this.hoverSprite = false;
    }
    
    
    /*
    * Get file from user. Check correct type.
    * Used for sprites and sheets.
    */
    uploadImage(type = "sprite"){
        let input = document.getElementById("upload-" + type);
        if(!input.files){
            console.log("No file chosen.");
            return;
        }
        
        let file = input.files[0],
            reader = new FileReader(),
            _this = this;
        
        reader.onload = function(e){
            if(file.type.indexOf("image") > -1){
                let img = new Image();
                img.src = e.target.result;
                img.onload = () => {
                
                    // Pass to other function.
                    if(type == "sprite"){
                        _this.saveSprite(file, img);
                    }else if(type == "sheet"){
                        _this.saveSheet(file, img);
                    }
                    
                };
                img.src = e.target.result;
            }else{
                console.log("File is not an image.");
                return;
            }
        }
        
        reader.readAsDataURL(file);
    }
    
    /*
    * Called by above function after image is ready.
    * Save in sprites array and images object.
    * Update list and canvas.
    */
    saveSprite(file, img){
        //$("#canvas-container").html(img);
        
        // Get filename. It can have . in it,
        // just remove last part (file extension).
        let name = file.name.split("."),
            p = name.pop();
        name = name.join(".");
        
        let id = this.getLastId() + 1;
      ...