diff --git a/helpers/trendings_helper.py b/helpers/trendings_helper.py
index b85caca..06951bb 100644
--- a/helpers/trendings_helper.py
+++ b/helpers/trendings_helper.py
@@ -158,3 +158,43 @@ class Trendings_helper:
tagSet.add(tag['name'])
to_ret[self.keyTag] = list(tagSet)
return to_ret
+
+ # In contrary of getGenericTrending, it regroups items in the format: {item, start: timestamp1, end: timestamp2}
+ # so that it can be displayed easily on the timeline.
+ def getGenericTrendingOvertime(self, dateS, dateE, trendingType=None, topNum=0):
+ trendingType = self.keyEvent
+ dico_items = {}
+ to_format = []
+ prev_days = (dateE - dateS).days
+ # get data
+ for curDate in util.getXPrevDaysSpan(dateE, prev_days):
+ keyname = "{}:{}".format(trendingType, util.getDateStrFormat(curDate))
+ data = self.serv_redis_db.zrange(keyname, 0, topNum-1, desc=True, withscores=True)
+ data = [ [record[0].decode('utf8'), record[1]] for record in data ]
+ data = data if data is not None else []
+ to_format.append([util.getTimestamp(curDate), data])
+
+ for timestamp, array in to_format:
+ for item, _ in array:
+ if item not in dico_items:
+ dico_items[item] = []
+ dico_items[item].append(timestamp)
+
+ # sort timestamps in correct order
+ for item in dico_items.keys():
+ dico_items[item].sort()
+ # dico_items have the form: {item: [t1,t2,t4], ...}
+ to_ret = []
+ ONEDAY = 60*60*24
+ for item, timestamps in dico_items.items():
+ obj = {'name': item, 'start': timestamps[0]-ONEDAY, 'end': timestamps[0]}
+ for t in timestamps:
+ if t-obj['end'] > ONEDAY: #new entry
+ to_ret.append(obj)
+ obj['start'] = t-ONEDAY
+ obj['end'] = t
+ else: # contrinue entry
+ obj['end'] = t
+ to_ret.append(obj)
+
+ return to_ret
diff --git a/install_dependencies.sh b/install_dependencies.sh
index 420fade..7c98f8b 100755
--- a/install_dependencies.sh
+++ b/install_dependencies.sh
@@ -108,4 +108,9 @@ mv temp/jquery-punchcard/src/punchcard.js ./static/js
mv temp/jquery-punchcard/src/punchcard.css ./static/css
wget https://momentjs.com/downloads/moment.js -O ./static/js/moment.js
+# timeline
+VISJS_VERSION="4.21.0"
+https://cdnjs.cloudflare.com/ajax/libs/vis/${VISJS_VERSION}/vis.min.js
+https://cdnjs.cloudflare.com/ajax/libs/vis/${VISJS_VERSION}/vis.min.css
+
rm -rf ./temp
diff --git a/server.py b/server.py
index ee57001..a23e40d 100755
--- a/server.py
+++ b/server.py
@@ -536,5 +536,17 @@ def getTypeaheadData():
data = trendings_helper.getTypeaheadData(dateS, dateE)
return jsonify(data)
+@app.route("/_getGenericTrendingOvertime")
+def getGenericTrendingOvertime():
+ try:
+ dateS = datetime.datetime.fromtimestamp(float(request.args.get('dateS')))
+ dateE = datetime.datetime.fromtimestamp(float(request.args.get('dateE')))
+ except:
+ dateS = datetime.datetime.now() - datetime.timedelta(days=7)
+ dateE = datetime.datetime.now()
+
+ data = trendings_helper.getGenericTrendingOvertime(dateS, dateE)
+ return jsonify(data)
+
if __name__ == '__main__':
app.run(host='localhost', port=8001, threaded=True)
diff --git a/static/js/trendings.js b/static/js/trendings.js
index 79741e9..7d38216 100644
--- a/static/js/trendings.js
+++ b/static/js/trendings.js
@@ -9,6 +9,7 @@ var tagPie = ["#tagPie"];
var tagLine = ["#tagLine"];
var sightingLineWidget;
var discLine = ["#discussionLine"];
+var timeline;
var allData;
var globalColorMapping = {};
@@ -103,6 +104,8 @@ var typeaheadOption_tag = {
updateLineForLabel(tagLine, tag, undefined, url_getTrendingTag);
}
}
+var timeline_option = {};
+
/* FUNCTIONS */
function getColor(label) {
@@ -396,6 +399,29 @@ function updateDisc() {
});
}
+function updateTimeline() {
+ $.getJSON( url_getGenericTrendingOvertime+"?dateS="+parseInt(dateStart.getTime()/1000)+"&dateE="+parseInt(dateEnd.getTime()/1000), function( data ) {
+ var items = [];
+ var i = 1;
+ for (var obj of data) {
+ if (obj.end == obj.start) { console.log(obj);}
+ items.push({
+ id: i,
+ content: obj.name,
+ start: obj.start*1000,
+ end: obj.end*1000
+ });
+ i++;
+ }
+ items = new vis.DataSet(items);
+ if (timeline === undefined) { // create timeline
+ timeline = new vis.Timeline(document.getElementById('timeline'), items, timeline_option);
+ } else { // update
+ timeline.setItems(items);
+ }
+ });
+}
+
function dateChanged() {
dateStart = datePickerWidgetStart.datepicker( "getDate" );
dateEnd = datePickerWidgetEnd.datepicker( "getDate" );
@@ -404,6 +430,7 @@ function dateChanged() {
updatePieLine(tagPie, tagLine, url_getTrendingTag);
updateSignthingsChart();
updateDisc();
+ updateTimeline();
}
$(document).ready(function () {
@@ -426,6 +453,7 @@ $(document).ready(function () {
updatePieLine(tagPie, tagLine, url_getTrendingTag)
updateSignthingsChart();
updateDisc();
+ updateTimeline();
$( "#num_selector" ).change(function() {
var sel = parseInt($( this ).val());
@@ -437,5 +465,4 @@ $(document).ready(function () {
position: "absolute",
display: "none",
}).appendTo("body");
-
});
diff --git a/templates/trendings.html b/templates/trendings.html
index 924e316..2a71b7e 100644
--- a/templates/trendings.html
+++ b/templates/trendings.html
@@ -36,6 +36,9 @@
+
+
+