最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Change svg fill color and then draw to canvas - Stack Overflow

programmeradmin2浏览0评论

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 badges
Add a comment  | 

2 Answers 2

Reset to default 13

The 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

发布评论

评论列表(0)

  1. 暂无评论