I'm having difficulty centering my D3 map on the webpage. The map is in a map class and within a div, but CSS won't appear to center it.
Any margins I apply to the class ".map", which the SVG is in, doesn't appear to work either. I'm not sure why I'm unable to apply any CSS to the map, but maybe I'm supposed to do something in the actual D3 code? Unsure. Thanks!
Here's my code:
<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.js'></script>
<meta charset='utf-8'>
<meta name="viewport" content='width=device-width, initial-scale=1.0'>
<title></title>
<style>
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 10px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 10px;
}
.active {
fill: rgba(149, 165, 166, 0.8);
}
body {
background: rgba(32, 32, 32, 1);
color: rgba(255, 255, 255, 0.8);
}
h1 {
font-family: Impact, Charcoal, sans-serif;
text-align: center;
}
h2 {
font-family: Impact, Charcoal, sans-serif;
text-align: center;
}
p {
font-family: "Arial Black", Gadget, sans-serif;
text-align: center;
}
#box {
border: 10px solid black;
margin: auto;
padding: 10px;
width: 75%;
border-radius: 10px;
}
.map {
margin-left: auto;
margin-right: auto;
}
</style>
<script>
function draw(geo_data) {
var margin = 0,
width = 2000 - margin,
height = 700 - margin;
var centered;
var svg = d3.select('#map')
.append('svg')
.attr('width', width + margin)
.attr('height', height + margin)
.append('g')
.attr('class', 'map');
var formatComma = d3.format(",")
var projection = d3.geoAlbersUsa();
var path = d3.geoPath().projection(projection);
var map = svg.selectAll('path')
.data(geo_data.features)
.enter()
.append('path')
.attr('d', path)
.attr('fill', 'rgba(105, 105, 105, 1)')
.attr('stroke', 'rgba(0, 0, 0, 1)')
.attr('stroke-width', 0.5)
.on('mouseover', function(d) {
d3.select(this).attr('fill', 'rgba(108, 122, 137, 0.5)')
})
.on('mouseout', function() {
if (d3.select(this).classed('clicked')) {
console.log('is clicked')
d3.select(this).attr('fill', 'rgba(105, 105, 105, 1)')
} else {
console.log('is not clicked')
d3.select(this).attr('fill', 'rgba(105, 105, 105, 1)')
}
})
// Calls click-to-zoom function defined below.
.on('click', clicked);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<p><font size='4rem'>" + d.city + ", " + d.state + "</p></font>" + "<p><font size='3rem'><strong>Guns Manufactured: </strong>" + formatComma(d.guns) + "</p>" +
"<p><strong>Top Manufacturer:</strong> " + d.manufacturer +
"</p></font>";
})
svg.call(tip);
// Click-to-zoom function adapted from Mike Bostock's code: https://bl.ocks.org/mbostock/2206590
function clicked(d) {
d3.select(this).attr('fill', 'rgba(108, 122, 137, 0.5)');
if (d3.select(this).classed('clicked')) {
d3.select(this).attr('clicked', false);
} else {
d3.select(this).attr('clicked', true);
}
var x, y, k;
if (d && centered !== d) {
var centroid = path.centroid(d);
x = centroid[0];
y = centroid[1];
k = 4;
centered = d;
} else {
x = width / 2;
y = height / 2;
k = 1;
centered = null;
}
map.selectAll('path')
.classed('active', centered && function(d) {
return d === centered;
});
map.transition()
.duration(1000)
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')scale(' + k + ')translate(' + -x + ',' + -y + ')')
.style('stroke-width', 1 / k + 'px');
// Transitions circles upon zoom.
svg.selectAll('circle')
.transition()
.duration(1000)
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')scale(' + k + ')translate(' + -x + ',' + -y + ')')
.style('stroke-width', 1 / k + 'px');
}
d3.csv('https://raw.githubusercontent.com/dieterholger/US-Gun-Manufacturing-Interactive/master/top100cities.csv', function(error, data) {
// Converts strings in csv to integers so they can be used.
data.forEach(function(d) {
return d.guns = +d.guns;
})
// This returns the max number of guns.
var guns = data.map(function(d) {
return d.guns;
});
var guns_extent = d3.extent(data, function(d) {
return d.guns;
});
var radius = d3.scaleSqrt()
.domain(guns_extent)
.range([2, 40]);
svg.append('g')
.attr('class', 'bubble')
.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', function(d) {
return radius(d.guns);
})
.attr('fill', 'rgba(248, 148, 6, 0.5)')
.attr('stroke', 'black')
.on('mouseover', function(d) {
tip.show(d);
return d3.select(this).attr('fill', 'rgba(248, 148, 6, 0.9)');
})
.on('mouseout', function(d) {
tip.hide(d);
return d3.select(this).attr('fill', 'rgba(248, 148, 6, 0.5)');
})
});
};
</script>
</head>
<body>
<div id='box'>
</div>
<div id='map'>
<h2>Hover your mouse to see data on the cities and click a state to zoom in.</h2>
</div>
<div id='box'>
</div>
<script>
d3.json('https://raw.githubusercontent.com/dieterholger/US-Gun-Manufacturing-Interactive/master/us_states.json', draw);
</script>
</body>
Enclose the map in another div, which has the same width as the box above it (75%). You may want to move the div style to a CSS class, if it works the way you want.
<div style="display:block; margin-left:auto; margin-right:auto; width:75%">
<div id="map">
...
</div>
</div>
UPDATE
I just found the real problem. Your css definition for map is for a class, not for an id. And... if you want to use auto margins, you need to define a width.
Change your css to match the following:
#map {
width: 75%;
margin-left: auto;
margin-right: auto;
}
I am working with the leaflet.markercluster plugin and have it working so it clusters my markers. Is it possible to assign a specific color to multiple cluster groups? Right now, all the cluster marker colors are the same between various layer groups and it's hard to differientate which layers represent which.
I want to use the default markerCluster marker styles, but I want to assign a different background-color to each group.
Example:
Group 1
var trucksGroup = L.markerClusterGroup({
iconCreateFunction: function(cluster) {
return L.divIcon({ /* assign color here?? */ });
}
});
var carsGroup = L.markerClusterGroup({
iconCreateFunction: function(cluster) {
return L.divIcon({ /* assign color here?? */ });
}
});
The default marker CSS:
.marker-cluster-small {
background-color: rgba(181, 226, 140, 0.6);
}
.marker-cluster-small div {
background-color: rgba(110, 204, 57, 0.6);
}
.marker-cluster-medium {
background-color: rgba(241, 211, 87, 0.6);
}
.marker-cluster-medium div {
background-color: rgba(240, 194, 12, 0.6);
}
.marker-cluster-large {
background-color: rgba(253, 156, 115, 0.6);
}
.marker-cluster-large div {
background-color: rgba(241, 128, 23, 0.6);
}`
I haven't tried it this, but here's what I recommend attempting:
Instead of returning L.divIcon() from your function, get the default icon by calling _defaultIconCreateFunction() on your markerClusterGroup, e.g., trucksGroup._defaultIconCreateFunction(cluster).
Add a new class to that default icon to denote what group it's in. E.g., icon.options.className += ' trucks-group'.
Add new styles in your CSS for .truck-group.marker-cluster-small, .truck-group.marker-cluster-medium, etc.
Putting the first two steps together:
var trucksGroup = L.markerClusterGroup({
iconCreateFunction: function(cluster) {
var icon = trucksGroup._defaultIconCreateFunction(cluster);
icon.options.className += ' trucks-group';
return icon;
}
});
var carsGroup = L.markerClusterGroup({
iconCreateFunction: function(cluster) {
var icon = carsGroup._defaultIconCreateFunction(cluster);
icon.options.className += ' cars-group';
return icon;
}
});
I have been staring at this for a long time now and can't see what's wrong...
I am drawing a line graph using d3 and want to keep the styling in a separate CSS file.
Line section:
var line = d3.svg.line()
.interpolate("monotone")
.x(function(d,i) { return xScale(graph_d.TimeStamp[i]) + 0.5; })
.y(function(d) { return yScale(d) });
//Average line
chart.select("#chartarea")
.selectAll(".avgline")
.data(graph_d.Data)
.enter()
.append('path')
.attr("class", "avgline")
.attr('d', function(d) { return line(graph_d.Data); });
CSS:
.avgline
{
fill: none;
stroke-width: 2px;
stroke: "grey";
}
This code does not render any line. Other parts of the CSS file are read and are working.
When putting the style into the line section it works:
//Average line
chart.select("#chartarea")
.selectAll(".avgline")
.data(graph_d.Data)
.enter()
.append('path')
.attr("class", "avgline")
.attr('d', function(d) { return line(graph_d.Data); })
.attr('fill', 'none')
.attr('stroke-width', '1px')
.attr('stroke', 'grey');
Can you please help me?
Colours in CSS are not written in quotes so you want
.avgline
{
fill: none;
stroke-width: 2px;
stroke: grey;
}
I made this simple SVG animation HERE , The code for drawing the dashed lines is below:
$(document).ready(function() {
var offset = parseInt($('#move-opacity').attr("offset"));
setInterval(function() {
$('#move-opacity').attr("offset", offset + "%");
if (offset < 100) {
$('#last-opacity').attr("offset", (offset + 1) + "%");
}
offset++;
}, 25);
/* code for secound line animation */
var offset1 = parseInt($('#move-opacity-1').attr('offset'));
setInterval(function() {
$('#move-opacity-1').attr("offset", offset + "%");
if (offset < 100) {
$('#last-opacity-1').attr("offset", (offset + 1) + "%");
}
offset++;
}, 25);
$("#lock").attr( "class" , "animated bounceInUp");
$("#quote-icon").attr( "class" , "animated bounceInUp delay-05s");
$("#lock").addClass("animated bounceInUp");
});
Now if you notice clearly even the arrow is overridden with a dashed arrow , once the line is drawn , how to prevent this from happening ?
The actual problem is because the polygon that produces the arrow head already has class='st0' which produces a yellow colored fill and the below code is also adding a yellow colored gradient as a stroke to the arrow head and thus you are ending up seeing both.
#dotted-lines-1 {
stroke: url(#yellow-gradient);
fill: none;
stroke-width:3;
stroke-miterlimit: 10;
stroke-dasharray:4.8732,2.9239;
}
#dotted-lines-2 {
stroke: url(#yellow-gradient);
fill: none !important;
stroke-width:3;
stroke-miterlimit: 10;
stroke-dasharray:4.8732,2.9239;
}
To overcome the issue, apply the yellow gradient only to the line and path elements within the g like in the below code block.
#dotted-lines-1 line, #dotted-lines-1 path {
stroke: url(#yellow-gradient);
fill: none;
stroke-width:3;
stroke-miterlimit: 10;
stroke-dasharray:4.8732,2.9239;
}
#dotted-lines-2 line, #dotted-lines-2 path {
stroke: url(#yellow-gradient);
fill: none !important;
stroke-width:3;
stroke-miterlimit: 10;
stroke-dasharray:4.8732,2.9239;
}
Fiddle Demo
I am trying to create a D3 differencing chart similar to this http://bl.ocks.org/mbostock/3894205
I have taken much of the D3 and CSS3 code verbatim from the example and got the relevant lines and colour areas to be drawn when the user checks on a particular checkbox. However, my coding problem lies in that the areas above and below the splitting line are highlighted using the same colour, not the differencing colours defined in the CSS code.
The relevant CSS is below:
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
/* display: none;*/
display: inline;
}
.area.above {
fill: rgb(252,141,89);
opacity:0.5;
}
.area.below {
fill: rgb(145,207,96);
opacity:0.5;
}
.line {
fill: none;
stroke: #000;
stroke-width: 1px;
}
With the relevant D3 code taken and adapted for use from the example above is here:
dvc.line = d3.svg.area()
.interpolate("basis")
.x(function(d) { return main_x0(d.date); })
.y(function(d) { return dvc.y(d[prelimLineArray]); });
dvc.area = d3.svg.area()
.interpolate("basis")
.x(function(d) {return main_x0(d.date)})
.y1(function(d) { return dvc.y(d[prelimLineArray]); });
dvc.focus.datum(dvc.data);
dvc.focus.append("clipPath")
.attr("id", "clip-below")
.append("path")
.attr("stroke-width", "1px")
.attr("d", dvc.area.y0(dvc.height));
dvc.focus.append("clipPath")
.attr("id", "clip-above")
.attr("stroke-width", "1px")
.append("path")
.attr("d", dvc.area.y0(0));
dvc.focus.append("path")
.attr("class", "area above")
.attr("clip-path", "url(#clip-above)")
.attr("d", dvc.area.y0(function(d) {
return dvc.y(d[selectedLineArray]);
}));
dvc.focus.append("path")
.attr("class", "area below")
.attr("clip-path", "url(#clip-below)")
.attr("stroke-width", "1px")
.attr("d", dvc.area);
Can any help me and spot any errors in this code that would force only one CSS highlight colour to be used for both positive and negative graphed areas?
Thanks