我在d3js的水平折线图上工作,根据json输入显示几行。它具有缩放和平移功能,但还需要为每条绘制的线条显示y轴。在我的情况下,三个。
首先,这是不好的做法吗?我应该将所有三个堆叠在一边,还是应该保留两个在左边,一个在右边或任何其他组合?
我已经尝试过关注this tutorial,但这确实只会造成更多混乱和令人困惑的代码。
我希望有人可以指导我如何添加额外的y轴以及我如何使用它们进行缩放和平移,就像我现在所拥有的那样。
这是我目前的看法:
这是我的代码:
<script>
var margin = { top: 20, right: 80, bottom: 20, left: 40 },
width = ($("#trendcontainer").width() - 50) - margin.left - margin.right,
height = 650 - margin.top - margin.bottom;
var svg;
var format = d3.time.format("%Y-%m-%dT%H:%M:%S").parse;
var x = d3.time.scale()
.range([0, width]);
var y0 = d3.scale.linear()
.range([height, 0]);
var y1 = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height);
// TODO: Rename axis to instrument name (i.e 'depth')
var yAxis0 = d3.svg.axis()
.scale(y0)
.orient("left")
.tickSize(-width);
var yAxis1 = d3.svg.axis()
.scale(y1)
.orient("right")
.tickSize(-width);
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y0(d.value);
});
d3.json('@Url.Action("DataBlob", "Trend", new {id = Model.Unit.UnitId, runId = Request.Params["runId"]})', function(error, tmparray) {
var json = JSON.parse(tmparray);
$('#processing').hide();
color.domain(d3.keys(json[0]).filter(function(key) {
return key !== "Time" && key !== "Id";
}));
json.forEach(function(d) {
var date = format(d.Time);
d.Time = date;
});
var instruments = color.domain().map(function(name) {
return {
name: name,
values: json.map(function(d) {
return {
date: d.Time,
value: +d[name]
};
})
};
});
x.domain(d3.extent(json, function(d) {
return d.Time;
}));
y0.domain([
d3.min(instruments, function (c) {
if (c.name == "Depth") {
return d3.min(c.values, function (v) {
return v.value;
});
}
//return d3.min(c.values, function (v) {
// return v.value;
//});
}),
d3.max(instruments, function(c) {
return d3.max(c.values, function(v) {
return v.value;
});
})
]);
y1.domain([
d3.min(instruments, function (c) {
console.log("In y1.domain c is: " + c);
if (c.name == "Weight") {
return d3.min(c.values, function (v) {
return v.value;
});
}
//return d3.min(c.values, function (v) {
// return v.value;
//});
}),
d3.max(instruments, function(c) {
return d3.max(c.values, function(v) {
return v.value;
});
})
]);
var zoom = d3.behavior.zoom()
.x(x)
.y(y0)
.scaleExtent([1, 10])
.on("zoom", zoomed);
svg = d3.select(".panel-body").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 + ")")
.call(zoom)
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
svg.append("rect")
.attr("width", width)
.attr("height", height);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis0);
svg.append("g")
.attr("class", "y axis")
.call(yAxis1);
var instrument = svg.selectAll(".instrument")
.data(instruments)
.enter().append("g")
.attr("class", "instrument");
instrument.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.values);
})
.style("stroke", function(d) {
return color(d.name);
});
instrument.append("text")
.datum(function(d) {
return {
name: d.name,
value: d.values[d.values.length - 1]
};
})
.attr("transform", function(d) {
return "translate(" + x(d.value.date) + "," + y0(d.value.value) + ")";
})
.attr("x", 3)
.attr("dy", ".35em")
.text(function(d) {
return d.name;
});
});
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis0);
svg.select(".x.grid")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.select(".y.grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
svg.selectAll(".line")
.attr("d", function(d) { return line(d.values); });
};
var make_x_axis = function() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
};
var make_y_axis = function() {
return d3.svg.axis()
.scale(y0)
.orient("left")
.ticks(5);
};
</script>
最后,这就是我想要实现的目标(此组件太慢,并且不能很好地处理大型数据集):
答案 0 :(得分:2)
最终得到了一个解决方案,得到了@LarsKotthoff的一些帮助。还根据this post添加了多轴缩放。
<script>
/* d3 vars */
var x;
var y1;
var y2;
var y3;
var graph;
var m = [];
var w;
var h;
/* d3 axes */
var xAxis;
var yAxisLeft;
var yAxisLeftLeft;
var yAxisRight;
/* d3 lines */
var line1;
var line2;
var line3;
/* d3 zoom */
var zoom;
var zoomLeftLeft;
var zoomRight;
/* Data */
var speed = [];
var depth = [];
var weight = [];
var timestamp = [];
var url = '@Url.Action("DataBlob", "Trend", new {id = Model.Unit.UnitId, runId = Request.Params["runId"]})';
var data = $.getJSON(url, null, function(data) {
var list = JSON.parse(data);
var format = d3.time.format("%Y-%m-%dT%H:%M:%S").parse;
list.forEach(function(d) {
speed.push(d.Speed);
depth.push(d.Depth);
weight.push(d.Weight);
var date = format(d.Time);
d.Time = date;
timestamp.push(d.Time);
});
m = [10, 80, 30, 100]; // margins: top, right, bottom, left
w = $("#trendcontainer").width() - m[1] - m[3]; // width
h = 550 - m[0] - m[2]; // height
x = d3.time.scale().domain(d3.extent(timestamp, function (d) {
return d;
})).range([0, w]);
y1 = d3.scale.linear().domain([0, d3.max(speed)]).range([h, 0]);
y2 = d3.scale.linear().domain([0, d3.max(depth)]).range([h, 0]);
y3 = d3.scale.linear().domain([0, d3.max(weight)]).range([h, 0]);
line1 = d3.svg.line()
.interpolate("basis")
.x(function (d, i) {
return x(timestamp[i]);
})
.y(function (d) {
return y1(d);
});
line2 = d3.svg.line()
.interpolate("basis")
.x(function (d, i) {
return x(timestamp[i]);
})
.y(function (d) {
return y2(d);
});
line3 = d3.svg.line()
.interpolate("basis")
.x(function (d, i) {
return x(timestamp[i]);
})
.y(function (d) {
return y3(d);
});
zoom = d3.behavior.zoom()
.x(x)
.y(y1)
.scaleExtent([1, 10])
.on("zoom", zoomed);
zoomLeftLeft = d3.behavior.zoom()
.x(x)
.y(y3)
.scaleExtent([1, 10]);
zoomRight = d3.behavior.zoom()
.x(x)
.y(y2)
.scaleExtent([1, 10]);
// Add an SVG element with the desired dimensions and margin.
graph = d3.select(".panel-body").append("svg:svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.call(zoom)
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
// create xAxis
xAxis = d3.svg.axis().scale(x).tickSize(-h).tickSubdivide(false);
// Add the x-axis.
graph.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.call(xAxis);
// create left yAxis
yAxisLeft = d3.svg.axis().scale(y1).ticks(10).orient("left");
// Add the y-axis to the left
graph.append("svg:g")
.attr("class", "y axis axisLeft")
.attr("transform", "translate(-15,0)")
.call(yAxisLeft);
// create leftleft yAxis
yAxisLeftLeft = d3.svg.axis().scale(y3).ticks(10).orient("left");
// Add the y-axis to the left
graph.append("svg:g")
.attr("class", "y axis axisLeftLeft")
.attr("transform", "translate(-50,0)")
.call(yAxisLeftLeft);
// create right yAxis
yAxisRight = d3.svg.axis().scale(y2).ticks(10).orient("right");
// Add the y-axis to the right
graph.append("svg:g")
.attr("class", "y axis axisRight")
.attr("transform", "translate(" + (w + 15) + ",0)")
.call(yAxisRight);
// add lines
// do this AFTER the axes above so that the line is above the tick-lines
graph.append("svg:path").attr("d", line1(speed)).attr("class", "y1");
graph.append("svg:path").attr("d", line2(depth)).attr("class", "y2");
graph.append("svg:path").attr("d", line3(weight)).attr("class", "y3");
});
function zoomed() {
zoomRight.scale(zoom.scale()).translate(zoom.translate());
zoomLeftLeft.scale(zoom.scale()).translate(zoom.translate());
graph.select(".x.axis").call(xAxis);
graph.select(".y.axisLeft").call(yAxisLeft);
graph.select(".y.axisLeftLeft").call(yAxisLeftLeft);
graph.select(".y.axisRight").call(yAxisRight);
graph.select(".x.grid")
.call(make_x_axis()
.tickFormat(""));
graph.select(".y.axis")
.call(make_y_axis()
.tickSize(5, 0, 0));
graph.selectAll(".y1")
.attr("d", line1(speed));
graph.selectAll(".y2")
.attr("d", line2(depth));
graph.selectAll(".y3")
.attr("d", line3(weight));
};
var make_x_axis = function () {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
};
var make_y_axis = function () {
return d3.svg.axis()
.scale(y1)
.orient("left")
.ticks(5);
};
</script>