From fac70b2918fbe87c37c81ecaa1ced5be6c22a48c Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Fri, 7 Oct 2016 14:34:32 +0200 Subject: [PATCH 1/7] Admit date X axes for fast (non-fancy) scattergl --- src/traces/scattergl/convert.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/traces/scattergl/convert.js b/src/traces/scattergl/convert.js index fe7a44ebaf3..aebf73d7aaa 100644 --- a/src/traces/scattergl/convert.js +++ b/src/traces/scattergl/convert.js @@ -135,7 +135,7 @@ proto.handlePick = function(pickResult) { // check if trace is fancy proto.isFancy = function(options) { - if(this.scene.xaxis.type !== 'linear') return true; + if(this.scene.xaxis.type !== 'linear' && this.scene.xaxis.type !== 'date') return true; if(this.scene.yaxis.type !== 'linear') return true; if(!options.x || !options.y) return true; @@ -279,7 +279,8 @@ proto.updateFast = function(options) { yy = y[i]; // check for isNaN is faster but doesn't skip over nulls - if(!isNumeric(xx) || !isNumeric(yy)) continue; + if(!isNumeric(yy)) continue; + if(!isNumeric(xx) && !(xx instanceof Date)) continue; idToIndex[pId++] = i; From a23756de213ecc8d2fb400c1d5b5a713a6a60c79 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Fri, 7 Oct 2016 16:23:28 +0200 Subject: [PATCH 2/7] Admit date X axes for fast (non-fancy) scattergl hover tooltip too --- src/traces/scattergl/convert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traces/scattergl/convert.js b/src/traces/scattergl/convert.js index aebf73d7aaa..67e85b17141 100644 --- a/src/traces/scattergl/convert.js +++ b/src/traces/scattergl/convert.js @@ -118,7 +118,7 @@ proto.handlePick = function(pickResult) { trace: this, dataCoord: pickResult.dataCoord, traceCoord: [ - this.pickXData[index], + Number(this.pickXData[index]), // non-fancy scattergl has Dates this.pickYData[index] ], textLabel: Array.isArray(this.textLabels) ? From ab4ffbfddc65183a8149a43c02e252eab0e6994d Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Mon, 10 Oct 2016 19:04:25 +0200 Subject: [PATCH 3/7] adding tests for fancy vs non-fancy scattergl --- test/jasmine/tests/axes_test.js | 79 +++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index 619a22098cf..a885feeaeee 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -4,6 +4,7 @@ var Plots = require('@src/plots/plots'); var Lib = require('@src/lib'); var Color = require('@src/components/color'); var tinycolor = require('tinycolor2'); +var hasWebGLSupport = require('../assets/has_webgl_support'); var handleTickValueDefaults = require('@src/plots/cartesian/tick_value_defaults'); var Axes = PlotlyInternal.Axes; @@ -387,6 +388,84 @@ describe('Test axes', function() { }); }); + describe('date axis', function() { + + if(!hasWebGLSupport('axes_test date axis')) return; + + var gd; + + beforeEach(function() { + gd = createGraphDiv(); + }); + + afterEach(destroyGraphDiv); + + it('should use the fancy gl-vis/gl-scatter2d', function() { + PlotlyInternal.plot(gd, [{ + type: 'scattergl', + 'marker': { + 'color': 'rgb(31, 119, 180)', + 'size': 18, + 'symbol': [ + 'diamond', + 'cross' + ] + }, + x: [new Date('2016-10-10'), new Date('2016-10-12')], + y: [15, 16] + }]); + + expect(gd._fullLayout.xaxis.type).toBe('date'); + expect(gd._fullLayout.yaxis.type).toBe('linear'); + expect(gd._fullData[0].type).toBe('scattergl'); + expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d'); + + // one way of check which renderer - fancy vs not - we're using + expect(gd._fullLayout._plots.xy._scene2d.glplot.objects[3].pointCount).toBe(0); + }); + + it('should use the fancy gl-vis/gl-scatter2d once again', function() { + PlotlyInternal.plot(gd, [{ + type: 'scattergl', + 'marker': { + 'color': 'rgb(31, 119, 180)', + 'size': 36, + 'symbol': [ + 'circle', + 'cross' + ] + }, + x: [new Date('2016-10-10'), new Date('2016-10-11')], + y: [15, 16] + }]); + + expect(gd._fullLayout.xaxis.type).toBe('date'); + expect(gd._fullLayout.yaxis.type).toBe('linear'); + expect(gd._fullData[0].type).toBe('scattergl'); + expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d'); + + // one way of check which renderer - fancy vs not - we're using + expect(gd._fullLayout._plots.xy._scene2d.glplot.objects[3].pointCount).toBe(0); + }); + + it('should now use the non-fancy gl-vis/gl-scatter2d', function() { + PlotlyInternal.plot(gd, [{ + type: 'scattergl', + mode: 'markers', // important, as otherwise lines are assumed (which needs fancy) + x: [new Date('2016-10-10'), new Date('2016-10-11')], + y: [15, 16] + }]); + + expect(gd._fullLayout.xaxis.type).toBe('date'); + expect(gd._fullLayout.yaxis.type).toBe('linear'); + expect(gd._fullData[0].type).toBe('scattergl'); + expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d'); + + expect(gd._fullLayout._plots.xy._scene2d.glplot.objects[3].pointCount).toBe(2); + }); + + }); + describe('categoryorder', function() { var gd; From f5d61130f5df69bb8aab3dad7a6fd3baa93b79a7 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Mon, 17 Oct 2016 15:53:17 +0200 Subject: [PATCH 4/7] separate the new date rendering tests from axes_test.js --- test/jasmine/tests/axes_test.js | 79 ----------------- .../tests/gl2d_date_axis_render_test.js | 84 +++++++++++++++++++ 2 files changed, 84 insertions(+), 79 deletions(-) create mode 100644 test/jasmine/tests/gl2d_date_axis_render_test.js diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index a885feeaeee..619a22098cf 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -4,7 +4,6 @@ var Plots = require('@src/plots/plots'); var Lib = require('@src/lib'); var Color = require('@src/components/color'); var tinycolor = require('tinycolor2'); -var hasWebGLSupport = require('../assets/has_webgl_support'); var handleTickValueDefaults = require('@src/plots/cartesian/tick_value_defaults'); var Axes = PlotlyInternal.Axes; @@ -388,84 +387,6 @@ describe('Test axes', function() { }); }); - describe('date axis', function() { - - if(!hasWebGLSupport('axes_test date axis')) return; - - var gd; - - beforeEach(function() { - gd = createGraphDiv(); - }); - - afterEach(destroyGraphDiv); - - it('should use the fancy gl-vis/gl-scatter2d', function() { - PlotlyInternal.plot(gd, [{ - type: 'scattergl', - 'marker': { - 'color': 'rgb(31, 119, 180)', - 'size': 18, - 'symbol': [ - 'diamond', - 'cross' - ] - }, - x: [new Date('2016-10-10'), new Date('2016-10-12')], - y: [15, 16] - }]); - - expect(gd._fullLayout.xaxis.type).toBe('date'); - expect(gd._fullLayout.yaxis.type).toBe('linear'); - expect(gd._fullData[0].type).toBe('scattergl'); - expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d'); - - // one way of check which renderer - fancy vs not - we're using - expect(gd._fullLayout._plots.xy._scene2d.glplot.objects[3].pointCount).toBe(0); - }); - - it('should use the fancy gl-vis/gl-scatter2d once again', function() { - PlotlyInternal.plot(gd, [{ - type: 'scattergl', - 'marker': { - 'color': 'rgb(31, 119, 180)', - 'size': 36, - 'symbol': [ - 'circle', - 'cross' - ] - }, - x: [new Date('2016-10-10'), new Date('2016-10-11')], - y: [15, 16] - }]); - - expect(gd._fullLayout.xaxis.type).toBe('date'); - expect(gd._fullLayout.yaxis.type).toBe('linear'); - expect(gd._fullData[0].type).toBe('scattergl'); - expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d'); - - // one way of check which renderer - fancy vs not - we're using - expect(gd._fullLayout._plots.xy._scene2d.glplot.objects[3].pointCount).toBe(0); - }); - - it('should now use the non-fancy gl-vis/gl-scatter2d', function() { - PlotlyInternal.plot(gd, [{ - type: 'scattergl', - mode: 'markers', // important, as otherwise lines are assumed (which needs fancy) - x: [new Date('2016-10-10'), new Date('2016-10-11')], - y: [15, 16] - }]); - - expect(gd._fullLayout.xaxis.type).toBe('date'); - expect(gd._fullLayout.yaxis.type).toBe('linear'); - expect(gd._fullData[0].type).toBe('scattergl'); - expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d'); - - expect(gd._fullLayout._plots.xy._scene2d.glplot.objects[3].pointCount).toBe(2); - }); - - }); - describe('categoryorder', function() { var gd; diff --git a/test/jasmine/tests/gl2d_date_axis_render_test.js b/test/jasmine/tests/gl2d_date_axis_render_test.js new file mode 100644 index 00000000000..24a4deb37d1 --- /dev/null +++ b/test/jasmine/tests/gl2d_date_axis_render_test.js @@ -0,0 +1,84 @@ +var PlotlyInternal = require('@src/plotly'); + +var hasWebGLSupport = require('../assets/has_webgl_support'); + +var createGraphDiv = require('../assets/create_graph_div'); +var destroyGraphDiv = require('../assets/destroy_graph_div'); + +describe('date axis', function() { + + if(!hasWebGLSupport('axes_test date axis')) return; + + var gd; + + beforeEach(function() { + gd = createGraphDiv(); + }); + + afterEach(destroyGraphDiv); + + it('should use the fancy gl-vis/gl-scatter2d', function() { + PlotlyInternal.plot(gd, [{ + type: 'scattergl', + 'marker': { + 'color': 'rgb(31, 119, 180)', + 'size': 18, + 'symbol': [ + 'diamond', + 'cross' + ] + }, + x: [new Date('2016-10-10'), new Date('2016-10-12')], + y: [15, 16] + }]); + + expect(gd._fullLayout.xaxis.type).toBe('date'); + expect(gd._fullLayout.yaxis.type).toBe('linear'); + expect(gd._fullData[0].type).toBe('scattergl'); + expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d'); + + // one way of check which renderer - fancy vs not - we're using + expect(gd._fullLayout._plots.xy._scene2d.glplot.objects[3].pointCount).toBe(0); + }); + + it('should use the fancy gl-vis/gl-scatter2d once again', function() { + PlotlyInternal.plot(gd, [{ + type: 'scattergl', + 'marker': { + 'color': 'rgb(31, 119, 180)', + 'size': 36, + 'symbol': [ + 'circle', + 'cross' + ] + }, + x: [new Date('2016-10-10'), new Date('2016-10-11')], + y: [15, 16] + }]); + + expect(gd._fullLayout.xaxis.type).toBe('date'); + expect(gd._fullLayout.yaxis.type).toBe('linear'); + expect(gd._fullData[0].type).toBe('scattergl'); + expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d'); + + // one way of check which renderer - fancy vs not - we're using + expect(gd._fullLayout._plots.xy._scene2d.glplot.objects[3].pointCount).toBe(0); + }); + + it('should now use the non-fancy gl-vis/gl-scatter2d', function() { + PlotlyInternal.plot(gd, [{ + type: 'scattergl', + mode: 'markers', // important, as otherwise lines are assumed (which needs fancy) + x: [new Date('2016-10-10'), new Date('2016-10-11')], + y: [15, 16] + }]); + + expect(gd._fullLayout.xaxis.type).toBe('date'); + expect(gd._fullLayout.yaxis.type).toBe('linear'); + expect(gd._fullData[0].type).toBe('scattergl'); + expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d'); + + expect(gd._fullLayout._plots.xy._scene2d.glplot.objects[3].pointCount).toBe(2); + }); + +}); From 3c790680089016dd0e14432d08b9518e6bf0c99d Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Wed, 19 Oct 2016 20:53:43 +0200 Subject: [PATCH 5/7] Admit isDateTime === true values (e.g. date strings) in non-fancy scattergl --- src/traces/scattergl/convert.js | 30 ++++++++++++------- .../tests/gl2d_date_axis_render_test.js | 15 ++++++++++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/traces/scattergl/convert.js b/src/traces/scattergl/convert.js index 67e85b17141..b0eb4be64ed 100644 --- a/src/traces/scattergl/convert.js +++ b/src/traces/scattergl/convert.js @@ -114,11 +114,13 @@ proto.handlePick = function(pickResult) { index = this.idToIndex[pickResult.pointId]; } + var x = this.pickXData[index]; + return { trace: this, dataCoord: pickResult.dataCoord, traceCoord: [ - Number(this.pickXData[index]), // non-fancy scattergl has Dates + isNumeric(x) || !Lib.isDateTime(x) ? x : Lib.dateTime2ms(x), this.pickYData[index] ], textLabel: Array.isArray(this.textLabels) ? @@ -270,7 +272,7 @@ proto.updateFast = function(options) { pId = 0, ptr = 0; - var xx, yy; + var xx, yy, fastType; // TODO add 'very fast' mode that bypasses this loop // TODO bypass this on modebar +/- zoom @@ -279,18 +281,24 @@ proto.updateFast = function(options) { yy = y[i]; // check for isNaN is faster but doesn't skip over nulls - if(!isNumeric(yy)) continue; - if(!isNumeric(xx) && !(xx instanceof Date)) continue; + fastType = isNumeric(xx) || xx instanceof Date; - idToIndex[pId++] = i; + if(isNumeric(yy) && (fastType || Lib.isDateTime(xx))) { - positions[ptr++] = xx; - positions[ptr++] = yy; + if(!fastType) { + xx = Lib.dateTime2ms(xx); + } + + idToIndex[pId++] = i; - bounds[0] = Math.min(bounds[0], xx); - bounds[1] = Math.min(bounds[1], yy); - bounds[2] = Math.max(bounds[2], xx); - bounds[3] = Math.max(bounds[3], yy); + positions[ptr++] = xx; + positions[ptr++] = yy; + + bounds[0] = Math.min(bounds[0], xx); + bounds[1] = Math.min(bounds[1], yy); + bounds[2] = Math.max(bounds[2], xx); + bounds[3] = Math.max(bounds[3], yy); + } } positions = truncate(positions, ptr); diff --git a/test/jasmine/tests/gl2d_date_axis_render_test.js b/test/jasmine/tests/gl2d_date_axis_render_test.js index 24a4deb37d1..53392de3e76 100644 --- a/test/jasmine/tests/gl2d_date_axis_render_test.js +++ b/test/jasmine/tests/gl2d_date_axis_render_test.js @@ -81,4 +81,19 @@ describe('date axis', function() { expect(gd._fullLayout._plots.xy._scene2d.glplot.objects[3].pointCount).toBe(2); }); + it('should use the non-fancy gl-vis/gl-scatter2d with string dates', function() { + PlotlyInternal.plot(gd, [{ + type: 'scattergl', + mode: 'markers', // important, as otherwise lines are assumed (which needs fancy) + x: ['2016-10-10', '2016-10-11'], + y: [15, 16] + }]); + + expect(gd._fullLayout.xaxis.type).toBe('date'); + expect(gd._fullLayout.yaxis.type).toBe('linear'); + expect(gd._fullData[0].type).toBe('scattergl'); + expect(gd._fullData[0]._module.basePlotModule.name).toBe('gl2d'); + + expect(gd._fullLayout._plots.xy._scene2d.glplot.objects[3].pointCount).toBe(2); + }); }); From 5b71b47d0ed1d437708da2a293481e911828865a Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Thu, 20 Oct 2016 10:57:26 +0200 Subject: [PATCH 6/7] doing cheaper, probabilistic checks outside the scattergl conversion loop --- src/plots/cartesian/axis_autotype.js | 73 ++++++++++++++++++++++++++++ src/plots/cartesian/axis_defaults.js | 61 +---------------------- src/traces/scattergl/convert.js | 34 +++++++++++-- 3 files changed, 103 insertions(+), 65 deletions(-) create mode 100644 src/plots/cartesian/axis_autotype.js diff --git a/src/plots/cartesian/axis_autotype.js b/src/plots/cartesian/axis_autotype.js new file mode 100644 index 00000000000..8202a7778d3 --- /dev/null +++ b/src/plots/cartesian/axis_autotype.js @@ -0,0 +1,73 @@ +/** +* Copyright 2012-2016, Plotly, Inc. +* All rights reserved. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + + +'use strict'; + +var isNumeric = require('fast-isnumeric'); + +var Lib = require('../../lib'); +var cleanDatum = require('./clean_datum'); + +module.exports = function autoType(array) { + if(moreDates(array)) return 'date'; + if(category(array)) return 'category'; + if(linearOK(array)) return 'linear'; + else return '-'; +}; + +// is there at least one number in array? If not, we should leave +// ax.type empty so it can be autoset later +function linearOK(array) { + if(!array) return false; + + for(var i = 0; i < array.length; i++) { + if(isNumeric(array[i])) return true; + } + + return false; +} + +// does the array a have mostly dates rather than numbers? +// note: some values can be neither (such as blanks, text) +// 2- or 4-digit integers can be both, so require twice as many +// dates as non-dates, to exclude cases with mostly 2 & 4 digit +// numbers and a few dates +function moreDates(a) { + var dcnt = 0, + ncnt = 0, + // test at most 1000 points, evenly spaced + inc = Math.max(1, (a.length - 1) / 1000), + ai; + + for(var i = 0; i < a.length; i += inc) { + ai = a[Math.round(i)]; + if(Lib.isDateTime(ai)) dcnt += 1; + if(isNumeric(ai)) ncnt += 1; + } + + return (dcnt > ncnt * 2); +} + +// are the (x,y)-values in td.data mostly text? +// require twice as many categories as numbers +function category(a) { + // test at most 1000 points + var inc = Math.max(1, (a.length - 1) / 1000), + curvenums = 0, + curvecats = 0, + ai; + + for(var i = 0; i < a.length; i += inc) { + ai = cleanDatum(a[Math.round(i)]); + if(isNumeric(ai)) curvenums++; + else if(typeof ai === 'string' && ai !== '' && ai !== 'None') curvecats++; + } + + return curvecats > curvenums * 2; +} diff --git a/src/plots/cartesian/axis_defaults.js b/src/plots/cartesian/axis_defaults.js index 015ec9d7cd0..69776d25ea3 100644 --- a/src/plots/cartesian/axis_defaults.js +++ b/src/plots/cartesian/axis_defaults.js @@ -23,9 +23,8 @@ var handleTickLabelDefaults = require('./tick_label_defaults'); var handleCategoryOrderDefaults = require('./category_order_defaults'); var setConvert = require('./set_convert'); var orderedCategories = require('./ordered_categories'); -var cleanDatum = require('./clean_datum'); var axisIds = require('./axis_ids'); - +var autoType = require('./axis_autotype'); /** * options: object containing: @@ -207,13 +206,6 @@ function isBoxWithoutPositionCoords(trace, axLetter) { ); } -function autoType(array) { - if(moreDates(array)) return 'date'; - if(category(array)) return 'category'; - if(linearOK(array)) return 'linear'; - else return '-'; -} - function getFirstNonEmptyTrace(data, id, axLetter) { for(var i = 0; i < data.length; i++) { var trace = data[i]; @@ -228,54 +220,3 @@ function getFirstNonEmptyTrace(data, id, axLetter) { } } } - -// is there at least one number in array? If not, we should leave -// ax.type empty so it can be autoset later -function linearOK(array) { - if(!array) return false; - - for(var i = 0; i < array.length; i++) { - if(isNumeric(array[i])) return true; - } - - return false; -} - -// does the array a have mostly dates rather than numbers? -// note: some values can be neither (such as blanks, text) -// 2- or 4-digit integers can be both, so require twice as many -// dates as non-dates, to exclude cases with mostly 2 & 4 digit -// numbers and a few dates -function moreDates(a) { - var dcnt = 0, - ncnt = 0, - // test at most 1000 points, evenly spaced - inc = Math.max(1, (a.length - 1) / 1000), - ai; - - for(var i = 0; i < a.length; i += inc) { - ai = a[Math.round(i)]; - if(Lib.isDateTime(ai)) dcnt += 1; - if(isNumeric(ai)) ncnt += 1; - } - - return (dcnt > ncnt * 2); -} - -// are the (x,y)-values in td.data mostly text? -// require twice as many categories as numbers -function category(a) { - // test at most 1000 points - var inc = Math.max(1, (a.length - 1) / 1000), - curvenums = 0, - curvecats = 0, - ai; - - for(var i = 0; i < a.length; i += inc) { - ai = cleanDatum(a[Math.round(i)]); - if(isNumeric(ai)) curvenums++; - else if(typeof ai === 'string' && ai !== '' && ai !== 'None') curvecats++; - } - - return curvecats > curvenums * 2; -} diff --git a/src/traces/scattergl/convert.js b/src/traces/scattergl/convert.js index b0eb4be64ed..06c6d2f1a18 100644 --- a/src/traces/scattergl/convert.js +++ b/src/traces/scattergl/convert.js @@ -17,6 +17,7 @@ var isNumeric = require('fast-isnumeric'); var Lib = require('../../lib'); var Axes = require('../../plots/cartesian/axes'); +var autoType = require('../../plots/cartesian/axis_autotype'); var ErrorBars = require('../../components/errorbars'); var str2RGBArray = require('../../lib/str2rgbarray'); var truncate = require('../../lib/float32_truncate'); @@ -261,6 +262,29 @@ proto.update = function(options) { this.color = getTraceColor(options, {}); }; +// We'd ideally know that all values are of fast types; sampling gives no certainty but faster +// (for the future, typed arrays can guarantee it, and Date values can be done with +// representing the epoch milliseconds in a typed array; +// also, perhaps the Python / R interfaces take care of String->Date conversions +// such that there's no need to check for string dates in plotly.js) +// Patterned from axis_defaults.js:moreDates +// Code DRYing is not done to preserve the most direct compilation possible for speed; +// also, there are quite a few differences +function allFastTypesLikely(a) { + var len = a.length, + inc = Math.max(0, (len - 1) / Math.min(Math.max(len, 1), 1000)), + ai; + + for(var i = 0; i < len; i += inc) { + ai = a[Math.floor(i)]; + if(!isNumeric(ai) && !(ai instanceof Date)) { + return false; + } + } + + return true; +} + proto.updateFast = function(options) { var x = this.xData = this.pickXData = options.x; var y = this.yData = this.pickYData = options.y; @@ -272,7 +296,10 @@ proto.updateFast = function(options) { pId = 0, ptr = 0; - var xx, yy, fastType; + var xx, yy; + + var fastType = allFastTypesLikely(x); + var isDateTime = !fastType && autoType(x) === 'date'; // TODO add 'very fast' mode that bypasses this loop // TODO bypass this on modebar +/- zoom @@ -280,10 +307,7 @@ proto.updateFast = function(options) { xx = x[i]; yy = y[i]; - // check for isNaN is faster but doesn't skip over nulls - fastType = isNumeric(xx) || xx instanceof Date; - - if(isNumeric(yy) && (fastType || Lib.isDateTime(xx))) { + if(isNumeric(yy) && (fastType || isDateTime)) { if(!fastType) { xx = Lib.dateTime2ms(xx); From 46a6b6ca2978d5e3a21023628a569fec09b0070f Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Thu, 20 Oct 2016 11:02:34 +0200 Subject: [PATCH 7/7] minor speedup - avoid some boolean checks in the scattergl conversion loop --- src/plots/cartesian/axis_defaults.js | 1 + src/traces/scattergl/convert.js | 31 +++++++++++++++------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/plots/cartesian/axis_defaults.js b/src/plots/cartesian/axis_defaults.js index 69776d25ea3..7d27bffc437 100644 --- a/src/plots/cartesian/axis_defaults.js +++ b/src/plots/cartesian/axis_defaults.js @@ -26,6 +26,7 @@ var orderedCategories = require('./ordered_categories'); var axisIds = require('./axis_ids'); var autoType = require('./axis_autotype'); + /** * options: object containing: * diff --git a/src/traces/scattergl/convert.js b/src/traces/scattergl/convert.js index 06c6d2f1a18..339d32679d2 100644 --- a/src/traces/scattergl/convert.js +++ b/src/traces/scattergl/convert.js @@ -303,25 +303,28 @@ proto.updateFast = function(options) { // TODO add 'very fast' mode that bypasses this loop // TODO bypass this on modebar +/- zoom - for(var i = 0; i < len; ++i) { - xx = x[i]; - yy = y[i]; + if(fastType || isDateTime) { - if(isNumeric(yy) && (fastType || isDateTime)) { + for(var i = 0; i < len; ++i) { + xx = x[i]; + yy = y[i]; - if(!fastType) { - xx = Lib.dateTime2ms(xx); - } + if(isNumeric(yy)) { + + if(!fastType) { + xx = Lib.dateTime2ms(xx); + } - idToIndex[pId++] = i; + idToIndex[pId++] = i; - positions[ptr++] = xx; - positions[ptr++] = yy; + positions[ptr++] = xx; + positions[ptr++] = yy; - bounds[0] = Math.min(bounds[0], xx); - bounds[1] = Math.min(bounds[1], yy); - bounds[2] = Math.max(bounds[2], xx); - bounds[3] = Math.max(bounds[3], yy); + bounds[0] = Math.min(bounds[0], xx); + bounds[1] = Math.min(bounds[1], yy); + bounds[2] = Math.max(bounds[2], xx); + bounds[3] = Math.max(bounds[3], yy); + } } }