/**
* Implementation of a dataset backed by a server, which in turn uses fi. postgreSQL
* Fully asynchronous, based on socketIO.
*
* Most methods below result in a message with the methodName and a data object, containing:
* * `dataset: dataset.toJSON()`
* * `facetId: facet.get()`, or
* * `filterId: filter.getId()`
*
* Extra messages are available for synchronizing state, which can be both send and received:
* * `syncFilters`
* * `syncFacets`
* * `syncDataset`
*
* these take the Dataset.toJSON() as content.
* Data can be requested by sending `getData` with dataset and filter ID, on which the server
* responds with a `newData` message containing `filterId` and `data`.
*
* @module client/dataset-server
*/
var Dataset = require('./dataset');
var socketIO = require('socket.io-client');
var app = require('ampersand-app');
/**
* Autoconfigure a dataset
* @param {Dataset} dataset
*/
function scanData (dataset) {
console.log('spot-server: scanData');
dataset.socket.emit('scanData', {
dataset: dataset.toJSON()
});
}
/**
* setMinMax sets the range of a continuous or time facet
* @param {Dataset} dataset
* @param {Facet} facet
*/
function setMinMax (dataset, facet) {
console.log('spot-server: setMinMax');
dataset.socket.emit('setMinMax', {
dataset: dataset.toJSON(),
facetId: facet.getId()
});
}
/**
* setCategories finds finds all values on an ordinal (categorial) axis
* Updates the categorialTransform of the facet
*
* @param {Dataset} dataset
* @param {Facet} facet
*/
function setCategories (dataset, facet) {
console.log('spot-server: setCategories');
dataset.socket.emit('setCategories', {
dataset: dataset.toJSON(),
facetId: facet.getId()
});
}
/**
* Calculate 100 percentiles (ie. 1,2,3,4 etc.), and initialize the `facet.continuousTransform`
* @param {Dataset} dataset
* @param {Facet} facet
*/
function setPercentiles (dataset, facet) {
console.log('spot-server: setPercentiles' + facet.getId());
dataset.socket.emit('setPercentiles', {
dataset: dataset.toJSON(),
facetId: facet.getId()
});
}
/**
* Calculate value where exceedance probability is one in 10,20,30,40,50,
* Set the `facet.continuousTransform` to the approximate mapping.
* @param {Dataset} dataset
* @param {Facet} facet
*/
function setExceedances (dataset, facet) {
console.log('spot-server: setExceedances' + facet.getId());
dataset.socket.emit('setExceedances', {
dataset: dataset.toJSON(),
facetId: facet.getId()
});
}
/**
* Initialize the data filter, and construct the getData callback function on the filter.
* @param {Dataset} dataset
* @param {Filter} filter
*/
function initDataFilter (dataset, filter) {
var socket = dataset.socket;
console.log('spot-server: syncFilters');
socket.emit('syncFilters', dataset.filters.toJSON());
var id = filter.getId();
filter.getData = function () {
console.log('spot-server: getData for filter ' + id);
socket.emit('getData', {
dataset: dataset.toJSON(),
filterId: id
});
};
}
/**
* The opposite or initDataFilter, it should remove the filter and deallocate other configuration
* related to the filter.
* @param {Dataset} dataset
* @param {Filter} filter
*/
function releaseDataFilter (dataset, filter) {
var socket = dataset.socket;
console.log('spot-server: syncFilters');
socket.emit('syncFilters', dataset.filters.toJSON());
filter.getData = function () {
var data = [];
filter.data = data;
};
}
/**
* Change the filter parameters for an initialized filter
* @param {Dataset} dataset
* @param {Filter} filter
*/
function updateDataFilter (dataset, filter) {
var socket = dataset.socket;
console.log('spot-server: syncFilters');
socket.emit('syncFilters', dataset.filters.toJSON());
}
/**
* Connect to the spot-server using a websocket on port 3080 and setup callbacks
*
* @function
* @params {Dataset} dataset
*/
function connect (dataset) {
var socket = socketIO('http://localhost:3080');
socket.on('connect', function () {
console.log('spot-server: connected');
dataset.isConnected = true;
console.log('spot-server: syncDataset');
socket.emit('syncDataset', dataset.toJSON());
});
socket.on('disconnect', function () {
console.log('spot-server: disconnected');
dataset.isConnected = false;
});
socket.on('syncDataset', function (data) {
console.log('spot-server: syncDataset');
dataset.reset(data);
});
socket.on('syncFilters', function (data) {
console.log('spot-server: syncFilters');
dataset.filters.add(data, {merge: true});
});
socket.on('syncFacets', function (data) {
console.log('spot-server: syncFacets');
dataset.facets.add(data, {merge: true});
// on the facets page, the list of facets needs upgrading
if (app.currentPage.pageTitle === 'Facets') {
window.componentHandler.upgradeDom();
}
// on the facet-define page, the minimum and maximum values are possibly updated,
// but the input fields still need to be informed for the mld javascript to work
if (app.currentPage.pageTitle === 'Facets - Edit') {
app.currentPage.queryByHook('define-minimum-input').dispatchEvent(new window.Event('input'));
app.currentPage.queryByHook('define-maximum-input').dispatchEvent(new window.Event('input'));
}
});
socket.on('newData', function (req) {
console.log('spot-server: newData ' + req.filterId);
var filter = dataset.filters.get(req.filterId);
if (req.data) {
filter.data = req.data;
filter.trigger('newData');
} else {
console.error('No data in response to getData for filter ' + filter.getId());
}
});
console.log('spot-server: connecting');
socket.connect();
dataset.socket = socket;
}
module.exports = Dataset.extend({
props: {
datasetType: {
type: 'string',
setOnce: true,
default: 'server'
}
},
/*
* Implementation of virtual methods
*/
scanData: function () {
scanData(this);
},
setMinMax: setMinMax,
setCategories: setCategories,
setPercentiles: setPercentiles,
setExceedances: setExceedances,
initDataFilter: initDataFilter,
releaseDataFilter: releaseDataFilter,
updateDataFilter: updateDataFilter,
// socketio for communicating with spot-server
isConnected: false,
connect: function () {
connect(this);
}
});