我正在使用d3.js版本5,并绘制了一个时间轴,以秒为单位显示持续时间。此时间轴仅显示整个持续时间的60秒间隔,但可以向左/向右平移/缩放以在时间轴中导航。一个人也应该能够使用画笔突出显示多个时间间隔。绘制多个笔刷的代码基于https://bl.ocks.org/NGuernse/4c75a051154cbe08bf80cddefefae22a / https://gist.github.com/NGuernse/4c75a051154cbe08bf80cddefefae22a
现在的问题是,一旦添加代码以在时间轴上绘制画笔,我就无法在时间轴上执行缩放/平移。
类似于上面的链接,我添加了一个禁用画笔功能的开关,作为回报,它还应该启用缩放功能。但是,我只能禁用/启用涂刷功能,而不能重新启用缩放功能。
var margin = {top: 200, right: 40, bottom: 200, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// Zoom
var zoom = d3.zoom()
.extent([[0, 0], [width, height]])
.scaleExtent([1, 10])
.translateExtent([[0, 0], [width, height]])
.on('zoom', zoomed);
// Scale
var xScale = d3.scaleTime()
.domain([0, 137 * 1000])//domain of [00:00 - 02:17] in seconds
.range([0, width]);
// Axis
var xAxis = d3.axisBottom(xScale)
.ticks(d3.timeSecond.every(1))
.tickSize(-height)
.tickFormat(d3.timeFormat('%M:%S'))
// Main svg
var svg = d3.select('#block')
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
var rect = svg
.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "white")
.call(zoom);
// axis
var axis = svg.append("g")
var formatSeconds = d3.timeFormat("%S");
// Jump to interval [00:00, 01:00] at start
startTransition();
var ticks = d3.selectAll(".tick text");
// Only display a tick-label if second is dividable by 5
ticks.attr("class", function (d, i) {
var s = formatSeconds(d)
if (s % 5 !== 0) d3.select(this).remove();
});
function zoomed() {
var transform = d3.event.transform;
var xNewScale = transform.rescaleX(xScale);
xAxis.scale(xNewScale);
axis.call(xAxis);
ticks = d3.selectAll(".tick text")
// readjust labels in case of zooming
ticks.attr("class", function (d, i) {
var s = formatSeconds(d)
if (s % 5 !== 0) d3.select(this).remove();
});
}
function startTransition() {
// to jump to [00:00,01:00] we need to calculate a new scale factor (k)...
var k = (xScale(137 * 1000) - xScale(0)) / (xScale(60 * 1000) - xScale(0));
// ...and then a translate to [01:00, 00:00]
var tx = 0 //- (k * xScale(60));
var t = d3.zoomIdentity.translate(tx, 0).scale(k);
// Rescale the axis
xAxis.scale(t.rescaleX(xScale));
axis
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.attr("text-anchor", "middle")
.selectAll("text")
.attr("x", 0)
rect.call(zoom.transform, t);
}
var gBrushes = svg.append('g')
.attr("height", height)
.attr("width", width)
.attr("fill", "none")
.attr("transform", "translate(" + 0 + "," + 0 + ")")
.attr("class", "brushes");
var mySelections = {}
var brushCount = 40;
var brushes = [];
newBrush()
drawBrushes()
function newBrush() {
console.log('newBrush')
var brush = d3.brushX()
.extent([[0, 0], [width, height]])
.on("start", brushstart)
.on("brush", brushed)
.on("end", brushend);
brushes.push({id: brushes.length, brush: brush});
function brushstart() {
// Brush start here
};
function brushed() {
let selection = d3.event.selection.map(xScale.invert);
mySelections[this.id] = {start: selection[0], end: selection[1]};
// console.log("Selections are: ", mySelections);
}
function brushend() {
// Figure out if our latest brush has a selection
var lastBrushID = brushes[brushes.length - 1].id;
var lastBrush = document.getElementById('brush-' + lastBrushID);
var selection = d3.brushSelection(lastBrush);
if (!d3.event.sourceEvent) return; // Only transition after input.
if (!d3.event.selection) return; // Ignore empty selections.
var d0 = d3.event.selection.map(xScale.invert),
d1 = d0.map(d3.timeSecond);
// If empty when rounded, use floor & ceil instead.
if (d1[0] >= d1[1]) {
d1[0] = d3.timeSecond.floor(d0[0]);
d1[1] = d3.timeSecond.offset(d1[0]);
}
d3.select(this).transition().call(d3.event.target.move, d1.map(xScale));
// If it does, that means we need another one
if (brushes.length < brushCount && selection && selection[0] !== selection[1]) {
newBrush();
}
// Always draw brushes
drawBrushes();
}
}
function drawBrushes() {
var brushSelection = gBrushes
.selectAll('.brush')
.data(brushes, function (d) {
return d.id
});
// Set up new brushes
brushSelection.enter()
.insert("g", '.brush')
.attr('class', 'brush')
.attr('id', function (brush) {
return "brush-" + brush.id;
})
.each(function (brushObject) {
// call the brush
brushObject.brush(d3.select(this));
});
brushSelection
.each(function (brushObject) {
d3.select(this)
.attr('class', 'brush')
.selectAll('.overlay')
.style('pointer-events', function () {
var brush = brushObject.brush;
if (brushObject.id === brushes.length - 1 && brush !== undefined) {
return 'all';
} else {
return 'none';
}
});
})
brushSelection.exit()
.remove();
}
let toggle = true;
document.getElementById('disable-btn').addEventListener('click', () => {
toggleBrush();
});
var toggleBrush = function () {
toggle = !toggle;
if (!toggle) {
document.getElementById('disable-btn').innerHTML = '<i class="fa fa-toggle-off"></i> Brushes Off';
for (let i = 0, len = brushes.length; i < len; i++) {
d3.select('#brush-' + i).on('.brush', null);
}
d3.select('.brushes').selectAll('.selection').style("cursor", "initial");
d3.select('.brushes').selectAll('.overlay').style("cursor", "initial");
rect.on(".zoom", null)
} else {
document.getElementById('disable-btn').innerHTML = '<i class="fa fa-toggle-on"></i> Brushes On';
for (let i = 0, len = brushes.length; i < len; i++) {
brushes[i].brush(d3.select('#brush-' + i));
}
rect.call(zoom)
startTransition();
d3.select('.brushes').selectAll('.selection').style("cursor", "move");
d3.select('.brushes').selectAll('.overlay').style("cursor", "crosshair");
}
};
这是jsfiddle,仅包含具有缩放/平移功能的时间轴:https://jsfiddle.net/prw67fu3/
还有指向当前小提琴的链接,其中包括绘制画笔和启用/禁用画笔的代码。 https://jsfiddle.net/gb8m4tr3/
将切换开关设置为关闭画笔后,应该可以在时间轴上缩放/平移,而不再能够绘制画笔。但是,添加画笔代码后,我不知道如何重新激活缩放功能。
非常感谢您!