In a browser window I have an svg containing an image. I also put some circles in this page. When I resize the window, the image resizes correct but the circles just stay on their absolute position.
What is the best way to set this up? If possible, the circles should not resize but change their position.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex, nofollow">
<meta name="googlebot" content="noindex, nofollow">
<style>
html,body{padding:0px; margin:0px; height:100%; width:100%;}
</style>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<title>Test</title>
<script type='text/javascript'>//<![CDATA[
window.onload=function()
{
function click()
{
// Ignore the click event if it was suppressed
if (d3.event.defaultPrevented) return;
// Extract the click location
var point = d3.mouse(this)
, p = {x: point[0], y: point[1] };
//Append the group
var newGroup = d3.select("svg").append("g")
.attr("transform", "translate(" + p.x + "," + p.y + ")")
.attr("drgg", "")
.style("cursor", "pointer")
.on("mouseup", selremove)
.call(drag);
//Append the circle
var newCircle = newGroup.append("circle")
.attr("r", "25")
.attr("class", "dot")
.style("stroke", "#999999")
.style("fill", "#66B132")
.attr("opacity", 0.8);
//Append the text
var newText = newGroup.append("text")
.text("43")
.style("fill", "#FFFFFF")
.style("font-family", "Arial")
.style("font-size", "24px")
.style("text-anchor", "middle")
.style("alignment-baseline", "central")
.style("readonly", "true");
}
//Create the SVG
var svg = d3.select("body").append("svg")
.attr("width", "100%")
.attr("height", "100%")
.on("click", click);
//Add a background to the SVG
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.style("stroke", "#999999")
.style("fill", "#F6F6F6")
//Add a Background-Picture
var pPic = d3.select("body").select("svg").append("image")
.attr("opacity", 1.0)
.attr("width", "100%")
.attr("height", "100%")
.attr("preserveAspectRatio", "xMidyMid")
.attr("xlink:href", "https://m.bmw.de/content/dam/bmw/common/all-models/m-series/x6m/2014/model-card/X6-M-F86_ModelCard.png")
//Move or delete
function selremove() {
if (d3.select(this).attr("drgg") == "")
{
d3.select(this).remove();
}
else
{
d3.select(this).attr("drgg", "");
}
}
function showinfo() {
//d3.select(this).attr("fill", "#000000");
var point = d3.mouse(this)
, p = {x: point[0], y: point[1] };
var newRect = svg.append("rectangle")
.attr("transform", "translate(" + p.x + "," + p.y + ")")
.attr("width", "25")
.attr("height", "25")
.style("stroke", "#999999")
.style("fill", "#FFFA83")
.attr("opacity", 1.0);
}
// Define drag beavior
var drag = d3.behavior.drag()
.on("drag", dragmove);
function dragmove()
{
var x = d3.event.x;
var y = d3.event.y;
d3.select(this)
.attr("transform", "translate(" + x + "," + y + ")")
.attr("drgg", "1");
}
}//]]>
</script>
</head>
<body>
<script>
// tell the embed parent frame the height of the content
if (window.parent && window.parent.parent){
window.parent.parent.postMessage(["resultsFrame", {
height: document.body.getBoundingClientRect().height,
slug: "None"
}], "*")
}
</script>
</body>
</html>
I first thought this could be achieved with relative units, but the changing aspect ratio of the SVG gets you into hot waters. So the best approach seems to come with clamping the SVG viewBox to the original image dimensions. These need to be known beforehand, as SVGImageElement is not able to extract them from the image source itself.
The price to pay for this is that the overlay circles have to be resized every time the window is resized.
This example does not concern itself with the drag functionality.
//an event counter
var counter = 0;
//image metadata
var pData = {
url: "https://m.bmw.de/content/dam/bmw/common/all-models/m-series/x6m/2014/model-card/X6-M-F86_ModelCard.png",
width: 890,
height: 501
}
//Create the SVG with viewBox at native image size
var svg = d3.select("body").append("svg")
.attr("xmlns:xlink", "http://www.w3.org/1999/xlink")
.attr("width", "100%")
.attr("height", "100%")
.attr('viewBox', "0 0 " + pData.width + " " + pData. height)
.attr("preserveAspectRatio", "xMidyMid")
.on("click", click);
var defs = svg.append("defs");
//Add a Background-Picture
var pPic = d3.select("body").select("svg").append("image")
.attr("width", "100%")
.attr("height", "100%")
.attr("xlink:href", pData.url)
function click() {
// Ignore the click event if it was suppressed
if (d3.event.defaultPrevented) return;
// Extract the click location relative to SVG
var point = d3.mouse(this);
// get SVG scaling
var ctm = svg.node().getScreenCTM(),
scale = "scale(" + (1 / ctm.a) + "," + (1 / ctm.d) + ")";
// Unique id
var id = "dot" + counter++;
//Append the group offscreen
var newGroup = defs.append("g")
.attr("id", id)
.attr("transform", scale);
//Append the circle
var newCircle = newGroup.append("circle")
.attr("r", "25")
.attr("class", "dot")
.style("stroke", "#999999")
.style("fill", "#66B132")
.attr("opacity", 0.8);
//Append the text
var newText = newGroup.append("text")
.text("43")
.style("fill", "#FFFFFF")
.style("font-family", "Arial")
.style("font-size", "24px")
.style("text-anchor", "middle")
.style("alignment-baseline", "central")
.style("readonly", "true");
// indirect rendering with a new viewport
svg.append("use")
.attr("xlink:href", "#" + id)
.attr("x", point[0])
.attr("y", point[1]);
}
// adjust group sizes on window resize
var resize;
window.addEventListener("resize", function() {
clearTimeout(resize);
resize = setTimeout(function () {
var ctm = svg.node().getScreenCTM();
// select all groups before they are repositioned
defs.selectAll('g').attr("transform", "scale(" + (1 / ctm.a) + "," + (1 / ctm.d) + ")");
}, 100);
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.