How to use hasCSSTransform method in Playwright Internal

Best JavaScript code snippet using playwright-internal

select_test.js

Source:select_test.js Github

copy

Full Screen

1var d3Select = require('../../strict-d3').select;2var d3SelectAll = require('../../strict-d3').selectAll;3var Plotly = require('@lib/index');4var Lib = require('@src/lib');5var click = require('../assets/click');6var doubleClick = require('../assets/double_click');7var DBLCLICKDELAY = require('@src/plot_api/plot_config').dfltConfig.doubleClickDelay;8var createGraphDiv = require('../assets/create_graph_div');9var destroyGraphDiv = require('../assets/destroy_graph_div');10var mouseEvent = require('../assets/mouse_event');11var touchEvent = require('../assets/touch_event');12var LONG_TIMEOUT_INTERVAL = 5 * jasmine.DEFAULT_TIMEOUT_INTERVAL;13var delay = require('../assets/delay');14var sankeyConstants = require('@src/traces/sankey/constants');15function drag(path, options) {16 var len = path.length;17 if(!options) options = {type: 'mouse'};18 Lib.clearThrottle();19 if(options.type === 'touch') {20 touchEvent('touchstart', path[0][0], path[0][1], options);21 path.slice(1, len).forEach(function(pt) {22 Lib.clearThrottle();23 touchEvent('touchmove', pt[0], pt[1], options);24 });25 touchEvent('touchend', path[len - 1][0], path[len - 1][1], options);26 return;27 }28 mouseEvent('mousemove', path[0][0], path[0][1], options);29 mouseEvent('mousedown', path[0][0], path[0][1], options);30 path.slice(1, len).forEach(function(pt) {31 Lib.clearThrottle();32 mouseEvent('mousemove', pt[0], pt[1], options);33 });34 mouseEvent('mouseup', path[len - 1][0], path[len - 1][1], options);35}36function assertSelectionNodes(cornerCnt, outlineCnt, _msg) {37 var msg = _msg ? ' - ' + _msg : '';38 expect(d3SelectAll('.zoomlayer > .zoombox-corners').size())39 .toBe(cornerCnt, 'selection corner count' + msg);40 expect(d3SelectAll('.zoomlayer > .select-outline').size())41 .toBe(outlineCnt, 'selection outline count' + msg);42}43var selectingCnt, selectingData, selectedCnt, selectedData, deselectCnt, doubleClickData;44var selectedPromise, deselectPromise, clickedPromise;45function resetEvents(gd) {46 selectingCnt = 0;47 selectedCnt = 0;48 deselectCnt = 0;49 doubleClickData = null;50 gd.removeAllListeners();51 selectedPromise = new Promise(function(resolve) {52 gd.on('plotly_selecting', function(data) {53 // note that since all of these events test node counts,54 // and all of the other tests at some point check that each of55 // these event handlers was called (via assertEventCounts),56 // we no longer need separate tests that these nodes are created57 // and this way *all* subplot variants get the test.58 assertSelectionNodes(1, 2);59 selectingCnt++;60 selectingData = data;61 });62 gd.on('plotly_selected', function(data) {63 // With click-to-select supported, selection nodes are only64 // in the DOM in certain circumstances.65 if(data &&66 gd._fullLayout.dragmode.indexOf('select') > -1 &&67 gd._fullLayout.dragmode.indexOf('lasso') > -1) {68 assertSelectionNodes(0, 2);69 }70 selectedCnt++;71 selectedData = data;72 resolve();73 });74 });75 deselectPromise = new Promise(function(resolve) {76 gd.on('plotly_deselect', function(data) {77 assertSelectionNodes(0, 0);78 deselectCnt++;79 doubleClickData = data;80 resolve();81 });82 });83 clickedPromise = new Promise(function(resolve) {84 gd.on('plotly_click', function() {85 resolve();86 });87 });88}89function assertEventCounts(selecting, selected, deselect, msg) {90 expect(selectingCnt).toBe(selecting, 'plotly_selecting call count: ' + msg);91 expect(selectedCnt).toBe(selected, 'plotly_selected call count: ' + msg);92 expect(deselectCnt).toBe(deselect, 'plotly_deselect call count: ' + msg);93}94// TODO: in v3, when we get rid of the `plotly_selected->undefined` event, these will95// change to BOXEVENTS = [1, 1, 1], LASSOEVENTS = [4, 1, 1]. See also _run down below96//97// events for box or lasso select mouse moves then a doubleclick98var NOEVENTS = [0, 0, 0];99// deselect used to give an extra plotly_selected event on the first click100// with undefined event data - but now that's gone, since `clickFn` handles this.101var BOXEVENTS = [1, 2, 1];102// assumes 5 points in the lasso path103var LASSOEVENTS = [4, 2, 1];104var SELECT_PATH = [[93, 193], [143, 193]];105var LASSO_PATH = [[316, 171], [318, 239], [335, 243], [328, 169]];106describe('Click-to-select', function() {107 var mock14Pts = {108 '1': { x: 134, y: 116 },109 '7': { x: 270, y: 160 },110 '10': { x: 324, y: 198 },111 '35': { x: 685, y: 341 }112 };113 var gd;114 beforeEach(function() {115 gd = createGraphDiv();116 });117 afterEach(destroyGraphDiv);118 function plotMock14(layoutOpts) {119 var mock = require('@mocks/14.json');120 var defaultLayoutOpts = {121 layout: {122 clickmode: 'event+select',123 dragmode: 'select',124 hovermode: 'closest'125 }126 };127 var mockCopy = Lib.extendDeep(128 {},129 mock,130 defaultLayoutOpts,131 { layout: layoutOpts });132 return Plotly.newPlot(gd, mockCopy.data, mockCopy.layout);133 }134 /**135 * Executes a click and before resets selection event handlers.136 * By default, click is executed with a delay to prevent unwanted double clicks.137 * Returns the `selectedPromise` promise for convenience.138 */139 function _click(x, y, clickOpts, immediate) {140 resetEvents(gd);141 // Too fast subsequent calls of `click` would142 // produce an unwanted double click, thus we need143 // to delay the click.144 if(immediate) {145 click(x, y, clickOpts);146 } else {147 setTimeout(function() {148 click(x, y, clickOpts);149 }, DBLCLICKDELAY * 1.03);150 }151 return selectedPromise;152 }153 function _clickPt(coords, clickOpts, immediate) {154 expect(coords).toBeDefined('coords needs to be defined');155 expect(coords.x).toBeDefined('coords.x needs to be defined');156 expect(coords.y).toBeDefined('coords.y needs to be defined');157 return _click(coords.x, coords.y, clickOpts, immediate);158 }159 /**160 * Convenient helper to execute a click immediately.161 */162 function _immediateClickPt(coords, clickOpts) {163 return _clickPt(coords, clickOpts, true);164 }165 /**166 * Asserting selected points.167 *168 * @param expected can be a point number, an array169 * of point numbers (for a single trace) or an array of point number170 * arrays in case of multiple traces. undefined in an array of arrays171 * is also allowed, e.g. useful when not all traces support selection.172 */173 function assertSelectedPoints(expected) {174 var expectedPtsPerTrace = toArrayOfArrays(expected);175 var expectedPts, traceNum;176 for(traceNum = 0; traceNum < expectedPtsPerTrace.length; traceNum++) {177 expectedPts = expectedPtsPerTrace[traceNum];178 expect(gd._fullData[traceNum].selectedpoints).toEqual(expectedPts);179 expect(gd.data[traceNum].selectedpoints).toEqual(expectedPts);180 }181 function toArrayOfArrays(expected) {182 var isArrayInArray, i;183 if(Array.isArray(expected)) {184 isArrayInArray = false;185 for(i = 0; i < expected.length; i++) {186 if(Array.isArray(expected[i])) {187 isArrayInArray = true;188 break;189 }190 }191 return isArrayInArray ? expected : [expected];192 } else {193 return [[expected]];194 }195 }196 }197 function assertSelectionCleared() {198 gd._fullData.forEach(function(fullDataItem) {199 expect(fullDataItem.selectedpoints).toBeUndefined();200 });201 }202 it('selects a single data point when being clicked', function(done) {203 plotMock14()204 .then(function() { return _immediateClickPt(mock14Pts[7]); })205 .then(function() { assertSelectedPoints(7); })206 .then(done, done.fail);207 });208 describe('clears entire selection when the last selected data point', function() {209 [{210 desc: 'is clicked',211 clickOpts: {}212 }, {213 desc: 'is clicked while add/subtract modifier keys are active',214 clickOpts: { shiftKey: true }215 }].forEach(function(testData) {216 it('' + testData.desc, function(done) {217 plotMock14()218 .then(function() { return _immediateClickPt(mock14Pts[7]); })219 .then(function() {220 assertSelectedPoints(7);221 _clickPt(mock14Pts[7], testData.clickOpts);222 return deselectPromise;223 })224 .then(function() {225 assertSelectionCleared();226 return _clickPt(mock14Pts[35], testData.clickOpts);227 })228 .then(function() {229 assertSelectedPoints(35);230 })231 .then(done, done.fail);232 });233 });234 });235 it('cleanly clears and starts selections although add/subtract mode on', function(done) {236 plotMock14()237 .then(function() {238 return _immediateClickPt(mock14Pts[7]);239 })240 .then(function() {241 assertSelectedPoints(7);242 _clickPt(mock14Pts[7], { shiftKey: true });243 return deselectPromise;244 })245 .then(function() {246 assertSelectionCleared();247 return _clickPt(mock14Pts[35], { shiftKey: true });248 })249 .then(function() {250 assertSelectedPoints(35);251 })252 .then(done, done.fail);253 });254 it('supports adding to an existing selection', function(done) {255 plotMock14()256 .then(function() { return _immediateClickPt(mock14Pts[7]); })257 .then(function() {258 assertSelectedPoints(7);259 return _clickPt(mock14Pts[35], { shiftKey: true });260 })261 .then(function() { assertSelectedPoints([7, 35]); })262 .then(done, done.fail);263 });264 it('supports subtracting from an existing selection', function(done) {265 plotMock14()266 .then(function() { return _immediateClickPt(mock14Pts[7]); })267 .then(function() {268 assertSelectedPoints(7);269 return _clickPt(mock14Pts[35], { shiftKey: true });270 })271 .then(function() {272 assertSelectedPoints([7, 35]);273 return _clickPt(mock14Pts[7], { shiftKey: true });274 })275 .then(function() { assertSelectedPoints(35); })276 .then(done, done.fail);277 });278 it('can be used interchangeably with lasso/box select', function(done) {279 plotMock14()280 .then(function() {281 return _immediateClickPt(mock14Pts[35]);282 })283 .then(function() {284 assertSelectedPoints(35);285 drag(SELECT_PATH, { shiftKey: true });286 })287 .then(function() {288 assertSelectedPoints([0, 1, 35]);289 return _immediateClickPt(mock14Pts[7], { shiftKey: true });290 })291 .then(function() {292 assertSelectedPoints([0, 1, 7, 35]);293 return _clickPt(mock14Pts[1], { shiftKey: true });294 })295 .then(function() {296 assertSelectedPoints([0, 7, 35]);297 return Plotly.relayout(gd, 'dragmode', 'lasso');298 })299 .then(function() {300 assertSelectedPoints([0, 7, 35]);301 drag(LASSO_PATH, { shiftKey: true });302 })303 .then(function() {304 assertSelectedPoints([0, 7, 10, 35]);305 return _clickPt(mock14Pts[10], { shiftKey: true });306 })307 .then(function() {308 assertSelectedPoints([0, 7, 35]);309 drag([[670, 330], [695, 330], [695, 350], [670, 350]],310 { shiftKey: true, altKey: true });311 })312 .then(function() {313 assertSelectedPoints([0, 7]);314 return _clickPt(mock14Pts[35], { shiftKey: true });315 })316 .then(function() {317 assertSelectedPoints([0, 7, 35]);318 return _clickPt(mock14Pts[7]);319 })320 .then(function() {321 assertSelectedPoints([7]);322 return doubleClick(650, 100);323 })324 .then(function() {325 assertSelectionCleared();326 })327 .then(done, done.fail);328 });329 it('@gl works in a multi-trace plot', function(done) {330 Plotly.newPlot(gd, [331 {332 x: [1, 3, 5, 4, 10, 12, 12, 7],333 y: [2, 7, 6, 1, 0, 13, 6, 12],334 type: 'scatter',335 mode: 'markers',336 marker: { size: 20 }337 }, {338 x: [1, 7, 6, 2],339 y: [2, 3, 5, 4],340 type: 'bar'341 }, {342 x: [7, 8, 9, 10],343 y: [7, 9, 13, 21],344 type: 'scattergl',345 mode: 'markers',346 marker: { size: 20 }347 }348 ], {349 width: 400,350 height: 600,351 hovermode: 'closest',352 dragmode: 'select',353 clickmode: 'event+select'354 })355 .then(function() {356 return _click(136, 369, {}, true);357 })358 .then(function() {359 assertSelectedPoints([[1], [], []]);360 return _click(245, 136, { shiftKey: true });361 })362 .then(function() {363 assertSelectedPoints([[1], [], [3]]);364 return _click(183, 470, { shiftKey: true });365 })366 .then(function() {367 assertSelectedPoints([[1], [2], [3]]);368 })369 .then(done, done.fail);370 });371 it('is supported in pan/zoom mode', function(done) {372 plotMock14({ dragmode: 'zoom' })373 .then(function() {374 return _immediateClickPt(mock14Pts[35]);375 })376 .then(function() {377 assertSelectedPoints(35);378 return _clickPt(mock14Pts[7], { shiftKey: true });379 })380 .then(function() {381 assertSelectedPoints([7, 35]);382 return _clickPt(mock14Pts[7], { shiftKey: true });383 })384 .then(function() {385 assertSelectedPoints(35);386 _clickPt(mock14Pts[35], { shiftKey: true });387 return deselectPromise;388 })389 .then(function() {390 assertSelectionCleared();391 return _clickPt(mock14Pts[7], { shiftKey: true });392 })393 .then(function() {394 assertSelectedPoints(7);395 drag([[110, 100], [300, 300]]);396 })397 .then(delay(100))398 .then(function() {399 // persist after zoombox400 assertSelectedPoints(7);401 })402 .then(done, done.fail);403 });404 it('retains selected points when switching between pan and zoom mode', function(done) {405 plotMock14({ dragmode: 'zoom' })406 .then(function() {407 return _immediateClickPt(mock14Pts[35]);408 })409 .then(function() {410 assertSelectedPoints(35);411 return Plotly.relayout(gd, 'dragmode', 'pan');412 })413 .then(function() {414 assertSelectedPoints(35);415 return _clickPt(mock14Pts[7], { shiftKey: true });416 })417 .then(function() {418 assertSelectedPoints([7, 35]);419 return Plotly.relayout(gd, 'dragmode', 'zoom');420 })421 .then(function() {422 assertSelectedPoints([7, 35]);423 return _clickPt(mock14Pts[7], { shiftKey: true });424 })425 .then(function() {426 assertSelectedPoints(35);427 })428 .then(done, done.fail);429 });430 it('@gl is supported by scattergl in pan/zoom mode', function(done) {431 Plotly.newPlot(gd, [432 {433 x: [7, 8, 9, 10],434 y: [7, 9, 13, 21],435 type: 'scattergl',436 mode: 'markers',437 marker: { size: 20 }438 }439 ], {440 width: 400,441 height: 600,442 hovermode: 'closest',443 dragmode: 'zoom',444 clickmode: 'event+select'445 })446 .then(function() {447 return _click(230, 340, {}, true);448 })449 .then(function() {450 assertSelectedPoints(2);451 })452 .then(done, done.fail);453 });454 it('deals correctly with histogram\'s binning in the persistent selection case', function(done) {455 var mock = require('@mocks/histogram_colorscale.json');456 var firstBinPts = [0];457 var secondBinPts = [1, 2];458 var thirdBinPts = [3, 4, 5];459 mock.layout.clickmode = 'event+select';460 Plotly.newPlot(gd, mock.data, mock.layout)461 .then(function() {462 return clickFirstBinImmediately();463 })464 .then(function() {465 assertSelectedPoints(firstBinPts);466 return shiftClickSecondBin();467 })468 .then(function() {469 assertSelectedPoints([].concat(firstBinPts, secondBinPts));470 return shiftClickThirdBin();471 })472 .then(function() {473 assertSelectedPoints([].concat(firstBinPts, secondBinPts, thirdBinPts));474 return clickFirstBin();475 })476 .then(function() {477 assertSelectedPoints([].concat(firstBinPts));478 clickFirstBin();479 return deselectPromise;480 })481 .then(function() {482 assertSelectionCleared();483 })484 .then(done, done.fail);485 function clickFirstBinImmediately() { return _immediateClickPt({ x: 141, y: 358 }); }486 function clickFirstBin() { return _click(141, 358); }487 function shiftClickSecondBin() { return _click(239, 330, { shiftKey: true }); }488 function shiftClickThirdBin() { return _click(351, 347, { shiftKey: true }); }489 });490 it('ignores clicks on boxes in a box trace type', function(done) {491 var mock = Lib.extendDeep({}, require('@mocks/box_grouped_horz.json'));492 mock.layout.clickmode = 'event+select';493 mock.layout.width = 1100;494 mock.layout.height = 450;495 Plotly.newPlot(gd, mock.data, mock.layout)496 .then(function() {497 return clickPtImmediately();498 })499 .then(function() {500 assertSelectedPoints(2);501 clickPt();502 return deselectPromise;503 })504 .then(function() {505 assertSelectionCleared();506 clickBox();507 return clickedPromise;508 })509 .then(function() {510 assertSelectionCleared();511 })512 .then(done, done.fail);513 function clickPtImmediately() { return _immediateClickPt({ x: 610, y: 342 }); }514 function clickPt() { return _clickPt({ x: 610, y: 342 }); }515 function clickBox() { return _clickPt({ x: 565, y: 329 }); }516 });517 describe('is disabled when clickmode does not include \'select\'', function() {518 ['select', 'lasso']519 .forEach(function(dragmode) {520 it('and dragmode is ' + dragmode, function(done) {521 plotMock14({ clickmode: 'event', dragmode: dragmode })522 .then(function() {523 // Still, the plotly_selected event should be thrown,524 // so return promise here525 return _immediateClickPt(mock14Pts[1]);526 })527 .then(function() {528 assertSelectionCleared();529 })530 .then(done, done.fail);531 });532 });533 });534 describe('is disabled when clickmode does not include \'select\'', function() {535 ['pan', 'zoom']536 .forEach(function(dragmode) {537 it('and dragmode is ' + dragmode, function(done) {538 plotMock14({ clickmode: 'event', dragmode: dragmode })539 .then(function() {540 _immediateClickPt(mock14Pts[1]);541 return clickedPromise;542 })543 .then(function() {544 assertSelectionCleared();545 })546 .then(done, done.fail);547 });548 });549 });550 describe('is supported by', function() {551 // On loading mocks:552 // - Note, that `require` function calls are resolved at compile time553 // and thus dynamically concatenated mock paths won't work.554 // - Some mocks don't specify a width and height, so this needs555 // to be set explicitly to ensure click coordinates fit.556 // The non-gl traces: use CI annotation557 [558 testCase('histrogram', require('@mocks/histogram_colorscale.json'), 355, 301, [3, 4, 5]),559 testCase('box', require('@mocks/box_grouped_horz.json'), 610, 342, [[2], [], []],560 { width: 1100, height: 450 }),561 testCase('violin', require('@mocks/violin_grouped.json'), 166, 187, [[3], [], []],562 { width: 1100, height: 450 }),563 testCase('ohlc', require('@mocks/ohlc_first.json'), 669, 165, [9]),564 testCase('candlestick', require('@mocks/finance_style.json'), 331, 162, [[], [5]]),565 testCase('choropleth', require('@mocks/geo_choropleth-text.json'), 440, 163, [6]),566 testCase('scattergeo', require('@mocks/geo_scattergeo-locations.json'), 285, 240, [1]),567 testCase('scatterternary', require('@mocks/ternary_markers.json'), 485, 335, [7]),568 // Note that first trace (carpet) in mock doesn't support selection,569 // thus undefined is expected570 testCase('scattercarpet', require('@mocks/scattercarpet.json'), 532, 178,571 [undefined, [], [], [], [], [], [2]], { width: 1100, height: 450 }),572 // scatterpolar and scatterpolargl do not support pan (the default),573 // so set dragmode to zoom574 testCase('scatterpolar', require('@mocks/polar_scatter.json'), 130, 290,575 [[], [], [], [19], [], []], { dragmode: 'zoom' }),576 ]577 .forEach(function(testCase) {578 it('trace type ' + testCase.label, function(done) {579 _run(testCase, done);580 });581 });582 [583 testCase('scatterpolargl', require('@mocks/glpolar_scatter.json'), 130, 290,584 [[], [], [], [19], [], []], { dragmode: 'zoom' }),585 testCase('splom', require('@mocks/splom_lower.json'), 427, 400, [[], [7], []])586 ]587 .forEach(function(testCase) {588 it('@gl trace type ' + testCase.label, function(done) {589 _run(testCase, done);590 });591 });592 [593 testCase('scattermapbox', require('@mocks/mapbox_0.json'), 650, 195, [[2], []], {},594 { mapboxAccessToken: require('@build/credentials.json').MAPBOX_ACCESS_TOKEN }),595 testCase('choroplethmapbox', require('@mocks/mapbox_choropleth0.json'), 270, 220, [[0]], {},596 { mapboxAccessToken: require('@build/credentials.json').MAPBOX_ACCESS_TOKEN })597 ]598 .forEach(function(testCase) {599 it('@gl trace type ' + testCase.label, function(done) {600 _run(testCase, done);601 });602 });603 function _run(testCase, doneFn) {604 Plotly.newPlot(gd, testCase.mock.data, testCase.mock.layout, testCase.mock.config)605 .then(function() {606 return _immediateClickPt(testCase);607 })608 .then(function() {609 assertSelectedPoints(testCase.expectedPts);610 return Plotly.relayout(gd, 'dragmode', 'lasso');611 })612 .then(function() {613 _clickPt(testCase);614 return deselectPromise;615 })616 .then(function() {617 assertSelectionCleared();618 return _clickPt(testCase);619 })620 .then(function() {621 assertSelectedPoints(testCase.expectedPts);622 })623 .then(doneFn, doneFn.fail);624 }625 });626 it('should maintain style of errorbars after double click cleared selection (bar case)', function(done) {627 Plotly.newPlot(gd, { // Note: this call should be newPlot not plot628 data: [{629 x: [0, 1, 2],630 y: [100, 200, 400],631 type: 'bar',632 marker: {633 color: 'yellow'634 },635 error_y: {636 type: 'sqrt'637 }638 }],639 layout: {640 dragmode: 'select'641 }642 })643 .then(function() {644 var x = 100;645 var y = 100;646 drag([[x, y], [x, y]]); // first empty drag647 return doubleClick(x, y); // then double click648 })649 .then(function() {650 assertSelectionCleared();651 })652 .then(function() {653 d3Select(gd).select('g.plot').each(function() {654 d3Select(this).selectAll('g.errorbar').selectAll('path').each(function() {655 expect(d3Select(this).attr('style'))656 .toBe('vector-effect: non-scaling-stroke; stroke-width: 2px; stroke: rgb(68, 68, 68); stroke-opacity: 1; opacity: 1; fill: rgb(255, 255, 0); fill-opacity: 1;', 'to be visible'657 );658 });659 });660 })661 .then(done, done.fail);662 });663 describe('triggers \'plotly_selected\' before \'plotly_click\'', function() {664 [665 testCase('cartesian', require('@mocks/14.json'), 270, 160, [7]),666 testCase('geo', require('@mocks/geo_scattergeo-locations.json'), 285, 240, [1]),667 testCase('ternary', require('@mocks/ternary_markers.json'), 485, 335, [7]),668 testCase('polar', require('@mocks/polar_scatter.json'), 130, 290,669 [[], [], [], [19], [], []], { dragmode: 'zoom' })670 ].forEach(function(testCase) {671 it('for base plot ' + testCase.label, function(done) {672 _run(testCase, done);673 });674 });675 [676 testCase('mapbox', require('@mocks/mapbox_0.json'), 650, 195, [[2], []], {},677 { mapboxAccessToken: require('@build/credentials.json').MAPBOX_ACCESS_TOKEN }),678 testCase('mapbox', require('@mocks/mapbox_choropleth0.json'), 270, 220, [[0], []], {},679 { mapboxAccessToken: require('@build/credentials.json').MAPBOX_ACCESS_TOKEN })680 ].forEach(function(testCase) {681 it('@gl for base plot ' + testCase.label, function(done) {682 _run(testCase, done);683 });684 });685 function _run(testCase, doneFn) {686 Plotly.newPlot(gd, testCase.mock.data, testCase.mock.layout, testCase.mock.config)687 .then(function() {688 var clickHandlerCalled = false;689 var selectedHandlerCalled = false;690 gd.on('plotly_selected', function() {691 expect(clickHandlerCalled).toBe(false);692 selectedHandlerCalled = true;693 });694 gd.on('plotly_click', function() {695 clickHandlerCalled = true;696 expect(selectedHandlerCalled).toBe(true);697 doneFn();698 });699 return click(testCase.x, testCase.y);700 })701 .then(doneFn, doneFn.fail);702 }703 });704 function testCase(label, mock, x, y, expectedPts, layoutOptions, configOptions) {705 var defaultLayoutOpts = {706 layout: {707 clickmode: 'event+select',708 dragmode: 'pan',709 hovermode: 'closest'710 }711 };712 var customLayoutOptions = {713 layout: layoutOptions714 };715 var customConfigOptions = {716 config: configOptions717 };718 var mockCopy = Lib.extendDeep(719 {},720 mock,721 defaultLayoutOpts,722 customLayoutOptions,723 customConfigOptions);724 return {725 label: label,726 mock: mockCopy,727 layoutOptions: layoutOptions,728 x: x,729 y: y,730 expectedPts: expectedPts,731 configOptions: configOptions732 };733 }734});735describe('Test select box and lasso in general:', function() {736 var mock = require('@mocks/14.json');737 var selectPath = [[93, 193], [143, 193]];738 var lassoPath = [[316, 171], [318, 239], [335, 243], [328, 169]];739 afterEach(destroyGraphDiv);740 function assertRange(actual, expected) {741 var PRECISION = 4;742 expect(actual.x).toBeCloseToArray(expected.x, PRECISION);743 expect(actual.y).toBeCloseToArray(expected.y, PRECISION);744 }745 function assertEventData(actual, expected, msg) {746 expect(actual.length).toBe(expected.length, msg + ' same number of pts');747 expected.forEach(function(e, i) {748 var a = actual[i];749 var m = msg + ' (pt ' + i + ')';750 expect(a.data).toBeDefined(m + ' has data ref');751 expect(a.fullData).toBeDefined(m + ' has fullData ref');752 expect(Object.keys(a).length - 2).toBe(Object.keys(e).length, m + ' has correct number of keys');753 Object.keys(e).forEach(function(k) {754 expect(a[k]).toBe(e[k], m + ' ' + k);755 });756 });757 }758 describe('select events', function() {759 var mockCopy = Lib.extendDeep({}, mock);760 mockCopy.layout.dragmode = 'select';761 mockCopy.layout.hovermode = 'closest';762 mockCopy.data[0].ids = mockCopy.data[0].x763 .map(function(v) { return 'id-' + v; });764 mockCopy.data[0].customdata = mockCopy.data[0].y765 .map(function(v) { return 'customdata-' + v; });766 addInvisible(mockCopy);767 var gd;768 beforeEach(function(done) {769 gd = createGraphDiv();770 Plotly.newPlot(gd, mockCopy.data, mockCopy.layout)771 .then(done);772 });773 it('should trigger selecting/selected/deselect events', function(done) {774 resetEvents(gd);775 drag(selectPath);776 selectedPromise.then(function() {777 expect(selectedCnt).toBe(1, 'with the correct selected count');778 assertEventData(selectedData.points, [{779 curveNumber: 0,780 pointNumber: 0,781 pointIndex: 0,782 x: 0.002,783 y: 16.25,784 id: 'id-0.002',785 customdata: 'customdata-16.25'786 }, {787 curveNumber: 0,788 pointNumber: 1,789 pointIndex: 1,790 x: 0.004,791 y: 12.5,792 id: 'id-0.004',793 customdata: 'customdata-12.5'794 }], 'with the correct selected points (2)');795 assertRange(selectedData.range, {796 x: [0.002000, 0.0046236],797 y: [0.10209191961595454, 24.512223978291406]798 }, 'with the correct selected range');799 return doubleClick(250, 200);800 })801 .then(deselectPromise)802 .then(function() {803 expect(doubleClickData).toBe(null, 'with the correct deselect data');804 })805 .then(done, done.fail);806 });807 it('should handle add/sub selection', function(done) {808 resetEvents(gd);809 drag(selectPath);810 selectedPromise.then(function() {811 expect(selectingCnt).toBe(1, 'with the correct selecting count');812 assertEventData(selectingData.points, [{813 curveNumber: 0,814 pointNumber: 0,815 pointIndex: 0,816 x: 0.002,817 y: 16.25,818 id: 'id-0.002',819 customdata: 'customdata-16.25'820 }, {821 curveNumber: 0,822 pointNumber: 1,823 pointIndex: 1,824 x: 0.004,825 y: 12.5,826 id: 'id-0.004',827 customdata: 'customdata-12.5'828 }], 'with the correct selecting points (1)');829 assertRange(selectingData.range, {830 x: [0.002000, 0.0046236],831 y: [0.10209191961595454, 24.512223978291406]832 }, 'with the correct selecting range');833 })834 .then(function() {835 // add selection836 drag([[193, 193], [213, 193]], {shiftKey: true});837 })838 .then(function() {839 expect(selectingCnt).toBe(2, 'with the correct selecting count');840 assertEventData(selectingData.points, [{841 curveNumber: 0,842 pointNumber: 0,843 pointIndex: 0,844 x: 0.002,845 y: 16.25,846 id: 'id-0.002',847 customdata: 'customdata-16.25'848 }, {849 curveNumber: 0,850 pointNumber: 1,851 pointIndex: 1,852 x: 0.004,853 y: 12.5,854 id: 'id-0.004',855 customdata: 'customdata-12.5'856 }, {857 curveNumber: 0,858 pointNumber: 4,859 pointIndex: 4,860 x: 0.013,861 y: 6.875,862 id: 'id-0.013',863 customdata: 'customdata-6.875'864 }], 'with the correct selecting points (1)');865 })866 .then(function() {867 // sub selection868 drag([[219, 143], [219, 183]], {altKey: true});869 }).then(function() {870 assertEventData(selectingData.points, [{871 curveNumber: 0,872 pointNumber: 0,873 pointIndex: 0,874 x: 0.002,875 y: 16.25,876 id: 'id-0.002',877 customdata: 'customdata-16.25'878 }, {879 curveNumber: 0,880 pointNumber: 1,881 pointIndex: 1,882 x: 0.004,883 y: 12.5,884 id: 'id-0.004',885 customdata: 'customdata-12.5'886 }], 'with the correct selecting points (1)');887 return doubleClick(250, 200);888 })889 .then(function() {890 expect(doubleClickData).toBe(null, 'with the correct deselect data');891 })892 .then(done, done.fail);893 });894 });895 describe('lasso events', function() {896 var mockCopy = Lib.extendDeep({}, mock);897 mockCopy.layout.dragmode = 'lasso';898 mockCopy.layout.hovermode = 'closest';899 addInvisible(mockCopy);900 var gd;901 beforeEach(function(done) {902 gd = createGraphDiv();903 Plotly.newPlot(gd, mockCopy.data, mockCopy.layout)904 .then(done);905 });906 it('should trigger selecting/selected/deselect events', function(done) {907 resetEvents(gd);908 drag(lassoPath);909 selectedPromise.then(function() {910 expect(selectingCnt).toBe(3, 'with the correct selecting count');911 assertEventData(selectingData.points, [{912 curveNumber: 0,913 pointNumber: 10,914 pointIndex: 10,915 x: 0.099,916 y: 2.75917 }], 'with the correct selecting points (1)');918 expect(selectedCnt).toBe(1, 'with the correct selected count');919 assertEventData(selectedData.points, [{920 curveNumber: 0,921 pointNumber: 10,922 pointIndex: 10,923 x: 0.099,924 y: 2.75,925 }], 'with the correct selected points (2)');926 expect(selectedData.lassoPoints.x).toBeCloseToArray(927 [0.084, 0.087, 0.115, 0.103], 'lasso points x coords');928 expect(selectedData.lassoPoints.y).toBeCloseToArray(929 [4.648, 1.342, 1.247, 4.821], 'lasso points y coords');930 return doubleClick(250, 200);931 })932 .then(deselectPromise)933 .then(function() {934 expect(doubleClickData).toBe(null, 'with the correct deselect data');935 })936 .then(done, done.fail);937 });938 it('should set selected points in graph data', function(done) {939 resetEvents(gd);940 drag(lassoPath);941 selectedPromise.then(function() {942 expect(selectingCnt).toBe(3, 'with the correct selecting count');943 expect(gd.data[0].selectedpoints).toEqual([10]);944 return doubleClick(250, 200);945 })946 .then(deselectPromise)947 .then(function() {948 expect(gd.data[0].selectedpoints).toBeUndefined();949 })950 .then(done, done.fail);951 });952 it('should set selected points in full data', function(done) {953 resetEvents(gd);954 drag(lassoPath);955 selectedPromise.then(function() {956 expect(selectingCnt).toBe(3, 'with the correct selecting count');957 expect(gd._fullData[0].selectedpoints).toEqual([10]);958 return doubleClick(250, 200);959 })960 .then(deselectPromise)961 .then(function() {962 expect(gd._fullData[0].selectedpoints).toBeUndefined();963 })964 .then(done, done.fail);965 });966 it('should trigger selecting/selected/deselect events for touches', function(done) {967 resetEvents(gd);968 drag(lassoPath, {type: 'touch'});969 selectedPromise.then(function() {970 expect(selectingCnt).toBe(3, 'with the correct selecting count');971 assertEventData(selectingData.points, [{972 curveNumber: 0,973 pointNumber: 10,974 pointIndex: 10,975 x: 0.099,976 y: 2.75977 }], 'with the correct selecting points (1)');978 expect(selectedCnt).toBe(1, 'with the correct selected count');979 assertEventData(selectedData.points, [{980 curveNumber: 0,981 pointNumber: 10,982 pointIndex: 10,983 x: 0.099,984 y: 2.75,985 }], 'with the correct selected points (2)');986 return doubleClick(250, 200);987 })988 .then(deselectPromise)989 .then(function() {990 expect(doubleClickData).toBe(null, 'with the correct deselect data');991 })992 .then(done, done.fail);993 });994 });995 it('should skip over non-visible traces', function(done) {996 // note: this tests a mock with one or several invisible traces997 // the invisible traces in the other tests test for multiple998 // traces, with some visible and some not.999 var mockCopy = Lib.extendDeep({}, mock);1000 mockCopy.layout.dragmode = 'select';1001 var gd = createGraphDiv();1002 function resetAndSelect() {1003 resetEvents(gd);1004 drag(selectPath);1005 return selectedPromise;1006 }1007 function resetAndLasso() {1008 resetEvents(gd);1009 drag(lassoPath);1010 return selectedPromise;1011 }1012 function checkPointCount(cnt, msg) {1013 expect((selectedData.points || []).length).toBe(cnt, msg);1014 }1015 Plotly.newPlot(gd, mockCopy.data, mockCopy.layout)1016 .then(resetAndSelect)1017 .then(function() {1018 checkPointCount(2, '(case 0)');1019 return Plotly.restyle(gd, 'visible', 'legendonly');1020 })1021 .then(resetAndSelect)1022 .then(function() {1023 checkPointCount(0, '(legendonly case)');1024 return Plotly.restyle(gd, 'visible', true);1025 })1026 .then(resetAndSelect)1027 .then(function() {1028 checkPointCount(2, '(back to case 0)');1029 return Plotly.relayout(gd, 'dragmode', 'lasso');1030 })1031 .then(resetAndLasso)1032 .then(function() {1033 checkPointCount(1, '(case 0 lasso)');1034 return Plotly.restyle(gd, 'visible', 'legendonly');1035 })1036 .then(resetAndSelect)1037 .then(function() {1038 checkPointCount(0, '(lasso legendonly case)');1039 return Plotly.restyle(gd, 'visible', true);1040 })1041 .then(resetAndLasso)1042 .then(function() {1043 checkPointCount(1, '(back to lasso case 0)');1044 mockCopy = Lib.extendDeep({}, mock);1045 mockCopy.layout.dragmode = 'select';1046 mockCopy.data[0].visible = false;1047 addInvisible(mockCopy);1048 return Plotly.newPlot(gd, mockCopy);1049 })1050 .then(resetAndSelect)1051 .then(function() {1052 checkPointCount(0, '(multiple invisible traces select)');1053 return Plotly.relayout(gd, 'dragmode', 'lasso');1054 })1055 .then(resetAndLasso)1056 .then(function() {1057 checkPointCount(0, '(multiple invisible traces lasso)');1058 })1059 .then(done, done.fail);1060 });1061 it('should skip over BADNUM items', function(done) {1062 var data = [{1063 mode: 'markers',1064 x: [null, undefined, NaN, 0, 'NA'],1065 y: [NaN, null, undefined, 0, 'NA']1066 }];1067 var layout = {1068 dragmode: 'select',1069 width: 400,1070 heigth: 400,1071 };1072 var gd = createGraphDiv();1073 Plotly.newPlot(gd, data, layout).then(function() {1074 resetEvents(gd);1075 drag([[100, 100], [300, 300]]);1076 return selectedPromise;1077 })1078 .then(function() {1079 expect(selectedData.points.length).toBe(1);1080 expect(selectedData.points[0].x).toBe(0);1081 expect(selectedData.points[0].y).toBe(0);1082 return Plotly.relayout(gd, 'dragmode', 'lasso');1083 })1084 .then(function() {1085 resetEvents(gd);1086 drag([[100, 100], [100, 300], [300, 300], [300, 100], [100, 100]]);1087 return selectedPromise;1088 })1089 .then(function() {1090 expect(selectedData.points.length).toBe(1);1091 expect(selectedData.points[0].x).toBe(0);1092 expect(selectedData.points[0].y).toBe(0);1093 })1094 .then(done, done.fail);1095 });1096 it('scroll zoom should clear selection regions', function(done) {1097 var gd = createGraphDiv();1098 var mockCopy = Lib.extendDeep({}, mock);1099 mockCopy.layout.dragmode = 'select';1100 mockCopy.config = {scrollZoom: true};1101 function _drag() {1102 resetEvents(gd);1103 drag(selectPath);1104 return selectedPromise;1105 }1106 function _scroll() {1107 mouseEvent('mousemove', selectPath[0][0], selectPath[0][1]);1108 mouseEvent('scroll', selectPath[0][0], selectPath[0][1], {deltaX: 0, deltaY: -20});1109 }1110 Plotly.newPlot(gd, mockCopy)1111 .then(_drag)1112 .then(_scroll)1113 .then(function() {1114 assertSelectionNodes(0, 0);1115 })1116 .then(_drag)1117 .then(_scroll)1118 .then(function() {1119 // make sure it works the 2nd time aroung1120 assertSelectionNodes(0, 0);1121 })1122 .then(done, done.fail);1123 });1124 describe('should return correct range data on dragmode *select*', function() {1125 var specs = [{1126 axType: 'linear',1127 rng: [-0.6208, 0.8375]1128 }, {1129 axType: 'log',1130 rng: [0.2394, 6.8785]1131 }, {1132 axType: 'date',1133 rng: ['2000-01-20 19:48', '2000-04-06 01:48']1134 }, {1135 axType: 'category',1136 rng: [-0.6208, 0.8375]1137 }, {1138 axType: 'multicategory',1139 rng: [-0.6208, 0.8375]1140 }];1141 specs.forEach(function(s) {1142 it('- on ' + s.axType + ' axes', function(done) {1143 var gd = createGraphDiv();1144 Plotly.newPlot(gd, [], {1145 xaxis: {type: s.axType},1146 dragmode: 'select',1147 width: 400,1148 height: 4001149 })1150 .then(function() {1151 resetEvents(gd);1152 drag(selectPath);1153 return selectedPromise;1154 })1155 .then(function() {1156 expect(selectedData.range.x).toBeCloseToArray(s.rng, 2);1157 })1158 .then(done, done.fail);1159 });1160 });1161 });1162 describe('should return correct range data on dragmode *lasso*', function() {1163 var specs = [{1164 axType: 'linear',1165 pts: [5.883, 5.941, 6, 6]1166 }, {1167 axType: 'log',1168 pts: [764422.2742, 874312.4580, 1000000, 1000000]1169 }, {1170 axType: 'date',1171 pts: ['2000-12-25 21:36', '2000-12-28 22:48', '2001-01-01', '2001-01-01']1172 }, {1173 axType: 'category',1174 pts: [5.8833, 5.9416, 6, 6]1175 }, {1176 axType: 'multicategory',1177 pts: [5.8833, 5.9416, 6, 6]1178 }];1179 specs.forEach(function(s) {1180 it('- on ' + s.axType + ' axes', function(done) {1181 var gd = createGraphDiv();1182 Plotly.newPlot(gd, [], {1183 xaxis: {type: s.axType},1184 dragmode: 'lasso',1185 width: 400,1186 height: 4001187 })1188 .then(function() {1189 resetEvents(gd);1190 drag(lassoPath);1191 return selectedPromise;1192 })1193 .then(function() {1194 expect(selectedData.lassoPoints.x).toBeCloseToArray(s.pts, 2);1195 })1196 .then(done, done.fail);1197 });1198 });1199 });1200 it('should have their selection outlines cleared during *axrange* relayout calls', function(done) {1201 var gd = createGraphDiv();1202 var fig = Lib.extendDeep({}, mock);1203 fig.layout.dragmode = 'select';1204 function _drag() {1205 resetEvents(gd);1206 drag(selectPath);1207 return selectedPromise;1208 }1209 Plotly.newPlot(gd, fig)1210 .then(_drag)1211 .then(function() { assertSelectionNodes(0, 2, 'after drag 1'); })1212 .then(function() { return Plotly.relayout(gd, 'xaxis.range', [-5, 5]); })1213 .then(function() { assertSelectionNodes(0, 0, 'after axrange relayout'); })1214 .then(_drag)1215 .then(function() { assertSelectionNodes(0, 2, 'after drag 2'); })1216 .then(done, done.fail);1217 });1218 it('should select the right data with the corresponding select direction', function(done) {1219 var gd = createGraphDiv();1220 // drag around just the center point, but if we have a selectdirection we may1221 // get either the ones to the left and right or above and below1222 var selectPath = [[175, 175], [225, 225]];1223 function selectDrag() {1224 resetEvents(gd);1225 drag(selectPath);1226 return selectedPromise;1227 }1228 function assertSelectedPointNumbers(pointNumbers) {1229 var pts = selectedData.points;1230 expect(pts.length).toBe(pointNumbers.length);1231 pointNumbers.forEach(function(pointNumber, i) {1232 expect(pts[i].pointNumber).toBe(pointNumber);1233 });1234 }1235 Plotly.newPlot(gd, [{1236 x: [1, 1, 1, 2, 2, 2, 3, 3, 3],1237 y: [1, 2, 3, 1, 2, 3, 1, 2, 3],1238 mode: 'markers'1239 }], {1240 width: 400,1241 height: 400,1242 dragmode: 'select',1243 margin: {l: 100, r: 100, t: 100, b: 100},1244 xaxis: {range: [0, 4]},1245 yaxis: {range: [0, 4]}1246 })1247 .then(selectDrag)1248 .then(function() {1249 expect(gd._fullLayout.selectdirection).toBe('any');1250 assertSelectedPointNumbers([4]);1251 return Plotly.relayout(gd, {selectdirection: 'h'});1252 })1253 .then(selectDrag)1254 .then(function() {1255 assertSelectedPointNumbers([3, 4, 5]);1256 return Plotly.relayout(gd, {selectdirection: 'v'});1257 })1258 .then(selectDrag)1259 .then(function() {1260 assertSelectedPointNumbers([1, 4, 7]);1261 return Plotly.relayout(gd, {selectdirection: 'd'});1262 })1263 .then(selectDrag)1264 .then(function() {1265 assertSelectedPointNumbers([4]);1266 })1267 .then(done, done.fail);1268 });1269 it('@flaky should cleanly clear and restart selections on double click when add/subtract mode on', function(done) {1270 var gd = createGraphDiv();1271 var fig = Lib.extendDeep({}, require('@mocks/0.json'));1272 fig.layout.dragmode = 'select';1273 Plotly.newPlot(gd, fig)1274 .then(function() {1275 return drag([[350, 100], [400, 400]]);1276 })1277 .then(function() {1278 _assertSelectedPoints([49, 50, 51, 52, 53, 54, 55, 56, 57]);1279 // Note: although Shift has no behavioral effect on clearing a selection1280 // with a double click, users might hold the Shift key by accident.1281 // This test ensures selection is cleared as expected although1282 // the Shift key is held and no selection state is retained in any way.1283 return doubleClick(500, 200, { shiftKey: true });1284 })1285 .then(function() {1286 _assertSelectedPoints(null);1287 return drag([[450, 100], [500, 400]], { shiftKey: true });1288 })1289 .then(function() {1290 _assertSelectedPoints([67, 68, 69, 70, 71, 72, 73, 74]);1291 })1292 .then(done, done.fail);1293 function _assertSelectedPoints(selPts) {1294 if(selPts) {1295 expect(gd.data[0].selectedpoints).toEqual(selPts);1296 } else {1297 expect('selectedpoints' in gd.data[0]).toBe(false);1298 }1299 }1300 });1301 it('should clear selected points on double click only on pan/lasso modes', function(done) {1302 var gd = createGraphDiv();1303 var fig = Lib.extendDeep({}, require('@mocks/0.json'));1304 fig.data = [fig.data[0]];1305 fig.layout.xaxis.autorange = false;1306 fig.layout.xaxis.range = [2, 8];1307 fig.layout.yaxis.autorange = false;1308 fig.layout.yaxis.range = [0, 3];1309 fig.layout.hovermode = 'closest';1310 function _assert(msg, exp) {1311 expect(gd.layout.xaxis.range)1312 .toBeCloseToArray(exp.xrng, 2, 'xaxis range - ' + msg);1313 expect(gd.layout.yaxis.range)1314 .toBeCloseToArray(exp.yrng, 2, 'yaxis range - ' + msg);1315 if(exp.selpts === null) {1316 expect('selectedpoints' in gd.data[0])1317 .toBe(false, 'cleared selectedpoints - ' + msg);1318 } else {1319 expect(gd.data[0].selectedpoints)1320 .toBeCloseToArray(exp.selpts, 2, 'selectedpoints - ' + msg);1321 }1322 }1323 Plotly.newPlot(gd, fig).then(function() {1324 _assert('base', {1325 xrng: [2, 8],1326 yrng: [0, 3],1327 selpts: null1328 });1329 return Plotly.relayout(gd, 'xaxis.range', [0, 10]);1330 })1331 .then(function() {1332 _assert('after xrng relayout', {1333 xrng: [0, 10],1334 yrng: [0, 3],1335 selpts: null1336 });1337 return doubleClick(200, 200);1338 })1339 .then(function() {1340 _assert('after double-click under dragmode zoom', {1341 xrng: [2, 8],1342 yrng: [0, 3],1343 selpts: null1344 });1345 return Plotly.relayout(gd, 'dragmode', 'select');1346 })1347 .then(function() {1348 _assert('after relayout to select', {1349 xrng: [2, 8],1350 yrng: [0, 3],1351 selpts: null1352 });1353 return drag([[100, 100], [400, 400]]);1354 })1355 .then(function() {1356 _assert('after selection', {1357 xrng: [2, 8],1358 yrng: [0, 3],1359 selpts: [40, 41, 42, 43, 44, 45, 46, 47, 48]1360 });1361 return doubleClick(200, 200);1362 })1363 .then(function() {1364 _assert('after double-click under dragmode select', {1365 xrng: [2, 8],1366 yrng: [0, 3],1367 selpts: null1368 });1369 return drag([[100, 100], [400, 400]]);1370 })1371 .then(function() {1372 _assert('after selection 2', {1373 xrng: [2, 8],1374 yrng: [0, 3],1375 selpts: [40, 41, 42, 43, 44, 45, 46, 47, 48]1376 });1377 return Plotly.relayout(gd, 'dragmode', 'pan');1378 })1379 .then(function() {1380 _assert('after relayout to pan', {1381 xrng: [2, 8],1382 yrng: [0, 3],1383 selpts: [40, 41, 42, 43, 44, 45, 46, 47, 48]1384 });1385 return Plotly.relayout(gd, 'yaxis.range', [0, 20]);1386 })1387 .then(function() {1388 _assert('after yrng relayout', {1389 xrng: [2, 8],1390 yrng: [0, 20],1391 selpts: [40, 41, 42, 43, 44, 45, 46, 47, 48]1392 });1393 return doubleClick(200, 200);1394 })1395 .then(function() {1396 _assert('after double-click under dragmode pan', {1397 xrng: [2, 8],1398 yrng: [0, 3],1399 // N.B. does not clear selection!1400 selpts: [40, 41, 42, 43, 44, 45, 46, 47, 48]1401 });1402 })1403 .then(done, done.fail);1404 });1405 it('should remember selection polygons from previous select/lasso mode', function(done) {1406 var gd = createGraphDiv();1407 var path1 = [[150, 150], [170, 170]];1408 var path2 = [[193, 193], [213, 193]];1409 var fig = Lib.extendDeep({}, mock);1410 fig.layout.margin = {l: 0, t: 0, r: 0, b: 0};1411 fig.layout.width = 500;1412 fig.layout.height = 500;1413 fig.layout.dragmode = 'select';1414 fig.config = {scrollZoom: true};1415 // d attr to array of segment [x,y]1416 function outline2coords(outline) {1417 if(!outline.size()) return [[]];1418 return outline.attr('d')1419 .replace(/Z/g, '')1420 .split('M')1421 .filter(Boolean)1422 .map(function(s) {1423 return s.split('L')1424 .map(function(s) { return s.split(',').map(Number); });1425 })1426 .reduce(function(a, b) { return a.concat(b); });1427 }1428 function _assert(msg, exp) {1429 var outline = d3Select(gd).select('.zoomlayer').select('.select-outline-1');1430 if(exp.outline) {1431 expect(outline2coords(outline)).toBeCloseTo2DArray(exp.outline, 2, msg);1432 } else {1433 assertSelectionNodes(0, 0, msg);1434 }1435 }1436 function _drag(path, opts) {1437 return function() {1438 resetEvents(gd);1439 drag(path, opts);1440 return selectedPromise;1441 };1442 }1443 Plotly.newPlot(gd, fig)1444 .then(function() { _assert('base', {outline: false}); })1445 .then(_drag(path1))1446 .then(function() {1447 _assert('select path1', {1448 outline: [[150, 150], [150, 170], [170, 170], [170, 150]]1449 });1450 })1451 .then(_drag(path2))1452 .then(function() {1453 _assert('select path2', {1454 outline: [[193, 0], [193, 500], [213, 500], [213, 0]]1455 });1456 })1457 .then(_drag(path1))1458 .then(_drag(path2, {shiftKey: true}))1459 .then(function() {1460 _assert('select path1+path2', {1461 outline: [1462 [170, 170], [170, 150], [150, 150], [150, 170],1463 [213, 500], [213, 0], [193, 0], [193, 500]1464 ]1465 });1466 })1467 .then(function() {1468 return Plotly.relayout(gd, 'dragmode', 'lasso');1469 })1470 .then(function() {1471 // N.B. all relayout calls clear the selection outline at the moment,1472 // perhaps we could make an exception for select <-> lasso ?1473 _assert('after relayout -> lasso', {outline: false});1474 })1475 .then(_drag(lassoPath, {shiftKey: true}))1476 .then(function() {1477 // merged with previous 'select' polygon1478 _assert('after shift lasso', {1479 outline: [1480 [170, 170], [170, 150], [150, 150], [150, 170],1481 [213, 500], [213, 0], [193, 0], [193, 500],1482 [335, 243], [328, 169], [316, 171], [318, 239]1483 ]1484 });1485 })1486 .then(_drag(lassoPath))1487 .then(function() {1488 _assert('after lasso (no-shift)', {1489 outline: [[316, 171], [318, 239], [335, 243], [328, 169]]1490 });1491 })1492 .then(function() {1493 return Plotly.relayout(gd, 'dragmode', 'pan');1494 })1495 .then(function() {1496 _assert('after relayout -> pan', {outline: false});1497 drag(path2);1498 _assert('after pan', {outline: false});1499 return Plotly.relayout(gd, 'dragmode', 'select');1500 })1501 .then(function() {1502 _assert('after relayout back to select', {outline: false});1503 })1504 .then(_drag(path1, {shiftKey: true}))1505 .then(function() {1506 // this used to merged 'lasso' polygons before (see #2669)1507 _assert('shift select path1 after pan', {1508 outline: [[150, 150], [150, 170], [170, 170], [170, 150]]1509 });1510 })1511 .then(_drag(path2, {shiftKey: true}))1512 .then(function() {1513 _assert('shift select path1+path2 after pan', {1514 outline: [1515 [170, 170], [170, 150], [150, 150], [150, 170],1516 [213, 500], [213, 0], [193, 0], [193, 500]1517 ]1518 });1519 })1520 .then(function() {1521 mouseEvent('mousemove', 200, 200);1522 mouseEvent('scroll', 200, 200, {deltaX: 0, deltaY: -20});1523 })1524 .then(_drag(path1, {shiftKey: true}))1525 .then(function() {1526 _assert('shift select path1 after scroll', {1527 outline: [[150, 150], [150, 170], [170, 170], [170, 150]]1528 });1529 })1530 .then(done, done.fail);1531 });1532});1533describe('Test select box and lasso per trace:', function() {1534 var gd;1535 beforeEach(function() {1536 gd = createGraphDiv();1537 spyOn(Lib, 'error');1538 });1539 afterEach(destroyGraphDiv);1540 function makeAssertPoints(keys) {1541 var callNumber = 0;1542 return function(expected) {1543 var msg = '(call #' + callNumber + ') ';1544 var pts = (selectedData || {}).points || [];1545 expect(pts.length).toBe(expected.length, msg + 'selected points length');1546 pts.forEach(function(p, i) {1547 var e = expected[i] || [];1548 keys.forEach(function(k, j) {1549 var msgFull = msg + 'selected pt ' + i + ' - ' + k + ' val';1550 if(typeof p[k] === 'number' && typeof e[j] === 'number') {1551 expect(p[k]).toBeCloseTo(e[j], 1, msgFull);1552 } else if(Array.isArray(p[k]) && Array.isArray(e[j])) {1553 expect(p[k]).toBeCloseToArray(e[j], 1, msgFull);1554 } else {1555 expect(p[k]).toBe(e[j], msgFull);1556 }1557 });1558 });1559 callNumber++;1560 };1561 }1562 function makeAssertSelectedPoints() {1563 var callNumber = 0;1564 return function(expected) {1565 var msg = '(call #' + callNumber + ') ';1566 gd.data.forEach(function(trace, i) {1567 var msgFull = msg + 'selectedpoints array for trace ' + i;1568 var actual = trace.selectedpoints;1569 if(expected[i]) {1570 expect(actual).toBeCloseToArray(expected[i], 1, msgFull);1571 } else {1572 expect(actual).toBe(undefined, 1, msgFull);1573 }1574 });1575 callNumber++;1576 };1577 }1578 function makeAssertRanges(subplot, tol) {1579 tol = tol || 1;1580 var callNumber = 0;1581 return function(expected) {1582 var msg = '(call #' + callNumber + ') select box range ';1583 var ranges = selectedData.range || {};1584 if(subplot) {1585 expect(ranges[subplot] || [])1586 .toBeCloseTo2DArray(expected, tol, msg + 'for ' + subplot);1587 } else {1588 expect(ranges.x || [])1589 .toBeCloseToArray(expected[0], tol, msg + 'x coords');1590 expect(ranges.y || [])1591 .toBeCloseToArray(expected[1], tol, msg + 'y coords');1592 }1593 callNumber++;1594 };1595 }1596 function makeAssertLassoPoints(subplot, tol) {1597 tol = tol || 1;1598 var callNumber = 0;1599 return function(expected) {1600 var msg = '(call #' + callNumber + ') lasso points ';1601 var lassoPoints = selectedData.lassoPoints || {};1602 if(subplot) {1603 expect(lassoPoints[subplot] || [])1604 .toBeCloseTo2DArray(expected, tol, msg + 'for ' + subplot);1605 } else {1606 expect(lassoPoints.x || [])1607 .toBeCloseToArray(expected[0], tol, msg + 'x coords');1608 expect(lassoPoints.y || [])1609 .toBeCloseToArray(expected[1], tol, msg + 'y coords');1610 }1611 callNumber++;1612 };1613 }1614 function transformPlot(gd, transformString) {1615 gd.style.webkitTransform = transformString;1616 gd.style.MozTransform = transformString;1617 gd.style.msTransform = transformString;1618 gd.style.OTransform = transformString;1619 gd.style.transform = transformString;1620 }1621 var cssTransform = 'translate(-25%, -25%) scale(0.5)';1622 function _run(hasCssTransform, dragPath, afterDragFn, dblClickPos, eventCounts, msg) {1623 afterDragFn = afterDragFn || function() {};1624 dblClickPos = dblClickPos || [250, 200];1625 var scale = 1;1626 if(hasCssTransform) {1627 scale = 0.5;1628 }1629 dblClickPos[0] *= scale;1630 dblClickPos[1] *= scale;1631 for(var i = 0; i < dragPath.length; i++) {1632 for(var j = 0; j < dragPath[i].length; j++) {1633 dragPath[i][j] *= scale;1634 }1635 }1636 resetEvents(gd);1637 assertSelectionNodes(0, 0);1638 drag(dragPath);1639 return (eventCounts[0] ? selectedPromise : Promise.resolve())1640 .then(afterDragFn)1641 .then(function() {1642 // TODO: in v3 when we remove the `plotly_selecting->undefined` the Math.max(...)1643 // in the middle here will turn into just eventCounts[1].1644 // It's just here because one of the selected events is generated during1645 // doubleclick so hasn't happened yet when we're testing this.1646 assertEventCounts(eventCounts[0], Math.max(0, eventCounts[1] - 1), 0, msg + ' (before dblclick)');1647 return doubleClick(dblClickPos[0], dblClickPos[1]);1648 })1649 .then(eventCounts[2] ? deselectPromise : Promise.resolve())1650 .then(function() {1651 assertEventCounts(eventCounts[0], eventCounts[1], eventCounts[2], msg + ' (after dblclick)');1652 expect(Lib.error).not.toHaveBeenCalled();1653 });1654 }1655 [false, true].forEach(function(hasCssTransform) {1656 it('should work on scatterternary traces, hasCssTransform: ' + hasCssTransform, function(done) {1657 var assertPoints = makeAssertPoints(['a', 'b', 'c']);1658 var assertSelectedPoints = makeAssertSelectedPoints();1659 var fig = Lib.extendDeep({}, require('@mocks/ternary_simple'));1660 fig.layout.width = 800;1661 fig.layout.dragmode = 'select';1662 addInvisible(fig);1663 Plotly.newPlot(gd, fig)1664 .then(function() {1665 if(hasCssTransform) transformPlot(gd, cssTransform);1666 return _run(hasCssTransform,1667 [[400, 200], [445, 235]],1668 function() {1669 assertPoints([[0.5, 0.25, 0.25]]);1670 assertSelectedPoints({0: [0]});1671 },1672 [380, 180],1673 BOXEVENTS, 'scatterternary select'1674 );1675 })1676 .then(function() {1677 return Plotly.relayout(gd, 'dragmode', 'lasso');1678 })1679 .then(function() {1680 return _run(hasCssTransform,1681 [[400, 200], [445, 200], [445, 235], [400, 235], [400, 200]],1682 function() {1683 assertPoints([[0.5, 0.25, 0.25]]);1684 assertSelectedPoints({0: [0]});1685 },1686 [380, 180],1687 LASSOEVENTS, 'scatterternary lasso'1688 );1689 })1690 .then(function() {1691 // should work after a relayout too1692 return Plotly.relayout(gd, 'width', 400);1693 })1694 .then(function() {1695 return _run(hasCssTransform,1696 [[200, 200], [230, 200], [230, 230], [200, 230], [200, 200]],1697 function() {1698 assertPoints([[0.5, 0.25, 0.25]]);1699 assertSelectedPoints({0: [0]});1700 },1701 [180, 180],1702 LASSOEVENTS, 'scatterternary lasso after relayout'1703 );1704 })1705 .then(done, done.fail);1706 });1707 });1708 [false, true].forEach(function(hasCssTransform) {1709 it('should work on scattercarpet traces, hasCssTransform: ' + hasCssTransform, function(done) {1710 var assertPoints = makeAssertPoints(['a', 'b']);1711 var assertSelectedPoints = makeAssertSelectedPoints();1712 var fig = Lib.extendDeep({}, require('@mocks/scattercarpet'));1713 delete fig.data[6].selectedpoints;1714 fig.layout.dragmode = 'select';1715 addInvisible(fig);1716 Plotly.newPlot(gd, fig)1717 .then(function() {1718 if(hasCssTransform) transformPlot(gd, cssTransform);1719 return _run(hasCssTransform,1720 [[300, 200], [400, 250]],1721 function() {1722 assertPoints([[0.2, 1.5]]);1723 assertSelectedPoints({1: [], 2: [], 3: [], 4: [], 5: [1], 6: []});1724 },1725 null, BOXEVENTS, 'scattercarpet select'1726 );1727 })1728 .then(function() {1729 return Plotly.relayout(gd, 'dragmode', 'lasso');1730 })1731 .then(function() {1732 return _run(hasCssTransform,1733 [[300, 200], [400, 200], [400, 250], [300, 250], [300, 200]],1734 function() {1735 assertPoints([[0.2, 1.5]]);1736 assertSelectedPoints({1: [], 2: [], 3: [], 4: [], 5: [1], 6: []});1737 },1738 null, LASSOEVENTS, 'scattercarpet lasso'1739 );1740 })1741 .then(done, done.fail);1742 });1743 });1744 [false, true].forEach(function(hasCssTransform) {1745 it('@gl should work on scattermapbox traces, hasCssTransform: ' + hasCssTransform, function(done) {1746 var assertPoints = makeAssertPoints(['lon', 'lat']);1747 var assertRanges = makeAssertRanges('mapbox');1748 var assertLassoPoints = makeAssertLassoPoints('mapbox');1749 var assertSelectedPoints = makeAssertSelectedPoints();1750 var fig = Lib.extendDeep({}, require('@mocks/mapbox_bubbles-text'));1751 fig.data[0].lon.push(null);1752 fig.data[0].lat.push(null);1753 fig.layout.dragmode = 'select';1754 fig.config = {1755 mapboxAccessToken: require('@build/credentials.json').MAPBOX_ACCESS_TOKEN1756 };1757 addInvisible(fig);1758 Plotly.newPlot(gd, fig)1759 .then(function() {1760 if(hasCssTransform) transformPlot(gd, cssTransform);1761 return _run(hasCssTransform,1762 [[370, 120], [500, 200]],1763 function() {1764 assertPoints([[30, 30]]);1765 assertRanges([[21.99, 34.55], [38.14, 25.98]]);1766 assertSelectedPoints({0: [2]});1767 },1768 null, BOXEVENTS, 'scattermapbox select'1769 );1770 })1771 .then(function() {1772 return Plotly.relayout(gd, 'dragmode', 'lasso');1773 })1774 .then(function() {1775 return _run(hasCssTransform,1776 [[300, 200], [300, 300], [400, 300], [400, 200], [300, 200]],1777 function() {1778 assertPoints([[20, 20]]);1779 assertSelectedPoints({0: [1]});1780 assertLassoPoints([1781 [13.28, 25.97], [13.28, 14.33], [25.71, 14.33], [25.71, 25.97], [13.28, 25.97]1782 ]);1783 },1784 null, LASSOEVENTS, 'scattermapbox lasso'1785 );1786 })1787 .then(function() {1788 // make selection handlers don't get called in 'pan' dragmode1789 return Plotly.relayout(gd, 'dragmode', 'pan');1790 })1791 .then(function() {1792 return _run(hasCssTransform,1793 [[370, 120], [500, 200]], null, null, NOEVENTS, 'scattermapbox pan'1794 );1795 })1796 .then(done, done.fail);1797 }, LONG_TIMEOUT_INTERVAL);1798 });1799 [false, true].forEach(function(hasCssTransform) {1800 it('@gl should work on choroplethmapbox traces, hasCssTransform: ' + hasCssTransform, function(done) {1801 var assertPoints = makeAssertPoints(['location', 'z']);1802 var assertRanges = makeAssertRanges('mapbox');1803 var assertLassoPoints = makeAssertLassoPoints('mapbox');1804 var assertSelectedPoints = makeAssertSelectedPoints();1805 var fig = Lib.extendDeep({}, require('@mocks/mapbox_choropleth0.json'));1806 fig.data[0].locations.push(null);1807 fig.layout.dragmode = 'select';1808 fig.config = {1809 mapboxAccessToken: require('@build/credentials.json').MAPBOX_ACCESS_TOKEN1810 };1811 addInvisible(fig);1812 Plotly.newPlot(gd, fig)1813 .then(function() {1814 if(hasCssTransform) transformPlot(gd, cssTransform);1815 return _run(hasCssTransform,1816 [[150, 150], [300, 300]],1817 function() {1818 assertPoints([['NY', 10]]);1819 assertRanges([[-83.38, 46.13], [-74.06, 39.29]]);1820 assertSelectedPoints({0: [0]});1821 },1822 null, BOXEVENTS, 'choroplethmapbox select'1823 );1824 })1825 .then(function() {1826 return Plotly.relayout(gd, 'dragmode', 'lasso');1827 })1828 .then(function() {1829 return _run(hasCssTransform,1830 [[300, 200], [300, 300], [400, 300], [400, 200], [300, 200]],1831 function() {1832 assertPoints([['MA', 20]]);1833 assertSelectedPoints({0: [1]});1834 assertLassoPoints([1835 [-74.06, 43.936], [-74.06, 39.293], [-67.84, 39.293],1836 [-67.84, 43.936], [-74.06, 43.936]1837 ]);1838 },1839 null, LASSOEVENTS, 'choroplethmapbox lasso'1840 );1841 })1842 .then(done, done.fail);1843 }, LONG_TIMEOUT_INTERVAL);1844 });1845 [false, true].forEach(function(hasCssTransform) {1846 it('should work on scattergeo traces, hasCssTransform: ' + hasCssTransform, function(done) {1847 var assertPoints = makeAssertPoints(['lon', 'lat']);1848 var assertSelectedPoints = makeAssertSelectedPoints();1849 var assertRanges = makeAssertRanges('geo');1850 var assertLassoPoints = makeAssertLassoPoints('geo');1851 function assertNodeOpacity(exp) {1852 var traces = d3Select(gd).selectAll('.scatterlayer > .trace');1853 expect(traces.size()).toBe(Object.keys(exp).length, 'correct # of trace <g>');1854 traces.each(function(_, i) {1855 d3Select(this).selectAll('path.point').each(function(_, j) {1856 expect(Number(this.style.opacity))1857 .toBe(exp[i][j], 'node opacity - trace ' + i + ' pt ' + j);1858 });1859 });1860 }1861 var fig = {1862 data: [{1863 type: 'scattergeo',1864 lon: [10, 20, 30, null],1865 lat: [10, 20, 30, null]1866 }, {1867 type: 'scattergeo',1868 lon: [-10, -20, -30],1869 lat: [10, 20, 30]1870 }],1871 layout: {1872 showlegend: false,1873 dragmode: 'select',1874 width: 800,1875 height: 6001876 }1877 };1878 addInvisible(fig);1879 Plotly.newPlot(gd, fig)1880 .then(function() {1881 if(hasCssTransform) transformPlot(gd, cssTransform);1882 return _run(hasCssTransform,1883 [[350, 200], [450, 400]],1884 function() {1885 assertPoints([[10, 10], [20, 20], [-10, 10], [-20, 20]]);1886 assertSelectedPoints({0: [0, 1], 1: [0, 1]});1887 assertNodeOpacity({0: [1, 1, 0.2], 1: [1, 1, 0.2]});1888 assertRanges([[-28.13, 61.88], [28.13, -50.64]]);1889 },1890 null, BOXEVENTS, 'scattergeo select'1891 );1892 })1893 .then(function() {1894 return Plotly.relayout(gd, 'dragmode', 'lasso');1895 })1896 .then(function() {1897 return _run(hasCssTransform,1898 [[300, 200], [300, 300], [400, 300], [400, 200], [300, 200]],1899 function() {1900 assertPoints([[-10, 10], [-20, 20], [-30, 30]]);1901 assertSelectedPoints({0: [], 1: [0, 1, 2]});1902 assertNodeOpacity({0: [0.2, 0.2, 0.2], 1: [1, 1, 1]});1903 assertLassoPoints([1904 [-56.25, 61.88], [-56.24, 5.63], [0, 5.63], [0, 61.88], [-56.25, 61.88]1905 ]);1906 },1907 null, LASSOEVENTS, 'scattergeo lasso'1908 );1909 })1910 .then(function() {1911 // some projection types can't handle BADNUM during c2p,1912 // make they are skipped here1913 return Plotly.relayout(gd, 'geo.projection.type', 'robinson');1914 })1915 .then(function() {1916 return _run(hasCssTransform,1917 [[300, 200], [300, 300], [400, 300], [400, 200], [300, 200]],1918 function() {1919 assertPoints([[-10, 10], [-20, 20], [-30, 30]]);1920 assertSelectedPoints({0: [], 1: [0, 1, 2]});1921 assertNodeOpacity({0: [0.2, 0.2, 0.2], 1: [1, 1, 1]});1922 assertLassoPoints([1923 [-67.40, 55.07], [-56.33, 4.968], [0, 4.968], [0, 55.07], [-67.40, 55.07]1924 ]);1925 },1926 null, LASSOEVENTS, 'scattergeo lasso (on robinson projection)'1927 );1928 })1929 .then(function() {1930 // make sure selection handlers don't get called in 'pan' dragmode1931 return Plotly.relayout(gd, 'dragmode', 'pan');1932 })1933 .then(function() {1934 return _run(hasCssTransform,1935 [[370, 120], [500, 200]], null, null, NOEVENTS, 'scattergeo pan'1936 );1937 })1938 .then(done, done.fail);1939 }, LONG_TIMEOUT_INTERVAL);1940 });1941 [false, true].forEach(function(hasCssTransform) {1942 it('should work on scatterpolar traces, hasCssTransform: ' + hasCssTransform, function(done) {1943 var assertPoints = makeAssertPoints(['r', 'theta']);1944 var assertSelectedPoints = makeAssertSelectedPoints();1945 var fig = Lib.extendDeep({}, require('@mocks/polar_subplots'));1946 fig.layout.width = 800;1947 fig.layout.dragmode = 'select';1948 addInvisible(fig);1949 Plotly.newPlot(gd, fig)1950 .then(function() {1951 if(hasCssTransform) transformPlot(gd, cssTransform);1952 return _run(hasCssTransform,1953 [[150, 150], [350, 250]],1954 function() {1955 assertPoints([[1, 0], [2, 45]]);1956 assertSelectedPoints({0: [0, 1]});1957 },1958 [200, 200],1959 BOXEVENTS, 'scatterpolar select'1960 );1961 })1962 .then(function() {1963 return Plotly.relayout(gd, 'dragmode', 'lasso');1964 })1965 .then(function() {1966 return _run(hasCssTransform,1967 [[150, 150], [350, 150], [350, 250], [150, 250], [150, 150]],1968 function() {1969 assertPoints([[1, 0], [2, 45]]);1970 assertSelectedPoints({0: [0, 1]});1971 },1972 [200, 200],1973 LASSOEVENTS, 'scatterpolar lasso'1974 );1975 })1976 .then(done, done.fail);1977 });1978 });1979 [false, true].forEach(function(hasCssTransform) {1980 it('should work on scattersmith traces, hasCssTransform: ' + hasCssTransform, function(done) {1981 var assertPoints = makeAssertPoints(['real', 'imag']);1982 var assertSelectedPoints = makeAssertSelectedPoints();1983 var fig = Lib.extendDeep({}, require('@mocks/smith_basic.json'));1984 fig.layout.dragmode = 'select';1985 addInvisible(fig);1986 Plotly.newPlot(gd, fig)1987 .then(function() {1988 if(hasCssTransform) transformPlot(gd, cssTransform);1989 return _run(hasCssTransform,1990 [[260, 260], [460, 460]],1991 function() {1992 assertPoints([[1, 0]]);1993 assertSelectedPoints({0: [2]});1994 },1995 [360, 360],1996 BOXEVENTS, 'scattersmith select'1997 );1998 })1999 .then(function() {2000 return Plotly.relayout(gd, 'dragmode', 'lasso');2001 })2002 .then(function() {2003 return _run(hasCssTransform,2004 [[260, 260], [260, 460], [460, 460], [460, 260], [260, 260]],2005 function() {2006 assertPoints([[1, 0]]);2007 assertSelectedPoints({0: [2]});2008 },2009 [360, 360],2010 LASSOEVENTS, 'scattersmith lasso'2011 );2012 })2013 .then(done, done.fail);2014 });2015 });2016 [false, true].forEach(function(hasCssTransform) {2017 it('should work on barpolar traces, hasCssTransform: ' + hasCssTransform, function(done) {2018 var assertPoints = makeAssertPoints(['r', 'theta']);2019 var assertSelectedPoints = makeAssertSelectedPoints();2020 var fig = Lib.extendDeep({}, require('@mocks/polar_wind-rose.json'));2021 fig.layout.showlegend = false;2022 fig.layout.width = 500;2023 fig.layout.height = 500;2024 fig.layout.dragmode = 'select';2025 addInvisible(fig);2026 Plotly.newPlot(gd, fig)2027 .then(function() {2028 if(hasCssTransform) transformPlot(gd, cssTransform);2029 return _run(hasCssTransform,2030 [[150, 150], [250, 250]],2031 function() {2032 assertPoints([2033 [62.5, 'N-W'], [55, 'N-W'], [40, 'North'],2034 [40, 'N-W'], [20, 'North'], [22.5, 'N-W']2035 ]);2036 assertSelectedPoints({2037 0: [7],2038 1: [7],2039 2: [0, 7],2040 3: [0, 7]2041 });2042 },2043 [200, 200],2044 BOXEVENTS, 'barpolar select'2045 );2046 })2047 .then(function() {2048 return Plotly.relayout(gd, 'dragmode', 'lasso');2049 })2050 .then(function() {2051 return _run(hasCssTransform,2052 [[150, 150], [350, 150], [350, 250], [150, 250], [150, 150]],2053 function() {2054 assertPoints([2055 [62.5, 'N-W'], [50, 'N-E'], [55, 'N-W'], [40, 'North'],2056 [30, 'N-E'], [40, 'N-W'], [20, 'North'], [7.5, 'N-E'], [22.5, 'N-W']2057 ]);2058 assertSelectedPoints({2059 0: [7],2060 1: [1, 7],2061 2: [0, 1, 7],2062 3: [0, 1, 7]2063 });2064 },2065 [200, 200],2066 LASSOEVENTS, 'barpolar lasso'2067 );2068 })2069 .then(done, done.fail);2070 });2071 });2072 [false, true].forEach(function(hasCssTransform) {2073 it('should work on choropleth traces, hasCssTransform: ' + hasCssTransform, function(done) {2074 var assertPoints = makeAssertPoints(['location', 'z']);2075 var assertSelectedPoints = makeAssertSelectedPoints();2076 var assertRanges = makeAssertRanges('geo', -0.5);2077 var assertLassoPoints = makeAssertLassoPoints('geo', -0.5);2078 var fig = Lib.extendDeep({}, require('@mocks/geo_choropleth-text'));2079 fig.layout.width = 870;2080 fig.layout.height = 450;2081 fig.layout.dragmode = 'select';2082 fig.layout.geo.scope = 'europe';2083 addInvisible(fig, false);2084 // add a trace with no locations which will then make trace invisible, lacking DOM elements2085 var emptyChoroplethTrace = Lib.extendDeep({}, fig.data[0]);2086 emptyChoroplethTrace.text = [];2087 emptyChoroplethTrace.locations = [];2088 emptyChoroplethTrace.z = [];2089 fig.data.push(emptyChoroplethTrace);2090 Plotly.newPlot(gd, fig)2091 .then(function() {2092 if(hasCssTransform) transformPlot(gd, cssTransform);2093 return _run(hasCssTransform,2094 [[350, 200], [400, 250]],2095 function() {2096 assertPoints([['GBR', 26.507354205352502], ['IRL', 86.4125147625692]]);2097 assertSelectedPoints({0: [43, 54]});2098 assertRanges([[-19.11, 63.06], [7.31, 53.72]]);2099 },2100 [280, 190],2101 BOXEVENTS, 'choropleth select'2102 );2103 })2104 .then(function() {2105 return Plotly.relayout(gd, 'dragmode', 'lasso');2106 })2107 .then(function() {2108 return _run(hasCssTransform,2109 [[350, 200], [400, 200], [400, 250], [350, 250], [350, 200]],2110 function() {2111 assertPoints([['GBR', 26.507354205352502], ['IRL', 86.4125147625692]]);2112 assertSelectedPoints({0: [43, 54]});2113 assertLassoPoints([2114 [-19.11, 63.06], [5.50, 65.25], [7.31, 53.72], [-12.90, 51.70], [-19.11, 63.06]2115 ]);2116 },2117 [280, 190],2118 LASSOEVENTS, 'choropleth lasso'2119 );2120 })2121 .then(function() {2122 // make selection handlers don't get called in 'pan' dragmode2123 return Plotly.relayout(gd, 'dragmode', 'pan');2124 })2125 .then(function() {2126 return _run(hasCssTransform,2127 [[370, 120], [500, 200]], null, [200, 180], NOEVENTS, 'choropleth pan'2128 );2129 })2130 .then(done, done.fail);2131 }, LONG_TIMEOUT_INTERVAL);2132 });2133 [false, true].forEach(function(hasCssTransform) {2134 it('should work for waterfall traces, hasCssTransform: ' + hasCssTransform, function(done) {2135 var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y']);2136 var assertSelectedPoints = makeAssertSelectedPoints();2137 var assertRanges = makeAssertRanges();2138 var assertLassoPoints = makeAssertLassoPoints();2139 var fig = Lib.extendDeep({}, require('@mocks/waterfall_profit-loss_2018_positive-negative'));2140 fig.layout.dragmode = 'lasso';2141 addInvisible(fig);2142 Plotly.newPlot(gd, fig)2143 .then(function() {2144 if(hasCssTransform) transformPlot(gd, cssTransform);2145 return _run(hasCssTransform,2146 [[400, 300], [200, 400], [400, 500], [600, 400], [500, 350]],2147 function() {2148 assertPoints([2149 [0, 281, 'Purchases'],2150 [0, 269, 'Material expenses'],2151 [0, 191, 'Personnel expenses'],2152 [0, 179, 'Other expenses']2153 ]);2154 assertSelectedPoints({2155 0: [5, 6, 7, 8]2156 });2157 assertLassoPoints([2158 [288.8086, 57.7617, 288.8086, 519.8555, 404.3321],2159 [4.33870, 6.7580, 9.1774, 6.75806, 5.54838]2160 ]);2161 },2162 null, LASSOEVENTS, 'waterfall lasso'2163 );2164 })2165 .then(function() {2166 return Plotly.relayout(gd, 'dragmode', 'select');2167 })2168 .then(function() {2169 return _run(hasCssTransform,2170 [[300, 300], [400, 400]],2171 function() {2172 assertPoints([2173 [0, 281, 'Purchases'],2174 [0, 269, 'Material expenses']2175 ]);2176 assertSelectedPoints({2177 0: [5, 6]2178 });2179 assertRanges([2180 [173.28519, 288.8086],2181 [4.3387, 6.7580]2182 ]);2183 },2184 null, BOXEVENTS, 'waterfall select'2185 );2186 })2187 .then(done, done.fail);2188 });2189 });2190 [false, true].forEach(function(hasCssTransform) {2191 it('should work for funnel traces, hasCssTransform: ' + hasCssTransform, function(done) {2192 var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y']);2193 var assertSelectedPoints = makeAssertSelectedPoints();2194 var assertRanges = makeAssertRanges();2195 var assertLassoPoints = makeAssertLassoPoints();2196 var fig = Lib.extendDeep({}, require('@mocks/funnel_horizontal_group_basic'));2197 fig.layout.dragmode = 'lasso';2198 addInvisible(fig);2199 Plotly.newPlot(gd, fig)2200 .then(function() {2201 if(hasCssTransform) transformPlot(gd, cssTransform);2202 return _run(hasCssTransform,2203 [[400, 300], [200, 400], [400, 500], [600, 400], [500, 350]],2204 function() {2205 assertPoints([2206 [0, 331.5, 'Author: etpinard'],2207 [1, 53.5, 'Pull requests'],2208 [1, 15.5, 'Author: etpinard'],2209 ]);2210 assertSelectedPoints({2211 0: [2],2212 1: [1, 2]2213 });2214 assertLassoPoints([2215 [-161.6974, -1701.6728, -161.6974, 1378.2779, 608.2902],2216 [1.1129, 1.9193, 2.7258, 1.9193, 1.5161]2217 ]);2218 },2219 null, LASSOEVENTS, 'funnel lasso'2220 );2221 })2222 .then(function() {2223 return Plotly.relayout(gd, 'dragmode', 'select');2224 })2225 .then(function() {2226 return _run(hasCssTransform,2227 [[300, 300], [500, 500]],2228 function() {2229 assertPoints([2230 [0, 331.5, 'Author: etpinard'],2231 [1, 53.5, 'Pull requests'],2232 [1, 15.5, 'Author: etpinard']2233 ]);2234 assertSelectedPoints({2235 0: [2],2236 1: [1, 2]2237 });2238 assertRanges([2239 [-931.6851, 608.2902],2240 [1.1129, 2.7258]2241 ]);2242 },2243 null, BOXEVENTS, 'funnel select'2244 );2245 })2246 .then(done, done.fail);2247 });2248 });2249 [false].forEach(function(hasCssTransform) {2250 it('@flaky should work for bar traces, hasCssTransform: ' + hasCssTransform, function(done) {2251 var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y']);2252 var assertSelectedPoints = makeAssertSelectedPoints();2253 var assertRanges = makeAssertRanges();2254 var assertLassoPoints = makeAssertLassoPoints();2255 var fig = Lib.extendDeep({}, require('@mocks/0'));2256 fig.layout.dragmode = 'lasso';2257 addInvisible(fig);2258 Plotly.newPlot(gd, fig)2259 .then(function() {2260 if(hasCssTransform) transformPlot(gd, cssTransform);2261 return _run(hasCssTransform,2262 [[350, 200], [400, 200], [400, 250], [350, 250], [350, 200]],2263 function() {2264 assertPoints([2265 [0, 4.9, 0.371], [0, 5, 0.368], [0, 5.1, 0.356], [0, 5.2, 0.336],2266 [0, 5.3, 0.309], [0, 5.4, 0.275], [0, 5.5, 0.235], [0, 5.6, 0.192],2267 [0, 5.7, 0.145],2268 [1, 5.1, 0.485], [1, 5.2, 0.409], [1, 5.3, 0.327],2269 [1, 5.4, 0.24], [1, 5.5, 0.149], [1, 5.6, 0.059],2270 [2, 4.9, 0.473], [2, 5, 0.368], [2, 5.1, 0.258],2271 [2, 5.2, 0.146], [2, 5.3, 0.036]2272 ]);2273 assertSelectedPoints({2274 0: [49, 50, 51, 52, 53, 54, 55, 56, 57],2275 1: [51, 52, 53, 54, 55, 56],2276 2: [49, 50, 51, 52, 53]2277 });2278 assertLassoPoints([2279 [4.87, 5.74, 5.74, 4.87, 4.87],2280 [0.53, 0.53, -0.02, -0.02, 0.53]2281 ]);2282 },2283 null, LASSOEVENTS, 'bar lasso'2284 );2285 })2286 .then(function() {2287 return Plotly.relayout(gd, 'dragmode', 'select');2288 })2289 .then(delay(100))2290 .then(function() {2291 return _run(hasCssTransform,2292 [[350, 200], [370, 220]],2293 function() {2294 assertPoints([2295 [0, 4.9, 0.371], [0, 5, 0.368], [0, 5.1, 0.356], [0, 5.2, 0.336],2296 [1, 5.1, 0.485], [1, 5.2, 0.41],2297 [2, 4.9, 0.473], [2, 5, 0.37]2298 ]);2299 assertSelectedPoints({2300 0: [49, 50, 51, 52],2301 1: [51, 52],2302 2: [49, 50]2303 });2304 assertRanges([[4.87, 5.22], [0.31, 0.53]]);2305 },2306 null, BOXEVENTS, 'bar select'2307 );2308 })2309 .then(function() {2310 // mimic https://github.com/plotly/plotly.js/issues/37952311 return Plotly.relayout(gd, {2312 'xaxis.rangeslider.visible': true,2313 'xaxis.range': [0, 6]2314 });2315 })2316 .then(function() {2317 return _run(hasCssTransform,2318 [[350, 200], [360, 200]],2319 function() {2320 assertPoints([2321 [0, 2.5, -0.429], [1, 2.5, -1.015], [2, 2.5, -1.172],2322 ]);2323 assertSelectedPoints({2324 0: [25],2325 1: [25],2326 2: [25]2327 });2328 assertRanges([[2.434, 2.521], [-1.4355, 2.0555]]);2329 },2330 null, BOXEVENTS, 'bar select (after xaxis.range relayout)'2331 );2332 })2333 .then(done, done.fail);2334 });2335 });2336 [false, true].forEach(function(hasCssTransform) {2337 it('should work for date/category traces, hasCssTransform: ' + hasCssTransform, function(done) {2338 var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y']);2339 var assertSelectedPoints = makeAssertSelectedPoints();2340 var fig = {2341 data: [{2342 x: ['2017-01-01', '2017-02-01', '2017-03-01'],2343 y: ['a', 'b', 'c']2344 }, {2345 type: 'bar',2346 x: ['2017-01-01', '2017-02-02', '2017-03-01'],2347 y: ['a', 'b', 'c']2348 }],2349 layout: {2350 dragmode: 'lasso',2351 width: 400,2352 height: 4002353 }2354 };2355 addInvisible(fig);2356 var x0 = 100;2357 var y0 = 100;2358 var x1 = 250;2359 var y1 = 250;2360 Plotly.newPlot(gd, fig)2361 .then(function() {2362 if(hasCssTransform) transformPlot(gd, cssTransform);2363 return _run(hasCssTransform,2364 [[x0, y0], [x1, y0], [x1, y1], [x0, y1], [x0, y0]],2365 function() {2366 assertPoints([2367 [0, '2017-02-01', 'b'],2368 [1, '2017-02-02', 'b']2369 ]);2370 assertSelectedPoints({0: [1], 1: [1]});2371 },2372 null, LASSOEVENTS, 'date/category lasso'2373 );2374 })2375 .then(function() {2376 return Plotly.relayout(gd, 'dragmode', 'select');2377 })2378 .then(function() {2379 return _run(hasCssTransform,2380 [[x0, y0], [x1, y1]],2381 function() {2382 assertPoints([2383 [0, '2017-02-01', 'b'],2384 [1, '2017-02-02', 'b']2385 ]);2386 assertSelectedPoints({0: [1], 1: [1]});2387 },2388 null, BOXEVENTS, 'date/category select'2389 );2390 })2391 .then(done, done.fail);2392 });2393 });2394 [false, true].forEach(function(hasCssTransform) {2395 it('should work for histogram traces, hasCssTransform: ' + hasCssTransform, function(done) {2396 var assertPoints = makeAssertPoints(['curveNumber', 'x', 'y', 'pointIndices']);2397 var assertSelectedPoints = makeAssertSelectedPoints();2398 var assertRanges = makeAssertRanges();2399 var assertLassoPoints = makeAssertLassoPoints();2400 var fig = Lib.extendDeep({}, require('@mocks/hist_grouped'));2401 fig.layout.dragmode = 'lasso';2402 fig.layout.width = 600;2403 fig.layout.height = 500;2404 addInvisible(fig);2405 Plotly.newPlot(gd, fig)2406 .then(function() {2407 if(hasCssTransform) transformPlot(gd, cssTransform);2408 return _run(hasCssTransform,2409 [[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]],2410 function() {2411 assertPoints([2412 [0, 1.8, 2, [3, 4]], [1, 2.2, 1, [1]], [1, 3.2, 1, [2]]2413 ]);2414 assertSelectedPoints({0: [3, 4], 1: [1, 2]});2415 assertLassoPoints([2416 [1.66, 3.59, 3.59, 1.66, 1.66],2417 [2.17, 2.17, 0.69, 0.69, 2.17]2418 ]);2419 },2420 null, LASSOEVENTS, 'histogram lasso'2421 );2422 })2423 .then(function() {2424 return Plotly.relayout(gd, 'dragmode', 'select');2425 })2426 .then(function() {2427 return _run(hasCssTransform,2428 [[200, 200], [400, 350]],2429 function() {2430 assertPoints([2431 [0, 1.8, 2, [3, 4]], [1, 2.2, 1, [1]], [1, 3.2, 1, [2]]2432 ]);2433 assertSelectedPoints({0: [3, 4], 1: [1, 2]});2434 assertRanges([[1.66, 3.59], [0.69, 2.17]]);2435 },2436 null, BOXEVENTS, 'histogram select'2437 );2438 })2439 .then(done, done.fail);2440 });2441 });2442 [false, true].forEach(function(hasCssTransform) {2443 it('should work for box traces, hasCssTransform: ' + hasCssTransform, function(done) {2444 var assertPoints = makeAssertPoints(['curveNumber', 'y', 'x']);2445 var assertSelectedPoints = makeAssertSelectedPoints();2446 var assertRanges = makeAssertRanges();2447 var assertLassoPoints = makeAssertLassoPoints();2448 var fig = Lib.extendDeep({}, require('@mocks/box_grouped'));2449 fig.data.forEach(function(trace) {2450 trace.boxpoints = 'all';2451 });2452 fig.layout.dragmode = 'lasso';2453 fig.layout.width = 600;2454 fig.layout.height = 500;2455 fig.layout.xaxis = {range: [-0.565, 1.5]};2456 addInvisible(fig);2457 Plotly.newPlot(gd, fig)2458 .then(function() {2459 if(hasCssTransform) transformPlot(gd, cssTransform);2460 return _run(hasCssTransform,2461 [[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]],2462 function() {2463 assertPoints([2464 [0, 0.2, 'day 2'], [0, 0.3, 'day 2'], [0, 0.5, 'day 2'], [0, 0.7, 'day 2'],2465 [1, 0.2, 'day 2'], [1, 0.5, 'day 2'], [1, 0.7, 'day 2'], [1, 0.7, 'day 2'],2466 [2, 0.3, 'day 1'], [2, 0.6, 'day 1'], [2, 0.6, 'day 1']2467 ]);2468 assertSelectedPoints({2469 0: [6, 11, 10, 7],2470 1: [11, 8, 6, 10],2471 2: [1, 4, 5]2472 });2473 assertLassoPoints([2474 [0.0423, 1.0546, 1.0546, 0.0423, 0.0423],2475 [0.71, 0.71, 0.1875, 0.1875, 0.71]2476 ]);2477 },2478 null, LASSOEVENTS, 'box lasso'2479 );2480 })2481 .then(function() {2482 return Plotly.relayout(gd, 'dragmode', 'select');2483 })2484 .then(function() {2485 return _run(hasCssTransform,2486 [[200, 200], [400, 350]],2487 function() {2488 assertPoints([2489 [0, 0.2, 'day 2'], [0, 0.3, 'day 2'], [0, 0.5, 'day 2'], [0, 0.7, 'day 2'],2490 [1, 0.2, 'day 2'], [1, 0.5, 'day 2'], [1, 0.7, 'day 2'], [1, 0.7, 'day 2'],2491 [2, 0.3, 'day 1'], [2, 0.6, 'day 1'], [2, 0.6, 'day 1']2492 ]);2493 assertSelectedPoints({2494 0: [6, 11, 10, 7],2495 1: [11, 8, 6, 10],2496 2: [1, 4, 5]2497 });2498 assertRanges([[0.04235, 1.0546], [0.1875, 0.71]]);2499 },2500 null, BOXEVENTS, 'box select'2501 );2502 })2503 .then(done, done.fail);2504 });2505 });2506 [false, true].forEach(function(hasCssTransform) {2507 it('should work for box traces (q1/median/q3 case), hasCssTransform: ' + hasCssTransform, function(done) {2508 var assertPoints = makeAssertPoints(['curveNumber', 'y', 'x']);2509 var assertSelectedPoints = makeAssertSelectedPoints();2510 var fig = {2511 data: [{2512 type: 'box',2513 x0: 'A',2514 q1: [1],2515 median: [2],2516 q3: [3],2517 y: [[0, 1, 2, 3, 4]],2518 pointpos: 0,2519 }],2520 layout: {2521 width: 500,2522 height: 500,2523 dragmode: 'lasso'2524 }2525 };2526 Plotly.newPlot(gd, fig)2527 .then(function() {2528 if(hasCssTransform) transformPlot(gd, cssTransform);2529 return _run(hasCssTransform,2530 [[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]],2531 function() {2532 assertPoints([ [0, 1, undefined], [0, 2, undefined] ]);2533 assertSelectedPoints({ 0: [[0, 1], [0, 2]] });2534 },2535 null, LASSOEVENTS, 'box lasso'2536 );2537 })2538 .then(function() {2539 return Plotly.relayout(gd, 'dragmode', 'select');2540 })2541 .then(function() {2542 return _run(hasCssTransform,2543 [[200, 200], [400, 300]],2544 function() {2545 assertPoints([ [0, 2, undefined] ]);2546 assertSelectedPoints({ 0: [[0, 2]] });2547 },2548 null, BOXEVENTS, 'box select'2549 );2550 })2551 .then(done, done.fail);2552 });2553 });2554 [false, true].forEach(function(hasCssTransform) {2555 it('should work for violin traces, hasCssTransform: ' + hasCssTransform, function(done) {2556 var assertPoints = makeAssertPoints(['curveNumber', 'y', 'x']);2557 var assertSelectedPoints = makeAssertSelectedPoints();2558 var assertRanges = makeAssertRanges();2559 var assertLassoPoints = makeAssertLassoPoints();2560 var fig = Lib.extendDeep({}, require('@mocks/violin_grouped'));2561 fig.layout.dragmode = 'lasso';2562 fig.layout.width = 600;2563 fig.layout.height = 500;2564 addInvisible(fig);2565 Plotly.newPlot(gd, fig)2566 .then(function() {2567 if(hasCssTransform) transformPlot(gd, cssTransform);2568 return _run(hasCssTransform,2569 [[200, 200], [400, 200], [400, 350], [200, 350], [200, 200]],2570 function() {2571 assertPoints([2572 [0, 0.3, 'day 2'], [0, 0.5, 'day 2'], [0, 0.7, 'day 2'], [0, 0.9, 'day 2'],2573 [1, 0.5, 'day 2'], [1, 0.7, 'day 2'], [1, 0.7, 'day 2'], [1, 0.8, 'day 2'],2574 [1, 0.9, 'day 2'],2575 [2, 0.3, 'day 1'], [2, 0.6, 'day 1'], [2, 0.6, 'day 1'], [2, 0.9, 'day 1']2576 ]);2577 assertSelectedPoints({2578 0: [11, 10, 7, 8],2579 1: [8, 6, 10, 9, 7],2580 2: [1, 4, 5, 3]2581 });2582 assertLassoPoints([2583 [0.07777, 1.0654, 1.0654, 0.07777, 0.07777],2584 [1.02, 1.02, 0.27, 0.27, 1.02]2585 ]);2586 },2587 null, LASSOEVENTS, 'violin lasso'2588 );2589 })2590 .then(function() {2591 return Plotly.relayout(gd, 'dragmode', 'select');2592 })2593 .then(function() {2594 return _run(hasCssTransform,2595 [[200, 200], [400, 350]],2596 function() {2597 assertPoints([2598 [0, 0.3, 'day 2'], [0, 0.5, 'day 2'], [0, 0.7, 'day 2'], [0, 0.9, 'day 2'],2599 [1, 0.5, 'day 2'], [1, 0.7, 'day 2'], [1, 0.7, 'day 2'], [1, 0.8, 'day 2'],2600 [1, 0.9, 'day 2'],2601 [2, 0.3, 'day 1'], [2, 0.6, 'day 1'], [2, 0.6, 'day 1'], [2, 0.9, 'day 1']2602 ]);2603 assertSelectedPoints({2604 0: [11, 10, 7, 8],2605 1: [8, 6, 10, 9, 7],2606 2: [1, 4, 5, 3]2607 });2608 assertRanges([[0.07777, 1.0654], [0.27, 1.02]]);2609 },2610 null, BOXEVENTS, 'violin select'2611 );2612 })2613 .then(done, done.fail);2614 });2615 });2616 [false].forEach(function(hasCssTransform) {2617 ['ohlc', 'candlestick'].forEach(function(type) {2618 it('should work for ' + type + ' traces, hasCssTransform: ' + hasCssTransform, function(done) {2619 var assertPoints = makeAssertPoints(['curveNumber', 'x', 'open', 'high', 'low', 'close']);2620 var assertSelectedPoints = makeAssertSelectedPoints();2621 var assertRanges = makeAssertRanges();2622 var assertLassoPoints = makeAssertLassoPoints();2623 var l0 = 275;2624 var lv0 = '2011-01-03 18:00';2625 var r0 = 325;2626 var rv0 = '2011-01-04 06:00';2627 var l1 = 75;2628 var lv1 = '2011-01-01 18:00';2629 var r1 = 125;2630 var rv1 = '2011-01-02 06:00';2631 var t = 75;2632 var tv = 7.565;2633 var b = 225;2634 var bv = -1.048;2635 function countUnSelectedPaths(selector) {2636 var unselected = 0;2637 d3Select(gd).selectAll(selector).each(function() {2638 var opacity = this.style.opacity;2639 if(opacity < 1) unselected++;2640 });2641 return unselected;2642 }2643 Plotly.newPlot(gd, [{2644 type: type,2645 x: ['2011-01-02', '2011-01-03', '2011-01-04'],2646 open: [1, 2, 3],2647 high: [3, 4, 5],2648 low: [0, 1, 2],2649 close: [0, 3, 2]2650 }], {2651 width: 400,2652 height: 400,2653 margin: {l: 50, r: 50, t: 50, b: 50},2654 yaxis: {range: [-3, 9]},2655 dragmode: 'lasso'2656 })2657 .then(function() {2658 if(hasCssTransform) transformPlot(gd, cssTransform);2659 return _run(hasCssTransform,2660 [[l0, t], [l0, b], [r0, b], [r0, t], [l0, t]],2661 function() {2662 assertPoints([[0, '2011-01-04', 3, 5, 2, 2]]);2663 assertSelectedPoints([[2]]);2664 assertLassoPoints([2665 [lv0, lv0, rv0, rv0, lv0],2666 [tv, bv, bv, tv, tv]2667 ]);2668 expect(countUnSelectedPaths('.cartesianlayer .trace path')).toBe(2);2669 expect(countUnSelectedPaths('.rangeslider-rangeplot .trace path')).toBe(2);2670 },2671 null, LASSOEVENTS, type + ' lasso'2672 );2673 })2674 .then(function() {2675 return Plotly.relayout(gd, 'dragmode', 'select');2676 })2677 .then(function() {2678 return _run(hasCssTransform,2679 [[l1, t], [r1, b]],2680 function() {2681 assertPoints([[0, '2011-01-02', 1, 3, 0, 0]]);2682 assertSelectedPoints([[0]]);2683 assertRanges([[lv1, rv1], [bv, tv]]);2684 },2685 null, BOXEVENTS, type + ' select'2686 );2687 })2688 .then(done, done.fail);2689 });2690 });2691 });2692 [false, true].forEach(function(hasCssTransform) {2693 it('should work on traces with enabled transforms, hasCssTransform: ' + hasCssTransform, function(done) {2694 var assertSelectedPoints = makeAssertSelectedPoints();2695 Plotly.newPlot(gd, [{2696 x: [1, 2, 3, 4, 5],2697 y: [2, 3, 1, 7, 9],2698 marker: {size: [10, 20, 20, 20, 10]},2699 transforms: [{2700 type: 'filter',2701 operation: '>',2702 value: 2,2703 target: 'y'2704 }, {2705 type: 'aggregate',2706 groups: 'marker.size',2707 aggregations: [2708 // 20: 6, 10: 52709 {target: 'x', func: 'sum'},2710 // 20: 5, 10: 92711 {target: 'y', func: 'avg'}2712 ]2713 }]2714 }], {2715 dragmode: 'select',2716 showlegend: false,2717 width: 400,2718 height: 400,2719 margin: {l: 0, t: 0, r: 0, b: 0}2720 })2721 .then(function() {2722 if(hasCssTransform) transformPlot(gd, cssTransform);2723 return _run(hasCssTransform,2724 [[5, 5], [395, 395]],2725 function() {2726 assertSelectedPoints({0: [1, 3, 4]});2727 },2728 [380, 180],2729 BOXEVENTS, 'transformed trace select (all points selected)'2730 );2731 })2732 .then(done, done.fail);2733 });2734 });2735 [false, true].forEach(function(hasCssTransform) {2736 it('should work on scatter/bar traces with text nodes, hasCssTransform: ' + hasCssTransform, function(done) {2737 var assertSelectedPoints = makeAssertSelectedPoints();2738 function assertFillOpacity(exp, msg) {2739 var txtPts = d3Select(gd).select('g.plot').selectAll('text');2740 expect(txtPts.size()).toBe(exp.length, '# of text nodes: ' + msg);2741 txtPts.each(function(_, i) {2742 var act = Number(this.style['fill-opacity']);2743 expect(act).toBe(exp[i], 'node ' + i + ' fill opacity: ' + msg);2744 });2745 }2746 Plotly.newPlot(gd, [{2747 mode: 'markers+text',2748 x: [1, 2, 3],2749 y: [1, 2, 1],2750 text: ['a', 'b', 'c']2751 }, {2752 type: 'bar',2753 x: [1, 2, 3],2754 y: [1, 2, 1],2755 text: ['A', 'B', 'C'],2756 textposition: 'outside'2757 }], {2758 dragmode: 'select',2759 hovermode: 'closest',2760 showlegend: false,2761 width: 400,2762 height: 400,2763 margin: {l: 0, t: 0, r: 0, b: 0}2764 })2765 .then(function() {2766 if(hasCssTransform) transformPlot(gd, cssTransform);2767 return _run(hasCssTransform,2768 [[10, 10], [100, 300]],2769 function() {2770 assertSelectedPoints({0: [0], 1: [0]});2771 assertFillOpacity([1, 0.2, 0.2, 1, 0.2, 0.2], '_run');2772 },2773 [10, 10], BOXEVENTS, 'selecting first scatter/bar text nodes'2774 );2775 })2776 .then(function() {2777 assertFillOpacity([1, 1, 1, 1, 1, 1], 'final');2778 })2779 .then(done, done.fail);2780 });2781 });2782 describe('should work on sankey traces', function() {2783 var waitingTime = sankeyConstants.duration * 2;2784 [false].forEach(function(hasCssTransform) {2785 it('select, hasCssTransform: ' + hasCssTransform, function(done) {2786 var fig = Lib.extendDeep({}, require('@mocks/sankey_circular.json'));2787 fig.layout.dragmode = 'select';2788 var dblClickPos = [250, 400];2789 Plotly.newPlot(gd, fig)2790 .then(function() {2791 if(hasCssTransform) transformPlot(gd, cssTransform);2792 // No groups initially2793 expect(gd._fullData[0].node.groups).toEqual([]);2794 })2795 .then(function() {2796 // Grouping the two nodes on the top right2797 return _run(hasCssTransform,2798 [[640, 130], [400, 450]],2799 function() {2800 expect(gd._fullData[0].node.groups).toEqual([[2, 3]], 'failed to group #2 + #3');2801 },2802 dblClickPos, BOXEVENTS, 'for top right nodes #2 and #3'2803 );2804 })2805 .then(delay(waitingTime))2806 .then(function() {2807 // Grouping node #4 and the previous group2808 drag([[715, 400], [300, 110]]);2809 })2810 .then(delay(waitingTime))2811 .then(function() {2812 expect(gd._fullData[0].node.groups).toEqual([[4, 3, 2]], 'failed to group #4 + existing group of #2 and #3');2813 })2814 .then(done, done.fail);2815 });2816 });2817 it('should not work when dragmode is undefined', function(done) {2818 var fig = Lib.extendDeep({}, require('@mocks/sankey_circular.json'));2819 fig.layout.dragmode = undefined;2820 Plotly.newPlot(gd, fig)2821 .then(function() {2822 // No groups initially2823 expect(gd._fullData[0].node.groups).toEqual([]);2824 })2825 .then(function() {2826 // Grouping the two nodes on the top right2827 drag([[640, 130], [400, 450]]);2828 })2829 .then(delay(waitingTime))2830 .then(function() {2831 expect(gd._fullData[0].node.groups).toEqual([]);2832 })2833 .then(done, done.fail);2834 });2835 });2836});2837describe('Test that selections persist:', function() {2838 var gd;2839 beforeEach(function() {2840 gd = createGraphDiv();2841 });2842 afterEach(destroyGraphDiv);2843 function assertPtOpacity(selector, expected) {2844 d3SelectAll(selector).each(function(_, i) {2845 var style = Number(this.style.opacity);2846 expect(style).toBe(expected.style[i], 'style for pt ' + i);2847 });2848 }2849 it('should persist for scatter', function(done) {2850 function _assert(expected) {2851 var selected = gd.calcdata[0].map(function(d) { return d.selected; });2852 expect(selected).toBeCloseToArray(expected.selected, 'selected vals');2853 assertPtOpacity('.point', expected);2854 }2855 Plotly.newPlot(gd, [{2856 x: [1, 2, 3],2857 y: [1, 2, 1]2858 }], {2859 dragmode: 'select',2860 width: 400,2861 height: 400,2862 margin: {l: 0, t: 0, r: 0, b: 0}2863 })2864 .then(function() {2865 resetEvents(gd);2866 drag([[5, 5], [250, 350]]);2867 return selectedPromise;2868 })2869 .then(function() {2870 _assert({2871 selected: [0, 1, 0],2872 style: [0.2, 1, 0.2]2873 });2874 // trigger a recalc2875 Plotly.restyle(gd, 'x', [[10, 20, 30]]);2876 })2877 .then(function() {2878 _assert({2879 selected: [undefined, 1, undefined],2880 style: [0.2, 1, 0.2]2881 });2882 })2883 .then(done, done.fail);2884 });2885 it('should persist for box', function(done) {2886 function _assert(expected) {2887 var selected = gd.calcdata[0][0].pts.map(function(d) { return d.selected; });2888 expect(selected).toBeCloseToArray(expected.cd, 'selected calcdata vals');2889 expect(gd.data[0].selectedpoints).toBeCloseToArray(expected.selectedpoints, 'selectedpoints array');2890 assertPtOpacity('.point', expected);2891 }2892 Plotly.newPlot(gd, [{2893 type: 'box',2894 x0: 0,2895 y: [5, 4, 4, 1, 2, 2, 2, 2, 2, 3, 3, 3],2896 boxpoints: 'all'2897 }], {2898 dragmode: 'select',2899 width: 400,2900 height: 400,2901 margin: {l: 0, t: 0, r: 0, b: 0}2902 })2903 .then(function() {2904 resetEvents(gd);2905 drag([[5, 5], [400, 150]]);2906 return selectedPromise;2907 })2908 .then(function() {2909 _assert({2910 // N.B. pts in calcdata are sorted2911 cd: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1],2912 selectedpoints: [1, 2, 0],2913 style: [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 1, 1, 1],2914 });2915 // trigger a recalc2916 return Plotly.restyle(gd, 'x0', 1);2917 })2918 .then(function() {2919 _assert({2920 cd: [undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 1, 1, 1],2921 selectedpoints: [1, 2, 0],2922 style: [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 1, 1, 1],2923 });2924 })2925 .then(done, done.fail);2926 });2927 it('should persist for histogram', function(done) {2928 function _assert(expected) {2929 var selected = gd.calcdata[0].map(function(d) { return d.selected; });2930 expect(selected).toBeCloseToArray(expected.selected, 'selected vals');2931 assertPtOpacity('.point > path', expected);2932 }2933 Plotly.newPlot(gd, [{2934 type: 'histogram',2935 x: [1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5],2936 boxpoints: 'all'2937 }], {2938 dragmode: 'select',2939 width: 400,2940 height: 400,2941 margin: {l: 0, t: 0, r: 0, b: 0}2942 })2943 .then(function() {2944 resetEvents(gd);2945 drag([[5, 5], [400, 150]]);2946 return selectedPromise;2947 })2948 .then(function() {2949 _assert({2950 selected: [0, 1, 0, 0, 0],2951 style: [0.2, 1, 0.2, 0.2, 0.2],2952 });2953 // trigger a recalc2954 return Plotly.restyle(gd, 'histfunc', 'sum');2955 })2956 .then(function() {2957 _assert({2958 selected: [undefined, 1, undefined, undefined, undefined],2959 style: [0.2, 1, 0.2, 0.2, 0.2],2960 });2961 })2962 .then(done, done.fail);2963 });2964});2965describe('Test that selection styles propagate to range-slider plot:', function() {2966 var gd;2967 beforeEach(function() {2968 gd = createGraphDiv();2969 });2970 afterEach(destroyGraphDiv);2971 function makeAssertFn(query) {2972 return function(msg, expected) {2973 var gd3 = d3Select(gd);2974 var mainPlot3 = gd3.select('.cartesianlayer');2975 var rangePlot3 = gd3.select('.rangeslider-rangeplot');2976 mainPlot3.selectAll(query).each(function(_, i) {2977 expect(this.style.opacity).toBe(String(expected[i]), msg + ' opacity for mainPlot pt ' + i);2978 });2979 rangePlot3.selectAll(query).each(function(_, i) {2980 expect(this.style.opacity).toBe(String(expected[i]), msg + ' opacity for rangePlot pt ' + i);2981 });2982 };2983 }2984 it('- svg points case', function(done) {2985 var _assert = makeAssertFn('path.point,.point>path');2986 Plotly.newPlot(gd, [2987 { mode: 'markers', x: [1], y: [1] },2988 { type: 'bar', x: [2], y: [2], },2989 { type: 'histogram', x: [3, 3, 3] },2990 { type: 'box', x: [4], y: [4], boxpoints: 'all' },2991 { type: 'violin', x: [5], y: [5], points: 'all' },2992 { type: 'waterfall', x: [6], y: [6]},2993 { type: 'funnel', x: [7], y: [7], orientation: 'v'}2994 ], {2995 dragmode: 'select',2996 xaxis: { rangeslider: {visible: true} },2997 width: 500,2998 height: 500,2999 margin: {l: 10, t: 10, r: 10, b: 10},3000 showlegend: false3001 })3002 .then(function() {3003 _assert('base', [1, 1, 1, 1, 1, 1, 1]);3004 })3005 .then(function() {3006 resetEvents(gd);3007 drag([[20, 20], [40, 40]]);3008 return selectedPromise;3009 })3010 .then(function() {3011 _assert('after empty selection', [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2]);3012 })3013 .then(function() { return doubleClick(200, 200); })3014 .then(function() {3015 _assert('after double-click reset', [1, 1, 1, 1, 1, 1, 1]);3016 })3017 .then(done, done.fail);3018 });3019 it('- svg finance case', function(done) {3020 var _assert = makeAssertFn('path.box,.ohlc>path');3021 Plotly.newPlot(gd, [3022 { type: 'ohlc', x: [6], open: [6], high: [6], low: [6], close: [6] },3023 { type: 'candlestick', x: [7], open: [7], high: [7], low: [7], close: [7] },3024 ], {3025 dragmode: 'select',3026 width: 500,3027 height: 500,3028 margin: {l: 10, t: 10, r: 10, b: 10},3029 showlegend: false3030 })3031 .then(function() {3032 _assert('base', [1, 1]);3033 })3034 .then(function() {3035 resetEvents(gd);3036 drag([[20, 20], [40, 40]]);3037 return selectedPromise;3038 })3039 .then(function() {3040 _assert('after empty selection', [0.3, 0.3]);3041 })3042 .then(function() { return doubleClick(200, 200); })3043 .then(function() {3044 _assert('after double-click reset', [1, 1]);3045 })3046 .then(done, done.fail);3047 });3048});3049// to make sure none of the above tests fail with extraneous invisible traces,3050// add a bunch of them here3051function addInvisible(fig, canHaveLegend) {3052 var data = fig.data;3053 var inputData = Lib.extendDeep([], data);3054 for(var i = 0; i < inputData.length; i++) {3055 data.push(Lib.extendDeep({}, inputData[i], {visible: false}));3056 if(canHaveLegend !== false) data.push(Lib.extendDeep({}, inputData[i], {visible: 'legendonly'}));3057 }3058 if(inputData.length === 1 && fig.layout.showlegend !== true) fig.layout.showlegend = false;...

Full Screen

Full Screen

runtime-dom.cjs.js

Source:runtime-dom.cjs.js Github

copy

Full Screen

...967 const moveClass = props.moveClass || `${props.name || 'v'}-move`;968 // Check if move transition is needed. This check is cached per-instance.969 hasMove =970 hasMove === null971 ? (hasMove = hasCSSTransform(prevChildren[0].el, instance.vnode.el, moveClass))972 : hasMove;973 if (!hasMove) {974 return;975 }976 // we divide the work into three loops to avoid mixing DOM reads and writes977 // in each iteration - which helps prevent layout thrashing.978 prevChildren.forEach(callPendingCbs);979 prevChildren.forEach(recordPosition);980 const movedChildren = prevChildren.filter(applyTranslation);981 // force reflow to put everything in position982 forceReflow();983 movedChildren.forEach(c => {984 const el = c.el;985 const style = el.style;986 addTransitionClass(el, moveClass);987 style.transform = style.WebkitTransform = style.transitionDuration = '';988 const cb = (el._moveCb = (e) => {989 if (e && e.target !== el) {990 return;991 }992 if (!e || /transform$/.test(e.propertyName)) {993 el.removeEventListener('transitionend', cb);994 el._moveCb = null;995 removeTransitionClass(el, moveClass);996 }997 });998 el.addEventListener('transitionend', cb);999 });1000 });1001 return () => {1002 const rawProps = runtimeCore.toRaw(props);1003 const cssTransitionProps = resolveTransitionProps(rawProps);1004 const tag = rawProps.tag || runtimeCore.Fragment;1005 prevChildren = children;1006 children = slots.default ? slots.default() : [];1007 // handle fragment children case, e.g. v-for1008 if (children.length === 1 && children[0].type === runtimeCore.Fragment) {1009 children = children[0].children;1010 }1011 for (let i = 0; i < children.length; i++) {1012 const child = children[i];1013 if (child.key != null) {1014 runtimeCore.setTransitionHooks(child, runtimeCore.resolveTransitionHooks(child, cssTransitionProps, state, instance));1015 }1016 else {1017 runtimeCore.warn(`<TransitionGroup> children must be keyed.`);1018 }1019 }1020 if (prevChildren) {1021 for (let i = 0; i < prevChildren.length; i++) {1022 const child = prevChildren[i];1023 runtimeCore.setTransitionHooks(child, runtimeCore.resolveTransitionHooks(child, cssTransitionProps, state, instance));1024 positionMap.set(child, child.el.getBoundingClientRect());1025 }1026 }1027 return runtimeCore.createVNode(tag, null, children);1028 };1029 }1030};1031const TransitionGroup = TransitionGroupImpl;1032{1033 const props = (TransitionGroup.props = {1034 ...TransitionPropsValidators,1035 tag: String,1036 moveClass: String1037 });1038 delete props.mode;1039}1040function callPendingCbs(c) {1041 if (c.el._moveCb) {1042 c.el._moveCb();1043 }1044 if (c.el._enterCb) {1045 c.el._enterCb();1046 }1047}1048function recordPosition(c) {1049 newPositionMap.set(c, c.el.getBoundingClientRect());1050}1051function applyTranslation(c) {1052 const oldPos = positionMap.get(c);1053 const newPos = newPositionMap.get(c);1054 const dx = oldPos.left - newPos.left;1055 const dy = oldPos.top - newPos.top;1056 if (dx || dy) {1057 const s = c.el.style;1058 s.transform = s.WebkitTransform = `translate(${dx}px,${dy}px)`;1059 s.transitionDuration = '0s';1060 return c;1061 }1062}1063// this is put in a dedicated function to avoid the line from being treeshaken1064function forceReflow() {1065 return document.body.offsetHeight;1066}1067function hasCSSTransform(el, root, moveClass) {1068 // Detect whether an element with the move class applied has1069 // CSS transitions. Since the element may be inside an entering1070 // transition at this very moment, we make a clone of it and remove1071 // all other transition classes applied to ensure only the move class1072 // is applied.1073 const clone = el.cloneNode();1074 if (el._vtc) {1075 el._vtc.forEach(cls => {1076 cls.split(/\s+/).forEach(c => c && clone.classList.remove(c));1077 });1078 }1079 moveClass.split(/\s+/).forEach(c => c && clone.classList.add(c));1080 clone.style.display = 'none';1081 const container = (root.nodeType === 1 ...

Full Screen

Full Screen

runtime-dom.esm-bundler.js

Source:runtime-dom.esm-bundler.js Github

copy

Full Screen

...600 const moveClass = props.moveClass || `${props.name || 'v'}-move`;601 // Check if move transition is needed. This check is cached per-instance.602 hasMove =603 hasMove === null604 ? (hasMove = hasCSSTransform(prevChildren[0].el, instance.vnode.el, moveClass))605 : hasMove;606 if (!hasMove) {607 return;608 }609 // we divide the work into three loops to avoid mixing DOM reads and writes610 // in each iteration - which helps prevent layout thrashing.611 prevChildren.forEach(callPendingCbs);612 prevChildren.forEach(recordPosition);613 const movedChildren = prevChildren.filter(applyTranslation);614 // force reflow to put everything in position615 forceReflow();616 movedChildren.forEach(c => {617 const el = c.el;618 const style = el.style;619 addTransitionClass(el, moveClass);620 style.transform = style.webkitTransform = style.transitionDuration = '';621 const cb = (el._moveCb = (e) => {622 if (e && e.target !== el) {623 return;624 }625 if (!e || /transform$/.test(e.propertyName)) {626 el.removeEventListener('transitionend', cb);627 el._moveCb = null;628 removeTransitionClass(el, moveClass);629 }630 });631 el.addEventListener('transitionend', cb);632 });633 });634 return () => {635 const rawProps = toRaw(props);636 const cssTransitionProps = resolveTransitionProps(rawProps);637 const tag = rawProps.tag || Fragment;638 prevChildren = children;639 children = getTransitionRawChildren(slots.default ? slots.default() : []);640 for (let i = 0; i < children.length; i++) {641 const child = children[i];642 if (child.key != null) {643 setTransitionHooks(child, resolveTransitionHooks(child, cssTransitionProps, state, instance));644 }645 else if ((process.env.NODE_ENV !== 'production') && child.type !== Comment) {646 warn(`<TransitionGroup> children must be keyed.`);647 }648 }649 if (prevChildren) {650 for (let i = 0; i < prevChildren.length; i++) {651 const child = prevChildren[i];652 setTransitionHooks(child, resolveTransitionHooks(child, cssTransitionProps, state, instance));653 positionMap.set(child, child.el.getBoundingClientRect());654 }655 }656 return createVNode(tag, null, children);657 };658 }659};660function getTransitionRawChildren(children) {661 let ret = [];662 for (let i = 0; i < children.length; i++) {663 const child = children[i];664 // handle fragment children case, e.g. v-for665 if (child.type === Fragment) {666 ret = ret.concat(getTransitionRawChildren(child.children));667 }668 else {669 ret.push(child);670 }671 }672 return ret;673}674// remove mode props as TransitionGroup doesn't support it675delete TransitionGroupImpl.props.mode;676const TransitionGroup = TransitionGroupImpl;677function callPendingCbs(c) {678 const el = c.el;679 if (el._moveCb) {680 el._moveCb();681 }682 if (el._enterCb) {683 el._enterCb();684 }685}686function recordPosition(c) {687 newPositionMap.set(c, c.el.getBoundingClientRect());688}689function applyTranslation(c) {690 const oldPos = positionMap.get(c);691 const newPos = newPositionMap.get(c);692 const dx = oldPos.left - newPos.left;693 const dy = oldPos.top - newPos.top;694 if (dx || dy) {695 const s = c.el.style;696 s.transform = s.webkitTransform = `translate(${dx}px,${dy}px)`;697 s.transitionDuration = '0s';698 return c;699 }700}701// this is put in a dedicated function to avoid the line from being treeshaken702function forceReflow() {703 return document.body.offsetHeight;704}705function hasCSSTransform(el, root, moveClass) {706 // Detect whether an element with the move class applied has707 // CSS transitions. Since the element may be inside an entering708 // transition at this very moment, we make a clone of it and remove709 // all other transition classes applied to ensure only the move class710 // is applied.711 const clone = el.cloneNode();712 if (el._vtc) {713 el._vtc.forEach(cls => {714 cls.split(/\s+/).forEach(c => c && clone.classList.remove(c));715 });716 }717 moveClass.split(/\s+/).forEach(c => c && clone.classList.add(c));718 clone.style.display = 'none';719 const container = (root.nodeType === 1 ...

Full Screen

Full Screen

runtime-dom.cjs.prod.js

Source:runtime-dom.cjs.prod.js Github

copy

Full Screen

...925 const moveClass = props.moveClass || `${props.name || 'v'}-move`;926 // Check if move transition is needed. This check is cached per-instance.927 hasMove =928 hasMove === null929 ? (hasMove = hasCSSTransform(prevChildren[0].el, instance.vnode.el, moveClass))930 : hasMove;931 if (!hasMove) {932 return;933 }934 // we divide the work into three loops to avoid mixing DOM reads and writes935 // in each iteration - which helps prevent layout thrashing.936 prevChildren.forEach(callPendingCbs);937 prevChildren.forEach(recordPosition);938 const movedChildren = prevChildren.filter(applyTranslation);939 // force reflow to put everything in position940 forceReflow();941 movedChildren.forEach(c => {942 const el = c.el;943 const style = el.style;944 addTransitionClass(el, moveClass);945 style.transform = style.WebkitTransform = style.transitionDuration = '';946 const cb = (el._moveCb = (e) => {947 if (e && e.target !== el) {948 return;949 }950 if (!e || /transform$/.test(e.propertyName)) {951 el.removeEventListener('transitionend', cb);952 el._moveCb = null;953 removeTransitionClass(el, moveClass);954 }955 });956 el.addEventListener('transitionend', cb);957 });958 });959 return () => {960 const rawProps = runtimeCore.toRaw(props);961 const cssTransitionProps = resolveTransitionProps(rawProps);962 const tag = rawProps.tag || runtimeCore.Fragment;963 prevChildren = children;964 children = slots.default ? slots.default() : [];965 // handle fragment children case, e.g. v-for966 if (children.length === 1 && children[0].type === runtimeCore.Fragment) {967 children = children[0].children;968 }969 for (let i = 0; i < children.length; i++) {970 const child = children[i];971 if (child.key != null) {972 runtimeCore.setTransitionHooks(child, runtimeCore.resolveTransitionHooks(child, cssTransitionProps, state, instance));973 }974 }975 if (prevChildren) {976 for (let i = 0; i < prevChildren.length; i++) {977 const child = prevChildren[i];978 runtimeCore.setTransitionHooks(child, runtimeCore.resolveTransitionHooks(child, cssTransitionProps, state, instance));979 positionMap.set(child, child.el.getBoundingClientRect());980 }981 }982 return runtimeCore.createVNode(tag, null, children);983 };984 }985};986const TransitionGroup = TransitionGroupImpl;987function callPendingCbs(c) {988 if (c.el._moveCb) {989 c.el._moveCb();990 }991 if (c.el._enterCb) {992 c.el._enterCb();993 }994}995function recordPosition(c) {996 newPositionMap.set(c, c.el.getBoundingClientRect());997}998function applyTranslation(c) {999 const oldPos = positionMap.get(c);1000 const newPos = newPositionMap.get(c);1001 const dx = oldPos.left - newPos.left;1002 const dy = oldPos.top - newPos.top;1003 if (dx || dy) {1004 const s = c.el.style;1005 s.transform = s.WebkitTransform = `translate(${dx}px,${dy}px)`;1006 s.transitionDuration = '0s';1007 return c;1008 }1009}1010// this is put in a dedicated function to avoid the line from being treeshaken1011function forceReflow() {1012 return document.body.offsetHeight;1013}1014function hasCSSTransform(el, root, moveClass) {1015 // Detect whether an element with the move class applied has1016 // CSS transitions. Since the element may be inside an entering1017 // transition at this very moment, we make a clone of it and remove1018 // all other transition classes applied to ensure only the move class1019 // is applied.1020 const clone = el.cloneNode();1021 if (el._vtc) {1022 el._vtc.forEach(cls => {1023 cls.split(/\s+/).forEach(c => c && clone.classList.remove(c));1024 });1025 }1026 moveClass.split(/\s+/).forEach(c => c && clone.classList.add(c));1027 clone.style.display = 'none';1028 const container = (root.nodeType === 1 ...

Full Screen

Full Screen

choroplethmapbox_test.js

Source:choroplethmapbox_test.js Github

copy

Full Screen

1var Plotly = require('@lib/index');2var Plots = require('@src/plots/plots');3var Lib = require('@src/lib');4var loggers = require('@src/lib/loggers');5var convertModule = require('@src/traces/choroplethmapbox/convert');6var MAPBOX_ACCESS_TOKEN = require('@build/credentials.json').MAPBOX_ACCESS_TOKEN;7var createGraphDiv = require('../assets/create_graph_div');8var destroyGraphDiv = require('../assets/destroy_graph_div');9var failTest = require('../assets/fail_test');10var mouseEvent = require('../assets/mouse_event');11var supplyAllDefaults = require('../assets/supply_defaults');12var assertHoverLabelContent = require('../assets/custom_assertions').assertHoverLabelContent;13describe('Test choroplethmapbox defaults:', function() {14 var gd;15 var fullData;16 function _supply(opts, layout) {17 gd = {};18 opts = Array.isArray(opts) ? opts : [opts];19 gd.data = opts.map(function(o) {20 return Lib.extendFlat({type: 'choroplethmapbox'}, o || {});21 });22 gd.layout = layout || {};23 supplyAllDefaults(gd);24 fullData = gd._fullData;25 }26 function expectVisibleFalse(msg) {27 fullData.forEach(function(trace, i) {28 expect(trace.visible).toBe(false, 'visible |trace #' + i + '- ' + msg);29 expect(trace._length).toBe(undefined, '_length |trace #' + i + '- ' + msg);30 });31 }32 it('should set *visible:false* when locations or z or geojson is missing', function() {33 _supply([34 {z: [1], geojson: 'url'},35 {locations: ['a'], geojson: 'url'},36 {locations: ['a'], z: [1]}37 ]);38 expectVisibleFalse();39 });40 it('should set *visible:false* when locations or z is empty', function() {41 _supply([42 {locations: [], z: [1], geojson: 'url'},43 {locations: ['a'], z: [], geojson: 'url'},44 {locations: [], z: [], geojson: 'url'}45 ]);46 expectVisibleFalse();47 });48 it('should accept string (URL) and object *geojson*', function() {49 _supply([50 {name: 'ok during defaults, will fail later', locations: ['a'], z: [1], geojson: 'url'},51 {name: 'ok during defaults, will fail later', locations: ['a'], z: [1], geojson: {}},52 ]);53 fullData.forEach(function(trace, i) {54 expect(trace.visible).toBe(true, 'visible |trace #' + i);55 expect(trace._length).toBe(1, '_length |trace #' + i);56 });57 _supply([58 {name: 'no', locations: ['a'], z: [1], geojson: ''},59 {name: 'no', locations: ['a'], z: [1], geojson: []},60 {name: 'no', locations: ['a'], z: [1], geojson: true}61 ]);62 expectVisibleFalse();63 });64 it('should not coerce *marker.line.color* when *marker.line.width* is *0*', function() {65 _supply([{66 locations: ['CAN', 'USA'],67 z: [1, 2],68 geojson: 'url',69 marker: {70 line: {71 color: 'red',72 width: 073 }74 }75 }]);76 expect(fullData[0].marker.line.width).toBe(0, 'mlw');77 expect(fullData[0].marker.line.color).toBe(undefined, 'mlc');78 });79});80describe('Test choroplethmapbox convert:', function() {81 var geojson0 = function() {82 return {83 type: 'FeatureCollection',84 features: [85 {type: 'Feature', id: 'a', geometry: {type: 'Polygon', coordinates: []}},86 {type: 'Feature', id: 'b', geometry: {type: 'Polygon', coordinates: []}},87 {type: 'Feature', id: 'c', geometry: {type: 'Polygon', coordinates: []}}88 ]89 };90 };91 var base = function() {92 return {93 locations: ['a', 'b', 'c'],94 z: [10, 20, 5],95 geojson: geojson0()96 };97 };98 function pre(trace, layout) {99 var gd = {data: [Lib.extendFlat({type: 'choroplethmapbox'}, trace)]};100 if(layout) gd.layout = layout;101 supplyAllDefaults(gd);102 Plots.doCalcdata(gd, gd._fullData[0]);103 return gd.calcdata[0];104 }105 function _convert(trace) {106 return convertModule.convert(pre(trace));107 }108 function expectBlank(opts, msg) {109 expect(opts.fill.layout.visibility).toBe('none', msg);110 expect(opts.line.layout.visibility).toBe('none', msg);111 expect(opts.geojson).toEqual({type: 'Point', coordinates: []}, msg);112 }113 function extract(opts, k) {114 return opts.geojson.features.map(function(f) { return f.properties[k]; });115 }116 it('should return early when trace is *visible:false*', function() {117 var opts = _convert(Lib.extendFlat(base(), {visible: false}));118 expectBlank(opts);119 });120 it('should return early when trace is has no *_length*', function() {121 var opts = _convert({122 locations: [],123 z: [],124 geojson: geojson0125 });126 expectBlank(opts);127 });128 it('should return early if something goes wrong while fetching a GeoJSON', function() {129 spyOn(loggers, 'error');130 var opts = _convert({131 locations: ['a'], z: [1],132 geojson: 'url'133 });134 expect(loggers.error).toHaveBeenCalledWith('Oops ... something went wrong when fetching url');135 expectBlank(opts);136 });137 describe('should warn when set GeoJSON is not a *FeatureCollection* or a *Feature* type and return early', function() {138 beforeEach(function() { spyOn(loggers, 'warn'); });139 it('- case missing *type* key', function() {140 var opts = _convert({141 locations: ['a'], z: [1],142 geojson: {143 missingType: ''144 }145 });146 expectBlank(opts);147 expect(loggers.warn).toHaveBeenCalledWith([148 'Invalid GeoJSON type none.',149 'Traces with locationmode *geojson-id* only support *FeatureCollection* and *Feature* types.'150 ].join(' '));151 });152 it('- case invalid *type*', function() {153 var opts = _convert({154 locations: ['a'], z: [1],155 geojson: {156 type: 'nop!'157 }158 });159 expectBlank(opts);160 expect(loggers.warn).toHaveBeenCalledWith([161 'Invalid GeoJSON type nop!.',162 'Traces with locationmode *geojson-id* only support *FeatureCollection* and *Feature* types.'163 ].join(' '));164 });165 });166 describe('should log when crossing a GeoJSON geometry that is not a *Polygon* or a *MultiPolygon* type', function() {167 beforeEach(function() { spyOn(loggers, 'log'); });168 it('- case missing geometry *type*', function() {169 var trace = base();170 delete trace.geojson.features[1].geometry.type;171 var opts = _convert(trace);172 expect(opts.geojson.features.length).toBe(2, '# of feature to be rendered');173 expect(loggers.log).toHaveBeenCalledWith([174 'Location b does not have a valid GeoJSON geometry.',175 'Traces with locationmode *geojson-id* only support *Polygon* and *MultiPolygon* geometries.'176 ].join(' '));177 });178 it('- case invalid geometry *type*', function() {179 var trace = base();180 trace.geojson.features[2].geometry.type = 'not-gonna-work';181 var opts = _convert(trace);182 expect(opts.geojson.features.length).toBe(2, '# of feature to be rendered');183 expect(loggers.log).toHaveBeenCalledWith([184 'Location c does not have a valid GeoJSON geometry.',185 'Traces with locationmode *geojson-id* only support *Polygon* and *MultiPolygon* geometries.'186 ].join(' '));187 });188 });189 it('should log when an entry set in *locations* does not a matching feature in the GeoJSON', function() {190 spyOn(loggers, 'log');191 var trace = base();192 trace.locations = ['a', 'b', 'c', 'd'];193 trace.z = [1, 2, 3, 1];194 var opts = _convert(trace);195 expect(opts.geojson.features.length).toBe(3, '# of features to be rendered');196 expect(loggers.log).toHaveBeenCalledWith('Location *d* does not have a matching feature with id-key *id*.');197 });198 describe('should accept numbers as *locations* items', function() {199 function _assert(act) {200 expect(act.fill.layout.visibility).toBe('visible', 'fill layer visibility');201 expect(act.line.layout.visibility).toBe('visible', 'line layer visibility');202 expect(act.geojson.features.length).toBe(3, '# of visible features');203 expect(extract(act, 'fc'))204 .toEqual(['rgb(178, 10, 28)', 'rgb(220, 220, 220)', 'rgb(240, 149, 99)']);205 }206 it('- regular array case', function() {207 var trace = {208 locations: [1, 2, 3],209 z: [20, 10, 2],210 geojson: {211 type: 'FeatureCollection',212 features: [213 {type: 'Feature', id: '1', geometry: {type: 'Polygon', coordinates: []}},214 {type: 'Feature', id: '3', geometry: {type: 'Polygon', coordinates: []}},215 {type: 'Feature', id: '2', geometry: {type: 'Polygon', coordinates: []}}216 ]217 }218 };219 _assert(_convert(trace));220 });221 it('- typed array case', function() {222 var trace = {223 locations: new Float32Array([1, 2, 3]),224 z: new Float32Array([20, 10, 2]),225 geojson: {226 type: 'FeatureCollection',227 features: [228 {type: 'Feature', id: 1, geometry: {type: 'Polygon', coordinates: []}},229 {type: 'Feature', id: 3, geometry: {type: 'Polygon', coordinates: []}},230 {type: 'Feature', id: 2, geometry: {type: 'Polygon', coordinates: []}}231 ]232 }233 };234 _assert(_convert(trace));235 });236 });237 it('should handle *Feature* on 1-item *FeatureCollection* the same way', function() {238 var locations = ['a'];239 var z = [1];240 var feature = {241 type: 'Feature',242 id: 'a',243 geometry: {type: 'Polygon', coordinates: []}244 };245 var opts = _convert({246 locations: locations,247 z: z,248 geojson: feature249 });250 var opts2 = _convert({251 locations: locations,252 z: z,253 geojson: {254 type: 'FeatureCollection',255 features: [feature]256 }257 });258 expect(opts).toEqual(opts2);259 });260 it('should fill stuff in corresponding calcdata items', function() {261 var calcTrace = pre(base());262 var opts = convertModule.convert(calcTrace);263 var fullTrace = calcTrace[0].trace;264 expect(fullTrace._opts).toBe(opts, 'opts ref');265 for(var i = 0; i < calcTrace.length; i++) {266 var cdi = calcTrace[i];267 expect(typeof cdi._polygons).toBe('object', '_polygons |' + i);268 expect(Array.isArray(cdi.ct)).toBe(true, 'ct|' + i);269 expect(typeof cdi.fIn).toBe('object', 'fIn |' + i);270 expect(typeof cdi.fOut).toBe('object', 'fOut |' + i);271 }272 });273 describe('should fill *fill-color* correctly', function() {274 function _assert(act, exp) {275 expect(act.fill.paint['fill-color'])276 .toEqual({type: 'identity', property: 'fc'});277 expect(extract(act, 'fc')).toEqual(exp);278 }279 it('- base case', function() {280 _assert(_convert(base()), [281 'rgb(245, 172, 122)',282 'rgb(178, 10, 28)',283 'rgb(220, 220, 220)'284 ]);285 });286 it('- custom colorscale case', function() {287 var trace = base();288 trace.colorscale = [[0, 'rgb(0, 255, 0)'], [1, 'rgb(0, 0, 255)']];289 trace.zmid = 10;290 _assert(_convert(trace), [291 'rgb(0, 128, 128)',292 'rgb(0, 0, 255)',293 'rgb(0, 191, 64)'294 ]);295 });296 });297 describe('should fill *fill-opacity* correctly', function() {298 function _assertScalar(act, exp) {299 expect(act.fill.paint['fill-opacity']).toBe(exp);300 expect(act.line.paint['line-opacity']).toBe(exp);301 expect(extract(act, 'mo')).toEqual([undefined, undefined, undefined]);302 }303 function _assertArray(act, k, exp) {304 expect(act.fill.paint['fill-opacity']).toEqual({type: 'identity', property: k});305 expect(act.line.paint['line-opacity']).toEqual({type: 'identity', property: k});306 expect(extract(act, k)).toBeCloseToArray(exp, 2);307 }308 function fakeSelect(calcTrace, selectedpoints) {309 if(selectedpoints === null) {310 delete calcTrace[0].trace.selectedpoints;311 } else {312 calcTrace[0].trace.selectedpoints = selectedpoints;313 }314 for(var i = 0; i < calcTrace.length; i++) {315 var cdi = calcTrace[i];316 if(selectedpoints) {317 if(selectedpoints.indexOf(i) !== -1) {318 cdi.selected = 1;319 } else {320 cdi.selected = 0;321 }322 } else {323 delete cdi.selected;324 }325 }326 }327 it('- base case', function() {328 var trace = base();329 trace.marker = {opacity: 0.4};330 _assertScalar(_convert(trace), 0.4);331 });332 it('- arrayOk case', function() {333 var trace = base();334 trace.marker = {opacity: [null, 0.2, -10]};335 _assertArray(_convert(trace), 'mo', [0, 0.2, 0]);336 });337 it('- arrayOk case + bad coordinates', function() {338 var trace = base();339 trace.locations = ['a', null, 'c'];340 trace.marker = {opacity: [-1, 0.2, 0.9]};341 _assertArray(_convert(trace), 'mo', [0, 0.9]);342 });343 it('- selection (base)', function() {344 var trace = base();345 trace.selectedpoints = [1];346 var calcTrace = pre(trace);347 _assertArray(convertModule.convert(calcTrace), 'mo2', [0.2, 1, 0.2]);348 fakeSelect(calcTrace, [1, 2]);349 _assertArray(convertModule.convertOnSelect(calcTrace), 'mo2', [0.2, 1, 1]);350 fakeSelect(calcTrace, []);351 _assertArray(convertModule.convertOnSelect(calcTrace), 'mo2', [0.2, 0.2, 0.2]);352 calcTrace[0].trace.unselected = {marker: {opacity: 0}};353 _assertArray(convertModule.convertOnSelect(calcTrace), 'mo2', [0, 0, 0]);354 fakeSelect(calcTrace, null);355 _assertScalar(convertModule.convertOnSelect(calcTrace), 1);356 });357 it('- selection of arrayOk marker.opacity', function() {358 var trace = base();359 trace.marker = {opacity: [0.4, 1, 0.8]};360 trace.selectedpoints = [1];361 var calcTrace = pre(trace);362 _assertArray(convertModule.convert(calcTrace), 'mo2', [0.08, 1, 0.16]);363 fakeSelect(calcTrace, [1, 2]);364 _assertArray(convertModule.convertOnSelect(calcTrace), 'mo2', [0.08, 1, 0.8]);365 calcTrace[0].trace.selected = {marker: {opacity: 1}};366 _assertArray(convertModule.convertOnSelect(calcTrace), 'mo2', [0.08, 1, 1]);367 fakeSelect(calcTrace, []);368 _assertArray(convertModule.convertOnSelect(calcTrace), 'mo2', [0.08, 0.2, 0.16]);369 calcTrace[0].trace.unselected = {marker: {opacity: 0}};370 _assertArray(convertModule.convertOnSelect(calcTrace), 'mo2', [0, 0, 0]);371 fakeSelect(calcTrace, null);372 _assertArray(convertModule.convertOnSelect(calcTrace), 'mo', [0.4, 1, 0.8]);373 });374 });375 describe('should fill *line-color*, *line-width* correctly', function() {376 it('- base case', function() {377 var trace = base();378 trace.marker = {line: {color: 'blue', width: 3}};379 var opts = _convert(trace);380 expect(opts.line.paint['line-color']).toBe('blue');381 expect(opts.line.paint['line-width']).toBe(3);382 expect(extract(opts, 'mlc')).toEqual([undefined, undefined, undefined]);383 expect(extract(opts, 'mlw')).toEqual([undefined, undefined, undefined]);384 });385 it('- arrayOk case', function() {386 var trace = base();387 trace.marker = {388 line: {389 color: ['blue', 'red', 'black'],390 width: [0.1, 2, 10]391 }392 };393 var opts = _convert(trace);394 expect(opts.line.paint['line-color']).toEqual({type: 'identity', property: 'mlc'});395 expect(opts.line.paint['line-width']).toEqual({type: 'identity', property: 'mlw'});396 expect(extract(opts, 'mlc')).toEqual(['blue', 'red', 'black']);397 expect(extract(opts, 'mlw')).toEqual([0.1, 2, 10]);398 });399 });400 it('should find correct centroid (single polygon case)', function() {401 var trace = base();402 var coordsIn = [403 [404 [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],405 [100.0, 1.0], [100.0, 0.0]406 ]407 ];408 trace.geojson.features[0].geometry.coordinates = coordsIn;409 var calcTrace = pre(trace);410 var opts = convertModule.convert(calcTrace);411 expect(opts.geojson.features[0].geometry.coordinates).toBe(coordsIn);412 expect(calcTrace[0].ct).toEqual([100.4, 0.4]);413 });414 it('should find correct centroid (multi-polygon case)', function() {415 var trace = base();416 var coordsIn = [417 [418 // this one has the bigger area419 [[30, 20], [45, 40], [10, 40], [30, 20]]420 ],421 [422 [[15, 5], [40, 10], [10, 20], [5, 10], [15, 5]]423 ]424 ];425 trace.geojson.features[0].geometry.type = 'MultiPolygon';426 trace.geojson.features[0].geometry.coordinates = coordsIn;427 var calcTrace = pre(trace);428 var opts = convertModule.convert(calcTrace);429 expect(opts.geojson.features[0].geometry.coordinates).toBe(coordsIn);430 expect(calcTrace[0].ct).toEqual([28.75, 30]);431 });432});433describe('Test choroplethmapbox hover:', function() {434 var gd;435 afterEach(function(done) {436 Plotly.purge(gd);437 destroyGraphDiv();438 setTimeout(done, 200);439 });440 function transformPlot(gd, transformString) {441 gd.style.webkitTransform = transformString;442 gd.style.MozTransform = transformString;443 gd.style.msTransform = transformString;444 gd.style.OTransform = transformString;445 gd.style.transform = transformString;446 }447 function run(hasCssTransform, s, done) {448 gd = createGraphDiv();449 var scale = 1;450 if(hasCssTransform) {451 scale = 0.5;452 }453 var fig = Lib.extendDeep({},454 s.mock || require('@mocks/mapbox_choropleth0.json')455 );456 if(s.patch) {457 fig = s.patch(fig);458 }459 if(!fig.layout) fig.layout = {};460 if(!fig.layout.mapbox) fig.layout.mapbox = {};461 fig.layout.mapbox.accesstoken = MAPBOX_ACCESS_TOKEN;462 var pos = s.pos || [270, 220];463 return Plotly.newPlot(gd, fig).then(function() {464 if(hasCssTransform) transformPlot(gd, 'translate(-25%, -25%) scale(0.5)');465 var to = setTimeout(function() {466 failTest('no event data received');467 done();468 }, 100);469 gd.on('plotly_hover', function(d) {470 clearTimeout(to);471 assertHoverLabelContent(s);472 var msg = ' - event data ' + s.desc;473 var actual = d.points || [];474 var exp = s.evtPts;475 expect(actual.length).toBe(exp.length, 'pt length' + msg);476 for(var i = 0; i < exp.length; i++) {477 for(var k in exp[i]) {478 var m = 'key ' + k + ' in pt ' + i + msg;479 var matcher = k === 'properties' ? 'toEqual' : 'toBe';480 expect(actual[i][k])[matcher](exp[i][k], m);481 }482 }483 // w/o this purge gets called before484 // hover throttle is complete485 setTimeout(done, 0);486 });487 mouseEvent('mousemove', scale * pos[0], scale * pos[1]);488 })489 .catch(failTest);490 }491 var specs = [{492 desc: 'basic',493 nums: '10',494 name: 'NY',495 evtPts: [{location: 'NY', z: 10, pointNumber: 0, curveNumber: 0, properties: {name: 'New York'}}]496 }, {497 desc: 'with a hovertemplate using values in *properties*',498 patch: function(fig) {499 fig.data.forEach(function(t) {500 t.hovertemplate = '%{z:.3f}<extra>PROP::%{properties.name}</extra>';501 });502 return fig;503 },504 nums: '10.000',505 name: 'PROP::New York',506 evtPts: [{location: 'NY', z: 10, pointNumber: 0, curveNumber: 0, properties: {name: 'New York'}}]507 }, {508 desc: 'with "typeof number" locations[i] and feature id (in *name* label case)',509 patch: function() {510 var fig = Lib.extendDeep({}, require('@mocks/mapbox_choropleth-raw-geojson.json'));511 fig.data = [fig.data[1]];512 fig.data[0].locations = [100];513 fig.data[0].geojson.id = 100;514 return fig;515 },516 nums: '10',517 name: '100',518 evtPts: [{location: 100, z: 10, pointNumber: 0, curveNumber: 0}]519 }, {520 desc: 'with "typeof number" locations[i] and feature id (in *nums* label case)',521 patch: function() {522 var fig = Lib.extendDeep({}, require('@mocks/mapbox_choropleth-raw-geojson.json'));523 fig.data = [fig.data[1]];524 fig.data[0].locations = [100];525 fig.data[0].geojson.id = 100;526 fig.data[0].hoverinfo = 'location+name';527 return fig;528 },529 nums: '100',530 name: 'trace 0',531 evtPts: [{location: 100, z: 10, pointNumber: 0, curveNumber: 0}]532 }, {533 desc: 'with "typeof number" locations[i] and feature id (hovertemplate case)',534 patch: function() {535 var fig = Lib.extendDeep({}, require('@mocks/mapbox_choropleth-raw-geojson.json'));536 fig.data = [fig.data[1]];537 fig.data[0].locations = [100];538 fig.data[0].geojson.id = 100;539 fig.data[0].hovertemplate = '### %{location}<extra>%{ct[0]:.1f} | %{ct[1]:.1f} ###</extra>';540 return fig;541 },542 nums: '### 100',543 name: '-86.7 | 32.0 ###',544 evtPts: [{location: 100, z: 10, pointNumber: 0, curveNumber: 0}]545 }];546 specs.forEach(function(s) {547 [false, true].forEach(function(hasCssTransform) {548 it('@gl should generate correct hover labels ' + s.desc + ', hasCssTransform: ' + hasCssTransform, function(done) {549 run(hasCssTransform, s, done);550 });551 });552 });553});554describe('Test choroplethmapbox interactions:', function() {555 var gd;556 var geojson = {557 type: 'Feature',558 id: 'AL',559 geometry: {560 type: 'Polygon',561 coordinates: [[562 [-87.359296, 35.00118 ], [-85.606675, 34.984749 ], [-85.431413, 34.124869 ], [-85.184951, 32.859696 ],563 [-85.069935, 32.580372 ], [-84.960397, 32.421541 ], [-85.004212, 32.322956 ], [-84.889196, 32.262709 ],564 [-85.058981, 32.13674 ], [-85.053504, 32.01077 ], [-85.141136, 31.840985 ], [-85.042551, 31.539753 ],565 [-85.113751, 31.27686 ], [-85.004212, 31.003013 ], [-85.497137, 30.997536 ], [-87.600282, 30.997536 ],566 [-87.633143, 30.86609 ], [-87.408589, 30.674397 ], [-87.446927, 30.510088 ], [-87.37025, 30.427934 ],567 [-87.518128, 30.280057 ], [-87.655051, 30.247195 ], [-87.90699, 30.411504 ], [-87.934375, 30.657966 ],568 [-88.011052, 30.685351 ], [-88.10416, 30.499135 ], [-88.137022, 30.318396 ], [-88.394438, 30.367688 ],569 [-88.471115, 31.895754 ], [-88.241084, 33.796253 ], [-88.098683, 34.891641 ], [-88.202745, 34.995703 ],570 [-87.359296, 35.00118 ]571 ]]572 }573 };574 beforeEach(function() {575 gd = createGraphDiv();576 });577 afterEach(function(done) {578 Plotly.purge(gd);579 destroyGraphDiv();580 setTimeout(done, 200);581 });582 it('@gl should be able to add and remove traces', function(done) {583 function _assert(msg, exp) {584 var map = gd._fullLayout.mapbox._subplot.map;585 var layers = map.getStyle().layers;586 expect(layers.length).toBe(exp.layerCnt, 'total # of layers |' + msg);587 }588 var trace0 = {589 type: 'choroplethmapbox',590 locations: ['AL'],591 z: [10],592 geojson: geojson593 };594 var trace1 = {595 type: 'choroplethmapbox',596 locations: ['AL'],597 z: [1],598 geojson: geojson,599 marker: {opacity: 0.3}600 };601 Plotly.newPlot(gd,602 [trace0, trace1],603 {mapbox: {style: 'basic'}},604 {mapboxAccessToken: MAPBOX_ACCESS_TOKEN}605 )606 .then(function() {607 _assert('base', { layerCnt: 24 });608 })609 .then(function() { return Plotly.deleteTraces(gd, [0]); })610 .then(function() {611 _assert('w/o trace0', { layerCnt: 22 });612 })613 .then(function() { return Plotly.addTraces(gd, [trace0]); })614 .then(function() {615 _assert('after adding trace0', { layerCnt: 24 });616 })617 .then(done, done.fail);618 });619 it('@gl should be able to restyle *below*', function(done) {620 function getLayerIds() {621 var subplot = gd._fullLayout.mapbox._subplot;622 var layers = subplot.map.getStyle().layers;623 var layerIds = layers.map(function(l) { return l.id; });624 return layerIds;625 }626 Plotly.newPlot(gd, [{627 type: 'choroplethmapbox',628 locations: ['AL'],629 z: [10],630 geojson: geojson,631 uid: 'a'632 }], {}, {mapboxAccessToken: MAPBOX_ACCESS_TOKEN})633 .then(function() {634 expect(getLayerIds()).withContext('default *below*').toEqual([635 'background', 'landuse_overlay_national_park', 'landuse_park',636 'waterway', 'water',637 'plotly-trace-layer-a-fill', 'plotly-trace-layer-a-line',638 'building', 'tunnel_minor', 'tunnel_major', 'road_minor', 'road_major',639 'bridge_minor case', 'bridge_major case', 'bridge_minor', 'bridge_major',640 'admin_country', 'poi_label', 'road_major_label',641 'place_label_other', 'place_label_city', 'country_label'642 ]);643 })644 .then(function() { return Plotly.restyle(gd, 'below', ''); })645 .then(function() {646 expect(getLayerIds()).withContext('*below* set to \'\'').toEqual([647 'background', 'landuse_overlay_national_park', 'landuse_park',648 'waterway', 'water',649 'building', 'tunnel_minor', 'tunnel_major', 'road_minor', 'road_major',650 'bridge_minor case', 'bridge_major case', 'bridge_minor', 'bridge_major',651 'admin_country', 'poi_label', 'road_major_label',652 'place_label_other', 'place_label_city', 'country_label',653 'plotly-trace-layer-a-fill', 'plotly-trace-layer-a-line'654 ]);655 })656 .then(function() { return Plotly.restyle(gd, 'below', 'place_label_other'); })657 .then(function() {658 expect(getLayerIds()).withContext('*below* set to same base layer').toEqual([659 'background', 'landuse_overlay_national_park', 'landuse_park',660 'waterway', 'water',661 'building', 'tunnel_minor', 'tunnel_major', 'road_minor', 'road_major',662 'bridge_minor case', 'bridge_major case', 'bridge_minor', 'bridge_major',663 'admin_country', 'poi_label', 'road_major_label',664 'plotly-trace-layer-a-fill', 'plotly-trace-layer-a-line',665 'place_label_other', 'place_label_city', 'country_label',666 ]);667 })668 .then(function() { return Plotly.restyle(gd, 'below', null); })669 .then(function() {670 expect(getLayerIds()).withContext('back to default *below*').toEqual([671 'background', 'landuse_overlay_national_park', 'landuse_park',672 'waterway', 'water',673 'plotly-trace-layer-a-fill', 'plotly-trace-layer-a-line',674 'building', 'tunnel_minor', 'tunnel_major', 'road_minor', 'road_major',675 'bridge_minor case', 'bridge_major case', 'bridge_minor', 'bridge_major',676 'admin_country', 'poi_label', 'road_major_label',677 'place_label_other', 'place_label_city', 'country_label'678 ]);679 })680 .then(done, done.fail);681 }, 5 * jasmine.DEFAULT_TIMEOUT_INTERVAL);...

Full Screen

Full Screen

choropleth_test.js

Source:choropleth_test.js Github

copy

Full Screen

1var Choropleth = require('@src/traces/choropleth');2var Plotly = require('@lib/index');3var Plots = require('@src/plots/plots');4var Lib = require('@src/lib');5var loggers = require('@src/lib/loggers');6var d3Select = require('../../strict-d3').select;7var d3SelectAll = require('../../strict-d3').selectAll;8var createGraphDiv = require('../assets/create_graph_div');9var destroyGraphDiv = require('../assets/destroy_graph_div');10var mouseEvent = require('../assets/mouse_event');11var customAssertions = require('../assets/custom_assertions');12var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle;13var assertHoverLabelContent = customAssertions.assertHoverLabelContent;14describe('Test choropleth', function() {15 'use strict';16 describe('supplyDefaults', function() {17 var traceIn;18 var traceOut;19 var defaultColor = '#444';20 var layout = {21 font: Plots.layoutAttributes.font,22 _dfltTitle: {colorbar: 'cb'}23 };24 beforeEach(function() {25 traceOut = {};26 });27 it('should set _length based on locations and z but not slice', function() {28 traceIn = {29 locations: ['CAN', 'USA'],30 z: [1, 2, 3]31 };32 Choropleth.supplyDefaults(traceIn, traceOut, defaultColor, layout);33 expect(traceOut.z).toEqual([1, 2, 3]);34 expect(traceOut.locations).toEqual(['CAN', 'USA']);35 expect(traceOut._length).toBe(2);36 traceIn = {37 locations: ['CAN', 'USA', 'ALB'],38 z: [1, 2]39 };40 Choropleth.supplyDefaults(traceIn, traceOut, defaultColor, layout);41 expect(traceOut.z).toEqual([1, 2]);42 expect(traceOut.locations).toEqual(['CAN', 'USA', 'ALB']);43 expect(traceOut._length).toBe(2);44 });45 it('should make trace invisible if locations is not defined', function() {46 traceIn = {47 z: [1, 2, 3]48 };49 Choropleth.supplyDefaults(traceIn, traceOut, defaultColor, layout);50 expect(traceOut.visible).toBe(false);51 });52 it('should make trace invisible if z is not an array', function() {53 traceIn = {54 locations: ['CAN', 'USA'],55 z: 'no gonna work'56 };57 Choropleth.supplyDefaults(traceIn, traceOut, defaultColor, layout);58 expect(traceOut.visible).toBe(false);59 });60 it('should not coerce *marker.line.color* when *marker.line.width* is *0*', function() {61 traceIn = {62 locations: ['CAN', 'USA'],63 z: [1, 2],64 marker: {65 line: {66 color: 'red',67 width: 068 }69 }70 };71 Choropleth.supplyDefaults(traceIn, traceOut, defaultColor, layout);72 expect(traceOut.marker.line.width).toBe(0, 'mlw');73 expect(traceOut.marker.line.color).toBe(undefined, 'mlc');74 });75 it('should default locationmode to *geojson-id* when a valid *geojson* is provided', function() {76 traceIn = {77 locations: ['CAN', 'USA'],78 z: [1, 2],79 geojson: 'url'80 };81 traceOut = {};82 Choropleth.supplyDefaults(traceIn, traceOut, defaultColor, layout);83 expect(traceOut.locationmode).toBe('geojson-id', 'valid url string');84 traceIn = {85 locations: ['CAN', 'USA'],86 z: [1, 2],87 geojson: {}88 };89 traceOut = {};90 Choropleth.supplyDefaults(traceIn, traceOut, defaultColor, layout);91 expect(traceOut.locationmode).toBe('geojson-id', 'valid object');92 traceIn = {93 locations: ['CAN', 'USA'],94 z: [1, 2],95 geojson: ''96 };97 traceOut = {};98 Choropleth.supplyDefaults(traceIn, traceOut, defaultColor, layout);99 expect(traceOut.locationmode).toBe('ISO-3', 'invalid sting');100 traceIn = {101 locations: ['CAN', 'USA'],102 z: [1, 2],103 geojson: []104 };105 traceOut = {};106 Choropleth.supplyDefaults(traceIn, traceOut, defaultColor, layout);107 expect(traceOut.locationmode).toBe('ISO-3', 'invalid object');108 });109 it('should only coerce *featureidkey* when locationmode is *geojson-id', function() {110 traceIn = {111 locations: ['CAN', 'USA'],112 z: [1, 2],113 geojson: 'url',114 featureidkey: 'properties.name'115 };116 traceOut = {};117 Choropleth.supplyDefaults(traceIn, traceOut, defaultColor, layout);118 expect(traceOut.featureidkey).toBe('properties.name', 'coerced');119 traceIn = {120 locations: ['CAN', 'USA'],121 z: [1, 2],122 featureidkey: 'properties.name'123 };124 traceOut = {};125 Choropleth.supplyDefaults(traceIn, traceOut, defaultColor, layout);126 expect(traceOut.featureidkey).toBe(undefined, 'NOT coerced');127 });128 });129});130describe('Test choropleth hover:', function() {131 var gd;132 afterEach(destroyGraphDiv);133 function transformPlot(gd, transformString) {134 gd.style.webkitTransform = transformString;135 gd.style.MozTransform = transformString;136 gd.style.msTransform = transformString;137 gd.style.OTransform = transformString;138 gd.style.transform = transformString;139 }140 function run(hasCssTransform, pos, fig, content, style) {141 gd = createGraphDiv();142 var scale = 1;143 style = style || {144 bgcolor: 'rgb(68, 68, 68)',145 bordercolor: 'rgb(255, 255, 255)',146 fontColor: 'rgb(255, 255, 255)',147 fontSize: 13,148 fontFamily: 'Arial'149 };150 return Plotly.newPlot(gd, fig)151 .then(function() {152 if(hasCssTransform) {153 scale = 0.5;154 transformPlot(gd, 'translate(-25%, -25%) scale(0.5)');155 }156 mouseEvent('mousemove', scale * pos[0], scale * pos[1]);157 assertHoverLabelContent({158 nums: content[0],159 name: content[1]160 });161 assertHoverLabelStyle(162 d3Select('g.hovertext'),163 style164 );165 });166 }167 [false, true].forEach(function(hasCssTransform) {168 it('should generate hover label info (base), hasCssTransform: ' + hasCssTransform, function(done) {169 var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));170 run(171 hasCssTransform,172 [400, 160],173 fig,174 ['RUS\n10', 'trace 1']175 )176 .then(done, done.fail);177 });178 });179 [false, true].forEach(function(hasCssTransform) {180 it('should use the hovertemplate, hasCssTransform: ' + hasCssTransform, function(done) {181 var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));182 fig.data[1].hovertemplate = 'tpl %{z}<extra>x</extra>';183 run(184 hasCssTransform,185 [400, 160],186 fig,187 ['tpl 10', 'x']188 )189 .then(done, done.fail);190 });191 });192 [false, true].forEach(function(hasCssTransform) {193 it('should generate hover label info (\'text\' single value case), hasCssTransform: ' + hasCssTransform, function(done) {194 var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));195 fig.data[1].text = 'tExT';196 fig.data[1].hoverinfo = 'text';197 run(198 hasCssTransform,199 [400, 160],200 fig,201 ['tExT', null]202 )203 .then(done, done.fail);204 });205 });206 [false, true].forEach(function(hasCssTransform) {207 it('should generate hover label info (\'text\' array case), hasCssTransform: ' + hasCssTransform, function(done) {208 var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));209 fig.data[1].text = ['tExT', 'TeXt', '-text-'];210 fig.data[1].hoverinfo = 'text';211 run(212 hasCssTransform,213 [400, 160],214 fig,215 ['-text-', null]216 )217 .then(done, done.fail);218 });219 });220 [false, true].forEach(function(hasCssTransform) {221 it('should generate hover labels from `hovertext`, hasCssTransform: ' + hasCssTransform, function(done) {222 var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));223 fig.data[1].hovertext = ['tExT', 'TeXt', '-text-'];224 fig.data[1].text = ['N', 'O', 'P'];225 fig.data[1].hoverinfo = 'text';226 run(227 hasCssTransform,228 [400, 160],229 fig,230 ['-text-', null]231 )232 .then(done, done.fail);233 });234 });235 [false, true].forEach(function(hasCssTransform) {236 it('should generate hover label with custom styling, hasCssTransform: ' + hasCssTransform, function(done) {237 var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));238 fig.data[1].hoverlabel = {239 bgcolor: 'red',240 bordercolor: ['blue', 'black', 'green'],241 font: {family: 'Roboto'}242 };243 run(244 hasCssTransform,245 [400, 160],246 fig,247 ['RUS\n10', 'trace 1'],248 {249 bgcolor: 'rgb(255, 0, 0)',250 bordercolor: 'rgb(0, 128, 0)',251 fontColor: 'rgb(0, 128, 0)',252 fontSize: 13,253 fontFamily: 'Roboto'254 }255 )256 .then(done, done.fail);257 });258 });259 [false, true].forEach(function(hasCssTransform) {260 it('should generate hover label with arrayOk \'hoverinfo\' settings, hasCssTransform: ' + hasCssTransform, function(done) {261 var fig = Lib.extendDeep({}, require('@mocks/geo_first.json'));262 fig.data[1].hoverinfo = ['location', 'z', 'location+name'];263 run(264 hasCssTransform,265 [400, 160],266 fig,267 ['RUS', 'trace 1']268 )269 .then(done, done.fail);270 });271 });272 describe('should preserve z formatting hovetemplate equivalence', function() {273 var base = function() {274 return {275 data: [{276 type: 'choropleth',277 locations: ['RUS'],278 z: [10.021321321432143]279 }]280 };281 };282 var pos = [400, 160];283 var exp = ['10.02132', 'RUS'];284 [false, true].forEach(function(hasCssTransform) {285 it('- base case (truncate z decimals), hasCssTransform: ' + hasCssTransform, function(done) {286 run(hasCssTransform, pos, base(), exp)287 .then(done, done.fail);288 });289 });290 [false, true].forEach(function(hasCssTransform) {291 it('- hovertemplate case (same z truncation), hasCssTransform: ' + hasCssTransform, function(done) {292 var fig = base();293 fig.hovertemplate = '%{z}<extra>%{location}</extra>';294 run(hasCssTransform, pos, fig, exp)295 .then(done, done.fail);296 });297 });298 });299 [false, true].forEach(function(hasCssTransform) {300 it('should include *properties* from input custom geojson, hasCssTransform: ' + hasCssTransform, function(done) {301 var fig = Lib.extendDeep({}, require('@mocks/geo_custom-geojson.json'));302 fig.data = [fig.data[1]];303 fig.data[0].hovertemplate = '%{properties.name}<extra>%{ct[0]:.1f} | %{ct[1]:.1f}</extra>';304 fig.layout.geo.projection = {scale: 20};305 run(hasCssTransform, [300, 200], fig, ['New York', '-75.1 | 42.6'])306 .then(done, done.fail);307 });308 });309});310describe('choropleth drawing', function() {311 var gd;312 beforeEach(function() {313 gd = createGraphDiv();314 });315 afterEach(destroyGraphDiv);316 it('should not throw an error with bad locations', function(done) {317 spyOn(loggers, 'log');318 Plotly.newPlot(gd, [{319 locations: ['canada', 0, null, '', 'utopia'],320 z: [1, 2, 3, 4, 5],321 locationmode: 'country names',322 type: 'choropleth'323 }])324 .then(function() {325 // only utopia logs - others are silently ignored326 expect(loggers.log).toHaveBeenCalledTimes(1);327 })328 .then(done, done.fail);329 });330 it('preserves order after hide/show', function(done) {331 function getIndices() {332 var out = [];333 d3SelectAll('.choropleth').each(function(d) { out.push(d[0].trace.index); });334 return out;335 }336 Plotly.newPlot(gd, [{337 type: 'choropleth',338 locations: ['CAN', 'USA'],339 z: [1, 2]340 }, {341 type: 'choropleth',342 locations: ['CAN', 'USA'],343 z: [2, 1]344 }])345 .then(function() {346 expect(getIndices()).toEqual([0, 1]);347 return Plotly.restyle(gd, 'visible', false, [0]);348 })349 .then(function() {350 expect(getIndices()).toEqual([1]);351 return Plotly.restyle(gd, 'visible', true, [0]);352 })353 .then(function() {354 expect(getIndices()).toEqual([0, 1]);355 })356 .then(done, done.fail);357 });...

Full Screen

Full Screen

TransitionGroup.js

Source:TransitionGroup.js Github

copy

Full Screen

...36 if (!prevChildren.length) {37 return38 }39 const moveClass = props.moveClass || `${props.name || 'v'}-move`40 if (!hasCSSTransform(prevChildren[0].el, instance.vnode.el, moveClass)) {41 return42 }43 // we divide the work into three loops to avoid mixing DOM reads and writes44 // in each iteration - which helps prevent layout thrashing.45 prevChildren.forEach(callPendingCbs)46 prevChildren.forEach(recordPosition)47 const movedChildren = prevChildren.filter(applyTranslation)48 // force reflow to put everything in position49 forceReflow()50 movedChildren.forEach(c => {51 const el = c.el52 const style = el.style53 addTransitionClass(el, moveClass)54 style.transform = style.webkitTransform = style.transitionDuration = ''...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1const { hasCSSTransform } = require('playwright/lib/server/chromium/crPage');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 const hasTransform = await hasCSSTransform(page, 'body', 'translate(0px, 0px)');8 console.log(`Has transform: ${hasTransform}`);9 await browser.close();10})();11const { hasCSSProperty } = require('playwright/lib/server/chromium/crPage');12const { chromium } = require('playwright');13(async () => {14 const browser = await chromium.launch();15 const context = await browser.newContext();16 const page = await context.newPage();17 const hasTransform = await hasCSSProperty(page, 'body', 'transform', 'translate(0px, 0px)');18 console.log(`Has transform: ${hasTransform}`);19 await browser.close();20})();21const { hasCSSProperty } = require('playwright/lib/server/chromium/crPage');22const { chromium } = require('playwright');23(async () => {24 const browser = await chromium.launch();25 const context = await browser.newContext();26 const page = await context.newPage();27 const hasTransform = await hasCSSProperty(page, 'body', 'transform', 'translate(0px, 0px)');28 console.log(`Has transform: ${hasTransform}`);29 await browser.close();30})();31const { hasCSSProperty } = require('playwright/lib/server/chromium/crPage');32const { chromium } = require('playwright');33(async () => {34 const browser = await chromium.launch();35 const context = await browser.newContext();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { hasCSSTransform } = require('playwright/lib/server/chromium/crPage');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 await page.waitForSelector('text="Get started"');8 const element = await page.$('text="Get started"');9 const result = await hasCSSTransform(element);10 console.log(result);11 await browser.close();12})();13 at CDPSession.send (/home/raghav/Desktop/playwright/node_modules/playwright/lib/server/cjs/webkit/wkConnection.js:41:23)14 at CDPSession.send (/home/raghav/Desktop/playwright/node_modules/playwright/lib/server/cjs/chromium/crConnection.js:65:39)15 at ExecutionContext._evaluateInternal (/home/raghav/Desktop/playwright/node_modules/playwright/lib/server/cjs/common/ExecutionContext.js:132:48)16 at ExecutionContext.evaluateHandle (/home/raghav/Desktop/playwright/node_modules/playwright/lib/server/cjs/common/ExecutionContext.js:69:17)17 at ExecutionContext.evaluate (/home/raghav/Desktop/playwright/node_modules/playwright/lib/server/cjs/common/ExecutionContext.js:56:31)18 at CDPSession.send (/home/raghav/Desktop/playwright/node_modules/playwright/lib/server/cjs/webkit/wkConnection.js:41:23)19 at CDPSession.send (/home/raghav/Desktop/playwright/node_modules/playwright/lib/server/cjs/chromium/crConnection.js:65:39)20 at Page._evaluateInternal (/home/raghav/Desktop/playwright/node_modules/playwright/lib/server/cjs/common/Page.js:171:48)21 at Page.evaluateHandle (/home/raghav/Desktop/playwright/node_modules/playwright/lib/server/cjs/common/Page.js:108:17)

Full Screen

Using AI Code Generation

copy

Full Screen

1const { hasCSSTransform } = require('playwright/lib/server/dom.js');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 const element = await page.$('#iframeResult');8 const frame = await element.contentFrame();9 const div = await frame.$('div');10 const result = await hasCSSTransform(div, 'rotateX(50deg)');11 console.log(result);12 await browser.close();13})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { hasCSSTransform } = require('playwright-core/lib/server/dom.js');2const { chromium } = require('playwright-core');3(async () => {4 const browser = await chromium.launch();5 const page = await browser.newPage();6 const element = await page.$('text=Learn more');7 const result = await hasCSSTransform(element);8 console.log(result);9 await browser.close();10})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { hasCSSTransform } = require('playwright-core/lib/server/dom.js');2const { chromium } = require('playwright-core');3(async () => {4 const browser = await chromium.launch();5 const page = await browser.newPage();6 const element = await page.$('input[title="Search"]');7 const result = await hasCSSTransform(element);8 console.log(result);9 await browser.close();10})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { hasCSSTransform } = require('playwright/lib/server/supplements/recorder/recorderSupplement');2const assert = require('assert');3(async () => {4 const browser = await chromium.launch();5 const page = await browser.newPage();6 const hasTransform = await hasCSSTransform(page, 'input[name="q"]');7 assert.equal(hasTransform, true);8 await browser.close();9})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { hasCSSTransform } = require('playwright/lib/server/supplements/recorder/recorderSupplement');2(async () => {3 const browser = await chromium.launch({headless: false});4 const page = await browser.newPage();5 const element = await page.$('input[name="q"]');6 console.log(await hasCSSTransform(page, element));7 await browser.close();8})();9const { hasCSSTransform } = require('playwright/lib/server/supplements/recorder/recorderSupplement');10(async () => {11 const browser = await chromium.launch({headless: false});12 const page = await browser.newPage();13 const element = await page.$('input[name="q"]');14 await element.evaluate(element => element.style.transform = 'none');15 console.log(await hasCSSTransform(page, element));16 await browser.close();17})();18const { hasCSSTransform } = require('playwright/lib/server/supplements/recorder/recorderSupplement');19(async () => {20 const browser = await chromium.launch({headless: false});21 const page = await browser.newPage();22 const element = await page.$('input[name="q"]');23 await element.evaluate(element => element.style.transform = 'rotate(20deg)');24 console.log(await hasCSSTransform(page, element));25 await browser.close();26})();27const { hasCSSTransform } = require('playwright/lib/server/supplements/recorder/rec

Full Screen

Using AI Code Generation

copy

Full Screen

1const { InternalUtils } = require('playwright/lib/utils/internal-utils');2const { hasCSSTransform } = InternalUtils;3const { chromium } = require('playwright');4(async () => {5 const browser = await chromium.launch();6 const context = await browser.newContext();7 const page = await context.newPage();8 const element = await page.$('input');9 console.log(hasCSSTransform(element));10 await browser.close();11})();12const { InternalUtils } = require('playwright/lib/utils/internal-utils');13const { hasCSSTransform } = InternalUtils;14const { chromium } = require('playwright');15(async () => {16 const browser = await chromium.launch();17 const context = await browser.newContext();18 const page = await context.newPage();19 const element = await page.$('input');20 console.log(hasCSSTransform(element));21 await browser.close();22})();23const { InternalUtils } = require('playwright/lib/utils/internal-utils');24const { hasCSSTransform } = InternalUtils;25const { chromium } = require('playwright');26(async () => {27 const browser = await chromium.launch();28 const context = await browser.newContext();29 const page = await context.newPage();30 const element = await page.$('input');31 console.log(hasCSSTransform(element));32 await browser.close();33})();34const { InternalUtils } = require('playwright/lib/utils/internal-utils');35const { hasCSSTransform } = InternalUtils;36const { chromium } = require('playwright');37(async () => {38 const browser = await chromium.launch();39 const context = await browser.newContext();40 const page = await context.newPage();41 const element = await page.$('input');42 console.log(hasCSSTransform(element));43 await browser.close();44})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { hasCSSTransform } = require('playwright/lib/server/dom.js');2const page = await browser.newPage();3const element = await page.$('input[name="q"]');4const supportsCSSTransforms = await hasCSSTransform(element);5console.log(supportsCSSTransforms);6const { BrowserContext } = require('playwright/lib/server/browserContext.js');7const page = await browser.newPage();8const browserName = await page.context().browserName();9const browserVersion = await page.context().browserVersion();10console.log(browserName);11console.log(browserVersion);12const { hasCSSTransform } = require('playwright/lib/server/dom.js');13const page = await browser.newPage();14const element = await page.$('input[name="q"]');15const supportsCSSTransforms = await hasCSSTransform(element);16console.log(supportsCSSTransforms);

Full Screen

Using AI Code Generation

copy

Full Screen

1const { hasCSSTransform } = require('@playwright/test/lib/server/domSnapshot');2const hasCSSTransform = hasCSSTransform();3const { hasCSSTransform } = require('@playwright/test/lib/server/domSnapshot');4const hasCSSTransform = hasCSSTransform();5const { hasCSSTransform } = require('@playwright/test/lib/server/domSnapshot');6const hasCSSTransform = hasCSSTransform();7const { hasCSSTransform } = require('@playwright/test/lib/server/domSnapshot');8const hasCSSTransform = hasCSSTransform();9const { hasCSSTransform } = require('@playwright/test/lib/server/domSnapshot');10const hasCSSTransform = hasCSSTransform();11const { hasCSSTransform } = require('@playwright/test/lib/server/domSnapshot');12const hasCSSTransform = hasCSSTransform();13const { hasCSSTransform } = require('@playwright/test/lib/server/domSnapshot');14const hasCSSTransform = hasCSSTransform();15const { hasCSSTransform } = require('@playwright/test/lib/server/domSnapshot');16const hasCSSTransform = hasCSSTransform();17const { hasCSSTransform } = require('@playwright/test/lib/server/domSnapshot');18const hasCSSTransform = hasCSSTransform();19const { hasCSSTransform } = require('@playwright/test/lib/server/domSnapshot');20const hasCSSTransform = hasCSSTransform();21const { hasCSSTransform } = require('@playwright/test/lib/server/dom

Full Screen

Playwright tutorial

LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful