My index.html is
<object id="embed" data="test.html" width="500" height="500"
type="text/xml"></object>
<script>
var test = document.getElementById("test");
var embed = document.getElementById("embed");
test.style.fill = "purple";
</script>
My test.html is
<style>
#test {
cx: 80%;
fill: green;
}
</style>
<svg width="500" height="500">
<circle id="test" cx="50%" cy="50%" r="40%"
stroke="black" stroke-width="1" fill="red" />
</svg>
I would like to apply css from the parent document to the loaded svg. I would also like to manipulate the svg using javascript in the parent document. The css works. JavaScript also works. They both modify position and fill, but they only work from the test.html document.
How do I manipulate and style embedded SVGs? I have a folder full of them and they can be mixed and relabeled, which is necessary for my larger project. I got a David Lynch plot sized headache reading up on the trainwreck of html imports and am avoiding them for now.
Prefer no jQuery.
Related
I am trying to use d3.zoom on an inline svg, specifically a map of the USA (please note that I am very inexperienced at d3js). After some research I found a simple tutorial for using d3.zoom https://www.datamake.io/blog/d3-zoom/.
The issue I have now is that it just doesn't work. There is no error which shows up. It just does nothing.
Here is the HTML code with the svg map.
<div id="map">
<?xml version="1.0" encoding="UTF-8"?>
<svg id="usa_svg" height="800" width="1200" version="1.1" viewBox="0 0 800 600" xmlns="http://www.w3.org/2000/svg">
<g id="USA">
<rect height="600" width="1200"></rect>
<!-- paths here -->
</g>
</svg>
</div>
Here is the JavaScript
var usa = d3.select("svg")
var rect = d3.select("rect");
var zoom = d3.zoom().on("zoom", zoomed);
rect.call(zoom);
function zoomed() {
var transform = d3.event.transform;
usa.attr("transform", transform.toString());
}
I have no clue what I am doing wrong. Is it a syntax error? Am I just missing a vital part of the code? Help would be much appreciated.
If I am embedding an SVG using an <object> tag, is it possible to use normal DOM methods to access the children elements?
Example
First a simple SVG:
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg"
viewBox="0,0 100, 100">
<defs>
<style>
#cls-1 {
fill: none;
stroke: #000;
stroke-width: 4;
}
</style>
</defs>
<title>Circles</title>
<g id="cls-1">
<circle cx="30" cy="30" r="10" />
<circle cx="60" cy="60" r="10" />
</g>
</svg>
Then an HTML file that embeds the SVG using and tries to access the group defined in the SVG within a script:
<html>
<body>
<object
type="image/svg+xml"
height="200px"
data="mysvg.svg"
></object>
<button onclick="myAnimate()" />
<script>
const myAnimate = () => {
const group = document.getElementById("cls-1");
};
</script>
</body>
</html>
Wy doesn't this work?
I see in the devtools that the first child of this is #document. So it seems to have it's own DOM, I think I read this, but still have not wrapped my head around how it works.
Is there a way to access the element with id "cls-1" from JS?
EDIT: one way to make this work is to add the script within the svg itself; the DOM methods work normally for the DOM in the SVG
Is getSVGDocument broken? Obsolete?
Because when I "run" the following:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>SVG Embedded - Chapter 07</title>
<link rel="stylesheet" href="../bootstrap/css/bootstrap.css">
<link rel="stylesheet" href="../assets/style.css">
<style>
body { margin: 1em; }
svg { border: 1px solid silver; }
rect, text { fill: white; }
circle { fill: black; }
</style>
</head>
<body>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" height="200" width="300">
<rect width="100%" height="100%" fill="black" />
<circle cx="150" cy="100" r="80" fill="white" />
<text x="150" y="125" font-size="60" text-anchor="middle">SVG</text>
</svg>
<embed src="../assets/svg.svg"></embed>
<object data="../assets/svg.svg"></object>
<script>
document.addEventListener('DOMContentLoaded',function() {
'use strict';
var rects = document.querySelectorAll('svg'),
embed = document.querySelector('embed').getSVGDocument();
console.log(rects.length);
console.log(embed,embed.childNodes.length);
},false);
</script>
</body>
</html>
then wait for all the 3 SVG to be (loaded and) displayed, and input inside the console: document.getElementsByTagName('embed')[0].getSVGDocument() it returns null
Full page (with files) can be downloaded there:
https://github.com/stopsatgreen/modernwebbook/blob/master/Code%20Examples/Chapter%2007/svg-embedded.html
Note: I'll try to have the page running in JS Bin.
EDIT:
Could the problem be this? SVG not working when access on localhost. Why?
If so, how to fix it without configuring a (local) webserver?
The getSVGDocument() method is deprecated. The recommended way is to use the contentDocument attribute instead.
See here
Found how to work around this, it's a security related issue.
Chrome
Close all running chrome instances first. Then start Chrome executable with a command line flag:
chrome --allow-file-access-from-files
On Windows, the easiest is probably to create a special shortcut which has added flag (right-click on shortcut -> properties -> target).
Firefox
Go to about:config
Find security.fileuri.strict_origin_policy parameter
Set it to false
Got it there: https://github.com/mrdoob/three.js/wiki/How-to-run-things-locally
It seems like a contrived problem but I am trying to make a proof of concept of an HTML 5 document, containing inline SVG, which itself contains a <foreignObject> element with an HTML canvas inside. I then want to call a JavaScript function to draw on the canvas.
(How I got here: I want to use SVG as a format for defining an animated graphical view which can contain graphs, which are animated by replacing a dummy element in the SVG with a live graph using JavaScript / ECMAScript, and one of the JavaScript libraries we are considering to generate the graphs (Flot) uses an HTML canvas for the view, so I want to inject this canvas into the SVG view. A further complication is we ideally want this system to run on local files, on the file:// protocol, meaning we can't run scripts on external files (e.g. referenced with <object> or <iframe>) because browsers block them, hence the inline SVG.)
Here is an HTML source illustrating the problem:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Canvas Test</title>
<script type="text/javascript">
function draw_box() {
var canvas = document.getElementById("box_canvas");
var context = canvas.getContext("2d");
context.fillRect(50, 20, 50, 60);
}
</script>
</head>
<body>
<h1>Canvas Test
<p>
<svg width="400" viewBox="-10 -10 268 108">
<rect style="fill: #a0a0a0" x="8" y="8" width="240" height="80" rx="40" ry="40"/>
<g>
<rect style="fill: #0000ff" x="0" y="0" width="240" height="80" rx="40" ry="40"/>
<rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke-linejoin: round; stroke: #000000" x="0" y="0" width="240" height="80" rx="40" ry="40"/>
<foreignObject x="120" y="25" width="150" height="100">
<canvas id="box_canvas" width="150" height="100" style="border:1px dotted;float:left">Canvas alt text</canvas>
</foreignObject>
</g>
</svg>
<p>
<button type="button" onclick="draw_box();return false">Animate</button>
</body>
</html>
The above page doesn't display the canvas at all in IE 11. In the latest version of Chrome it displays the canvas, but the effects of the JavaScript function called by the button - drawing the black box - only show up if you click on the SVG image.
What I need to know:
1) Is there something wrong with what I've written - e.g. am I missing some function call to make the SVG or foreignObject update after I have drawn on the canvas?
2) Is this a lost cause? Is the specification of <foreignObject> etc. immature enough that I could never be confident that this will work, even if we can control what browser the user views the document in? It's actually fine if this is the case because we can just say going forward that we need our graph library to generate SVG and not HTML.
Thanks a lot
I'm trying to make a very simple modification of a circle SVG. The script code should change the radius of the circle, but nothing seems to happen. (using the same format, I am able to change the color but none of the other elements of the circle).
<!DOCTYPE html>
<html>
<body>
<svg xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="red" id="cir"/>
</svg>
<script>
document.getElementById("cir").r = 2000;
</script>
</body>
</html>
"r" is no property of the element, it's an attribute. Use this:
document.getElementById("cir").setAttribute("r", 2000);