-
Eike Cochu authoredEike Cochu authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
controllers.js 58.70 KiB
/******************************************************************************
* Vipra Application
* Controllers
******************************************************************************/
/* globals angular, Vipra, moment, vis, prompt, randomColor, Highcharts, $ */
(function() {
"use strict";
var app = angular.module('vipra.controllers', []);
app.controller('RootController', ['$scope', '$rootScope', '$state', '$window', 'hotkeys', 'TopicModelFactory',
function($scope, $rootScope, $state, $window, hotkeys, TopicModelFactory) {
$scope.rootModels = {
topicModel: null,
search: null
};
var prevTopicModelLoading = false;
if (localStorage.tm) {
prevTopicModelLoading = true;
$rootScope.loadingScreen = true;
TopicModelFactory.get({
id: localStorage.tm
}, function(data) {
$scope.rootModels.topicModel = data;
prevTopicModelLoading = false;
$scope.loadingScreen = false;
}, function() {
delete localStorage.tm;
prevTopicModelLoading = false;
$scope.loadingScreen = false;
$scope.chooseTopicModel();
});
}
$scope.queryTopicModels = function() {
TopicModelFactory.query({
fields: '_all'
}, function(data) {
$scope.topicModels = data;
});
};
$scope.chooseTopicModel = function() {
if (prevTopicModelLoading)
return;
$scope.queryTopicModels();
$scope.rootModels.topicModelModalOpen = true;
$('#topicModelModal').modal();
if ($scope.rootModels.topicModel)
$('.selected-model').focus();
else
$('.topic-model').first().focus();
};
$scope.changeTopicModel = function(topicModel) {
$scope.rootModels.topicModel = topicModel;
$('#topicModelModal').modal('hide');
localStorage.tm = topicModel.id;
};
$scope.showFeedbackModal = function() {
$('#feedbackModal').modal();
$('#feedbackIframe').attr('src', 'https://docs.google.com/forms/d/1RjXyGgw8F3v7QsfgOQKz0Koa2Dkr1wDNx3veRZr9I3o/viewform?embedded=true');
};
$scope.menubarSearch = function(query) {
$state.transitionTo('index', {
q: query
});
};
$scope.goBack = function() {
$window.history.back();
};
$scope.$on('$stateChangeSuccess', function() {
$scope.rootModels.search = null;
});
hotkeys.add({
combo: 's',
description: 'Search for articles',
callback: function($event) {
if ($event.stopPropagation) $event.stopPropagation();
if ($event.preventDefault) $event.preventDefault();
if ($state.current.name === 'index')
$('#searchBox').focus();
else
$('#menuSearchBox').focus();
}
});
hotkeys.add({
combo: 'i',
description: 'Go to index',
callback: function() {
if ($scope.rootModels.topicModel && $state.current.name !== 'index')
$state.transitionTo('index');
}
});
hotkeys.add({
combo: 'e',
description: 'Go to explorer',
callback: function() {
if ($scope.rootModels.topicModel && $state.current.name !== 'explorer')
$state.transitionTo('explorer');
}
});
hotkeys.add({
combo: 'n',
description: 'Go to network',
callback: function() {
if ($scope.rootModels.topicModel && $state.current.name !== 'network')
$state.transitionTo('network');
}
});
hotkeys.add({
combo: 'a',
description: 'Go to articles',
callback: function() {
if ($scope.rootModels.topicModel && $state.current.name !== 'articles')
$state.transitionTo('articles');
}
});
hotkeys.add({
combo: 't',
description: 'Go to topics',
callback: function() {
if ($scope.rootModels.topicModel && $state.current.name !== 'topics')
$state.transitionTo('topics');
}
});
hotkeys.add({
combo: 'i',
description: 'Go to entities',
callback: function() {
if ($scope.rootModels.topicModel && $state.current.name !== 'entities')
$state.transitionTo('entities');
}
});
hotkeys.add({
combo: 'w',
description: 'Go to words',
callback: function() {
if ($scope.rootModels.topicModel && $state.current.name !== 'words')
$state.transitionTo('words');
}
});
hotkeys.add({
combo: 'm',
description: 'Choose a topic model',
callback: function() {
$scope.chooseTopicModel();
}
});
$scope.showCheatSheet = hotkeys.toggleCheatSheet;
}
]);
/**
* Index controller
*/
app.controller('IndexController', ['$scope', '$stateParams', '$location', '$timeout', 'ArticleFactory', 'TopicFactory', 'SearchFactory',
function($scope, $stateParams, $location, $timeout, ArticleFactory, TopicFactory, SearchFactory) {
// page was reloaded, choose topic model
if (!$scope.rootModels.topicModel)
$scope.chooseTopicModel();
$scope.searchResultsStep = 10;
$scope.advancedSearchEnabled = false;
$scope.search = $stateParams.q || $scope.search;
$scope.$watch('rootModels.topicModel', function() {
if (!$scope.rootModels.topicModel) return;
ArticleFactory.query({
topicModel: $scope.rootModels.topicModel.id,
limit: 3,
sort: '-created'
}, function(data) {
$scope.latestArticles = data;
});
TopicFactory.query({
topicModel: $scope.rootModels.topicModel.id,
limit: 3,
sort: '-created'
}, function(data) {
$scope.latestTopics = data;
});
});
$scope.$watchGroup(['search', 'rootModels.topicModel', 'rootModels.advFromDate', 'rootModels.advToDate'], function() {
if ($scope.search && $scope.rootModels.topicModel) {
$location.search('q', $scope.search);
$scope.goSearch();
} else {
$location.search('q', null);
$scope.searchResults = [];
}
});
$scope.goSearch = function() {
$scope.searching = true;
$scope.skip = 0;
$scope.searchResults = [];
$scope.loadMoreResults();
};
$scope.loadMoreResults = function() {
SearchFactory.query({
topicModel: $scope.rootModels.topicModel.id,
skip: $scope.skip,
limit: $scope.searchResultsStep,
query: $scope.search,
from: $scope.rootModels.advFromDate ? $scope.rootModels.advFromDate.getTime() : null,
to: $scope.rootModels.advToDate ? $scope.rootModels.advToDate.getTime() : null
}, function(data, headers) {
$scope.searching = false;
$scope.searchResults.push.apply($scope.searchResults, data);
$scope.skip += $scope.searchResultsStep;
$scope.totalResults = headers("V-Total");
$scope.noMoreResults = data.length < $scope.searchResultsStep;
}, function() {
$scope.searching = false;
});
};
}
]);
/**
* About controller
*/
app.controller('AboutController', ['$scope', 'InfoFactory',
function($scope, InfoFactory) {
InfoFactory.get(function(data) {
$scope.info = data;
$scope.buildDate = Vipra.formatDateTime(moment($scope.info.app.builddate, 'YYMMDD_HHmm').toDate());
$scope.startTime = Vipra.formatDateTime(moment($scope.info.vm.starttime, 'x').toDate());
$scope.upTime = moment.duration($scope.info.vm.uptime).humanize();
});
}
]);
/**
* Network controller
*/
app.controller('NetworkController', ['$scope', '$state', '$stateParams', '$timeout', 'ArticleFactory', 'TopicFactory', 'WordFactory', 'WindowFactory',
function($scope, $state, $stateParams, $timeout, ArticleFactory, TopicFactory, WordFactory, WindowFactory) {
var id = 0,
ids = {},
edges = {};
$scope.colors = {
articles: '#BBC9D2',
topics: '#DBB234',
words: '#FFFFFF'
};
$scope.nodes = new vis.DataSet();
$scope.edges = new vis.DataSet();
$scope.data = {
nodes: $scope.nodes,
edges: $scope.edges
};
$scope.options = {
nodes: {
font: {
size: 14
},
shape: 'dot',
borderWidth: 1
},
edges: {
color: {
highlight: '#f00'
}
},
layout: {
randomSeed: 1
},
physics: {
barnesHut: {
springConstant: 0.008,
gravitationalConstant: -3500
}
},
interaction: {
tooltipDelay: 200,
hideEdgesOnDrag: true
}
};
$scope.shown = {
articles: true,
similararticles: false,
topics: true,
words: false
};
var newNode = function(title, type, show, dbid, color, shape, loader, x, y) {
ids[dbid] = ++id;
return {
id: id,
x: x,
y: y,
title: title,
label: title.multiline(5).ellipsize(50),
type: type,
show: show,
dbid: dbid,
shape: shape || 'dot',
loader: loader,
borderWidth: 1,
origColor: {
background: color,
highlight: {
background: color,
}
},
color: {
border: '#000',
background: color,
highlight: {
background: color,
}
},
font: {
color: '#000'
},
shadow: {
enabled: true
}
};
};
var newEdge = function(from, to) {
return {
from: from,
to: to,
selectionWidth: 1,
color: {
color: '#333',
highlight: '#f00'
}
};
};
var topicNode = function(topic, x, y) {
topic = topic.topic || topic;
return newNode(topic.name, 'topic', 'topics.show', topic.id, $scope.colors.topics, 'triangle', $scope.loadTopic, x, y);
};
var articleNode = function(article, x, y) {
return newNode(article.title, 'article', 'articles.show', article.id, $scope.colors.articles, 'square', $scope.loadArticle, x, y);
};
var wordNode = function(word, x, y) {
return newNode(word.id, 'word', 'words.show', word.id, $scope.colors.words, 'box', $scope.loadWord, x, y);
};
var edgeExists = function(idA, idB) {
if (idB < idA) {
var tmp = idA;
idA = idB;
idB = tmp;
}
return edges.hasOwnProperty(idA + '-' + idB);
};
var addEdge = function(idA, idB) {
if (idB < idA) {
var tmp = idA;
idA = idB;
idB = tmp;
}
edges[idA + '-' + idB] = 1;
};
// construct new nodes
var constructor = function(result, nodeFunction, node, props) {
if (result) {
var newNodes = [],
newEdges = [];
for (var i = 0; i < result.length; i++) {
var current = result[i];
if (ids.hasOwnProperty(current.id)) {
if (node && edgeExists(ids[current.id], node.id))
continue;
if(node) {
newEdges.push(newEdge(ids[current.id], node.id));
addEdge(ids[current.id], node.id);
}
} else {
if(node) {
if(props) {
newNodes.push(nodeFunction(current, props.pointer.canvas.x, props.pointer.canvas.y));
} else {
newNodes.push(nodeFunction(current));
}
newEdges.push(newEdge(id, node.id));
addEdge(id, node.id);
} else {
newNodes.push(nodeFunction(current));
}
}
}
if (newNodes.length)
$scope.nodes.add(newNodes);
if (newEdges.length)
$scope.edges.add(newEdges);
}
};
// on node select
$scope.select = function(props) {
var node = $scope.nodes.get(props.nodes[0]);
if (node && !node.loaded) {
node.loader(node, props);
node.loaded = true;
$scope.nodes.update(node);
}
};
$scope.deselect = function() {
$scope.$apply(function() {
$scope.currentArticle = null;
});
};
$scope.loadArticle = function(node, props) {
ArticleFactory.get({
id: node.dbid,
fields: '_all'
}, function(data) {
$scope.currentArticle = data;
var i;
if (data.topics) {
for (i = 0; i < data.topics.length; i++)
data.topics[i] = data.topics[i].topic;
constructor(data.topics, topicNode, node, props);
}
if (data.similarArticles && $scope.shown.similararticles) {
var articles = [];
for (i = 0; i < data.similarArticles.length; i++)
articles.push(data.similarArticles[i].article);
constructor(articles, articleNode, node, props);
}
});
};
$scope.loadTopic = function(node, props) {
if ($scope.shown.articles) {
TopicFactory.articles({
id: node.dbid,
limit: 50
}, function(data) {
constructor(data, articleNode, node, props);
});
}
if ($scope.shown.words) {
TopicFactory.get({
id: node.dbid,
limit: 50
}, function(data) {
constructor(data.words, wordNode, node, props);
});
}
};
$scope.loadWord = function(node, props) {
if ($scope.shown.articles) {
ArticleFactory.query({
word: node.dbid,
topicModel: $scope.rootModels.topicModel.id,
limit: 50
}, function(data) {
constructor(data, articleNode, node, props);
});
}
if ($scope.shown.topics) {
TopicFactory.query({
word: node.dbid,
topicModel: $scope.rootModels.topicModel.id,
limit: 50
}, function(data) {
constructor(data, topicNode, node, props);
});
}
};
// on node open
$scope.open = function(props) {
var node = $scope.nodes.get(props.nodes[0]);
$state.transitionTo(node.show, {
id: node.dbid
});
};
$scope.reset = function() {
$state.go($state.current, {}, {
reload: true
});
};
$scope.fit = function() {
$scope.graph.fit({
animation: {
offset: {x: 0, y: 0},
duration: 1000,
easingFunction: 'easeInOutQuad'
}
});
};
$scope.completeNetwork = function() {
var nodes = $scope.nodes.get(),
updates = [];
for(var i = 0; i < nodes.length; i++)
nodes[i].loader(nodes[i]);
$scope.nodes.update(updates);
};
$scope.$watch('rootModels.topicModel', function(newVal) {
if ($scope.rootNode && $scope.rootNode.topicModel.id !== newVal.id)
$state.transitionTo('index');
});
$scope.$watch('searchNodes', function() {
var nodes = $scope.nodes.get();
var i;
var updates = [];
if($scope.searchNodes) {
for(i = 0; i < nodes.length; i++) {
if(nodes[i].title.indexOf($scope.searchNodes) != -1) {
updates.push({
id: nodes[i].id,
color: nodes[i].origColor,
font: {
color: '#000'
}
});
} else {
updates.push({
id: nodes[i].id,
color: {
background: '#eee'
},
font: {
color: '#ccc'
}
});
}
}
} else {
for(i = 0; i < nodes.length; i++) {
updates.push({
id: nodes[i].id,
color: nodes[i].origColor,
font: {
color: '#000'
}
});
}
}
$scope.data.nodes.update(updates);
});
// create graph
var container = document.getElementById("visgraph");
$scope.graph = new vis.Network(container, $scope.data, $scope.options);
$scope.graph.on('selectNode', $scope.select);
$scope.graph.on('deselectNode', $scope.deselect);
$scope.graph.on('doubleClick', $scope.open);
if($stateParams.type) {
// if the topic model is not set, the page was refreshed
// set to true, id of current node decides topic model
if (!$scope.rootModels.topicModel)
$scope.rootModels.topicModel = true;
// type is given, load node
var factory;
if ($stateParams.type === 'articles')
factory = ArticleFactory;
else if ($stateParams.type === 'topics')
factory = TopicFactory;
else if ($stateParams.type === 'word')
factory = WordFactory;
// get root node
factory.get({
id: $stateParams.id
}, function(data) {
$scope.rootNode = data;
// add root node
if ($stateParams.type === 'articles')
$scope.nodes.add([articleNode(data)]);
else if ($stateParams.type === 'topics')
$scope.nodes.add([topicNode(data)]);
else if ($stateParams.type === 'words')
$scope.nodes.add([wordNode(data)]);
ids[data.id] = id;
// take topic model from node
if (!angular.isObject($scope.rootModels.topicModel))
$scope.rootModels.topicModel = data.topicModel;
});
} else {
$scope.queryTopics = function() {
if ($scope.shown.topics) {
TopicFactory.query({
topicModel: $scope.rootModels.topicModel.id
}, function(data) {
constructor(data, topicNode);
});
}
};
$scope.$watch('rootModels.topicModel', function() {
$scope.queryTopics();
});
// page was reloaded, choose topic model
if (!$scope.rootModels.topicModel)
$scope.chooseTopicModel();
else
$scope.queryTopics();
}
$scope.reloadWindows = function() {
if(!$scope.rootModels.topicModel) return;
WindowFactory.query({
topicModel: $scope.rootModels.topicModel.id
}, function(data) {
$scope.windows = data;
});
};
$scope.$watch('rootModels.topicModel', function() {
$scope.reloadWindows();
});
}
]);
app.controller('ExplorerController', ['$scope', '$templateCache', '$timeout', 'TopicFactory',
function($scope, $templateCache, $timeout, TopicFactory) {
// page was reloaded, choose topic model
if (!$scope.rootModels.topicModel)
$scope.chooseTopicModel();
$scope.reflowCharts = function() {
var topicHC = $('#topicRelChart').highcharts();
if (topicHC) topicHC.reflow();
var wordHC = $('#wordEvoChart').highcharts();
if (wordHC) wordHC.reflow();
};
$timeout(function() {
$('#outer').layout({
applyDefaultStyles: true,
south__size: '50%'
});
$('#upper').layout({
applyDefaultStyles: true,
center__onresize: function() {
$scope.reflowCharts();
},
west: {
size: 250
}
});
$('#lower').layout({
applyDefaultStyles: true,
center__onresize: function() {
$scope.reflowCharts();
},
west: {
size: 250
}
});
});
var avgMax = 0,
varMax = 0,
fallingMax = 0,
risingMax = 0,
risingDecayMax = 0,
risingDecayMin = 0;
$scope.explorerModels = {
sorttopics: 'name',
sortdir: false,
seqstyle: 'absolute',
chartstyle: 'areaspline',
chartstack: 'none',
articlesSort: 'title'
};
$scope.$watch('rootModels.topicModel', function() {
if (!$scope.rootModels.topicModel) return;
TopicFactory.query({
fields: 'name,sequences,avgRelevance,varRelevance,risingRelevance,fallingRelevance,risingDecayRelevance,words',
topicModel: $scope.rootModels.topicModel.id
}, function(data) {
$scope.topics = data;
var colors = randomColor({
count: $scope.topics.length
});
for (var i = 0, t; i < $scope.topics.length; i++) {
t = $scope.topics[i];
t.color = colors[i];
avgMax = Math.max(t.avgRelevance, avgMax);
varMax = Math.max(t.varRelevance, varMax);
fallingMax = Math.max(t.fallingRelevance, fallingMax);
risingMax = Math.max(t.risingRelevance, risingMax);
risingDecayMax = Math.max(t.risingDecayRelevance, risingDecayMax);
risingDecayMin = Math.max(t.risingDecayRelevance, risingDecayMin);
}
risingDecayMin = Math.abs(risingDecayMin);
risingDecayMax = risingDecayMin + Math.abs(risingDecayMax);
$scope.redrawGraph();
});
});
$scope.checkTopics = function(to) {
var toggle = typeof to === 'undefined';
for (var i = 0, t; i < $scope.topics.length; i++) {
t = $scope.topics[i];
t.selected = toggle ? !t.selected : to;
}
$scope.redrawGraph();
$scope.changeSelectedTopics();
};
$scope.changeSelectedTopics = function() {
if($scope.explorerModels.activeTopic && !$scope.explorerModels.activeTopic.selected) {
delete $scope.explorerModels.activeTopic;
delete $scope.explorerModels.activeSequence;
}
$scope.redrawGraph();
};
$scope.redrawGraph = function() {
if (!$scope.topics) return;
var series = [];
// create series of selected topics
for (var i = 0; i < $scope.topics.length; i++) {
if ($scope.topics[i].selected) {
var topic = $scope.topics[i],
relevances = [];
// data array with relevances and min/max
for (var j = 0, sequence, relevance; j < topic.sequences.length; j++) {
sequence = topic.sequences[j];
relevance = $scope.explorerModels.seqstyle === 'relative' ? sequence.relevanceChange : sequence.relevance;
relevances.push({
x: new Date(sequence.window.startDate).getTime(),
y: relevance,
sequence: sequence,
topic: topic
});
}
series.push({
id: topic.id,
name: topic.name,
data: relevances,
color: topic.color,
topic: topic,
zIndex: i + 1
});
}
}
// highcharts configuration
$scope.topicSeq = areaRelevanceChart(series, 'Topic Relevance', $scope.explorerModels.chartstyle,
$scope.explorerModels.chartstack, $scope.pointSelected);
$scope.topicsSelected = series.length;
};
$scope.topicCurrValue = function(topic) {
var percent = 0;
switch ($scope.explorerModels.sorttopics) {
case 'avgRelevance':
percent = topic.avgRelevance / avgMax;
break;
case 'varRelevance':
percent = topic.varRelevance / varMax;
break;
case 'fallingRelevance':
percent = topic.fallingRelevance / fallingMax;
break;
case 'risingRelevance':
percent = topic.risingRelevance / risingMax;
break;
case 'risingDecayRelevance':
percent = (topic.risingDecayRelevance + risingDecayMin) / risingDecayMax;
break;
}
return (percent * 100) + '%';
};
$scope.highlightSeries = function(id, toggle) {
if (!$scope.topicsSelected) return;
var highcharts = $('#topicRelChart').highcharts();
if (!highcharts) return;
var series = highcharts.get(id);
if (!series) return;
if (toggle) {
series.onMouseOver();
series.group.zIndexOrig = series.group.zIndex;
series.group.zIndexSetter(9999, 'zIndex');
series.graph.attr('stroke', '#000000').attr('stroke-dasharray', '5,5');
} else {
series.onMouseOut();
series.group.zIndexSetter(series.group.zIndexOrig, 'zIndex');
series.graph.attr('stroke', series.color).attr('stroke-dasharray', '');
}
};
$scope.resetZoom = function() {
if (!$scope.topicsSelected) return;
var highcharts = $('#topicRelChart').highcharts();
if (!highcharts) return;
highcharts.xAxis[0].setExtremes(null, null);
};
$scope.pointSelected = function(e) {
$scope.$apply(function() {
$scope.activateTopic(e.point.topic);
$scope.activateSequence(e.point.sequence);
});
};
$scope.activateTopic = function(topic) {
$scope.explorerModels.activeTopic = topic;
};
$scope.activateSequence = function(seq) {
$scope.explorerModels.activeSequence = seq;
};
$scope.clearSequence = function() {
if(!$scope.explorerModels.activeSequence) return;
delete $scope.explorerModels.activeSequence;
delete $scope.articles;
var selectedPoints = $('#topicRelChart').highcharts().getSelectedPoints();
for(var i = 0; i < selectedPoints.length; i++) {
selectedPoints[i].select(false);
}
};
$scope.sequenceChanged = function() {
if(!$scope.explorerModels.activeTopic || !$scope.explorerModels.activeSequence) return;
$scope.articles = [];
$scope.showMoreArticles();
};
$scope.showMoreArticles = function(limit) {
$scope.loadingArticles = true;
TopicFactory.articles({
skip: $scope.articles ? $scope.articles.length : 0,
limit: typeof limit === 'undefined' ? 20 : limit,
id: $scope.explorerModels.activeTopic.id,
from: new Date($scope.explorerModels.activeSequence.window.startDate).getTime(),
to: new Date($scope.explorerModels.activeSequence.window.endDate).getTime()
}, function(data, headers) {
$scope.articles.push.apply($scope.articles, data);
$scope.articlesTotal = headers("V-Total");
$scope.loadingArticles = false;
}, function() {
$scope.loadingArticles = false;
});
};
$scope.showAllArticles = function() {
$scope.showMoreArticles(0);
};
$scope.$watchGroup(['explorerModels.seqstyle', 'explorerModels.chartstyle', 'explorerModels.chartstack'], $scope.redrawGraph);
$scope.$watch('explorerModels.sorttopics', function() {
if (!$scope.topics) return;
if ($scope.explorerModels.sorttopics === 'name') {
$scope.explorerModels.sortdir = false;
} else {
$scope.explorerModels.sortdir = true;
}
$timeout(function() {
for (var i = 0; i < $scope.topics.length; i++)
$scope.topics[i].topicCurrValue = $scope.topicCurrValue($scope.topics[i]);
}, 0);
});
$scope.$watch('explorerModels.activeTopic', function() {
if(!$scope.explorerModels.activeTopic) return;
// preselect some words
if ($scope.explorerModels.activeTopic.words) {
for (var i = 0; i < Math.min(3, $scope.explorerModels.activeTopic.words.length); i++)
$scope.explorerModels.activeTopic.words[i].selected = true;
}
});
$scope.$watch('explorerModels.activeSequence', function() {
$scope.sequenceChanged();
});
}
]);
/****************************************************************************
* Article Controllers
****************************************************************************/
/**
* Article Index route
*/
app.controller('ArticlesIndexController', ['$scope', '$state', 'ArticleFactory',
function($scope, $state, ArticleFactory) {
// page was reloaded, choose topic model
if (!$scope.rootModels.topicModel && $state.current.name === 'articles')
$scope.chooseTopicModel();
$scope.articlesIndexModels = {
sortkey: 'date',
sortdir: true,
page: 1,
limit: 100
};
$scope.reloadArticles = function() {
if (!$scope.rootModels.topicModel) return;
$scope.loadingArticles = true;
ArticleFactory.query({
skip: ($scope.articlesIndexModels.page - 1) * $scope.articlesIndexModels.limit,
limit: $scope.articlesIndexModels.limit,
sort: ($scope.articlesIndexModels.sortdir ? '' : '-') + $scope.articlesIndexModels.sortkey,
topicModel: $scope.rootModels.topicModel.id,
char: $scope.articlesIndexModels.startChar,
contains: $scope.articlesIndexModels.contains
}, function(data, headers) {
$scope.articles = data;
$scope.articlesTotal = headers("V-Total");
$scope.maxPage = Math.ceil($scope.articlesTotal / $scope.articlesIndexModels.limit);
$scope.loadingArticles = false;
}, function() {
$scope.loadingArticles = false;
});
};
$scope.$watchGroup(['articlesIndexModels.page', 'articlesIndexModels.sortkey', 'articlesIndexModels.sortdir', 'rootModels.topicModel'], function() {
$scope.reloadArticles();
});
$scope.$watchGroup(['articlesIndexModels.startChar', 'articlesIndexModels.contains'], function() {
if($scope.articlesIndexModels.page !== 1)
$scope.articlesIndexModels.page = 1;
else
$scope.reloadArticles();
});
}
]);
/**
* Article Show route
*/
app.controller('ArticlesShowController', ['$scope', '$state', '$stateParams', '$timeout', 'ArticleFactory',
function($scope, $state, $stateParams, $timeout, ArticleFactory) {
$scope.articlesShowModels = {
topicsSort: '-share',
similarSort: '-share',
wordsSort: '-count',
entitiesSort: '-count'
};
ArticleFactory.get({
id: $stateParams.id
}, function(data) {
$scope.article = data;
$scope.articleDate = Vipra.formatDate($scope.article.date);
$scope.articleCreated = Vipra.formatDateTime($scope.article.created);
$scope.articleModified = Vipra.formatDateTime($scope.article.modified);
// calculate share from divergence
if ($scope.article.similarArticles) {
for (var articleIndex = 0; articleIndex < $scope.article.similarArticles.length; articleIndex++)
$scope.article.similarArticles[articleIndex].share = Math.round(((1 - $scope.article.similarArticles[articleIndex].divergence) * 100));
}
// take topic model from article
if (!angular.isObject($scope.rootModels.topicModel))
$scope.rootModels.topicModel = data.topicModel;
// calculate percentage share
var topicShareSeries = [];
if ($scope.article.topics) {
var topics = $scope.article.topics,
colors = randomColor({
count: $scope.article.topics.length
});
for (var topicIndex = 0, d; topicIndex < topics.length; topicIndex++) {
d = {
name: topics[topicIndex].topic.name,
y: topics[topicIndex].share,
color: colors[topicIndex],
id: topics[topicIndex].topic.id
};
topicShareSeries.push(d);
$scope.article.topics[topicIndex].color = colors[topicIndex];
}
}
$timeout(function() {
// highcharts data
$scope.topicShare = topicShareChart([{
name: 'Topic Share',
colorByPoint: true,
data: topicShareSeries
}]);
}, 0);
});
$scope.$watch('rootModels.topicModel', function(newVal) {
if ($scope.article && $scope.article.topicModel.id !== newVal.id)
$state.transitionTo('index');
});
$scope.openTabWords = function() {
if ($scope.words) return;
ArticleFactory.get({
id: $stateParams.id,
fields: 'words'
}, function(data) {
$scope.allWords = data.words;
$scope.showMoreWords();
});
};
var wordsCount = 0;
$scope.showMoreWords = function() {
wordsCount += 20;
$scope.words = $scope.allWords.slice(0, wordsCount);
};
$scope.showAllWords = function() {
wordsCount = $scope.allWords.length;
$scope.words = $scope.allWords;
};
$scope.openTabEntities = function() {
if ($scope.entities) return;
ArticleFactory.get({
id: $stateParams.id,
fields: 'entities'
}, function(data) {
$scope.allEntities = data.entities;
$scope.showMoreEntities();
});
};
var entitiesCount = 0;
$scope.showMoreEntities = function() {
entitiesCount += 20;
$scope.entities = $scope.allEntities.slice(0, entitiesCount);
};
$scope.showAllEntities = function() {
entitiesCount = $scope.allEntities.length;
$scope.entities = $scope.allEntities;
};
var topicShareChartElement = $('#topic-share');
$scope.highlightSlice = function(id, toggle) {
var highcharts = topicShareChartElement.highcharts();
if (!highcharts) return;
var point = highcharts.get(id);
if (!point) return;
if (toggle) {
point.onMouseOver();
} else {
point.onMouseOut();
highcharts.tooltip.hide();
}
};
}
]);
/****************************************************************************
* Topic Controllers
****************************************************************************/
/**
* Topic Index route
*/
app.controller('TopicsIndexController', ['$scope', '$state', 'TopicFactory',
function($scope, $state, TopicFactory) {
// page was reloaded, choose topic model
if (!$scope.rootModels.topicModel && $state.current.name === 'topics')
$scope.chooseTopicModel();
$scope.topicsIndexModels = {
sortkey: 'name',
sortdir: true,
page: 1,
limit: 100
};
$scope.reloadTopics = function() {
if (!$scope.rootModels.topicModel) return;
$scope.loadingTopics = true;
TopicFactory.query({
topicModel: $scope.rootModels.topicModel.id,
skip: ($scope.topicsIndexModels.page - 1) * $scope.topicsIndexModels.limit,
limit: $scope.topicsIndexModels.limit,
sort: ($scope.topicsIndexModels.sortdir ? '' : '-') + $scope.topicsIndexModels.sortkey,
char: $scope.topicsIndexModels.startChar,
contains: $scope.topicsIndexModels.contains
}, function(data, headers) {
$scope.topics = data;
$scope.topicsTotal = headers("V-Total");
$scope.maxPage = Math.ceil($scope.topicsTotal / $scope.topicsIndexModels.limit);
$scope.loadingTopics = false;
}, function() {
$scope.loadingTopics = false;
});
};
$scope.$watchGroup(['topicsIndexModels.page', 'topicsIndexModels.sortkey', 'topicsIndexModels.sortdir', 'rootModels.topicModel'], function() {
$scope.reloadTopics();
});
$scope.$watchGroup(['topicsIndexModels.startChar', 'topicsIndexModels.contains'], function() {
if($scope.topicsIndexModels.page !== 1)
$scope.topicsIndexModels.page = 1;
else
$scope.reloadTopics();
});
}
]);
/**
* Topic Show route
*/
app.controller('TopicsShowController', ['$scope', '$state', '$stateParams', '$timeout', 'TopicFactory', 'SequenceFactory',
function($scope, $state, $stateParams, $timeout, TopicFactory, SequenceFactory) {
$scope.topicsShowModels = {
relSeqstyle: 'absolute',
relChartstyle: 'areaspline',
wordSeqstyle: 'absolute',
wordChartstyle: 'spline',
seqSortWords: '-probability'
};
TopicFactory.get({
id: $stateParams.id
}, function(data) {
$scope.topic = data;
$scope.topicCreated = Vipra.formatDateTime($scope.topic.created);
$scope.topicModified = Vipra.formatDateTime($scope.topic.modified);
// take topic model from topic
if (!angular.isObject($scope.rootModels.topicModel))
$scope.rootModels.topicModel = data.topicModel;
// preselect some words
if ($scope.topic.words) {
for (var i = 0; i < Math.min(3, $scope.topic.words.length); i++)
$scope.topic.words[i].selected = true;
}
// preselect first sequence
if ($scope.topic.sequences && $scope.topic.sequences.length)
$scope.topicsShowModels.sequence = $scope.topic.sequences[0];
$scope.redrawRelevanceGraph();
});
$scope.redrawRelevanceGraph = function() {
if (!$scope.topic || !$scope.topic.sequences) return;
var relevances = [];
// create series
for (var i = 0, sequence, relevance; i < $scope.topic.sequences.length; i++) {
sequence = $scope.topic.sequences[i];
relevance = $scope.topicsShowModels.relSeqstyle === 'relative' ? sequence.relevanceChange : sequence.relevance;
relevances.push([new Date(sequence.window.startDate).getTime(), relevance]);
}
// highcharts configuration
$scope.topicSeq = areaRelevanceChart([{
name: $scope.topic.name,
data: relevances
}], 'Topic Relevance', $scope.topicsShowModels.relChartstyle);
};
$scope.resetRelZoom = function() {
if (!$scope.topic) return;
var highcharts = $('#topicRelChart').highcharts();
if (!highcharts) return;
highcharts.xAxis[0].setExtremes(null, null);
};
$scope.startRename = function() {
$scope.origName = $scope.topic.name;
$scope.isRename = true;
$timeout(function() {
document.getElementById('topicName').select();
}, 0);
};
$scope.endRename = function(save) {
delete $scope.renameErrors;
if (save) {
TopicFactory.update({
id: $scope.topic.id
}, $scope.topic, function(data) {
$scope.topic = data;
$scope.isRename = false;
// if topic list of parent view is loaded, replace name by new name
if ($scope.$parent.topics) {
for (var i = 0, topic; i < $scope.$parent.topics.length; i++) {
topic = $scope.$parent.topics[i];
if (topic.id === data.id) {
break;
}
}
}
});
} else {
$scope.isRename = false;
$scope.topic.name = $scope.origName;
}
};
$scope.keyup = function($event) {
if ($event.which === 13 || $event.which === 27) {
$scope.endRename($event.which === 13);
$event.preventDefault();
}
};
$scope.recalcSeqChange = function() {
if (!$scope.sequence || !$scope.sequenceCompare) return;
wordLoop:
for (var i = 0, word; i < $scope.sequence.words.length; i++) {
word = $scope.sequence.words[i];
for (var j = 0, word2; j < $scope.sequenceCompare.words.length; j++) {
word2 = $scope.sequenceCompare.words[j];
if (word.id === word2.id) {
word.change = word2.change = j - i;
continue wordLoop;
}
}
word.change = '-';
}
};
$scope.closeCompare = function() {
delete $scope.sequenceCompare;
delete $scope.topicsShowModels.sequenceCompare;
};
$scope.$watch('topicsShowModels.relSeqstyle', $scope.redrawRelevanceGraph);
$scope.$watch('topicsShowModels.relChartstyle', $scope.redrawRelevanceGraph);
$scope.$watch('topicsShowModels.sequence', function() {
if (!$scope.topicsShowModels.sequence) return;
SequenceFactory.get({
id: $scope.topicsShowModels.sequence.id
}, function(data) {
$scope.sequence = data;
$scope.recalcSeqChange();
});
});
$scope.$watch('topicsShowModels.sequenceCompare', function() {
if (!$scope.topicsShowModels.sequenceCompare) return;
SequenceFactory.get({
id: $scope.topicsShowModels.sequenceCompare.id
}, function(data) {
$scope.sequenceCompare = data;
$scope.recalcSeqChange();
});
});
$scope.$watch('rootModels.topicModel', function(newVal) {
if ($scope.topic && $scope.topic.topicModel.id !== newVal.id)
$state.transitionTo('index');
});
$('.tab-sequences').on('mouseleave', '.compare-row', function() {
$('[word-id=' + $(this).attr('word-id') + ']').removeClass('highlight');
});
$('.tab-sequences').on('mouseenter', '.compare-row', function() {
$('[word-id=' + $(this).attr('word-id') + ']').addClass('highlight');
});
}
]);
/**
* Topic Show Articles route
*/
app.controller('TopicsArticlesController', ['$scope', '$stateParams', 'TopicFactory',
function($scope, $stateParams, TopicFactory) {
$scope.topicsArticlesModels = {
sortkey: 'title',
sortdir: true,
page: 1,
limit: 100
};
$scope.$watchGroup(['topicsArticlesModels.page', 'topicsArticlesModels.sortkey', 'topicsArticlesModels.sortdir'], function() {
TopicFactory.articles({
id: $stateParams.id,
skip: ($scope.topicsArticlesModels.page - 1) * $scope.topicsArticlesModels.limit,
limit: $scope.topicsArticlesModels.limit,
sort: ($scope.topicsArticlesModels.sortdir ? '' : '-') + $scope.topicsArticlesModels.sortkey
}, function(data, headers) {
$scope.articles = data;
$scope.articlesTotal = headers("V-Total");
$scope.maxPage = Math.ceil($scope.articlesTotal / $scope.topicsArticlesModels.limit);
});
});
}
]);
/****************************************************************************
* Entity Controllers
****************************************************************************/
app.controller('EntitiesIndexController', ['$scope', '$state', 'EntityFactory',
function($scope, $state, EntityFactory) {
// page was reloaded, choose topic model
if (!$scope.rootModels.topicModel && $state.current.name === 'entities')
$scope.chooseTopicModel();
$scope.entitiesIndexModels = {
sortkey: 'id',
sortdir: true,
page: 1,
limit: 100
};
$scope.reloadEntities = function() {
if (!$scope.rootModels.topicModel) return;
$scope.loadingEntities = true;
EntityFactory.query({
topicModel: $scope.rootModels.topicModel.id,
skip: ($scope.entitiesIndexModels.page - 1) * $scope.entitiesIndexModels.limit,
limit: $scope.entitiesIndexModels.limit,
sort: ($scope.entitiesIndexModels.sortdir ? '' : '-') + $scope.entitiesIndexModels.sortkey,
char: $scope.entitiesIndexModels.startChar,
contains: $scope.entitiesIndexModels.contains
}, function(data, headers) {
$scope.entities = data;
$scope.entitiesTotal = headers("V-Total");
$scope.maxPage = Math.ceil($scope.entitiesTotal / $scope.entitiesIndexModels.limit);
$scope.loadingEntities = false;
}, function() {
$scope.loadingEntities = false;
});
};
$scope.$watchGroup(['entitiesIndexModels.page', 'entitiesIndexModels.sortkey', 'entitiesIndexModels.sortdir', 'rootModels.topicModel'], function() {
$scope.reloadEntities();
});
$scope.$watchGroup(['entitiesIndexModels.startChar', 'entitiesIndexModels.contains'], function() {
if($scope.entitiesIndexModels.page !== 1)
$scope.entitiesIndexModels.page = 1;
else
$scope.reloadEntities();
});
}
]);
app.controller('EntitiesShowController', ['$scope', '$stateParams', 'EntityFactory',
function($scope, $stateParams, EntityFactory) {
EntityFactory.get({
id: $stateParams.id
}, function(data) {
$scope.entity = data;
$scope.entityCreated = Vipra.formatDateTime($scope.entity.created);
$scope.entityModified = Vipra.formatDateTime($scope.entity.modified);
// take entity model from entity
if (!angular.isObject($scope.rootModels.topicModel))
$scope.rootModels.topicModel = data.topicModel;
});
}
]);
app.controller('EntitiesArticlesController', ['$scope', '$state', '$stateParams', 'ArticleFactory',
function($scope, $state, $stateParams, ArticleFactory) {
$scope.entity = $stateParams.id;
// page was reloaded, choose topic model
if (!$scope.rootModels.topicModel && $state.current.name === 'entities.articles')
$scope.chooseTopicModel();
$scope.entitiesArticlesModels = {
sortkey: 'date',
sortdir: true,
page: 1,
limit: 100
};
$scope.$watchGroup(['entitiesArticlesModels.page', 'entitiesArticlesModels.sortkey', 'entitiesArticlesModels.sortdir', 'rootModels.topicModel'], function() {
if (!$scope.rootModels.topicModel) return;
ArticleFactory.query({
skip: ($scope.entitiesArticlesModels.page - 1) * $scope.entitiesArticlesModels.limit,
limit: $scope.entitiesArticlesModels.limit,
sort: ($scope.entitiesArticlesModels.sortdir ? '' : '-') + $scope.entitiesArticlesModels.sortkey,
topicModel: $scope.rootModels.topicModel.id,
entity: $scope.entity
}, function(data, headers) {
$scope.articles = data;
$scope.articlesTotal = headers("V-Total");
$scope.maxPage = Math.ceil($scope.articlesTotal / $scope.entitiesArticlesModels.limit);
});
});
}
]);
/****************************************************************************
* Word Controllers
****************************************************************************/
app.controller('WordsIndexController', ['$scope', '$state', 'WordFactory',
function($scope, $state, WordFactory) {
// page was reloaded, choose topic model
if (!$scope.rootModels.topicModel && $state.current.name === 'words')
$scope.chooseTopicModel();
$scope.wordsIndexModels = {
sortkey: 'id',
sortdir: true,
page: 1,
limit: 100
};
$scope.reloadWords = function() {
if (!$scope.rootModels.topicModel) return;
$scope.loadingWords = true;
WordFactory.query({
topicModel: $scope.rootModels.topicModel.id,
skip: ($scope.wordsIndexModels.page - 1) * $scope.wordsIndexModels.limit,
limit: $scope.wordsIndexModels.limit,
sort: ($scope.wordsIndexModels.sortdir ? '' : '-') + $scope.wordsIndexModels.sortkey,
char: $scope.wordsIndexModels.startChar,
contains: $scope.wordsIndexModels.contains
}, function(data, headers) {
$scope.words = data;
$scope.wordsTotal = headers("V-Total");
$scope.maxPage = Math.ceil($scope.wordsTotal / $scope.wordsIndexModels.limit);
$scope.loadingWords = false;
}, function() {
$scope.loadingWords = false;
});
};
$scope.$watchGroup(['wordsIndexModels.page', 'wordsIndexModels.sortkey', 'wordsIndexModels.sortdir', 'rootModels.topicModel'], function() {
$scope.reloadWords();
});
$scope.$watchGroup(['wordsIndexModels.startChar', 'wordsIndexModels.contains'], function() {
if($scope.wordsIndexModels.page !== 1)
$scope.wordsIndexModels.page = 1;
else
$scope.reloadWords();
});
}
]);
app.controller('WordsShowController', ['$scope', '$stateParams', 'WordFactory',
function($scope, $stateParams, WordFactory) {
WordFactory.get({
id: $stateParams.id
}, function(data) {
$scope.word = data;
// take word model from word
if (!angular.isObject($scope.rootModels.topicModel))
$scope.rootModels.topicModel = data.topicModel;
});
}
]);
app.controller('WordsTopicsController', ['$scope', '$state', '$stateParams', 'TopicFactory',
function($scope, $state, $stateParams, TopicFactory) {
$scope.word = $stateParams.id;
// page was reloaded, choose topic model
if (!$scope.rootModels.topicModel && $state.current.name === 'words.topics')
$scope.chooseTopicModel();
$scope.wordsTopicsModels = {
sortkey: 'name',
sortdir: true,
page: 1,
limit: 100
};
$scope.$watchGroup(['wordsTopicsModels.page', 'wordsTopicsModels.sortkey', 'wordsTopicsModels.sortdir', 'rootModels.topicModel'], function() {
if (!$scope.rootModels.topicModel) return;
TopicFactory.query({
topicModel: $scope.rootModels.topicModel.id,
skip: ($scope.wordsTopicsModels.page - 1) * $scope.wordsTopicsModels.limit,
limit: $scope.wordsTopicsModels.limit,
sort: ($scope.wordsTopicsModels.sortdir ? '' : '-') + $scope.wordsTopicsModels.sortkey,
word: $scope.word
}, function(data, headers) {
$scope.topics = data;
$scope.topicsTotal = headers("V-Total");
$scope.maxPage = Math.ceil($scope.topicsTotal / $scope.wordsTopicsModels.limit);
});
});
}
]);
app.controller('WordsArticlesController', ['$scope', '$state', '$stateParams', 'ArticleFactory',
function($scope, $state, $stateParams, ArticleFactory) {
$scope.word = $stateParams.id;
// page was reloaded, choose topic model
if (!$scope.rootModels.topicModel && $state.current.name === 'words.articles')
$scope.chooseTopicModel();
$scope.wordsArticlesModels = {
sortkey: 'date',
sortdir: true,
page: 1,
limit: 100
};
$scope.$watchGroup(['wordsArticlesModels.page', 'wordsArticlesModels.sortkey', 'wordsArticlesModels.sortdir', 'rootModels.topicModel'], function() {
if (!$scope.rootModels.topicModel) return;
ArticleFactory.query({
skip: ($scope.wordsArticlesModels.page - 1) * $scope.wordsArticlesModels.limit,
limit: $scope.wordsArticlesModels.limit,
sort: ($scope.wordsArticlesModels.sortdir ? '' : '-') + $scope.wordsArticlesModels.sortkey,
topicModel: $scope.rootModels.topicModel.id,
word: $scope.word
}, function(data, headers) {
$scope.articles = data;
$scope.articlesTotal = headers("V-Total");
$scope.maxPage = Math.ceil($scope.articlesTotal / $scope.wordsArticlesModels.limit);
});
});
}
]);
/****************************************************************************
* Slides Controllers
****************************************************************************/
app.controller('SlidesController', ['$scope', function($scope) {
$scope.current = 1;
var folder = '//ftp.cochu.io/vipra/slides/';
var prefix = 'Folie';
var suffix = '.PNG';
var slides = $('.slides');
slides.css('background-image', 'url(' + folder + prefix + $scope.current + suffix + ')');
$scope.go = function(next) {
$('<img/>').attr('src', folder + prefix + next + suffix).load(function() {
$scope.$apply(function() {
$scope.current = next;
slides.css('background-image', 'url(' + folder + prefix + $scope.current + suffix + ')');
});
});
};
}
]);
/****************************************************************************
* Error Controllers
****************************************************************************/
app.controller('ErrorsController', ['$scope', '$state', '$stateParams',
function($scope, $state, $stateParams) {
$scope.code = $stateParams.code;
$scope.title = Vipra.statusMsg($scope.code);
}
]);
/****************************************************************************
* Directive Controllers
****************************************************************************/
/**
* Pagination
*/
app.controller('PaginationController', ['$scope',
function($scope) {
$scope.calculatePages = function() {
var pages = [],
max = Math.ceil($scope.total / $scope.limit * 1.0),
pad = 4,
start = Math.max($scope.page - pad, 1),
end = Math.min(Math.max($scope.page + pad, start + pad * 2), max);
for (var i = start; i <= end; i++) {
pages.push(i);
}
$scope.pages = pages;
$scope.maxPage = max;
};
$scope.$watchGroup(['total', 'page', 'limit'], function(newVal, oldVal) {
if (!angular.equals(newVal, oldVal)) {
$scope.calculatePages();
}
});
$scope.calculatePages();
$scope.changePage = function(page) {
$scope.page = parseInt(page, 10);
};
$scope.toPage = function() {
var page = prompt("Enter a page number (between 1 and " + $scope.maxPage + ")");
if (page > 0 && page <= $scope.maxPage)
$scope.changePage(page);
};
}
]);
app.controller('WordEvolutionController', ['$scope',
function($scope) {
$scope.chartId = $scope.chartId || Vipra.randomId();
$scope.wordSeqstyle = 'absolute';
$scope.wordChartstyle = 'spline';
$scope.resetWordZoom = function() {
if (!$scope.wordsSelected) return;
var highcharts = $('#' + $scope.chartId).highcharts();
if (!highcharts) return;
highcharts.xAxis[0].setExtremes(null, null);
};
$scope.redrawWordEvolutionChart = function() {
var evolutions = [];
if ($scope.topic && $scope.topic.words && $scope.topic.sequences) {
// create series
for (var i = 0, word, probs; i < $scope.topic.words.length; i++) {
word = $scope.topic.words[i];
if (!word.selected) continue;
probs = [];
for (var j = 0, prob; j < word.sequenceProbabilities.length; j++) {
prob = $scope.wordSeqstyle === 'relative' ? word.sequenceProbabilitiesChange[j] : word.sequenceProbabilities[j];
probs.push([new Date($scope.topic.sequences[j].window.startDate).getTime(), prob]);
}
evolutions.push({
id: word.id,
name: word.id,
color: word.color,
data: probs
});
}
}
$scope.wordEvolution = areaRelevanceChart(evolutions, 'Word Evolution', $scope.wordChartstyle);
$scope.wordsSelected = evolutions.length;
};
$scope.highlightSeries = function(id, toggle) {
if (!$scope.wordsSelected) return;
var highcharts = $('#' + $scope.chartId).highcharts();
if (!highcharts) return;
var series = highcharts.get(id);
if (!series) return;
if (toggle) {
series.onMouseOver();
series.group.zIndexOrig = series.group.zIndex;
series.group.zIndexSetter(9999, 'zIndex');
series.graph.attr('stroke', '#000000').attr('stroke-dasharray', '5,5');
} else {
series.onMouseOut();
series.group.zIndexSetter(series.group.zIndexOrig, 'zIndex');
series.graph.attr('stroke', series.color).attr('stroke-dasharray', '');
}
};
$scope.$watchGroup(['wordSeqstyle', 'wordChartstyle', 'topic'], $scope.redrawWordEvolutionChart);
$scope.$watch('topic', function() {
if($scope.topic) {
var colors = randomColor({
count: $scope.topic.words.length
});
for (var i = 0; i < $scope.topic.words.length; i++) {
$scope.topic.words[i].color = colors[i];
}
}
$scope.redrawWordEvolutionChart();
});
}
]);
/****************************************************************************
* Shared Highcharts configurations
****************************************************************************/
function areaRelevanceChart(series, title, chartType, chartStack, clickCallback) {
return {
chart: {
type: (chartType || 'areaspline'),
zoomType: 'x',
spacingLeft: 0,
spacingRight: 0
},
title: {
text: title
},
xAxis: {
type: 'datetime',
title: {
text: 'Sequence'
}
},
yAxis: {
title: {
text: 'Relevance'
}
},
tooltip: {
headerFormat: '<b>{series.name}</b><br>',
pointFormat: '{point.x:%Y}: {point.y:.4f}'
},
legend: {
enabled: false
},
credits: {
enabled: false
},
navigator: {
enabled: true
},
plotOptions: {
areaspline: {
fillOpacity: 0.5,
},
series: {
stacking: (chartStack === 'none' ? null : chartStack),
animation: false,
cursor: 'pointer',
allowPointSelect: true,
states: {
hover: {
color: '#ff0000',
lineWidth: 4,
halo: {
size: 9,
attributes: {
fill: Highcharts.getOptions().colors[2],
'stroke-width': 2,
stroke: Highcharts.getOptions().colors[1]
}
}
}
},
point: {
events: {
click: clickCallback
}
}
}
},
noData: {
style: {
fontSize: "14px",
color: "#777",
fontWeight: "normal"
}
},
series: series
};
}
function topicShareChart(series) {
return {
chart: {
type: 'pie',
spacingBottom: 0,
spacingTop: 0,
spacingLeft: 0,
spacingRight: 0,
},
credits: {
enabled: false
},
plotOptions: {
pie: {
size: '100%',
dataLabels: {
enabled: false
},
allowPointSelect: true
}
},
title: {
text: ''
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
noData: {
style: {
fontSize: "14px",
color: "#777",
fontWeight: "normal"
}
},
series: series
};
}
})();