I am trying to add current time to an SVG file using ECMAScript.
Following is the code I have. Unfortunately it's not working. How do I fix it?
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="300">
<text x="0" y="15" fill="red">It is now
<script type="text/javascript">
<![CDATA[
var currentTime = new Date();
var month = currentTime.getMonth() + 1;
var day = currentTime.getDate();
var year = currentTime.getFullYear();
document.write(month + "/" + day + "/" + year);
]]>
</script>
</text>
</svg>
Demo: http://jsfiddle.net/M8YXS/
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300">
<text x="0" y="15" fill="red">It is now <tspan id="now">(time)</tspan></text>
<!--
This script block must either be after the element in the source code
or else the code below must be wrapped in a callback that is invoked
only after the DOM is created (e.g. window.onload in a browser)
-->
<script>
// Create whatever string you want
var dateString = (new Date).toDateString();
// Set the string content of the Text Node child of the <tspan>
document.getElementById('now').firstChild.nodeValue = dateString;
</script>
</svg>
Related
I am trying to get an element in an SVG file using XPath. I have tried the following code, but singleNodeValue is null. The doc seems to be correct, so I guess either evaluate() arguments or the XPath is wrong, but I cannot find anything wrong. Why doesn't it work?
JavaScript
fetch('test.svg')
.then(response => response.text())
.then(data=>{
const parser = new DOMParser();
const doc = parser.parseFromString(data, "text/xml");
console.log(doc);
const res = doc.evaluate("//symbol[#label='square']", doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
console.log(res.singleNodeValue);
})
SVG
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<symbol label ="square">
<rect y="5" x="5" width="90" height="90" stroke-width="5" stroke="#f00" fill="#f00" fill-opacity="0.5" />
</symbol>
</svg>
After some testing, I have discovered that it works if I remove xmlns="http://www.w3.org/2000/svg". I searched the web and found an answer: Why XPath does not work with xmlns attribute
var data = '<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><symbol label ="square"><rect y="5" x="5" width="90" height="90" stroke-width="5" stroke="#f00" fill="#f00" fill-opacity="0.5" /></symbol></svg>';
const parser = new DOMParser();
const doc = parser.parseFromString(data, "text/xml");
const res = doc.querySelector("symbol[label=square]");
console.log(res);
You can make use of a namespace resolver in XPath 1 and with the evaluate function and even of an XPath default namespace in XPath 2 and later such as supported by Saxon-JS 2:
const svgString = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"
xmlns:dog = "http://dog.com/dog">
<symbol dog:label="square">
<rect y="5" x="5" width="90" height="90" stroke-width="5" stroke="#f00" fill="#f00" fill-opacity="0.5" />
</symbol>
<symbol dog:label="cat">
<rect y="5" x="5" width="90" height="90" stroke-width="5" stroke="#f00" fill="#f00" fill-opacity="0.5" />
</symbol>
</svg>`;
const doc = new DOMParser().parseFromString(svgString, 'application/xml');
const result = doc.evaluate(`//svg:symbol[#dog:label='cat']`, doc, function(prefix) { if (prefix === 'svg') return 'http://www.w3.org/2000/svg'; else if (prefix === 'dog') return 'http://dog.com/dog'; else return null; }, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
console.log(result.singleNodeValue);
const result2 = SaxonJS.XPath.evaluate(`//symbol[#dog:label = 'cat']`, doc, { xpathDefaultNamespace : 'http://www.w3.org/2000/svg', namespaceContext : { 'dog' : 'http://dog.com/dog' } });
console.log(result2);
<script src="https://www.saxonica.com/saxon-js/documentation/SaxonJS/SaxonJS2.rt.js"></script>
This question already has answers here:
jquery's append not working with svg element?
(17 answers)
Closed 2 years ago.
I'm trying to use JQuery to create an SVG element. The contents of the SVG is generated from a list of strings which is where I'm having my issues.
I'm populating a variable called 'arr' by looping through several hundred items in my database and creating an svg rect shaped based on that data which then gets appended to 'arr'. How can i append this list of string elements to my main SVG element in order to properly display it?
The main points here are:
Arr is populated with a list of strings, each one representing a shape to go inside the svg
The final Arr will be several hundreds strings
var mapSvg = $.parseHTML('<svg id="tile-map-svg" width="100%" height="300"></svg>');
arr = [
'<rect height="50" width="50" fill="blue"/>',
'<rect height="20" width="20" fill="green"/>'
]
mapSvg[0].append(arr);
$('#tile-map').append(mapSvg);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<div style="background:lightblue; padding:10px;">
<div id="tile-map">
</div>
<svg id='tile-map-svg' width="100" height="100">
<rect height="25" width="25" fill="red" class="tile"/>
</svg>
</div>
I also tried this and it didn't work either...
var mapSvg = $.parseHTML('<svg id="tile-map-svg" width="100%" height="600"></svg>');
arr = [
'<rect height="50" width="50" fill="blue"/>',
'<rect height="20" width="20" fill="green"/>'
]
for (var i = 0; i < arr.length; i++) {
var el = $.parseHTML(arr[i])[0];
mapSvg[0].append(el);
}
$('#tile-map').append(mapSvg);
How about looping over all the elements in arr before parsing the html:
let html = '<svg id="tile-map-svg" width="100%" height="300">';
arr.forEach(shape => {
html += shape;
});
html += "</svg>";
const mapSvg = $.parseHTML(html);
$("#tile-map").append(mapSvg);
Or simply copy HTML without jQ for example:
var mapSvg = document.getElementById("tile-map");
var arr = [
'<rect height="50" width="50" fill="blue"/>',
'<rect height="20" width="20" fill="green"/>'
]
var s = "<svg id='tile-map-svg' width=100 height=100>"+
arr.join('\n')+
"</svg>";
mapSvg.innerHTML = s;
mapSvg.innerHTML += s;
mapSvg.parentElement.innerHTML += mapSvg.outerHTML.replace(/</g,'<').replace(/>/g,'>');
<div style="background:lightblue; padding:10px;">
<div id="tile-map">
</div>
</div>
I need to convert a svg into a png. I tried using this code
<!DOCTYPE html>
<meta charset="utf-8">
<style>
path {
stroke: #000;
fill-opacity: .8;
}
</style>
<body>
<div id="svg">
<?php include 'small.svg'; ?>
</div>
<button id="save">Save as Image</button>
<h2>SVG dataurl:</h2>
<div id="svgdataurl"></div>
<h2>SVG converted to PNG dataurl via HTML5 CANVAS:</h2>
<div id="pngdataurl"></div>
<canvas width="960" height="500" style="display:none"></canvas>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var svg = document.querySelector( "svg" );
var svgData = new XMLSerializer().serializeToString( svg );
var canvas = document.createElement( "canvas" );
var ctx = canvas.getContext( "2d" );
var img = document.createElement( "img" );
img.setAttribute( "src", "data:image/svg+xml;base64," + btoa( svgData ) );
img.onload = function() {
ctx.drawImage( img, 0, 0 );
// Now is done
console.log( canvas.toDataURL( "image/png" ) );
};
document.getElementById("pngdataurl").appendChild(img);
</script>
but it doenst work. im pretty sure it's because im using an image pattern, rect and a clip path to product my SVG. I say that because i tried this code with just the path object and it worked fine. I also tried using image magic with this code
<?php
error_reporting(E_ALL);
$svg ="small.svg";
$mask = new Imagick('mask.png');
$im = new Imagick();
//$im->setBackgroundColor(new ImagickPixel('transparent'));
$im->readImageBlob($svg);
$im->setImageFormat("png32");
$im->compositeImage( $mask, imagick::COMPOSITE_DEFAULT, 0, 0 );
header('Content-type: image/png');
echo $im;
?>
Fatal error: Uncaught exception 'ImagickException' with message 'no decode delegate for this image format `' # error/blob.c/BlobToImage/346' in /home/[path to file]:10 Stack trace: #0 /home/path to file: Imagick->readimageblob('small.svg') #1 {main} thrown in /home/[path to file] on line 10
i would rather do this with js if possible. please help...my boss really hates me right now. Here is my svg
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 3384.2 2608.6" enable-background="new 0 0 3384.2 2608.6" xml:space="preserve">
<defs>
<pattern id="img1" patternUnits="userSpaceOnUse" width="100%" height="100%">
<image xlink:href="https://upload.wikimedia.org/wikipedia/commons/7/71/Weaved_truncated_square_tiling.png" x="0" y="0" width="100%" height="100%" />
</pattern>
</defs>
<rect width="3384.2" height="2608.6" clip-path="url(#shirt)" fill="url(#img1)" />
<clipPath id="shirt">
<path fill-rule="evenodd" clip-rule="evenodd" fill="url(#img1)" d="[coordinates that are too long for this post ]"/>
</clipPath>
</svg>
I had this issue recently too, at least with the pattern fills - it seems to be an issue with remote images, so if you base64 encode them into a data URL, it works fine:
var img = new Image();
img.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
canvas.getContext('2d').drawImage(img, 0, 0);
var patternImage = document.createElementNS('http://www.w3.org/2000/svg', 'image');
patternImage.setAttributeNS('http://www.w3.org/1999/xlink', 'href', canvas.toDataURL());
};
img.src = patternImageUrl;
You can then add/update this image in a pattern def (or do this once and hardcode the result of canvas.toDataURL() into the pattern image href).
I'm just curious - is it possible to send by SVG image code in the following way?
<original div with inline SVG> -> Input field -> <final DIV>
I want to use following code:
Copy-1
<div id="source-1">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="10" y="10" height="100" width="100"
style="stroke:#ff0000; fill: #0000ff"/>
</svg>
</div>
<input name="dynamichidden-637" value="" id="pole" />
<br />
Copy-2
<div id="source-2"></div>
and Jquery:
jQuery( document ).ready(function( $ ) {
$('#copy-1').click(function() {
var value = $('#source-1').html();
var input = $('#pole');
input.val('')
input.val(input.val() + value);
return false;
});
$('#copy-2').click(function() {
$('#pole').appendTo('#source-2');
return false;
});
});
So my question is - is it possible to achieve it in that way? or using somehow other solution which will allow me to transfer svg code from one page to another without storing the data in Database? This is JSfiddle:
http://jsfiddle.net/v2br8/16/
You just need to create the copy using the value of the input:
var value = $('#pole').val();
var copy = $(value);
copy.appendTo('#source-2');
or simply:
$($('#pole').val()).appendTo('#source-2');
DEMO
Try: source-2.innerHTML=source_1.innerHTML
I have a php-file that sends an SVG header and draws itself partly with JavaScript. Everything works fine when I show the SVG directly in the browser. However, when I embed it in an <img>, then the JavaScript seems not to be executed. Maybe I am doing something wrong?
Here is the php-file (testsvg.php):
<?php
header('Content-type: image/svg+xml');
?>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="800"
height="600"
id="example_text">
<g id="layer1">
<text
x="100"
y="100"
id="text_holder">
<?php echo filter_input(INPUT_GET, 'text'); ?>
</text>
</g>
<script type="text/javascript">
function create_from_rect (client_rect, offset_px) {
if (! offset_px) {
offset_px=0;
}
var box = document.createElementNS(
document.rootElement.namespaceURI,
'rect'
);
if (client_rect) {
box.setAttribute('x', client_rect.left - offset_px);
box.setAttribute('y', client_rect.top - offset_px);
box.setAttribute('width', client_rect.width + offset_px * 2);
box.setAttribute('height', client_rect.height + offset_px * 2);
}
return box;
}
function add_bounding_box (text_id, padding) {
var text_elem = document.getElementById(text_id);
if (text_elem) {
var f = text_elem.getClientRects();
if (f) {
var bbox = create_from_rect(f[0], padding);
bbox.setAttribute(
'style',
'fill: none;'+
'stroke: black;'+
'stroke-width: 0.5px;'
);
text_elem.parentNode.appendChild(bbox);
}
}
}
add_bounding_box('text_holder', 10);
</script>
</svg>
(The SVG/JavaScript is mostly taken from How can I draw a box around text with SVG?.)
When I open this file directly in the browser, e.g. with http://localhost/testsvg.php?text=Test it draws a proper box around the text Test.
However, when I embed it with an <img>, e.g. with <img src="testsvg.php?text=Test" alt="">, it does not show the box.
To protect user's privacy, script is not run in images. There are other restrictions.
When thinking of an image it helps to have the mental model "could I do this if I used a raster image"? If you bear that in mind you won't go far wrong as that's basically the model the browsers implement.
Your alternatives are to use <object> or <iframe> tags instead of <img> as they do allow scripting.