JSFiddle - React, Tailwind, and code Playground

by Gwyn Milcote

HTML

<div id='container'>
<div id='page-content'>
    
    <p>Customisation: live editor 2. Here you can fiddle with items and perfect your griffin's appearance! All of your owned items are listed in the boxes. Click on one to add it to the editor and play with it.<br>Don't worry, <b>nothing will be taken from your inventory</b>, or actually added/removed from your griffin, until you click the 'Save Changes' button.</p>
    <p>Other users/guests will see simple lists of current equipment (img, name, opacity etc). No preview canvas or other options. ... maybe option to view griff without wearables or bg stuff? just the plain coat.</p>
    
    <div id='custom-container'>
        <div id='custom-options'>
            
            <div class='custom-option'>
                Background
                <input type='checkbox' id='show-background' checked>
            </div>
            <div class='custom-option'>
                Scenery
                <input type='checkbox' id='show-scenery' checked>
            </div>
            <!--<div class='custom-option'>
                Griffin
                <input type='checkbox' id='show-pet' checked>
            </div>-->
            <div class='custom-option'>
                Wearables
                <input type='checkbox' id='show-wearables' checked>
            </div>
            
            <br>
            
            <div class='custom-option'>
                Flip griffin
                <input type='checkbox' id='flip-pet'>
            </div>
            <div class='custom-option'>
                <select id='pet-effect'>
                    <option value='0'>No effect</option>
                    <option value='1'>Multiply</option>
                    <option value='2'>Overlay</option>
                    <option value='3'>Add</option>
                </select>
            </div>
            <div class='custom-option'>
                <input type='range' min='0' max='100' step='10' value='100' id='pet-opacity'>
   ...

CSS

div, img, canvas, p, button, input, ul, li, select {
    box-sizing: border-box;
}

body {
    background-color: #eee;
    width: 1040px;
    color: #664C30;
}












#container {
    width: 970px;
    margin: 20px auto;
    
}
#page-content {
    background-color: #fff;
    padding: 30px;
    margin: 20px auto;
}


#custom-container {
    display: flex;
    justify-content: space-between;
}

#custom-options {
    background-color: #eee;
    width: 140px;
}
#custom-options .custom-option {
    display: flex;
    justify-content: space-between;
    font-size: 20px;
    margin: 12px 0;
}
#custom-options input[type="checkbox"] {
    width: 20px;
    height: 20px;
}
#custom-options input[type="range"], 
#custom-options select {
    width: 100%;
    height: 20px;
}

/* Tab btns are in this side panel. */
#tab-btns {}
#tab-btns .tab-btn {
    padding: 5px;
    text-align: center;
    border: 1px solid silver;
}
#tab-btns .tab-btn:hover {
    cursor: pointer;
}
#tab-btns .active-tab {
    background-color: #fff;
}


/* Canvas will be inserted in here. */
#custom-canvas {
    width: 760px;
    height: 450px;
    background-color: skyblue;
}



#tab-content .tab-content {
    width: 100%;
}



/* For editing scenery and wearables. */
.equipped-items {
    width: 100%;
    border-collapse: collapse;
}
.equipped-items th {
    padding: 5px;
    border: 1px solid grey;
    background-color: #eee;
}
.equipped-items td {
    padding: 5px;
    border: 1px solid silver;
    text-align: center;
}


.equipped-items td:nth-child(1) {
    width: 40px;
}
.equipped-items td:nth-child(1) img {
    width: 40px;
    height: 30px;
    background-color: lightblue;
}
.equipped-items td:nth-child(2) {
    width: 200px;
}
.equipped-items td:nth-child(7) {
    width: 90px;
}


/* Inside final TD */
.equipped-items .priority-options {
    display: flex;
    justify-content: space-between;
}
.equipped-items .priority-options .option-btn {
    width: 24px;
    height: 24px;
   ...

JavaScript

const path = "";
const imagePath = "";


class PetImage {

    constructor(){
        this.breed = "aquila";
        this.sex = 1;
        this.pose = "stand";
        this.render = "abcd";
        
        this.bg = [];
        this.scenery = [];
        this.wearables = [];
        
        // From render string to this.
        this.layers = [];
        
        // Save canvases.
        this.canvas = null;
        this.bgCanvas = null;
        this.sceneryCanvas = null;
        this.wearableCanvas = null;
        this.petCanvas = null;
    }
    
    renderImage(settings){
    
        $("#" + settings.targetDiv).html("render pet canvas, size " + settings.size);
    
    }

}

class PetRenderer {}


class CustomiseTool {

    /*
    * Parse JSON echoed on page. Render everything.
    */
    constructor(){
        
        this.pet = new PetImage();
        this.pet.breed = "aquila";
        this.pet.sex = 1;
        this.pet.pose = "stand";
        this.pet.render = "abcd";
        
        // Store data about each item, to look up.
        // Name, size, position...
        this.itemDb = [
            {
                id: "1", name: "scarf",
                pxT: 50, pxL: 50,
                pxW: 100, pxH: 150
            },{
                id: "2", name: "horns",
                pxT: 50, pxL: 50,
                pxW: 100, pxH: 150
            },{
                id: "3", name: "fiery eyes",
                pxT: 50, pxL: 50,
                pxW: 100, pxH: 150
            },{
                id: "4", name: "belly scales",
                pxT: 50, pxL: 50,
                pxW: 100, pxH: 150
            },{
                id: "5", name: "antlers",
                pxT: 50, pxL: 50,
                pxW: 100, pxH: 150
            },{
                id: "6", name: "rings",
                pxT: 50, pxL: 50,
                pxW: 100, pxH: 150
            },{
                id: "7", name: "snow scenery",
            },{
                id: "8", name: "rose...