D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
biovisualize
Full window
Github gist
streaming line chart with animation and long-scrolling
<!DOCTYPE HTML> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <script type='text/javascript' src="https://d3js.org/d3.v3.min.js"></script> <style> div{ box-sizing: border-box; } .gallery-container{ position: absolute; height: 100px; width: 1000px; overflow:hidden; } .gallery-slide{ height: 125px; width: 1000px; overflow:auto; white-space: nowrap; /*font-size: 0;*/ } .handle{ top: 0px; width: 50px; height: 100px; position: absolute; background: url(handle.png); background-repeat: no-repeat; background-size: 50px 100%; } .handle.right{ right: 0px; -moz-transform:rotate(180deg); -webkit-transform:rotate(180deg); -o-transform:rotate(180deg); transform:rotate(180deg); -ms-transform:rotate(180deg); } .panel{ position: relative; top: 0; width: 1000px; height: 100px; z-index: -1; display: inline-block; text-align: center; font-size: 50px; margin: -2px; /*hack*/ } .before{ background-color: orange; } .current{ background: radial-gradient(circle at 0% 50%, rgba(96, 16, 48, 0) 9px, #613 10px, rgba(96, 16, 48, 0) 11px) 0px 10px, radial-gradient(at 100% 100%, rgba(96, 16, 48, 0) 9px, #613 10px, rgba(96, 16, 48, 0) 11px), #8a3; background-size: 20px 20px; } .after{ background-color: skyblue; } </style> <script src="../lib/pixi.dev.js"></script> </head> <body> <div class="gallery-container"> <div class="gallery-slide"> <div class="handle left"></div> <div class="handle right"></div> <div class="panel before"><canvas></canvas></div> <div class="panel current"><canvas></canvas></div> <div class="panel after"><canvas></canvas></div> </div> </div> <script> /* super cool features: -scroll without redraw -long scrolling with lazy loading -adjustable speed -requestAnimationFrame: smooth, stops when hidden -could be adjusted for more granular partial loading []|[][][][]|[] -webgl with canvas fallback */ // array of data arrays var DataGenerator = function(){ var config = {datacount: 100, min: 0, max: 1000}; var lastDatum; var exports = {}; exports.generate = function(){ var data = d3.range(config.datacount).map(function(d, i){ if(i === 0 && typeof lastDatum !== 'undefined') return {y: lastDatum.y, x: i}; return {y: ~~((Math.random()*(config.max - config.min) - config.min) * 100) / 100, x: i}; }); lastDatum = data[data.length-1]; return data; }; return exports; }; var dataGenerator = DataGenerator(); // 3 canvases var chartW = 1000, chartH = 100; var scaleX = d3.scale.linear().domain([0, 100]).range([0, chartW]); var scaleY = d3.scale.linear().domain([0, 1000]).range([chartH, 0]); var canvases = []; function renderCanvas(_selector){ var data = dataGenerator.generate(); var canvasSelection = d3.select(_selector).attr({width: chartW, height: chartH}); var canvasNode = canvasSelection.node(); var ctx = canvasNode.getContext('2d'); ctx.globalCompositeOperation = "source-over"; ctx.fillStyle = 'aliceblue'; ctx.strokeStyle = 'orange'; ctx.clearRect(0, 0, canvasNode.width, canvasNode.height); ctx.fillRect(0, 0, chartW, chartH); ctx.strokeRect(0, 0, chartW, chartH); ctx.strokeStyle = 'skyblue'; ctx.beginPath(); var x, y, i; for(i=0; i<data.length; i++){ x = ~~scaleX(data[i].x); y = ~~scaleY(data[i].y); ctx.lineTo(x, y); } ctx.stroke(); canvases.push(canvasNode); } renderCanvas('.before canvas'); renderCanvas('.current canvas'); renderCanvas('.after canvas'); // plot/cloneNode before/current/after canvases on jump var containerW = d3.select('.gallery-container').node().getBoundingClientRect().width; var slideSelection = d3.select('.gallery-slide'); var slideEl = slideSelection.node(); d3.select('.gallery-slide').node().scrollLeft = containerW; function scrollLeftTween(scrollLeft) { return function() { var i = d3.interpolateNumber(this.scrollLeft, scrollLeft); return function(t) { this.scrollLeft = i(t); }; }; } var shiftStepCount = 100; var scrollDuration = 10000; var shiftStepSize = containerW/shiftStepCount; var shiftDuration = scrollDuration/shiftStepCount; var canvasIndices = [0, 1, 2]; function shiftPanel(_isGoingRight, _duration, _easingFuncName, _stepNum){ if(typeof _isGoingRight === 'undefined') _isGoingRight = true; if(typeof _stepNum === 'undefined') _stepNum = 1; var directionSign = (_isGoingRight) ? 1 : -1; if(slideEl.scrollLeft >= containerW * 2 - 2 || slideEl.scrollLeft <= 2){ slideSelection.interrupt(); (directionSign === 1) ? canvasIndices.push(canvasIndices.shift()) : canvasIndices.unshift(canvasIndices.pop()); slideEl.scrollLeft = containerW; document.querySelector('.before').appendChild(canvases[canvasIndices[0]]); document.querySelector('.current').appendChild(canvases[canvasIndices[1]]); document.querySelector('.after').appendChild(canvases[canvasIndices[2]]); } else{ slideSelection.transition().duration(_duration) .ease(_easingFuncName) .tween("uniquetweenname", scrollLeftTween(slideEl.scrollLeft + (shiftStepSize *_stepNum) * directionSign)) } } var timer, isGoingRight = true; function setTimer(_isGoingRight, _duration, ease, stepNum){ clearInterval(timer); shiftPanel(_isGoingRight, _duration, ease, stepNum); return setInterval(function(){ shiftPanel(_isGoingRight, _duration, ease, stepNum); }, _duration); } timer = setTimer(true, 500, 'cubic-in-out'); d3.selectAll('.handle').on('mouseenter', function(d, i){ isGoingRight = this.className.split(' ').indexOf('right') != -1; timer = setTimer(isGoingRight, 20, 'linear', 2); }) .on('mouseout', function(d, i){ if (d3.event.target === this){ if(d3.event.toElement.className === 'gallery-slide') clearInterval(timer); else timer = setTimer(true, 500, 'cubic-in-out'); } }) .on('mousemove', function(d, i){ var isRight = this.className.split(' ').indexOf('right') != -1; var handleWidth = this.getBoundingClientRect().width; var mouseX = d3.mouse(this)[0]; var speed = !isRight ? mouseX / handleWidth : (1 - mouseX / handleWidth); timer = setTimer(isGoingRight, speed*100, 'linear', 2); }); slideSelection.on('mouseenter', function(d, i){ clearInterval(timer); }) .on('mouseout', function(d, i){ if (d3.event.target === this){ timer = setTimer(true, 500, 'cubic-in-out'); } }); </script> </body> </html>
Modified
http://d3js.org/d3.v3.min.js
to a secure url
https://d3js.org/d3.v3.min.js