Background image to SVG choropleth map using D3 - javascript

I'm putting together a choropleth map in D3 of U.S. States and already have the code to render the map with solid colored backgrounds using fill.
However, I want the fill of the state paths to be an image. I tried setting the path background-image to the img's URL, but that didn't work.
How can I do this? I'd also like to fill each state a different image.
var svg = d3.select("#map").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("rect")
.attr("class", "background")
.attr("fill","none")
.attr("width", width)
.attr("height", height);
var g = svg.append("g")
.attr("class", "states");
$(document).ready(function() {
d3.json("us-states.json", function(json) {
var features = json.features;
g.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.attr("fill", "purple")
.attr("stroke","white")
.attr("stroke-width", 1);
});
});

As Superboggly points out, first define a pattern, then use it.
Definition example:
<defs>
<pattern id="chloroplethbackground" patternUnits="userSpaceOnUse" width="??" height="??">
<image xlink:href="bg.jpg" x="0" y="0" width="??" height="??" />
</pattern>
</defs>
Then set your fill to url(#chloroplethbackground)
So it will be:
var svg = d3.select("#map").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("rect")
.attr("class", "background")
.attr("fill","none")
.attr("width", width)
.attr("height", height);
var g = svg.append("g")
.attr("class", "states");
$(document).ready(function() {
d3.json("us-states.json", function(json) {
var features = json.features;
g.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.attr("fill", "url(#chloroplethbackground)")
.attr("stroke","white")
.attr("stroke-width", 1);
});
});

Related

SVG element not being responsive - when screen resized

I have a map-container which shows world map, that is supposed to be responsive but it does not work when I run it and resize the page, I cant find whats the issue. what it is expected when screen is resized. here's my code
var tooltipMap = d3.select("body")
.append("div")
.attr("class", "map-tooltip shadow")
.style("opacity", 0);
var projection = d3.geo.mercator()
.center([0, 62 ])
.scale(150)
.rotate([0, 0]);
var svg = d3.select("#map-container").append("svg")
.attr("width", width)
.attr("height", height)
.attr('viewBox', "0 0 "+(width)+" "+(height))
.attr('preserveAspectRatio', 'xMinYMid')
.attr("class","chart");
var path = d3.geo.path()
.projection(projection);
var defs = svg.append('svg:defs');
defs.append("svg:pattern")
.attr("id", "bgImg")
.attr("width", 6)
.attr("height", 6)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", '../assets/img/map-tile.png')
.attr("width", 6)
.attr("height", 6)
.attr("x", 0)
.attr("y", 0);
var g = svg.append("g")
.attr("width", width+160)
.attr("height", height);
// load and display the World
d3.json("om.json", function (error, topology) {
g.selectAll("path")
.data(topojson.object(topology, topology.objects.countries).geometries)
.enter()
.append("path")
.attr("fill", "url(#bgImg)")
.attr("d", path);
});
<script src="js/d3.v3.min.js"></script>
<div id="map-container"></div>
Basically as of what appears,
.attr("class","chart");
does not work, wondering why ?
Solution -
CSS - strange as hell, but this was the issue my css was not placed perfectly. !!! Facepalm !!!
.chart{ width:100%; height:100%; }

d3.js transparent shape tesselations - complex subtractions

Expanding on this first example. I am interested to expand the solutions.
1 - make this more responsive - scaling wise
2 - make the subtraction more complex
3 - ensure the svg fits over the width of the banner.
d3.js - masking shapes to create transparent sectio
So here is the goal
this is the code as it is - I've given it a little clean up.
http://jsfiddle.net/NYEaX/1521/
function maskMaker(el) {
var backcolor = $(el).data("color");
var backopacity = $(el).data("opacity");
// Set the main elements for the series chart
var svgroot = d3.select($(el)[0]).append("svg");
var mask = svgroot
.append("defs")
.append("mask")
.attr("id", "myMask");
mask.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", "1200px")
.attr("height", 500)
.style("fill", "white")
.style("opacity", backopacity);
mask.append("circle")
.attr("cx", 550)
.attr("cy", 250)
.attr("r", 150);
var svg = svgroot
.attr("class", "series")
.attr("width", "1200px")
.attr("height", "500px")
.append("g")
.attr("transform", "translate(0,0)")
var rect = svg
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", "1200px")
.attr("height", 500)
.attr("mask", "url(#myMask)")
.style("fill", backcolor);
}
//var el = $(".mask"); //selector
$('[data-role="mask"]').each(function(index) {
console.log("test")
maskMaker(this);
});

d3.js - masking shapes to create transparent sectio

I am interested in learning how to create a transparent mask with d3.js.
http://jsfiddle.net/59bunh8u/35/
This is where I am up to - how would I create a subtraction mask on the red rectangle - also how could you style the red rectangle to take on more of a multiply style property?
$(document).ready(function() {
var el = $(".mask"); //selector
// Set the main elements for the series chart
var svg = d3.select(el[0]).append("svg")
.attr("class", "series")
.attr("width", "800px")
.attr("height", "500px")
.append("g")
.attr("transform", "translate(0,0)")
var rect = svg
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 500)
.attr("height", 500)
.style("fill", "red")
.style('opacity', 0.75)
var rect = svg
.append("circle").attr("cx", 250).attr("cy", 250).attr("r", 125).style("fill", "white");
});
You need an SVG mask. Feel free to play with it to tweak the parameters:
var mask = svgroot
.append("defs")
.append("mask")
.attr("id", "myMask");
mask.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 500)
.attr("height", 500)
.style("fill", "white")
.style("opacity", 0.7);
mask.append("circle")
.attr("cx", 300)
.attr("cy", 300)
.attr("r", 100);
Modified example: http://jsfiddle.net/59bunh8u/40/
See also SVG clipPath to clip the *outer* content out

D3.js Circles on Map

I am very new to coding and am trying to learn D3. I have map of France which I am able to make appear in the browser. However, I am trying to display circles on the map based on a csv file. I am not sure what I am doing wrong with the function... Any help/direction would be great.
Here is a Cloud9 of the code and files... https://ide.c9.io/santiallende/d3-map-bubbles-france
I won't sugarcoat, your code's a mess.
You define and append 4 different svg elements to the body and you create 3 different projections. All of it is unnecessary. Just go through and remove all the redundancies.
//Width and height
var w = 800;
var h = 350;
var canvas = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h)
d3.json("france.json", function(data) {
var group = canvas.selectAll("g")
.data(data.features)
.enter()
.append("g")
//Define map projection
var projection = d3.geo.mercator()
.translate([400, 1200])
.scale([1100]);
//Define path generator
var path = d3.geo.path()
.projection(projection);
var areas = group.append("path")
.attr("d", path)
.attr("class", "area")
.attr("fill", "steelblue");
//Load in cities data
d3.csv("wineregions.csv", function(data) {
canvas.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) {
return projection([d.lon, d.lat])[0];
})
.attr("cy", function(d) {
return projection([d.lon, d.lat])[1];
})
.attr("r", 5)
.style("fill", "yellow")
.style("opacity", 0.75);
});
});
Fixed code here.

D3 fill shape with image using pattern

I'm trying to create a circular avatar with D3.js but I cannot get my image to show up in my circle. I'm using a svg pattern def to attempt to fill the circle with an image.
Can anyone tell me what I'm doing wrong below? Thank you.
var config = {
"avatar_size" : 48
}
var body = d3.select("body");
var svg = body.append("svg")
.attr("width", 500)
.attr("height", 500);
var defs = svg.append('svg:defs');
defs.append("svg:pattern")
.attr("id", "grump_avatar")
.attr("width", config.avatar_size)
.attr("height", config.avatar_size)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", 'images/avatars/avatar_grumpy.png')
.attr("width", config.avatar_size)
.attr("height", config.avatar_size)
.attr("x", 0)
.attr("y", 0);
var circle = svg.append("circle")
.attr("cx", config.avatar_size)
.attr("cy", config.avatar_size)
.attr("r", config.avatar_size)
.style("fill", "#fff")
.style("fill", "#grump_avatar");
"Fill" is a style property, you have to use CSS url() notation for the reference to the pattern element.
Once you fix that, you'll discover that you also have your sizes wrong -- unless your intention was to have four copies of the avatar tiled in the circle!
P.S. I would normally have left this just as a comment, and marked this for closure as a simple typo, but I wanted to try out Stack Snippets:
var config = {
"avatar_size" : 48
}
var body = d3.select("body");
var svg = body.append("svg")
.attr("width", 500)
.attr("height", 500);
var defs = svg.append('svg:defs');
defs.append("svg:pattern")
.attr("id", "grump_avatar")
.attr("width", config.avatar_size)
.attr("height", config.avatar_size)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", 'http://placekitten.com/g/48/48')
.attr("width", config.avatar_size)
.attr("height", config.avatar_size)
.attr("x", 0)
.attr("y", 0);
var circle = svg.append("circle")
.attr("cx", config.avatar_size/2)
.attr("cy", config.avatar_size/2)
.attr("r", config.avatar_size/2)
.style("fill", "#fff")
.style("fill", "url(#grump_avatar)");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Categories

Resources