我正在使用D3js创建一个带有正值和负值的堆积条形图。
这是我目前用于创建图表的代码:
function showChart1(yArray){
var data = yArray;
var x = d3.scale.ordinal()
.domain(['te1', 'te2'])
.rangeRoundBands([ margin, w - margin ], .1)
var y = d3.scale.linear()
.range([h-margin,0+margin]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(0, 0);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
barStack(data);
y.domain(data.extent);
svg = d3.select("#svg1")
.append("svg")
.attr("height", h)
.attr("width", w)
.attr("class", "graph-svg-component");
var gradientVerde1 = svg.append("defs")
.append("linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%")
.attr("spreadMethod", "reflect");
gradientVerde1.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#7ac141")
.attr("stop-opacity", 1);
gradientVerde1.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#7ac141")
.attr("stop-opacity", 1);
gradientVerde1.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#6db03c")
.attr("stop-opacity", 1);
gradientVerde1.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#6db03c")
.attr("stop-opacity", 1);
var gradientVerde2 = svg.append("defs")
.append("linearGradient")
.attr("id", "gradient2")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%")
.attr("spreadMethod", "reflect");
gradientVerde2.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#acd038")
.attr("stop-opacity", 1);
gradientVerde2.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#acd038")
.attr("stop-opacity", 1);
gradientVerde2.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#9abd2f")
.attr("stop-opacity", 1);
gradientVerde2.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#9abd2f")
.attr("stop-opacity", 1);
var gradientVerde3 = svg.append("defs")
.append("linearGradient")
.attr("id", "gradient3")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%")
.attr("spreadMethod", "reflect");
gradientVerde3.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#d1dd31")
.attr("stop-opacity", 1);
gradientVerde3.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#d1dd31")
.attr("stop-opacity", 1);
gradientVerde3.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#bdc82b")
.attr("stop-opacity", 1);
gradientVerde3.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#bdc82b")
.attr("stop-opacity", 1);
var gradientRosso = svg.append("defs")
.append("linearGradient")
.attr("id", "gradient4")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%")
.attr("spreadMethod", "reflect");
gradientRosso.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#c9242b")
.attr("stop-opacity", 1);
gradientRosso.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#c9242b")
.attr("stop-opacity", 1);
gradientRosso.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#b72025")
.attr("stop-opacity", 1);
gradientRosso.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#b72025")
.attr("stop-opacity", 1);
var gradientRosso2 = svg.append("defs")
.append("linearGradient")
.attr("id", "gradient5")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%")
.attr("spreadMethod", "reflect");
gradientRosso2.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#ee1c25")
.attr("stop-opacity", 1);
gradientRosso2.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#ee1c25")
.attr("stop-opacity", 1);
gradientRosso2.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#d7181f")
.attr("stop-opacity", 1);
gradientRosso2.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#d7181f")
.attr("stop-opacity", 1);
svg.selectAll(".series")
.data(data)
.enter()
.append("g")
.classed("series", true)
.style("fill", function(d,i) {
if (i == 0) {
return "url(#gradient4)";
//return "#c9242b";
}
else if (i == 1) {
return "url(#gradient5)";
//return "#ee1c25";
}
else if (i == 2) {
return "url(#gradient)";
//return "#7ac141";
}
else if (i == 3) {
return "url(#gradient2)";
//return "#aecf36";
}
else if (i == 4) {
return "url(#gradient3)";
//return "#d1dd31";
}
else
{
return color(i)
}
})
.style("opacity", 1)
.selectAll("rect")
.data(Object)
.enter()
.append("rect")
.attr("x", function(d, i) { return x(x.domain()[i]) })
.attr("y", function(d) { return y(d.y0) })
.attr("height", function(d) { return y(0) - y(d.size) })
//.attr("width", x.rangeBand()) questo allarga le barre al massimo della larghezza possibile
.attr("width", "100px")
.attr("transform", "translate(50 0)")
.on("mouseover", function() { tooltip.style("display", null); })
.on("mouseout", function() { tooltip.style("display", "none"); })
.on("mousemove", function(d) {
var xPosition = d3.mouse(this)[0] - 35;
var yPosition = d3.mouse(this)[1] - 5;
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
tooltip.select("text").text(d.y);
});
var yScale = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d[1]; })])
.range([0, h]);
console.log(yScale);
/*console.log("y(0)", y(0));
console.log("margin", margin); */
svg.append("g")
.attr("class", "axis x")
.attr("transform", "translate(0 " + y(0) + ")")
.call(xAxis);
/* svg.append("g")
.attr("class", "axis y")
.attr("transform", "translate(" + margin + " 0)")
.call(yAxis); */
/* Here we add tooltips */
// Prep the tooltip bits, initial display is hidden
var tooltip = svg.append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("rect")
.attr("width", 30)
.attr("height", 20)
.attr("fill", "white")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 15)
.attr("dy", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
}
这很有效,除了它没有缩放图表以显示x轴始终在中间。 这是结果: 请不要注意背景。
所以我的问题是:是否有可能让x轴始终位于中间?
答案 0 :(得分:1)
我会根据当前xAxis y位置与容器y位置中间的差异来翻译整个图形。
这样的事情:
var xAxis = document.getElementById('assex'); //get xAxis based on ID
var container = document.getElementById('svg1'); //get container based on ID
var containerCenterY = container.getBoundingClientRect().top + container.getBoundingClientRect().height / 2; //get containers central y position, so get Y and add half the height
var xAxisY = xAxis.getBoundingClientRect().top; //get xAxis y pos
var difference = xAxisY - containerCenterY; //work out difference
关于你的例子:
我使用了上面的代码并使用了这个翻译函数:
d3.select('#mainSVGContainer').transition().duration(1000).attr("transform", "translate(0 "+(-difference) +")")
我进行了转换,以便您可以看到之前的情况。
现在这首先不起作用,因为某些浏览器(包括Chrome)不支持SVG
元素的翻译,但您可以翻译g
元素。因此,在您创建g
后添加了svg
元素,为此元素添加了ID
并对其进行了翻译。
新的svg创作:
svg = d3.select("#svg1")
.append("svg").attr("height", h)
.attr("width", w).append('g').attr('id', 'mainSVGContainer')
.attr("height", h)
.attr("width", w)
.attr("class", "graph-svg-component")
更新了小提琴:https://jsfiddle.net/thatOneGuy/8k8ggpcn/6/
我会把代码放在这里,以防JSFiddle崩溃:
function barStack(d) {
var l = d[0].length
while (l--) {
var posBase = 0,
negBase = 0;
d.forEach(function(d) {
d = d[l]
d.size = Math.abs(d.y)
if (d.y < 0) {
d.y0 = negBase
negBase -= d.size
} else {
d.y0 = posBase = posBase + d.size
}
})
}
d.extent = d3.extent(d3.merge(d3.merge(d.map(function(e) {
return e.map(function(f) {
return [f.y0, f.y0 - f.size]
})
}))))
return d
}
var h = 548;
var w = 408;
var margin = 0;
var color = d3.scale.category10();
/* Here is an example */
function chart() {
var data = [
[{
y: 3
}, {
y: 6
}],
[{
y: 4
}, {
y: -2
}],
[{
y: 10
}, {
y: -3
}]
]
var x = d3.scale.ordinal()
.domain(['te1', 'te2'])
.rangeRoundBands([margin, w - margin], .1)
var y = d3.scale.linear()
.range([h - 30, 0 + 30]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(0, 0);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
barStack(data);
y.domain(data.extent);
svg = d3.select("#svg1")
.append("svg").attr("height", h)
.attr("width", w)
.append('g')
.attr('id', 'mainSVGContainer')
.attr("height", h)
.attr("width", w)
.attr("class", "graph-svg-component")
var gradientVerde1 = svg.append("defs")
.append("linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%")
.attr("spreadMethod", "reflect");
gradientVerde1.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#7ac141")
.attr("stop-opacity", 1);
gradientVerde1.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#7ac141")
.attr("stop-opacity", 1);
gradientVerde1.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#6db03c")
.attr("stop-opacity", 1);
gradientVerde1.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#6db03c")
.attr("stop-opacity", 1);
var gradientVerde2 = svg.append("defs")
.append("linearGradient")
.attr("id", "gradient2")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%")
.attr("spreadMethod", "reflect");
gradientVerde2.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#acd038")
.attr("stop-opacity", 1);
gradientVerde2.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#acd038")
.attr("stop-opacity", 1);
gradientVerde2.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#9abd2f")
.attr("stop-opacity", 1);
gradientVerde2.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#9abd2f")
.attr("stop-opacity", 1);
var gradientVerde3 = svg.append("defs")
.append("linearGradient")
.attr("id", "gradient3")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%")
.attr("spreadMethod", "reflect");
gradientVerde3.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#d1dd31")
.attr("stop-opacity", 1);
gradientVerde3.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#d1dd31")
.attr("stop-opacity", 1);
gradientVerde3.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#bdc82b")
.attr("stop-opacity", 1);
gradientVerde3.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#bdc82b")
.attr("stop-opacity", 1);
var gradientRosso = svg.append("defs")
.append("linearGradient")
.attr("id", "gradient4")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%")
.attr("spreadMethod", "reflect");
gradientRosso.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#c9242b")
.attr("stop-opacity", 1);
gradientRosso.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#c9242b")
.attr("stop-opacity", 1);
gradientRosso.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#b72025")
.attr("stop-opacity", 1);
gradientRosso.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#b72025")
.attr("stop-opacity", 1);
var gradientRosso2 = svg.append("defs")
.append("linearGradient")
.attr("id", "gradient5")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "0%")
.attr("spreadMethod", "reflect");
gradientRosso2.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#ee1c25")
.attr("stop-opacity", 1);
gradientRosso2.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#ee1c25")
.attr("stop-opacity", 1);
gradientRosso2.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#d7181f")
.attr("stop-opacity", 1);
gradientRosso2.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#d7181f")
.attr("stop-opacity", 1);
svg.selectAll(".series")
.data(data)
.enter()
.append("g")
.classed("series", true)
.style("fill", function(d, i) {
if (i == 0) {
return "url(#gradient4)";
//return "#c9242b";
} else if (i == 1) {
return "url(#gradient5)";
//return "#ee1c25";
} else if (i == 2) {
return "url(#gradient)";
//return "#7ac141";
} else if (i == 3) {
return "url(#gradient2)";
//return "#aecf36";
} else if (i == 4) {
return "url(#gradient3)";
//return "#d1dd31";
} else {
return color(i)
}
})
.style("opacity", 1)
.selectAll("rect")
.data(Object)
.enter()
.append("rect")
.attr("x", function(d, i) {
return x(x.domain()[i])
})
.attr("y", function(d) {
return y(d.y0)
})
.attr("height", function(d) {
return y(0) - y(d.size)
})
//.attr("width", x.rangeBand()) questo allarga le barre al massimo della larghezza possibile
.attr("width", "100px")
.attr("transform", "translate(50 0)")
.on("mouseover", function() {
tooltip.style("display", null);
})
.on("mouseout", function() {
tooltip.style("display", "none");
})
.on("mousemove", function(d) {
var xPosition = d3.mouse(this)[0] - 35;
var yPosition = d3.mouse(this)[1] - 5;
tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
tooltip.select("text").text(d.y);
});
var yScale = d3.scale.linear()
.domain([0, d3.max(data, function(d) {
return d[1];
})])
.range([0, h]);
console.log(yScale);
/*console.log("y(0)", y(0));
console.log("margin", margin); */
svg.append("g")
.attr("class", "axis x")
.attr("id", "assex")
.attr("transform", "translate(0 " + y(0) + ")")
.call(xAxis);
/* svg.append("g")
.attr("class", "axis y")
.attr("transform", "translate(" + margin + " 0)")
.call(yAxis); */
/* Here we add tooltips */
// Prep the tooltip bits, initial display is hidden
var tooltip = svg.append("g")
.attr("class", "tooltip")
.style("display", "none");
tooltip.append("rect")
.attr("width", 30)
.attr("height", 20)
.attr("fill", "white")
.style("opacity", 0.5);
tooltip.append("text")
.attr("x", 15)
.attr("dy", "1.2em")
.style("text-anchor", "middle")
.attr("font-size", "12px")
.attr("font-weight", "bold");
var xAxis = document.getElementById('assex'); //get xAxis based on ID
var container = document.getElementById('svg1'); //get container based on ID
var containerCenterY = container.getBoundingClientRect().top + container.getBoundingClientRect().height / 2; //get containers central y position, so get Y and add half the height
var xAxisY = xAxis.getBoundingClientRect().top; //get xAxis y pos
var difference = xAxisY - containerCenterY; //work out difference
d3.select('#mainSVGContainer').transition().duration(1000).attr("transform", "translate(0 "+(-difference) +")")
};
chart();
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #82c5cb;
stroke-width: 5px;
shape-rendering: crispEdges;
}
#svg1{
border: black 2px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="svg1">
</div>