我最近开始研究d3.js.我正在开发具有双x轴的交互式多线图。请看看我的工作,JSFiDDLE:http://jsfiddle.net/dalapati/88bsax53/2/
data1 = [{
"date": 1357717800000,
"value": "5.6"
}, {
"date": 1357718400000,
"value": "5.6"
}, {
"date": 1357719000000,
"value": "6"
}, {
"date": 1357719600000,
"value": "5.1"
}, {
"date": 1357720200000,
"value": "5.3"
},
//{"date": 1357720800000,"value": "5.4"}
];
data2 = [{
"date": 1357714800000,
"value": "5.2"
}, {
"date": 1357715400000,
"value": "5.2"
}, {
"date": 1357716000000,
"value": "5.2"
}, {
"date": 1357716600000,
"value": "5.1"
}, {
"date": 1357717200000,
"value": "5.5"
}, ]
// date manipulation to format UTC to js Date obj
data1.forEach(function (d) {
d.time = new Date(d.time * 1000);
});
data2.forEach(function (d) {
d.time = new Date(d.time * 1000);
});
// helpers and constants
var margin = {
"top": 50,
"right": 50,
"bottom": 50,
"left": 100,
"axis": 55
};
var width = 800 - margin.left - margin.right;
var height = 580 - margin.top - margin.bottom;
var timeFormat = d3.time.format("%X");
// find data range
var x1Domain = d3.extent(data1, function (d) {
return d.date;
});
var x2Domain = d3.extent(data2, function (d) {
return d.date;
});
var x1Min = d3.min(data1, function (d) {
return Math.min(d.date);
});
var x1Max = d3.max(data1, function (d) {
return Math.max(d.date);
});
var x2Min = d3.min(data2, function (d) {
return Math.min(d.date);
});
var x2Max = d3.max(data2, function (d) {
return Math.max(d.date);
});
var y1Min = d3.min(data1, function (d) {
return Math.min(d.value);
});
var y1Max = d3.max(data1, function (d) {
return Math.max(d.value);
});
var y2Min = d3.min(data2, function (d) {
return Math.min(d.value);
});
var y2Max = d3.max(data2, function (d) {
return Math.max(d.value);
});
var yMin = (y1Min < y2Min) ? y1Min : y2Min;
var yMax = (y1Max > y2Max) ? y1Max : y2Max;
// scales
var x1Scale = d3.time.scale()
.domain(d3.extent(data1, function (d) {
return d.date;
}))
.range([0, width]);
var x2Scale = d3.time.scale()
.domain(d3.extent(data2, function (d) {
return d.date;
}))
.range([0, width]);
var yScale = d3.scale.linear()
.domain([yMin, yMax]).range([height, 0]);
// set up axes
var x1Axis = d3.svg.axis()
.scale(x1Scale)
.orient("bottom")
.ticks(5)
.tickPadding(5)
.tickFormat(timeFormat);
var x2Axis = d3.svg.axis()
.scale(x2Scale)
.orient("top")
.ticks(5)
.tickPadding(5)
.tickFormat(timeFormat);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5);
var make_y_axis = function () {
return d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5);
};
// Set up chart type
// create a line function that can convert data into x and y points
var line1 = d3.svg.line().interpolate("basis")
.x(function (d) {
return x1Scale(d.date);
})
.y(function (d) {
return yScale(d.value);
});
var line2 = d3.svg.line().interpolate("basis")
.x(function (d) {
return x2Scale(d.date);
})
.y(function (d) {
return yScale(d.value);
});
// Create Drag behaviour
var drag = d3.behavior.drag()
.origin(function (d) {
return d;
})
.on("drag", dragmove);
// create svg container
var svg = d3.select('#chart')
.append("svg:svg")
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append("svg:g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr("class", "plot");
//Draw Axes
svg.append("svg:g")
.attr("class", "x axis axisBottom")
.attr("transform", "translate(0, " + height + ")")
.call(x1Axis);
svg.append("svg:g")
.attr("class", "x axis axisTop")
.attr("transform", "translate(0, 0)")
.call(x2Axis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// grid plot
svg.append("g")
.attr("class", "y grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
// add lines
// do this AFTER the axes above so that the line is above the tick-lines
var clip = svg.append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("x1Scale", 0)
.attr("x2Scale", 0)
.attr("yScale", 0)
.attr("width", width)
.attr("height", height);
var chartBody = svg.append("g")
.attr("clip-path", "url(#clip)");
chartBody.append("svg:path")
.datum(data1)
.attr("class", "data1")
.attr("d", line1(data1));
chartBody.append("svg:path")
.datum(data2)
.attr("class", "data2")
.attr("d", line2(data2));
/************************** ADDING CROSS HAIRS *******************************************/
// Add cross hairs and floating value on axis
var crossHair = svg.append("g")
.attr("id", "crosshair");
//vertical crosshair
crossHair.append("line").attr("id", "v_crosshair")
.attr("x1", 0)
.attr("y1", -height)
.attr("x2", 0)
.attr("y2", height)
//text label for cross hair
var crossHairTextData1 = svg.append("g")
.attr("id", "crosshair_text");
crossHairTextData1.append("text")
.style("background", "white");
var crossHairTextData2 = svg.append("g")
.attr("id", "crosshair_text");
crossHairTextData2.append("text")
var crossHairTextValue = svg.append("g")
.attr("id", "crosshair_text");
crossHairTextValue.append("text")
svg.on("mousemove", function () {
var xCoord = d3.mouse(this)[0],
yCoord = d3.mouse(this)[1];
addCrossHair(xCoord, yCoord);
})
.on("mouseover", function () {
d3.selectAll(".crosshair").style("display", null);
})
.on("mouseout", function () {
d3.selectAll(".crosshair").style("display", "none");
})
.append("rect")
.style('visibility', 'hidden')
.attr('x', 0)
.attr('y', 0)
.attr('width', width)
.attr('height', height);
function addCrossHair(xCoord, yCoord) {
// Update horizontal cross hair
d3.select("#h_crosshair")
.attr("x1", x1Scale(x1Min))
.attr("y1", yCoord)
.attr("x2", x1Scale(x1Max))
.attr("y2", yCoord)
.style("display", "block");
// Update vertical cross hair
d3.select("#v_crosshair")
.attr("x1", xCoord)
.attr("y1", yScale(yMin))
.attr("x2", xCoord)
.attr("y2", yScale(yMax))
.style("display", "block");
// Update text label
crossHairTextData1.select("text")
.attr("transform", "translate(" + (xCoord) + "," + (height - 10) + ")")
.text("(" + x1Scale.invert(xCoord) + ")");
crossHairTextData2.select("text")
.attr("transform", "translate(" + (xCoord) + ", 15)")
.text("(" + x2Scale.invert(xCoord) + ")");
crossHairTextValue.select("text")
.attr("transform", "translate(" + (xCoord + 5) + "," + (yCoord - 5) + ")")
.text("(" + yScale.invert(yCoord) + ")");
}
/*********************** Adding Dragging feature****************************/
d3.select(".data1")
.attr("cursor", "move")
.call(drag);
function dragmove(d) {
var lineToMove = d3.event.x;
d3.select(this)
.transition()
.duration(500)
.ease("linear")
.attr("transform", function () {
return "translate(" + lineToMove + ")";
});
}
&#13;
text{
fill: black;
font-family: 'Ubuntu', 'Helvetica', 'Arial', sans-serif !important;
}
path {
stroke-width: 3px;
fill: none;
}
.line{
fill: none;
stroke: #0CD1AA;
stroke-width: 3px;
}
.data1, .line1{
stroke: #0CD1AA;
}
.data2, .line2{
stroke: orange;
}
.plot{
fill: #c9c9c9; /*Gray*/
opacity: 0.5;
}
.horizontalGrid{
fill: none;
shape-rendering: crispEdges;
stroke: grey;
stroke-width: 1px;
stroke-dasharray: 6,3;
opacity: 0.33;
}
.grid .tick{
fill: none;
shape-rendering: crispEdges;
stroke: grey;
stroke-width: 1px;
stroke-dasharray: 6,3;
opacity: 0.33;
}
.grid path{
stoke-width: 0;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path{
display: none;
}
.x.axisBottom text{
fill: #0CD1AA ;
}
.x.axisTop text{
fill: orange ;
}
/*
.area{
fill: url(#temperature-gradient);
opacity: 0.6;
}
*/
.overlay {
fill: none;
pointer-events: all;
cursor: none;
}
.focus line {
fill: none;
stroke: black;
}
#h_crosshair, #v_crosshair{
stroke: gray;
stroke-width: 1px;
stoke-dasharray:5,5;
display: none;
}
#crosshair_text{
font-size: 12px;
color: black;
stroke-width: 0.5px;
background-color: white;
opacity: 0.7;
}
&#13;
<!doctype html>
<html>
<head>
<title> D3 Chart </title>
<link rel="stylesheet" type="text/css" href="base.css">
<script src="http://d3js.org/d3.v3.min.js"> </script>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
</head>
<body>
<div id="chart"></div>
</body>
</html>
&#13;
如您所见,有两个不同的折线图,取自不同的数据源并相对于两个不同的x轴绘制。我试图将拖动行为实现到每个线图,使得相应的轴也应该与图一起移动。
以一种简单的方式,当我选择一个图形并拖动它并保持另一个图形不变时,相应的轴值也应该更新。任何人都可以帮助我完成这项任务。