What I want to do is load an svg, change its fill color to a random value and then draw it on the canvas. This has proved to be much more difficult than I would have thought. Here's the code I have at the moment.
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
//images
var bottomLeftTop = new Image();
var bottomRightTop = new Image();
var fullTop= new Image();
var leftMidSide = new Image();
var leftSide = new Image();
var rightMidSide = new Image();
var rightSide = new Image();
var topLeftTop = new Image();
var topRightTop = new Image();
bottomLeftTop.src = "img/bottomLeftTop.svg";
bottomRightTop.src = "img/bottomRightTop.svg";
fullTop.src = "img/fullTop.svg";
leftMidSide.src = "img/leftMidSide.svg";
leftSide.src = "img/leftSide.svg";
rightMidSide.src = "img/rightMidSide.svg";
rightSide.src = "img/rightSide.svg";
topLeftTop.src = "img/topLeftTop.svg";
topRightTop.src = "img/topRightTop.svg";
//draw
context.drawImage(fullTop,50,50);
I'm currently loading my svg's as Image objects, which works fine for just drawing but won't allow me to change the fill color.
I did try converting my svg to canvas commands, which allows me to change the fill but requires a lot of work to get scaled and positioned properly, and just isn't feasible with the amount of images I'm working with.
Is there any other way I can do this while still working with the canvas?
What I want to do is load an svg, change its fill color to a random value and then draw it on the canvas. This has proved to be much more difficult than I would have thought. Here's the code I have at the moment.
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
//images
var bottomLeftTop = new Image();
var bottomRightTop = new Image();
var fullTop= new Image();
var leftMidSide = new Image();
var leftSide = new Image();
var rightMidSide = new Image();
var rightSide = new Image();
var topLeftTop = new Image();
var topRightTop = new Image();
bottomLeftTop.src = "img/bottomLeftTop.svg";
bottomRightTop.src = "img/bottomRightTop.svg";
fullTop.src = "img/fullTop.svg";
leftMidSide.src = "img/leftMidSide.svg";
leftSide.src = "img/leftSide.svg";
rightMidSide.src = "img/rightMidSide.svg";
rightSide.src = "img/rightSide.svg";
topLeftTop.src = "img/topLeftTop.svg";
topRightTop.src = "img/topRightTop.svg";
//draw
context.drawImage(fullTop,50,50);
I'm currently loading my svg's as Image objects, which works fine for just drawing but won't allow me to change the fill color.
I did try converting my svg to canvas commands, which allows me to change the fill but requires a lot of work to get scaled and positioned properly, and just isn't feasible with the amount of images I'm working with.
Is there any other way I can do this while still working with the canvas?
Share Improve this question asked Dec 22, 2014 at 4:37 thrillingheroicsthrillingheroics 1231 gold badge1 silver badge6 bronze badges2 Answers
Reset to default 13The trick is to load your svg as XML via XHR and manipulate it any way you want, then create your image out of it using data:image
format.
E.g.
$.get('img/bottomLeftTop.svg', function(svgXml) {
var img = new Image();
var coloredSvgXml = svgXml.replace(/#3080d0/g,'#e05030');
img.onload = () => context.drawImage(img,0,0);
img.src = "data:image/svg+xml;charset=utf-8,"+coloredSvgXml;
});
Here is a snippet I created to demonstrate the manipulation principle. It uses in-html hidden svg node to draw on 2d canvas, then changes the color via regexp and draws on the same canvas again:
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var svg = document.getElementById('tmpSvg')
var blueCircle = (new XMLSerializer).serializeToString(svg);
var img = new Image();
img.onload = () => context.drawImage(img, 0, 0, 160, 120);
img.src = "data:image/svg+xml;charset=utf-8;base64, " + btoa(blueCircle);
redCircle = blueCircle.replace(/#3080d0/g, '#e05030');
var img2 = new Image();
img2.onload = () => context.drawImage(img2, 10, 10, 160, 120);
img2.src = "data:image/svg+xml;charset=utf-8;base64, " + btoa(redCircle);
.wrapper {
display: none;
}
#canvas {
width: 400px;
height: 300px;
}
<canvas id="canvas"></canvas>
<div class="wrapper">
<svg id="tmpSvg" xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<style>
circle {
fill-opacity: 0.5;
stroke-width: 4;
fill: #3080d0;
stroke: #3080d0;
}
</style>
<circle id="my-circle" cx="50" cy="50" r="30" />
</svg>
</div>
Of course, nothing prevents you from using JavaScript built-in XML parser and XPath-based node manipulation. But in this particular case and for particular colors, regexp is probably more efficient.
One way is to create a temporary canvas for each image, get the image data and loop through it. In the loop, if pixel has color data, change that to the desired value.
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
canvas.width = 600;
canvas.height = 400;
var svg = new Image();
svg.onload = function () {
canvas.width = svg.width;
canvas.height = svg.height;
// create temporary canvas
var svgCanvas = document.createElement("canvas");
var svgCtx = svgCanvas.getContext("2d");
svgCanvas.width = svg.width;
svgCanvas.height = svg.height;
// draw the actual svg image to temporary canvas
svgCtx.drawImage(svg, 0, 0);
// get ImageData object
var svgData = svgCtx.getImageData(0, 0, svgCanvas.width, svgCanvas.height);
// get pixel data
var data = svgData.data;
// loop through data
for (var i = 0; i < data.length; i += 4) {
// check if pixel alpha value is not 0, then change the data
if (data[i + 3] !== 0) {
data[i] = 255; // pixel red value
data[i + 1] = 0; // pixel green value
data[i + 2] = 0; // pixel blue value
}
}
// put the data back to the temporary svg canvas
svgCtx.putImageData(svgData, 0, 0);
// draw temporary canvas to the real canvas
ctx.drawImage(svgCanvas, 0, 0);
}
// look out for CORS, the svg needs to be on the same origin.
svg.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/38/Maki-alcohol-shop-15.svg/1024px-Maki-alcohol-shop-15.svg.png";
Reference to Pixel manipulation with canvas