我有时候一直在努力解决这个问题,真的需要帮助。我想创建一个热图,内容和轴都是可扩展的,并且可以相应地进行缩放。注意我已经将svg内容转换为画布。我想我已经在那里了一半,不幸的是我无法使画布变焦并相应地拖动,同时轴本身也没问题。
以下是我的来源,真的需要你的帮助。谢谢,抱歉我的语法不好。
$(document).ready(function() {
let w = $('#bodyBackground')[0];
let clientWidthz = w.clientWidth;
let clientHeightz = w.clientHeight;
var radars = [];
var newSample = [];
var timeStampLegends = [];
for (var i = 0; i < 1440; i++) {
var legend_xTime = new Date(Date.now() - (i * 60 * 1000));
timeStampLegends.push(legend_xTime);
}
for (var unit_i = 0; unit_i <= 101;) {
if (unit_i == 0) {
radars.push(1);
unit_i = unit_i + 5;
} else {
radars.push(unit_i);
unit_i = unit_i + 4;
}
}
//by using below method we can observe the delay is not due to the data during insertion
for (var unit = 1; unit <= 5; unit++) {
timeStampLegends.forEach(function(dbData) {
var i = Math.random() * 1400;
newSample.push({ radars: unit, timestamp: dbData, level: i });
});
}
var margin = { top: 20, right: 20, bottom: 30, left: 60 };
var width = 1200 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;
var x = d3.scaleTime()
.domain([new Date(timeStampLegends[0]), new Date(timeStampLegends[timeStampLegends.length - 1])])
.range([0, width]);
var min = d3.min(newSample, function(d) {
return d.radars;
});
var max = d3.max(newSample, function(d) {
return d.radars;
});
var y = d3.scaleLinear()
.domain([min, max])
.range([0, height]);
var xAxis = d3.axisTop(x).tickSize(height); //the size of the inner grid line (vertical - x-axis)
var yAxis = d3.axisLeft(y).ticks(5).tickSize(-width); //the size of the inner grid line (horizontal - y - axis)
var zoom = d3.zoom()
.translateExtent([
[0, 0],
[width + 2000, height]
])
.scaleExtent([1, 10])
.on("zoom", zoomed);
var svg = d3.select(".TrafficCongestions").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 canvas = d3.select('.TrafficCongestions').append("canvas")
.attr("id", "canvas")
//absolute: a feature that allows any sort of element
//to be positioned disregards to other elements
//i.e. it will calculate its own position again from (0,0)
.style("position", "absolute")
.style("top", "20px")
.style("left", "60px")
.attr("width", width + margin.left + margin.right) //optimization
.attr("height", height + margin.top + margin.bottom);//optimization
var context = canvas.node().getContext("2d");
context.clearRect(0, 0, width, height);
var detachedContainer = document.createElement("custom");
var dataContainer = d3.select(detachedContainer);
var colorScale = d3.scaleLinear().domain([0, 600, 1200]).range(["#009933", "#FFCC00", "#990000"]);
//x-axis (solely based on data of times)
var timeLabels = svg.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(0," + (height) + ")")
.style("font-size", "20px")
.call(xAxis);
//y-axis (solely based on data of radars)
var radarLabels = svg.append("g")
.attr("class", "y-axis")
.call(yAxis);
//console.log(JSON.stringify(newSample));
var heatMap = dataContainer.selectAll(".custom.rect")
.data(newSample)
.enter().append("custom")
.attr("x", function(d){
return x(d.timestamp);
})
.attr("y", function(d){
return y(d.radars);
})
.classed("rect", true)
.attr("class", "rect bordered")
.attr("width", function(d){
var offSetX = x(d3.timeMinute.offset(d.timestamp, 1))- x(d.timestamp);
return offSetX;
})
//.attr("width", "1120px")
.attr("height", function(d){
var offSetY = y(d.radars - 1) - y(d.radars);
return offSetY;
})
//.attr("strokeStyle", "rgba(255,255,255,0.2)")
.attr("fillStyle", function(d, i){
return colorScale(d.level);
});
canvas.call(zoom);
drawCanvas();
function drawCanvas(){
var elements = dataContainer.selectAll("custom.rect");
elements.each(function(d){
var node = d3.select(this);
context.beginPath();
context.fillStyle = node.attr("fillStyle");
context.rect(node.attr("x"), node.attr("y"), node.attr("width"), node.attr("height"));
context.fill();
context.closePath();
});
}
function zoomed() {
var currentTransform = d3.event.transform;
// update: rescale x axis
timeLabels.call(xAxis.scale(d3.event.transform.rescaleX(x)));
update();
}
function update() {
// update: cache rescaleX value
var rescaleX = d3.event.transform.rescaleX(x);
heatMap.selectAll(".custom.rect")
// update: apply rescaleX value
.attr("x", function(d) {
return rescaleX(d.timestamp);
})
.attr("y", function(d) {
return y(d.radars);
})
// update: apply rescaleX value
.attr("width", function(d) {
return rescaleX(d3.timeMinute.offset(d.timestamp, 1)) - rescaleX(d.timestamp);
//return rescaleX(x);
})
.attr("height", function(d) {
return y(d.radars - 1) - y(d.radars);
})
//.attr("strokeStyle", "rgba(255,255,255,0.2)")
.attr("fillStyle", function(d, i){
return colorScale(d.level);
});
drawCanvas();
}
});
&#13;
body {
position: relative;
width: 960px;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
&#13;
<script
src="https://code.jquery.com/jquery-1.10.0.min.js"
integrity="sha256-2+LznWeWgL7AJ1ciaIG5rFP7GKemzzl+K75tRyTByOE="
crossorigin="anonymous"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<html>
<head>
<title></title>
</head>
<body id="bodyBackground">
<div class="TrafficCongestions"></div>
</body>
</html>
&#13;