2016-07-12 16 views
1

Ich versuche, SVG-Bilder auf einer Leinwand die Bilder gezeichnet einer nach dem anderen zu machen, eine bestimmte Zeile zu füllen, ist unter dem Code-Schnipsel aus dem gleichen:Rendern von SVG-Bildern auf einer Leinwand

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; 
    }; 

Die Problem ist, dass ich die teilweise gefüllten Reihen sehen kann, die ich nicht will, gibt es irgendeine Weise, die ganze Reihe auf einmal zu füllen?

+0

Nur für alle Bild warten haben vorinstalliert, dann ziehen. Btw, imageSmoothingEnabled sollte vor dem Aufruf von drawImage gesetzt werden, und es sollte vermieden werden, es in eine Schleife zu setzen. – Kaiido

+0

Mögliches Duplikat von [Wie funktionieren Bild-Preloader?] (Http://stackoverflow.com/questions/30578521/how-do-image-preladers-work) – Kaiido

+0

@Kaiido nicht genau ich habe die vorgeschlagene Lösung ausprobiert, tut es aber nicht funktionieren in meinem Fall, möglicherweise aufgrund der sehr großen Anzahl von Bildern pro Zeile. Theoretisch sollte es funktionieren, aber es nicht, [hier] (http://codereview.stackexchange.com/q/133964/58341) können Sie das Beispiel sehen. – CodeYogi

Antwort

1

Ja. Zeichnen Sie Ihre gesamte Kachelreihe zuerst auf ein Offscreen-Canvas. Wenn Sie damit fertig sind, können Sie diese Leinwand auf die Leinwand projizieren.

Etwas wie:

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); 

Demo:

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

Ich probiere das, weil ich das vorher versucht habe, aber nicht erfolgreich war. – CodeYogi

+0

Arbeitsdemo hinzugefügt (wenn auch mit normalen Bitmap-Bildern). Getestet in Chrome und Firefox. –

+0

LGTM! Ich werde es selbst versuchen. – CodeYogi

0

Dies ist, wie ich es tun, obwohl ich nicht sicher bin, ob es Ihren Zweck dienen wie ich das Bild im Dokument zum Zeitpunkt der Wiedergabe, es ist nur versteckt.

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

Nein, die SVG werden dynamisch generiert. – CodeYogi

+0

Dann habe ich Angst, es kann nicht funktionieren, es sei denn, Sie sind bereit, eine dynamisch erzeugte SVG-Datei zu einem Bild im Dokument hinzuzufügen, in welchem ​​Fall es funktionieren würde. Ich bin nicht sicher, ob ctx.drawImage ein Nicht-Element-Bild akzeptieren würde, Sie könnten versuchen, da Sie die gleiche Methode verwenden. Außerdem muss kein Element an die Seite angehängt sein, solange es erstellt und referenziert wird. – Dellirium

0

Die Lösung unten für mich funktioniert gut:

/** 
    * @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; 
    };