【问题标题】:How can I save and load art made without a canvas element?如何保存和加载没有画布元素的艺术作品?
【发布时间】:2020-09-22 05:28:38
【问题描述】:

我正在做一个像素艺术创作者,我已经完成了大部分功能;但是,我希望用户能够保存和加载他们在页面上所做的设计。我为模板使用了一个 div 网格,但我看到的所有保存和加载示例都使用了画布元素。有什么办法可以用我的设计来做,还是我需要用画布重新设计它?

let canvas = document.querySelector('.canvas');
let button = document.querySelector('button');
let high;
let wide;
let color = document.querySelector('.colorChoice').value;

//create cell listeners
function listenCells() {
    let cell = document.querySelectorAll('.grid-square');
    cell.forEach((cell) => {
        cell.addEventListener('click', function() {
            cell.style.backgroundColor = color;
        });
    });
}

//Check for updated color picker
function onChangeColor() {
    color = this.value;
}

document.querySelector('.colorChoice').addEventListener("change", onChangeColor);

//function to build the grid based on user input
function createGrid(height = 25, width = 25) {
    canvas.innerHTML = '';
    for (let i = 0; i < height; i++) {
        let row = document.createElement('div');
        row.classList.add('row');
        canvas.appendChild(row);
        for (let j = 0; j < width; j++) {
            let cell = document.createElement('div');
            cell.classList.add('grid-square');
            row.appendChild(cell);
        }
    }
    listenCells();
}

//listens for input of rows and columns
button.addEventListener('click', function() {
    high = parseInt(document.querySelector('.column-input').value);
    wide = parseInt(document.querySelector('.row-input').value);
    if (Number.isNaN(high) || Number.isNaN(wide)) {
        createGrid();
    } else {
        createGrid(wide, high);
    }
});

//Default grid built on load
window.onload = createGrid(25, 25);
/* import pixel font for navbar */
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');

.grid-square {
    height: 12px;
    width: 12px;
    border: 1px black solid;
    flex-shrink: 0;
}

.row {
    display: flex;
    justify-content: center;
    flex-wrap: nowrap;
}

.canvas {
    max-height: inherit;
    max-width: 75%;
}

body {
    font-family: 'Press Start 2P', cursive;
}
<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
    <link rel="stylesheet" href="styles/style.css">

    <title>Pixel Art Maker</title>
  </head>
  <body>

    <!-- Navbar -->
    <nav class="navbar navbar-dark bg-dark">
        <span class="navbar-brand mb-0 h1 mx-auto">Pixel Art Maker</span>
    </nav>

    <!-- Container to put grid in -->
    <div class="container shadow p-3 mb-5 bg-white rounded mt-5 main">
      
      <div class="container canvas d-flex-inline">
        
      </div>

      <form class="d-flex-inline w-50 mx-auto mt-4">
        <div class="d-flex">
          <div class="form-group w-25 ml-auto mr-2">
            <label class="d-block text-center" for="gridRows">Rows</label>
            <input type="number" class="form-control row-input" id="gridRows">
          </div>
          <div class="form-group w-25 mr-auto ml-2">
            <label class="d-block text-center" for="gridColumns">Columns</label>
            <input type="number" class="form-control column-input" id="gridColumns">
          </div>
        </div>  
        </form>
        <div class="form-group w-25 mx-auto">
          <button type="submit" class="btn btn-primary w-100">Submit</button>
        </div>
      <form class="d-flex-inline w-50 mx-auto">
        <div class="form-group w-25 mx-auto">
          <label for="color">Color</label>
          <input type="color" class="form-control colorChoice" id="color">
        </div>
      </form>
    </div>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS, then local JS -->
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
    <script src="scripts/script.js"></script>
  </body>
</html>

附:我使用的是纯 JavaScript,没有 jQuery

【问题讨论】:

  • 您可以调用canvas.toDataURL(); 来获取具有图像表示的URL。该 URL 可以保存到 localStorage
  • 你绝对应该转向画布设计。您应该创建绘图函数以获取可以重新创建客户端在 GUI 上创建的相同绘图的参数。有几种方法可以保存东西; localStorage 在您的浏览器(如 localStorage.data = JSON.stringify(jsonObjectHere);)和服务器本身上,只要您的客户在您的系统上有一个帐户(需要正确完成大量工作),我会建议您这样做。
  • 了解您正在使用&lt;div&gt; 的网格,如果您需要,这些可以序列化为具有尺寸和位置属性、内容、基本样式等的javascript 对象数组。然后可以将该数组发送到服务器,或存储在本地。当您需要再次加载每个对象时,给定足够的属性,您可以为每个对象创建元素并插入 dom。不知道你为什么不使用画布来完成整个事情
  • 只需将坐标存储在颜色映射中,然后将整体保存为 JSON。与所有其他以前的 cmets 不同,我认为这里不使用画布的很好的理由:在画布上绘制网格意味着你实际上必须有一个比像素艺术大 12 倍的画布,如果你想删除那个网格export 这意味着您必须重绘所有内容等。指针事件逻辑会更加复杂等。将 div 作为控件保持对我来说似乎是合理的,如果您需要 png 输出,则始终可以只在画布上绘制。

标签: javascript html css canvas


【解决方案1】:

您没有提供有关 able to save and load 的详细信息,所以我会选择 SVG...
如果您从未听说过 SVG,您应该阅读一下:
https://en.wikipedia.org/wiki/Scalable_Vector_Graphics

以下是已保存文档的示例:

<svg xmlns="http://www.w3.org/2000/svg" 
     xmlns:ev="http://www.w3.org/2001/xml-events" 
     xmlns:xlink="http://www.w3.org/1999/xlink" 
     version="1.1" baseProfile="full" 
     height="80px" width="440px">
  <defs/>
  
  <rect fill="rgb(105,10,255)" height="40px" width="40px" x="40px"  y="0px"/>
  <rect fill="rgb(135,20,245)" height="40px" width="40px" x="80px"  y="0px"/>
  <rect fill="rgb(165,30,235)" height="40px" width="40px" x="120px" y="0px"/>
  <rect fill="rgb(195,40,225)" height="40px" width="40px" x="160px" y="0px"/>
  <rect fill="rgb(205,50,215)" height="40px" width="40px" x="200px" y="0px"/>
  <rect fill="rgb(215,60,205)" height="40px" width="40px" x="240px" y="0px"/>
  <rect fill="rgb(225,70,195)" height="40px" width="40px" x="280px" y="0px"/>
  <rect fill="rgb(235,80,165)" height="40px" width="40px" x="320px" y="0px"/>
  <rect fill="rgb(245,90,135)" height="40px" width="40px" x="360px" y="0px"/>
  <rect fill="rgb(255,10,105)" height="40px" width="40px" x="400px" y="0px"/>
 
  <rect fill="rgb(105,255,10)" height="40px" width="40px" x="40px"  y="40px"/>
  <rect fill="rgb(135,245,20)" height="40px" width="40px" x="80px"  y="40px"/>
  <rect fill="rgb(165,235,30)" height="40px" width="40px" x="120px" y="40px"/>
  <rect fill="rgb(195,225,40)" height="40px" width="40px" x="160px" y="40px"/>
  <rect fill="rgb(205,215,50)" height="40px" width="40px" x="200px" y="40px"/>
  <rect fill="rgb(215,205,60)" height="40px" width="40px" x="240px" y="40px"/>
  <rect fill="rgb(225,195,70)" height="40px" width="40px" x="280px" y="40px"/>
  <rect fill="rgb(235,165,80)" height="40px" width="40px" x="320px" y="40px"/>
  <rect fill="rgb(245,135,90)" height="40px" width="40px" x="360px" y="40px"/>
  <rect fill="rgb(255,105,10)" height="40px" width="40px" x="400px" y="40px"/>
</svg>

当然,这只是一个只有两行的小样本。
您的每个定义的像素都会有一个 rect

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 2017-01-10
    • 1970-01-01
    相关资源
    最近更新 更多