diff --git a/src/components/chart/chart.directive.coffee b/src/components/chart/chart.directive.coffee
index 10b84b25..cbad37f5 100644
--- a/src/components/chart/chart.directive.coffee
+++ b/src/components/chart/chart.directive.coffee
@@ -46,7 +46,7 @@ angular
$log.error(error)
(chartData) ->
userAgent = $window.navigator.userAgent
-
+
# Previously, this hack was only for Safari,
# then we activated it for chrome after release of version 51,
# now it becomes the default behaviour as IE11 has shown some unstability in the display of charts
diff --git a/src/components/widgets-common/chart-threshold/chart-threshold.component.coffee b/src/components/widgets-common/chart-threshold/chart-threshold.component.coffee
index d5d4cad2..6eed97c6 100644
--- a/src/components/widgets-common/chart-threshold/chart-threshold.component.coffee
+++ b/src/components/widgets-common/chart-threshold/chart-threshold.component.coffee
@@ -67,6 +67,10 @@ module.component('chartThreshold', {
, 100)
return
+ handleInvalidAlertAmount = ->
+ toastr.error("Please choose a number one or greater.", 'Error')
+ ctrl.loading = false
+
ctrl.saveKpi = ->
return if ctrl.loading
ctrl.loading = true
@@ -74,7 +78,10 @@ module.component('chartThreshold', {
params.targets[ctrl.kpi.watchables[0]] = [{
"#{ctrl.kpiTargetMode}": parseFloat(ctrl.draftTarget.value)
}]
- return unless ImpacKpisSvc.validateKpiTargets(params.targets)
+
+ unless ImpacKpisSvc.validateKpiTargets(params.targets)
+ return handleInvalidAlertAmount()
+
promise = if ctrl.isEditingKpi
ImpacKpisSvc.update(getKpi(), params, false).then(
(kpi)->
@@ -121,7 +128,7 @@ module.component('chartThreshold', {
onChartNotify = (chart)->
ctrl.chart = chart
return unless validateHistParameters()
- ctrl.chart.options.chartOnClickCallbacks.push(onChartClick)
+ ctrl.chart.addOnClickCallback(onChartClick)
_.each buildThresholdsFromKpis(), (threshold)->
thresholdSerie = ctrl.chart.findThreshold(threshold.kpiId)
thresholdSerie = ctrl.chart.addThreshold(threshold) unless thresholdSerie?
diff --git a/src/components/widgets/accounts-cash-balance/accounts-cash-balance.directive.coffee b/src/components/widgets/accounts-cash-balance/accounts-cash-balance.directive.coffee
index 6bc66080..b214fb59 100644
--- a/src/components/widgets/accounts-cash-balance/accounts-cash-balance.directive.coffee
+++ b/src/components/widgets/accounts-cash-balance/accounts-cash-balance.directive.coffee
@@ -4,11 +4,16 @@ module.controller('WidgetAccountsCashBalanceCtrl', ($scope, $q, $timeout, $filte
w = $scope.widget
# Define settings
- # --------------------------------------
+ # -------------------------------------
$scope.orgDeferred = $q.defer()
settingsPromises = [$scope.orgDeferred.promise]
+ # Setup Highcharts Options
+ # -------------------------------------
+ getPeriod = ->
+ w.metadata? && w.metadata.hist_parameters? && w.metadata.hist_parameters.period || 'MONTHLY'
+
# Widget specific methods
# --------------------------------------
w.initContext = ->
@@ -46,9 +51,6 @@ module.controller('WidgetAccountsCashBalanceCtrl', ($scope, $q, $timeout, $filte
return '#000' unless serie
serie.color
- getPeriod = ->
- w.metadata? && w.metadata.hist_parameters? && w.metadata.hist_parameters.period || 'MONTHLY'
-
getSerieByAccount = (series, account)->
_.find(series, (serie)-> (serie.id || serie.options && serie.options.id) == account.id)
@@ -79,19 +81,23 @@ module.controller('WidgetAccountsCashBalanceCtrl', ($scope, $q, $timeout, $filte
# Called after initContext - draws the chart using HighCharts
w.format = ->
- options =
- chartType: 'line'
- currency: w.metadata.currency
- period: getPeriod()
- showToday: true
- showLegend: false
- withZooming:
+ $timeout ->
+ _highChartOptions =
+ chartType: 'line'
+ currency: w.metadata.currency
+ period: getPeriod()
+ showToday: true
+ showLegend: false
+
+ # Add Custom Highchart Options.
+ $scope.chart = new HighchartsFactory($scope.chartId(), w.content.chart.series, _highChartOptions)
+ $scope.chart.addXAxisOptions({
defaults: w.metadata.xAxis
callback: onZoom
+ })
+ $scope.chart.removeLegend()
- $timeout ->
- $scope.chart ||= new HighchartsFactory($scope.chartId(), w.content.chart, options)
- $scope.chart.render(w.content.chart, options)
+ $scope.chart.render()
# Widget is ready: can trigger the "wait for settings to be ready"
# --------------------------------------
diff --git a/src/components/widgets/accounts-cash-projection/accounts-cash-projection.directive.coffee b/src/components/widgets/accounts-cash-projection/accounts-cash-projection.directive.coffee
index 40172fa7..107f9dc4 100644
--- a/src/components/widgets/accounts-cash-projection/accounts-cash-projection.directive.coffee
+++ b/src/components/widgets/accounts-cash-projection/accounts-cash-projection.directive.coffee
@@ -193,28 +193,26 @@ module.controller('WidgetAccountsCashProjectionCtrl', ($scope, $q, $filter, $tim
# Executed after the widget and its settings are initialised and ready
w.format = ->
- # Instantiate and render chart
- options =
+ _highChartOptions =
chartType: 'line'
- chartOnClickCallbacks: []
currency: w.metadata.currency
showToday: true
- showLegend: true
- withZooming:
- defaults: w.metadata.xAxis
- callback: onZoom
- $scope.chart ||= new HighchartsFactory($scope.chartId(), w.content.chart, options)
- $scope.chart.render(w.content.chart, options)
-
- # Add events callbacks to chart object
+ # Add custom options to the chart before render.
+ $scope.chart = new HighchartsFactory($scope.chartId(), w.content.chart.series, _highChartOptions)
$scope.chart.addCustomLegend(legendFormatter)
$scope.chart.addSeriesEvent('click', onClickBar)
$scope.chart.addSeriesEvent('legendItemClick', onClickLegend)
+ $scope.chart.addXAxisOptions(({
+ defaults: w.metadata.xAxis
+ callback: onZoom
+ }))
+ $scope.chart.render()
# Notifies parent element that the chart is ready to be displayed
$scope.chartDeferred.notify($scope.chart)
+
$scope.widgetDeferred.resolve(settingsPromises)
)
diff --git a/src/services/highcharts-factory/highcharts-factory.svc.coffee b/src/services/highcharts-factory/highcharts-factory.svc.coffee
index 30387801..69cf6494 100644
--- a/src/services/highcharts-factory/highcharts-factory.svc.coffee
+++ b/src/services/highcharts-factory/highcharts-factory.svc.coffee
@@ -4,69 +4,51 @@ angular
templates =
line: Object.freeze
- get: (series = [], options = {})->
- zoomingOptions = _.get(options, 'withZooming')
- xAxisOptions = if zoomingOptions?
- {
- events:
- setExtremes: zoomingOptions.callback
- max: _.get(zoomingOptions.defaults, 'max')
- min: _.get(zoomingOptions.defaults, 'min')
- }
-
- chart:
- type: 'line'
- zoomType: 'x'
- spacingTop: 20
- events:
- click: (event)-> _.each(_.get(options, 'chartOnClickCallbacks', []), (cb)-> cb(event))
+ chart:
+ type: 'line'
+ zoomType: 'x'
+ spacingTop: 20
+ legend:
+ enabled: true
+ layout: 'vertical'
+ align: 'left'
+ verticalAlign: 'middle'
+ title: null
+ credits:
+ enabled: false
+ yAxis:
title: null
- credits:
- enabled: false
- legend:
- enabled: _.get(options, 'showLegend', true)
- layout: 'vertical'
- align: 'left'
- verticalAlign: 'middle'
- xAxis: xAxisOptions
- yAxis:
- title: null
- startOnTick: true
- minPadding: 0
- series: series
- rangeSelector:
- buttons: [
- { type: 'month', count: 4, text: 'def.' },
- { type: 'month', count: 1, text: '1m' },
- { type: 'month', count: 3, text: '3m' },
- { type: 'month', count: 6, text: '6m' },
- { type: 'year', count: 1, text: '1y' },
- { type: 'all', text: 'All' }
- ]
- selected: (if _.get(xAxisOptions, 'min') then null else 0)
+ startOnTick: true
+ minPadding: 0
+ buttons: [
+ { type: 'month', count: 4, text: 'def.' },
+ { type: 'month', count: 1, text: '1m' },
+ { type: 'month', count: 3, text: '3m' },
+ { type: 'month', count: 6, text: '6m' },
+ { type: 'year', count: 1, text: '1y' },
+ { type: 'all', text: 'All' }
+ ]
todayUTC = moment().startOf('day').add(moment().utcOffset(), 'minutes')
class Chart
- constructor: (@id, @data = {}, @options = {})->
- @_template = templates[@options.chartType]
+ constructor: (@id, @series = {}, @settings = {})->
+ # Setup the basic options for highcharts.
+ template = templates[@settings.chartType]
+ formatters = @formatters(@settings.currency)
+ todayMarker = @todayMarker(@settings.showToday, @settings.markerColor)
+ onClickCallbacks = @onClickCallbacks(@settings.chartOnClickCallbacks)
+ series = { series: @series }
+ @highChartOptions = angular.merge({}, series, template, formatters, todayMarker, onClickCallbacks)
return
- render: (data, options)->
- @data = data if _.isObject(data)
- angular.extend(@options, options)
- chartConfig = angular.merge({}, @template(), @formatters(), @todayMarker())
- if _.isEmpty(@hc)
- @hc = Highcharts.stockChart(@id, chartConfig)
- else
- @hc.update(chartConfig)
+ render: () ->
+ # Options are already populated in the constructor, and through the options setter methods.
+ # It is faster to create a new stockChart than to update an existing one when data changes.
+ @hc = Highcharts.stockChart(@id, @highChartOptions)
return @
- template: ->
- @_template.get(@data.series, @options)
-
- formatters: ->
- currency = @options.currency
+ formatters: (currency) ->
xAxis:
labels:
formatter: ->
@@ -86,11 +68,11 @@ angular
name = _.startCase _.trim name.toLowerCase().replace(/\s*projected\s*/, ' ')
"#{date}
#{name}: #{amount}"
- todayMarker: ->
- return {} unless @options.showToday
+ todayMarker: (showToday, markerColor = 'rgba(0, 85, 255, 0.2)') ->
+ return {} unless showToday
xAxis:
plotLines: [{
- color: _.get(@options, 'todayMarkerColor', 'rgba(0, 85, 255, 0.2)')
+ color: markerColor
value: todayUTC.unix() * 1000
width: 1
label:
@@ -104,7 +86,7 @@ angular
addThreshold: (thresholdOptions)->
return if _.isEmpty(@hc)
# Initialize data matrix
- data = angular.copy @data.series[0].data
+ data = angular.copy @series[0].data
for vector in data
# When in the past, set y-axis value at null
if !thresholdOptions.fullLengthThresholds && moment(vector[0]) < todayUTC
@@ -130,22 +112,51 @@ angular
return unless thresholdSerie? && eventName? && _.isFunction(callback)
Highcharts.addEvent(thresholdSerie, eventName, (_event)-> callback(thresholdSerie))
- # Extend default chart formatters to add custom legend img icon
- addCustomLegend: (formatterCallback, useHTML = true) ->
- @hc.legend.update({
- useHTML: useHTML
- labelFormatter: formatterCallback
- })
+ addCustomLegend: (labelFormatter, useHTML = true, showLegend = true) ->
+ legend =
+ legend:
+ labelFormatter: labelFormatter
+ useHTML: useHTML
+ enabled: showLegend
+ angular.merge(@highChartOptions, legend)
+
+ removeLegend: () ->
+ legend =
+ legend:
+ enabled: false
+ angular.merge(@highChartOptions, legend)
- # Adds events to series objects
addSeriesEvent: (eventName, callback) ->
- return if _.isEmpty(@hc)
eventHash = {}
eventHash[eventName] = callback
- @hc.update({
+ plotOptions =
plotOptions:
series:
events: eventHash
- })
- @hc
+ angular.merge(@highChartOptions, plotOptions)
+
+ onClickCallbacks: (chartOnClickCallbacks = []) ->
+ # We need onClickCallbacks pointing to settings.onClickCallbacks, so that we can add callbacks to the settings later on.
+ @settings.chartOnClickCallbacks = chartOnClickCallbacks
+ click = (event) -> _.each(@settings.chartOnClickCallbacks, (cb) -> cb(event))
+ chart:
+ events:
+ click: click.bind(@)
+
+ addOnClickCallback: (event) ->
+ @settings.chartOnClickCallbacks.push(event)
+
+ addXAxisOptions: (zoomingOptions) ->
+ xAxisOptions = if zoomingOptions?
+ events:
+ setExtremes: zoomingOptions.callback
+ max: _.get(zoomingOptions.defaults, 'max')
+ min: _.get(zoomingOptions.defaults, 'min')
+
+ xAxis =
+ xAxis: xAxisOptions
+ rangeSelector:
+ selected: (if _.get(xAxisOptions, 'min') then null else 0)
+
+ angular.merge(@highChartOptions, xAxis)
)