我试图在24小时内显示线图中的数据。d3 v4如何在x缩放线图上限制左/右平移
我创建了一个D3 V4线图,并已成功:
- 应用的X轴仅变焦,并重绘所有元素的
- 用于clippath保持从我的数据显示,左/低于我的轴线
我的问题是现在试图将translateExtent应用到我的d3.zoom。它似乎阻止我在缩放前左/右平移,但是当我缩放时,它似乎在我的数据集的结尾和开始半小时左右截断或添加。
我认为我需要做的就是向d3.zoom声明中添加一些代码,也许还会在我的缩放功能中添加一些内容。
我曾尝试添加.translateExtent([[0,0],[W,H]])到我d3.zoom代码和许多其它变型,其中包括减法/加法我的边距等
看起来像添加如下的w“2 *边距会在初始点击时跳过跳跃(这会让我感到困惑,因为我认为第一个坐标组会影响我的图形的左侧平移),但是一旦放大,它就会让我从摇保留超出一天(耶)的开始,但让我泛一点过去一天(BOO)结束。
var zoomCall = d3.zoom()
.scaleExtent([1, 24]) // no zooming out (1x), only zoom to 1hr (24x)
.translateExtent([[0,0],[w+2*margin,h]])
.on("zoom", zoom);
我还想到在MUL我的变焦功能通过d3.event.transform.k tiplying我的宽度程度应该是缩放级别,我相信,但它不给我我想要的东西之一:
function zoom() {
zoomCall.translateExtent([[0,0],[w+margin*2*d3.event.transform.k, h]]);
还有有时是离开了我的数据的转换或在添加translateExtent代码后单击图形一次右边20px。
window.onload = function() {
// parse the date/time functions
var formatTime = d3.timeFormat("%H:%M"),
formatMinutes = function(d) {
return formatTime(new Date(2012, 0, 1, 0, d));
};
// Get and Prepare Data for gap_array and range_array
var count_data = [
{
"date_time":"\/Date(1494864780000)\/",
"count":14
},
{
"date_time":"\/Date(1494864780000)\/",
"count":11
},
{
"date_time":"\/Date(1494864780000)\/",
"count":25
},
{
"date_time":"\/Date(1494864840000)\/",
"count":31
},
{
"date_time":"\/Date(1494864840000)\/",
"count":53
},
{
"date_time":"\/Date(1494864840000)\/",
"count":56
},
{
"date_time":"\/Date(1494864900000)\/",
"count":57
},
{
"date_time":"\/Date(1494864960000)\/",
"count":68
},
{
"date_time":"\/Date(1494865020000)\/",
"count":69
},
{
"date_time":"\/Date(1494865020000)\/",
"count":70
},
{
"date_time":"\/Date(1494865140000)\/",
"count":65
},
{
"date_time":"\/Date(1494865200000)\/",
"count":68
},
{
"date_time":"\/Date(1494865320000)\/",
"count":68
},
{
"date_time":"\/Date(1494865380000)\/",
"count":68
},
{
"date_time":"\/Date(1494865500000)\/",
"count":70
},
{
"date_time":"\/Date(1494865560000)\/",
"count":67
},
{
"date_time":"\/Date(1494865680000)\/",
"count":61
},
{
"date_time":"\/Date(1494865740000)\/",
"count":61
},
{
"date_time":"\/Date(1494865860000)\/",
"count":67
},
{
"date_time":"\/Date(1494865920000)\/",
"count":67
},
{
"date_time":"\/Date(1494866040000)\/",
"count":67
},
{
"date_time":"\/Date(1494866100000)\/",
"count":67
},
{
"date_time":"\/Date(1494866220000)\/",
"count":68
},
{
"date_time":"\/Date(1494866280000)\/",
"count":66
},
{
"date_time":"\/Date(1494866400000)\/",
"count":67
},
{
"date_time":"\/Date(1494866460000)\/",
"count":67
},
{
"date_time":"\/Date(1494866580000)\/",
"count":68
},
{
"date_time":"\/Date(1494866640000)\/",
"count":66
},
{
"date_time":"\/Date(1494866760000)\/",
"count":67
},
{
"date_time":"\/Date(1494866820000)\/",
"count":67
},
{
"date_time":"\/Date(1494866940000)\/",
"count":67
},
{
"date_time":"\/Date(1494867000000)\/",
"count":67
},
{
"date_time":"\/Date(1494867120000)\/",
"count":53
},
{
"date_time":"\/Date(1494867180000)\/",
"count":66
},
{
"date_time":"\/Date(1494867300000)\/",
"count":72
},
{
"date_time":"\/Date(1494867360000)\/",
"count":67
},
{
"date_time":"\/Date(1494867480000)\/",
"count":69
},
{
"date_time":"\/Date(1494867540000)\/",
"count":70
},
{
"date_time":"\/Date(1494867660000)\/",
"count":61
},
{
"date_time":"\/Date(1494867720000)\/",
"count":28
},
{
"date_time":"\/Date(1494867720000)\/",
"count":10
},
{
"date_time":"\/Date(1494867840000)\/",
"count":60
},
{
"date_time":"\/Date(1494867900000)\/",
"count":60
},
{
"date_time":"\/Date(1494868020000)\/",
"count":50
},
{
"date_time":"\/Date(1494868020000)\/",
"count":42
},
{
"date_time":"\/Date(1494868140000)\/",
"count":63
},
{
"date_time":"\/Date(1494868200000)\/",
"count":63
},
{
"date_time":"\/Date(1494868320000)\/",
"count":63
},
{
"date_time":"\/Date(1494868380000)\/",
"count":61
},
{
"date_time":"\/Date(1494868500000)\/",
"count":63
},
{
"date_time":"\/Date(1494868560000)\/",
"count":44
},
{
"date_time":"\/Date(1494868560000)\/",
"count":14
},
{
"date_time":"\/Date(1494868680000)\/",
"count":35
},
{
"date_time":"\/Date(1494868740000)\/",
"count":73
},
{
"date_time":"\/Date(1494868860000)\/",
"count":63
},
{
"date_time":"\/Date(1494868920000)\/",
"count":63
},
{
"date_time":"\/Date(1494869040000)\/",
"count":58
},
{
"date_time":"\/Date(1494869100000)\/",
"count":63
},
{
"date_time":"\/Date(1494869220000)\/",
"count":63
},
{
"date_time":"\/Date(1494869280000)\/",
"count":62
},
{
"date_time":"\/Date(1494869400000)\/",
"count":62
},
{
"date_time":"\/Date(1494869460000)\/",
"count":63
},
{
"date_time":"\/Date(1494869580000)\/",
"count":63
},
{
"date_time":"\/Date(1494869640000)\/",
"count":55
},
{
"date_time":"\/Date(1494869700000)\/",
"count":63
},
{
"date_time":"\/Date(1494869820000)\/",
"count":63
},
{
"date_time":"\/Date(1494869880000)\/",
"count":58
},
{
"date_time":"\/Date(1494869880000)\/",
"count":58
},
{
"date_time":"\/Date(1494869880000)\/",
"count":58
},
{
"date_time":"\/Date(1494870000000)\/",
"count":35
},
{
"date_time":"\/Date(1494870060000)\/",
"count":43
},
{
"date_time":"\/Date(1494870120000)\/",
"count":53
},
{
"date_time":"\/Date(1494870180000)\/",
"count":0
},
{
"date_time":"\/Date(1494870180000)\/",
"count":6
},
{
"date_time":"\/Date(1494870180000)\/",
"count":8
},
{
"date_time":"\/Date(1494870240000)\/",
"count":0
},
{
"date_time":"\/Date(1494870240000)\/",
"count":4
},
{
"date_time":"\/Date(1494870240000)\/",
"count":0
},
{
"date_time":"\/Date(1494870240000)\/",
"count":6
},
{
"date_time":"\/Date(1494870300000)\/",
"count":0
},
{
"date_time":"\/Date(1494870300000)\/",
"count":6
},
{
"date_time":"\/Date(1494870300000)\/",
"count":15
},
{
"date_time":"\/Date(1494870300000)\/",
"count":14
},
{
"date_time":"\/Date(1494870300000)\/",
"count":22
},
{
"date_time":"\/Date(1494870360000)\/",
"count":27
},
{
"date_time":"\/Date(1494870420000)\/",
"count":63
},
{
"date_time":"\/Date(1494870540000)\/",
"count":63
},
{
"date_time":"\/Date(1494870600000)\/",
"count":67
},
{
"date_time":"\/Date(1494870720000)\/",
"count":63
},
{
"date_time":"\/Date(1494870780000)\/",
"count":63
},
{
"date_time":"\/Date(1494870900000)\/",
"count":54
},
{
"date_time":"\/Date(1494870900000)\/",
"count":0
},
{
"date_time":"\/Date(1494870900000)\/",
"count":6
},
{
"date_time":"\/Date(1494870960000)\/",
"count":15
},
{
"date_time":"\/Date(1494871020000)\/",
"count":13
},
{
"date_time":"\/Date(1494871020000)\/",
"count":0
},
{
"date_time":"\/Date(1494871080000)\/",
"count":0
},
{
"date_time":"\/Date(1494871200000)\/",
"count":0
},
{
"date_time":"\/Date(1494871260000)\/",
"count":0
},
{
"date_time":"\/Date(1494871380000)\/",
"count":0
},
{
"date_time":"\/Date(1494871440000)\/",
"count":0
},
{
"date_time":"\/Date(1494871560000)\/",
"count":0
},
{
"date_time":"\/Date(1494871620000)\/",
"count":0
},
{
"date_time":"\/Date(1494888600000)\/",
"count":6
},
{
"date_time":"\/Date(1494888600000)\/",
"count":6
},
{
"date_time":"\/Date(1494888720000)\/",
"count":0
},
{
"date_time":"\/Date(1494888780000)\/",
"count":0
},
{
"date_time":"\/Date(1494888900000)\/",
"count":0
},
{
"date_time":"\/Date(1494888960000)\/",
"count":0
},
{
"date_time":"\/Date(1494889080000)\/",
"count":0
},
{
"date_time":"\/Date(1494889140000)\/",
"count":0
},
{
"date_time":"\/Date(1494889260000)\/",
"count":0
},
{
"date_time":"\/Date(1494889320000)\/",
"count":0
},
{
"date_time":"\/Date(1494889380000)\/",
"count":4
},
{
"date_time":"\/Date(1494889380000)\/",
"count":4
},
{
"date_time":"\/Date(1494889380000)\/",
"count":0
},
{
"date_time":"\/Date(1494889380000)\/",
"count":5
},
{
"date_time":"\/Date(1494889380000)\/",
"count":0
},
{
"date_time":"\/Date(1494889500000)\/",
"count":0
},
{
"date_time":"\/Date(1494889560000)\/",
"count":0
},
{
"date_time":"\/Date(1494889680000)\/",
"count":0
},
{
"date_time":"\/Date(1494889740000)\/",
"count":4
},
{
"date_time":"\/Date(1494889740000)\/",
"count":0
},
{
"date_time":"\/Date(1494889860000)\/",
"count":0
},
{
"date_time":"\/Date(1494889920000)\/",
"count":0
},
{
"date_time":"\/Date(1494889920000)\/",
"count":4
},
{
"date_time":"\/Date(1494889980000)\/",
"count":0
},
{
"date_time":"\/Date(1494889980000)\/",
"count":0
},
{
"date_time":"\/Date(1494890220000)\/",
"count":5
},
{
"date_time":"\/Date(1494890220000)\/",
"count":5
},
{
"date_time":"\/Date(1494890280000)\/",
"count":6
},
{
"date_time":"\/Date(1494890340000)\/",
"count":0
},
{
"date_time":"\/Date(1494890400000)\/",
"count":0
},
{
"date_time":"\/Date(1494890520000)\/",
"count":0
},
{
"date_time":"\/Date(1494890580000)\/",
"count":0
},
{
"date_time":"\/Date(1494890700000)\/",
"count":0
},
{
"date_time":"\/Date(1494890760000)\/",
"count":0
},
{
"date_time":"\/Date(1494890880000)\/",
"count":0
},
];
count_data.forEach(function(d) {
d.date_time = new Date(parseInt(d.date_time.replace(/\/Date\((-?\d+)\)\//gi, "$1")));
//d.date_time = formatTime(d.date_time);
});
var maxY = d3.max(count_data, function(d) {
return d.count;
});
var minY = 0;
var minX = new Date(count_data[0].date_time).setHours(0, 0, 0, 0);
var maxX = new Date(count_data[0].date_time).setHours(23, 59, 59, 999);
var gap_array = [];
var range_array = [];
var range_start = moment(new Date(firstDateTime)),
range_end,
range_start_position = 0,
range_end_position,
in_range = true;
var gap_start,
gap_end,
gap_start_position,
gap_end_position,
in_gap = false,
gap_min = 2;
var firstDateTime = count_data[0].date_time;
var lastDateTime = count_data[count_data.length - 1].date_time;
var date_previous = moment(new Date(firstDateTime));
for (i = 0; i < count_data.length; i++) {
var current = moment(new Date(count_data[i].date_time));
if (current.diff(date_previous, "m") > gap_min && !in_gap) {
range_end = date_previous;
range_end_position = i - 1;
in_range = !in_range;
range_array.push({
start: range_start.toDate(),
end: range_end.toDate(),
start_position: range_start_position,
end_position: range_end_position
});
gap_start = date_previous;
gap_start_position = i;
in_gap = !in_gap;
} else if (current.diff(date_previous, "m") <= gap_min && in_gap) {
range_start_position = i;
range_start = current;
in_range = !in_range;
gap_end_position = i;
gap_end = current;
in_gap = !in_gap;
gap_array.push({
start: gap_start.toDate(),
end: gap_end.toDate(),
start_position: gap_start_position,
end_position: gap_end_position
});
} else if (i == count_data.length - 1) {
if (in_gap) {
gap_end_position = i;
gap_end = current;
in_gap = !in_gap;
gap_array.push({
start: gap_start.toDate(),
end: gap_end.toDate(),
start_position: gap_start_position,
end_position: gap_end_position
});
} else {
range_end = current;
range_end_position = i;
in_range = !in_range;
range_array.push({
start: range_start.toDate(),
end: range_end.toDate(),
start_position: range_start_position,
end_position: range_end_position
});
}
}
date_previous = current;
}
gap_array.push({
start: minX,
end: firstDateTime,
start_position: null,
end_position: 0
}); // push initial gap
gap_array.push({
start: lastDateTime,
end: maxX,
start_position: count_data.length - 1,
end_position: null
}); // push final gap
var count_data_array = [];
for (i = 0; i < range_array.length; i++) {
count_data_array.push(count_data.slice(range_array[i].start_position, range_array[i].end_position + (range_array[i].end_position < count_data.length - 1 ? 1 : 0)));
}
//
var margin = 40;
var w = document.getElementById("d3-chart").offsetWidth - margin - margin,
h = 250 - margin - margin;
var x = d3.scaleTime().range([0, w]).domain([minX, maxX]);
var y = d3.scaleLinear().range([h, 0]).domain([minY, maxY]);
var zoomCall = d3.zoom()
.scaleExtent([1, 24]) // no zooming out (1x), only zoom to 1hr (24x)
.on("zoom", zoom);
var container = d3.select("#d3-chart");
var svg = container.append("svg")
.attr("width", w + margin + margin)
.attr("height", h + margin + margin);
var g = svg.append("g")
.attr("transform",
"translate(" + margin + "," + margin + ")")
.call(zoomCall);
g.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", w)
.attr("height", h);
var xAxis = d3.axisBottom(x).ticks(20); //.tickFormat(formatMinutes);
var yAxis = d3.axisLeft(y);
function zoom() {
// re-scale y axis during zoom;
xAxisCall.transition()
.duration(50)
.call(xAxis.scale(d3.event.transform.rescaleX(x)));
// re-draw circles using new y-axis scale;
var new_xScale = d3.event.transform.rescaleX(x);
var new_valueline = d3.line()
.x(function(d) {
return new_xScale(d.date_time);
})
.y(function(d) {
return y(d.count);
});
gaps.attr("x", d => new_xScale(d.start)).attr("width", d => new_xScale(d.end) - new_xScale(d.start)).attr("clip-path", "url(#clip)");
for (i = 0; i < paths.length; i++) {
paths[i]
.attr("d", new_valueline).attr("clip-path", "url(#clip)");
}
}
var gaps = g.selectAll('.gap')
.data(gap_array)
.enter().append('rect')
.attr("class", "gap")
.attr("x", d => x(d.start))
.attr("y", 0)
.attr("width", d => x(d.end) - x(d.start))
.attr("height", h)
.attr("fill", "#efefef");
var xAxisCall = g.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + h + ")")
.call(xAxis);
var yAxisCall = g.append("g")
.attr("class", "axis")
.call(yAxis);
// define the line
var valueline = d3.line()
.x(function(d) {
return x(d.date_time);
})
.y(function(d) {
return y(d.count);
});
var paths = [];
// Add the valueline path.
for (i = 0; i < count_data_array.length; i++) {
paths.push(
g.append("path")
.data([count_data_array[i]])
.attr("class", "line")
.attr("d", valueline)
);
}
g.append("rect")
.attr("class", "overlay")
.attr("width", w)
.attr("height", h)
};
#d3-chart {
position: relative;
}
.axis {
font: 14px sans-serif;
}
.line {
fill: none;
stroke: #3988ff;
stroke-width: 2px;
}
.overlay {
fill: none;
pointer-events: all;;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.js"></script>
<h3>D3 Test</h3>
<div id="d3-chart"></div>
我认为将translateExtent仅放在缩放函数中而不是初始调用中可能没有问题,如果我需要访问缩放比率以计算范围值 – SweetTomato