How to make svg symbols dropshadow - d3.js

I tried to append filter to a path using svg.symbols but it is not appeared.
This is my code
let namngu = d3.select("body")
.append("svg")
.attr("width", "5000")
.attr("height", "5000");
let namnguvcl = namngu.append("defs")
let filter = namnguvcl.append("filters")
.attr("id", "drop-shadow-line");
filter.append("feGaussianBlur")
.attr("in","SourceAlpha")
.attr("stdDeviation",4)
let namnhuconbo = filter.append("feMerge")
namnhuconbo.append("feMergeNode")
namnhuconbo.append("feMergeNode")
.attr("in","SourceGraphic")
let namngunhucho = namnguvcl.append("symbol")
.attr("id","may")
.attr("preserveAspectRatio", "none")
.attr("viewBox", "0 0 17275 8599")
namngunhucho.append("svg:path")
.attr("d", "M 5097.99967 2512.5 q 67 -30 134 0")
.attr("style", "fill: transparent; stroke: blue")
namngu.append("use")
.style("filter", "url(#drop-shadow-line)")
.attr("xlink:href","#may")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
https://jsfiddle.net/pn9ta08w/
This is what I am trying to replicate https://jsfiddle.net/fonwrspj/3/
How can I fix this, Thanks

Errors in the resulting SVG code:
In your code you have <filters> instead of <filter>
The symbol has a viewBox but the use element has no width and height
The svg element is huge and has no viewBox attribute
The viewBox attribute of the symbol is enormous compares with the bounding box of the shape.
After correcting all this the filter gets applied.
svg{border:solid}
<svg viewBox="0 0 150 75">
<defs>
<filter id="drop-shadow-line" y="-1" height="20">
<feGaussianBlur in="SourceAlpha" stdDeviation="4"></feGaussianBlur>
<feMerge>
<feMergeNode></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<symbol id="may" preserveAspectRatio="none" viewBox="5090 2490 150 50">
<path d="M 5097.99967 2512.5 q 67 -30 134 0" style="fill:transparent; stroke: blue"></path>
</symbol>
</defs>
<use xlink:href="#may" width="150" height="150" style="filter: url('#drop-shadow-line')" />
</svg>

Related

How to create vertical continuous legend without rotating the legend

I have created the horizontal continous legend using linear gradient. But my legend can be either horizonatl or vertical based on the flag. How can i make same legend vertical but i do not want to rotate it as it takes too much space.
const svgLegend = select(divRef.current).append("svg")
const defs = svgLegend.append("defs")
const linearGradient = defs
.append("linearGradient")
.attr("id", "linear-gradient")
.attr("x1", "0%")
.attr("x2", "100%") //since it's a horizontal linear gradient
.attr("y2", "0%");
// other code to add color
svgLegend
.append("rect")
.attr("x", 25)
.attr("y", 30)
.attr("width", 250)
.attr("height", 25)
.style("fill", "url(#linear-gradient)");
const xLeg = scaleLinear().domain([min, max]).range([10, 258]);
const axisLeg = axisBottom(xLeg).tickValues(colorScale.domain());
svgLegend
.attr("class", "axis")
.append("g")
.attr("transform", "translate(15, 55)")
.style("font-size", "10px")
.style("font-weight", "700")
.call(axisLeg);
Fiddle link : https://jsfiddle.net/r1t60ges/3/
Desired Output :
<div id="container">
<svg class="axis" style="background-color: rgba(255, 255, 255, 0.8); border-radius: 5px;">
<defs>
<linearGradient id="linear-gradient" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#ff0000"></stop>
<stop offset="25%" stop-color="#ffff00"></stop><stop offset="50%" stop-color="#00ff00"></stop>
<stop offset="75%" stop-color="#00ffff"></stop><stop offset="100%" stop-color="#0000ff"></stop>
</linearGradient></defs>
<text class="legendTitle" x="25" y="10">Legend</text>
<rect x="25" y="20" width="25" height="150" style="fill: url("#linear-gradient");"></rect>
<g transform="translate(15, 55)" fill="none" font-size="10" font-family="sans-serif" text-anchor="middle" style="font-size: 10px; font-weight: 700;">
</svg>
</div>

How to group g elements in D3?

Say for example I have a g element that contains a rect and text :
var cells = innercanvas
.selectAll(".newcell")
.data(treemap)
.enter()
.append("g")
.attr("class", "newcell");
cells
.append("rect")
.attr("x", function (d) {
return d.x;
})
.attr("y", function (d) {
return d.y;
})
.attr("id", "rectangle")
.attr("width", function (d) {
return d.dx;
})
.attr("height", function (d) {
return d.dy;
})
.style("fill", function (d) {
return d.children ? cfg.color(d.name) : 'none';
})
.attr("stroke", "#000000")
.attr('pointer-events', 'all')
cells
.append("text")
.attr("x", function (d) {
return d.x + d.dx / 2;
})
.attr("y", function (d) {
return d.y + d.dy / 2;
})
.attr('dy', '.95em')
.attr("text-anchor", "middle")
.text(function (d) { return d.children ? d.name : null })
I want to add a parent g element that groups cells based on their common name. For example ,
var parent = d3.selectAll("cells").attr("groupBy",function(d){ return d.children? d.name : null;})
This is so that I can display the parent name as a header for these common cells.
Nodes don't have to be grouped together physically to be able to group them to apply a label or highlight them. At present, the code you are using produces a g element for each parent node, with a rect that provides the colour fill and a blank text element. The child nodes are then overlaid on this parent node with a black stroke along the edges and a text node with the country name.
If you want to be able to highlight all the elements that have the same parent and put a header on the element, you can do it a couple of ways:
alter existing elements to show a header
create an overlay with the same dimensions as the parent node to display a header
Altering existing elements
To be able to do this, we first need to be able to identify parent nodes and their children. One way to do this is by giving nodes classes according to their position in the hierarchy and their data content. Here's one possible way to do this:
var cells = innercanvas
.selectAll(".newcell")
.data(treemap)
.enter()
.append("g")
.attr("class", function (d,i) {
return 'newcell _' + i // i provides a unique identifier for each node
+ ' cell-level-' + d.depth // cell-level-0 for root, cell-level-1, cell-level-2, etc
+ ( d.name ? ' ' + safe_name(d.name) : '' ) // if d.name exists, use the 'safe' version
+ ( ! d.children
? ' leaf' // d has no children => it's a leaf node
: (d.depth === 0
? ' root' // d.depth = 0 => it's the root node
: ' internal ')); // has children, depth > 0 => internal node
})
// strips non-alphanumeric characters out of `name` strings, replaces with _
function safe_name (txt) {
return txt.replace(/\W/g, '_');
}
The SVG g elements now look like this:
Now we can easily access the parent node for any country name c.name by using
d3.select('.internal.' + safe_name(c.name))
or (e.g.) the text elements of the leaf nodes for the country using
d3.selectAll('.leaf.' + safe_name(c.name) + ' text')
We can then use CSS to show or hide text elements, rect strokes, etc.; e.g.
var bool = false;
var toggle = d3.select('#toggle')
.on('click', toggleSvg);
function toggleSvg() {
bool = !bool;
d3.selectAll('.Cyprus')
.classed('highlightAll', bool);
}
.newcell text {
font-family: Arial, sans-serif;
font-size: 10px;
}
.newcell.leaf rect {
stroke: #000;
stroke-width: 0.5px;
}
.oversize {
display: none;
}
.internal text {
opacity: 0
}
.internal.highlightAll text {
opacity: 1
}
.highlightAll.leaf rect {
opacity: 0.1
}
.highlightAll.leaf text {
opacity: 0
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<p><a id="toggle" href='#'>Toggle Cyprus highlighting</a></p>
<svg width="186" height="77">
<g transform="translate(-30.1234, -258.33)">
<g class="newcell _2331 cell-level-1 Cyprus internal ">
<rect x="30.123480134121516" y="258.33086334171067" width="185.81893466750355" height="76.6094615363257" style="fill: rgb(100, 200, 75);"></rect>
<title>Cyprus</title>
<text x="123.0329474678733" y="296.63559410987354" dy=".35em" text-anchor="middle">Cyprus</text>
</g>
<g class="newcell _2332 cell-level-2 Cyprus leaf">
<rect x="40.12348013412152" y="268.33086334171067" width="31.51365155392795" height="23.97574841366901" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="55.88030591108549" y="280.3187375485452" dy=".35em" text-anchor="middle" class="oversize">Cyprus</text>
</g>
<g class="newcell _2333 cell-level-2 Cyprus leaf">
<rect x="40.12348013412152" y="292.30661175537968" width="31.51365155392795" height="32.633713122656687" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="55.88030591108549" y="308.62346831670802" dy=".35em" text-anchor="middle" class="oversize">Cyprus</text>
</g>
<g class="newcell _2334 cell-level-2 Cyprus leaf">
<rect x="71.637131688049465" y="268.33086334171067" width="55.48181226963859" height="56.60946153632569" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="99.37803782286876" y="296.63559410987354" dy=".35em" text-anchor="middle">Cyprus</text>
</g>
<g class="newcell _2335 cell-level-2 Cyprus leaf">
<rect x="127.11894395768805" y="268.33086334171067" width="78.823470843937" height="56.60946153632569" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="166.53067937965655" y="296.63559410987354" dy=".35em" text-anchor="middle">Cyprus</text>
</g>
</g>
</svg>
Creating an overlay
This will duplicate an existing parent node on top of the treemap.
Add a new g element to the treemap with rect and text nodes as children:
var highlightG = canvas.append('g')
.attr("transform", "translate(" + cfg.margin.left + "," + cfg.margin.top + ")")
.append('g')
.classed('highlighter', true)
.attr('opacity',0);
highlightG.append('rect');
highlightG.append('text');
We can use the data from an existing parent node to set the appropriate position and size for the rect element and the content for the text element.
var d = d3.select('.internal.Cyprus').datum();
highlightG.select('rect')
.attr("x", d.x)
.attr("y", d.y)
.attr("width", d.dx)
.attr("height", d.dy)
highlightG
.select("text")
.attr("x", d.x + d.dx / 2 )
.attr("y", d.y + d.dy / 2 )
.attr('dy', '.35em')
.attr("text-anchor", "middle")
.text(function () {
return d.name;
})
d3.select('.internal.Cyprus').property('__data__', {
depth: 1,
dx: 185.81893466750355,
dy: 76.6094615363257,
name: "Cyprus",
value: 446770,
x: 30.123480134121516,
y: 258.33086334171067
});
var opacity = 1;
var highlightG = d3.select('svg')
.append('g')
.attr("transform", "translate(-30.1234, -258.33)")
.append('g')
.classed('highlighter', true)
.attr('opacity', 0);
highlightG.append('rect');
highlightG.append('text');
d3.select('#toggle')
.on('click', function() {
var d = d3.select('.internal.Cyprus').datum();
highlightG.attr('opacity', opacity);
highlightG.select('rect')
.attr("x", d.x)
.attr("y", d.y)
.attr("width", d.dx)
.attr("height", d.dy)
highlightG
.select("text")
.attr("x", d.x + d.dx / 2)
.attr("y", d.y + d.dy / 2)
.attr('dy', '.35em')
.attr("text-anchor", "middle")
.text(function() {
return d.name;
})
opacity = opacity ? 0 : 1;
});
.newcell text {
font-family: Arial, sans-serif;
font-size: 10px;
}
.newcell.leaf rect {
stroke: #000;
stroke-width: 0.5px;
}
.oversize {
display: none;
}
.internal text {
opacity: 0
}
.highlighter rect {
fill: #000;
fill-opacity: 0.7;
stroke: deepskyblue;
stroke-width: 5px;
}
.highlighter text {
fill: deepskyblue;
opacity: 1
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<p><a id="toggle" href='#'>Activate Cyprus overlay</a></p>
<svg width="186" height="77">
<g transform="translate(-30.1234, -258.33)">
<g class="newcell _2331 cell-level-1 Cyprus internal ">
<rect x="30.123480134121516" y="258.33086334171067" width="185.81893466750355" height="76.6094615363257" style="fill: rgb(100, 200, 75);"></rect>
<title>Cyprus</title>
<text x="123.0329474678733" y="296.63559410987354" dy=".35em" text-anchor="middle">Cyprus</text>
</g>
<g class="newcell _2332 cell-level-2 Cyprus leaf">
<rect x="40.12348013412152" y="268.33086334171067" width="31.51365155392795" height="23.97574841366901" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="55.88030591108549" y="280.3187375485452" dy=".35em" text-anchor="middle" class="oversize">Cyprus</text>
</g>
<g class="newcell _2333 cell-level-2 Cyprus leaf">
<rect x="40.12348013412152" y="292.30661175537968" width="31.51365155392795" height="32.633713122656687" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="55.88030591108549" y="308.62346831670802" dy=".35em" text-anchor="middle" class="oversize">Cyprus</text>
</g>
<g class="newcell _2334 cell-level-2 Cyprus leaf">
<rect x="71.637131688049465" y="268.33086334171067" width="55.48181226963859" height="56.60946153632569" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="99.37803782286876" y="296.63559410987354" dy=".35em" text-anchor="middle">Cyprus</text>
</g>
<g class="newcell _2335 cell-level-2 Cyprus leaf">
<rect x="127.11894395768805" y="268.33086334171067" width="78.823470843937" height="56.60946153632569" style="fill: none;"></rect>
<title>Cyprus</title>
<text x="166.53067937965655" y="296.63559410987354" dy=".35em" text-anchor="middle">Cyprus</text>
</g>
</g>
</svg>
I've created a .block with more comprehensive versions of these options.
You should be able to find some combination of these that you can use for your purposes.

Every instance of <use xlink:href...> animates?

I'm using the "use xlink:ref" tag to render a polyline that's defined in the "defs" tag and animate it. I want to also use xlink:ref to render the same polyline, but without the animation, i.e., as just a static object. But all three instances of the "use xlink:ref" that I render animate, even though there's no animation associated with two of them!? How can I have only one of the three instances of it animate? I don't understand why SVG thinks I want the other 2 instances to animate. Thanks for any help!
<?xml version="1.0" encoding="utf-8"?>
<!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"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="600" height="600" viewBox="0 0 600 600">
<defs>
<marker id="mCircle" markerWidth="160" markerHeight="160" refX="80" refY="80" markerUnits="userSpaceOnUse">
<circle cx="80" cy="80" r="70" style="fill: red; stroke: black; stroke-width: 5px; opacity:0.2"/>
</marker>
<marker id="mMid" markerWidth="100" markerHeight="100" refX="50" refY="50" markerUnits="userSpaceOnUse" >
<circle cx="50" cy="50" r="6" style="fill: black; stroke: none; stroke-width:4px; opacity:1"/>
</marker>
<path d="M 0,0 60,0 120,0 180,0 240,0 300,0 360,0" id="linered" style="marker-start: url(#mCircle); marker-end: url(#mCircle); marker-mid: url(#mMid); stroke-width: 12; fill:none; stroke-linejoin:round; stroke-linecap:round; stroke-opacity: 0.6"/>
</defs>
<use xlink:href="#linered" transform="translate(120, 280)" style="stroke-dasharray:222; stroke-dashoffset:-70px; stroke:orange;"/>
<animate
xlink:href="#linered"
attributename="d"
dur="2s"
begin="1s;"
values= "M 0 0, 60 0, 120 0, 180 0, 240 0, 300 0, 360 0;
M 180 0, 60 40, 120 -30, 180 60, 240 220, 300 60, 180 0;
M 180 0, 60 -33, 120 60, 180 -90, 240 70, 300 0, 180 0;
M 180 0, 60 40, 120 -30, 180 60, 240 220, 300 60, 180 0;
M 0 0, 60 0, 120 0, 180 0, 240 0, 300 0, 360 0;"
keySplines= "0 0.8 0.3 1; 0 0.8 0.3 1; 0 0.8 0.3 1; 0 0.8 0.3 1;"
keyTimes= "0; 0.33; 0.5; 0.66; 1"
calcMode="spline"
repeatcount="4"
/>
<g transform="translate(300 280)">
<use id="static1" xlink:href="#linered" x="-180" y="0" transform="rotate(60)" style="stroke-dasharray:222; stroke-dashoffset:-70px; stroke:blue;"/>
<use id="static2" xlink:href="#linered" x="-180" y="0" transform="rotate(120)" style="stroke-dasharray:222; stroke-dashoffset:-70px; stroke:white;"/>
</g>
</svg>
First, there are a few errors in your code concerning upper case letters in attributes. While Chrome seems to be a bit more forgiving (as defined in SVG v2), other browsers still adhere to SVG v1.1, which is fully XML-compliant in this regard. So you should always use case-sensitive markerUnits, attributeName and repeatCount attributes.
Your main problem is what you are animating:
<animate xlink:href="#linered" attributeName="d" ... />
Your animation references the <path id="linered" /> element, which is the template from which each <use> is derived. Each of them copies the whole template, including its animation.
Please note that your <animate> tag is a sibling to the <use> tag it is positioned next to. Both are self-closing tags, and there is no connection between those two exept their placement in the source code next to each other - but that is incitental.
The connection between an element and its animation can only be established in two ways.
an <animate> element is the child of the animated element (do not use the xlink:href attribute for this syntax):
<path ...>
<animate ... />
</path>
an <animate> element, positioned anywhere in the same svg fragment, references the animated element:
<path id="target"... />
<!-- other content -->
<animate xlink:href="#target" ... />
If you want to animate one <use> element, but not the others, you need to animate that element. For example you could animate a transform attribute set on the <use> element. But the d attribute you want to animate is part of the referenced <path> element.
The <use> element is no stand-in for what it is referencing, but conceptually a container that hides a copy of its reference inside (in what is called a Shadow DOM). This copy cannot be referenced with a url, or a CSS selector. It cannot be animated individually.
The only solution is to write down the element to be animated seperately (note the id):
<?xml version="1.0" encoding="utf-8"?>
<!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"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="600" height="600" viewBox="0 0 600 600">
<defs>
<marker id="mCircle" markerWidth="160" markerHeight="160" refX="80" refY="80" markerUnits="userSpaceOnUse">
<circle cx="80" cy="80" r="70" style="fill: red; stroke: black; stroke-width: 5px; opacity:0.2"/>
</marker>
<marker id="mMid" markerWidth="100" markerHeight="100" refX="50" refY="50" markerUnits="userSpaceOnUse" >
<circle cx="50" cy="50" r="6" style="fill: black; stroke: none; stroke-width:4px; opacity:1"/>
</marker>
<path id="linered" d="M 0,0 60,0 120,0 180,0 240,0 300,0 360,0" style="marker-start: url(#mCircle); marker-end: url(#mCircle); marker-mid: url(#mMid); stroke-width: 12; fill:none; stroke-linejoin:round; stroke-linecap:round; stroke-opacity: 0.6"/>
</defs>
<path id="linered-animated" transform="translate(120, 280)" d="M 0,0 60,0 120,0 180,0 240,0 300,0 360,0" style="marker-start: url(#mCircle); marker-end: url(#mCircle); marker-mid: url(#mMid); stroke-width: 12; fill:none; stroke-linejoin:round; stroke-linecap:round; stroke-opacity: 0.6;stroke-dasharray:222; stroke-dashoffset:-70px; stroke:orange;"/>
<animate
xlink:href="#linered-animated"
attributeName="d"
dur="2s"
begin="1s;"
values= "M 0 0, 60 0, 120 0, 180 0, 240 0, 300 0, 360 0;
M 180 0, 60 40, 120 -30, 180 60, 240 220, 300 60, 180 0;
M 180 0, 60 -33, 120 60, 180 -90, 240 70, 300 0, 180 0;
M 180 0, 60 40, 120 -30, 180 60, 240 220, 300 60, 180 0;
M 0 0, 60 0, 120 0, 180 0, 240 0, 300 0, 360 0;"
keySplines="0 0.8 0.3 1; 0 0.8 0.3 1; 0 0.8 0.3 1; 0 0.8 0.3 1;"
keyTimes= "0; 0.33; 0.5; 0.66; 1"
calcMode="spline"
repeatCount="4"
/>
<g transform="translate(300 280)">
<use id="static1" xlink:href="#linered" x="-180" y="0" transform="rotate(60)" style="stroke-dasharray:222; stroke-dashoffset:-70px; stroke:blue;"/>
<use id="static2" xlink:href="#linered" x="-180" y="0" transform="rotate(120)" style="stroke-dasharray:222; stroke-dashoffset:-70px; stroke:white;"/>
</g>
</svg>
As a footnote only, it seems that the xlink:href attribute in an <animate> element has a bug in Firefox where the animation is never applied to a referencing <use> element.

D3 re drawing adds elements again

My html after the first time I called drawLegend looks like this:
<svg>
<g class="legend">
<rect class="active-dimension-rect"></rect>
<text class="dimension-text">Some text</text>
</g>
<g class="legend">
<rect class="active-dimension-rect"></rect>
<text class="dimension-text">Some text</text>
</g>
<svg>
On window resize I call the function again, but now my html looks like this:
<svg>
<g class="legend">
<rect class="active-dimension-rect"></rect>
<text class="dimension-text">Some text</text>
<rect class="active-dimension-rect"></rect>
<text class="dimension-text">Some text</text>
</g>
<g class="legend">
<rect class="active-dimension-rect"></rect>
<text class="dimension-text">Some text</text>
<rect class="active-dimension-rect"></rect>
<text class="dimension-text">Some text</text>
</g>
<svg>
How do I only append the rect and text elements on enter? At the moment the only way I get it to work, is to actually remove the elements (rect's and text's) from the dom when I resize.
d3.select(window).on('resize', drawLegend);
function drawLegend() {
var legendScale = d3.scale.ordinal()
.domain(dimensions)
.rangeRoundBands([0, legendWidth], .1);
var legendGroups = legendSVG.selectAll(".legend").data(dimensions);
legendGroups.enter().append("g")
.attr("class", "legend");
legendGroups.attr("transform", function (d, i) {
return "translate(" + legendScale(d) + ",0)";
});
legendGroups.exit().remove();
var legendRects = legendGroups.append("rect")
.attr("width", 18)
.attr("height", 18)
.attr('class', 'active-dimension-rect')
.attr('id', function(d){
return 'dimension-rect-' + d.replace(/\s+/g, '');
})
.style({"fill": colourScale});
var legendText = legendGroups.append("text")
.attr("dy", "1em")
.attr("dx", 20)
.attr('dimension', function(d) { return d })
.attr('class', 'dimension-text')
.attr('rectId', function(d) { return'dimension-rect-' + d.replace(/\s+/g, '') })
.style({"text-anchor": "start", 'font-size': '14px'})
.text(function(d) {
visibleDimensions.push(d);
return d;
});
}

How to apply a pattern for a D3 bar chart?

I am trying to apply a pattern to a D3 bar chart, but what I get is this:
the chart should stop exactly at 100,000
the pattern should be "fluid"
I am using a green and red pattern defined as follows:
var defs = this.svg.append("g:defs");
defs.append("g:pattern")
.attr("id", "red-fill")
.attr("patternUnits", "userSpaceOnUse")
.attr("width", "85")
.attr("height", "10")
.append("g:image")
.attr("xlink:href", "../10px-barchart-red.png")
.attr("x", 0)
.attr("y", 0)
.attr("width", 85)
.attr("height", 10);
var defs = this.svg.append("g:defs");
defs.append("g:pattern")
.attr("id", "green-fill")
.attr("patternUnits", "userSpaceOnUse")
.attr("width", "85")
.attr("height", "10")
.append("g:image")
.attr("xlink:href", "../10px-barchart-green.png")
.attr("x", 0)
.attr("y", 0)
.attr("width", 85)
.attr("height", 10);
And the plot is made with:
this.svg.selectAll("rect")
.data(dataset, getKeys)
.enter()
.append("rect")
.attr('class', 'bar')
.attr("x", function(d, i) {
return x(i) + 44;
})
.attr("y", function(d, i) {
return y(d.value);
})
.attr("width", x.rangeBand())
.attr("height", function(d, i) {
return height + padding - y(d.value);
})
.attr("fill", function(d) {
if (d.key == 0) {
return "url(#green-fill)";
} else {
return "url(#red-fill)";
}
})
This block by John Schulz successfully makes patterned bar charts that look fantastic (https://bl.ocks.org/jfsiii/7772281).
Copied the code in the below snippet for convenience and perpetuity (also added a little animation to show that it transitions well also).
var first = true;
setInterval( function(){
if(first){
d3.select('.thing-2').transition()
.delay(500)
.duration(1000)
.attr('height',20)
.attr('y',80)
}else{
d3.select('.thing-2').transition()
.delay(500)
.duration(1000)
.attr('height',100)
.attr('y',0)
}
first = !first;
},2500)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>SVG colored patterns via mask</title>
<style>
/* FF seems to need explicit dimensions */
svg {
width: 500px;
height: 500px;
}
rect.hbar {
mask: url(#mask-stripe)
}
.thing-1 {
fill: blue;
}
.thing-2 {
fill: green;
}
</style>
</head>
<body>
<svg>
<defs>
<pattern id="pattern-stripe"
width="4" height="4"
patternUnits="userSpaceOnUse"
patternTransform="rotate(45)">
<rect width="2" height="4" transform="translate(0,0)" fill="white"></rect>
</pattern>
<mask id="mask-stripe">
<rect x="0" y="0" width="100%" height="100%" fill="url(#pattern-stripe)" />
</mask>
</defs>
<!-- bar chart -->
<rect class="hbar thing-2" x="0" y="0" width="50" height="100"></rect>
<rect class="hbar thing-2" x="51" y="50" width="50" height="50"></rect>
<rect class="hbar thing-2" x="102" y="25" width="50" height="75"></rect>
<!-- horizontal bar chart -->
<rect class="hbar thing-1" x="0" y="200" width="10" height="50"></rect>
<rect class="hbar thing-1" x="0" y="251" width="123" height="50"></rect>
<rect class="hbar thing-1" x="0" y="302" width="41" height="50"></rect>
</svg>
</body>
</html>

Resources