我想根据用户需要加载旧的(以前的)数据。
概念是这样的:
- 当用户第一次加载图表时,他会看到最近的数据
- 然后,他可以从左向右拖动图表以检查以前的数据
- 当他到达最后一个数据时,先进行检测,然后加载较旧的数据,将它们重新绘制到图表中,刷新缩放比例等等……
我的目标是在用户到达最后一个数据并拖动时检测事件,以便他显示前一个数据...我只需要检测该事件即可。
以下是我要应用更改的示例:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
text {
fill: #000;
}
text.symbol {
fill: #BBBBBB;
}
path {
fill: none;
stroke-width: 1;
}
path.candle {
stroke: #000000;
}
path.candle.body {
stroke-width: 0;
}
path.candle.up {
fill: #00AA00;
stroke: #00AA00;
}
path.candle.down {
fill: #FF0000;
stroke: #FF0000;
}
.close.annotation.up path {
fill: #00AA00;
}
path.volume {
fill: #DDDDDD;
}
.indicator-plot path.line {
fill: none;
stroke-width: 1;
}
.ma-0 path.line {
stroke: #1f77b4;
}
.ma-1 path.line {
stroke: #aec7e8;
}
.ma-2 path.line {
stroke: #ff7f0e;
}
button {
position: absolute;
right: 110px;
top: 25px;
}
path.macd {
stroke: #0000AA;
}
path.signal {
stroke: #FF9999;
}
path.zero {
stroke: #BBBBBB;
stroke-dasharray: 0;
stroke-opacity: 0.5;
}
path.difference {
fill: #BBBBBB;
opacity: 0.5;
}
path.rsi {
stroke: #000000;
}
path.overbought,path.oversold {
stroke: #FF9999;
stroke-dasharray: 5,5;
}
path.middle,path.zero {
stroke: #BBBBBB;
stroke-dasharray: 5,5;
}
.analysis path,.analysis circle {
stroke: blue;
stroke-width: 0.8;
}
.trendline circle {
stroke-width: 0;
display: none;
}
.mouseover .trendline path {
stroke-width: 1.2;
}
.mouseover .trendline circle {
stroke-width: 1;
display: inline;
}
.dragging .trendline path,.dragging .trendline circle {
stroke: darkblue;
}
.interaction path,.interaction circle {
pointer-events: all;
}
.interaction .body {
cursor: move;
}
.trendlines .interaction .start,.trendlines .interaction .end {
cursor: nwse-resize;
}
.supstance path {
stroke-dasharray: 2,2;
}
.supstances .interaction path {
pointer-events: all;
cursor: ns-resize;
}
.mouseover .supstance path {
stroke-width: 1.5;
}
.dragging .supstance path {
stroke: darkblue;
}
.crosshair {
cursor: crosshair;
}
.crosshair path.wire {
stroke: #DDDDDD;
stroke-dasharray: 1,1;
}
.crosshair .axisannotation path {
fill: #DDDDDD;
}
.tradearrow path.tradearrow {
stroke: none;
}
.tradearrow path.buy {
fill: #0000FF;
}
.tradearrow path.sell {
fill: #9900FF;
}
.tradearrow path.highlight {
fill: none;
stroke-width: 2;
}
.tradearrow path.highlight.buy {
stroke: #0000FF;
}
.tradearrow path.highlight.sell {
stroke: #9900FF;
}
</style>
<body>
<button>Reset</button>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="http://techanjs.org/techan.min.js"></script>
<script>
var dim = {
width: 960,height: 500,margin: { top: 20,right: 50,bottom: 30,left: 50 },ohlc: { height: 305 },indicator: { height: 65,padding: 5 }
};
dim.plot = {
width: dim.width - dim.margin.left - dim.margin.right,height: dim.height - dim.margin.top - dim.margin.bottom
};
dim.indicator.top = dim.ohlc.height+dim.indicator.padding;
dim.indicator.bottom = dim.indicator.top+dim.indicator.height+dim.indicator.padding;
var indicatorTop = d3.scaleLinear()
.range([dim.indicator.top,dim.indicator.bottom]);
var parseDate = d3.timeParse("%d-%b-%y");
var zoom = d3.zoom()
.on("zoom",zoomed);
var x = techan.scale.financetime()
.range([0,dim.plot.width]);
var y = d3.scaleLinear()
.range([dim.ohlc.height,0]);
var yPercent = y.copy(); // Same as y at this stage,will get a different domain later
var yInit,yPercentInit,zoomableInit;
var yVolume = d3.scaleLinear()
.range([y(0),y(0.2)]);
var candlestick = techan.plot.candlestick()
.xScale(x)
.yScale(y);
var tradearrow = techan.plot.tradearrow()
.xScale(x)
.yScale(y)
.y(function(d) {
// Display the buy and sell arrows a bit above and below the price,so the price is still visible
if(d.type === 'buy') return y(d.low)+5;
if(d.type === 'sell') return y(d.high)-5;
else return y(d.price);
});
var sma0 = techan.plot.sma()
.xScale(x)
.yScale(y);
var sma1 = techan.plot.sma()
.xScale(x)
.yScale(y);
var ema2 = techan.plot.ema()
.xScale(x)
.yScale(y);
var volume = techan.plot.volume()
.accessor(candlestick.accessor()) // Set the accessor to a ohlc accessor so we get highlighted bars
.xScale(x)
.yScale(yVolume);
var trendline = techan.plot.trendline()
.xScale(x)
.yScale(y);
var supstance = techan.plot.supstance()
.xScale(x)
.yScale(y);
var xAxis = d3.axisBottom(x);
var timeAnnotation = techan.plot.axisannotation()
.axis(xAxis)
.orient('bottom')
.format(d3.timeFormat('%Y-%m-%d'))
.width(65)
.translate([0,dim.plot.height]);
var yAxis = d3.axisRight(y);
var ohlcAnnotation = techan.plot.axisannotation()
.axis(yAxis)
.orient('right')
.format(d3.format(',.2f'))
.translate([x(1),0]);
var closeAnnotation = techan.plot.axisannotation()
.axis(yAxis)
.orient('right')
.accessor(candlestick.accessor())
.format(d3.format(',0]);
var percentAxis = d3.axisLeft(yPercent)
.tickFormat(d3.format('+.1%'));
var percentAnnotation = techan.plot.axisannotation()
.axis(percentAxis)
.orient('left');
var volumeAxis = d3.axisRight(yVolume)
.ticks(3)
.tickFormat(d3.format(",.3s"));
var volumeAnnotation = techan.plot.axisannotation()
.axis(volumeAxis)
.orient("right")
.width(35);
var macdScale = d3.scaleLinear()
.range([indicatorTop(0)+dim.indicator.height,indicatorTop(0)]);
var rsiScale = macdScale.copy()
.range([indicatorTop(1)+dim.indicator.height,indicatorTop(1)]);
var macd = techan.plot.macd()
.xScale(x)
.yScale(macdScale);
var macdAxis = d3.axisRight(macdScale)
.ticks(3);
var macdAnnotation = techan.plot.axisannotation()
.axis(macdAxis)
.orient("right")
.format(d3.format(',0]);
var macdAxisLeft = d3.axisLeft(macdScale)
.ticks(3);
var macdAnnotationLeft = techan.plot.axisannotation()
.axis(macdAxisLeft)
.orient("left")
.format(d3.format(',.2f'));
var rsi = techan.plot.rsi()
.xScale(x)
.yScale(rsiScale);
var rsiAxis = d3.axisRight(rsiScale)
.ticks(3);
var rsiAnnotation = techan.plot.axisannotation()
.axis(rsiAxis)
.orient("right")
.format(d3.format(',0]);
var rsiAxisLeft = d3.axisLeft(rsiScale)
.ticks(3);
var rsiAnnotationLeft = techan.plot.axisannotation()
.axis(rsiAxisLeft)
.orient("left")
.format(d3.format(',.2f'));
var ohlcCrosshair = techan.plot.crosshair()
.xScale(timeAnnotation.axis().scale())
.yScale(ohlcAnnotation.axis().scale())
.xAnnotation(timeAnnotation)
.yAnnotation([ohlcAnnotation,percentAnnotation,volumeAnnotation])
.verticalWireRange([0,dim.plot.height]);
var macdCrosshair = techan.plot.crosshair()
.xScale(timeAnnotation.axis().scale())
.yScale(macdAnnotation.axis().scale())
.xAnnotation(timeAnnotation)
.yAnnotation([macdAnnotation,macdAnnotationLeft])
.verticalWireRange([0,dim.plot.height]);
var rsiCrosshair = techan.plot.crosshair()
.xScale(timeAnnotation.axis().scale())
.yScale(rsiAnnotation.axis().scale())
.xAnnotation(timeAnnotation)
.yAnnotation([rsiAnnotation,rsiAnnotationLeft])
.verticalWireRange([0,dim.plot.height]);
var svg = d3.select("body").append("svg")
.attr("width",dim.width)
.attr("height",dim.height);
var defs = svg.append("defs");
defs.append("clipPath")
.attr("id","ohlcClip")
.append("rect")
.attr("x",0)
.attr("y",0)
.attr("width",dim.plot.width)
.attr("height",dim.ohlc.height);
defs.selectAll("indicatorClip").data([0,1])
.enter()
.append("clipPath")
.attr("id",function(d,i) { return "indicatorClip-" + i; })
.append("rect")
.attr("x",i) { return indicatorTop(i); })
.attr("width",dim.indicator.height);
svg = svg.append("g")
.attr("transform","translate(" + dim.margin.left + "," + dim.margin.top + ")");
svg.append('text')
.attr("class","symbol")
.attr("x",20)
.text("Facebook,Inc. (FB)");
svg.append("g")
.attr("class","x axis")
.attr("transform","translate(0," + dim.plot.height + ")");
var ohlcSelection = svg.append("g")
.attr("class","ohlc")
.attr("transform",0)");
ohlcSelection.append("g")
.attr("class","axis")
.attr("transform","translate(" + x(1) + ",0)")
.append("text")
.attr("transform","rotate(-90)")
.attr("y",-12)
.attr("dy",".71em")
.style("text-anchor","end")
.text("Price ($)");
ohlcSelection.append("g")
.attr("class","close annotation up");
ohlcSelection.append("g")
.attr("class","volume")
.attr("clip-path","url(#ohlcClip)");
ohlcSelection.append("g")
.attr("class","candlestick")
.attr("clip-path","indicator sma ma-0")
.attr("clip-path","indicator sma ma-1")
.attr("clip-path","indicator ema ma-2")
.attr("clip-path","percent axis");
ohlcSelection.append("g")
.attr("class","volume axis");
var indicatorSelection = svg.selectAll("svg > g.indicator").data(["macd","rsi"]).enter()
.append("g")
.attr("class",function(d) { return d + " indicator"; });
indicatorSelection.append("g")
.attr("class","axis right")
.attr("transform",0)");
indicatorSelection.append("g")
.attr("class","axis left")
.attr("transform","translate(" + x(0) + ","indicator-plot")
.attr("clip-path",i) { return "url(#indicatorClip-" + i + ")"; });
// Add trendlines and other interactions last to be above zoom pane
svg.append('g')
.attr("class","crosshair ohlc");
svg.append("g")
.attr("class","tradearrow")
.attr("clip-path","url(#ohlcClip)");
svg.append('g')
.attr("class","crosshair macd");
svg.append('g')
.attr("class","crosshair rsi");
svg.append("g")
.attr("class","trendlines analysis")
.attr("clip-path","url(#ohlcClip)");
svg.append("g")
.attr("class","supstances analysis")
.attr("clip-path","url(#ohlcClip)");
d3.select("button").on("click",reset);
d3.csv("data.csv",function(error,data) {
var accessor = candlestick.accessor(),indicatorPreRoll = 33; // Don't show where indicators don't have data
data = data.map(function(d) {
return {
date: parseDate(d.Date),open: +d.Open,high: +d.High,low: +d.Low,close: +d.Close,volume: +d.Volume
};
}).sort(function(a,b) { return d3.ascending(accessor.d(a),accessor.d(b)); });
x.domain(techan.scale.plot.time(data).domain());
y.domain(techan.scale.plot.ohlc(data.slice(indicatorPreRoll)).domain());
yPercent.domain(techan.scale.plot.percent(y,accessor(data[indicatorPreRoll])).domain());
yVolume.domain(techan.scale.plot.volume(data).domain());
var trendlineData = [
{ start: { date: new Date(2014,2,11),value: 72.50 },end: { date: new Date(2014,5,9),value: 63.34 } },{ start: { date: new Date(2013,10,21),value: 43 },17),value: 70.50 } }
];
var supstanceData = [
{ start: new Date(2014,end: new Date(2014,value: 63.64 },{ start: new Date(2013,value: 55.50 }
];
var trades = [
{ date: data[67].date,type: "buy",price: data[67].low,low: data[67].low,high: data[67].high },{ date: data[100].date,type: "sell",price: data[100].high,low: data[100].low,high: data[100].high },{ date: data[130].date,price: data[130].low,low: data[130].low,high: data[130].high },{ date: data[170].date,price: data[170].low,low: data[170].low,high: data[170].high }
];
var macddata = techan.indicator.macd()(data);
macdScale.domain(techan.scale.plot.macd(macddata).domain());
var rsiData = techan.indicator.rsi()(data);
rsiScale.domain(techan.scale.plot.rsi(rsiData).domain());
svg.select("g.candlestick").datum(data).call(candlestick);
svg.select("g.close.annotation").datum([data[data.length-1]]).call(closeAnnotation);
svg.select("g.volume").datum(data).call(volume);
svg.select("g.sma.ma-0").datum(techan.indicator.sma().period(10)(data)).call(sma0);
svg.select("g.sma.ma-1").datum(techan.indicator.sma().period(20)(data)).call(sma1);
svg.select("g.ema.ma-2").datum(techan.indicator.ema().period(50)(data)).call(ema2);
svg.select("g.macd .indicator-plot").datum(macddata).call(macd);
svg.select("g.rsi .indicator-plot").datum(rsiData).call(rsi);
svg.select("g.crosshair.ohlc").call(ohlcCrosshair).call(zoom);
svg.select("g.crosshair.macd").call(macdCrosshair).call(zoom);
svg.select("g.crosshair.rsi").call(rsiCrosshair).call(zoom);
svg.select("g.trendlines").datum(trendlineData).call(trendline).call(trendline.drag);
svg.select("g.supstances").datum(supstanceData).call(supstance).call(supstance.drag);
svg.select("g.tradearrow").datum(trades).call(tradearrow);
// Stash for zooming
zoomableInit = x.zoomable().domain([indicatorPreRoll,data.length]).copy(); // zoom in a little to hide indicator preroll
yInit = y.copy();
yPercentInit = yPercent.copy();
draw();
});
function reset() {
zoom.scale(1);
zoom.translate([0,0]);
draw();
}
function zoomed() {
x.zoomable().domain(d3.event.transform.rescaleX(zoomableInit).domain());
y.domain(d3.event.transform.rescaleY(yInit).domain());
yPercent.domain(d3.event.transform.rescaleY(yPercentInit).domain());
draw();
}
function draw() {
svg.select("g.x.axis").call(xAxis);
svg.select("g.ohlc .axis").call(yAxis);
svg.select("g.volume.axis").call(volumeAxis);
svg.select("g.percent.axis").call(percentAxis);
svg.select("g.macd .axis.right").call(macdAxis);
svg.select("g.rsi .axis.right").call(rsiAxis);
svg.select("g.macd .axis.left").call(macdAxisLeft);
svg.select("g.rsi .axis.left").call(rsiAxisLeft);
// We know the data does not change,a simple refresh that does not perform data joins will suffice.
svg.select("g.candlestick").call(candlestick.refresh);
svg.select("g.close.annotation").call(closeAnnotation.refresh);
svg.select("g.volume").call(volume.refresh);
svg.select("g .sma.ma-0").call(sma0.refresh);
svg.select("g .sma.ma-1").call(sma1.refresh);
svg.select("g .ema.ma-2").call(ema2.refresh);
svg.select("g.macd .indicator-plot").call(macd.refresh);
svg.select("g.rsi .indicator-plot").call(rsi.refresh);
svg.select("g.crosshair.ohlc").call(ohlcCrosshair.refresh);
svg.select("g.crosshair.macd").call(macdCrosshair.refresh);
svg.select("g.crosshair.rsi").call(rsiCrosshair.refresh);
svg.select("g.trendlines").call(trendline.refresh);
svg.select("g.supstances").call(supstance.refresh);
svg.select("g.tradearrow").call(tradearrow.refresh);
}
</script>
在此处找到完整的示例以及(data.csv)文件:
http://bl.ocks.org/andredumas/edf630690c10b89be390
因此,当用户拖动最后一个端点时,我将用另一个csv文件(data2.csv)等替换图表...
您的帮助将不胜感激。