@@ -61,17 +61,44 @@ module.exports = function linePoints(d, opts) {
6161 // turn one calcdata point into pixel coordinates
6262 function getPt ( index ) {
6363 var di = d [ index ] ;
64+ if ( ! di ) return false ;
6465 var x = xa . c2p ( di . x ) ;
6566 var y = ya . c2p ( di . y ) ;
6667 if ( x === BADNUM || y === BADNUM ) return di . intoCenter || false ;
6768 return [ x , y ] ;
6869 }
6970
71+ function crossesViewport ( xFrac0 , yFrac0 , xFrac1 , yFrac1 ) {
72+ var dx = xFrac1 - xFrac0 ;
73+ var dy = yFrac1 - yFrac0 ;
74+ var dx0 = 0.5 - xFrac0 ;
75+ var dy0 = 0.5 - yFrac0 ;
76+ var norm2 = dx * dx + dy * dy ;
77+ var dot = dx * dx0 + dy * dy0 ;
78+ if ( dot > 0 && dot < norm2 ) {
79+ var cross = dx0 * dy - dy0 * dx ;
80+ if ( cross * cross < norm2 ) return true ;
81+ }
82+ }
83+
84+ var latestXFrac , latestYFrac ;
7085 // if we're off-screen, increase tolerance over baseTolerance
71- function getTolerance ( pt ) {
86+ function getTolerance ( pt , nextPt ) {
7287 var xFrac = pt [ 0 ] / xa . _length ;
7388 var yFrac = pt [ 1 ] / ya . _length ;
74- return ( 1 + constants . toleranceGrowth * Math . max ( 0 , - xFrac , xFrac - 1 , - yFrac , yFrac - 1 ) ) * baseTolerance ;
89+ var offScreenFraction = Math . max ( 0 , - xFrac , xFrac - 1 , - yFrac , yFrac - 1 ) ;
90+ if ( offScreenFraction && ( latestXFrac !== undefined ) &&
91+ crossesViewport ( xFrac , yFrac , latestXFrac , latestYFrac )
92+ ) {
93+ offScreenFraction = 0 ;
94+ }
95+ if ( offScreenFraction && nextPt &&
96+ crossesViewport ( xFrac , yFrac , nextPt [ 0 ] / xa . _length , nextPt [ 1 ] / ya . _length )
97+ ) {
98+ offScreenFraction = 0 ;
99+ }
100+
101+ return ( 1 + constants . toleranceGrowth * offScreenFraction ) * baseTolerance ;
75102 }
76103
77104 function ptDist ( pt1 , pt2 ) {
@@ -239,6 +266,8 @@ module.exports = function linePoints(d, opts) {
239266 }
240267
241268 function addPt ( pt ) {
269+ latestXFrac = pt [ 0 ] / xa . _length ;
270+ latestYFrac = pt [ 1 ] / ya . _length ;
242271 // Are we more than maxScreensAway off-screen any direction?
243272 // if so, clip to this box, but in such a way that on-screen
244273 // drawing is unchanged
@@ -333,9 +362,11 @@ module.exports = function linePoints(d, opts) {
333362 continue ;
334363 }
335364
365+ var nextPt = getPt ( i + 1 ) ;
366+
336367 clusterRefDist = ptDist ( clusterHighPt , clusterStartPt ) ;
337368
338- if ( clusterRefDist < getTolerance ( clusterHighPt ) * minTolerance ) continue ;
369+ if ( clusterRefDist < getTolerance ( clusterHighPt , nextPt ) * minTolerance ) continue ;
339370
340371 clusterUnitVector = [
341372 ( clusterHighPt [ 0 ] - clusterStartPt [ 0 ] ) / clusterRefDist ,
@@ -350,7 +381,8 @@ module.exports = function linePoints(d, opts) {
350381
351382 // loop over one cluster of points that collapse onto one line
352383 for ( i ++ ; i < d . length ; i ++ ) {
353- thisPt = getPt ( i ) ;
384+ thisPt = nextPt ;
385+ nextPt = getPt ( i + 1 ) ;
354386 if ( ! thisPt ) {
355387 if ( connectGaps ) continue ;
356388 else break ;
@@ -364,7 +396,7 @@ module.exports = function linePoints(d, opts) {
364396 clusterMinDeviation = Math . min ( clusterMinDeviation , thisDeviation ) ;
365397 clusterMaxDeviation = Math . max ( clusterMaxDeviation , thisDeviation ) ;
366398
367- if ( clusterMaxDeviation - clusterMinDeviation > getTolerance ( thisPt ) ) break ;
399+ if ( clusterMaxDeviation - clusterMinDeviation > getTolerance ( thisPt , nextPt ) ) break ;
368400
369401 clusterEndPt = thisPt ;
370402 thisVal = thisVector [ 0 ] * clusterUnitVector [ 0 ] + thisVector [ 1 ] * clusterUnitVector [ 1 ] ;
0 commit comments