Draw 10,000 objects on canvas javascript

Active3 hr before
Viewed126 times

7 Answers


I can get you 10,000 but there are two main drawbacks. ,You may notice the images don't respect transparency entirely, its possible to fix.. but that's beyond the scope of this answer.,Layered canvas only helps performance when static elements need not be constantly redrawn. ,Here are some steps you can do to increase the performance:

So what I did is first I created a temporary canvas for the image

imgToDraw.onload = function() {
   // In memory canvas
   imageCanvas = document.createElement("canvas"),
      iCtx = imageCanvas.getContext("2d");

   // set the canvas to the size of the image
   imageCanvas.width = this.width;
   imageCanvas.height = this.height;

   // draw the image onto the canvas
   iCtx.drawImage(this, 0, 0);

   // get the ImageData for the image.
   imageData = iCtx.getImageData(0, 0, this.width, this.height);
   // get the pixel component data from the image Data.
   imagePixData = imageData.data;

   // store our width and height so we can reference it faster.
   imgWidth = this.width;
   imgHeight = this.height;


I'm just posting the relevant portion.

// create new Image data. Doing this everytime gets rid of our 
// need to manually clear the canvas since the data is fresh each time
var canvasData = ctx.createImageData(canvas.width, canvas.height),
   // get the pixel data
   cData = canvasData.data;

// Iterate over the image we stored 
for (var w = 0; w < imgWidth; w++) {
   for (var h = 0; h < imgHeight; h++) {
      // make sure the edges of the image are still inside the canvas
      // This also is VERY important for perf reasons
      // you never want to draw outside of the canvas bounds with this method
      if (entity.x + w < width && entity.x + w > 0 &&
         entity.y + h > 0 && entity.y + h < height) {

         // get the position pixel from the image canvas
         var iData = (h * imgWidth + w) * 4;

         // get the position of the data we will write to on our main canvas
         // the values must be whole numbers ~~ is just Math.floor basically
         var pData = (~~(entity.x + w) + ~~(entity.y + h) * width) * 4;

         // copy the r/g/b/ and alpha values to our main canvas from 
         // our image canvas data.

         cData[pData] = imagePixData[iData];
         cData[pData + 1] = imagePixData[iData + 1];
         cData[pData + 2] = imagePixData[iData + 2];
         // this is where alpha blending could be applied
         if (cData[pData + 3] < 100) {
            cData[pData + 3] = imagePixData[iData + 3];

// now put all of that image data we just wrote onto the actual canvas.
ctx.putImageData(canvasData, 0, 0);
load more v

I need draw over 10,000 images (32x32 px) on canvas but over 2000 draws the performances is very bad.,this is a little example:,object structure {position:0},I've done a lot of experiments with canvas in many browsers. Some performance issues that I noticed:

object structure {position:0}

for (var nObject = 0; nObject < objects.length; nObject++) {
   ctx.translate(coords.x, coords.y);
   ctx.rotate(objects[nObject].position / 100);
   ctx.translate(radio, 0);
   ctx.drawImage(img, 0, 0);
load more v

Let’s get more into the code and start with the basics and work our way up. In this example we start by simply drawing an image on the canvas (read the comments in the code for additional details):,Next we need to add logic in the draw function to know which image to draw when the screen is scrolled. To do this we need to know the position of each image (see comments in the code for details):,Now we have to go through an array of images with conditional statements to see if we need to draw the image at the start or end of the canvas.,The next idea was what if we drew the images on a canvas? There are some neat interactive applications out there that use this technology. Just check out this one. If that can perform fairly well surely we can make our ‘simple’ scrolling wall perform somersaults.

But even setting the quality parameter to its highest (1.0)  toDataURL() , there was still a lose of image quality. Instead, for the best quality I found that drawing a larger image on to a smaller canvas. Which is actually what we’re already accomplishing this by using the img_posX_start_ratio to scale down the large 1024px images for mobile devices.

I had though since the wall guide in the app would only be landscape enabled, I could draw all the images to the canvas once and take a snapshot with toDataURL() to get the exact sizes. This way I don’t have to worry about the image aspect ratio and draw them as is. Additionally for devices like an iPod which aren’t 1024 px tall in landscape I won’t have to store the larger version of the images. While scrolling seemed silky smooth there was now a much longer initial loading time. And, as I mentioned, even setting the second parameter to 1 which tells it to use high quality the images still ended up a bit pixelated and was quite noticeable on retina screens.


The Javascript source code to do "Canvas draw 10,000 image objects on canvas" is ,Javascript Canvas draw 10,000 objects on canvas,Javascript Canvas Drag and Drop to HTML5 Canvas,Canvas Javascript Canvas example Javascript drawing

window.requestAnimFrame = (function() {
   return window.requestAnimationFrame ||
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.oRequestAnimationFrame ||
      window.msRequestAnimationFrame ||
      function(callback) {
         window.setTimeout(callback, 1000 / 60);
      }; /*from w w w. d e  m  o 2s  .  com*/
var numberOfObjects = 30000;
var canvas;
var ctx;
var objects = [];
var imgToDraw;
var coords = {
   x: 100,
   y: 100
var radio = 30;
for (var i = 0; i < numberOfObjects; i++) {
      position: 0
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
imgToDraw = new Image();
imgToDraw.src = "http://png-1.findicons.com/files/icons/1579/devine/16/circle.png";
imgToDraw.onload = function() {

function draw() {
   ctx.clearRect(0, 0, canvas.width, canvas.height);
   for (
      var nObject = 0,
         len = objects.length, // cache these
         x = coords.x,
         y = coords.y; nObject < len; nObject++
   ) {
      var banPrint = true;
      for (nOverlap = nObject; nOverlap < objects.length; nOverlap++) {
         if (
            objects[nOverlap].position == objects[nObject].position &&
            nOverlap != nObject
         ) {
            banPrint = false;
      if (banPrint === true) {
         ctx.setTransform(1, 0, 0, 1, x, y); // sets absolute transformation
         ctx.rotate(objects[nObject].position * 0.01);
         ctx.translate(radio, 0);
         ctx.drawImage(imgToDraw, 0, 0);
load more v

There are two alternatives. The first is DOM-based but utilizes Scalable Vector Graphics (SVG), rather than HTML. Think of SVG as a document-markup dialect that focuses on shapes rather than text. You can embed an SVG document directly in an HTML document or include it with an <img> tag.,The results binding contains an array of objects that represent the survey responses.,Make sure you reset the transformation after drawing any shape that creates one.,This is an HTML document with a simple SVG picture in it:

The angle of this line is currentAngle + 0.5 * sliceAngle. The following code finds a position on this line 120 pixels from the center:

let middleAngle = currentAngle + 0.5 * sliceAngle;
let textX = Math.cos(middleAngle) * 120 + centerX;
let textY = Math.sin(middleAngle) * 120 + centerY;

The JavaScript of the template does a couple of things.,Here are some of the JavaScript methods associated with drawing rectangles:,Canvas consists of a drawable region defined in HTML code with height and width attributes. JavaScript code may access the area through a full set of drawing functions similar to other common 2D APIs, thus allowing for dynamically generated graphics. Some anticipated uses of canvas include building graphs, animations, games, and image composition.,You can erase everything that is drawn on the canvas by resetting the width and/or height of the canvas element

The markup for the canvas element looks like this:

<canvas id="myCanvas" width="200" height="200"></canvas>
load more v

<!DOCTYPE html><html>  <head>    <script src="https://unpkg.com/[email protected]/konva.min.js"></script>    <meta charset="utf-8" />    <title>Konva Drag and Drop Stress Test with 10,000 Shapes Demo</title>    <style>      body {        margin: 0;        padding: 0;        overflow: hidden;        background-color: #f0f0f0;      }    </style>  </head>  <body>    <div id="container"></div>    <script>      var width = window.innerWidth;      var height = window.innerHeight;      function addCircle(layer) {        var color = colors[colorIndex++];        if (colorIndex >= colors.length) {          colorIndex = 0;        }        var randX = Math.random() * stage.width();        var randY = Math.random() * stage.height();        var circle = new Konva.Circle({          x: randX,          y: randY,          radius: 6,          fill: color,        });        layer.add(circle);      }      var stage = new Konva.Stage({        container: 'container',        width: width,        height: height,      });      var dragLayer = new Konva.Layer();      var colors = [        'red',        'orange',        'yellow',        'green',        'blue',        'cyan',        'purple',      ];      var colorIndex = 0;      var layersArr = [];      /*       * create 10 layers each containing 1000 shapes to create       * 10,000 shapes.  This greatly improves performance because       * only 1,000 shapes will have to be drawn at a time when a       * circle is removed from a layer rather than all 10,000 shapes.       * Keep in mind that having too many layers can also slow down performance.       * I found that using 10 layers each made up of 1,000 shapes performs better       * than 20 layers with 500 shapes or 5 layers with 2,000 shapes       */      for (var i = 0; i < 10; i++) {        var layer = new Konva.Layer();        layersArr.push(layer);        for (var n = 0; n < 1000; n++) {          addCircle(layer);        }        stage.add(layer);      }      stage.add(dragLayer);      stage.on('mousedown', function (evt) {        var circle = evt.target;        var layer = circle.getLayer();        circle.moveTo(dragLayer);        circle.startDrag();      });    </script>  </body></html>

Other "canvas-javascript" queries related to "Draw 10,000 objects on canvas javascript"