to append an image i use this code
node.append("image")
.attr("xlink:href", function(d) { return d.img; })
.attr("x", -25)
.attr("y", -25)
.attr("width", 50)
.attr("height", 50)
i want the image to be round i have tried to use this code
.attr("style", "border-radius: 30px;");
but it didn't work.. i also tried this one
<style>
.node image{
border-color: 2px solid orange;
border-radius: 25px;
}
</style>
but to no avail.
.
You need to use patterns.
Create patterns containing the images you want to use in a <defs> tag.
Use a circle
Set circle fill to one of the patterns you created.
eg.:
var defs = svg.append("defs").attr("id", "imgdefs")
var catpattern = defs.append("pattern")
.attr("id", "catpattern")
.attr("height", 1)
.attr("width", 1)
.attr("x", "0")
.attr("y", "0")
Adding the image:
catpattern.append("image")
.attr("x", -130)
.attr("y", -220)
.attr("height", 640)
.attr("width", 480)
.attr("xlink:href", imgurl)
And then setting the fill:
svg.append("circle")
.attr("r", 100)
.attr("cy", 80)
.attr("cx", 120)
.attr("fill", "url(#catpattern)")
A JS Fiddle example: http://jsfiddle.net/wcnxywuy/1/
Related
I have code to make a circle and I'd like to place text on top of it.
I'm using this for my example: https://bl.ocks.org/mbostock/raw/7341714/
infoHeight = 200
infoWidth = 200
var compareSVG = d3.select(".info-container")
.append("svg")
.attr("class","comparison-svg")
.attr("width", infoWidth)
.attr("height", infoHeight);
var circle = compareSVG.append("g")
circle.append("circle")
.attr("r", circleRadius(d.properties.contextvalue))
.attr("cy", infoHeight/2)
.attr("cx", infoWidth/2)
.style("fill","grey")
.style("stroke","black")
.style("stroke-width","3px")
circle.append("text")
.text(d.properties.contextvalue)
.style("display", "block")
.style("y", infoHeight/2)
.style("x", infoHeight/2)
.style("color","red")
.style("font-size","20px")
The circle works, but the text won't appear on top of it. Instead, it is in the top left corner of the SVG element. I've tried position: absolute along with top and left and it stays in the same corner.
In D3, the attr methods uses Element.setAttribute internally, while style uses CSSStyleDeclaration.setProperty().
In an SVG <text> element, x and y are attributes. Therefore, change those style() methods for attr(). Also, get rid of that .style("display", "block").
So, it should be:
circle.append("text")
.text(d.properties.contextvalue)
.attr("y", infoHeight/2)
.attr("x", infoHeight/2)
.style("color","red")
.style("font-size","20px")
Here is your code with that change:
infoHeight = 200
infoWidth = 200
var compareSVG = d3.select("body")
.append("svg")
.attr("width", infoWidth)
.attr("height", infoHeight);
var circle = compareSVG.append("g")
circle.append("circle")
.attr("r", 50)
.attr("cy", infoHeight / 2)
.attr("cx", infoWidth / 2)
.style("fill", "lightgrey")
.style("stroke", "black")
.style("stroke-width", "3px")
circle.append("text")
.text("Foo Bar Baz")
.attr("y", infoHeight / 2)
.attr("x", infoHeight / 2)
.style("color", "red")
.style("font-size", "20px")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
Finally, pay attention to the position of the text: it's not entered (regarding the circle). If you want to center it, use text-anchor and dominant-baseline:
infoHeight = 200
infoWidth = 200
var compareSVG = d3.select("body")
.append("svg")
.attr("width", infoWidth)
.attr("height", infoHeight);
var circle = compareSVG.append("g")
circle.append("circle")
.attr("r", 50)
.attr("cy", infoHeight / 2)
.attr("cx", infoWidth / 2)
.style("fill", "lightgrey")
.style("stroke", "black")
.style("stroke-width", "3px")
circle.append("text")
.text("Foo Bar Baz")
.attr("y", infoHeight / 2)
.attr("x", infoHeight / 2)
.attr("text-anchor", "middle")
.attr("dominant-baseline", "central")
.style("color", "red")
.style("font-size", "20px")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
How could I scale a rectangle in svg to fit the text using d3.js.
When you run it for the first time the yellowgreen rect covers the text nicely, but if you will resize the screen the text size and position will be changed, while the rectangle stays the same.
Below is the code, here is the fiddle:
debugger;
var svg = d3.select("#drawRegion")
.append("svg")
.attr("width", "100%")
.attr("height", "100%");
svg.append("rect")
.attr("x", "0")
.attr("y", "0")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "yellow");
const rectAroundText = svg
.append("rect");
const textMiddleX = 50;
const textMiddleY = 50;
const testText = svg
.append("text");
testText
.attr("x", textMiddleX + "%")
.attr("y", textMiddleY + "50%")
.attr("text-anchor", "middle")
.attr("alignment-baseline", "central")
.attr("x", "50%")
.attr("y", "50%")
.attr("fill", "#000")
.classed("scalingText", true)
.text("svdfv");
const textBox = testText.node().getBBox();
rectAroundText
.attr("x", textBox.x)
.attr("y", textBox.y)
.attr("width", textBox.width)
.attr("height", textBox.height)
.attr("fill", "yellowgreen");
<div id="drawRegion">
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
I would like the rectangle to scale up and move along with the text. Is it possible?
I am using SVG to draw text and shapes in D3.js, and want to draw shapes inline with text and with similar dimensions to the text. The only way I can think of doing this is draw a rect around each tspan then draw the shape in relative position to the tspan rect. The result being:
This is a rectangle [] this is a circle ()
Where the brackets above represent the SVG shapes. Current code is below.
js:
function setupSVG(){
d3.select("div#chartId")
.append("div")
.classed("svg-container", true)
.append("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 200 200")
.attr("id", "svg_area_id")
}
function renderSVGText(){
var svgArea = d3.select("svg#svg_area_id");
svgArea.append("rect")
.attr("x", 100)
.attr("y", 0)
.attr("height", 10)
.attr("width", 10)
.attr("id", "shape");
var group = svgArea.append("g")
.attr("width", "100%")
.attr("height", "100%")
.style("stroke", "red") //I only want to draw rect stroke
.style("fill", "none");
var text = group.append("text")
.attr("y", "0")
.attr("font-size",52)
.attr("dy", "1em")
.style('fill', 'black')
var tspan1 = text.append('tspan')
tspan1.text("This is a square");
var tspan2 = text.append('tspan')
tspan2.text("and this is a triangle");
var boundingRect = group.append("rect")
//see http://phrogz.net/SVG/tspan_bounding_box.xhtml
var bbox = tspan1.getBoundingClientRect();
var pt = svg.createSVGPoint();
pt.x = bbox.left;
pt.y = bbox.top;
var pt2 = pt.matrixTransform(xform);
rect.setAttribute('x',pt2.x);
rect.setAttribute('y',pt2.y);
pt.x = bbox.right;
pt.y = bbox.bottom;
pt = pt.matrixTransform(xform);
boundingRect.attr('width', pt.x-pt2.x);
boundingRect.attr('height',pt.y-pt2.y);
/* this draws a rect around all text
var textSize = text.node().getBBox();
boundingRect.attr("width", textSize.width)
.attr("height", textSize.height);
*/
}
html:
<div class="svg-container" id="chartId"></div>
css:
.svg-container {
display: inline-block;
width: 512px;
height: 512px;
padding-top: 50px;
padding-bottom: 100%; /* aspect ratio */
vertical-align: top;
overflow: hidden;
border: 1px solid black;
}
Any ideas on how to do this? Any easier ways than the track I am following?
I tried to get tspan dimensions using tspan.node().getComputedTextLength() but this returned an error, I presume because it hadn't been rendered at the call time. I just used text.node().getBBox() to get each text blocks dimensions instead:
function renderSVGText(){
var svgArea = d3.select("svg#svg_area_id");
var group = svgArea.append("g")
.attr("width", "100%")
.attr("height", "100%")
.style("stroke", "red")
.style("fill", "none");
var text = group.append("text")
.attr("y", "0")
.attr("font-size",52)
.attr("dy", "1em")
.attr("id", "text_id")
.style('fill', 'black');
var tspan1 = text.append('tspan')
.attr("id", "tspan1_id")
tspan1.text("This is a square");
var boundingRect = svgArea.append("rect")
.style("stroke", "pink")
.style("fill", "none");
var textSize = text.node().getBBox();
boundingRect.attr("width", textSize.width)
.attr("height", textSize.height);
svgArea.append("rect")
.attr("x", textSize.width+10)
.attr("y", 0)
.attr("height", textSize.height)
.attr("width", textSize.height)
.attr("id", "shape");
var text2 = group.append("text")
.attr("x", textSize.width+textSize.height+20)
.attr("y", "0")
.attr("font-size",52)
.attr("dy", "1em")
.attr("id", "text2_id")
.style('fill', 'black');
var tspan2 = text2.append('tspan')
tspan2.text("and this is a triangle");
}
I am trying to render gantt chart using d3.js and svg.
The chart has two part, one (the mini chart) display the complete gantt chart.
Other (the main chart) display only partial of the chart.
I have a view window in in the mini chart which I can drag over the mini chart.
Now the main chart is supposed to render only the portion inside the view widow (main chart works as a zoomed version of the mini chart).
Now I need to render the data in the main chart which is bordered by a "rect".
How can I crop the elements that goes outside that main chart area?
Adding another svg as the inside the main svg could be a solution. Is there any other way to do it?
Thanks.
You can use clipPath.
Sample Code
svg.append("clipPath") // define a clip path
.attr("id", "rect-clip") // give the clipPath an ID
.append("rect") //Append the shape for clipping
.attr("x", 20)
.attr("y", 20)
.attr("width", 420)
.attr("height", 260)
.attr("fill", "#ccffff");
var chartElem1 = svg.append("circle")
.attr("cx", 50)
.attr("cy", 80)
.attr("r", 40)
.attr("fill", "#ffccff")
.attr("fill-opacity", 0.6)
.attr("clip-path", "url(#rect-clip)"); //Set clip-path using id
var dataset = {
apples: [53245, 28479, 19697, 24037, 40245],
};
var width = 460,
height = 300;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.style("background-color", "grey");
svg.append("clipPath") // define a clip path
.attr("id", "rect-clip") // give the clipPath an ID
.append("rect") //Append the shape for clipping
.attr("x", 20)
.attr("y", 20)
.attr("width", 420)
.attr("height", 260)
.attr("fill", "#ccffff");
var chartContainer = svg.append("rect")
.attr("x", 20)
.attr("y", 20)
.attr("width", 420)
.attr("height", 260)
.attr("fill", "#ccffff");
var chartElem1 = svg.append("circle")
.attr("cx", 50)
.attr("cy", 80)
.attr("r", 40)
.attr("fill", "#ffccff")
.attr("fill-opacity", 0.6)
.attr("clip-path", "url(#rect-clip)");
var chartElem2 = svg.append("rect")
.attr("x", 10)
.attr("y", 200)
.attr("width", 100)
.attr("height", 20)
.attr("fill", "#ffccff")
.attr("clip-path", "url(#rect-clip)");
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
position: relative;
width: 960px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
It appears I've followed the steps properly to fill a circle with an external image. I've tried numerous different image links, yet still can't resolve this pixelation issue. Any help is appreciated, here's a link to my fiddle:
http://jsfiddle.net/SdN2F/7/
Code issue snipet:
var photoCircle = d3.select('svg')
.append("circle")
.attr("cx", width-160)
.attr("cy", height-140)
.attr("r", radius-35)
.style("fill", "url(#photo)");
var image = d3.select('svg')
.append("pattern")
.attr("id", "photo")
.attr("x", 0)
.attr("y", 0)
.attr("width", width-160)
.attr("height", height-140)
.append("image")
.attr("x", 0)
.attr("y", 0)
.attr("width", width-160)
.attr("height", height-140)
.attr("xlink:href", "http://static-1.nexusmods.com/15/mods/110/images/50622-1-1391287636.jpeg");
You need to set the patternUnits attribute of pattern.
var image = d3.select('svg').append('defs')
.append("pattern")
.attr("id", "photo")
.attr("patternUnits","userSpaceOnUse")
.attr("x", 0)
.attr("y", 0)
.attr("width", 2*radius)
.attr("height", 2*radius)
.append("image")
.attr("x", 0)
.attr("y", 0)
.attr("width", 2*radius)
.attr("height", 2*radius)
.attr("xlink:href", "http://static-1.nexusmods.com/15/mods/110/images/50622-1-1391287636.jpeg");
jsFiddle: http://jsfiddle.net/chrisJamesC/SdN2F/11/