从对象属性在画布上绘制图像

时间:2019-01-24 14:22:05

标签: javascript image canvas

我想在每次迭代时在画布上绘制图像,图像来自对象。 我在控制台中收到“不是HTML格式的信息...”,或者什么也没有,它阻止了循环。

是否有一种方法可以在画布上绘制图像而无需先将其放在index.html上,也可以不从URL加载?

我尝试了两种标准解决方案,但是它们没有用。

使用包含图像的对象属性将其绘制在画布上时,我没有发现类似的问题。

<table class="table outerTbl mb-0">
    <thead>
        <tr>
            <th scope="col">SL No.</th>
            <th scope="col">Program Details</th>
            <th scope="col">Program Levels</th>
            <th scope="col">Program Start Date</th>
            <th scope="col">Program End Date</th>
            <th scope="col">Total Duration</th>
            <th scope="col">Start</th>
            <th scope="col">Cacel</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row" class="collapsed" data-toggle="collapse" data-target="#row1" aria-expanded="false" aria-controls="row1">View</th>
            <td>Stay Active & Win</td>
            <td>03</td>
            <td>03/12/2018</td>
            <td>03/02/2019</td>
            <td>5 Days, 240secs.</td>
            <td><img src="images/start.png"></td>
            <td><img src="images/cancel.png"></td>
        </tr>
        <tr id="row1" class="table collapse innerTbl text-center col-11">
            <td colspan="8">
                <table width="100%">
                    <thead>
                        <tr>
                            <th scope="col">Program Details</th>
                            <th scope="col">Program Levels</th>      
                            <th scope="col">Progrma Duration</th>
                            <th scope="col">Status</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>               
                            <td>Power Up <img src="images/trophy.png"/></td>
                            <td>Level 1</td>
                            <td>240 secs</td>
                            <td>Play</td>              
                        </tr>
                        <tr>               
                            <td>Warriors <img src="images/trophy.png"/></td>
                            <td>Level 2</td>
                            <td>5 Days</td>
                            <td>Play</td>              
                        </tr>
                    </tbody>
                </table>
            </td>
        </tr>
        <tr>
            <th scope="row" class="collapsed" data-toggle="collapse" data-target="#row2" aria-expanded="false" aria-controls="row2">View</th>
            <td>New Year Goals</td>
            <td>01</td>
            <td>01/01/2019</td>
            <td>01/02/2019</td>
            <td>5 Days, 240secs.</td>
            <td><img src="images/start.png"/></td>
            <td><img src="images/cancel.png"/></td>
        </tr>
        <tr id="row2" class="table collapse innerTbl text-center col-11">  
            <td>
                <table >
                    <thead>
                        <tr>
                            <th scope="col">Program Details</th>
                            <th scope="col">Program Levels</th>      
                            <th scope="col">Progrma Duration</th>
                            <th scope="col">Status</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>               
                            <td>Power Up <img src="images/trophy.png"/></td>
                            <td>Level 1</td>
                            <td>240 secs</td>
                            <td>Play</td>              
                        </tr>
                        <tr>               
                            <td>Warriors <img src="images/trophy.png"/></td>
                            <td>Level 2</td>
                            <td>5 Days</td>
                            <td>Play</td>              
                        </tr>
                    </tbody>
                </table>
            </td>
        </tr>  
    </tbody>
</table>

实际:未绘制图像。如果我尝试fillRect,它会很好地工作。这样循环就可以了。

预期:能够通过对象属性在画布上绘制图像。

1 个答案:

答案 0 :(得分:1)

目前还不清楚您要做什么。

您评论的代码

ctx.drawImage = (image, drawX, drawY);

应该是这个

ctx.drawImage(image, drawX, drawY);

看得更广一点

let image = Obstacle.sprite;
ctx.drawImage(image, drawX, drawY);  // assume this was fixed

但是Obstacle是一个类,而不是该类的实例。你想要

let image = piece.sprite;
ctx.drawImage(image, drawX, drawY);

但这导致下一个问题。查看代码piece.sprite的其余部分是字符串而不是图像。请参阅此代码。

// OBJECT TO DRAW
function Obstacle(name, sprite) {
    this.name = name;
    this.sprite = sprite;
}

const lava = new Obstacle("Lave", "assets/lave.png");

有几种方法可以将图像绘制到画布上。如果它们来自文件,则必须等待它们下载。否则,您可以从另一个画布生成它们。您还可以使用createImageDataputImageData作为制作图像的另一种方法。

让我们更改代码以加载一堆图像然后开始

我将所有类代码移至顶部,将启动代码移至底部。

Board方法中有一些地方使用了全局变量board而不是this,所以我修复了这些地方。

这是一个加载图像并返回Promise的函数

function loadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => { resolve(img); };
    img.onerror = reject;
    img.crossOrigin = 'anonymous';  // REMOVE IF SAME DOMAIN!
    img.src = url;
  });
}

您可以使用它来加载一张这样的图像

loadImage(urlOfImage).then(function(img) {
  // use the loaded img
});

我使用该函数编写了该函数,该函数将名称对象传递给url,然后将名称对象返回给加载的图像。

function loadImages(images) {
  return new Promise((resolve) => {
    const loadedImages = {};
    const imagePromises = Object.entries(images).map((keyValue) => {
      const [name, url] = keyValue;
      return loadImage(url).then((img) => {
         loadedImages[name] = img;
      });
    });
    Promise.all(imagePromises).then(() => {
      resolve(loadedImages);
    });
  });
}

然后我调用它,并将名称对象传递给已加载的图像到start函数。目前仅加载一张图片,但您可以添加更多图片。

const images = {
  lave: 'https://i.imgur.com/enx5Xc8.png',
  // player: 'foo/player.png',
  // enemy: 'foo/enemny.png',
};
loadImages(images).then(start);

// CONTEXT OF THE CANVAS
const ctx = $('#board').get(0).getContext('2d');

function Board(width, height) {
    this.width = width;
    this.height = height;
    this.chartBoard = [];

    // Création du plateau logique
    for (var i = 0; i < this.width; i++) {
        const row = [];
        this.chartBoard.push(row);
        for (var j = 0; j < this.height; j++) {
            const col = {};
            row.push(col);
        }
    }
}

Board.prototype.drawBoard = function () {
    for (var i = 0; i < this.width; i++) {
        for (var j = 0; j < this.height; j++) {
            ctx.beginPath();
            ctx.strokeStyle = 'black';
            ctx.strokeRect(j * 64, i * 64, 64, 64);
            ctx.closePath();
        }
    }
};

// OBJECT TO DRAW
function Obstacle(name, sprite) {
    this.name = name;
    this.sprite = sprite;
}


// FUNCTION TO DRAW

Board.prototype.setPiece = function (piece) {

    let randomX = Math.floor(Math.random() * this.width);
    let randomY = Math.floor(Math.random() * this.height);

    let drawX = randomX * 64;
    let drawY = randomY * 64;


    if (randomX >= this.width || randomY >= this.height) {
        throw new Error('Pièce hors limite');
    }

    if (piece instanceof Obstacle) {

        if (!(this.chartBoard[randomY][randomX] instanceof Obstacle)) {
            this.chartBoard[randomY][randomX] = piece;

            // CODE TO DRAW, BUG DOESN'T WORK
            ctx.fillRect(drawX, drawY,64,64);
            let image = piece.sprite;
            ctx.drawImage(image, drawX, drawY);
        }
    } else {
        throw new Error('Pièce non valide');
    }
};

Board.prototype.setObstacles = function (lavaArray) {
    for (let lava of lavaArray) {

        const obstacle = this.setPiece(lava);
    }
};

function start(images) {
  let board = new Board(10, 10);
//  console.log(board);

  const lava = new Obstacle("Lave", images.lave);
  const lava1 = new Obstacle("Lave1", images.lave);
  const lava2 = new Obstacle("Lave2", images.lave);
  const lava3 = new Obstacle("Lave3", images.lave);
  const lava4 = new Obstacle("Lave4", images.lave);
  const lava5 = new Obstacle("Lave5", images.lave);
  const lava6 = new Obstacle("Lave6", images.lave);
  const lava7 = new Obstacle("Lave7", images.lave);
  const lava8 = new Obstacle("Lave8", images.lave);
  const lava9 = new Obstacle("Lave9", images.lave);
  const lavaArray = [lava, lava1, lava2, lava3, lava4, lava5, lava6, lava7, lava8, lava9];

  board.drawBoard();


  board.setObstacles(lavaArray);
}

function loadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => { resolve(img); };
    img.onerror = reject;
    img.crossOrigin = 'anonymous';  // REMOVE IF SAME DOMAIN!
    img.src = url;
  });
}

function loadImages(images) {
  return new Promise((resolve) => {
    const loadedImages = {};
    // for each name/url pair in image make a promise to load the image
    // by calling loadImage
    const imagePromises = Object.entries(images).map((keyValue) => {
      const [name, url] = keyValue;
      // load the image and when it's finished loading add the name/image
      // pair to loadedImages
      return loadImage(url).then((img) => {
         loadedImages[name] = img;
      });
    });
    // wait for all the images to load then pass the name/image object
    Promise.all(imagePromises).then(() => {
      resolve(loadedImages);
    });
  });
}

const images = {
  lave: 'https://i.imgur.com/enx5Xc8.png',
  // player: 'foo/player.png',
  // enemy: 'foo/enemny.png',
};
loadImages(images).then(start);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="board" width="640" height="640"></canvas>