2016-07-12 2 views
1

Я пытаюсь сделать SVG изображения на холсте образы рисуются один в то время, чтобы заполнить данную строку ниже фрагмент кода одного и того же:рендеринга SVG изображений на холсте

function createSVGUrl(svg) { 
    var svgBlob = new Blob([svg], {type: 'image/svg+xml;charset=utf-8'}); 
    return DOMURL.createObjectURL(svgBlob); 
    }; 

/** 
    * Renders svg tile on the given context. 
    * @param {CanvasRenderingContext2D} ctx 
    * @param {SVGElement} svg The svg tile. 
    * @param {{x: number, y:number}} pos The position to draw the svg tile on. 
    * @throws Error 
    */ 
    function renderSVGTile(ctx, svg, pos) { 
    var img = new Image(); 
    var url = createSVGUrl(svg); 
    img.onload = function() { 
     try { 
     ctx.drawImage(img, pos.x, pos.y); 
     ctx.imageSmoothingEnabled = false; 
     ctx.mozImageSmoothingEnabled = false; 
     DOMURL.revokeObjectURL(url); 
     } catch (e) { 
     throw new Error('Could not render image' + e); 
     } 
    }; 
    img.src = url; 
    }; 

проблема в том, что я вижу частично заполненные строки, которые мне не нужны, есть ли способ заполнить всю строку сразу?

+0

Просто ждать все ваши изображения были предварительно загружены, а затем нарисовать его. Btw, imageSmoothingEnabled необходимо установить перед вызовом drawImage и не устанавливать его в цикле. – Kaiido

+0

Возможный дубликат [Как работают предварительные загрузчики изображений?] (Http://stackoverflow.com/questions/30578521/how-do-image-preloaders-work) – Kaiido

+0

@ Кайдо не совсем я попробовал предлагаемое решение, но оно не работа в моем случае, возможно, из-за очень большого количества изображений в строке. Теоретически это должно работать, но это не так, [здесь] (http://codereview.stackexchange.com/q/133964/58341) вы можете увидеть пример. – CodeYogi

ответ

1

Да. Сначала нарисуйте весь ряд плиток на заставку Canvas. Когда это будет сделано, вы можете нарисовать этот экранный холст на своем основном холсте.

Что-то вроде:

var offscreenCanvas = document.createElement('canvas'); 
offscreenCanvas .width = <whatever>; 
offscreenCanvas .height = <whatever>; 
var offscreenContext = offscreenCanvas.getContext('2d'); 

// Draw all your tiles 
renderSVGTile(offscreenContext, svg, pos); 
//... loop through all tiles etc 

// When finished... 
mainCanvasContext.drawImage(offscreenCanvas, 0, 0); 

Демо:

var canvas = document.getElementById("canvas"); 
 
var ctx = canvas.getContext("2d"); 
 
var image = document.getElementById("source"); 
 

 
var offscreenCanvas = document.createElement("canvas"); 
 
offscreenCanvas.width = 300; 
 
offscreenCanvas.height = 150; 
 
var offscreenContext = offscreenCanvas.getContext("2d"); 
 

 
offscreenContext.drawImage(image, 33, 71, 104, 124, 21, 20, 87, 104); 
 
offscreenContext.drawImage(image, 33, 71, 104, 124, 108, 20, 87, 104); 
 

 
ctx.drawImage(offscreenCanvas, 0, 0);
<canvas id="canvas"></canvas> 
 
<div style="display:none;"> 
 
    <img id="source" src="http://placekitten.com/300/227" 
 
     width="300" height="227"> 
 
</div>

+0

DID вы пытаетесь это сделать, потому что я пробовал это раньше, но не увенчался успехом. – CodeYogi

+0

Добавлена ​​рабочая демонстрация (хотя и с обычными растровыми изображениями). Протестировано в Chrome и Firefox. –

+0

LGTM! Я попробую сам. – CodeYogi

0

Это, как я это делаю, хотя я не уверен, если это будет служить вашей цели, как я изображение в документе во время рендеринга, оно просто скрыто.

var ctx = document.getElementById("canvasID").getContext("2d"); 
ctx.drawImage(document.getElementById("imageID"), x,y,w,h); 
+0

Нет, svg динамически генерируются. – CodeYogi

+0

Тогда я боюсь, что он не сработает, если вы не захотите добавить динамически сгенерированный SVG-файл к изображению в документе, и в этом случае он будет работать. Я не уверен, что если ctx.drawImage примет неэлементный образ, вы можете попробовать, так как используете тот же метод. Кроме того, на самом деле вам не нужно прикреплять элемент к странице, пока он создается и ссылается. – Dellirium

0

Раствор ниже работает отлично для меня:

/** 
    * @param {CanvasRenderingContext2D} ctx 
    * @param {!Array<!SVGTile>} tiles 
    */ 
    function drawTiles(ctx, tiles) { 
    var canvas = document.createElement('canvas'); 
    var width = tiles.length * TILE_WIDTH; 
    var height = TILE_HEIGHT; 
    var y = tiles[0].y; 
    canvas.width = tiles.length * TILE_WIDTH; 
    canvas.height = TILE_HEIGHT; 
    var context = canvas.getContext("2d"); 
    tiles.forEach(function(tile, index) { 
     renderTile(context, tile, function() { 
     if (tiles.length === index + 1) { 
      ctx.drawImage(canvas, 0, y); 
     } 
     }); 
    }); 
    // TODO: Below code is for testing purpose. 
    var temp = document.createElement('div'); 
    temp.appendChild(canvas); 
    document.body.appendChild(temp); 
    }; 


    /** 
    * Renders svg tile on the given context. 
    * @param {CanvasRenderingContext2D} ctx 
    * @param {!Tile} tile The tile to render. 
    * @param {function()} callback To be called after image is loaded. 
    * @throws Error 
    */ 
    function renderTile(ctx, tile, callback) { 
    var img = new Image(); 
    img.onload = function() { 
     try { 
     ctx.drawImage(this, tile.x, 0, tile.width, tile.height); 
     ctx.imageSmoothingEnabled = false; 
     ctx.mozImageSmoothingEnabled = false; 
     DOMURL.revokeObjectURL(tile.svgURL); 
     callback(); 
     } catch (e) { 
     throw new Error('Could not render image' + e); 
     } 
    }; 
    img.src = tile.svgURL; 
    }; 
Смежные вопросы