CSS styles not applied to SVG when SVG is rendered on Canvas - html

I am styling an SVG image using CSS in a separate file. Then I am rendering the SVG onto a canvas that can be saved as a PNG.
The SVG receives the CSS styles properly when it is just an SVG element on an HTML page, and renders as expected. However, when the SVG is rendered in a canvas element, the styles are not applied.
Is it possible to use external CSS to style an SVG and save that to a canvas without losing the styles? I cannot use inline CSS due to Content Security Policy in the browser.
Here is a sample.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>svg to png</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<button>svg to png</button>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200" height="200">
<path d="M10 40, C20 20, 50 20, 70 30, 70 30, 110 50, 160 20" id="path-1" fill="#CCCCCC" />
<text class="text-red">
<textpath xlink:href="#path-1" startOffset="50%" text-anchor="middle">Sample Path Text</textpath>
</text>
<rect x="10" y="14" width="10" height="10" />
<text x="0" y="100" class="text-primary">Text Style 1</text>
<text x="0" y="150" class="text-secondary">Text Style 2</text>
</svg>
<canvas id="canvas"></canvas>
<script src="./script.js"></script>
</body>
</html>
style.css
.text-primary {
font-size: 24px;
font-family: calibri;
}
.text-secondary {
font-size: 12px;
font-family: arial;
}
.text-red {
fill: #ff0000;
}
script.js
var btn = document.querySelector("button");
var svg = document.querySelector("svg");
var canvas = document.querySelector("canvas");
btn.addEventListener("click", function () {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var data = new XMLSerializer().serializeToString(svg);
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var svgBlob = new Blob([data], { type: "image/svg+xml;charset=utf-8" });
var url = DOMURL.createObjectURL(svgBlob);
img.onload = function () {
ctx.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
var imgURI = canvas
.toDataURL("image/png")
.replace("image/png", "image/octet-stream");
};
img.src = url;
});
Here is a render of the basic example, svg on the left and canvas on the right.
css styles applied to svg on left, css styles not applied to svg on canvas on right

Related

Drag an image and drop on top of a SVG element

I've created two circles using SVG and an image. I'm trying to drag the image into the circles and while I'm able to do so after dropping the image it is not being visible. How can I drop it on top of the circles.
<!DOCTYPE html>
<html>
<body>
<div id="circle" >
<svg id="dest" ondrop="drop(event)" ondragover="allowDrop(event)" width="250" height="100">
<circle id="yelcirc" cx="50" cy="50" r="50" fill="yellow" />
<circle id="greencirc" cx="160" cy="50" r="50" fill="green" />
</svg>
</div>
<img id="draglogo" src="logo.gif" draggable="true" ondragstart="drag(event)" class="draggable" ondragend="" width="105" height="73">
</body>
<script>
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}
</script>
</html>
Apparently the ondrop and ondragover events are not detected on your svg tag. On top of that, images in SVG don't have the same syntax than in regular HTML.
This is a simple example of how you can achieve the basics of what you want to do, of course there are some adjustments to do, the position of the image, its size etc. So basically what i do here is getting the original image attributes to create an SVG image. You could also have a regular image placed outside of the SVG tag, but i'm not sure it will be easier for positioning and such.
You can also read this answer about emulating the drag events on SVG elements
NOTE: this works only for the first drag, even if the image still looks draggable after being moved, the function will throw an error because of the way img is selected from the DOM, it has been removed, so the img tag is not found anymore.
<!DOCTYPE html>
<html>
<body>
<div id="circle" ondrop="drop(event)" ondragover="allowDrop(event)" >
<svg id="dest" width="250" height="100">
<circle id="yelcirc" cx="50" cy="50" r="50" fill="yellow" />
<circle id="greencirc" cx="160" cy="50" r="50" fill="green" />
</svg>
</div>
<img id="draglogo" src="https://placeimg.com/105/73/any" draggable="true" ondragstart="drag(event)" class="draggable" ondragend="" width="105" height="73">
</body>
<script>
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text"),
img = document.getElementById(data),
imgSrc = img.getAttribute('src'),
imgW = img.getAttribute('width'),
imgH = img.getAttribute('height'),
//for example you can calculate X position from event circle
imgX = ev.target.getAttribute('cx') - ev.target.getAttribute('r');
ev.target.parentElement.innerHTML += '<image xlink:href="' + imgSrc + '" x="' + imgX + '" y="0" width="' + imgW + 'px" height="' + imgH + 'px"/>';
img.parentNode.removeChild(img);
}
</script>
</html>

How to prevent preservation of aspect ratio in svg.js

I am trying to render a rectangle with svg.js (https://svgjs.dev) and NOT preserve the aspect ratio when the parent/window is resized. It works fine for a plain svg element but not for the svg.js elements:
https://jsfiddle.net/h8sgown7/3/
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.4/svg.min.js"></script>
<script type="text/javascript">
SVG.on(document, 'DOMContentLoaded', function() {
var draw = SVG('drawing')
var rect = draw.rect(300, 50).move(0, 0).fill('#ff0000');
draw.viewbox(0, 0, 300, 55);
draw.attr('preserveAspectRatio', 'none');
})
</script>
<title>SVGTest</title>
<style>
.drawing
{
width: 100%;
height:50px;
}
</style>
</head>
<body>
<div id="drawing"></div>
<svg width="100%" height="100px" viewbox="0 0 100 100" preserveAspectRatio="none">
<rect width="100" height="100" style="fill:rgb(0,0,255)" />
</svg>
</body>
</html>
You have set the height to 100px in your plain svg element. By default the svg is set to width="100%" height="100%" by svg.js.
Just change your svg.js generated svg height to match your inline svg.
draw.viewbox(0, 0, 300, 55).height('100px');
https://jsfiddle.net/h8sgown7/7/

Chrome Memory Leak with moving SVG text and blur filter

I have a page with several SVG elements and each of them has an SVG Blur filter applied to it. I noticed that Chrome was running out of memory quickly if the elements keep moving continuously.
To reproduce check this codepen: http://codepen.io/anon/pen/xZJMVz
<html>
<head>
<meta charset="UTF-8">
<style> body {padding: 0; margin: 0;} </style>
<svg height="0" width="0">
<defs>
<filter id="f1">
<feGaussianBlur in="SourceGraphic" stdDeviation="2" />
</filter>
</defs>
</svg>
</head>
<body>
<svg height="30" style="position: absolute; top: 100px; width: 1000px;height: 500px;">
<text x="0" y="15" fill="black" id="t0">BLUR TEST!</text>
</svg>
<script>
(function() {
var svgText = document.getElementById('t0');
svgText.setAttribute('filter', 'url(#f1)');
var x = 0;
var y = 0;
setInterval(function(){
x+=1;
y+=1;
if(x > 1000) {
x = 0;
}
if( y > 500) {
y = 0;
}
svgText.setAttribute('transform', 'translate(' + x + ',' + y + ')');
}, 100);
})();
</script>
</body>
</html>
Open Chrome's Task Manager and notice memory usage by that tab. I filed a bug report on Chromium's Issue tracker. But wondering if anybody has run into this before and if there's a work around to this.
Thanks!
edit: Noticing this issue on Chrome 48.0.2564.97 m on Windows 7.

i have Multiple svg elements when mouseover on 1 element all element must be show text hover at a same time

I have Multiple SVG elements when mouseover on 1 element all element must be show text hover at a same time..
How i can do this?
Here is my code...
<html>
<head>
<title>conservedClusters_FRAAL_16</title>
</head>
<body>
<svg width="1500" height="500" xmlns="http://www.w3.org/2000/svg" version="1.1">
<style>
.tooltip{
font-size: 16px;
font-family: Times New Roman;
}
.tooltip_bg{
fill: white;
stroke: black;
stroke-width: 1;
opacity: 0.9;
}
</style>
<script type="text/ecmascript">
<![CDATA[
function init(evt)
{
if ( window.svgDocument == null )
{
svgDocument = evt.target.ownerDocument;
}
tooltip = svgDocument.getElementById('tooltip');
tooltip_bg = svgDocument.getElementById('tooltip_bg');
}
function ShowTooltip(evt, mouseovertext, xpos, ypos)
{
tooltip.firstChild.data = mouseovertext;
length = tooltip.getComputedTextLength();
if (length + xpos > 1500)
{
xpos=1500-length-10;
}
tooltip.setAttributeNS(null,"x",xpos+3);
tooltip.setAttributeNS(null,"y",ypos+13);
tooltip.setAttributeNS(null,"visibility","visible");
length = tooltip.getComputedTextLength();
tooltip_bg.setAttributeNS(null,"width",length+8);
tooltip_bg.setAttributeNS(null,"x",xpos);
tooltip_bg.setAttributeNS(null,"y",ypos);
tooltip_bg.setAttributeNS(null,"visibility","visibile");
}
function HideTooltip(evt)
{
tooltip.setAttributeNS(null,"visibility","hidden");
tooltip_bg.setAttributeNS(null,"visibility","hidden");
}
function writeConsole(content,linkaddress,linktext,winTitle) {
top.consoleRef=window.open('','myconsole',
'',//'width=350,height=250'
+',menubar=0'
+',toolbar=1'
+',status=0'
+',scrollbars=1'
+',resizable=1')
top.consoleRef.document.writeln(
'<html><head><title>'+winTitle+'</title></head>'
+'<body bgcolor=white onLoad="self.focus()">'
+''+linktext+''+
'<p><font face="courier">'+content+'</font></p>'
+'</body></html>'
)
top.consoleRef.document.close()
}
function onGeneMouseOver(evt,strokecolor,colorval)
{
var gene = evt.target;
var parent = gene.parentNode;
var others = parent.getElementsByTagName('path');
for (var i=0,len=others.length;i<len;++i)
{
others[i].style.stroke=strokecolor;
others[i].style.fill=colorval;
//others[i].setAttribute("style", "stroke-linecap: square; stroke-linejoin: miter; fill:"+colorval+"; stroke:"+strokecolor+"; stroke-width:1");
}
}
]]>
</script>
<g class="all1303" onmouseover="onGeneMouseOver(evt,'red','pink')" onmouseout="onGeneMouseOver(evt,'black','#cf0f78')">
<path id="all" d=" M487 73L423 73L423 63L403 83L423 103L423 93L487 93 L487 73 " style="stroke-linecap: square; stroke-linejoin: miter; fill:#cf0f78; fill-opacity:1.00; stroke:black; stroke-width:1" onmousemove="ShowTooltip(evt, 'FraEuI1c_4753, 1.00, Beta-ketoacyl synthase', 492, 93)" onmouseout="HideTooltip(evt)" />
<path id="all" d=" M257 156L324 156L324 146L344 166L324 186L324 176L257 176 L257 156 " style="stroke-linecap: square; stroke-linejoin: miter; fill:#cf0f78; fill-opacity:1.00; stroke:black; stroke-width:1" onmousemove="ShowTooltip(evt, 'Franean1_2393, 1.00, Beta-ketoacyl synthase', 349, 176)" onmouseout="HideTooltip(evt)" />
</g>
<rect class="tooltip_bg" id="tooltip_bg"
x="0" y="0" rx="4" ry="4"
width="55" height="17" visibility="hidden"/>
<text class="tooltip" id="tooltip"
x="0" y="0" visibility="hidden">Tooltip</text>
</svg>
</body>
</html>

Creating image using html5

I wanted to know if it is possible to create an image using html5.
Currently i am creating a text using canvas, now i want to convert that text into an image.
In order to save the canvas to an image file, you can use Nihilogic's code.
Use the canvas text functions.
For example:
<html>
<head>
<title>Canvas tutorial</title>
<script type="text/javascript">
function draw(){
var canvas = document.getElementById('tutorial');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
ctx.fillText("Sample String", 10, 50);
}
}
</script>
<style type="text/css">
canvas { border: 1px solid black; }
</style>
</head>
<body onload="draw();">
<canvas id="tutorial" width="150" height="150"></canvas>
</body>
</html>
Create an image DOM element, and set the src to the canvas.toDataURL method.
var c = document.getElementById("c");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 50, 50);
function copy() {
var image = document.getElementById("Img");
image.src = c.toDataURL("image/png");
}
<canvas id="c" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<img id="Img" width="300" height="150" style="border:1px solid #d3d3d3;"/>
<button onclick="copy()">Copy</button>