Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/chart/chart.directive.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,21 @@ 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
params = targets: {}, metadata: {}
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)->
Expand Down Expand Up @@ -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?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ->
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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"
# --------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)

Expand Down
149 changes: 80 additions & 69 deletions src/services/highcharts-factory/highcharts-factory.svc.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {})->
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@settings can be removed from the this scope, and just be settings right?

Copy link
Copy Markdown
Contributor Author

@iseessel iseessel Feb 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EDIT: We can't remove settings from this, as it is called in #onChartNotify in chart-threshold.component.coffee

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok, do you think we should rename @options to @hcOptions or @highchartsOptions for clarity between options & settings?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah probably a good idea.

# 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: ->
Expand All @@ -86,11 +68,11 @@ angular
name = _.startCase _.trim name.toLowerCase().replace(/\s*projected\s*/, ' ')
"<strong>#{date}</strong><br>#{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:
Expand All @@ -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
Expand All @@ -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)
)