()
| 234 | g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : ''); |
| 235 | |
| 236 | function updateInteractiveLayer() { |
| 237 | // Always clear needs-update flag regardless of whether or not |
| 238 | // we will actually do anything (avoids needless invocations). |
| 239 | needsUpdate = false; |
| 240 | |
| 241 | if (!interactive) return false; |
| 242 | |
| 243 | // inject series and point index for reference into voronoi |
| 244 | if (useVoronoi === true) { |
| 245 | |
| 246 | // nuke all voronoi paths on reload and recreate them |
| 247 | wrap.select('.nv-point-paths').selectAll('path').remove(); |
| 248 | |
| 249 | var vertices = d3.merge(data.map(function(group, groupIndex) { |
| 250 | return group.values |
| 251 | .map(function(point, pointIndex) { |
| 252 | // *Adding noise to make duplicates very unlikely |
| 253 | // *Injecting series and point index for reference |
| 254 | // *Adding a 'jitter' to the points, because there's an issue in d3.geom.voronoi. |
| 255 | var pX = getX(point,pointIndex); |
| 256 | var pY = getY(point,pointIndex); |
| 257 | |
| 258 | return [nv.utils.NaNtoZero(x(pX)) + Math.random() * 1e-4, |
| 259 | nv.utils.NaNtoZero(y(pY)) + Math.random() * 1e-4, |
| 260 | groupIndex, |
| 261 | pointIndex, point]; |
| 262 | }) |
| 263 | .filter(function(pointArray, pointIndex) { |
| 264 | return pointActive(pointArray[4], pointIndex); // Issue #237.. move filter to after map, so pointIndex is correct! |
| 265 | }) |
| 266 | }) |
| 267 | ); |
| 268 | |
| 269 | if (vertices.length == 0) return false; // No active points, we're done |
| 270 | if (vertices.length < 3) { |
| 271 | // Issue #283 - Adding 2 dummy points to the voronoi b/c voronoi requires min 3 points to work |
| 272 | vertices.push([x.range()[0] - 20, y.range()[0] - 20, null, null]); |
| 273 | vertices.push([x.range()[1] + 20, y.range()[1] + 20, null, null]); |
| 274 | vertices.push([x.range()[0] - 20, y.range()[0] + 20, null, null]); |
| 275 | vertices.push([x.range()[1] + 20, y.range()[1] - 20, null, null]); |
| 276 | } |
| 277 | |
| 278 | // keep voronoi sections from going more than 10 outside of graph |
| 279 | // to avoid overlap with other things like legend etc |
| 280 | var bounds = d3.geom.polygon([ |
| 281 | [-10,-10], |
| 282 | [-10,height + 10], |
| 283 | [width + 10,height + 10], |
| 284 | [width + 10,-10] |
| 285 | ]); |
| 286 | |
| 287 | // delete duplicates from vertices - essential assumption for d3.geom.voronoi |
| 288 | var epsilon = 1e-4; // Uses 1e-4 to determine equivalence. |
| 289 | vertices = vertices.sort(function(a,b){return ((a[0] - b[0]) || (a[1] - b[1]))}); |
| 290 | for (var i = 0; i < vertices.length - 1; ) { |
| 291 | if ((Math.abs(vertices[i][0] - vertices[i+1][0]) < epsilon) && |
| 292 | (Math.abs(vertices[i][1] - vertices[i+1][1]) < epsilon)) { |
| 293 | vertices.splice(i+1, 1); |
no test coverage detected
searching dependent graphs…