Здесь делается вжух 🪄

test

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » test » новый не новый » рас


рас

Сообщений 1 страница 20 из 20

1

[html]
<div style="max-width:700px;margin:10px auto;padding:15px;background:#fafafa;border:1px solid #ccc;border-radius:10px;">
  <h2 style="text-align:center;">🎨 Онлайн-раскраска</h2>
  <p style="font-size:13px;text-align:center;color:#555;">
    Выберите цвет и кликните по элементу картинки, чтобы закрасить.
    Администратор может загрузить собственную картинку (SVG-файл).
  </p>

  <!-- Панель управления -->
  <div style="display:flex;flex-wrap:wrap;justify-content:center;gap:10px;margin-bottom:10px;">
    <input type="color" id="colorPicker" value="#ff6666" style="width:60px;height:40px;border:none;cursor:pointer;">
    <button onclick="randomColor()" style="padding:6px 10px;">🎲 Случайный</button>
    <button onclick="clearColors()" style="padding:6px 10px;">🧽 Очистить</button>
    <button onclick="copySVG()" style="padding:6px 10px;">📋 Скопировать</button>
    <button onclick="downloadSVG()" style="padding:6px 10px;">⬇️ Скачать</button>
    <label style="cursor:pointer;padding:6px 10px;background:#eee;border-radius:5px;">
      📁 Загрузить картинку
      <input type="file" id="upload" accept=".svg" style="display:none;">
    </label>
  </div>

  <!-- Область для SVG -->
  <div id="coloringArea" style="border:1px dashed #bbb;background:#fff;padding:10px;text-align:center;">
    <svg id="drawing" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300" width="100%" height="auto">
      <rect width="400" height="300" fill="#fff"/>
      <circle class="fillable" cx="100" cy="150" r="50" stroke="#000" fill="#fff"/>
      <rect class="fillable" x="200" y="100" width="120" height="100" stroke="#000" fill="#fff" rx="10"/>
      <polygon class="fillable" points="150,50 180,100 120,100" stroke="#000" fill="#fff"/>
      <text x="100" y="280" text-anchor="middle" font-size="16" fill="#444">Пример изображения</text>
    </svg>
  </div>
</div>

<script>
(function() {
  const svg = document.getElementById('drawing');
  const picker = document.getElementById('colorPicker');
  const upload = document.getElementById('upload');
  let activeColor = picker.value;

  // Клик по области
  svg.addEventListener('click', (e) => {
    if (e.target.classList.contains('fillable')) {
      e.target.setAttribute('fill', activeColor);
    }
  });

  // Выбор цвета
  picker.addEventListener('input', (e) => activeColor = e.target.value);

  // Случайный цвет
  window.randomColor = function() {
    const r = Math.floor(Math.random() * 256);
    const g = Math.floor(Math.random() * 256);
    const b = Math.floor(Math.random() * 256);
    activeColor = `rgb(${r},${g},${b})`;
    picker.value = rgbToHex(r,g,b);
  };

  function rgbToHex(r,g,b){
    return "#" + [r,g,b].map(x=>{
      const h=x.toString(16); return h.length===1?'0'+h:h;
    }).join('');
  }

  // Очистить цвета
  window.clearColors = function() {
    svg.querySelectorAll('.fillable').forEach(el => el.setAttribute('fill','#fff'));
  };

  // Копировать SVG
  window.copySVG = function() {
    const text = new XMLSerializer().serializeToString(svg);
    navigator.clipboard.writeText(text);
    alert('SVG-код скопирован! Вставьте его в сообщение или сохраните как файл.');
  };

  // Скачать
  window.downloadSVG = function() {
    const text = new XMLSerializer().serializeToString(svg);
    const blob = new Blob([text], {type:'image/svg+xml'});
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url; a.download = 'raskraska.svg';
    a.click();
    URL.revokeObjectURL(url);
  };

  // Загрузка SVG-файла
  upload.addEventListener('change', (e) => {
    const file = e.target.files[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = function(ev) {
      document.getElementById('coloringArea').innerHTML = ev.target.result;
      document.getElementById('coloringArea').querySelectorAll('.fillable').forEach(el => {
        el.addEventListener('click', evt => {
          evt.target.setAttribute('fill', activeColor);
        });
      });
    };
    reader.readAsText(file);
  });
})();
</script>
[/html]

0

2

[html]
<div style="max-width:720px;margin:10px auto;padding:15px;background:#fafafa;border:1px solid #ccc;border-radius:10px;">
  <h2 style="text-align:center;">🎨 Онлайн-раскраска</h2>
  <p style="font-size:13px;text-align:center;color:#555;">
    Кликните по области картинки, чтобы закрасить выбранным цветом.<br>
    Администратор может загрузить свой <b>SVG</b> — он автоматически подстроится под формат поля.
  </p>

  <!-- Панель управления -->
  <div style="display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-bottom:10px;">
    <input type="color" id="colorPicker" value="#ff6666" style="width:60px;height:40px;border:none;cursor:pointer;">
    <button onclick="randomColor()" style="padding:6px 10px;">🎲 Случайный</button>
    <button onclick="clearColors()" style="padding:6px 10px;">🧽 Очистить</button>
    <button onclick="copySVG()" style="padding:6px 10px;">📋 Скопировать</button>
    <button onclick="downloadSVG()" style="padding:6px 10px;">⬇️ Скачать</button>
    <label style="cursor:pointer;padding:6px 10px;background:#eee;border-radius:5px;">
      📁 Загрузить SVG
      <input type="file" id="upload" accept=".svg" style="display:none;">
    </label>
  </div>

  <!-- Палитра -->
  <div id="palette" style="display:flex;flex-wrap:wrap;justify-content:center;gap:6px;margin-bottom:10px;"></div>

  <!-- Область для SVG -->
  <div id="coloringArea" style="border:1px dashed #bbb;background:#fff;padding:10px;text-align:center;min-height:400px;display:flex;align-items:center;justify-content:center;">
    <svg id="drawing" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300" width="100%" height="auto" preserveAspectRatio="xMidYMid meet">
      <rect width="400" height="300" fill="#fff"/>
      <circle class="fillable" cx="100" cy="150" r="50" stroke="#000" fill="#fff"/>
      <rect class="fillable" x="200" y="100" width="120" height="100" stroke="#000" fill="#fff" rx="10"/>
      <polygon class="fillable" points="150,50 180,100 120,100" stroke="#000" fill="#fff"/>
      <text x="100" y="280" text-anchor="middle" font-size="16" fill="#444">Пример изображения</text>
    </svg>
  </div>
</div>

<script>
(function() {
  const svg = document.getElementById('drawing');
  const picker = document.getElementById('colorPicker');
  const upload = document.getElementById('upload');
  const paletteEl = document.getElementById('palette');
  const area = document.getElementById('coloringArea');
  let activeColor = picker.value;

  // Палитра из 20 цветов
  const palette = [
    "#ffffff","#000000","#ff6666","#ff9966","#ffcc66","#ffff66",
    "#ccff66","#99ff66","#66ff99","#66ffcc","#66ffff","#6699ff",
    "#9966ff","#cc66ff","#ff66ff","#ff66cc","#ff6699","#ff6666",
    "#999999","#663300"
  ];

  // Создание палитры
  palette.forEach(c => {
    const d = document.createElement('div');
    d.style.width = '28px';
    d.style.height = '28px';
    d.style.background = c;
    d.style.border = '1px solid #777';
    d.style.borderRadius = '4px';
    d.style.cursor = 'pointer';
    d.title = c;
    d.onclick = () => {
      activeColor = c;
      picker.value = c;
      document.querySelectorAll('#palette div').forEach(el=>el.style.outline='none');
      d.style.outline='3px solid #222';
    };
    paletteEl.appendChild(d);
  });

  // Клик по области
  svg.addEventListener('click', (e) => {
    if (e.target.classList.contains('fillable')) {
      e.target.setAttribute('fill', activeColor);
    }
  });

  // Изменение цвета
  picker.addEventListener('input', (e) => activeColor = e.target.value);

  // Случайный цвет
  window.randomColor = function() {
    const r = Math.floor(Math.random()*256);
    const g = Math.floor(Math.random()*256);
    const b = Math.floor(Math.random()*256);
    activeColor = `rgb(${r},${g},${b})`;
    picker.value = rgbToHex(r,g,b);
  };

  function rgbToHex(r,g,b){
    return "#" + [r,g,b].map(x=>{
      const h=x.toString(16); return h.length===1?'0'+h:h;
    }).join('');
  }

  // Очистить
  window.clearColors = function() {
    area.querySelectorAll('.fillable').forEach(el => el.setAttribute('fill','#fff'));
  };

  // Копировать
  window.copySVG = function() {
    const svgEl = area.querySelector('svg');
    const text = new XMLSerializer().serializeToString(svgEl);
    navigator.clipboard.writeText(text);
    alert('SVG-код скопирован!');
  };

  // Скачать
  window.downloadSVG = function() {
    const svgEl = area.querySelector('svg');
    const text = new XMLSerializer().serializeToString(svgEl);
    const blob = new Blob([text], {type:'image/svg+xml'});
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url; a.download = 'raskraska.svg';
    a.click();
    URL.revokeObjectURL(url);
  };

  // Загрузка SVG администрацией
  upload.addEventListener('change', (e) => {
    const file = e.target.files[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = function(ev) {
      const svgText = ev.target.result;
      // Очистка контейнера, сохранение отступов и рамки
      area.innerHTML = `<div style='width:100%;height:100%;display:flex;align-items:center;justify-content:center;'>${svgText}</div>`;
      const newSvg = area.querySelector('svg');
      if (newSvg) {
        // Автоматическое форматирование
        newSvg.setAttribute('width', '100%');
        newSvg.setAttribute('height', 'auto');
        newSvg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
        if (!newSvg.getAttribute('viewBox')) newSvg.setAttribute('viewBox', '0 0 600 400');
        // Добавляем клики по заливке
        newSvg.querySelectorAll('.fillable').forEach(el => {
          el.addEventListener('click', evt => {
            evt.target.setAttribute('fill', activeColor);
          });
        });
      }
    };
    reader.readAsText(file);
  });
})();
</script>
[/html]

0

3

[html]
<div style="max-width:720px;margin:10px auto;padding:15px;background:#fafafa;border:1px solid #ccc;border-radius:10px;">
  <h2 style="text-align:center;">🎨 Онлайн-раскраска</h2>
  <p style="font-size:13px;text-align:center;color:#555;">
    Кликните по любой части изображения, чтобы закрасить выбранным цветом.<br>
    Администратор может загрузить свой <b>SVG-файл</b> — система сама определит области для раскрашивания.
  </p>

  <!-- Панель -->
  <div style="display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-bottom:10px;">
    <input type="color" id="colorPicker" value="#ff6666" style="width:60px;height:40px;border:none;cursor:pointer;">
    <button onclick="randomColor()" style="padding:6px 10px;">🎲 Случайный</button>
    <button onclick="clearColors()" style="padding:6px 10px;">🧽 Очистить</button>
    <button onclick="copySVG()" style="padding:6px 10px;">📋 Скопировать</button>
    <button onclick="downloadSVG()" style="padding:6px 10px;">⬇️ Скачать</button>
    <label style="cursor:pointer;padding:6px 10px;background:#eee;border-radius:5px;">
      📁 Загрузить SVG
      <input type="file" id="upload" accept=".svg" style="display:none;">
    </label>
  </div>

  <!-- Палитра -->
  <div id="palette" style="display:flex;flex-wrap:wrap;justify-content:center;gap:6px;margin-bottom:10px;"></div>

  <!-- Поле -->
  <div id="coloringArea" style="border:1px dashed #bbb;background:#fff;padding:10px;text-align:center;min-height:400px;display:flex;align-items:center;justify-content:center;">
    <svg id="drawing" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300" width="100%" height="auto" preserveAspectRatio="xMidYMid meet">
      <rect width="400" height="300" fill="#fff"/>
      <circle cx="100" cy="150" r="50" stroke="#000" fill="#fff"/>
      <rect x="200" y="100" width="120" height="100" stroke="#000" fill="#fff" rx="10"/>
      <polygon points="150,50 180,100 120,100" stroke="#000" fill="#fff"/>
      <text x="100" y="280" text-anchor="middle" font-size="16" fill="#444">Пример изображения</text>
    </svg>
  </div>
</div>

<script>
(function() {
  const area = document.getElementById('coloringArea');
  const picker = document.getElementById('colorPicker');
  const upload = document.getElementById('upload');
  const paletteEl = document.getElementById('palette');
  let activeColor = picker.value;

  // 🎨 Палитра 20 цветов
  const palette = [
    "#ffffff","#000000","#ff6666","#ff9966","#ffcc66","#ffff66",
    "#ccff66","#99ff66","#66ff99","#66ffcc","#66ffff","#6699ff",
    "#9966ff","#cc66ff","#ff66ff","#ff66cc","#ff6699","#999999","#663300","#00cc99"
  ];

  palette.forEach(c => {
    const d = document.createElement('div');
    d.style.width = '28px';
    d.style.height = '28px';
    d.style.background = c;
    d.style.border = '1px solid #777';
    d.style.borderRadius = '4px';
    d.style.cursor = 'pointer';
    d.title = c;
    d.onclick = () => {
      activeColor = c;
      picker.value = c;
      document.querySelectorAll('#palette div').forEach(el=>el.style.outline='none');
      d.style.outline='3px solid #222';
    };
    paletteEl.appendChild(d);
  });

  // Изменение цвета
  picker.addEventListener('input', (e) => activeColor = e.target.value);

  // 🎲 Случайный цвет
  window.randomColor = function() {
    const r = Math.floor(Math.random()*256);
    const g = Math.floor(Math.random()*256);
    const b = Math.floor(Math.random()*256);
    activeColor = `rgb(${r},${g},${b})`;
    picker.value = rgbToHex(r,g,b);
  };

  function rgbToHex(r,g,b){
    return "#" + [r,g,b].map(x=>{
      const h=x.toString(16); return h.length===1?'0'+h:h;
    }).join('');
  }

  // 🧽 Очистить
  window.clearColors = function() {
    area.querySelectorAll('path,rect,circle,ellipse,polygon,polyline').forEach(el => {
      el.setAttribute('fill','#fff');
    });
  };

  // 📋 Копировать
  window.copySVG = function() {
    const svgEl = area.querySelector('svg');
    const text = new XMLSerializer().serializeToString(svgEl);
    navigator.clipboard.writeText(text);
    alert('SVG-код скопирован!');
  };

  // ⬇️ Скачать
  window.downloadSVG = function() {
    const svgEl = area.querySelector('svg');
    const text = new XMLSerializer().serializeToString(svgEl);
    const blob = new Blob([text], {type:'image/svg+xml'});
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url; a.download = 'raskraska.svg';
    a.click();
    URL.revokeObjectURL(url);
  };

  // 🖼️ Функция сделать SVG кликабельным
  function makeFillable(svg) {
    const fillableEls = svg.querySelectorAll('path,rect,circle,ellipse,polygon,polyline');
    fillableEls.forEach(el => {
      el.style.cursor = 'pointer';
      el.addEventListener('click', e => {
        e.target.setAttribute('fill', activeColor);
      });
      // если нет заливки — делаем белой
      if (!el.getAttribute('fill') || el.getAttribute('fill') === 'none') {
        el.setAttribute('fill', '#fff');
      }
    });
  }

  // 📁 Загрузка SVG
  upload.addEventListener('change', (e) => {
    const file = e.target.files[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = function(ev) {
      const svgText = ev.target.result;
      area.innerHTML = `<div style='width:100%;height:100%;display:flex;align-items:center;justify-content:center;'>${svgText}</div>`;
      const newSvg = area.querySelector('svg');
      if (newSvg) {
        newSvg.setAttribute('width', '100%');
        newSvg.setAttribute('height', 'auto');
        newSvg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
        if (!newSvg.getAttribute('viewBox')) newSvg.setAttribute('viewBox', '0 0 600 400');
        makeFillable(newSvg);
      }
    };
    reader.readAsText(file);
  });

  // активируем стандартное SVG
  makeFillable(document.getElementById('drawing'));
})();
</script>
[/html]

0

4

[html]
<div style="max-width:720px;margin:10px auto;padding:15px;background:#fafafa;border:1px solid #ccc;border-radius:10px;">
  <h2 style="text-align:center;">🎨 Раскраска с заливкой областей</h2>
  <p style="font-size:13px;text-align:center;color:#555;">
    Кликните по белой области, чтобы закрасить её выбранным цветом.<br>
    Контурные рисунки автоматически становятся интерактивными.
  </p>

  <div style="display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-bottom:10px;">
    <input type="color" id="colorPicker" value="#ff6666" style="width:60px;height:40px;border:none;cursor:pointer;">
    <button onclick="randomColor()" style="padding:6px 10px;">🎲 Случайный</button>
    <button onclick="clearColors()" style="padding:6px 10px;">🧽 Очистить</button>
    <button onclick="copySVG()" style="padding:6px 10px;">📋 Скопировать</button>
    <button onclick="downloadSVG()" style="padding:6px 10px;">⬇️ Скачать</button>
  </div>

  <div id="coloringArea" style="border:1px dashed #bbb;background:#fff;padding:10px;text-align:center;min-height:400px;display:flex;align-items:center;justify-content:center;">
    ⏳ Загрузка картинки...
  </div>
</div>

<script>
(function(){
  const area = document.getElementById('coloringArea');
  const picker = document.getElementById('colorPicker');
  let activeColor = picker.value;

  // 🖼️ Админская картинка (контурное SVG)
  const SVG_URL = "https://forumstatic.ru/files/001c/84/76/90451.svg"; // ← вставь сюда ссылку на своё SVG

  picker.addEventListener('input', e => activeColor = e.target.value);
  window.randomColor = function(){
    const r=Math.floor(Math.random()*256),g=Math.floor(Math.random()*256),b=Math.floor(Math.random()*256);
    activeColor=`rgb(${r},${g},${b})`;
    picker.value=rgbToHex(r,g,b);
  };
  function rgbToHex(r,g,b){return"#"+[r,g,b].map(x=>{const h=x.toString(16);return h.length===1?'0'+h:h;}).join('');}

  window.clearColors=function(){
    area.querySelectorAll('path,rect,circle,ellipse,polygon').forEach(el=>{
      if (el.getAttribute('data-fillable')==='true') el.setAttribute('fill','#fff');
    });
  };
  window.copySVG=function(){
    const svg=area.querySelector('svg');
    const text=new XMLSerializer().serializeToString(svg);
    navigator.clipboard.writeText(text);
    alert('SVG скопирован!');
  };
  window.downloadSVG=function(){
    const svg=area.querySelector('svg');
    const text=new XMLSerializer().serializeToString(svg);
    const blob=new Blob([text],{type:'image/svg+xml'});
    const url=URL.createObjectURL(blob);
    const a=document.createElement('a');a.href=url;a.download='raskraska.svg';a.click();
    URL.revokeObjectURL(url);
  };

  // Загружаем SVG
  fetch(SVG_URL)
  .then(r=>r.text())
  .then(svgText=>{
    area.innerHTML = `<div style='width:100%;height:100%;display:flex;align-items:center;justify-content:center;'>${svgText}</div>`;
    const svg = area.querySelector('svg');
    if (!svg) return area.innerHTML = "Ошибка загрузки SVG";

    svg.setAttribute('width','100%');
    svg.setAttribute('height','auto');
    svg.setAttribute('preserveAspectRatio','xMidYMid meet');

    // Создаём заливки под линиями
    const paths = svg.querySelectorAll('path,polygon,rect,circle,ellipse');
    paths.forEach(p=>{
      const clone = p.cloneNode(true);
      clone.removeAttribute('stroke');
      clone.setAttribute('fill','#fff');
      clone.setAttribute('data-fillable','true');
      clone.style.cursor='pointer';
      clone.addEventListener('click', e => {
        e.target.setAttribute('fill', activeColor);
      });
      p.parentNode.insertBefore(clone, p); // вставляем под оригинальную линию
    });
  })
  .catch(()=>{
    area.innerHTML = "<p style='color:red;'>Не удалось загрузить изображение.</p>";
  });
})();
</script>
[/html]

0

5

[html]
<div id="coloring" style="text-align:center;">
  <h3>🎨 Раскраска</h3>
  <input type="color" id="color" value="#ff6666"><br><br>

  <svg id="pic" width="200" height="200" viewBox="0 0 200 200">
    <!-- Контур -->
    <path d="M50 50 L150 50 L150 150 L50 150 Z" stroke="black" fill="#fff" data-fillable="true"></path>
    <circle cx="100" cy="100" r="30" stroke="black" fill="#fff" data-fillable="true"></circle>
  </svg>
</div>

<script>
const picker = document.getElementById('color');
let active = picker.value;
picker.addEventListener('input', e => active = e.target.value);
document.querySelectorAll('[data-fillable]').forEach(el=>{
  el.style.cursor='pointer';
  el.addEventListener('click', e=>{
    e.target.setAttribute('fill', active);
  });
});
</script>
[/html]

0

6

[html]
<div id="coloringApp" style="text-align:center; font-family:sans-serif;">
  <h3>🧟‍♂️ Раскраска Зомби</h3>

  <!-- Палитра -->
  <div id="palette" style="margin:10px 0; display:flex; flex-wrap:wrap; justify-content:center; gap:5px;"></div>
  <input type="color" id="customColor" value="#000000" title="Выбрать свой цвет">
  <p><small>Нажмите на цвет, затем кликните по области картинки</small></p>

  <!-- Картинка -->
  <div id="canvas" style="display:inline-block; border:1px solid #ccc; border-radius:10px; padding:10px; background:#fff;">
    <img id="zombie" xmlns="https://forumstatic.ru/files/001c/84/76/80305.svg" viewBox="0 0 800 800" width="400" height="400">
      <!-- 🔹 Здесь администратор может заменить рисунок на другой SVG -->
      <!-- Твой текущий файл встроен ниже -->
      <g stroke="#000" stroke-width="2" fill="#fff" class="fillable">
        <path d="M247.4 32.6c-..." /> <!-- Сокращённый пример -->
      </g>
    </svg>
  </div>
</div>

<script>
(function() {
  // 🎨 Палитра из 20 цветов
  const colors = [
    '#ff0000','#ff7f00','#ffff00','#7fff00','#00ff00',
    '#00ff7f','#00ffff','#007fff','#0000ff','#7f00ff',
    '#ff00ff','#ff007f','#ff6666','#ffcc00','#ccff00',
    '#66ffcc','#00ccff','#3399ff','#9966ff','#ff99cc'
  ];
 
  const palette = document.getElementById('palette');
  let activeColor = colors[0];
 
  colors.forEach(c => {
    const btn = document.createElement('div');
    btn.style.background = c;
    btn.style.width = '25px';
    btn.style.height = '25px';
    btn.style.border = '1px solid #333';
    btn.style.cursor = 'pointer';
    btn.style.borderRadius = '4px';
    btn.title = c;
    btn.onclick = () => { activeColor = c; };
    palette.appendChild(btn);
  });

  const custom = document.getElementById('customColor');
  custom.addEventListener('input', e => activeColor = e.target.value);

  // 🖌️ Раскрашивание кликом
  document.querySelectorAll('#zombie path').forEach(el => {
    el.style.cursor = 'pointer';
    el.addEventListener('click', e => {
      e.target.setAttribute('fill', activeColor);
    });
  });
})();
</script>
[/html]

0

7

[html]
<div id="coloringApp" style="text-align:center; font-family:sans-serif;">
  <h3>🧟‍♂️ Раскраска</h3>

  <!-- 🎨 Палитра -->
  <div id="palette" style="margin:10px 0; display:flex; flex-wrap:wrap; justify-content:center; gap:5px;"></div>
  <input type="color" id="customColor" value="#000000" title="Выбрать свой цвет">
  <p><small>Выберите цвет и кликайте по картинке, чтобы "раскрасить"</small></p>

  <!-- 🖼️ Картинка администратора -->
  <div style="position:relative; display:inline-block; border:1px solid #aaa; border-radius:8px;">
    <img id="baseImg"
         src="https://upforme.ru/uploads/001c/84/76/2/160064.jpg"
         alt="Раскраска"
         style="width:400px; height:auto; display:block; border-radius:8px;">
    <canvas id="overlay" width="400" height="400"
            style="position:absolute; left:0; top:0; cursor:crosshair; border-radius:8px;"></canvas>
  </div>
</div>

<script>
(function() {
  // 🎨 Палитра из 20 цветов
  const colors = [
    '#ff0000','#ff7f00','#ffff00','#7fff00','#00ff00',
    '#00ff7f','#00ffff','#007fff','#0000ff','#7f00ff',
    '#ff00ff','#ff007f','#ff6666','#ffcc00','#ccff00',
    '#66ffcc','#00ccff','#3399ff','#9966ff','#ff99cc'
  ];

  const palette = document.getElementById('palette');
  let activeColor = colors[0];

  colors.forEach(c => {
    const swatch = document.createElement('div');
    Object.assign(swatch.style, {
      background:c,width:'25px',height:'25px',
      border:'1px solid #333',cursor:'pointer',borderRadius:'4px'
    });
    swatch.title = c;
    swatch.onclick = () => activeColor = c;
    palette.appendChild(swatch);
  });

  const custom = document.getElementById('customColor');
  custom.addEventListener('input', e => activeColor = e.target.value);

  // 🖌️ Рисование поверх изображения
  const canvas = document.getElementById('overlay');
  const ctx = canvas.getContext('2d');
  let painting = false;

  canvas.addEventListener('mousedown', e => { painting = true; draw(e); });
  canvas.addEventListener('mouseup', () => painting = false);
  canvas.addEventListener('mouseleave', () => painting = false);
  canvas.addEventListener('mousemove', draw);

  function draw(e) {
    if (!painting) return;
    const rect = canvas.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    ctx.fillStyle = activeColor;
    ctx.beginPath();
    ctx.arc(x, y, 6, 0, Math.PI * 2);
    ctx.fill();
  }
})();
</script>
[/html]

0

8

[html]
<div id="coloringApp" style="display:inline-block;position:relative;">
   <!-- 🎨 SVG-КАРТИНКА, которую может менять администратор -->
  <svg id="coloringSVG" xmlns="https://forumstatic.ru/files/001c/84/76/90451.svg" viewBox="0 0 600 600" width="600" height="600">
  <path d="M150 100 Q300 0 450 100 T600 300 T450 500 Q300 600 150 500 T0 300 T150 100 Z"
          fill="#ffffff" stroke="#000000" stroke-width="3"/>
    <circle cx="250" cy="250" r="40" fill="#ffffff" stroke="#000000" stroke-width="3"/>
    <circle cx="350" cy="250" r="40" fill="#ffffff" stroke="#000000" stroke-width="3"/>
    <rect x="270" y="350" width="60" height="20" fill="#ffffff" stroke="#000000" stroke-width="3"/>
  </svg>
</div>

<!-- 🎨 Палитра -->
<div id="palette" style="margin-top:10px;display:flex;flex-wrap:wrap;gap:4px;"></div>
<input type="color" id="customColor" value="#000000" title="Выбери свой цвет">
<p style="font-size:12px;color:#555;">💡 Кликни по области, чтобы закрасить. Цвет сохраняется локально в браузере.</p>

<script>
(function(){
  const svg = document.getElementById('coloringSVG');
  const palette = document.getElementById('palette');
  const customColor = document.getElementById('customColor');

  const paletteColors = [
    "#ff0000","#ff7f00","#ffff00","#7fff00","#00ff00",
    "#00ff7f","#00ffff","#007fff","#0000ff","#7f00ff",
    "#ff00ff","#ff007f","#ff6666","#ffaa00","#aaff00",
    "#00ffaa","#00aaff","#aa00ff","#ff00aa","#000000"
  ];

  let currentColor = "#000000";

  // создать палитру
  paletteColors.forEach(c=>{
    const div=document.createElement('div');
    div.style.background=c;
    div.style.width="25px";
    div.style.height="25px";
    div.style.border="1px solid #333";
    div.style.cursor="pointer";
    div.onclick=()=>{currentColor=c;};
    palette.appendChild(div);
  });
  customColor.oninput=()=>{currentColor=customColor.value;};

  // закраска по клику
  svg.addEventListener('click',function(e){
    const target = e.target;
    if(target.tagName==="path" || target.tagName==="circle" || target.tagName==="rect" || target.tagName==="polygon"){
      target.setAttribute("fill", currentColor);
      saveColors();
    }
  });

  // сохранить цвета локально
  function saveColors(){
    const colors = {};
    svg.querySelectorAll('*[fill]').forEach((el,i)=>{
      colors[i]=el.getAttribute('fill');
    });
    localStorage.setItem('coloringData', JSON.stringify(colors));
  }

  // восстановить сохранённые цвета
  function loadColors(){
    const saved = localStorage.getItem('coloringData');
    if(!saved) return;
    const colors = JSON.parse(saved);
    svg.querySelectorAll('*[fill]').forEach((el,i)=>{
      if(colors[i]) el.setAttribute('fill', colors[i]);
    });
  }

  loadColors();
})();
</script>
[/html]

0

9

[html]<div class="coloring-book">
   
    <div id="color-palette">
        <div class="color-swatch" style="background-color: #FF5733;" data-color="#FF5733" title="Оранжевый"></div>
        <div class="color-swatch" style="background-color: #33FF57;" data-color="#33FF57" title="Зеленый"></div>
        <div class="color-swatch" style="background-color: #3357FF;" data-color="#3357FF" title="Синий"></div>
        <div class="color-swatch" style="background-color: #FF33A1;" data-color="#FF33A1" title="Розовый"></div>
        <div class="color-swatch" style="background-color: #FFE033;" data-color="#FFE033" title="Желтый"></div>
        <div class="color-swatch" style="background-color: #9A33FF;" data-color="#9A33FF" title="Фиолетовый"></div>
    </div>
   
    <div id="svg-container">
        <object type="image/svg+xml" data="https://forumstatic.ru/files/001c/84/76/90451.svg" id="coloring-svg">
            Ваш браузер не поддерживает SVG.
        </object>
    </div>

</div>

<style>
.coloring-book {
    max-width: 600px;
    margin: 10px auto;
    text-align: center;
    border: 1px solid #ccc;
    padding: 10px;
}

#color-palette {
    margin-bottom: 10px;
}

.color-swatch {
    display: inline-block;
    width: 30px;
    height: 30px;
    border: 2px solid #000;
    margin: 3px;
    cursor: pointer;
    border-radius: 50%;
    transition: transform 0.1s;
}

.color-swatch.selected {
    border-color: red;
    border-width: 4px;
    transform: scale(1.1);
}

#svg-container object {
    width: 100%;
    height: auto;
    display: block;
}

/* Стилизация раскрашиваемых элементов в SVG:
   делаем их кликабельными и явно устанавливаем белый цвет по умолчанию */
#coloring-svg * {
    cursor: pointer;
    /* Убедитесь, что все элементы, которые нужно раскрашивать, изначально белые */
    /* Если у вас в SVG они не белые, то нужно их изменить! */
    /* fill: white; /* раскомментируйте, если нужно принудительно установить начальный цвет */
}

/* Черные линии (stroke или fill="black") должны быть некликабельными,
   или их нужно исключить из логики JS */
</style>

<script>
// Проверка на наличие JQuery (часто есть на форумах)
// Если нет, код может быть адаптирован под чистый JS.
if (typeof jQuery == 'undefined') {
    // Вставьте здесь код чистого JS или используйте JQuery-свободные аналоги.
    console.error("Требуется jQuery для этого скрипта или нужно переписать на чистый JS.");
} else {
    $(document).ready(function() {
        let currentColor = '';

        // 1. Выбор цвета
        $('.color-swatch').on('click', function() {
            $('.color-swatch').removeClass('selected');
            $(this).addClass('selected');
            currentColor = $(this).data('color');
        });

        // Инициализация: выбор первого цвета по умолчанию
        $('.color-swatch:first').trigger('click');

        // 2. Получение доступа к SVG и добавление обработчика клика
        // Используем .load() для iframe/object - это может быть сложно.
        // Более надежный способ: использовать тег <object> и получить его contentDocument.
        const svgObject = document.getElementById('coloring-svg');

        svgObject.onload = function() {
            const svgDoc = svgObject.contentDocument;
            if (!svgDoc) {
                console.error("Не удалось получить доступ к контенту SVG.");
                return;
            }

            // Добавляем обработчик клика ко всем элементам внутри SVG
            // которые, как предполагается, являются раскрашиваемыми областями (т.е. не черные линии).
            $(svgDoc).find('path, polygon, rect, circle, ellipse').on('click', function(event) {
                const $target = $(event.target);
               
                // Проверяем, что элемент не черный (черные линии не раскрашиваются)
                // Нужно, чтобы в SVG черные линии имели fill="black" или другой явный цвет
                // А раскрашиваемые области - fill="white" или fill="none"
                // Простая эвристика: если fill не черный И не имеет stroke (чтобы не закрасить линии)
                // Эту логику, возможно, придется настроить под ваш конкретный SVG.
                const currentFill = $target.attr('fill') || 'white';
               
                // Проверяем, что текущий fill не является черным или околочерным
                if (currentColor && currentFill.toLowerCase() !== '#000000' && currentFill.toLowerCase() !== 'black') {
                    $target.attr('fill', currentColor);
                }
            });
           
            // Опционально: если вы хотите закрашивать ТОЛЬКО белые области:
            /*
            $(svgDoc).find('path, polygon, rect, circle, ellipse').on('click', function(event) {
                const $target = $(event.target);
                const currentFill = $target.attr('fill');
               
                // Закрашиваем, только если текущий цвет — белый или не установлен.
                if (currentColor && (currentFill === 'white' || currentFill === '#fff' || !currentFill)) {
                    $target.attr('fill', currentColor);
                }
            });
            */
           
            console.log("SVG раскраска готова к использованию.");
        };

        // Обработка случая, если SVG уже загружен до навешивания onload (редко, но бывает)
        if (svgObject.contentDocument && svgObject.contentDocument.readyState === 'complete') {
             svgObject.onload(); // Вызываем вручную
        }
    });
}
</script>[/html]

0

10

[html]
<div id="paintApp" style="text-align:center;">
  <h3>🎨 Онлайн-раскраска</h3>

  <!-- Администратор вставляет сюда ссылку на контур -->
  <img id="baseImage" src="https://upforme.ru/uploads/001c/84/76/2/493564.jpg" alt="Контур" style="display:none;">

  <div style="margin-bottom:10px;">
    <button id="clearBtn">🧹 Очистить всё</button>
    <button id="eraserBtn">🩹 Ластик</button>
    <button id="pickerBtn">🎯 Пипетка</button>

    <label style="margin-left:10px;">Размер кисти:
      <input type="range" id="brushSize" min="1" max="30" value="5">
    </label>
  </div>

  <div style="margin:10px 0;">
    <strong>Выбери цвет:</strong>
    <input type="color" id="customColor" value="#000000">
  </div>

  <canvas id="paintCanvas" style="border:1px solid #555;cursor:crosshair;max-width:100%;height:auto;"></canvas>
</div>

<script>
(function() {
  const canvas = document.getElementById('paintCanvas');
  const ctx = canvas.getContext('2d');
  const baseImage = document.getElementById('baseImage');
  const clearBtn = document.getElementById('clearBtn');
  const eraserBtn = document.getElementById('eraserBtn');
  const pickerBtn = document.getElementById('pickerBtn');
  const brushSize = document.getElementById('brushSize');
  const customColor = document.getElementById('customColor');

  let painting = false;
  let erasing = false;
  let picking = false;
  let color = '#000000';
  let size = 5;
  let imgScale = 1;

  // Загружаем контур и подгоняем под окно
  baseImage.onload = function() {
    resizeCanvas();
    drawBase();
  };

  // Масштаб при изменении окна
  window.addEventListener('resize', () => {
    const saved = ctx.getImageData(0, 0, canvas.width, canvas.height);
    resizeCanvas();
    ctx.putImageData(saved, 0, 0);
    drawBase();
  });

  function resizeCanvas() {
    const maxWidth = document.getElementById('paintApp').clientWidth - 20;
    imgScale = Math.min(maxWidth / baseImage.width, 1);
    canvas.width = baseImage.width * imgScale;
    canvas.height = baseImage.height * imgScale;
  }

  function drawBase() {
    ctx.drawImage(baseImage, 0, 0, baseImage.width * imgScale, baseImage.height * imgScale);
  }

  // Рисование
  canvas.addEventListener('mousedown', (e) => {
    if (picking) {
      pickColor(e);
      return;
    }
    painting = true;
    draw(e);
  });

  canvas.addEventListener('mouseup', stopPaint);
  canvas.addEventListener('mouseout', stopPaint);
  canvas.addEventListener('mousemove', draw);

  function stopPaint() {
    painting = false;
    ctx.beginPath();
  }

  function draw(e) {
    if (!painting || picking) return;
    const rect = canvas.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;

    ctx.lineWidth = size;
    ctx.lineCap = 'round';
    ctx.strokeStyle = erasing ? '#ffffff' : color;

    ctx.lineTo(x, y);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(x, y);
  }

  // Смена цвета
  customColor.addEventListener('input', () => {
    color = customColor.value;
    erasing = false;
    picking = false;
    eraserBtn.style.background = '';
    pickerBtn.style.background = '';
  });

  // Ластик
  eraserBtn.addEventListener('click', () => {
    erasing = !erasing;
    picking = false;
    eraserBtn.style.background = erasing ? '#ddd' : '';
    pickerBtn.style.background = '';
  });

  // Пипетка
  pickerBtn.addEventListener('click', () => {
    picking = !picking;
    erasing = false;
    pickerBtn.style.background = picking ? '#ddd' : '';
    eraserBtn.style.background = '';
  });

  function pickColor(e) {
    const rect = canvas.getBoundingClientRect();
    const x = Math.floor(e.clientX - rect.left);
    const y = Math.floor(e.clientY - rect.top);
    const pixel = ctx.getImageData(x, y, 1, 1).data;
    const pickedColor = `rgb(${pixel[0]}, ${pixel[1]}, ${pixel[2]})`;
    color = rgbToHex(pixel[0], pixel[1], pixel[2]);
    customColor.value = color;
    picking = false;
    pickerBtn.style.background = '';
  }

  function rgbToHex(r, g, b) {
    return (
      '#' +
      [r, g, b]
        .map((v) => {
          const hex = v.toString(16);
          return hex.length === 1 ? '0' + hex : hex;
        })
        .join('')
    );
  }

  // Очистить (перерисовывает контур)
  clearBtn.addEventListener('click', () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawBase();
  });

  // Размер кисти
  brushSize.addEventListener('input', () => {
    size = brushSize.value;
  });
})();
</script>
[/html]

0

11

[html]<div class="row">
    <img class="overlay" src="https://sandmoshi.github.io/eColorBook/pages/fox-trans.png"/>
    <div class="col-8">
     
    <canvas id="c" height="600" width="800" style="border:1px solid #aaa;"></canvas>
    </div>
    <div class="col-4">

    <div style="">
        <button id="drawing-mode" class="btn btn-info">Cancel drawing mode</button><br>
        <button id="clear-canvas" class="btn btn-info">Clear</button><br>

        <div id="drawing-mode-options">
        <label for="drawing-mode-selector">Mode:</label>
        <select id="drawing-mode-selector">
            <option>Pencil</option>
            <option>Circle</option>
            <option>Spray</option>
            <option>Pattern</option>

            <option>hline</option>
            <option>vline</option>
            <option>square</option>
            <option>diamond</option>
            <option>texture</option>
        </select><br>

        <label for="drawing-line-width">Line width:</label>
        <span class="info">30</span><input type="range" value="30" min="0" max="150" id="drawing-line-width"><br>

        <label for="drawing-color">Line color:</label>
        <input type="color" value="#005E7A" id="drawing-color"><br>

        <label for="drawing-shadow-color">Shadow color:</label>
        <input type="color" value="#005E7A" id="drawing-shadow-color"><br>

        <label for="drawing-shadow-width">Shadow width:</label>
        <span class="info">0</span><input type="range" value="0" min="0" max="50" id="drawing-shadow-width"><br>

        <label for="drawing-shadow-offset">Shadow offset:</label>
        <span class="info">0</span><input type="range" value="0" min="0" max="50" id="drawing-shadow-offset"><br>
        </div>
    </div>

    </div>
</div>[/html]

0

12

[html]
<style>
.coloring-container {
  position: relative;
  display: inline-block;
}
.coloring-container img.overlay {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none; /* не мешает рисованию */
  width: 800px;
  height: 600px;
  z-index: 2; /* поверх закраски */
  opacity: 1; /* полностью видимый контур */
}
.coloring-container canvas {
  position: relative;
  z-index: 1;
}
.controls {
  margin-top: 10px;
}
</style>

<div class="coloring-container">
  <!-- Картинка-контур, под которой рисуем -->
  <img class="overlay" src="https://sandmoshi.github.io/eColorBook/pages/fox-trans.png" alt="Контур">
  <canvas id="c" width="800" height="600"></canvas>
</div>

<div class="controls">
  <label>🎨 Цвет: <input type="color" id="brushColor" value="#ff0000"></label>
  <label>Размер кисти: <input type="range" id="brushSize" min="1" max="100" value="25"></label>
  <button id="clearCanvas">Очистить</button>
</div>

<script>
(function() {
  const canvas = document.getElementById('c');
  const ctx = canvas.getContext('2d');
  let painting = false;

  const colorPicker = document.getElementById('brushColor');
  const sizePicker = document.getElementById('brushSize');
  const clearBtn = document.getElementById('clearCanvas');

  function startPosition(e) {
    painting = true;
    draw(e);
  }

  function endPosition() {
    painting = false;
    ctx.beginPath();
  }

  function draw(e) {
    if (!painting) return;

    const rect = canvas.getBoundingClientRect();
    const x = (e.clientX || e.touches?.[0]?.clientX) - rect.left;
    const y = (e.clientY || e.touches?.[0]?.clientY) - rect.top;

    ctx.lineWidth = sizePicker.value;
    ctx.lineCap = 'round';
    ctx.strokeStyle = colorPicker.value;

    ctx.lineTo(x, y);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(x, y);
  }

  // Очистка
  clearBtn.addEventListener('click', () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  });

  // События
  canvas.addEventListener('mousedown', startPosition);
  canvas.addEventListener('mouseup', endPosition);
  canvas.addEventListener('mousemove', draw);

  canvas.addEventListener('touchstart', startPosition);
  canvas.addEventListener('touchend', endPosition);
  canvas.addEventListener('touchmove', draw);

})();
</script>
[/html]

0

13

[html]
<style>
.coloring-wrapper {
  position: relative;
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
  text-align: center;
}
.coloring-container {
  position: relative;
  display: inline-block;
  width: 100%;
}
.coloring-container img.overlay {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  width: 100%;
  height: auto;
  z-index: 2;
}
.coloring-container canvas {
  position: relative;
  width: 100%;
  height: auto;
  z-index: 1;
  border: 1px solid #aaa;
  touch-action: none;
}
.palette {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 10px;
  gap: 5px;
}
.palette button {
  width: 25px;
  height: 25px;
  border: 1px solid #555;
  border-radius: 4px;
  cursor: pointer;
}
.controls {
  margin-top: 10px;
  text-align: center;
}
</style>

<div class="coloring-wrapper">
  <div class="coloring-container">
    <canvas id="colorCanvas"></canvas>
    <img class="overlay" id="coloringImage" src="https://sandmoshi.github.io/eColorBook/pages/fox-trans.png" alt="Контур">
  </div>

  <div class="palette" id="palette"></div>

  <div class="controls">
    <label>🎨 Свой цвет: <input type="color" id="customColor" value="#ff0000"></label>
    <label>🖌️ Размер кисти: <input type="range" id="brushSize" min="5" max="100" value="25"></label>
    <button id="eraserBtn">Ластик</button>
    <button id="clearCanvas">Очистить всё</button>
  </div>
</div>

<script>
(function() {
  const canvas = document.getElementById('colorCanvas');
  const ctx = canvas.getContext('2d');
  const img = document.getElementById('coloringImage');
  const palette = document.getElementById('palette');
  const brushSize = document.getElementById('brushSize');
  const customColor = document.getElementById('customColor');
  const eraserBtn = document.getElementById('eraserBtn');
  const clearBtn = document.getElementById('clearCanvas');

  let painting = false;
  let erasing = false;
  let currentColor = '#ff0000';

  const colors = [
    '#000000', '#7f7f7f', '#ffffff', '#ff0000', '#ff7f00',
    '#ffff00', '#00ff00', '#00ffff', '#0000ff', '#8b00ff',
    '#ff1493', '#ff69b4', '#a0522d', '#008000', '#006400',
    '#4682b4', '#708090', '#c0c0c0', '#ff4500', '#ffd700'
  ];

  // палитра
  colors.forEach(c => {
    const btn = document.createElement('button');
    btn.style.backgroundColor = c;
    btn.addEventListener('click', () => {
      currentColor = c;
      erasing = false;
    });
    palette.appendChild(btn);
  });

  // свой цвет
  customColor.addEventListener('input', e => {
    currentColor = e.target.value;
    erasing = false;
  });

  // ластик
  eraserBtn.addEventListener('click', () => {
    erasing = !erasing;
    eraserBtn.textContent = erasing ? '🧽 Рисовать' : 'Ластик';
  });

  // очистка
  clearBtn.addEventListener('click', () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  });

  function resizeCanvas() {
    const rect = img.getBoundingClientRect();
    canvas.width = rect.width;
    canvas.height = rect.height;
  }

  window.addEventListener('resize', resizeCanvas);
  img.onload = resizeCanvas;

  function getCoords(e) {
    const rect = canvas.getBoundingClientRect();
    return {
      x: (e.clientX || e.touches?.[0]?.clientX) - rect.left,
      y: (e.clientY || e.touches?.[0]?.clientY) - rect.top
    };
  }

  function startDraw(e) {
    painting = true;
    draw(e);
  }

  function endDraw() {
    painting = false;
    ctx.beginPath();
  }

  function draw(e) {
    if (!painting) return;
    const { x, y } = getCoords(e);

    ctx.lineWidth = brushSize.value;
    ctx.lineCap = 'round';
    ctx.strokeStyle = erasing ? '#ffffff' : currentColor;
    ctx.lineTo(x, y);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(x, y);
  }

  canvas.addEventListener('mousedown', startDraw);
  canvas.addEventListener('mouseup', endDraw);
  canvas.addEventListener('mousemove', draw);

  canvas.addEventListener('touchstart', startDraw);
  canvas.addEventListener('touchend', endDraw);
  canvas.addEventListener('touchmove', draw);
})();
</script>
[/html]

0

14

[html]
<style>
.coloring-wrapper {
  position: relative;
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
  text-align: center;
}
.coloring-container {
  position: relative;
  display: inline-block;
  width: 100%;
}
.coloring-container img.overlay {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  width: 100%;
  height: auto;
  z-index: 2;
}
.coloring-container canvas {
  position: relative;
  width: 100%;
  height: auto;
  z-index: 1;
  border: 1px solid #aaa;
  touch-action: none;
}
.palette {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 10px;
  gap: 5px;
}
.palette button {
  width: 25px;
  height: 25px;
  border: 1px solid #555;
  border-radius: 4px;
  cursor: pointer;
}
.controls {
  margin-top: 10px;
  text-align: center;
}
button {
  cursor: pointer;
}
</style>

<div class="coloring-wrapper">
  <div class="coloring-container">
    <canvas id="colorCanvas"></canvas>
    <img class="overlay" id="coloringImage" src="https://sandmoshi.github.io/eColorBook/pages/fox-trans.png" alt="Контур">
  </div>

  <div class="palette" id="palette"></div>

  <div class="controls">
    <label>🎨 Свой цвет: <input type="color" id="customColor" value="#ff0000"></label>
    <label>🖌️ Размер кисти: <input type="range" id="brushSize" min="5" max="100" value="25"></label><br>
    <button id="eraserBtn">Ластик</button>
    <button id="clearCanvas">Очистить всё</button>
    <button id="saveImage">💾 Сохранить</button>
    <button id="copyCode">📋 Взять код</button>
  </div>
</div>

<script>
(function() {
  const canvas = document.getElementById('colorCanvas');
  const ctx = canvas.getContext('2d');
  const img = document.getElementById('coloringImage');
  const palette = document.getElementById('palette');
  const brushSize = document.getElementById('brushSize');
  const customColor = document.getElementById('customColor');
  const eraserBtn = document.getElementById('eraserBtn');
  const clearBtn = document.getElementById('clearCanvas');
  const saveBtn = document.getElementById('saveImage');
  const copyBtn = document.getElementById('copyCode');

  let painting = false;
  let erasing = false;
  let currentColor = '#ff0000';
  const storageKey = 'coloring_zombie_progress';

  const colors = [
    '#000000', '#7f7f7f', '#ffffff', '#ff0000', '#ff7f00',
    '#ffff00', '#00ff00', '#00ffff', '#0000ff', '#8b00ff',
    '#ff1493', '#ff69b4', '#a0522d', '#008000', '#006400',
    '#4682b4', '#708090', '#c0c0c0', '#ff4500', '#ffd700'
  ];

  // палитра
  colors.forEach(c => {
    const btn = document.createElement('button');
    btn.style.backgroundColor = c;
    btn.addEventListener('click', () => {
      currentColor = c;
      erasing = false;
      eraserBtn.textContent = 'Ластик';
    });
    palette.appendChild(btn);
  });

  customColor.addEventListener('input', e => {
    currentColor = e.target.value;
    erasing = false;
    eraserBtn.textContent = 'Ластик';
  });

  // ластик
  eraserBtn.addEventListener('click', () => {
    erasing = !erasing;
    eraserBtn.textContent = erasing ? '🧽 Рисовать' : 'Ластик';
  });

  // очистка
  clearBtn.addEventListener('click', () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    localStorage.removeItem(storageKey);
  });

  // сохранение в localStorage
  function saveProgress() {
    const dataURL = canvas.toDataURL();
    localStorage.setItem(storageKey, dataURL);
  }

  saveBtn.addEventListener('click', saveProgress);

  // восстановление при загрузке
  function restoreProgress() {
    const saved = localStorage.getItem(storageKey);
    if (saved) {
      const imgRestore = new Image();
      imgRestore.onload = () => ctx.drawImage(imgRestore, 0, 0, canvas.width, canvas.height);
      imgRestore.src = saved;
    }
  }

  // копирование кода картинки
  copyBtn.addEventListener('click', () => {
    const mergedCanvas = document.createElement('canvas');
    mergedCanvas.width = canvas.width;
    mergedCanvas.height = canvas.height;
    const mctx = mergedCanvas.getContext('2d');

    mctx.drawImage(canvas, 0, 0);
    mctx.drawImage(img, 0, 0, canvas.width, canvas.height);

    const code = `<img src="${mergedCanvas.toDataURL()}" alt="Моя раскраска">`;
    navigator.clipboard.writeText(code).then(() => {
      alert('✅ Код картинки скопирован! Вставьте его в сообщение форума.');
    });
  });

  function resizeCanvas() {
    const rect = img.getBoundingClientRect();
    const saved = canvas.toDataURL();
    canvas.width = rect.width;
    canvas.height = rect.height;

    const tempImg = new Image();
    tempImg.onload = () => ctx.drawImage(tempImg, 0, 0, canvas.width, canvas.height);
    tempImg.src = saved;

    restoreProgress();
  }

  window.addEventListener('resize', resizeCanvas);
  img.onload = () => {
    resizeCanvas();
    restoreProgress();
  };

  function getCoords(e) {
    const rect = canvas.getBoundingClientRect();
    return {
      x: (e.clientX || e.touches?.[0]?.clientX) - rect.left,
      y: (e.clientY || e.touches?.[0]?.clientY) - rect.top
    };
  }

  function startDraw(e) {
    painting = true;
    draw(e);
  }

  function endDraw() {
    painting = false;
    ctx.beginPath();
    saveProgress();
  }

  function draw(e) {
    if (!painting) return;
    const { x, y } = getCoords(e);

    ctx.lineWidth = brushSize.value;
    ctx.lineCap = 'round';
    ctx.strokeStyle = erasing ? '#ffffff' : currentColor;
    ctx.lineTo(x, y);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(x, y);
  }

  canvas.addEventListener('mousedown', startDraw);
  canvas.addEventListener('mouseup', endDraw);
  canvas.addEventListener('mousemove', draw);

  canvas.addEventListener('touchstart', startDraw);
  canvas.addEventListener('touchend', endDraw);
  canvas.addEventListener('touchmove', draw);
})();
</script>
[/html]

0

15

[html]
<style>
.coloring-wrapper {
  position: relative;
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
  text-align: center;
}
.coloring-container {
  position: relative;
  display: inline-block;
  width: 100%;
}
.coloring-container img.overlay {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  width: 100%;
  height: auto;
  z-index: 2;
}
.coloring-container canvas {
  position: relative;
  width: 100%;
  height: auto;
  z-index: 1;
  border: 1px solid #aaa;
  touch-action: none;
}
.palette {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 10px;
  gap: 5px;
}
.palette button {
  width: 25px;
  height: 25px;
  border: 1px solid #555;
  border-radius: 4px;
  cursor: pointer;
}
.controls {
  margin-top: 10px;
  text-align: center;
}
button {
  cursor: pointer;
}
</style>

<div class="coloring-wrapper">
  <div class="coloring-container">
    <canvas id="colorCanvas"></canvas>
    <img class="overlay" id="coloringImage" src="https://sandmoshi.github.io/eColorBook/pages/fox-trans.png" alt="Контур">
  </div>

  <div class="palette" id="palette"></div>

  <div class="controls">
    <label>🎨 Свой цвет: <input type="color" id="customColor" value="#ff0000"></label>
    <label>🖌️ Размер кисти: <input type="range" id="brushSize" min="5" max="150" value="40"></label><br>
    <button id="eraserBtn">Ластик</button>
    <button id="clearCanvas">Очистить всё</button>
    <button id="saveImage">💾 Сохранить</button>
    <button id="copyCode">📋 Взять код</button>
  </div>
</div>

<script>
(function() {
  const canvas = document.getElementById('colorCanvas');
  const ctx = canvas.getContext('2d');
  const img = document.getElementById('coloringImage');
  const palette = document.getElementById('palette');
  const brushSize = document.getElementById('brushSize');
  const customColor = document.getElementById('customColor');
  const eraserBtn = document.getElementById('eraserBtn');
  const clearBtn = document.getElementById('clearCanvas');
  const saveBtn = document.getElementById('saveImage');
  const copyBtn = document.getElementById('copyCode');

  let painting = false;
  let erasing = false;
  let currentColor = '#ff0000';
  const storageKey = 'coloring_zombie_blend';

  const colors = [
    '#000000', '#7f7f7f', '#ffffff', '#ff0000', '#ff7f00',
    '#ffff00', '#00ff00', '#00ffff', '#0000ff', '#8b00ff',
    '#ff1493', '#ff69b4', '#a0522d', '#008000', '#006400',
    '#4682b4', '#708090', '#c0c0c0', '#ff4500', '#ffd700'
  ];

  // Палитра
  colors.forEach(c => {
    const btn = document.createElement('button');
    btn.style.backgroundColor = c;
    btn.addEventListener('click', () => {
      currentColor = c;
      erasing = false;
      eraserBtn.textContent = 'Ластик';
    });
    palette.appendChild(btn);
  });

  customColor.addEventListener('input', e => {
    currentColor = e.target.value;
    erasing = false;
    eraserBtn.textContent = 'Ластик';
  });

  // Ластик
  eraserBtn.addEventListener('click', () => {
    erasing = !erasing;
    eraserBtn.textContent = erasing ? '🧽 Рисовать' : 'Ластик';
  });

  // Очистка
  clearBtn.addEventListener('click', () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    localStorage.removeItem(storageKey);
  });

  // Сохранение
  function saveProgress() {
    const dataURL = canvas.toDataURL();
    localStorage.setItem(storageKey, dataURL);
  }

  saveBtn.addEventListener('click', saveProgress);

  // Восстановление
  function restoreProgress() {
    const saved = localStorage.getItem(storageKey);
    if (saved) {
      const imgRestore = new Image();
      imgRestore.onload = () => ctx.drawImage(imgRestore, 0, 0, canvas.width, canvas.height);
      imgRestore.src = saved;
    }
  }

  // Взять код
  copyBtn.addEventListener('click', () => {
    const mergedCanvas = document.createElement('canvas');
    mergedCanvas.width = canvas.width;
    mergedCanvas.height = canvas.height;
    const mctx = mergedCanvas.getContext('2d');

    mctx.drawImage(canvas, 0, 0);
    mctx.drawImage(img, 0, 0, canvas.width, canvas.height);

    const code = `<img src="${mergedCanvas.toDataURL()}" alt="Моя раскраска">`;
    navigator.clipboard.writeText(code).then(() => {
      alert('✅ Код картинки скопирован! Вставьте его в сообщение форума.');
    });
  });

  function resizeCanvas() {
    const rect = img.getBoundingClientRect();
    const saved = canvas.toDataURL();
    canvas.width = rect.width;
    canvas.height = rect.height;

    const tempImg = new Image();
    tempImg.onload = () => ctx.drawImage(tempImg, 0, 0, canvas.width, canvas.height);
    tempImg.src = saved;

    restoreProgress();
  }

  window.addEventListener('resize', resizeCanvas);
  img.onload = () => {
    resizeCanvas();
    restoreProgress();
  };

  function getCoords(e) {
    const rect = canvas.getBoundingClientRect();
    return {
      x: (e.clientX || e.touches?.[0]?.clientX) - rect.left,
      y: (e.clientY || e.touches?.[0]?.clientY) - rect.top
    };
  }

  // Мягкое рисование (плавная кисть с наложением)
  function softStroke(x, y) {
    const grd = ctx.createRadialGradient(x, y, 0, x, y, brushSize.value / 2);
    const color = erasing ? '#ffffff' : currentColor;
    grd.addColorStop(0, color + 'cc'); // полупрозрачный центр
    grd.addColorStop(1, color + '00'); // прозрачные края
    ctx.fillStyle = grd;
    ctx.globalAlpha = 0.2;
    ctx.globalCompositeOperation = erasing ? 'destination-out' : 'source-over';
    ctx.beginPath();
    ctx.arc(x, y, brushSize.value / 2, 0, Math.PI * 2);
    ctx.fill();
  }

  function startDraw(e) {
    painting = true;
    draw(e);
  }

  function endDraw() {
    painting = false;
    saveProgress();
  }

  function draw(e) {
    if (!painting) return;
    const { x, y } = getCoords(e);
    softStroke(x, y);
  }

  canvas.addEventListener('mousedown', startDraw);
  canvas.addEventListener('mouseup', endDraw);
  canvas.addEventListener('mousemove', draw);
  canvas.addEventListener('touchstart', startDraw);
  canvas.addEventListener('touchend', endDraw);
  canvas.addEventListener('touchmove', draw);
})();
</script>
[/html]

0

16

[html]
<style>
.coloring-wrapper {
  position: relative;
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
  text-align: center;
}
.coloring-container {
  position: relative;
  display: inline-block;
  width: 100%;
}
.coloring-container img.overlay {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  width: 100%;
  height: auto;
  z-index: 2;
}
.coloring-container canvas {
  position: relative;
  width: 100%;
  height: auto;
  z-index: 1;
  border: 1px solid #aaa;
  touch-action: none;
}
.palette {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 10px;
  gap: 5px;
}
.palette button {
  width: 25px;
  height: 25px;
  border: 1px solid #555;
  border-radius: 4px;
  cursor: pointer;
}
.controls {
  margin-top: 10px;
  text-align: center;
}
button {
  cursor: pointer;
}
</style>

<div class="coloring-wrapper">
  <div class="coloring-container">
    <canvas id="colorCanvas"></canvas>
    <img class="overlay" id="coloringImage" src="https://sandmoshi.github.io/eColorBook/pages/fox-trans.png" alt="Контур">
  </div>

  <div class="palette" id="palette"></div>

  <div class="controls">
    <label>🎨 Свой цвет: <input type="color" id="customColor" value="#ff0000"></label><br>
    <label>🖌️ Размер кисти: <input type="range" id="brushSize" min="5" max="150" value="40"></label><br>
    <label>🌫️ Мягкость кисти: <input type="range" id="softness" min="0" max="100" value="60"></label><br>
    <button id="eraserBtn">Ластик</button>
    <button id="clearCanvas">Очистить всё</button>
    <button id="saveImage">💾 Сохранить</button>
    <button id="copyCode">📋 Взять код</button>
  </div>
</div>

<script>
(function() {
  const canvas = document.getElementById('colorCanvas');
  const ctx = canvas.getContext('2d');
  const img = document.getElementById('coloringImage');
  const palette = document.getElementById('palette');
  const brushSize = document.getElementById('brushSize');
  const customColor = document.getElementById('customColor');
  const softness = document.getElementById('softness');
  const eraserBtn = document.getElementById('eraserBtn');
  const clearBtn = document.getElementById('clearCanvas');
  const saveBtn = document.getElementById('saveImage');
  const copyBtn = document.getElementById('copyCode');

  let painting = false;
  let erasing = false;
  let currentColor = '#ff0000';
  const storageKey = 'coloring_softbrush';

  const colors = [
    '#000000', '#7f7f7f', '#ffffff', '#ff0000', '#ff7f00',
    '#ffff00', '#00ff00', '#00ffff', '#0000ff', '#8b00ff',
    '#ff1493', '#ff69b4', '#a0522d', '#008000', '#006400',
    '#4682b4', '#708090', '#c0c0c0', '#ff4500', '#ffd700'
  ];

  // Палитра
  colors.forEach(c => {
    const btn = document.createElement('button');
    btn.style.backgroundColor = c;
    btn.addEventListener('click', () => {
      currentColor = c;
      erasing = false;
      eraserBtn.textContent = 'Ластик';
    });
    palette.appendChild(btn);
  });

  customColor.addEventListener('input', e => {
    currentColor = e.target.value;
    erasing = false;
    eraserBtn.textContent = 'Ластик';
  });

  // Ластик
  eraserBtn.addEventListener('click', () => {
    erasing = !erasing;
    eraserBtn.textContent = erasing ? '🧽 Рисовать' : 'Ластик';
  });

  // Очистка
  clearBtn.addEventListener('click', () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    localStorage.removeItem(storageKey);
  });

  // Сохранение
  function saveProgress() {
    const dataURL = canvas.toDataURL();
    localStorage.setItem(storageKey, dataURL);
  }

  saveBtn.addEventListener('click', saveProgress);

  // Восстановление
  function restoreProgress() {
    const saved = localStorage.getItem(storageKey);
    if (saved) {
      const imgRestore = new Image();
      imgRestore.onload = () => ctx.drawImage(imgRestore, 0, 0, canvas.width, canvas.height);
      imgRestore.src = saved;
    }
  }

  // Взять код
  copyBtn.addEventListener('click', () => {
    const mergedCanvas = document.createElement('canvas');
    mergedCanvas.width = canvas.width;
    mergedCanvas.height = canvas.height;
    const mctx = mergedCanvas.getContext('2d');

    mctx.drawImage(canvas, 0, 0);
    mctx.drawImage(img, 0, 0, canvas.width, canvas.height);

    const code = `<img src="${mergedCanvas.toDataURL()}" alt="Моя раскраска">`;
    navigator.clipboard.writeText(code).then(() => {
      alert('✅ Код картинки скопирован! Вставьте его в сообщение форума.');
    });
  });

  function resizeCanvas() {
    const rect = img.getBoundingClientRect();
    const saved = canvas.toDataURL();
    canvas.width = rect.width;
    canvas.height = rect.height;

    const tempImg = new Image();
    tempImg.onload = () => ctx.drawImage(tempImg, 0, 0, canvas.width, canvas.height);
    tempImg.src = saved;

    restoreProgress();
  }

  window.addEventListener('resize', resizeCanvas);
  img.onload = () => {
    resizeCanvas();
    restoreProgress();
  };

  function getCoords(e) {
    const rect = canvas.getBoundingClientRect();
    return {
      x: (e.clientX || e.touches?.[0]?.clientX) - rect.left,
      y: (e.clientY || e.touches?.[0]?.clientY) - rect.top
    };
  }

  // Мягкое рисование с регулировкой мягкости
  function softStroke(x, y) {
    const radius = brushSize.value / 2;
    const softnessValue = softness.value / 100;
    const color = erasing ? '#ffffff' : currentColor;

    const grd = ctx.createRadialGradient(x, y, 0, x, y, radius);
    grd.addColorStop(0, color + 'ff');
    grd.addColorStop(softnessValue, color + 'aa');
    grd.addColorStop(1, color + '00');

    ctx.fillStyle = grd;
    ctx.globalAlpha = 0.2 + (1 - softnessValue) * 0.5;
    ctx.globalCompositeOperation = erasing ? 'destination-out' : 'source-over';
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, Math.PI * 2);
    ctx.fill();
  }

  function startDraw(e) {
    painting = true;
    draw(e);
  }

  function endDraw() {
    painting = false;
    saveProgress();
  }

  function draw(e) {
    if (!painting) return;
    const { x, y } = getCoords(e);
    softStroke(x, y);
  }

  canvas.addEventListener('mousedown', startDraw);
  canvas.addEventListener('mouseup', endDraw);
  canvas.addEventListener('mousemove', draw);
  canvas.addEventListener('touchstart', startDraw);
  canvas.addEventListener('touchend', endDraw);
  canvas.addEventListener('touchmove', draw);
})();
</script>
[/html]

0

17

[html]
<style>
.coloring-wrapper {
  position: relative;
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
  text-align: center;
}
.coloring-container {
  position: relative;
  display: inline-block;
  width: 100%;
}
.coloring-container img.overlay {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  width: 100%;
  height: auto;
  z-index: 2;
}
.coloring-container canvas {
  position: relative;
  width: 100%;
  height: auto;
  z-index: 1;
  border: 1px solid #aaa;
  touch-action: none;
}
.palette {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 10px;
  gap: 5px;
}
.palette button {
  width: 25px;
  height: 25px;
  border: 1px solid #555;
  border-radius: 4px;
  cursor: pointer;
}
.controls {
  margin-top: 10px;
  text-align: center;
}
button {
  cursor: pointer;
}
</style>

<div class="coloring-wrapper">
  <div class="coloring-container">
    <canvas id="colorCanvas"></canvas>
    <img class="overlay" id="coloringImage" src="https://sandmoshi.github.io/eColorBook/pages/fox-trans.png" alt="Контур">
  </div>

  <div class="palette" id="palette"></div>

  <div class="controls">
    <label>🎨 Свой цвет: <input type="color" id="customColor" value="#ff0000"></label><br>
    <label>🖌️ Размер кисти: <input type="range" id="brushSize" min="5" max="150" value="40"></label><br>
    <label>🌫️ Мягкость кисти: <input type="range" id="softness" min="0" max="100" value="0"></label><br>
    <button id="brushMode">✏️ Четкая кисть</button>
    <button id="eraserBtn">Ластик</button>
    <button id="clearCanvas">Очистить всё</button>
    <button id="saveImage">💾 Сохранить</button>
    <button id="copyCode">📋 Взять код</button>
  </div>
</div>

<script>
(function() {
  const canvas = document.getElementById('colorCanvas');
  const ctx = canvas.getContext('2d');
  const img = document.getElementById('coloringImage');
  const palette = document.getElementById('palette');
  const brushSize = document.getElementById('brushSize');
  const customColor = document.getElementById('customColor');
  const softness = document.getElementById('softness');
  const eraserBtn = document.getElementById('eraserBtn');
  const clearBtn = document.getElementById('clearCanvas');
  const saveBtn = document.getElementById('saveImage');
  const copyBtn = document.getElementById('copyCode');
  const brushModeBtn = document.getElementById('brushMode');

  let painting = false;
  let erasing = false;
  let airbrush = false;
  let currentColor = '#ff0000';
  const storageKey = 'coloring_softbrush_v2';

  const colors = [
    '#000000', '#7f7f7f', '#ffffff', '#ff0000', '#ff7f00',
    '#ffff00', '#00ff00', '#00ffff', '#0000ff', '#8b00ff',
    '#ff1493', '#ff69b4', '#a0522d', '#008000', '#006400',
    '#4682b4', '#708090', '#c0c0c0', '#ff4500', '#ffd700'
  ];

  // Палитра
  colors.forEach(c => {
    const btn = document.createElement('button');
    btn.style.backgroundColor = c;
    btn.addEventListener('click', () => {
      currentColor = c;
      erasing = false;
      eraserBtn.textContent = 'Ластик';
    });
    palette.appendChild(btn);
  });

  customColor.addEventListener('input', e => {
    currentColor = e.target.value;
    erasing = false;
    eraserBtn.textContent = 'Ластик';
  });

  // Переключение типа кисти
  brushModeBtn.addEventListener('click', () => {
    airbrush = !airbrush;
    brushModeBtn.textContent = airbrush ? '💨 Аэрограф' : '✏️ Четкая кисть';
  });

  // Ластик
  eraserBtn.addEventListener('click', () => {
    erasing = !erasing;
    eraserBtn.textContent = erasing ? '🧽 Рисовать' : 'Ластик';
  });

  // Очистка
  clearBtn.addEventListener('click', () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    localStorage.removeItem(storageKey);
  });

  // Сохранение прогресса
  function saveProgress() {
    const dataURL = canvas.toDataURL();
    localStorage.setItem(storageKey, dataURL);
  }

  saveBtn.addEventListener('click', saveProgress);

  // Восстановление
  function restoreProgress() {
    const saved = localStorage.getItem(storageKey);
    if (saved) {
      const imgRestore = new Image();
      imgRestore.onload = () => ctx.drawImage(imgRestore, 0, 0, canvas.width, canvas.height);
      imgRestore.src = saved;
    }
  }

  // Копирование кода
  copyBtn.addEventListener('click', () => {
    const mergedCanvas = document.createElement('canvas');
    mergedCanvas.width = canvas.width;
    mergedCanvas.height = canvas.height;
    const mctx = mergedCanvas.getContext('2d');
    mctx.drawImage(canvas, 0, 0);
    mctx.drawImage(img, 0, 0, canvas.width, canvas.height);
    const code = `<img src="${mergedCanvas.toDataURL()}" alt="Моя раскраска">`;
    navigator.clipboard.writeText(code).then(() => alert('✅ Код картинки скопирован!'));
  });

  // Подгонка
  function resizeCanvas() {
    const rect = img.getBoundingClientRect();
    const saved = canvas.toDataURL();
    canvas.width = rect.width;
    canvas.height = rect.height;
    const tempImg = new Image();
    tempImg.onload = () => ctx.drawImage(tempImg, 0, 0, canvas.width, canvas.height);
    tempImg.src = saved;
    restoreProgress();
  }

  window.addEventListener('resize', resizeCanvas);
  img.onload = () => {
    resizeCanvas();
    restoreProgress();
  };

  function getCoords(e) {
    const rect = canvas.getBoundingClientRect();
    return {
      x: (e.clientX || e.touches?.[0]?.clientX) - rect.left,
      y: (e.clientY || e.touches?.[0]?.clientY) - rect.top
    };
  }

  // Рисование
  function drawBrush(x, y) {
    const size = +brushSize.value;
    const soft = +softness.value / 100;
    const color = erasing ? '#ffffff' : currentColor;

    if (airbrush || soft > 0) {
      // Плавная кисть / аэрограф
      const grd = ctx.createRadialGradient(x, y, 0, x, y, size / 2);
      grd.addColorStop(0, color);
      grd.addColorStop(soft, color + 'aa');
      grd.addColorStop(1, color + '00');

      ctx.fillStyle = grd;
      ctx.globalAlpha = erasing ? 1 : 0.2 + (1 - soft) * 0.6;
      ctx.globalCompositeOperation = erasing ? 'destination-out' : 'source-over';
      ctx.beginPath();
      ctx.arc(x, y, size / 2, 0, Math.PI * 2);
      ctx.fill();
    } else {
      // Четкая кисть
      ctx.globalAlpha = 1;
      ctx.globalCompositeOperation = erasing ? 'destination-out' : 'source-over';
      ctx.beginPath();
      ctx.arc(x, y, size / 2, 0, Math.PI * 2);
      ctx.fillStyle = color;
      ctx.fill();
    }
  }

  let painting = false;
  function startDraw(e) {
    painting = true;
    draw(e);
  }

  function endDraw() {
    painting = false;
    saveProgress();
  }

  function draw(e) {
    if (!painting) return;
    const { x, y } = getCoords(e);
    drawBrush(x, y);
  }

  canvas.addEventListener('mousedown', startDraw);
  canvas.addEventListener('mouseup', endDraw);
  canvas.addEventListener('mousemove', draw);
  canvas.addEventListener('touchstart', startDraw);
  canvas.addEventListener('touchend', endDraw);
  canvas.addEventListener('touchmove', draw);
})();
</script>
[/html]

0

18

[html]
<style>
  #paintContainer {
    position: relative;
    display: block;
    width: 100%;
    max-width: 100%;
  }
  #overlayImage {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: auto;
    pointer-events: none;
    user-select: none;
    z-index: 2;
  }
  #paintCanvas {
    width: 100%;
    height: auto;
    border: 1px solid #666;
    display: block;
    z-index: 1;
  }
  .toolbar {
    margin-top: 10px;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
  }
  .palette {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
  }
  .color {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 1px solid #444;
    cursor: pointer;
  }
  button {
    padding: 5px 10px;
    border-radius: 6px;
    border: 1px solid #555;
    background: #eee;
    cursor: pointer;
  }
  button:hover { background: #ddd; }
  #codePanel {
    display: none;
    margin-top: 10px;
  }
  #codePanel textarea {
    width: 100%;
    height: 100px;
  }
</style>

<div id="paintContainer">
  <canvas id="paintCanvas"></canvas>
  <!-- Администратор может заменить ссылку на картинку -->
  <img id="overlayImage" src="https://sandmoshi.github.io/eColorBook/pages/fox-trans.png">
</div>

<div class="toolbar">
  <div class="palette" id="palette"></div>
  <input type="color" id="customColor" value="#000000" title="Выбрать свой цвет">
  <label>Размер кисти:
    <input type="range" id="brushSize" min="1" max="100" value="20">
  </label>
  <button id="hardBrush">✏️ Жесткая кисть</button>
  <button id="softBrush">💨 Мягкая кисть</button>
  <button id="eraser">🩹 Ластик</button>
  <button id="saveProgress">💾 Сохранить</button>
  <button id="clearCanvas">🧹 Очистить всё</button>
  <button id="showCode">📋 Взять код</button>
</div>

<div id="codePanel">
  <p>Скопируй этот код и вставь в сообщение:</p>
  <textarea readonly id="codeOutput"></textarea>
  <button id="copyCode">📄 Копировать</button>
</div>

<script>
(function() {
  const canvas = document.getElementById("paintCanvas");
  const ctx = canvas.getContext("2d");
  const img = document.getElementById("overlayImage");

  let painting = false;
  let brushType = "hard";
  let brushColor = "#000";
  let brushSize = 20;

  const colors = [
    "#000000","#ffffff","#ff0000","#00ff00","#0000ff","#ffff00","#ff00ff","#00ffff",
    "#808080","#804000","#ff8000","#8000ff","#0080ff","#80ff00","#ff0080","#008080",
    "#404040","#c0c0c0","#a52a2a","#add8e6"
  ];

  const palette = document.getElementById("palette");
  colors.forEach(c => {
    const el = document.createElement("div");
    el.className = "color";
    el.style.background = c;
    el.onclick = () => brushColor = c;
    palette.appendChild(el);
  });

  document.getElementById("customColor").oninput = e => brushColor = e.target.value;
  document.getElementById("brushSize").oninput = e => brushSize = e.target.value;
  document.getElementById("hardBrush").onclick = () => brushType = "hard";
  document.getElementById("softBrush").onclick = () => brushType = "soft";
  document.getElementById("eraser").onclick = () => brushType = "eraser";

  document.getElementById("clearCanvas").onclick = () => {
    ctx.clearRect(0,0,canvas.width,canvas.height);
    localStorage.removeItem("coloringProgress");
  };

  document.getElementById("saveProgress").onclick = () => {
    localStorage.setItem("coloringProgress", canvas.toDataURL());
    alert("✅ Прогресс сохранён в браузере!");
  };

  document.getElementById("showCode").onclick = () => {
    const panel = document.getElementById("codePanel");
    panel.style.display = "block";
    document.getElementById("codeOutput").value = canvas.toDataURL();
  };

  document.getElementById("copyCode").onclick = () => {
    const area = document.getElementById("codeOutput");
    area.select();
    document.execCommand("copy");
    alert("✅ Код изображения скопирован!");
  };

  function resizeCanvas() {
    const ratio = img.naturalWidth / img.naturalHeight || 1.5;
    canvas.width = img.clientWidth || window.innerWidth;
    canvas.height = (img.clientWidth || window.innerWidth) / ratio;
    restoreProgress();
  }

  img.onload = resizeCanvas;
  window.onresize = resizeCanvas;

  function startPosition(e) {
    painting = true;
    draw(e);
  }

  function endPosition() {
    painting = false;
    ctx.beginPath();
    saveProgress();
  }

  function draw(e) {
    if (!painting) return;
    const rect = canvas.getBoundingClientRect();
    const x = (e.clientX || e.touches?.[0]?.clientX) - rect.left;
    const y = (e.clientY || e.touches?.[0]?.clientY) - rect.top;

    if (brushType === "eraser") {
      ctx.clearRect(x - brushSize/2, y - brushSize/2, brushSize, brushSize);
      return;
    }

    ctx.lineWidth = brushSize;
    ctx.lineCap = "round";
    ctx.lineJoin = "round";

    if (brushType === "hard") {
      ctx.globalAlpha = 1;
      ctx.strokeStyle = brushColor;
    } else if (brushType === "soft") {
      ctx.globalAlpha = 0.05;
      ctx.strokeStyle = brushColor;
    }

    ctx.lineTo(x, y);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(x, y);
  }

  function saveProgress() {
    localStorage.setItem("coloringProgress", canvas.toDataURL());
  }

  function restoreProgress() {
    const saved = localStorage.getItem("coloringProgress");
    if (saved) {
      const imgData = new Image();
      imgData.onload = () => ctx.drawImage(imgData, 0, 0, canvas.width, canvas.height);
      imgData.src = saved;
    }
  }

  canvas.addEventListener("mousedown", startPosition);
  canvas.addEventListener("mouseup", endPosition);
  canvas.addEventListener("mousemove", draw);
  canvas.addEventListener("touchstart", startPosition);
  canvas.addEventListener("touchend", endPosition);
  canvas.addEventListener("touchmove", draw);
})();
</script>
[/html]

0

19

[html]
<style>
.coloring-wrapper {
  position: relative;
  width: 100%;
  max-width: 900px;
  margin: 0 auto;
  text-align: center;
}
.coloring-container {
  position: relative;
  display: inline-block;
  width: 100%;
}
.coloring-container img.overlay {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  width: 100%;
  height: auto;
  z-index: 2;
}
.coloring-container canvas {
  position: relative;
  width: 100%;
  height: auto;
  z-index: 1;
  border: 1px solid #aaa;
  touch-action: none;
}
.palette {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 10px;
  gap: 5px;
}
.palette button {
  width: 25px;
  height: 25px;
  border: 1px solid #555;
  border-radius: 4px;
  cursor: pointer;
}
.controls {
  margin-top: 10px;
  text-align: center;
}
button {
  cursor: pointer;
}
</style>

<div class="coloring-wrapper">
  <div class="coloring-container">
    <canvas id="colorCanvas"></canvas>
    <img class="overlay" id="coloringImage" src="https://upforme.ru/uploads/001c/84/76/2/729135.png" alt="Контур">
  </div>

  <div class="palette" id="palette"></div>

  <div class="controls">
    <label>🎨 Свой цвет: <input type="color" id="customColor" value="#ff0000"></label>
    <label>🖌️ Размер кисти: <input type="range" id="brushSize" min="5" max="150" value="40"></label><br>
    <button id="eraserBtn">Ластик</button>
    <button id="clearCanvas">Очистить всё</button>
    <button id="saveImage">💾 Сохранить</button>
    <button id="copyCode">📋 Взять код</button>
  </div>
</div>

<script>
(function() {
  const canvas = document.getElementById('colorCanvas');
  const ctx = canvas.getContext('2d');
  const img = document.getElementById('coloringImage');
  const palette = document.getElementById('palette');
  const brushSize = document.getElementById('brushSize');
  const customColor = document.getElementById('customColor');
  const eraserBtn = document.getElementById('eraserBtn');
  const clearBtn = document.getElementById('clearCanvas');
  const saveBtn = document.getElementById('saveImage');
  const copyBtn = document.getElementById('copyCode');

  let painting = false;
  let erasing = false;
  let currentColor = '#ff0000';
  const storageKey = 'coloring_zombie_blend';

  const colors = [
    '#000000', '#7f7f7f', '#ffffff', '#ff0000', '#ff7f00',
    '#ffff00', '#00ff00', '#00ffff', '#0000ff', '#8b00ff',
    '#ff1493', '#ff69b4', '#a0522d', '#008000', '#006400',
    '#4682b4', '#708090', '#c0c0c0', '#ff4500', '#ffd700'
  ];

  // Палитра
  colors.forEach(c => {
    const btn = document.createElement('button');
    btn.style.backgroundColor = c;
    btn.addEventListener('click', () => {
      currentColor = c;
      erasing = false;
      eraserBtn.textContent = 'Ластик';
    });
    palette.appendChild(btn);
  });

  customColor.addEventListener('input', e => {
    currentColor = e.target.value;
    erasing = false;
    eraserBtn.textContent = 'Ластик';
  });

  // Ластик
  eraserBtn.addEventListener('click', () => {
    erasing = !erasing;
    eraserBtn.textContent = erasing ? '🧽 Рисовать' : 'Ластик';
  });

  // Очистка
  clearBtn.addEventListener('click', () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    localStorage.removeItem(storageKey);
  });

  // Сохранение
  function saveProgress() {
    const dataURL = canvas.toDataURL();
    localStorage.setItem(storageKey, dataURL);
  }

  saveBtn.addEventListener('click', saveProgress);

  // Восстановление
  function restoreProgress() {
    const saved = localStorage.getItem(storageKey);
    if (saved) {
      const imgRestore = new Image();
      imgRestore.onload = () => ctx.drawImage(imgRestore, 0, 0, canvas.width, canvas.height);
      imgRestore.src = saved;
    }
  }

  // Взять код
  copyBtn.addEventListener('click', () => {
    const mergedCanvas = document.createElement('canvas');
    mergedCanvas.width = canvas.width;
    mergedCanvas.height = canvas.height;
    const mctx = mergedCanvas.getContext('2d');

    mctx.drawImage(canvas, 0, 0);
    mctx.drawImage(img, 0, 0, canvas.width, canvas.height);

    const code = `<img src="${mergedCanvas.toDataURL()}" alt="Моя раскраска">`;
    navigator.clipboard.writeText(code).then(() => {
      alert('✅ Код картинки скопирован! Вставьте его в сообщение форума.');
    });
  });

  function resizeCanvas() {
    const rect = img.getBoundingClientRect();
    const saved = canvas.toDataURL();
    canvas.width = rect.width;
    canvas.height = rect.height;

    const tempImg = new Image();
    tempImg.onload = () => ctx.drawImage(tempImg, 0, 0, canvas.width, canvas.height);
    tempImg.src = saved;

    restoreProgress();
  }

  window.addEventListener('resize', resizeCanvas);
  img.onload = () => {
    resizeCanvas();
    restoreProgress();
  };

  function getCoords(e) {
    const rect = canvas.getBoundingClientRect();
    return {
      x: (e.clientX || e.touches?.[0]?.clientX) - rect.left,
      y: (e.clientY || e.touches?.[0]?.clientY) - rect.top
    };
  }

  // Мягкое рисование (плавная кисть с наложением)
  function softStroke(x, y) {
    const grd = ctx.createRadialGradient(x, y, 0, x, y, brushSize.value / 2);
    const color = erasing ? '#ffffff' : currentColor;
    grd.addColorStop(0, color + 'cc'); // полупрозрачный центр
    grd.addColorStop(1, color + '00'); // прозрачные края
    ctx.fillStyle = grd;
    ctx.globalAlpha = 0.2;
    ctx.globalCompositeOperation = erasing ? 'destination-out' : 'source-over';
    ctx.beginPath();
    ctx.arc(x, y, brushSize.value / 2, 0, Math.PI * 2);
    ctx.fill();
  }

  function startDraw(e) {
    painting = true;
    draw(e);
  }

  function endDraw() {
    painting = false;
    saveProgress();
  }

  function draw(e) {
    if (!painting) return;
    const { x, y } = getCoords(e);
    softStroke(x, y);
  }

  canvas.addEventListener('mousedown', startDraw);
  canvas.addEventListener('mouseup', endDraw);
  canvas.addEventListener('mousemove', draw);
  canvas.addEventListener('touchstart', startDraw);
  canvas.addEventListener('touchend', endDraw);
  canvas.addEventListener('touchmove', draw);
})();
</script>
[/html]

0

20

[html]
<style>
  #paintContainer {
    position: relative;
    display: block;
    width: 100%;
    max-width: 100%;
  }
  #overlayImage {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: auto;
    pointer-events: none;
    user-select: none;
    z-index: 2;
  }
  #paintCanvas {
    width: 100%;
    height: auto;
    border: 1px solid #666;
    display: block;
    z-index: 1;
  }
  .toolbar {
    margin-top: 10px;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
  }
  .palette {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
  }
  .color {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 1px solid #444;
    cursor: pointer;
  }
  button {
    padding: 5px 10px;
    border-radius: 6px;
    border: 1px solid #555;
    background: #eee;
    cursor: pointer;
  }
  button:hover { background: #ddd; }
  #codePanel {
    display: none;
    margin-top: 10px;
  }
  #codePanel textarea {
    width: 100%;
    height: 100px;
  }
</style>

<div id="paintContainer">
  <canvas id="paintCanvas"></canvas>
  <!-- Админ может заменить ссылку на любую PNG/SVG -->
  <img id="overlayImage" src="https://upforme.ru/uploads/001c/84/76/2/729135.png">
</div>

<div class="toolbar">
  <div class="palette" id="palette"></div>
  <input type="color" id="customColor" value="#000000" title="Выбрать свой цвет">
  <label>Размер:
    <input type="range" id="brushSize" min="5" max="100" value="20">
  </label>
  <button id="hardBrush">✏️ Жесткая</button>
  <button id="softBrush">💨 Мягкая</button>
  <button id="eraser">🩹 Ластик</button>
  <button id="saveProgress">💾 Сохранить</button>
  <button id="clearCanvas">🧹 Очистить</button>
  <button id="showCode">📋 Взять код</button>
</div>

<div id="codePanel">
  <p>Скопируй этот код и вставь в сообщение:</p>
  <textarea readonly id="codeOutput"></textarea>
  <button id="copyCode">📄 Копировать</button>
</div>

<script>
(function() {
  const canvas = document.getElementById("paintCanvas");
  const ctx = canvas.getContext("2d");
  const img = document.getElementById("overlayImage");

  let painting = false;
  let brushType = "hard";
  let currentColor = "#000";
  let brushSize = document.getElementById("brushSize");
  let erasing = false;

  // === Палитра ===
  const colors = [
    "#000000","#ffffff","#ff0000","#00ff00","#0000ff","#ffff00","#ff00ff","#00ffff",
    "#808080","#804000","#ff8000","#8000ff","#0080ff","#80ff00","#ff0080","#008080",
    "#404040","#c0c0c0","#a52a2a","#add8e6"
  ];

  const palette = document.getElementById("palette");
  colors.forEach(c => {
    const el = document.createElement("div");
    el.className = "color";
    el.style.background = c;
    el.onclick = () => { currentColor = c; erasing = false; };
    palette.appendChild(el);
  });
  document.getElementById("customColor").oninput = e => { currentColor = e.target.value; erasing = false; };

  // === Настройки ===
  document.getElementById("hardBrush").onclick = () => { brushType = "hard"; erasing = false; };
  document.getElementById("softBrush").onclick = () => { brushType = "soft"; erasing = false; };
  document.getElementById("eraser").onclick = () => { erasing = true; };

  document.getElementById("clearCanvas").onclick = () => {
    ctx.clearRect(0,0,canvas.width,canvas.height);
    localStorage.removeItem("coloringProgress");
  };
  document.getElementById("saveProgress").onclick = () => {
    localStorage.setItem("coloringProgress", canvas.toDataURL());
    alert("✅ Прогресс сохранён!");
  };
  document.getElementById("showCode").onclick = () => {
    const panel = document.getElementById("codePanel");
    panel.style.display = "block";
    document.getElementById("codeOutput").value = canvas.toDataURL();
  };
  document.getElementById("copyCode").onclick = () => {
    const area = document.getElementById("codeOutput");
    area.select();
    document.execCommand("copy");
    alert("✅ Код скопирован!");
  };

  // === Размер под страницу ===
  function resizeCanvas() {
    const ratio = img.naturalWidth / img.naturalHeight || 1.5;
    canvas.width = img.clientWidth || window.innerWidth;
    canvas.height = (img.clientWidth || window.innerWidth) / ratio;
    restoreProgress();
  }
  img.onload = resizeCanvas;
  window.onresize = resizeCanvas;

  // === Рисование ===
  function startDraw(e) { painting = true; draw(e); }
  function endDraw() { painting = false; ctx.beginPath(); saveProgress(); }

  function draw(e) {
    if (!painting) return;
    const rect = canvas.getBoundingClientRect();
    const x = (e.clientX || e.touches?.[0]?.clientX) - rect.left;
    const y = (e.clientY || e.touches?.[0]?.clientY) - rect.top;

    if (brushType === "soft") {
      softStroke(x, y);
    } else if (erasing) {
      ctx.globalCompositeOperation = "destination-out";
      ctx.beginPath();
      ctx.arc(x, y, brushSize.value / 2, 0, Math.PI * 2);
      ctx.fill();
    } else {
      ctx.globalCompositeOperation = "source-over";
      ctx.lineWidth = brushSize.value;
      ctx.lineCap = "round";
      ctx.strokeStyle = currentColor;
      ctx.globalAlpha = 1;
      ctx.lineTo(x, y);
      ctx.stroke();
      ctx.beginPath();
      ctx.moveTo(x, y);
    }
  }

  // === Мягкая кисть ===
  function softStroke(x, y) {
    const grd = ctx.createRadialGradient(x, y, 0, x, y, brushSize.value / 2);
    const color = erasing ? '#ffffff' : currentColor;
    grd.addColorStop(0, color + 'cc'); // полупрозрачный центр
    grd.addColorStop(1, color + '00'); // прозрачные края
    ctx.globalCompositeOperation = erasing ? 'destination-out' : 'source-over';
    ctx.globalAlpha = 0.25;
    ctx.fillStyle = grd;
    ctx.beginPath();
    ctx.arc(x, y, brushSize.value / 2, 0, Math.PI * 2);
    ctx.fill();
  }

  // === Сохранение прогресса ===
  function saveProgress() {
    localStorage.setItem("coloringProgress", canvas.toDataURL());
  }

  function restoreProgress() {
    const saved = localStorage.getItem("coloringProgress");
    if (saved) {
      const imgData = new Image();
      imgData.onload = () => ctx.drawImage(imgData, 0, 0, canvas.width, canvas.height);
      imgData.src = saved;
    }
  }

  // === События ===
  canvas.addEventListener("mousedown", startDraw);
  canvas.addEventListener("mouseup", endDraw);
  canvas.addEventListener("mousemove", draw);
  canvas.addEventListener("touchstart", startDraw);
  canvas.addEventListener("touchend", endDraw);
  canvas.addEventListener("touchmove", draw);
})();
</script>
[/html]

0


Вы здесь » test » новый не новый » рас


Рейтинг форумов | Создать форум бесплатно