我需要设计一个d3组件,如下图所示。
我引用了this link中的现有代码示例,并对其进行了修改以创建类似这样的内容。
左更改轴的宽度,我尝试通过更改 domain class 的 stroke-width 属性来尝试。但是,我结束了这样的事情。
问题:
问题:
我正在为此使用d3 v4。还有我的final code is here的jsfiddle。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<style>
.tick{
visibility:hidden;
}
.domain {
stroke: grey;
stroke-width:10px;
stroke-linecap: round;
}
.selection {
fill:red
}
</style>
</head>
<body>
<div style="margin-left: 20px;margin-top: 20px;">
<span></span> to <span></span>
</div>
<script>
var margin = 20,
width = 400 - margin * 2,
height = 15;
// v3 = var x = d3.scale.linear()
var x = d3.scaleLinear()
.domain([0,100])
.range([0, width]);
/*
var brush = d3.svg.brush()
.x(x)
.extent([20, 50]);
*/
var brush = d3.brushX()
.extent([[0,0], [width,height]])
.on("brush", brushed);
var svg = d3.select("body").append("svg")
.attr("width", width + margin * 2)
.attr("height", 100)
.append("g")
.attr("transform", "translate(" + margin + "," + margin + ")")
.call(d3.axisBottom()
.scale(x)
.tickSize(0));
var brushg = svg.append("g")
.attr("class", "brush")
.call(brush)
// left circle
var left_text = brushg.append("text")
.attr("class", "label")
.attr("fill", "black")
.attr("text-anchor", "middle")
.text("hello world")
.attr("transform", "translate(0," + (35) + ")")
var right_text = brushg.append("text")
.attr("class", "label")
.attr("fill", "black")
.attr("text-anchor", "middle")
.text("hello world")
.attr("transform", "translate(0," + (35) + ")")
/*
Height of the brush's rect is now
generated by brush.extent():
brushg.selectAll("rect")
.attr("height", height);
*/
function brushed() {
/*
The brush attributes are no longer stored
in the brush itself, but rather in the
element it is brushing. That's where much of
the confusion around v4's brushes seems to be.
The new method is a little difficult to adapt
to, but seems more efficient. I think much of
this confusion comes from the fact that
brush.extent() still exists, but means
something completely different.
Instead of calling brush.extent() to get the
range of the brush, call
d3.brushSelection(node) on what is being
brushed.
d3.select('#start-number')
.text(Math.round(brush.extent()[0]));
d3.select('#end-number')
.text(Math.round(brush.extent()[1]));
*/
var range = d3.brushSelection(this)
.map(x.invert);
console.log('range->'+range)
d3.selectAll("span")
.text(function(d, i) {
console.log(Math.round(range[i]))
return Math.round(range[i])
})
left_text.attr("x", x(range[0]));
left_text.text(Math.round(range[0]));
right_text.attr("x", x(range[1]));
right_text.text(Math.round(range[1]));
d3.selectAll("rect").attr("dy", "-5em")
}
// v3: brushed();
brush.move(brushg, [20, 40].map(x));
</script>
</body>
</html>
答案 0 :(得分:2)
轴和画笔实际上完全对齐!
如果将stroke-width
设置为1px,则可以看到以下内容:
.as-console-wrapper { max-height: 30% !important;}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<style>
.tick{
visibility:hidden;
}
.domain {
stroke: grey;
stroke-width:1px;
stroke-linecap: round;
}
.selection {
fill:red
}
</style>
</head>
<body>
<div style="margin-left: 20px;margin-top: 20px;">
<span></span> to <span></span>
</div>
<script>
var margin = 20,
width = 400 - margin * 2,
height = 15;
// v3 = var x = d3.scale.linear()
var x = d3.scaleLinear()
.domain([0,100])
.range([0, width]);
/*
var brush = d3.svg.brush()
.x(x)
.extent([20, 50]);
*/
var brush = d3.brushX()
.extent([[0,0], [width,height]])
.on("brush", brushed);
var svg = d3.select("body").append("svg")
.attr("width", width + margin * 2)
.attr("height", 100)
.append("g")
.attr("transform", "translate(" + margin + "," + margin + ")")
.call(d3.axisBottom()
.scale(x)
.tickSize(0));
var brushg = svg.append("g")
.attr("class", "brush")
.call(brush)
// left circle
var left_text = brushg.append("text")
.attr("class", "label")
.attr("fill", "black")
.attr("text-anchor", "middle")
.text("hello world")
.attr("transform", "translate(0," + (35) + ")")
var right_text = brushg.append("text")
.attr("class", "label")
.attr("fill", "black")
.attr("text-anchor", "middle")
.text("hello world")
.attr("transform", "translate(0," + (35) + ")")
/*
Height of the brush's rect is now
generated by brush.extent():
brushg.selectAll("rect")
.attr("height", height);
*/
function brushed() {
/*
The brush attributes are no longer stored
in the brush itself, but rather in the
element it is brushing. That's where much of
the confusion around v4's brushes seems to be.
The new method is a little difficult to adapt
to, but seems more efficient. I think much of
this confusion comes from the fact that
brush.extent() still exists, but means
something completely different.
Instead of calling brush.extent() to get the
range of the brush, call
d3.brushSelection(node) on what is being
brushed.
d3.select('#start-number')
.text(Math.round(brush.extent()[0]));
d3.select('#end-number')
.text(Math.round(brush.extent()[1]));
*/
var range = d3.brushSelection(this)
.map(x.invert);
console.log('range->'+range)
d3.selectAll("span")
.text(function(d, i) {
console.log(Math.round(range[i]))
return Math.round(range[i])
})
left_text.attr("x", x(range[0]));
left_text.text(Math.round(range[0]));
right_text.attr("x", x(range[1]));
right_text.text(Math.round(range[1]));
d3.selectAll("rect").attr("dy", "-5em")
}
// v3: brushed();
brush.move(brushg, [20, 40].map(x));
</script>
</body>
</html>
那么,这是怎么回事?问题是,当您告诉浏览器走一条线(在这种情况下,这是一条路径,但没有关系)并将其笔触增加到例如100像素时,它将增加一侧的50像素和50的像素像素到另一边。因此,该粗轴的中间恰好在画笔矩形的顶部。
这里有几种解决方案,例如绘制矩形。但是,如果您想采用增加.domain
笔触宽度的方法,那么让我们打破选择,然后将轴stroke-width
的一半向下移动(这里我将宽度增加到20像素,因此更容易看到对齐方式):
.as-console-wrapper { max-height: 30% !important;}
<!DOCTYPE html>
<meta charset="utf-8">
<script src="//d3js.org/d3.v4.min.js"></script>
<!--
axes and brushes are styled out of the box,
so this is no longer needed
<style>
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.brush .extent {
fill-opacity: .125;
shape-rendering: crispEdges;
}
</style>
-->
<style>
.tick {
visibility: hidden;
}
.domain {
stroke: grey;
stroke-width: 20px;
stroke-linecap: round;
}
.selection {
fill: red
}
</style>
<body>
<div style="margin-left: 20px;margin-top: 20px;">
<span></span> to <span></span>
</div>
</body>
<script>
var margin = 20,
width = 400 - margin * 2,
height = 20;
// v3 = var x = d3.scale.linear()
var x = d3.scaleLinear()
.domain([0, 100])
.range([0, width]);
/*
var brush = d3.svg.brush()
.x(x)
.extent([20, 50]);
*/
var brush = d3.brushX()
.extent([
[0, 0],
[width, height]
])
.on("brush", brushed);
var svg = d3.select("body").append("svg")
.attr("width", width + margin * 2)
.attr("height", 100);
svg.append("g")
.attr("transform", "translate(" + margin + "," + (margin + 10) + ")")
.call(d3.axisBottom()
.scale(x)
.tickSize(0));
var brushg = svg.append("g")
.attr("transform", "translate(" + margin + "," + margin + ")")
.attr("class", "brush")
.call(brush)
// left circle
var left_text = brushg.append("text")
.attr("class", "label")
.attr("fill", "black")
.attr("text-anchor", "middle")
.text("hello world")
.attr("transform", "translate(0," + (35) + ")")
var right_text = brushg.append("text")
.attr("class", "label")
.attr("fill", "black")
.attr("text-anchor", "middle")
.text("hello world")
.attr("transform", "translate(0," + (35) + ")")
/*
Height of the brush's rect is now
generated by brush.extent():
brushg.selectAll("rect")
.attr("height", height);
*/
function brushed() {
/*
The brush attributes are no longer stored
in the brush itself, but rather in the
element it is brushing. That's where much of
the confusion around v4's brushes seems to be.
The new method is a little difficult to adapt
to, but seems more efficient. I think much of
this confusion comes from the fact that
brush.extent() still exists, but means
something completely different.
Instead of calling brush.extent() to get the
range of the brush, call
d3.brushSelection(node) on what is being
brushed.
d3.select('#start-number')
.text(Math.round(brush.extent()[0]));
d3.select('#end-number')
.text(Math.round(brush.extent()[1]));
*/
var range = d3.brushSelection(this)
.map(x.invert);
console.log('range->' + range)
d3.selectAll("span")
.text(function(d, i) {
console.log(Math.round(range[i]))
return Math.round(range[i])
})
left_text.attr("x", x(range[0]));
left_text.text(Math.round(range[0]));
right_text.attr("x", x(range[1]));
right_text.text(Math.round(range[1]));
d3.selectAll("rect").attr("dy", "-5em")
}
// v3: brushed();
brush.move(brushg, [20, 40].map(x));
</script>
答案 1 :(得分:0)
轴上的路径是闭合的形状,并且抚摸会产生问题。另外,您也不想打勾,为什么不自己绘制“轴”。然后,将正确绘制圆形边缘。
var svg = d3.select("body").append("svg")
.attr("width", width + margin * 2)
.attr("height", 100)
.append("g")
.attr("transform", "translate(" + margin + "," + margin + ")")
// .call(d3.axisBottom()
// .scale(x)
// .tickSize(0))
;
svg.append("path")
.attr("class", "domain")
.attr("d", `M${x(0)},0 ${x(100)},0`);
您必须将笔刷范围与描边的路径表面匹配
var margin = 20,
width = 400 - margin * 2,
height = 10; // same as stroke width
var brush = d3.brushX()
.extent([[0,-height*0.5], [width,height*0.5]])
.on("brush", brushed);
dy
属性没有目的
//d3.selectAll("rect").attr("dy", "-5em")
设置所选内容的填充不透明度
.selection {
fill:red;
fill-opacity: 1;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<style>
.tick{
visibility:hidden;
}
.domain {
stroke: grey;
stroke-width:10;
stroke-linecap: round;
}
.selection {
fill:red;
fill-opacity: 1;
}
</style>
</head>
<body>
<div style="margin-left: 20px;margin-top: 20px;">
<span></span> to <span></span>
</div>
<script>
var margin = 20,
width = 400 - margin * 2,
height = 10; // same as stroke width
// v3 = var x = d3.scale.linear()
var x = d3.scaleLinear()
.domain([0,100])
.range([0, width]);
/*
var brush = d3.svg.brush()
.x(x)
.extent([20, 50]);
*/
var brush = d3.brushX()
.extent([[0,-height*0.5], [width,height*0.5]])
.on("brush", brushed);
var svg = d3.select("body").append("svg")
.attr("width", width + margin * 2)
.attr("height", 100)
.append("g")
.attr("transform", "translate(" + margin + "," + margin + ")")
// .call(d3.axisBottom()
// .scale(x)
// .tickSize(0))
;
svg.append("path")
.attr("class", "domain")
.attr("d", `M${x(0)},0 ${x(100)},0`);
var brushg = svg.append("g")
.attr("class", "brush")
.call(brush)
// left circle
var left_text = brushg.append("text")
.attr("class", "label")
.attr("fill", "black")
.attr("text-anchor", "middle")
.text("hello world")
.attr("transform", "translate(0," + (35) + ")")
var right_text = brushg.append("text")
.attr("class", "label")
.attr("fill", "black")
.attr("text-anchor", "middle")
.text("hello world")
.attr("transform", "translate(0," + (35) + ")")
/*
Height of the brush's rect is now
generated by brush.extent():
brushg.selectAll("rect")
.attr("height", height);
*/
function brushed() {
/*
The brush attributes are no longer stored
in the brush itself, but rather in the
element it is brushing. That's where much of
the confusion around v4's brushes seems to be.
The new method is a little difficult to adapt
to, but seems more efficient. I think much of
this confusion comes from the fact that
brush.extent() still exists, but means
something completely different.
Instead of calling brush.extent() to get the
range of the brush, call
d3.brushSelection(node) on what is being
brushed.
d3.select('#start-number')
.text(Math.round(brush.extent()[0]));
d3.select('#end-number')
.text(Math.round(brush.extent()[1]));
*/
var range = d3.brushSelection(this)
.map(x.invert);
//console.log('range->'+range)
d3.selectAll("span")
.text(function(d, i) {
//console.log(Math.round(range[i]))
return Math.round(range[i])
})
left_text.attr("x", x(range[0]));
left_text.text(Math.round(range[0]));
right_text.attr("x", x(range[1]));
right_text.text(Math.round(range[1]));
//d3.selectAll("rect").attr("dy", "-5em")
}
// v3: brushed();
brush.move(brushg, [20, 40].map(x));
</script>
</body>
</html>