From 2b1f855c88aa01c12f9faf82ea76edb9875dc322 Mon Sep 17 00:00:00 2001 From: Tung Jin Chew Date: Wed, 22 Feb 2017 11:22:53 +0000 Subject: [PATCH 1/9] Squashed commit of the dategraph changes, rebased onto develop. --- webapp/core/bower.json | 1 + webapp/core/src/main/less/app-include.less | 19 +- .../js/find/app/page/search/filter-view.js | 7 +- .../parametric/parametric-field-view.js | 8 +- .../parametric-select-modal-item-view.js | 7 +- .../parametric-select-modal-list-view.js | 3 + .../parametric-select-modal-view.js | 9 +- .../parametric/parametric-select-modal.js | 7 +- .../parametric/parametric-value-view.js | 5 + .../filters/parametric/parametric-view.js | 11 +- .../results/dategraph/dategraph-view.js | 309 ++++++++++++++++++ .../js/find/app/page/search/service-view.js | 14 +- .../public/static/js/find/nls/root/bundle.js | 3 + .../parametric-select-modal-item-view.html | 5 +- .../parametric/parametric-value-view.html | 3 + .../results/dategraph/dategraph-view.html | 8 + .../main/public/static/js/require-config.js | 8 +- .../main/resources/defaultIdolConfigFile.json | 3 +- 18 files changed, 410 insertions(+), 20 deletions(-) create mode 100644 webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js create mode 100644 webapp/core/src/main/public/static/js/find/templates/app/page/search/results/dategraph/dategraph-view.html diff --git a/webapp/core/bower.json b/webapp/core/bower.json index 5ada3de631..cfa58aa1fb 100644 --- a/webapp/core/bower.json +++ b/webapp/core/bower.json @@ -54,6 +54,7 @@ "datatables.net-fixedcolumns-bs": "3.2.2", "hp-autonomy-about-page": "0.3.0", "bootstrap": "3.3.7", + "Flot": "flot#~0.8.3", "moment-timezone": "0.5.11" }, "devDependencies": { diff --git a/webapp/core/src/main/less/app-include.less b/webapp/core/src/main/less/app-include.less index 5e0d931cc5..ca16d244a0 100644 --- a/webapp/core/src/main/less/app-include.less +++ b/webapp/core/src/main/less/app-include.less @@ -1599,12 +1599,17 @@ input.find-input { width: @custom3; } -.parametric-value-count { +.parametric-value-graph-cell { + width: @custom3; +} + +.parametric-value-count,.parametric-value-graph { &:extend(.text-right); } .parametric-value-name, -.parametric-value-count { +.parametric-value-count, +.parametric-value-graph{ white-space: nowrap; } @@ -2238,19 +2243,23 @@ h4.similar-dates-message { } @media @smHeightScreen { - .entity-topic-map { + .entity-topic-map, .dategraph-content { height: @custom4; } } @media @mHeightScreen { - .entity-topic-map { + .entity-topic-map, .dategraph-content { height: 500px; } } @media @lgHeightScreen { - .entity-topic-map { + .entity-topic-map, .dategraph-content { height: @lgHeightScreenTopicMapHeight; } } + +.dategraph-content { + clear: both; +} \ No newline at end of file diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/filter-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/filter-view.js index e648e7e19e..b3a29962d9 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/filter-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/filter-view.js @@ -35,8 +35,10 @@ define([ const IndexesView = options.IndexesView; this.collapsed = {}; + const config = configuration(); + const views = [{ - shown: configuration().enableMetaFilter, + shown: config.enableMetaFilter, initialize: function () { //Initializing the text with empty string to stop IE11 issue with triggering input event on render this.filterModel = new Backbone.Model({text: ''}); @@ -175,7 +177,8 @@ define([ inputTemplate: NumericParametricFieldView.dateInputTemplate, formatting: NumericParametricFieldView.dateFormatting, indexesCollection: options.indexesCollection, - filteredParametricCollection: filteredParametricCollection + filteredParametricCollection: filteredParametricCollection, + showGraphButtons: _.contains(config.resultViewOrder, 'dategraph') }); }.bind(this), get$els: function () { diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-field-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-field-view.js index 80cc71a38b..dfaaaa186c 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-field-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-field-view.js @@ -42,7 +42,8 @@ define([ queryModel: this.queryModel, parametricFieldsCollection: this.parametricFieldsCollection, selectedParametricValues: this.selectedParametricValues, - indexesCollection: this.indexesCollection + indexesCollection: this.indexesCollection, + showGraphButtons: this.showGraphButtons }); } }, @@ -52,6 +53,7 @@ define([ this.indexesCollection = options.indexesCollection; this.parametricFieldsCollection = options.parametricFieldsCollection; this.queryModel = options.queryModel; + this.showGraphButtons = options.showGraphButtons; this.listView = new ListView({ collection: this.collection, @@ -61,6 +63,7 @@ define([ tagName: 'tbody', itemOptions: { selectedValuesCollection: options.selectedValuesCollection, + showGraphButtons: options.showGraphButtons } }); }, @@ -109,7 +112,8 @@ define([ parametricFieldsCollection: this.parametricFieldsCollection, queryModel: this.queryModel, selectedParametricValues: this.selectedParametricValues, - indexesCollection: this.indexesCollection + indexesCollection: this.indexesCollection, + showGraphButtons: options.showGraphButtons }) }); diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal-item-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal-item-view.js index 15b28097a6..04158c9467 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal-item-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal-item-view.js @@ -15,12 +15,17 @@ define([ tagName: 'li', template: _.template(template), + initialize: function(options) { + this.showGraphButtons = options.showGraphButtons; + }, + render: function() { this.$el .html(this.template({ count: this.model.get('count') || 0, value: this.model.get('value'), - displayValue: this.model.get('displayValue') + displayValue: this.model.get('displayValue'), + showGraphButtons: this.showGraphButtons })) .iCheck({checkboxClass: 'icheckbox-hp'}); diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal-list-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal-list-view.js index 7e75f1ff9e..f17d04fc9e 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal-list-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal-list-view.js @@ -42,6 +42,9 @@ define([ ItemView: ItemView, collectionChangeEvents: { selected: 'updateSelected' + }, + itemOptions: { + showGraphButtons: options.showGraphButtons } }); diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal-view.js index 8d2241a634..3c2f094443 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal-view.js @@ -57,7 +57,10 @@ define([ return { id: fieldModel.id, displayName: fieldModel.get('displayName'), - view: new ParametricSelectModalListView({paginator: paginator}) + view: new ParametricSelectModalListView({ + showGraphButtons: options.showGraphButtons, + paginator: paginator + }) }; }.bind(this)); @@ -102,6 +105,10 @@ define([ }); }, + getSelectedField: function(){ + return this.fieldSelectionModel.get('field'); + }, + remove: function () { this.fieldData.forEach(function (data) { data.view.remove(); diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal.js b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal.js index 3165a79daa..deeddae903 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-select-modal.js @@ -26,6 +26,10 @@ define([ 'shown.bs.modal': function() { // The content view will be visible now, so check if we need to load parametric values this.parametricSelectView.checkScroll(); + }, + 'click .parametric-value-graph': function(e){ + var $checkboxEl = $(e.currentTarget).prev() + this.externalSelectedValues.trigger('graph', this.parametricSelectView.getSelectedField(), $checkboxEl.data('value')); } }, Modal.prototype.events), @@ -40,7 +44,8 @@ define([ indexesCollection: options.indexesCollection, queryModel: options.queryModel, parametricFieldsCollection: options.parametricFieldsCollection, - selectedParametricValues: this.selectedParametricValues + selectedParametricValues: this.selectedParametricValues, + showGraphButtons: options.showGraphButtons }); Modal.prototype.initialize.call(this, { diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-value-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-value-view.js index 8a3a9b2cc0..69a4736350 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-value-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-value-view.js @@ -11,6 +11,7 @@ define([ initialize: function (options) { this.selectedValuesCollection = options.selectedValuesCollection; + this.showGraphButtons = options.showGraphButtons; this.$el.attr('data-value', this.model.get('value')); this.$el.attr('data-display-value', this.model.get('displayValue')); @@ -21,6 +22,10 @@ define([ render: function () { this.$el.html(template); + if (!this.showGraphButtons) { + this.$('.parametric-value-graph-cell').addClass('hide'); + } + this.$text = this.$('.parametric-value-text'); this.$name = this.$('.parametric-value-name'); this.$count = this.$('.parametric-value-count'); diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-view.js index 20012d6cf1..3f1d3759dd 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/filters/parametric/parametric-view.js @@ -41,7 +41,9 @@ define([ type: 'Parametric' }; - if (this.selectedParametricValues.get(attributes)) { + if ($(e.target).closest('.parametric-value-graph-cell').length) { + this.selectedParametricValues.trigger('graph', attributes.field, attributes.value); + } else if (this.selectedParametricValues.get(attributes)) { this.selectedParametricValues.remove(attributes); } else { this.selectedParametricValues.add(attributes); @@ -54,6 +56,7 @@ define([ this.filteredParametricCollection = options.filteredParametricCollection; this.selectedParametricValues = options.queryState.selectedParametricValues; this.filterModel = options.filterModel; + this.showGraphButtons = options.showGraphButtons; this.initializeProcessingBehaviour(); @@ -96,7 +99,8 @@ define([ parametricFieldsCollection: options.parametricFieldsCollection, filteredParametricCollection: this.filteredParametricCollection, selectedParametricValues: this.selectedParametricValues, - filterModel: this.filterModel + filterModel: this.filterModel, + showGraphButtons: options.showGraphButtons }, numericViewItemOptions: { inputTemplate: options.inputTemplate, @@ -110,7 +114,8 @@ define([ zoomEnabled: options.zoomEnabled, buttonsEnabled: options.buttonsEnabled, coordinatesEnabled: options.coordinatesEnabled, - collapsed: isCollapsed + collapsed: isCollapsed, + showGraphButtons: options.showGraphButtons } } }); diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js new file mode 100644 index 0000000000..19e8c6d6ba --- /dev/null +++ b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js @@ -0,0 +1,309 @@ +/* + * Copyright 2015 Hewlett-Packard Development Company, L.P. + * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. + */ +define([ + 'backbone', + 'underscore', + 'd3', + 'find/app/util/topic-map-view', + 'find/app/model/entity-collection', + 'i18n!find/nls/bundle', + 'find/app/configuration', + 'find/app/page/search/filters/parametric/calibrate-buckets', + 'find/app/page/search/results/field-selection-view', + 'find/app/model/bucketed-parametric-collection', + 'parametric-refinement/to-field-text-node', + 'find/app/util/generate-error-support-message', + 'text!find/templates/app/page/search/results/dategraph/dategraph-view.html', + 'text!find/templates/app/page/loading-spinner.html', + 'iCheck', + 'slider/bootstrap-slider', + 'flot.time' +], function(Backbone, _, d3, TopicMapView, EntityCollection, i18n, configuration, calibrateBuckets, FieldSelectionView, + BucketedParametricCollection, toFieldTextNode, generateErrorHtml, template, + loadingTemplate) { + 'use strict'; + + var loadingHtml = _.template(loadingTemplate)({i18n: i18n, large: true}); + + var category10 = d3.scale.category10(); + + function rangeModelMatching(fieldName, dataType) { + var upperCase = fieldName.toUpperCase(); + + return function(model) { + return model.get('field').toUpperCase() === upperCase && model.get('range') && model.get('dataType') === dataType; + }; + } + + function dateModelMatching(fieldName, dataType) { + var upperCase = fieldName.toUpperCase(); + + return function(model) { + return model.id.toUpperCase() === upperCase && model.get('dataType') === dataType; + }; + } + + return Backbone.View.extend({ + template: _.template(template), + + events: { + 'click .dategraph-view-pptx': function(evt){ + evt.preventDefault(); + + var modelBuckets = this.bucketModel.get('values'); + var rows = []; + var multiAxes = !this.hideMainPlot && this.plots.length > 1; + + if (!this.hideMainPlot) { + rows.push({ + color: '#00B388', + label: 'Documents', + secondaryAxis: false, + values: _.pluck(modelBuckets, 'count') + }) + } + + _.each(this.plots, function(plot){ + var label = plot.field.replace(/^.*\//, '').replace(/_/g, '\u00A0') + ': ' + plot.value; + + rows.push({ + color: category10(label), + label: label, + secondaryAxis: multiAxes, + values: _.pluck(plot.model.get('values'), 'count') + }) + }) + + var data = { + rows: rows, + timestamps: _.map(modelBuckets, function(a) { + return Math.round(0.5*(a.min+a.max)); + }) + } + + var $form = $('
'); + $form[0].data.value = JSON.stringify(data) + $form.appendTo(document.body).submit().remove() + } + }, + + initialize: function(options) { + this.queryState = options.queryState; + + this.queryModel = options.queryModel; + this.pixelsPerBucket = options.pixelsPerBucket || 20; + + this.fieldName = 'autn_date'; + this.dataType = 'date'; + + this.bucketModel = new BucketedParametricCollection.Model({id: this.fieldName}); + this.selectedParametricValues = options.queryState.selectedParametricValues; + this.dateParametricFieldsCollection = options.dateParametricFieldsCollection; + + this.listenTo(this.queryModel, 'change', this.fetchBuckets); + + this.listenTo(this.bucketModel, 'change:values request sync error', this.updateGraph); + + this.listenTo(this.selectedParametricValues, 'graph', this.graphRequest) + + this.plots = [] + }, + + graphRequest: function(field, value){ + if (!_.where(this.plots, { field: field, value: value }).length) { + var model = new BucketedParametricCollection.Model({id: this.fieldName}); + var subPlot = { field: field, value: value, model: model }; + this.plots.push(subPlot); + this.listenTo(model, 'change:values', this.updateGraph) + this.lastOtherSelectedValues && this.fetchSubPlot(subPlot) + } + }, + + update: function() { + }, + + updateGraph: function() { + if (this.$tooltip) { + this.$tooltip.hide() + } + + var hadError = this.bucketModel.error; + var fetching = this.bucketModel.fetching; + var modelBuckets = this.bucketModel.get('values'); + var noValues = !modelBuckets || !modelBuckets.length; + + this.$('.dategraph-view-error-message').toggleClass('hide', !hadError); + this.$('.dategraph-view-empty-text').toggleClass('hide', hadError || !noValues); + + var hideLoadingIndicator = hadError || !fetching; + this.$('.dategraph-loading').toggleClass('hide', hideLoadingIndicator); + + + var $contentEl = this.$('.dategraph-content'); + var width = $contentEl.width(); + + function transform(values) { + return values.map(function (a) { + return [0.5e3 * (a.min + a.max), a.count, a.min, a.max] + }) + } + + if(!hadError && !noValues && hideLoadingIndicator && width > 0) { + var multiAxes = !this.hideMainPlot && this.plots.length > 1; + + var data = (this.hideMainPlot ? [] : [{ + color: '#00B388', + label: 'Documents', + data: transform(modelBuckets) + }]).concat(_.map(this.plots, function(plot, idx, plots){ + var label = plot.field.replace(/^.*\//, '').replace(/_/g, '\u00A0') + ': ' + plot.value; + return { + color: category10(label), + label: label, + data: transform(plot.model.get('values')), + yaxis: multiAxes ? 2 : 1 + } + })) + + $.plot($contentEl[0], data, { + grid: { hoverable: true }, + xaxis: {mode: 'time'}, + yaxes: multiAxes ? [ {}, { position: 'right' } ] : {} + }) + } + else { + $contentEl.empty(); + } + }, + + fetchBuckets: function() { + var width = this.$('.dategraph-content').width(); + + // If the SVG has no width or there are no values, there is no point fetching new data + // if(width !== 0 && this.model.get('totalValues') !== 0) { + if(width) { + var rangeFilter = this.selectedParametricValues.find(rangeModelMatching(this.fieldName, this.dataType)); + + var otherSelectedValues = this.selectedParametricValues + .map(function(model) { + return model.toJSON(); + }); + + var dateRange = rangeFilter && rangeFilter.get('range'); + + var minDate = this.queryModel.getIsoDate('minDate'); + var maxDate = this.queryModel.getIsoDate('maxDate'); + + var dateField = this.dateParametricFieldsCollection.find(dateModelMatching(this.fieldName, this.dataType)); + + var baseParams = { + queryText: this.queryModel.get('queryText'), + fieldText: toFieldTextNode(otherSelectedValues), + minDate: minDate, + maxDate: maxDate, + minScore: this.queryModel.get('minScore'), + databases: this.queryModel.get('indexes'), + targetNumberOfBuckets: Math.floor(width / this.pixelsPerBucket), + bucketMin: dateRange ? dateRange[0] : dateField ? dateField.get('min') : Math.floor((new Date().getTime() - 86400e3*365)/1000), + bucketMax: dateRange ? dateRange[1] : dateField ? dateField.get('max') : Math.floor(new Date().getTime()/1000) + }; + + this.lastBaseParams = baseParams; + this.lastOtherSelectedValues = otherSelectedValues; + + this.hideMainPlot = false; + + this.bucketModel.fetch({ + data: baseParams + }); + + _.each(this.plots, this.fetchSubPlot, this) + } + }, + + fetchSubPlot: function(plot){ + var newFieldText = toFieldTextNode([{field: plot.field, value: plot.value}]) + var plotSelectedValues = toFieldTextNode(this.lastOtherSelectedValues); + + plot.model.set([]) + plot.model.fetch({ + data: _.defaults({ + fieldText: plotSelectedValues ? '(' + plotSelectedValues + ') AND (' + newFieldText + ')': newFieldText + }, this.lastBaseParams) + }) + }, + + render: function() { + this.$el.html(this.template({ + i18n: i18n, + errorTemplate: this.errorTemplate, + loadingHtml: loadingHtml, + cid: this.cid + })); + + this.$('.dategraph-content').on('click .legendColorBox', _.bind(function(evt){ + var idx = $(evt.target).closest('tr').index(), removed + + if (idx >= 0) { + if (this.hideMainPlot) { + removed = this.plots.splice(idx, 1) + this.stopListening(removed[0].model) + + if (!this.plots.length) { + this.hideMainPlot = false; + } + + this.updateGraph(); + } + else if (idx) { + removed = this.plots.splice(idx - 1, 1) + this.stopListening(removed[0].model) + + this.updateGraph(); + } + else if (this.plots.length) { + this.hideMainPlot = true; + this.updateGraph(); + } + } + }, this)).on('plothover', _.bind(function(evt, pos, item){ + function lPad2(num) { + return num < 10 ? '0' + num : num; + } + + function formatDate(epochSeconds){ + var date = new Date(1000 * epochSeconds); + return [ + [date.getFullYear(), lPad2(date.getMonth() + 1), lPad2(date.getDate())].join('-'), + [lPad2(date.getHours()), lPad2(date.getMinutes())].join(':') + ] + } + + if (item) { + if (!this.$tooltip) { + this.$tooltip = $('').appendTo(this.$el) + } + var origPt = item.series.data[item.dataIndex] + var minStr = formatDate(origPt[2]), maxStr = formatDate(origPt[3]) + + var timeStr = minStr[0] === maxStr[0] ? maxStr[0] + ' ' + minStr[1] + ' to ' + maxStr[1] : minStr[0] + ' to ' + maxStr[0]; + + this.$tooltip.find('.tooltip-inner').html(timeStr + '
' + _.escape(item.series.label) + ': ' + item.datapoint[1]) + this.$tooltip.show() + .css({ top: item.pageY - 20 - this.$tooltip.height(), left: item.pageX - 0.5 * this.$tooltip.width(), opacity: 1 }) + } + else if (this.$tooltip) { + this.$tooltip.hide() + } + }, this)).on('mouseout', _.bind(function(){ + if (this.$tooltip) { + this.$tooltip.hide() + } + }, this)) + + this.fetchBuckets(); + } + }); +}); diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/service-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/service-view.js index 976c5c7160..c44807379f 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/service-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/service-view.js @@ -25,6 +25,7 @@ define([ 'find/app/page/search/results/entity-topic-map-view', 'find/app/page/search/results/sunburst-view', 'find/app/page/search/results/map-results-view', + 'find/app/page/search/results/dategraph/dategraph-view', 'find/app/page/search/results/table/table-view', 'find/app/page/search/time-bar-view', 'find/app/configuration', @@ -34,7 +35,7 @@ define([ ParametricCollection, ParametricFieldsCollection, queryStrategy, stateTokenStrategy, ResultsViewContainer, ResultsViewSelection, RelatedConceptsView, addChangeListener, SavedSearchControlView, TopicMapView, - SunburstView, MapResultsView, TableView, TimeBarView, configuration, i18n, templateString) { + SunburstView, MapResultsView, DateGraphView, TableView, TimeBarView, configuration, i18n, templateString) { 'use strict'; const $window = $(window); @@ -257,6 +258,17 @@ define([ displayNameKey: 'table', icon: 'hp-table' } + }, + dategraph: { + Constructor: DateGraphView, + constructorArguments: _.extend({ + timeBarModel: this.timeBarModel + }, subViewArguments), + shown: hasBiRole, + selector: { + displayNameKey: 'dategraph', + icon: 'hp-analytics' + } } }; diff --git a/webapp/core/src/main/public/static/js/find/nls/root/bundle.js b/webapp/core/src/main/public/static/js/find/nls/root/bundle.js index 93649f2973..8ce57a6109 100644 --- a/webapp/core/src/main/public/static/js/find/nls/root/bundle.js +++ b/webapp/core/src/main/public/static/js/find/nls/root/bundle.js @@ -207,6 +207,9 @@ define([ 'search.resultsView.amount.shown': 'Showing {0} to {1} of {2} results', 'search.resultsView.amount.shown.no.increment': 'Showing the top {0} results of {1}', 'search.resultsView.amount.shown.no.results': 'There are no results with the location field selected', + 'search.resultsView.dategraph': 'Date', + 'search.resultsView.dategraph.error': 'Failed to load data', + 'search.resultsView.dategraph.noValues': 'No values', 'search.answeredQuestion': 'Answered question', 'search.answeredQuestion.systemName': 'Answered by {0}', 'search.promoted': 'Promoted', diff --git a/webapp/core/src/main/public/static/js/find/templates/app/page/search/filters/parametric/parametric-select-modal-item-view.html b/webapp/core/src/main/public/static/js/find/templates/app/page/search/filters/parametric/parametric-select-modal-item-view.html index 3861a8adf6..7e84e166c8 100644 --- a/webapp/core/src/main/public/static/js/find/templates/app/page/search/filters/parametric/parametric-select-modal-item-view.html +++ b/webapp/core/src/main/public/static/js/find/templates/app/page/search/filters/parametric/parametric-select-modal-item-view.html @@ -1,4 +1,7 @@ \ No newline at end of file + +<% if (showGraphButtons) { %> + +<% } %> \ No newline at end of file diff --git a/webapp/core/src/main/public/static/js/find/templates/app/page/search/filters/parametric/parametric-value-view.html b/webapp/core/src/main/public/static/js/find/templates/app/page/search/filters/parametric/parametric-value-view.html index cb449082bd..e7c9dff453 100644 --- a/webapp/core/src/main/public/static/js/find/templates/app/page/search/filters/parametric/parametric-value-view.html +++ b/webapp/core/src/main/public/static/js/find/templates/app/page/search/filters/parametric/parametric-value-view.html @@ -5,3 +5,6 @@ + + + diff --git a/webapp/core/src/main/public/static/js/find/templates/app/page/search/results/dategraph/dategraph-view.html b/webapp/core/src/main/public/static/js/find/templates/app/page/search/results/dategraph/dategraph-view.html new file mode 100644 index 0000000000..bf9a4f611c --- /dev/null +++ b/webapp/core/src/main/public/static/js/find/templates/app/page/search/results/dategraph/dategraph-view.html @@ -0,0 +1,8 @@ +
+ PPTX +
+
<%- i18n['search.resultsView.dategraph.noValues'] %>
+
<%- i18n['search.resultsView.dategraph.error'] %>
+
<%= loadingHtml %>
+
+
\ No newline at end of file diff --git a/webapp/core/src/main/public/static/js/require-config.js b/webapp/core/src/main/public/static/js/require-config.js index fd202c9fc4..0914ddeeb9 100644 --- a/webapp/core/src/main/public/static/js/require-config.js +++ b/webapp/core/src/main/public/static/js/require-config.js @@ -39,7 +39,9 @@ require.config({ sunburst: '../bower_components/hp-autonomy-sunburst/src', topicmap: '../bower_components/hp-autonomy-topic-map/src', underscore: '../bower_components/underscore/underscore', - typeahead: '../bower_components/corejs-typeahead/dist/typeahead.jquery' + typeahead: '../bower_components/corejs-typeahead/dist/typeahead.jquery', + 'flot': '../bower_components/Flot/jquery.flot', + 'flot.time': '../bower_components/Flot/jquery.flot.time' }, shim: { 'backbone': { @@ -59,6 +61,8 @@ require.config({ exports: '_' }, 'Leaflet.awesome-markers': ['leaflet'], - 'leaflet.markercluster': ['leaflet'] + 'leaflet.markercluster': ['leaflet'], + 'flot': ['jquery'], + 'flot.time': ['flot'] } }); diff --git a/webapp/idol/src/main/resources/defaultIdolConfigFile.json b/webapp/idol/src/main/resources/defaultIdolConfigFile.json index f309c35364..dddfb2354e 100644 --- a/webapp/idol/src/main/resources/defaultIdolConfigFile.json +++ b/webapp/idol/src/main/resources/defaultIdolConfigFile.json @@ -126,7 +126,8 @@ "list", "sunburst", "table", - "map" + "map", + "dategraph" ], "user": [ "list" From 4b6bc6828c9697f260ec8e282323181ca097c840 Mon Sep 17 00:00:00 2001 From: Tung Jin Chew Date: Thu, 23 Feb 2017 19:25:15 +0000 Subject: [PATCH 2/9] Apply text-align: right to the parametric graph cell, it looks better when there's really large parametric counts. Avoiding using &:extend since that seems to generate multiple matching selectors, one of which is redundant and has its value overwritten by the other. --- webapp/core/src/main/less/app-include.less | 1 + 1 file changed, 1 insertion(+) diff --git a/webapp/core/src/main/less/app-include.less b/webapp/core/src/main/less/app-include.less index ca16d244a0..c4ed6ac848 100644 --- a/webapp/core/src/main/less/app-include.less +++ b/webapp/core/src/main/less/app-include.less @@ -1601,6 +1601,7 @@ input.find-input { .parametric-value-graph-cell { width: @custom3; + text-align: right; } .parametric-value-count,.parametric-value-graph { From 3fdf575a561f314cd6d985144e96a8ee83a7c92b Mon Sep 17 00:00:00 2001 From: Tung Jin Chew Date: Fri, 24 Feb 2017 12:41:06 +0000 Subject: [PATCH 3/9] i18n string for the default series label. Don't show the no-values text if the graph is still loading. --- .../app/page/search/results/dategraph/dategraph-view.js | 6 +++--- .../core/src/main/public/static/js/find/nls/root/bundle.js | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js index 19e8c6d6ba..85add206e3 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js @@ -59,7 +59,7 @@ define([ if (!this.hideMainPlot) { rows.push({ color: '#00B388', - label: 'Documents', + label: i18n['search.resultsView.dategraph.defaultSeriesLabel'], secondaryAxis: false, values: _.pluck(modelBuckets, 'count') }) @@ -135,7 +135,7 @@ define([ var noValues = !modelBuckets || !modelBuckets.length; this.$('.dategraph-view-error-message').toggleClass('hide', !hadError); - this.$('.dategraph-view-empty-text').toggleClass('hide', hadError || !noValues); + this.$('.dategraph-view-empty-text').toggleClass('hide', hadError || !noValues || fetching); var hideLoadingIndicator = hadError || !fetching; this.$('.dategraph-loading').toggleClass('hide', hideLoadingIndicator); @@ -155,7 +155,7 @@ define([ var data = (this.hideMainPlot ? [] : [{ color: '#00B388', - label: 'Documents', + label: i18n['search.resultsView.dategraph.defaultSeriesLabel'], data: transform(modelBuckets) }]).concat(_.map(this.plots, function(plot, idx, plots){ var label = plot.field.replace(/^.*\//, '').replace(/_/g, '\u00A0') + ': ' + plot.value; diff --git a/webapp/core/src/main/public/static/js/find/nls/root/bundle.js b/webapp/core/src/main/public/static/js/find/nls/root/bundle.js index 8ce57a6109..b7bee486ac 100644 --- a/webapp/core/src/main/public/static/js/find/nls/root/bundle.js +++ b/webapp/core/src/main/public/static/js/find/nls/root/bundle.js @@ -208,6 +208,7 @@ define([ 'search.resultsView.amount.shown.no.increment': 'Showing the top {0} results of {1}', 'search.resultsView.amount.shown.no.results': 'There are no results with the location field selected', 'search.resultsView.dategraph': 'Date', + 'search.resultsView.dategraph.defaultSeriesLabel': 'Documents', 'search.resultsView.dategraph.error': 'Failed to load data', 'search.resultsView.dategraph.noValues': 'No values', 'search.answeredQuestion': 'Answered question', From 0bb4b2b1b8df67825aa9a581b5686e9ae37858ae Mon Sep 17 00:00:00 2001 From: Tung Jin Chew Date: Fri, 24 Feb 2017 14:27:41 +0000 Subject: [PATCH 4/9] If you click on the parametric graphing buttons, jump straight to the dategraph page --- .../public/static/js/find/app/page/search/service-view.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/service-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/service-view.js index c44807379f..10da8e7b8b 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/service-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/service-view.js @@ -294,6 +294,10 @@ define([ views: this.resultsViews, model: this.resultsViewSelectionModel }); + + this.listenTo(this.queryModel.queryState.selectedParametricValues, 'graph', function(){ + this.resultsViewSelection.switchTab('dategraph') + }) } this.resultsViewContainer = new ResultsViewContainer({ From 4ab694453f13a5d1e94608dcea3b927ec3b1ff22 Mon Sep 17 00:00:00 2001 From: Tung Jin Chew Date: Mon, 27 Feb 2017 19:17:16 +0000 Subject: [PATCH 5/9] Disable dategraph powerpoint export buttons until data is available --- .../find/app/page/search/results/dategraph/dategraph-view.js | 3 +++ .../app/page/search/results/dategraph/dategraph-view.html | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js index 85add206e3..8aa7a88322 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js @@ -172,9 +172,12 @@ define([ xaxis: {mode: 'time'}, yaxes: multiAxes ? [ {}, { position: 'right' } ] : {} }) + + this.$('.dategraph-view-pptx').removeClass('disabled'); } else { $contentEl.empty(); + this.$('.dategraph-view-pptx').addClass('disabled'); } }, diff --git a/webapp/core/src/main/public/static/js/find/templates/app/page/search/results/dategraph/dategraph-view.html b/webapp/core/src/main/public/static/js/find/templates/app/page/search/results/dategraph/dategraph-view.html index bf9a4f611c..f7d6bf9d3b 100644 --- a/webapp/core/src/main/public/static/js/find/templates/app/page/search/results/dategraph/dategraph-view.html +++ b/webapp/core/src/main/public/static/js/find/templates/app/page/search/results/dategraph/dategraph-view.html @@ -1,5 +1,5 @@
- PPTX + PPTX
<%- i18n['search.resultsView.dategraph.noValues'] %>
<%- i18n['search.resultsView.dategraph.error'] %>
From d6d01aa1a9e9c1fdb75dc6b2091acc35941877f7 Mon Sep 17 00:00:00 2001 From: Tung Jin Chew Date: Tue, 28 Feb 2017 12:38:05 +0000 Subject: [PATCH 6/9] Specify minTickSize: 1 since there aren't fractional documents. --- .../app/page/search/results/dategraph/dategraph-view.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js index 8aa7a88322..76c74c533a 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js @@ -167,10 +167,16 @@ define([ } })) + var yaxes = [{ minTickSize: 1 }]; + + if (multiAxes) { + yaxes.push({ minTickSize: 1, position: 'right' }); + } + $.plot($contentEl[0], data, { grid: { hoverable: true }, xaxis: {mode: 'time'}, - yaxes: multiAxes ? [ {}, { position: 'right' } ] : {} + yaxes: yaxes }) this.$('.dategraph-view-pptx').removeClass('disabled'); From 62422171969d1d0410d8c15f533b6f43a6a9da95 Mon Sep 17 00:00:00 2001 From: Tung Jin Chew Date: Thu, 9 Mar 2017 13:37:16 +0000 Subject: [PATCH 7/9] Fix dategraph not updating if you change the date restrictions while it's not active --- .../app/page/search/results/dategraph/dategraph-view.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js index 76c74c533a..9eb4b1fc5d 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js @@ -122,6 +122,9 @@ define([ }, update: function() { + if(this.$el.is(':visible')) { + this.updateGraph(); + } }, updateGraph: function() { @@ -188,7 +191,10 @@ define([ }, fetchBuckets: function() { - var width = this.$('.dategraph-content').width(); + // We now use the width of the closest visible ancestor, even if this tab itself is currently hidden, + // since the filters may change when we're not looking at the screen; which gives zero width for + // the SVG if it's not on the screen, but we still need data. + var width = this.$('.dategraph-content').closest(':visible').width(); // If the SVG has no width or there are no values, there is no point fetching new data // if(width !== 0 && this.model.get('totalValues') !== 0) { From fd26b69b44555732c0b6728a52e90822d0b2d270 Mon Sep 17 00:00:00 2001 From: Tung Jin Chew Date: Fri, 10 Mar 2017 19:08:55 +0000 Subject: [PATCH 8/9] Merge dategraph updates to work with rebased code. --- .../find/app/page/search/results/dategraph/dategraph-view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js index 9eb4b1fc5d..b7b8a59f6b 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js @@ -100,7 +100,7 @@ define([ this.bucketModel = new BucketedParametricCollection.Model({id: this.fieldName}); this.selectedParametricValues = options.queryState.selectedParametricValues; - this.dateParametricFieldsCollection = options.dateParametricFieldsCollection; + this.parametricFieldsCollection = options.parametricFieldsCollection; this.listenTo(this.queryModel, 'change', this.fetchBuckets); @@ -211,7 +211,7 @@ define([ var minDate = this.queryModel.getIsoDate('minDate'); var maxDate = this.queryModel.getIsoDate('maxDate'); - var dateField = this.dateParametricFieldsCollection.find(dateModelMatching(this.fieldName, this.dataType)); + var dateField = this.parametricFieldsCollection.find(dateModelMatching(this.fieldName, this.dataType)); var baseParams = { queryText: this.queryModel.get('queryText'), From 439a809e99f8f9ee89510ecae07effda17dd2b6f Mon Sep 17 00:00:00 2001 From: Tung Jin Chew Date: Mon, 13 Mar 2017 12:16:22 +0000 Subject: [PATCH 9/9] Fix the dategraph to work with the rebased code --- .../app/page/search/results/dategraph/dategraph-view.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js index b7b8a59f6b..7637d6ed31 100644 --- a/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js +++ b/webapp/core/src/main/public/static/js/find/app/page/search/results/dategraph/dategraph-view.js @@ -33,7 +33,7 @@ define([ var upperCase = fieldName.toUpperCase(); return function(model) { - return model.get('field').toUpperCase() === upperCase && model.get('range') && model.get('dataType') === dataType; + return model.get('field').toUpperCase() === upperCase && model.get('range') && model.get('type') === dataType; }; } @@ -41,7 +41,7 @@ define([ var upperCase = fieldName.toUpperCase(); return function(model) { - return model.id.toUpperCase() === upperCase && model.get('dataType') === dataType; + return model.id.toUpperCase() === upperCase && model.get('type') === dataType; }; } @@ -96,7 +96,7 @@ define([ this.pixelsPerBucket = options.pixelsPerBucket || 20; this.fieldName = 'autn_date'; - this.dataType = 'date'; + this.dataType = 'NumericDate'; this.bucketModel = new BucketedParametricCollection.Model({id: this.fieldName}); this.selectedParametricValues = options.queryState.selectedParametricValues;