我的要求是生成带平移和缩放的条形图通过刷涂来克服x轴标签重叠id数据更多。我实现了条形图平移和基于下面的链接示例通过刷涂进行缩放 http://bl.ocks.org/MartynJones87/7db0d637e178e7204c0a 我能够进行平移和缩放,但x轴标签不会显示在轴上。我不知道我错在哪里。
这是代码的plunker link。
在数据加载时,调用的核心代码是:
var xBrush = d3.svg.brush().x(min_x).on("brush", xBrushed);
// Called to re-draw the bars on the main chart when the brush on the x axis
// has been altered.
function xBrushed() {
var originalRange = main_xZoom.range();
main_xZoom.domain(xBrush.empty() ? originalRange : xBrush.extent());
x.rangeRoundBands([main_xZoom(originalRange[0]), main_xZoom(originalRange[1])], .2);
//main_x1.rangeRoundBands([0, x.rangeBand()], 0);
main.selectAll("rect")
.data(data)
.attr("width", function (d) {
return x.rangeBand();
})
.attr("x", function (d) {
// alert("d is"+JSON.stringify(d));
return x(d.letter);
});
main.select("g.x.axis").call(xAxis).selectAll(".tick text").call(wrap, x.rangeBand());
};
答案 0 :(得分:0)
我在你的代码中找到了两个问题。
svg clipPath
中使用的defs
矩形也在xBrushed
函数内更新。问题出在您使用的选择器上。
您应该使用
main.selectAll(".rect") //which selects all elements with class rect in main selection.
而不是
main.selectAll("rect") //which selects all rect elements in main selection which includes clipPath rect also.
在xBrushed
函数中。
您需要将clip-path
属性应用于包含矩形栏元素的group元素。
工作代码段
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
width = 860 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var min_margin = {
top: height,
right: margin.right + 10,
bottom: margin.bottom,
left: margin.left + 10
},
min_height = 10,
min_width = 860 - min_margin.left - min_margin.right;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .2);
var min_x = d3.scale.ordinal().rangeRoundBands([0, width], .2);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var min_xAxis = d3.svg.axis()
.scale(min_x)
.orient("bottom");
var main_xZoom = d3.scale.linear()
.range([0, width])
.domain([0, width]);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10, "%");
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var main = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
main.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height + min_height + margin.bottom);
var mini_x_append = svg.append("g")
.attr("transform", "translate(" + min_margin.left + "," + (margin.top + height) + ")")
.attr("width", min_width);
var data = [{
"letter": "A~q112",
"frequency": 0.08167
}, {
"letter": "B~12",
"frequency": 0.01492
}, {
"letter": "C~c",
"frequency": 0.02782
}, {
"letter": "D~1a",
"frequency": 0.04253
}, {
"letter": "E~d",
"frequency": 0.12702
}, {
"letter": "F~x",
"frequency": 0.02288
}, {
"letter": "G~v",
"frequency": 0.02015
}, {
"letter": "H~xs",
"frequency": 0.06094
}, {
"letter": "I~za",
"frequency": 0.06966
}, {
"letter": "J~mj",
"frequency": 0.00153
}, {
"letter": "K~th",
"frequency": 0.00772
}, {
"letter": "L~ws",
"frequency": 0.04025
}, {
"letter": "M~qjl",
"frequency": 0.02406
}, {
"letter": "N~i",
"frequency": 0.06749
}, {
"letter": "O~p",
"frequency": 0.07507
}, {
"letter": "P~zs",
"frequency": 0.01929
}, {
"letter": "Q~rip",
"frequency": 0.00095
}, {
"letter": "R~hi",
"frequency": 0.05987
}, {
"letter": "S~eop",
"frequency": 0.06327
}, {
"letter": "T~tl",
"frequency": 0.09056
}, {
"letter": "U~se",
"frequency": 0.02758
}, {
"letter": "V~wh",
"frequency": 0.00978
}, {
"letter": "W~jl",
"frequency": 0.0236
}, {
"letter": "X~y",
"frequency": 0.0015
}, {
"letter": "Y~ty",
"frequency": 0.01974
}, {
"letter": "Z~o",
"frequency": 0.00074
}, {
"letter": "A~q12",
"frequency": 0.08167
}, {
"letter": "B~122",
"frequency": 0.01492
}, {
"letter": "C~c2",
"frequency": 0.02782
}, {
"letter": "D~1a2",
"frequency": 0.04253
}, {
"letter": "E~d2",
"frequency": 0.12702
}, {
"letter": "F~x2",
"frequency": 0.02288
}, {
"letter": "G~v2",
"frequency": 0.02015
}, {
"letter": "H~xs2",
"frequency": 0.06094
}, {
"letter": "I~za2",
"frequency": 0.06966
}, {
"letter": "J~mj2",
"frequency": 0.00153
}, {
"letter": "K~th2",
"frequency": 0.00772
}, {
"letter": "L~ws2",
"frequency": 0.04025
}, {
"letter": "M~qjl2",
"frequency": 0.02406
}, {
"letter": "N~i2",
"frequency": 0.06749
}, {
"letter": "O~p2",
"frequency": 0.07507
}, {
"letter": "P~zs2",
"frequency": 0.01929
}, {
"letter": "Q~rip2",
"frequency": 0.00095
}, {
"letter": "R~hi2",
"frequency": 0.05987
}, {
"letter": "S~eo2p",
"frequency": 0.06327
}, {
"letter": "T~tl2",
"frequency": 0.09056
}, {
"letter": "U~se2",
"frequency": 0.02758
}, {
"letter": "V~wh2",
"frequency": 0.00978
}, {
"letter": "W~jl2",
"frequency": 0.0236
}, {
"letter": "X~y2",
"frequency": 0.0015
}, {
"letter": "Y~ty2",
"frequency": 0.01974
}, {
"letter": "Z~o2",
"frequency": 0.00074
}];
x.domain(data.map(function(d) {
return d.letter;
}));
min_x.domain(data.map(function(d) {
return d.letter;
}));
y.domain([0, d3.max(data, function(d) {
return d.frequency;
})]);
var xBrush = d3.svg.brush().x(min_x).on("brush", xBrushed);
// Add the x axis
main.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height + min_height) + ")")
.attr("clip-path", "url(#clip)")
.call(xAxis)
.selectAll(".tick text")
.call(wrap, x.rangeBand());
var x_arc = d3.svg.arc()
.outerRadius(min_height / 2)
.startAngle(0)
.endAngle(function(d, i) {
return i ? -Math.PI : Math.PI;
});
var brush_x_grab = mini_x_append.append("g")
.attr("class", "x brush")
.call(xBrush);
brush_x_grab.selectAll(".resize").append("path")
.attr("transform", "translate(0," + min_height / 2 + ")")
.attr("d", x_arc);
brush_x_grab.selectAll("rect").attr("height", min_height);
main.append("g")
.attr("class", "y axis")
.call(yAxis);
var bar = main.append("g")
.attr("clip-path", "url(#clip)")
.selectAll(".rect")
.data(data)
.enter().append("rect")
.attr("class", "rect")
.attr("x", function(d) {
return x(d.letter);
})
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d.frequency);
})
.attr("height", function(d) {
return height - y(d.frequency);
});
// Called to re-draw the bars on the main chart when the brush on the x axis
// has been altered.
function xBrushed() {
var originalRange = main_xZoom.range();
main_xZoom.domain(xBrush.empty() ? originalRange : xBrush.extent());
x.rangeRoundBands([main_xZoom(originalRange[0]), main_xZoom(originalRange[1])], .2);
// min_x.rangeRoundBands([0, x.rangeBand()], 0);
main.selectAll(".rect")
.data(data)
.attr("width", function(d) {
return x.rangeBand();
})
.attr("x", function(d) {
// alert("d is"+JSON.stringify(d));
return x(d.letter);
});
main.select("g.x.axis").call(xAxis).selectAll(".tick text").call(wrap, x.rangeBand());
};
// This comes from the example at http://bl.ocks.org/mbostock/7555321
// for wrapping long axis tick labels
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
// console.log("wrap is"+JSON.stringify(word));
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
};
// Set the initial brush selections.
// svg.select(".x.brush").call(xBrush.extent(main_xZoom.domain()));
svg.select(".x.brush").call(xBrush.extent([0, 110]));
//svg.select(".y.brush").call(yBrush.extent(mini_y0.domain()));
// Forces a refresh of the brushes and main chart based
// on the selected extents.
xBrushed();
//yBrushed();
function type(d) {
d.frequency = +d.frequency;
return d;
}

g.axis path,
g.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
g.brush rect.extent {
fill-opacity: 0.2;
}
.resize path {
fill-opacity: 0.2;
}
.bar {
fill: steelblue;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;
修改强>
我发现通过将您拥有的json数据转换为此link使用的相同格式,可以更轻松地实现此功能。
var nestedData;
var main_margin = {
top: 25,
right: 80,
bottom: 60,
left: 70
},
width = 900 - main_margin.left - main_margin.right,
mini_x_height = 10;
main_height = 525 - main_margin.top - main_margin.bottom,
mini_x_margin = {
top: main_height,
right: main_margin.right + 10,
bottom: main_margin.bottom,
left: main_margin.left + 10
},
mini_x_width = 900 - mini_x_margin.left - mini_x_margin.right,
mini_y_margin = {
top: main_margin.top + 10,
right: 0,
bottom: main_margin.bottom + 10,
left: 0
},
mini_y_width = 10,
mini_y_height = 525 - mini_y_margin.top - mini_y_margin.bottom;
var color = d3.scale.category10();
// x0 is the groups scale on the x axis.
var main_x0 = d3.scale.ordinal().rangeRoundBands([0, width], 0.2);
var mini_x0 = d3.scale.ordinal().rangeRoundBands([0, width], 0.2);
var main_xZoom = d3.scale.linear()
.range([0, width])
.domain([0, width]);
// x1 is the series scale on the x axis.
var main_x1 = d3.scale.ordinal();
var mini_x1 = d3.scale.ordinal();
// y is the value scale on the y axis.
var main_y0 = d3.scale.linear().range([main_height, 0]);
var mini_y0 = d3.scale.linear().range([mini_y_height, 0]);
var main_xAxis = d3.svg.axis()
.scale(main_x0)
.orient("bottom");
var mini_xAxis = d3.svg.axis()
.scale(mini_x0)
.orient("bottom");
var main_yAxis = d3.svg.axis()
.scale(main_y0)
.orient("left");
var mini_yAxis = d3.svg.axis()
.scale(mini_y0)
.orient("left");
var svg = d3.select("#chart").append("svg")
.attr("width", width + main_margin.left + main_margin.right)
.attr("height", main_height + main_margin.top + main_margin.bottom);
var main = svg.append("g")
.attr("transform", "translate(" + main_margin.left + "," + main_margin.top + ")");
main.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", main_height + mini_x_height + main_margin.bottom);
var mini_x = svg.append("g")
.attr("transform", "translate(" + mini_x_margin.left + "," + (main_margin.top + main_height) + ")")
.attr("width", mini_x_width);
var mini_y = svg.append("g")
.attr("width", mini_y_width)
.attr("transform", "translate(" + (main_margin.left - mini_y_width) + ", " + mini_y_margin.top + ")")
.attr("height", mini_y_height);
var data = [{
key: 'Mechanical',
values: [{
key: 'Gear',
value: 11
}, {
key: 'Bearing',
value: 8
}, {
key: 'Motor',
value: 3
}, {
key: 'Bearing',
value: 8
}, {
key: 'Motor',
value: 3
}, {
key: 'Bearing',
value: 8
}, {
key: 'Motor',
value: 3
}]
}, {
key: 'Electrical',
values: [{
key: 'Switch',
value: 19
}, {
key: 'Plug',
value: 12
}, {
key: 'Cord',
value: 11
}, {
key: 'Fuse',
value: 3
}, {
key: 'Bulb',
value: 2
}]
}, {
key: 'Hydraulic',
values: [{
key: 'Pump',
value: 4
}, {
key: 'Leak',
value: 3
}, {
key: 'Seals',
value: 1
},{
key: 'Switch',
value: 19
}, {
key: 'Plug',
value: 12
}, {
key: 'Cord',
value: 11
}, {
key: 'Fuse',
value: 3
}, {
key: 'Bulb',
value: 2
}]
}];
var res = [];
data.forEach(function(d){
res.push(d.values.map(function(o){
o.item=o.key;
o.subject = d.key; return o; }));
});
data = [].concat.apply([], res);
res.sort(function(a,b){ return a.subject<b.subject });
//console.log(data);
var seriesValues = d3.set(data.map(function(x) {
return x.item;
})).values().sort(d3.ascending);
nestedData = d3.nest()
.key(function(d) {
return d.subject;
})
.sortKeys(d3.ascending)
.sortValues(function(a, b) {
return a.item - b.item;
})
.entries(data);
var groupValues = d3.set(data.map(function(x) {
return x.subject;
})).values();
// Define the axis domains
main_x0.domain(groupValues);
mini_x0.domain(groupValues);
main_x1.domain(seriesValues).rangeRoundBands([0, main_x0.rangeBand()], 0);
mini_x1.domain(seriesValues).rangeRoundBands([0, main_x0.rangeBand()], 0);
main_y0.domain([0, d3.max(nestedData, function(d) {
return d3.max(d.values, function(d) {
return d.value;
});
})]);
mini_y0.domain(main_y0.domain());
var xBrush = d3.svg.brush().x(mini_x0).on("brush", xBrushed);
var yBrush = d3.svg.brush().y(mini_y0).on("brush", yBrushed);
// Add the x axis
main.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (main_height + mini_x_height) + ")")
.attr("clip-path", "url(#clip)")
.call(main_xAxis)
.selectAll(".tick text")
.call(wrap, main_x0.rangeBand());
// Add the y axis
main.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + (-mini_y_width) + ", 0)")
.call(main_yAxis)
.append("text")
.attr("transform", "rotate(-90), translate(" + -(main_height / 2) + ", " + -(mini_y_width + main_margin.left - 20) + ")")
.attr("dy", ".71em")
.style("text-anchor", "middle")
.text("value");
var x_arc = d3.svg.arc()
.outerRadius(mini_x_height / 2)
.startAngle(0)
.endAngle(function(d, i) {
return i ? -Math.PI : Math.PI;
});
var brush_x_grab = mini_x.append("g")
.attr("class", "x brush")
.call(xBrush);
brush_x_grab.selectAll(".resize").append("path")
.attr("transform", "translate(0," + mini_x_height / 2 + ")")
.attr("d", x_arc);
brush_x_grab.selectAll("rect").attr("height", mini_x_height);
var y_arc = d3.svg.arc()
.outerRadius(mini_y_width / 2)
.startAngle(-(Math.PI / 2))
.endAngle(function(d, i) {
return i ? -((3 * Math.PI) / 2) : ((Math.PI) / 2);
});
var brush_y_grab = mini_y.append("g")
.attr("class", "y brush")
.call(yBrush);
brush_y_grab.selectAll(".resize").append("path")
.attr("transform", "translate(" + (mini_y_width / 2) + ", 0)")
.attr("d", y_arc);
brush_y_grab.selectAll("rect").attr("width", mini_y_width);
// Create the main bars
var bar = main.selectAll(".bars")
.data(nestedData)
.enter().append("g")
.attr("clip-path", "url(#clip)")
.attr("class", function(d) {
return d.key + "-group bar";
});
bar.selectAll("rect")
.data(function(d) {
return d.values;
})
.enter().append("rect")
.attr("class", function(d) {
return d.item;
})
.attr("transform", function(d) {
return "translate(" + main_x0(d.subject) + ",0)";
})
.attr("width", function(d) {
return main_x1.rangeBand();
})
.attr("x", function(d) {
return main_x1(d.item);
})
.attr("y", function(d) {
return main_y0(d.value);
})
.attr("height", function(d) {
return main_height - main_y0(d.value);
})
.style("fill", function(d) {
return color(d.item);
});
// Draws the series items onto a legend
var legend = svg.selectAll(".legend")
.data(seriesValues.slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(50," + (main_margin.top + (i * 20)) + ")";
});
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {
return d;
});
// Called to re-draw the bars on the main chart when the brush on the x axis
// has been altered.
function xBrushed() {
var originalRange = main_xZoom.range();
main_xZoom.domain(xBrush.empty() ? originalRange : xBrush.extent());
main_x0.rangeRoundBands([main_xZoom(originalRange[0]), main_xZoom(originalRange[1])], .1);
main_x1.rangeRoundBands([0, main_x0.rangeBand()], 0);
bar.selectAll("rect")
.attr("transform", function(d) {
return "translate(" + main_x0(d.subject) + ",0)";
})
.attr("width", function(d) {
return main_x1.rangeBand();
})
.attr("x", function(d) {
return main_x1(d.item);
});
main.select("g.x.axis").call(main_xAxis).selectAll(".tick text").call(wrap, main_x0.rangeBand());
};
// Called to re-draw the bars on the main chart when the
// brush on the y axis has been altered.
function yBrushed() {
main_y0.domain(yBrush.empty() ? mini_y0.domain() : yBrush.extent());
bar.selectAll("rect")
.attr("y", function(d) {
return main_y0(d.value);
})
.attr("height", function(d) {
return main_height - main_y0(d.value);
});
main.select("g.y.axis").call(main_yAxis);
};
// This comes from the example at http://bl.ocks.org/mbostock/7555321
// for wrapping long axis tick labels
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
};
// Set the initial brush selections.
// svg.select(".x.brush").call(xBrush.extent(main_xZoom.domain()));
svg.select(".x.brush").call(xBrush.extent([0, 610]));
svg.select(".y.brush").call(yBrush.extent(mini_y0.domain()));
// Forces a refresh of the brushes and main chart based
// on the selected extents.
xBrushed();
yBrushed();
//});
&#13;
g.axis path,
g.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
g.brush rect.extent {
fill-opacity: 0.2;
}
.resize path {
fill-opacity: 0.2;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="chart"></div>
&#13;