From 7e4e0cb84cd856526f4ba3256e5b8bd249c932c3 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 27 Sep 2018 18:00:03 +0200 Subject: [PATCH] [ML] Fixes Anomaly Explorer IE11 issues (#23558) Fixes two issues in IE11 for Anomaly Explorer: - The format of the string returned from element.attr('transform') is different in IE11 so the regex based on it would fail. This fixes the issue and adds tests for the different formats. The code was also changed to gracefully return NaN in case the regex wouldn't return results, the previous version triggered a JS error. - The migration of the swimlanes to React caused the cell selection to malfunction in IE11. This fixes it by updating the dragSelect library to use the new method setSelectables. The previous method we used (addSelectables) didn't play well with how React rerenders the swimlanes. Note this lib update using the new method will require to run yarn kbn bootstrap. --- x-pack/package.json | 2 +- .../ml/public/explorer/explorer_controller.js | 5 ++-- .../ml/public/explorer/explorer_swimlane.js | 4 ---- x-pack/plugins/ml/public/util/chart_utils.js | 20 ++++++++++++---- .../ml/public/util/chart_utils.test.js | 23 +++++++++++++++++++ x-pack/yarn.lock | 6 ++--- yarn.lock | 6 ++--- 7 files changed, 48 insertions(+), 18 deletions(-) diff --git a/x-pack/package.json b/x-pack/package.json index 8d502a11c79a5..f501d9b5d2b5e 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -117,7 +117,7 @@ "d3": "3.5.6", "d3-scale": "1.0.6", "dedent": "^0.7.0", - "dragselect": "1.7.17", + "dragselect": "1.8.1", "elasticsearch": "^15.1.1", "extract-zip": "1.5.0", "file-saver": "^1.3.8", diff --git a/x-pack/plugins/ml/public/explorer/explorer_controller.js b/x-pack/plugins/ml/public/explorer/explorer_controller.js index 94604244dd43c..83e09a332c332 100644 --- a/x-pack/plugins/ml/public/explorer/explorer_controller.js +++ b/x-pack/plugins/ml/public/explorer/explorer_controller.js @@ -105,7 +105,7 @@ module.controller('MlExplorerController', function ( $scope.queryFilters = []; const dragSelect = new DragSelect({ - selectables: document.querySelectorAll('.sl-cell'), + selectables: document.getElementsByClassName('sl-cell'), callback(elements) { if (elements.length > 1 && !ALLOW_CELL_RANGE_SELECTION) { elements = [elements[0]]; @@ -508,7 +508,8 @@ module.controller('MlExplorerController', function ( // Listens to render updates of the swimlanes to update dragSelect const swimlaneRenderDoneListener = function () { - dragSelect.addSelectables(document.querySelectorAll('.sl-cell')); + dragSelect.clearSelection(); + dragSelect.setSelectables(document.getElementsByClassName('sl-cell')); }; mlExplorerDashboardService.swimlaneRenderDone.watch(swimlaneRenderDoneListener); diff --git a/x-pack/plugins/ml/public/explorer/explorer_swimlane.js b/x-pack/plugins/ml/public/explorer/explorer_swimlane.js index baaa1cf94f787..223ced53acbea 100644 --- a/x-pack/plugins/ml/public/explorer/explorer_swimlane.js +++ b/x-pack/plugins/ml/public/explorer/explorer_swimlane.js @@ -202,8 +202,6 @@ export class ExplorerSwimlane extends React.Component { } clearSelection() { - const { mlExplorerDashboardService } = this.props; - // This selects both overall and viewby swimlane const wrapper = d3.selectAll('.ml-explorer-swimlane'); @@ -212,8 +210,6 @@ export class ExplorerSwimlane extends React.Component { wrapper.selectAll('.sl-cell-inner.sl-cell-inner-selected').classed('sl-cell-inner-selected', false); wrapper.selectAll('.sl-cell-inner-dragselect.sl-cell-inner-selected').classed('sl-cell-inner-selected', false); wrapper.selectAll('.ds-selected').classed('sl-cell-inner-selected', false); - - mlExplorerDashboardService.swimlaneCellClick.changed({}); } renderSwimlane() { diff --git a/x-pack/plugins/ml/public/util/chart_utils.js b/x-pack/plugins/ml/public/util/chart_utils.js index 158db91ebdacf..df0a1121ee7a9 100644 --- a/x-pack/plugins/ml/public/util/chart_utils.js +++ b/x-pack/plugins/ml/public/util/chart_utils.js @@ -228,6 +228,20 @@ export function getTickValues(startTimeMs, tickInterval, earliest, latest) { return tickValues; } +// To get xTransform it would be nicer to use d3.transform, but that doesn't play well with JSDOM. +// So this uses a regex variant because we definitely want test coverage for the label removal. +// Once JSDOM supports SVGAnimatedTransformList we can use this simpler inline version: +// const xTransform = d3.transform(tick.attr('transform')).translate[0]; +export function getXTransform(t) { + const regexResult = /translate\(\s*([^\s,)]+)([ ,]([^\s,)]+))?\)/.exec(t); + if (Array.isArray(regexResult) && regexResult.length >= 2) { + return Number(regexResult[1]); + } + + // fall back to NaN if regex didn't return any results. + return NaN; +} + // This removes overlapping x-axis labels by starting off from a specific label // that is required/wanted to show up. The code then traverses to both sides along the axis // and decides which labels to keep or remove. All vertical tick lines will be kept visible, @@ -266,11 +280,7 @@ export function removeLabelOverlap(axis, startTimeMs, tickInterval, width) { const tickWidth = textNode.getBBox().width; const padding = 15; - // To get xTransform it would be nicer to use d3.transform, but that doesn't play well with JSDOM. - // So this uses a regex variant because we definitely want test coverage for the label removal. - // Once JSDOM supports SVGAnimatedTransformList we can use the simpler version. - // const xTransform = d3.transform(tick.attr('transform')).translate[0]; - const xTransform = +(/translate\(\s*([^\s,)]+)[ ,]([^\s,)]+)\)/.exec(tick.attr('transform'))[1]); + const xTransform = getXTransform(tick.attr('transform')); const xMinOffset = xTransform - (tickWidth / 2 + padding); const xMaxOffset = xTransform + (tickWidth / 2 + padding); diff --git a/x-pack/plugins/ml/public/util/chart_utils.test.js b/x-pack/plugins/ml/public/util/chart_utils.test.js index d4beee8484b9b..d44cc933d0ad2 100644 --- a/x-pack/plugins/ml/public/util/chart_utils.test.js +++ b/x-pack/plugins/ml/public/util/chart_utils.test.js @@ -47,6 +47,7 @@ import { timefilter } from 'ui/timefilter'; import { getExploreSeriesLink, getTickValues, + getXTransform, removeLabelOverlap } from './chart_utils'; @@ -133,6 +134,28 @@ describe('getTickValues', () => { }); }); +describe('getXTransform', () => { + const expectedXTransform = 0.007167499999999999; + + test('Chrome/Safari/Firefox String variant.', () => { + const transformStr = 'translate(0.007167499999999999,0)'; + const xTransform = getXTransform(transformStr); + expect(xTransform).toEqual(expectedXTransform); + }); + + test('IE11 String variant.', () => { + const transformStr = 'translate(0.007167499999999999)'; + const xTransform = getXTransform(transformStr); + expect(xTransform).toEqual(expectedXTransform); + }); + + test('Invalid String.', () => { + const transformStr = 'translate()'; + const xTransform = getXTransform(transformStr); + expect(xTransform).toEqual(NaN); + }); +}); + describe('removeLabelOverlap', () => { const originalGetBBox = SVGElement.prototype.getBBox; diff --git a/x-pack/yarn.lock b/x-pack/yarn.lock index 4c165d8923e0b..270638892e224 100644 --- a/x-pack/yarn.lock +++ b/x-pack/yarn.lock @@ -2345,9 +2345,9 @@ dotenv@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-2.0.0.tgz#bd759c357aaa70365e01c96b7b0bec08a6e0d949" -dragselect@1.7.17: - version "1.7.17" - resolved "https://registry.yarnpkg.com/dragselect/-/dragselect-1.7.17.tgz#ab98661d8599286c0ada66ce5f5923b06b4f09fd" +dragselect@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/dragselect/-/dragselect-1.8.1.tgz#63f71a6f980f710c87e28b328e175b7afc9e162b" duplexer2@0.0.2, duplexer2@~0.0.2: version "0.0.2" diff --git a/yarn.lock b/yarn.lock index 119164204357c..805930d4961da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4223,9 +4223,9 @@ download@^5.0.3: mkdirp "^0.5.1" pify "^2.3.0" -dragselect@1.7.17: - version "1.7.17" - resolved "https://registry.yarnpkg.com/dragselect/-/dragselect-1.7.17.tgz#ab98661d8599286c0ada66ce5f5923b06b4f09fd" +dragselect@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/dragselect/-/dragselect-1.8.1.tgz#63f71a6f980f710c87e28b328e175b7afc9e162b" dragula@3.7.0: version "3.7.0"