File size: 5,889 Bytes
b747299
 
 
c317bf2
 
 
 
 
 
 
 
 
 
 
 
b747299
c317bf2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91bc898
b747299
c317bf2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91bc898
c317bf2
 
 
b747299
c317bf2
 
 
91bc898
26fbc3b
c317bf2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26fbc3b
c317bf2
 
 
 
 
 
 
 
91bc898
c317bf2
 
 
 
 
 
 
b747299
c317bf2
 
 
 
 
 
 
 
 
91bc898
c317bf2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91bc898
c317bf2
 
 
 
b747299
3d5d9f5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <!-- Tailwind CSS (Play CDN) -->
  <script src="https://cdn.tailwindcss.com"></script>
  <!-- FontAwesome -->
  <link rel="stylesheet"
    href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"
  />
  <!-- Fabric.js -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/6.6.4/fabric.min.js"></script>
  <!-- fabric-brushes addon -->
  <script src="https://cdn.jsdelivr.net/gh/av01d/fabric-brushes@1.0/dist/fabric.brushes.min.js"></script>
</head>
<body class="h-screen flex bg-gray-100">
  <!-- Layers Panel -->
  <aside class="w-64 bg-white border-r p-4 flex flex-col">
    <h2 class="text-xl font-semibold mb-4">Layers</h2>
    <div id="layers" class="flex-1 overflow-auto space-y-2"></div>
    <button id="add-layer"
      class="mt-4 flex items-center justify-center px-3 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
      <i class="fa fa-plus mr-2"></i>Add Layer
    </button>
  </aside>

  <!-- Main Canvas Area -->
  <main class="flex-1 flex flex-col">
    <!-- Brush Toolbar -->
    <div class="p-4 bg-white border-b flex space-x-4">
      <button class="brush-btn" data-brush="pencil" title="Pencil">
        <i class="fa fa-pencil-alt fa-lg"></i>
      </button>
      <button class="brush-btn" data-brush="chalk" title="Chalk">
        <i class="fa fa-chalkboard fa-lg"></i>
      </button>
      <button class="brush-btn" data-brush="paint" title="Paint">
        <i class="fa fa-paint-brush fa-lg"></i>
      </button>
      <button class="brush-btn" data-brush="splatter" title="Splatter">
        <i class="fa fa-spray-can fa-lg"></i>
      </button>
    </div>

    <!-- Canvas Stack -->
    <div id="canvas-wrapper" class="relative flex-1 bg-white"></div>
  </main>

  <!-- Script -->
  <script>
    const layersContainer = document.getElementById('layers');
    const addLayerBtn   = document.getElementById('add-layer');
    const canvasWrapper = document.getElementById('canvas-wrapper');
    let layers = [], current = -1;

    // Create a new layer
    function addLayer(name='Layer') {
      const id = Date.now().toString();
      // Create <canvas>
      const c = document.createElement('canvas');
      c.id = 'canvas-' + id;
      c.width  = canvasWrapper.clientWidth;
      c.height = canvasWrapper.clientHeight;
      c.classList.add('absolute','top-0','left-0');
      canvasWrapper.appendChild(c);

      // Init Fabric canvas
      const fc = new fabric.Canvas(c.id, {
        isDrawingMode: true,
        backgroundColor: 'transparent'
      });
      fc.freeDrawingBrush = new fabric.PencilBrush(fc); // default :contentReference[oaicite:5]{index=5}

      layers.push({ id, name, el: c, fc });
      selectLayer(layers.length - 1);
      updateLayersUI();
    }

    // Refresh the layers panel
    function updateLayersUI() {
      layersContainer.innerHTML = '';
      layers.forEach((ly, i) => {
        const div = document.createElement('div');
        div.className = [
          'flex items-center justify-between p-2 rounded',
          i===current ? 'bg-blue-100' : 'hover:bg-gray-100 cursor-pointer'
        ].join(' ');
        div.innerHTML = `
          <span>${ly.name}</span>
          <div class="space-x-1">
            <button onclick="moveLayer(${i},-1)"><i class="fa fa-arrow-up"></i></button>
            <button onclick="moveLayer(${i},+1)"><i class="fa fa-arrow-down"></i></button>
            <button onclick="removeLayer(${i})"><i class="fa fa-trash"></i></button>
          </div>`;
        div.addEventListener('click',()=>selectLayer(i));
        layersContainer.appendChild(div);
      });
      // Stack canvases by index
      layers.forEach((ly,i)=> {
        ly.el.style.zIndex = i;
      });
      if(current>=0) layers[current].el.style.zIndex = layers.length;
    }

    // Select a layer
    function selectLayer(i) {
      current = i;
      layers.forEach((ly,idx)=>{
        ly.fc.selection = (idx===i);
      });
      updateLayersUI();
    }

    // Remove a layer
    function removeLayer(i) {
      canvasWrapper.removeChild(layers[i].el);
      layers.splice(i,1);
      if(current >= layers.length) current = layers.length -1;
      updateLayersUI();
    }

    // Move layer up/down
    function moveLayer(i, dir) {
      const j = i + dir;
      if(j<0||j>=layers.length) return;
      [layers[i], layers[j]] = [layers[j], layers[i]];
      if(current === i) current = j;
      else if(current === j) current = i;
      updateLayersUI();
    }

    // Change brush type
    document.querySelectorAll('.brush-btn').forEach(btn=>{
      btn.addEventListener('click',()=>{
        if(current<0) return;
        const f = layers[current].fc;
        switch(btn.dataset.brush) {
          case 'pencil':
            f.freeDrawingBrush = new fabric.PencilBrush(f); break;
          case 'chalk':
            f.freeDrawingBrush = new fabric.SketchyBrush(f,{
              width: 10, color:'#222', opacity:0.6
            }); break;            // Sketchy for chalk :contentReference[oaicite:6]{index=6}
          case 'paint':
            f.freeDrawingBrush = new fabric.RibbonBrush(f,{
              width: 20, color:'#c00', opacity:0.8
            }); break;            // Ribbon for paint drips :contentReference[oaicite:7]{index=7}
          case 'splatter':
            f.freeDrawingBrush = new fabric.SpraypaintBrush(f,{
              width: 30, color:'#008', opacity:0.7
            }); break;            // Spraypaint for splatter :contentReference[oaicite:8]{index=8}
        }
      });
    });

    // Init with one layer
    window.addEventListener('DOMContentLoaded',()=> addLayer('Layer 1'));
    addLayerBtn.addEventListener('click',()=>addLayer(`Layer ${layers.length+1}`));
  </script>
</body>
</html>