@windborne/grapher 1.0.27 → 1.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windborne/grapher",
3
- "version": "1.0.27",
3
+ "version": "1.0.29",
4
4
  "description": "Graphing library",
5
5
  "main": "src/index.js",
6
6
  "module": "dist/bundle.esm.js",
@@ -171,7 +171,11 @@ function GraphBody({ stateController, webgl, bodyHeight, boundsSelectionEnabled,
171
171
  clientX: touch.clientX,
172
172
  clientY: touch.clientY
173
173
  });
174
- if (event.cancelable) event.preventDefault();
174
+
175
+ // Only prevent default if touch is within grapher bounds
176
+ if (event.cancelable && event.target.closest('.graph-body')) {
177
+ event.preventDefault();
178
+ }
175
179
  };
176
180
 
177
181
  const onGlobalTouchMove = (event) => {
@@ -184,7 +188,11 @@ function GraphBody({ stateController, webgl, bodyHeight, boundsSelectionEnabled,
184
188
  clientX: touch.clientX,
185
189
  clientY: touch.clientY
186
190
  });
187
- if (event.cancelable) event.preventDefault();
191
+
192
+ // Only prevent default if touch is within grapher bounds
193
+ if (event.cancelable && event.target.closest('.graph-body')) {
194
+ event.preventDefault();
195
+ }
188
196
  };
189
197
 
190
198
  const onGlobalTouchEnd = () => {
@@ -8,8 +8,7 @@ import drawBars from './draw_bars';
8
8
  import drawLine from './draw_line';
9
9
  import LineProgram from './line_program';
10
10
  import ShadowProgram from './shadow_program';
11
- import sizeCanvas from './size_canvas';
12
- import { applyReducedOpacity } from "../helpers/colors";
11
+ import sizeCanvas, { DPI_INCREASE } from './size_canvas';
13
12
 
14
13
  export default class GraphBodyRenderer extends Eventable {
15
14
 
@@ -161,21 +160,34 @@ export default class GraphBodyRenderer extends Eventable {
161
160
  }
162
161
  }
163
162
 
164
- const getIndividualPoints = (useDataSpace) => {
163
+ const getIndividualPoints = (useDataSpace, includeBeyondBounds = false) => {
165
164
  if (!useDataSpace && inRenderSpace && inRenderSpace.yValues) {
165
+ if (!bounds) {
166
+ bounds = singleSeries.axis.currentBounds;
167
+ }
168
+
166
169
  const individualPoints = [];
167
170
  const { yValues, nullMask } = inRenderSpace;
171
+ const threshold = yValues.length / 2;
172
+ let pastThreshold = 0;
173
+ const samples = [];
168
174
 
169
175
  for (let pixelX = 0; pixelX < yValues.length; pixelX++) {
170
176
  if (nullMask[pixelX] === 0) {
171
- individualPoints.push([pixelX, yValues[pixelX]]);
177
+ const xCoord = pixelX * DPI_INCREASE;
178
+ individualPoints.push([xCoord, yValues[pixelX]]);
179
+
180
+ if (pixelX > threshold) {
181
+ pastThreshold++;
182
+ if (samples.length < 3) samples.push({pixelX, xCoord, nullMask: nullMask[pixelX]});
183
+ }
172
184
  }
173
185
  }
174
186
 
175
- if (individualPoints.length === 0) {
176
- return getIndividualPoints(true);
187
+ if (individualPoints.length < 50) {
188
+ return getIndividualPoints(true, includeBeyondBounds);
177
189
  }
178
-
190
+
179
191
  return individualPoints;
180
192
  }
181
193
 
@@ -189,6 +201,12 @@ export default class GraphBodyRenderer extends Eventable {
189
201
  data = singleSeries.inDataSpace;
190
202
  }
191
203
 
204
+ let boundsMinX = bounds.minX instanceof Date ? bounds.minX.getTime() : bounds.minX;
205
+ let boundsMaxX = bounds.maxX instanceof Date ? bounds.maxX.getTime() : bounds.maxX;
206
+
207
+ let foundBeyondBounds = false;
208
+ let lastPointBeforeBounds = null;
209
+
192
210
  for (let i = 0; i < data.length; i++) {
193
211
  let x, y;
194
212
 
@@ -206,15 +224,36 @@ export default class GraphBodyRenderer extends Eventable {
206
224
  }
207
225
 
208
226
  let xValue = x instanceof Date ? x.getTime() : x;
209
- let boundsMinX = bounds.minX instanceof Date ? bounds.minX.getTime() : bounds.minX;
210
- let boundsMaxX = bounds.maxX instanceof Date ? bounds.maxX.getTime() : bounds.maxX;
227
+
228
+ if (xValue < boundsMinX) {
229
+ if (includeBeyondBounds) {
230
+ lastPointBeforeBounds = [xValue, y];
231
+ }
232
+ continue;
233
+ }
234
+
235
+ if (xValue > boundsMaxX) {
236
+ if (includeBeyondBounds && !foundBeyondBounds) {
237
+ foundBeyondBounds = true;
238
+ } else {
239
+ break;
240
+ }
241
+ }
211
242
 
212
- individualPoints.push([
213
- (xValue - boundsMinX) / (boundsMaxX - boundsMinX) * this._sizing.renderWidth,
214
- (1.0 - (y - bounds.minY) / (bounds.maxY - bounds.minY)) * this._sizing.renderHeight
215
- ]);
243
+ const renderWidth = this._sizing.renderWidth / DPI_INCREASE;
244
+ const xCoord = (xValue - boundsMinX) / (boundsMaxX - boundsMinX) * (renderWidth - 1) * DPI_INCREASE;
245
+ const yCoord = (1.0 - (y - bounds.minY) / (bounds.maxY - bounds.minY)) * this._sizing.renderHeight;
246
+
247
+ individualPoints.push([xCoord, yCoord]);
216
248
  }
217
249
 
250
+ if (lastPointBeforeBounds && includeBeyondBounds) {
251
+ const [beforeXValue, beforeY] = lastPointBeforeBounds;
252
+ const renderWidth = this._sizing.renderWidth / DPI_INCREASE;
253
+ const beforeXCoord = (beforeXValue - boundsMinX) / (boundsMaxX - boundsMinX) * (renderWidth - 1) * DPI_INCREASE;
254
+ const beforeYCoord = (1.0 - (beforeY - bounds.minY) / (bounds.maxY - bounds.minY)) * this._sizing.renderHeight;
255
+ individualPoints.unshift([beforeXCoord, beforeYCoord]);
256
+ }
218
257
 
219
258
  return individualPoints;
220
259
  };
@@ -424,7 +463,7 @@ export default class GraphBodyRenderer extends Eventable {
424
463
  shadowParams.selectionBounds = selection || bounds;
425
464
  }
426
465
 
427
- this._shadowProgram.draw(getIndividualPoints(false), shadowParams);
466
+ this._shadowProgram.draw(getIndividualPoints(false, true), shadowParams);
428
467
 
429
468
  if (this._webgl) {
430
469
  const gl = this._context;
@@ -433,7 +472,6 @@ export default class GraphBodyRenderer extends Eventable {
433
472
  gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
434
473
  }
435
474
 
436
-
437
475
  if (singleSeries.zeroLineWidth && singleSeries.zeroLineWidth > 0) {
438
476
  if (this._context2d) {
439
477
  this._context2d.save();
@@ -253,10 +253,28 @@ export default class ShadowProgram {
253
253
  });
254
254
  }
255
255
  } else {
256
- const trapezoid = { x1, y1, x2, y2, bottomY1, bottomY2 };
256
+ // Skip trapezoids completely outside canvas
257
+ if (x1 > width || x2 < 0) {
258
+ continue;
259
+ }
260
+
261
+ // Clip trapezoid to canvas bounds if it extends beyond
262
+ let finalX2 = x2;
263
+ let finalY2 = y2;
264
+ let finalBottomY2 = bottomY2;
265
+
266
+ if (x2 > width) {
267
+ const ratio = (width - x1) / (x2 - x1);
268
+ finalX2 = width;
269
+ finalY2 = y1 + (y2 - y1) * ratio;
270
+ finalBottomY2 = bottomY1 + (bottomY2 - bottomY1) * ratio;
271
+ }
272
+
273
+ const trapezoid = { x1, y1, x2: finalX2, y2: finalY2, bottomY1, bottomY2: finalBottomY2 };
257
274
  trapezoids.push(trapezoid);
258
275
  }
259
276
  }
277
+
260
278
 
261
279
 
262
280
  if (trapezoids.length === 0) {
@@ -264,7 +282,6 @@ export default class ShadowProgram {
264
282
  }
265
283
 
266
284
  const geometry = this.generateTrapezoidGeometry(trapezoids);
267
-
268
285
  const positionLoc = gl.getAttribLocation(this._program, "position");
269
286
  const trapezoidBoundsLoc = gl.getAttribLocation(
270
287
  this._program,