diff --git a/overviewer_core/data/js_src/util.js b/overviewer_core/data/js_src/util.js index 0e738da..3d6c36e 100644 --- a/overviewer_core/data/js_src/util.js +++ b/overviewer_core/data/js_src/util.js @@ -58,6 +58,10 @@ overviewer.util = { var coordsdiv = new overviewer.views.CoordboxView({tagName: 'DIV'}); coordsdiv.render(); + var progressdiv = new overviewer.views.ProgressView({tagName: 'DIV'}); + progressdiv.render(); + progressdiv.updateProgress(); + if (overviewer.collections.haveSigns) { var signs = new overviewer.views.SignControlView(); signs.registerEvents(signs); diff --git a/overviewer_core/data/js_src/views.js b/overviewer_core/data/js_src/views.js index 323c1fc..cbc6453 100644 --- a/overviewer_core/data/js_src/views.js +++ b/overviewer_core/data/js_src/views.js @@ -108,7 +108,26 @@ overviewer.views.CoordboxView = Backbone.View.extend({ } }); - +overviewer.views.ProgressView = Backbone.View.extend({ + initialize: function() { + this.el.id = 'progressDiv'; + this.el.innerHTML = 'Current Render Progress'; + overviewer.map.controls[google.maps.ControlPosition.BOTTOM_RIGHT].push(this.el); + this.hidden = true; + }, + updateProgress: function() { + e = this; + $.getJSON('progress.js', null, function(d){ + e.el.hidden = false; + e.el.innerHTML = d['message']; + if (d.update > 0) { + setTimeout("e.updateProgress()", d.update); + } else { + e.el.hidden = true; + } + }); + } +}); /* GoogleMapView is responsible for dealing with the GoogleMaps API to create the */ diff --git a/overviewer_core/data/web_assets/overviewer.css b/overviewer_core/data/web_assets/overviewer.css index 0ae76e5..e1f1527 100644 --- a/overviewer_core/data/web_assets/overviewer.css +++ b/overviewer_core/data/web_assets/overviewer.css @@ -86,7 +86,7 @@ body { } -#link, #coordsDiv { +#link, #coordsDiv, #progressDiv { background-color: #fff; /* fallback */ background-color: rgba(255,255,255,0.55); border: 1px solid rgb(0, 0, 0); diff --git a/overviewer_core/observer.py b/overviewer_core/observer.py index c58a0d9..15cb6d7 100644 --- a/overviewer_core/observer.py +++ b/overviewer_core/observer.py @@ -17,6 +17,7 @@ import time import logging import progressbar import sys +import os class Observer(object): """Base class that defines the observer interface. @@ -164,3 +165,98 @@ class ProgressBarObserver(progressbar.ProgressBar, Observer): def _need_update(self): return self.get_current_value() - self.last_update > self.UPDATE_INTERVAL + +class JSObserver(Observer): + """Display progress on index.html using JavaScript + """ + + def __init__(self, outputdir, minrefresh=5): + """Initialise observer + outputdir must be set to the map output directory path + minrefresh specifies the minimum gap between requests, in seconds + """ + self.last_update = -11 + self.last_update_time = -1 + self._current_value = -1 + self.minrefresh = 1000*minrefresh + self.logfile = os.path.join(outputdir, "progress.js") + + f = open(self.logfile, "w", 0) + f.write('{"message": "Render in progress", "update": %d}' % self.minrefresh) + f.close() + + def start(self, max_value): + f = open(self.logfile, "w", 0) + f.write('{"message": "Rendering %d tiles", "update": %s}' % (max_value, self.minrefresh) + self.start_time=time.time() + self._set_max_value(max_value) + + def is_started(self): + return self.start_time is not None + + def finish(self): + """Signals the end of the processes, should be called after the + process is done. + """ + self.end_time = time.time() + duration = self.end_time - self.start_time + f = open(self.logfile, "w", 0) + f.write('{"message": "Render completed in %dm %ds", "update": "false"}' % (duration//60, duration - duration//60)) + f.close() + + def is_finished(self): + return self.end_time is not None + + def is_running(self): + return self.is_started() and not self.is_finished() + + def add(self, amount): + """Shortcut to update by increments instead of absolute values. Zero + amounts are ignored. + """ + if amount: + self.update(self.get_current_value() + amount) + + def update(self, current_value): + """Set the progress value. Should be between 0 and max_value. Returns + whether this update is actually displayed. + """ + self._current_value = current_value + if self._need_update(): + refresh = max(1500*(time.time() - self.last_update_time), self.minrefresh) + f = open(self.logfile, "w", 0) + f.write('{"message": "Rendered %d of %d tiles (%d%%)", "update": %d }' % (self.get_current_value(), self.get_max_value(), self.get_percentage(), refresh)) + f.close() + self.last_update_time = time.time() + self.last_update = current_value + return True + return False + + def get_percentage(self): + """Get the current progress percentage. Assumes 100% if max_value is 0 + """ + if self.get_max_value() is 0: + return 100.0 + else: + return self.get_current_value() * 100.0 / self.get_max_value() + + def get_current_value(self): + return self._current_value + + def get_max_value(self): + return self._max_value + + def _set_max_value(self, max_value): + self._max_value = max_value + + def _need_update(self): + cur_val = self.get_current_value() + if (time.time() - self.last_update_time) <= self.minrefresh//1000: + return False + if cur_val < 100: + return cur_val - self.last_update > 10 + elif cur_val < 500: + return cur_val - self.last_update > 50 + else: + return cur_val - self.last_update > 100 + diff --git a/overviewer_core/settingsDefinition.py b/overviewer_core/settingsDefinition.py index d2e357c..cfb6539 100644 --- a/overviewer_core/settingsDefinition.py +++ b/overviewer_core/settingsDefinition.py @@ -45,7 +45,7 @@ from settingsValidators import * import util -from observer import ProgressBarObserver, LoggingObserver +from observer import ProgressBarObserver, LoggingObserver, JSObserver import platform import sys