⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 176710 in webkit


Ignore:
Timestamp:
Dec 2, 2014, 8:17:32 PM (12 years ago)
Author:
rniwa@webkit.org
Message:

New perf dashboard's chart UI is buggy
https://bugs.webkit.org/show_bug.cgi?id=139214

Reviewed by Chris Dumez.

The bugginess was caused by weird interactions between charts and panes. Rewrote the code to fix it.

Superfluous selectionChanged and domainChanged "event" actions were removed from the interactive chart
component. This is not how Ember.js components should interact to begin with. The component now exposes
selectedPoints and always updates selection instead of sharedSelection.

  • public/v2/app.js:

(App.ChartsController.present): Added. We can't call Date.now() in various points in our code as that
would lead to infinite mutual recursions since X-axis domain values wouldn't match up.
(App.ChartsController.updateSharedDomain): This function was completely useless. The overview's start
and end time should be completely determined by "since" and the present time.
(App.ChartsController._startTimeChanged): Ditto.
(App.ChartsController._scheduleQueryStringUpdate):
(App.ChartsController._updateQueryString): Set "zoom" only if it's different from the shared domain.

(App.domainsAreEqual): Moved from InteractiveChartComponent._xDomainsAreSame.

(App.PaneController.actions.createAnalysisTask): Use selectedPoints property set by the chart.
(App.PaneController.actions.overviewDomainChanged): Removed; only needed to call updateSharedDomain.
(App.PaneController.actions.rangeChanged): Removed. _showDetails (renamed to _updateDetails) directly
observes the changes to selectedPoints property as it gets updated by the main chart.
(App.PaneController._overviewSelectionChanged): This was previously a dead code. Now it's used again
with a bug fix. When the overview selection is cleared, we use the same domain in the main chart and
the overview chart.
(App.PaneController._sharedDomainChanged): Fixed a but that it erroneously updates the overview domain
when domain arrays aren't identical. This was causing a subtle race with other logic.
(App.PaneController._sharedZoomChanged): Ditto. Also don't set mainPlotDomain here as any changes to
overviewSelection will automatically propagate to the main plot's domain as they're aliased.
(App.PaneController._currentItemChanged): Merged into _updateDetails (renamed from _showDetails).
(App.PaneController._updateDetails): Previously, this function took points and inspected _hasRange to
see if those two points correspond to a range or a single data point. Rewrote all that logic by
directly observing selectedPoints and currentItem properties instead of taking points and relying on
an instance variable, which was a terrible API.
(App.PaneController._updateCanAnalyze): Use selectedPoints property. Since this property is only set
when the main plot has a selected range, we don't have to check this._hasRange anymore.

(App.InteractiveChartComponent._updateDomain): No longer sends domainChanged "event" action.
(App.InteractiveChartComponent._sharedSelectionChanged): Removed. This is a dead code.
(App.InteractiveChartComponent._updateSelection):
(App.InteractiveChartComponent._xDomainsAreSame): Moved to App.domainsAreEqual.
(App.InteractiveChartComponent._setCurrentSelection): Update the selection only if needed. Also set
selectedPoints property.

(App.AnalysisTaskController._fetchedRuns):
(App.AnalysisTaskController._rootChangedForTestSet):

  • public/v2/index.html:

Removed non-functional sharedSelection and superfluous selectionChanged and domainChanged actions.

Location:
trunk/Websites/perf.webkit.org
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Websites/perf.webkit.org/ChangeLog

    r176498 r176710  
     12014-12-02  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        New perf dashboard's chart UI is buggy
     4        https://bugs.webkit.org/show_bug.cgi?id=139214
     5
     6        Reviewed by Chris Dumez.
     7
     8        The bugginess was caused by weird interactions between charts and panes. Rewrote the code to fix it.
     9
     10        Superfluous selectionChanged and domainChanged "event" actions were removed from the interactive chart
     11        component. This is not how Ember.js components should interact to begin with. The component now exposes
     12        selectedPoints and always updates selection instead of sharedSelection.
     13
     14        * public/v2/app.js:
     15        (App.ChartsController.present): Added. We can't call Date.now() in various points in our code as that
     16        would lead to infinite mutual recursions since X-axis domain values wouldn't match up.
     17        (App.ChartsController.updateSharedDomain): This function was completely useless. The overview's start
     18        and end time should be completely determined by "since" and the present time.
     19        (App.ChartsController._startTimeChanged): Ditto.
     20        (App.ChartsController._scheduleQueryStringUpdate):
     21        (App.ChartsController._updateQueryString): Set "zoom" only if it's different from the shared domain.
     22
     23        (App.domainsAreEqual): Moved from InteractiveChartComponent._xDomainsAreSame.
     24
     25        (App.PaneController.actions.createAnalysisTask): Use selectedPoints property set by the chart.
     26        (App.PaneController.actions.overviewDomainChanged): Removed; only needed to call updateSharedDomain.
     27        (App.PaneController.actions.rangeChanged): Removed. _showDetails (renamed to _updateDetails) directly
     28        observes the changes to selectedPoints property as it gets updated by the main chart.
     29        (App.PaneController._overviewSelectionChanged): This was previously a dead code. Now it's used again
     30        with a bug fix. When the overview selection is cleared, we use the same domain in the main chart and
     31        the overview chart.
     32        (App.PaneController._sharedDomainChanged): Fixed a but that it erroneously updates the overview domain
     33        when domain arrays aren't identical. This was causing a subtle race with other logic.
     34        (App.PaneController._sharedZoomChanged): Ditto. Also don't set mainPlotDomain here as any changes to
     35        overviewSelection will automatically propagate to the main plot's domain as they're aliased.
     36        (App.PaneController._currentItemChanged): Merged into _updateDetails (renamed from _showDetails).
     37        (App.PaneController._updateDetails): Previously, this function took points and inspected _hasRange to
     38        see if those two points correspond to a range or a single data point. Rewrote all that logic by
     39        directly observing selectedPoints and currentItem properties instead of taking points and relying on
     40        an instance variable, which was a terrible API.
     41        (App.PaneController._updateCanAnalyze): Use selectedPoints property. Since this property is only set
     42        when the main plot has a selected range, we don't have to check this._hasRange anymore.
     43
     44        (App.InteractiveChartComponent._updateDomain): No longer sends domainChanged "event" action.
     45        (App.InteractiveChartComponent._sharedSelectionChanged): Removed. This is a dead code.
     46        (App.InteractiveChartComponent._updateSelection):
     47        (App.InteractiveChartComponent._xDomainsAreSame): Moved to App.domainsAreEqual.
     48        (App.InteractiveChartComponent._setCurrentSelection): Update the selection only if needed. Also set
     49        selectedPoints property.
     50
     51        (App.AnalysisTaskController._fetchedRuns):
     52        (App.AnalysisTaskController._rootChangedForTestSet):
     53
     54        * public/v2/index.html:
     55        Removed non-functional sharedSelection and superfluous selectionChanged and domainChanged actions.
     56
    1572014-11-21  Ryosuke Niwa  <rniwa@webkit.org>
    258
  • trunk/Websites/perf.webkit.org/public/v2/app.js

    r176497 r176710  
    400400    sharedZoom: null,
    401401    startTime: null,
     402    present: Date.now(),
    402403    defaultSince: Date.now() - 7 * 24 * 3600 * 1000,
    403404
     
    451452    }.observes('zoom').on('init'),
    452453
    453     updateSharedDomain: function ()
    454     {
    455         var panes = this.get('panes');
    456         if (!panes.length)
    457             return;
    458 
    459         var union = [undefined, undefined];
    460         for (var i = 0; i < panes.length; i++) {
    461             var domain = panes[i].intrinsicDomain;
    462             if (!domain)
    463                 continue;
    464             if (!union[0] || domain[0] < union[0])
    465                 union[0] = domain[0];
    466             if (!union[1] || domain[1] > union[1])
    467                 union[1] = domain[1];
    468         }
    469         if (union[0] === undefined)
    470             return;
    471 
    472         var startTime = this.get('startTime');
    473         var zoom = this.get('sharedZoom');
    474         if (startTime)
    475             union[0] = zoom ? Math.min(zoom[0], startTime) : startTime;
    476 
    477         this.set('sharedDomain', union);
    478     }.observes('panes.@each'),
    479 
    480454    _startTimeChanged: function () {
    481         this.updateSharedDomain();
     455        this.set('sharedDomain', [this.get('startTime'), this.get('present')]);
    482456        this._scheduleQueryStringUpdate();
    483457    }.observes('startTime'),
     
    537511    _scheduleQueryStringUpdate: function ()
    538512    {
    539         Ember.run.debounce(this, '_updateQueryString', 500);
    540     }.observes('sharedZoom')
    541         .observes('panes.@each.platform', 'panes.@each.metric', 'panes.@each.selectedItem',
     513        Ember.run.debounce(this, '_updateQueryString', 1000);
     514    }.observes('sharedZoom', 'panes.@each.platform', 'panes.@each.metric', 'panes.@each.selectedItem',
    542515        'panes.@each.timeRange', 'panes.@each.timeRangeIsLocked'),
    543516
     
    548521
    549522        var zoom = undefined;
    550         var selection = this.get('sharedZoom');
    551         if (selection)
    552             zoom = (selection[0] - 0) + '-' + (selection[1] - 0);
     523        var sharedZoom = this.get('sharedZoom');
     524        if (sharedZoom && !App.domainsAreEqual(sharedZoom, this.get('sharedDomain')))
     525            zoom = +sharedZoom[0] + '-' + +sharedZoom[1];
    553526        this.set('zoom', zoom);
    554527
     
    635608    }.property('childTests', 'metrics'),
    636609});
     610
     611App.domainsAreEqual = function (domain1, domain2) {
     612    return (!domain1 && !domain2) || (domain1 && domain2 && !(domain1[0] - domain2[0]) && !(domain1[1] - domain2[1]));
     613}
    637614
    638615App.PaneController = Ember.ObjectController.extend({
     
    658635        {
    659636            var name = this.get('newAnalysisTaskName');
    660             var points = this._selectedPoints;
     637            var points = this.get('selectedPoints');
    661638            Ember.assert('The analysis name should not be empty', name);
    662639            Ember.assert('There should be at least two points in the range', points && points.length >= 2);
     
    696673            Ember.run.debounce(this, 'propagateZoom', 100);
    697674        },
    698         overviewDomainChanged: function (domain, intrinsicDomain)
    699         {
    700             this.set('overviewDomain', domain);
    701             this.set('intrinsicDomain', intrinsicDomain);
    702             this.get('parentController').updateSharedDomain();
    703         },
    704         rangeChanged: function (extent, points)
    705         {
    706             if (!points) {
    707                 this._hasRange = false;
    708                 this.set('details', null);
    709                 this.set('timeRange', null);
    710                 return;
    711             }
    712             this._hasRange = true;
    713             this._showDetails(points);
    714             this.set('timeRange', extent);
    715         },
    716675    },
    717676    _detailsChanged: function ()
     
    722681    {
    723682        var overviewSelection = this.get('overviewSelection');
    724         this.set('mainPlotDomain', overviewSelection);
     683        this.set('mainPlotDomain', overviewSelection || this.get('overviewDomain'));
    725684        Ember.run.debounce(this, 'propagateZoom', 100);
    726685    }.observes('overviewSelection'),
     
    728687    {
    729688        var newDomain = this.get('parentController').get('sharedDomain');
    730         if (newDomain == this.get('overviewDomain'))
     689        if (App.domainsAreEqual(newDomain, this.get('overviewDomain')))
    731690            return;
    732691        this.set('overviewDomain', newDomain);
     
    741700    {
    742701        var newSelection = this.get('parentController').get('sharedZoom');
    743         if (newSelection == this.get('mainPlotDomain'))
     702        if (App.domainsAreEqual(newSelection, this.get('mainPlotDomain')))
    744703            return;
    745704        this.set('overviewSelection', newSelection);
    746         this.set('mainPlotDomain', newSelection);
    747705    }.observes('parentController.sharedZoom').on('init'),
    748     _currentItemChanged: function ()
    749     {
    750         if (this._hasRange)
    751             return;
    752         var point = this.get('currentItem');
    753         if (!point || !point.measurement)
     706    _updateDetails: function ()
     707    {
     708        var selectedPoints = this.get('selectedPoints');
     709        var currentPoint = this.get('currentItem');
     710        if (!selectedPoints && !currentPoint) {
    754711            this.set('details', null);
    755         else {
    756             var previousPoint = point.series.previousPoint(point);
    757             this._showDetails(previousPoint ? [previousPoint, point] : [point]);
    758         }
    759     }.observes('currentItem'),
    760     _showDetails: function (points)
    761     {
    762         var isShowingEndPoint = !this._hasRange;
    763         var currentMeasurement = points[points.length - 1].measurement;
    764         var oldMeasurement = points[0].measurement;
     712            return;
     713        }
     714
     715        var currentMeasurement;
     716        var oldMeasurement;
     717        if (currentPoint) {
     718            currentMeasurement = currentPoint.measurement;
     719            var previousPoint = currentPoint.series.previousPoint(currentPoint);
     720            oldMeasurement = previousPoint ? previousPoint.measurement : null;
     721        } else {
     722            currentMeasurement = selectedPoints[selectedPoints.length - 1].measurement;
     723            oldMeasurement = selectedPoints[0].measurement;           
     724        }
     725
    765726        var formattedRevisions = currentMeasurement.formattedRevisions(oldMeasurement);
    766727        var revisions = App.Manifest.get('repositories')
     
    779740        var buildNumber = null;
    780741        var buildURL = null;
    781         if (isShowingEndPoint) {
     742        if (currentPoint) {
    782743            buildNumber = currentMeasurement.buildNumber();
    783744            var builder = App.Manifest.builder(currentMeasurement.builderId());
     
    786747        }
    787748
    788         this._selectedPoints = points;
    789749        this.set('details', Ember.Object.create({
    790750            currentValue: currentMeasurement.mean().toFixed(2),
    791             oldValue: oldMeasurement && !isShowingEndPoint ? oldMeasurement.mean().toFixed(2) : null,
     751            oldValue: oldMeasurement && selectedPoints ? oldMeasurement.mean().toFixed(2) : null,
    792752            buildNumber: buildNumber,
    793753            buildURL: buildURL,
     
    796756        }));
    797757        this._updateCanAnalyze();
    798     },
     758    }.observes('currentItem', 'selectedPoints'),
    799759    _updateCanAnalyze: function ()
    800760    {
    801         var points = this._selectedPoints;
    802         this.set('cannotAnalyze', !this.get('newAnalysisTaskName') || !this._hasRange || !points || points.length < 2);
     761        var points = this.get('selectedPoints');
     762        this.set('cannotAnalyze', !this.get('newAnalysisTaskName') || !points || points.length < 2);
    803763    }.observes('newAnalysisTaskName'),
    804764});
     
    995955            xDomain = intrinsicXDomain;
    996956        var currentDomain = this._x.domain();
    997         if (currentDomain && this._xDomainsAreSame(currentDomain, xDomain))
     957        if (currentDomain && App.domainsAreEqual(currentDomain, xDomain))
    998958            return currentDomain;
    999959
     
    1001961        this._x.domain(xDomain);
    1002962        this._y.domain(yDomain);
    1003         this.sendAction('domainChanged', xDomain, intrinsicXDomain);
    1004963        return xDomain;
    1005964    },
     
    11811140        this._updateSelection(this.get('selection'));
    11821141    }.observes('selection'),
    1183     _sharedSelectionChanged: function ()
    1184     {
    1185         if (this.get('selectionIsLocked'))
    1186             return;
    1187         this._updateSelection(this.get('sharedSelection'));
    1188     }.observes('sharedSelection'),
    11891142    _updateSelection: function (newSelection)
    11901143    {
     
    11931146
    11941147        var currentSelection = this._currentSelection();
    1195         if (newSelection && currentSelection && this._xDomainsAreSame(newSelection, currentSelection))
     1148        if (newSelection && currentSelection && App.domainsAreEqual(newSelection, currentSelection))
    11961149            return;
    11971150
    11981151        var domain = this._x.domain();
    1199         if (!newSelection || this._xDomainsAreSame(domain, newSelection))
     1152        if (!newSelection || App.domainsAreEqual(domain, newSelection))
    12001153            this._brush.clear();
    12011154        else
     
    12041157
    12051158        this._setCurrentSelection(newSelection);
    1206     },
    1207     _xDomainsAreSame: function (domain1, domain2)
    1208     {
    1209         return !(domain1[0] - domain2[0]) && !(domain1[1] - domain2[1]);
    12101159    },
    12111160    _brushChanged: function ()
     
    15581507        this._updateSelectionToolbar();
    15591508
    1560         this.set('sharedSelection', newSelection);
    1561         this.sendAction('selectionChanged', newSelection, points);
     1509        if (!App.domainsAreEqual(this.get('selection'), newSelection))
     1510            this.set('selection', newSelection);
     1511        this.set('selectedPoints', points);
    15621512    },
    15631513    _updateSelectionToolbar: function ()
     
    16761626        }));
    16771627    },
    1678     _fetchedRuns: function (data) {
     1628    _fetchedRuns: function (data)
     1629    {
    16791630        var runs = data.runs;
    16801631
     
    17191670        ];
    17201671    }.property('analysisPoints'),
    1721     _rootChangedForTestSet: function () {
     1672    _rootChangedForTestSet: function ()
     1673    {
    17221674        var sets = this.get('testSets');
    17231675        var roots = this.get('roots');
  • trunk/Websites/perf.webkit.org/public/v2/index.html

    r176493 r176710  
    157157                            rangeRoute="analysisTask"
    158158                            selection=timeRange
    159                             sharedSelection=sharedSelection
    160                             selectionChanged="rangeChanged"
     159                            selectedPoints=selectedPoints
    161160                            selectionIsLocked=timeRangeIsLocked
    162161                            markedPoints=markedPoints
     
    177176                                showYAxis=false
    178177                                domain=overviewDomain
    179                                 domainChanged="overviewDomainChanged"
    180                                 selection=mainPlotDomain
    181                                 selectionChanged="zoomed"}}
     178                                selection=overviewSelection}}
    182179                        {{/if}}
    183180                        </div>
Note: See TracChangeset for help on using the changeset viewer.