"
}
]);
$('#synapse_desc').bind('typeahead:selected', function (event, datum, dataset) {
if (datum.id) { // if they clicked on an existing synapse get it
Metamaps.Synapse.getSynapseFromAutocomplete(datum.id);
}
});
},
beingCreated: false,
description: null,
topic1id: null,
topic2id: null,
newSynapseId: null,
open: function () {
$('#new_synapse').fadeIn('fast', function () {
$('#synapse_desc').focus();
});
Metamaps.Create.newSynapse.beingCreated = true;
},
hide: function () {
$('#new_synapse').fadeOut('fast');
$("#synapse_desc").typeahead('setQuery', '');
Metamaps.Create.newSynapse.beingCreated = false;
Metamaps.Create.newTopic.addSynapse = false;
Metamaps.Create.newSynapse.topic1id = 0;
Metamaps.Create.newSynapse.topic2id = 0;
},
getSearchQuery: function () {
var self = Metamaps.Create.newSynapse;
if (Metamaps.Selected.Nodes.length < 2) {
return '/search/synapses?topic1id=' + self.topic1id + '&topic2id=' + self.topic2id;
} else return '';
}
}
}; // end Metamaps.Create
////////////////// TOPIC AND SYNAPSE CARDS //////////////////////////
/*
*
* TOPICCARD
*
*/
Metamaps.TopicCard = {
openTopicCard: null, //stores the JIT local ID of the topic with the topic card open
init: function () {
// initialize best_in_place editing
$('.authenticated div.permission.canEdit .best_in_place').best_in_place();
Metamaps.TopicCard.generateShowcardHTML = Hogan.compile($('#topicCardTemplate').html());
// initialize topic card draggability and resizability
$('.showcard').draggable({
handle: ".metacodeImage"
});
$('#showcard').resizable({
maxHeight: 500,
maxWidth: 500,
minHeight: 320,
minWidth: 226,
resize: function (event, ui) {
var p = $('#showcard').find('.scroll');
p.height(p.height()).mCustomScrollbar('update');
}
}).css({
display: 'none',
top: '300px',
left: '100px'
});
},
fadeInShowCard: function (topic) {
$('.showcard').fadeIn('fast');
Metamaps.TopicCard.openTopicCard = topic.isNew() ? topic.cid : topic.id;
},
/**
* Will open the Topic Card for the node that it's passed
* @param {$jit.Graph.Node} node
*/
showCard: function (node) {
var topic = node.getData('topic');
//populate the card that's about to show with the right topics data
Metamaps.TopicCard.populateShowCard(topic);
Metamaps.TopicCard.fadeInShowCard(topic);
},
hideCard: function () {
$('.showcard').fadeOut('fast');
Metamaps.TopicCard.openTopicCard = null;
},
bindShowCardListeners: function (topic) {
var self = Metamaps.TopicCard;
var showCard = document.getElementById('showcard');
var selectingMetacode = false;
// attach the listener that shows the metacode title when you hover over the image
$('.showcard .metacodeImage').mouseenter(function () {
$('.showcard .icon').css('z-index', '4');
$('.showcard .metacodeTitle').show();
});
$('.showcard .linkItem.icon').mouseleave(function () {
if (!selectingMetacode) {
$('.showcard .metacodeTitle').hide();
$('.showcard .icon').css('z-index', '1');
}
});
$('.showcard .metacodeTitle').click(function () {
if (!selectingMetacode) {
selectingMetacode = true;
$(this).addClass('minimize'); // this line flips the drop down arrow to a pull up arrow
$('.metacodeSelect').show();
// add the scroll bar to the list of metacode select options if it isn't already there
if (!$('.metacodeSelect ul').hasClass('mCustomScrollbar')) {
$('.metacodeSelect ul').mCustomScrollbar({
mouseWheelPixels: 200,
advanced: {
updateOnContentResize: true
}
});
$('.metacodeSelect li').click(function () {
selectingMetacode = false;
var metacodeName = $(this).find('.mSelectName').text();
var metacode = Metamaps.Metacodes.findWhere({
name: metacodeName
});
$('.CardOnGraph').find('.metacodeTitle').text(metacodeName)
.attr('class', 'metacodeTitle mbg' + metacodeName.replace(/\s/g, ''));
$('.CardOnGraph').find('.metacodeImage').css('background-image', 'url(' + metacode.get('icon') + ')');
topic.save({
metacode_id: metacode.id
});
Metamaps.Visualize.mGraph.plot();
$('.metacodeTitle').removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow
$('.metacodeSelect').hide();
setTimeout(function () {
$('.metacodeTitle').hide();
$('.showcard .icon').css('z-index', '1');
}, 500);
});
}
} else {
selectingMetacode = false;
$(this).removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow
$('.metacodeSelect').hide();
}
});
// ability to change permission
var selectingPermission = false;
if (topic.authorizePermissionChange(Metamaps.Active.Mapper)) {
$('.showcard .yourTopic .mapPerm').click(function () {
if (!selectingPermission) {
selectingPermission = true;
$(this).addClass('minimize'); // this line flips the drop down arrow to a pull up arrow
if ($(this).hasClass('co')) {
$(this).append('
');
} else if ($(this).hasClass('pu')) {
$(this).append('
');
} else if ($(this).hasClass('pr')) {
$(this).append('
');
}
$('.permissionSelect li').click(function (event) {
selectingPermission = false;
var permission = $(this).attr('class');
topic.save({
permission: permission
});
$('.showcard .mapPerm').removeClass('co pu pr minimize').addClass(permission.substring(0, 2));
$('.permissionSelect').remove();
event.stopPropagation();
});
} else {
selectingPermission = false;
$(this).removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow
$('.permissionSelect').remove();
}
});
}
// when you're typing a description, resize the scroll box to have space
$('.best_in_place_desc textarea').bind('keyup', function () {
var s = $('.showcard').find('.scroll');
s.height(s.height()).mCustomScrollbar('update');
});
//bind best_in_place ajax callbacks
$(showCard).find('.best_in_place_name').bind("ajax:success", function () {
var s = $('.showcard').find('.scroll');
s.height(s.height()).mCustomScrollbar('update');
var name = $(this).html();
topic.set("name", Metamaps.Util.decodeEntities(name));
Metamaps.Visualize.mGraph.plot();
});
$(showCard).find('.best_in_place_desc').bind("ajax:success", function () {
this.innerHTML = this.innerHTML.replace(/\r/g, '')
var s = $('.showcard').find('.scroll');
s.height(s.height()).mCustomScrollbar('update');
var desc = $(this).html();
topic.set("desc", desc);
});
$(showCard).find('.best_in_place_link').bind("ajax:success", function () {
var link = $(this).html();
$(showCard).find('.go-link').attr('href', link);
topic.set("link", link);
});
},
populateShowCard: function (topic) {
var self = Metamaps.TopicCard;
var showCard = document.getElementById('showcard');
$(showCard).find('.permission').remove();
var html = self.generateShowcardHTML.render(self.buildObject(topic));
if (topic.authorizeToEdit(Metamaps.Active.Mapper)) {
var perm = document.createElement('div');
var string = 'permission canEdit';
if (topic.authorizePermissionChange(Metamaps.Active.Mapper)) string += ' yourTopic';
perm.className = string;
perm.innerHTML = html;
showCard.appendChild(perm);
} else {
var perm = document.createElement('div');
perm.className = 'permission cannotEdit';
perm.innerHTML = html;
showCard.appendChild(perm);
}
Metamaps.TopicCard.bindShowCardListeners(topic);
},
generateShowcardHTML: null, // will be initialized into a Hogan template within init function
//generateShowcardHTML
buildObject: function (topic) {
var nodeValues = {};
var authorized = topic.authorizeToEdit(Metamaps.Active.Mapper);
//link is rendered differently if user is logged out or in
var go_link, a_tag, close_a_tag;
if (!authorized) {
go_link = '';
if (topic.get("link") != "") {
a_tag = '';
close_a_tag = '';
} else {
a_tag = '';
close_a_tag = '';
}
} else {
go_link = '';
a_tag = '';
close_a_tag = '';
}
var desc_nil = "Click to add description...";
var link_nil = "Click to add link...";
nodeValues.permission = topic.get("permission");
nodeValues.mk_permission = topic.get("permission").substring(0, 2);
//nodeValues.map_count = topic.get("inmaps").length;
//nodeValues.synapse_count = topic.get("synapseCount");
nodeValues.id = topic.isNew() ? topic.cid : topic.id;
nodeValues.metacode = topic.getMetacode().get("name");
nodeValues.metacode_class = 'mbg' + topic.getMetacode().get("name").replace(/\s/g, '');
nodeValues.imgsrc = topic.getMetacode().get("icon");
nodeValues.name = topic.get("name");
nodeValues.userid = topic.get("user_id");
nodeValues.username = topic.getUser().get("name");
nodeValues.date = topic.getDate();
// the code for this is stored in /views/main/_metacodeOptions.html.erb
nodeValues.metacode_select = $('#metacodeOptions').html();
nodeValues.go_link = go_link;
nodeValues.a_tag = a_tag;
nodeValues.close_a_tag = close_a_tag;
nodeValues.link_nil = link_nil;
nodeValues.link = (topic.get("link") == "" && authorized) ? link_nil : topic.get("link");
nodeValues.desc_nil = desc_nil;
nodeValues.desc = (topic.get("desc") == "" && authorized) ? desc_nil : topic.get("desc");
return nodeValues;
}
}; // end Metamaps.TopicCard
/*
*
* SYNAPSECARD
*
*/
Metamaps.SynapseCard = {
openSynapseCard: null,
showCard: function (edge, e) {
var self = Metamaps.SynapseCard;
//reset so we don't interfere with other edges, but first, save its x and y
var myX = $('#edit_synapse').css('left');
var myY = $('#edit_synapse').css('top');
$('#edit_synapse').remove();
//so label is missing while editing
Metamaps.Control.deselectEdge(edge);
var synapse = edge.getData('synapses')[0]; // for now, just get the first synapse
//create the wrapper around the form elements, including permissions
//classes to make best_in_place happy
var edit_div = document.createElement('div');
edit_div.setAttribute('id', 'edit_synapse');
if (synapse.authorizeToEdit(Metamaps.Active.Mapper)) {
edit_div.className = 'permission canEdit';
edit_div.className += synapse.authorizePermissionChange(Metamaps.Active.Mapper) ? ' yourEdge' : '';
} else {
edit_div.className = 'permission cannotEdit';
}
$('.main .wrapper').append(edit_div);
self.populateShowCard(synapse);
//drop it in the right spot, activate it
$('#edit_synapse').css('position', 'absolute');
if (e) {
$('#edit_synapse').css('left', e.clientX);
$('#edit_synapse').css('top', e.clientY);
} else {
$('#edit_synapse').css('left', myX);
$('#edit_synapse').css('top', myY);
}
//$('#edit_synapse_name').click(); //required in case name is empty
//$('#edit_synapse_name input').focus();
$('#edit_synapse').show();
self.openSynapseCard = synapse.isNew() ? synapse.cid : synapse.id;
},
hideCard: function () {
$('#edit_synapse').remove();
Metamaps.SynapseCard.openSynapseCard = null;
},
populateShowCard: function (synapse) {
var self = Metamaps.SynapseCard;
self.add_name_form(synapse);
self.add_user_info(synapse);
self.add_perms_form(synapse);
if (synapse.authorizeToEdit(Metamaps.Active.Mapper)) {
self.add_direction_form(synapse);
}
},
add_name_form: function (synapse) {
var data_nil = 'Click to add description.';
// TODO make it so that this would work even in sandbox mode,
// currently with Best_in_place it won't
//name editing form
$('#edit_synapse').append('');
$('#edit_synapse_name').attr('class', 'best_in_place best_in_place_desc');
$('#edit_synapse_name').attr('data-object', 'synapse');
$('#edit_synapse_name').attr('data-attribute', 'desc');
$('#edit_synapse_name').attr('data-type', 'textarea');
$('#edit_synapse_name').attr('data-nil', data_nil);
$('#edit_synapse_name').attr('data-url', '/synapses/' + synapse.id);
$('#edit_synapse_name').html(synapse.get("desc"));
//if edge data is blank or just whitespace, populate it with data_nil
if ($('#edit_synapse_name').html().trim() == '') {
$('#edit_synapse_name').html(data_nil);
}
$('#edit_synapse_name').bind("ajax:success", function () {
var desc = $(this).html();
if (desc == data_nil) {
synapse.set("desc", '');
} else {
synapse.set("desc", desc);
}
Metamaps.Control.selectEdge(synapse.get('edge'));
Metamaps.Visualize.mGraph.plot();
});
},
add_user_info: function (synapse) {
var u = '
';
u += '
Created by ' + synapse.getUser().get("name") + '
';
$('#edit_synapse').append(u);
},
add_perms_form: function (synapse) {
//permissions - if owner, also allow permission editing
$('#edit_synapse').append('');
// ability to change permission
var selectingPermission = false;
if (synapse.authorizePermissionChange(Metamaps.Active.Mapper)) {
$('#edit_synapse.yourEdge .mapPerm').click(function () {
if (!selectingPermission) {
selectingPermission = true;
$(this).addClass('minimize'); // this line flips the drop down arrow to a pull up arrow
if ($(this).hasClass('co')) {
$(this).append('
');
} else if ($(this).hasClass('pu')) {
$(this).append('
');
} else if ($(this).hasClass('pr')) {
$(this).append('
');
}
$('#edit_synapse .permissionSelect li').click(function (event) {
selectingPermission = false;
var permission = $(this).attr('class');
synapse.save({
permission: permission,
});
$('#edit_synapse .mapPerm').removeClass('co pu pr minimize').addClass(permission.substring(0, 2));
$('#edit_synapse .permissionSelect').remove();
event.stopPropagation();
});
} else {
selectingPermission = false;
$(this).removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow
$('#edit_synapse .permissionSelect').remove();
}
});
}
}, //add_perms_form
add_direction_form: function (synapse) {
//directionality checkboxes
$('#edit_synapse').append('');
$('#edit_synapse').append('');
$('#edit_synapse').append('');
$('#edit_synapse').append('');
var edge = synapse.get('edge');
//determine which node is to the left and the right
//if directly in a line, top is left
if (edge.nodeFrom.pos.x < edge.nodeTo.pos.x ||
edge.nodeFrom.pos.x == edge.nodeTo.pos.x &&
edge.nodeFrom.pos.y < edge.nodeTo.pos.y) {
var left = edge.nodeTo;
var right = edge.nodeFrom;
} else {
var left = edge.nodeFrom;
var right = edge.nodeTo;
}
/*
* One node is actually on the left onscreen. Call it left, & the other right.
* If category is from-to, and that node is first, check the 'right' checkbox.
* Else check the 'left' checkbox since the arrow is incoming.
*/
var directionCat = synapse.get('category'); //both, none, from-to
if (directionCat == 'from-to') {
var from_to = synapse.getDirection();
if (from_to[0] == left.id) {
//check left checkbox
$('#edit_synapse_left').prop('checked', true);
} else {
//check right checkbox
$('#edit_synapse_right').prop('checked', true);
}
} else if (directionCat == 'both') {
//check both checkboxes
$('#edit_synapse_left').prop('checked', true);
$('#edit_synapse_right').prop('checked', true);
}
$('#edit_synapse_left, #edit_synapse_right').click(function () {
var leftChecked = $('#edit_synapse_left').is(':checked');
var rightChecked = $('#edit_synapse_right').is(':checked');
var dir = synapse.getDirection();
var dirCat = 'none';
if (leftChecked && rightChecked) {
dirCat = 'both';
} else if (!leftChecked && rightChecked) {
dirCat = 'from-to';
dir = [right.id, left.id];
} else if (leftChecked && !rightChecked) {
dirCat = 'from-to';
dir = [left.id, right.id];
}
synapse.save({
category: dirCat,
node1_id: dir[0],
node2_id: dir[1]
});
Metamaps.Visualize.mGraph.plot();
});
} //add_direction_form
}; // end Metamaps.SynapseCard
////////////////////// END TOPIC AND SYNAPSE CARDS //////////////////////////////////
/*
*
* VISUALIZE
*
*/
Metamaps.Visualize = {
mGraph: {}, // a reference to the graph object.
cameraPosition: null, // stores the camera position when using a 3D visualization
type: "ForceDirected", // the type of graph we're building, could be "RGraph", "ForceDirected", or "ForceDirected3D"
savedLayout: true, // indicates whether the map has a saved layout or not
loadLater: false, // indicates whether there is JSON that should be loaded right in the offset, or whether to wait till the first topic is created
target: null, // the selector representing the location to render the graph
init: function () {
var self = Metamaps.Visualize;
// disable awkward dragging of the canvas element that would sometimes happen
$('#infovis-canvas').on('dragstart', function (event) {
event.preventDefault();
});
// prevent touch events on the canvas from default behaviour
$("#infovis-canvas").bind('touchstart', function (event) {
event.preventDefault();
self.mGraph.events.touched = true;
});
// prevent touch events on the canvas from default behaviour
$("#infovis-canvas").bind('touchmove', function (event) {
//Metamaps.JIT.touchPanZoomHandler(event);
});
// prevent touch events on the canvas from default behaviour
$("#infovis-canvas").bind('touchend touchcancel', function (event) {
lastDist = 0;
if (!self.mGraph.events.touchMoved && !Metamaps.Touch.touchDragNode) Metamaps.TopicCard.hideCurrentCard();
self.mGraph.events.touched = self.mGraph.events.touchMoved = false;
Metamaps.Touch.touchDragNode = false;
});
},
render: function (targetID, vizData) {
var self = Metamaps.Visualize;
self.mGraph = {};
self.target = targetID;
self.__buildGraph(vizData);
},
computePositions: function () {
var self = Metamaps.Visualize,
mapping;
if (self.type == "RGraph") {
self.mGraph.graph.eachNode(function (n) {
topic = Metamaps.Topics.get(n.id);
topic.set('node', n);
topic.updateNode();
n.eachAdjacency(function (edge) {
l = edge.getData('synapseIDs').length;
for (i = 0; i < l; i++) {
synapse = Metamaps.Synapses.get(edge.getData('synapseIDs')[i]);
synapse.set('edge', edge);
synapse.updateEdge();
}
});
var pos = n.getPos();
pos.setc(-200, -200);
});
self.mGraph.compute('end');
} else if (self.type == "ForceDirected" && self.savedLayout) {
var i, l, startPos, endPos, topic, synapse;
self.mGraph.graph.eachNode(function (n) {
topic = Metamaps.Topics.get(n.id);
topic.set('node', n);
topic.updateNode();
mapping = topic.getMapping();
n.eachAdjacency(function (edge) {
l = edge.getData('synapseIDs').length;
for (i = 0; i < l; i++) {
synapse = Metamaps.Synapses.get(edge.getData('synapseIDs')[i]);
synapse.set('edge', edge);
synapse.updateEdge();
}
});
startPos = new $jit.Complex(0, 0);
endPos = new $jit.Complex(mapping.get('xloc'), mapping.get('yloc'));
n.setPos(startPos, 'start');
n.setPos(endPos, 'end');
});
} else if (self.type == "ForceDirected3D" || !self.savedLayout) {
self.mGraph.compute();
}
},
/**
* __buildGraph does the heavy lifting of creating the engine that renders the graph with the properties we desire
*
* @param vizData a json structure containing the data to be rendered.
*/
__buildGraph: function (vizData) {
var self = Metamaps.Visualize
RGraphSettings = $.extend(true, {}, Metamaps.JIT.ForceDirected.graphSettings);
if (self.type == "RGraph") {
$jit.RGraph.Plot.NodeTypes.implement(Metamaps.JIT.ForceDirected.nodeSettings);
$jit.RGraph.Plot.EdgeTypes.implement(Metamaps.JIT.ForceDirected.edgeSettings);
RGraphSettings.background = Metamaps.JIT.RGraph.background;
RGraphSettings.levelDistance = Metamaps.JIT.RGraph.levelDistance;
self.mGraph = new $jit.RGraph(RGraphSettings);
} else if (self.type == "ForceDirected") {
$jit.ForceDirected.Plot.NodeTypes.implement(Metamaps.JIT.ForceDirected.nodeSettings);
$jit.ForceDirected.Plot.EdgeTypes.implement(Metamaps.JIT.ForceDirected.edgeSettings);
self.mGraph = new $jit.ForceDirected(Metamaps.JIT.ForceDirected.graphSettings);
} else if (self.type == "ForceDirected3D") {
// init ForceDirected3D
self.mGraph = new $jit.ForceDirected3D(Metamaps.JIT.ForceDirected3D.graphSettings);
self.cameraPosition = self.mGraph.canvas.canvases[0].camera.position;
}
// load JSON data, if it's not empty
if (!self.loadLater) {
//load JSON data.
self.mGraph.loadJSON(vizData);
//compute positions and plot.
self.computePositions();
if (self.type == "RGraph") {
self.mGraph.fx.animate(Metamaps.JIT.RGraph.animate);
} else if (self.type == "ForceDirected" && self.savedLayout) {
Metamaps.Organize.loadSavedLayout();
} else if (self.type == "ForceDirected3D" || !self.savedLayout) {
self.mGraph.animate(Metamaps.JIT.ForceDirected.animateFDLayout);
}
}
}
}; // end Metamaps.Visualize
/*
*
* UTIL
*
*/
Metamaps.Util = {
// helper function to determine how many lines are needed
// Line Splitter Function
// copyright Stephen Chapman, 19th April 2006
// you may copy this code but please keep the copyright notice as well
splitLine: function (st, n) {
var b = '';
var s = st;
while (s.length > n) {
var c = s.substring(0, n);
var d = c.lastIndexOf(' ');
var e = c.lastIndexOf('\n');
if (e != -1) d = e;
if (d == -1) d = n;
b += c.substring(0, d) + '\n';
s = s.substring(d + 1);
}
return b + s;
},
decodeEntities: function (desc) {
var str, temp = document.createElement('p');
temp.innerHTML = desc; //browser handles the topics
str = temp.textContent || temp.innerText;
temp = null; //delete the element;
return str;
}, //decodeEntities
getDistance: function (p1, p2) {
return Math.sqrt(Math.pow((p2.x - p1.x), 2) + Math.pow((p2.y - p1.y), 2));
},
generateOptionsList: function (data) {
var newlist = "";
for (var i = 0; i < data.length; i++) {
newlist = newlist + '';
}
return newlist;
},
checkURLisImage: function (url) {
// when the page reloads the following regular expression will be screwed up
// please replace it with this one before you save: /*backslashhere*.(jpeg|jpg|gif|png)$/
return (url.match(/\.(jpeg|jpg|gif|png)$/) != null);
},
checkURLisYoutubeVideo: function (url) {
return (url.match(/^http:\/\/(?:www\.)?youtube.com\/watch\?(?=[^?]*v=\w+)(?:[^\s?]+)?$/) != null);
}
}; // end Metamaps.Util
/*
*
* REALTIME
*
*/
Metamaps.Realtime = {
// this is for the heroku staging environment
//Metamaps.Realtime.socket = io.connect('http://gentle-savannah-1303.herokuapp.com');
// this is for metamaps.cc
//Metamaps.Realtime.socket = io.connect('http://metamaps.cc:5001');
// this is for localhost development
//Metamaps.Realtime.socket = io.connect('http://localhost:5001');
socket: null,
isOpen: false,
timeOut: null,
changing: false,
mappersOnMap: {},
status: true, // stores whether realtime is True/On or False/Off
init: function () {
var self = Metamaps.Realtime;
$(".realtimeOnOff").click(self.toggle);
$(".sidebarCollaborate").hover(self.open, self.close);
var mapperm = Metamaps.Active.Map && Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper);
if (mapperm) {
self.socket = io.connect('http://localhost:5001');
self.socket.on('connect', function () {
console.log('socket connected');
self.setupSocket();
});
}
},
toggle: function () {
var self = Metamaps.Realtime;
if (!self.status) {
self.sendRealtimeOn();
$(this).html('ON').removeClass('rtOff').addClass('rtOn');
$(".rtMapperSelf").removeClass('littleRtOff').addClass('littleRtOn');
} else {
self.sendRealtimeOff();
$(this).html('OFF').removeClass('rtOn').addClass('rtOff');
$(".rtMapperSelf").removeClass('littleRtOn').addClass('littleRtOff');
}
self.status = !self.status;
$(".sidebarCollaborateIcon").toggleClass("blue");
},
open: function () {
var self = Metamaps.Realtime;
clearTimeout(self.timeOut);
if (!self.isOpen && !self.changing) {
self.changing = true;
$('.sidebarCollaborateBox').fadeIn(200, function () {
self.changing = false;
self.isOpen = true;
});
}
},
close: function () {
var self = Metamaps.Realtime;
self.timeOut = setTimeout(function () {
if (!self.changing) {
self.changing = true;
$('.sidebarCollaborateBox').fadeOut(200, function () {
self.changing = false;
self.isOpen = false;
});
}
}, 500);
},
setupSocket: function () {
var self = Metamaps.Realtime;
var socket = Metamaps.Realtime.socket;
var myId = Metamaps.Active.Mapper.id;
socket.emit('newMapperNotify', {
userid: myId,
username: Metamaps.Active.Mapper.get("name"),
mapid: Metamaps.Active.Map.id
});
// if you're the 'new guy' update your list with who's already online
socket.on(myId + '-' + Metamaps.Active.Map.id + '-UpdateMapperList', self.updateMapperList);
// receive word that there's a new mapper on the map
socket.on('maps-' + Metamaps.Active.Map.id + '-newmapper', self.newPeerOnMap);
// receive word that a mapper left the map
socket.on('maps-' + Metamaps.Active.Map.id + '-lostmapper', self.lostPeerOnMap);
// receive word that there's a mapper turned on realtime
socket.on('maps-' + Metamaps.Active.Map.id + '-newrealtime', self.newCollaborator);
// receive word that there's a mapper turned on realtime
socket.on('maps-' + Metamaps.Active.Map.id + '-lostrealtime', self.lostCollaborator);
socket.on('maps-' + Metamaps.Active.Map.id, self.contentUpdate);
},
sendRealtimeOn: function () {
var self = Metamaps.Realtime;
var socket = Metamaps.Realtime.socket;
// send this new mapper back your details, and the awareness that you're online
var update = {
username: Metamaps.Active.Mapper.get("name"),
userid: Metamaps.Active.Mapper.id,
mapid: Metamaps.Active.Map.id
};
socket.emit('notifyStartRealtime', update);
},
sendRealtimeOff: function () {
var self = Metamaps.Realtime;
var socket = Metamaps.Realtime.socket;
// send this new mapper back your details, and the awareness that you're online
var update = {
username: Metamaps.Active.Mapper.get("name"),
userid: Metamaps.Active.Mapper.id,
mapid: Metamaps.Active.Map.id
};
socket.emit('notifyStopRealtime', update);
},
updateMapperList: function (data) {
var self = Metamaps.Realtime;
var socket = Metamaps.Realtime.socket;
// data.userid
// data.username
// data.userrealtime
self.mappersOnMap[data.userid] = {
name: data.username,
realtime: data.userrealtime
};
var onOff = data.userrealtime ? "On" : "Off";
var mapperListItem = '
' + data.username + '
';
$('#mapper' + data.userid).remove();
$('.realtimeMapperList ul').append(mapperListItem);
},
newPeerOnMap: function (data) {
var self = Metamaps.Realtime;
var socket = Metamaps.Realtime.socket;
// data.userid
// data.username
self.mappersOnMap[data.userid] = {
name: data.username,
realtime: true
};
var mapperListItem = '
' + data.username + '
';
$('#mapper' + data.userid).remove();
$('.realtimeMapperList ul').append(mapperListItem);
Metamaps.GlobalUI.notifyUser(data.username + ' just joined the map');
// send this new mapper back your details, and the awareness that you've loaded the map
var update = {
userToNotify: data.userid,
username: Metamaps.Active.Mapper.get("name"),
userid: Metamaps.Active.Mapper.id,
userrealtime: self.status,
mapid: Metamaps.Active.Map.id
};
socket.emit('updateNewMapperList', update);
},
lostPeerOnMap: function (data) {
var self = Metamaps.Realtime;
var socket = Metamaps.Realtime.socket;
// data.userid
// data.username
delete self.mappersOnMap[data.userid];
$('#mapper' + data.userid).remove();
Metamaps.GlobalUI.notifyUser(data.username + ' just left the map');
},
newCollaborator: function (data) {
var self = Metamaps.Realtime;
var socket = Metamaps.Realtime.socket;
// data.userid
// data.username
self.mappersOnMap[data.userid].realtime = true;
$('#mapper' + data.userid).removeClass('littleRtOff').addClass('littleRtOn');
Metamaps.GlobalUI.notifyUser(data.username + ' just turned on realtime');
},
lostCollaborator: function (data) {
var self = Metamaps.Realtime;
var socket = Metamaps.Realtime.socket;
// data.userid
// data.username
self.mappersOnMap[data.userid].realtime = false;
$('#mapper' + data.userid).removeClass('littleRtOn').addClass('littleRtOff');
Metamaps.GlobalUI.notifyUser(data.username + ' just turned off realtime');
},
contentUpdate: function (data) {
var self = Metamaps.Realtime;
var socket = Metamaps.Realtime.socket;
var graph = Metamaps.Visualize.mGraph.graph;
//as long as you weren't the origin of the changes, update your map
if (data.origin != Metamaps.Active.Mapper.id && self.status) {
if (data.resource == 'Topic') {
topic = $.parseJSON(data.obj);
if (data.action == 'create') {
self.addTopicToMap(topic);
} else if (data.action == 'update' && graph.getNode(topic.id) != 'undefined') {
self.updateTopicOnMap(topic);
} else if (data.action == 'destroy' && graph.getNode(topic.id) != 'undefined') {
Metamaps.Control.hideNode(topic.id)
}
return;
} else if (data.resource == 'Synapse') {
synapse = $.parseJSON(data.obj);
if (data.action == 'create') {
self.addSynapseToMap(synapse);
} else if (data.action == 'update' &&
graph.getAdjacence(synapse.data.$direction['0'], synapse.data.$direction['1']) != 'undefined') {
self.updateSynapseOnMap(synapse);
} else if (data.action == 'destroy' &&
graph.getAdjacence(synapse.data.$direction['0'], synapse.data.$direction['1']) != 'undefined') {
var edge = graph.getAdjacence(synapse.data.$direction['0'], synapse.data.$direction['1']);
Metamaps.Control.hideEdge(edge);
}
return;
}
}
},
addTopicToMap: function (topic) {
// TODO
var newPos, tempForT;
Metamaps.Visualize.mGraph.graph.addNode(topic);
tempForT = Metamaps.Visualize.mGraph.graph.getNode(topic.id);
tempForT.setData('dim', 1, 'start');
tempForT.setData('dim', 25, 'end');
newPos = new $jit.Complex();
newPos.x = tempForT.data.$xloc;
newPos.y = tempForT.data.$yloc;
tempForT.setPos(newPos, 'start');
tempForT.setPos(newPos, 'current');
tempForT.setPos(newPos, 'end');
Metamaps.Visualize.mGraph.fx.plotNode(tempForT, Metamaps.Visualize.mGraph.canvas);
},
updateTopicOnMap: function (topic) {
// TODO
var newPos, tempForT;
tempForT = Metamaps.Visualize.mGraph.graph.getNode(topic.id);
tempForT.data = topic.data;
tempForT.name = topic.name;
if (MetamapsModel.showcardInUse === topic.id) {
populateShowCard(tempForT);
}
newPos = new $jit.Complex();
newPos.x = tempForT.data.$xloc;
newPos.y = tempForT.data.$yloc;
tempForT.setPos(newPos, 'start');
tempForT.setPos(newPos, 'current');
tempForT.setPos(newPos, 'end');
return Metamaps.Visualize.mGraph.fx.animate({
modes: ['linear', 'node-property:dim', 'edge-property:lineWidth'],
transition: $jit.Trans.Quad.easeInOut,
duration: 500
});
},
addSynapseToMap: function (synapse) {
// TODO
var Node1, Node2, tempForS;
Node1 = Metamaps.Visualize.mGraph.graph.getNode(synapse.data.$direction[0]);
Node2 = Metamaps.Visualize.mGraph.graph.getNode(synapse.data.$direction[1]);
Metamaps.Visualize.mGraph.graph.addAdjacence(Node1, Node2, {});
tempForS = Metamaps.Visualize.mGraph.graph.getAdjacence(Node1.id, Node2.id);
tempForS.setDataset('start', {
lineWidth: 0.4
});
tempForS.setDataset('end', {
lineWidth: 2
});
tempForS.data = synapse.data;
Metamaps.Visualize.mGraph.fx.plotLine(tempForS, Metamaps.Visualize.mGraph.canvas);
return Metamaps.Visualize.mGraph.fx.animate({
modes: ['linear', 'node-property:dim', 'edge-property:lineWidth'],
transition: $jit.Trans.Quad.easeInOut,
duration: 500
});
},
updateSynapseOnMap: function (synapse) {
// TODO
var k, tempForS, v, wasShowDesc, _ref;
tempForS = Metamaps.Visualize.mGraph.graph.getAdjacence(synapse.data.$direction[0], synapse.data.$direction[1]);
wasShowDesc = tempForS.data.$showDesc;
_ref = synapse.data;
for (k in _ref) {
v = _ref[k];
tempForS.data[k] = v;
}
tempForS.data.$showDesc = wasShowDesc;
if (MetamapsModel.edgecardInUse === synapse.data.$id) { // TODO
editEdge(tempForS, false);
}
return Metamaps.Visualize.mGraph.plot();
}
}; // end Metamaps.Realtime
/*
*
* CONTROL
*
*/
Metamaps.Control = {
init: function () {
},
selectNode: function (node,e) {
if (Metamaps.Selected.Nodes.indexOf(node) != -1) return;
node.selected = true;
node.setData('dim', 30, 'current');
if(!(e.ctrlKey) && !(e.altKey)){
node.eachAdjacency(function (adj) {
Metamaps.Control.selectEdge(adj);
});
}
Metamaps.Selected.Nodes.push(node);
},
deselectAllNodes: function () {
var l = Metamaps.Selected.Nodes.length;
for (var i = l - 1; i >= 0; i -= 1) {
var node = Metamaps.Selected.Nodes[i];
Metamaps.Control.deselectNode(node);
}
Metamaps.Visualize.mGraph.plot();
},
deselectNode: function (node) {
delete node.selected;
/*
node.eachAdjacency(function (adj) {
Metamaps.Control.deselectEdge(adj);
});
*/
node.setData('dim', 25, 'current');
//remove the node
Metamaps.Selected.Nodes.splice(
Metamaps.Selected.Nodes.indexOf(node), 1);
},
deleteSelectedNodes: function () { // refers to deleting topics permanently
var l = Metamaps.Selected.Nodes.length;
for (var i = l - 1; i >= 0; i -= 1) {
var node = Metamaps.Selected.Nodes[i];
Metamaps.Control.deleteNode(node.id);
}
},
deleteNode: function (nodeid) { // refers to deleting topics permanently
var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid);
var id = node.getData('id');
Metamaps.Control.deselectNode(node);
Metamaps.Topics.get(id).destroy();
Metamaps.Control.hideNode(nodeid);
},
removeSelectedNodes: function () { // refers to removing topics permanently from a map
var l = Metamaps.Selected.Nodes.length,
i,
node,
mapperm = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper);
if (mapperm) {
for (i = l - 1; i >= 0; i -= 1) {
node = Metamaps.Selected.Nodes[i];
Metamaps.Control.removeNode(node.id);
}
}
},
removeNode: function (nodeid) { // refers to removing topics permanently from a map
var mapperm = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper);
var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid);
var mappingid = node.getData("mapping").id;
if (mapperm) {
Metamaps.Control.deselectNode(node);
Metamaps.Mappings.get(mappingid).destroy();
Metamaps.Control.hideNode(nodeid);
}
},
hideSelectedNodes: function () {
var l = Metamaps.Selected.Nodes.length,
i,
node;
for (i = l - 1; i >= 0; i -= 1) {
node = Metamaps.Selected.Nodes[i];
Metamaps.Control.hideNode(node.id);
}
},
hideNode: function (nodeid) {
var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid);
if (nodeid == Metamaps.Visualize.mGraph.root) { // && Metamaps.Visualize.type === "RGraph"
alert("You can't hide this topic, it is the root of your graph.");
return;
}
Metamaps.Control.deselectNode(node);
node.setData('alpha', 0, 'end');
node.eachAdjacency(function (adj) {
adj.setData('alpha', 0, 'end');
});
Metamaps.Visualize.mGraph.fx.animate({
modes: ['node-property:alpha',
'edge-property:alpha'
],
duration: 500
});
setTimeout(function () {
Metamaps.Visualize.mGraph.graph.removeNode(nodeid);
}, 500);
},
selectEdge: function (edge) {
if (Metamaps.Selected.Edges.indexOf(edge) != -1) return;
edge.setData('showDesc', true, 'current');
if (!Metamaps.Settings.embed) {
edge.setDataset('end', {
lineWidth: 4,
color: Metamaps.Settings.colors.synapses.selected,
alpha: 1
});
} else if (Metamaps.Settings.embed) {
edge.setDataset('end', {
lineWidth: 4,
color: Metamaps.Settings.colors.synapses.selected,
alpha: 1
});
}
Metamaps.Visualize.mGraph.fx.animate({
modes: ['edge-property:lineWidth:color:alpha'],
duration: 100
});
Metamaps.Selected.Edges.push(edge);
},
deselectAllEdges: function () {
var l = Metamaps.Selected.Edges.length;
for (var i = l - 1; i >= 0; i -= 1) {
var edge = Metamaps.Selected.Edges[i];
Metamaps.Control.deselectEdge(edge);
}
Metamaps.Visualize.mGraph.plot();
},
deselectEdge: function (edge) {
edge.setData('showDesc', false, 'current');
edge.setDataset('end', {
lineWidth: 2,
color: Metamaps.Settings.colors.synapses.normal,
alpha: 0.4
});
if (Metamaps.Mouse.edgeHoveringOver == edge) {
edge.setData('showDesc', true, 'current');
edge.setDataset('end', {
lineWidth: 4,
color: Metamaps.Settings.colors.synapses.hover,
alpha: 1
});
}
Metamaps.Visualize.mGraph.fx.animate({
modes: ['edge-property:lineWidth:color:alpha'],
duration: 100
});
//remove the edge
Metamaps.Selected.Edges.splice(
Metamaps.Selected.Edges.indexOf(edge), 1);
},
deleteSelectedEdges: function () { // refers to deleting topics permanently
var edge,
l = Metamaps.Selected.Edges.length;
for (var i = l - 1; i >= 0; i -= 1) {
edge = Metamaps.Selected.Edges[i];
Metamaps.Control.deleteEdge(edge);
}
},
deleteEdge: function (edge) {
// TODO make it so that you select which one, of multiple possible synapses you want to delete
//var id = edge.getData("id");
//Metamaps.Synapses.get(id).destroy();
//Metamaps.Control.hideEdge(edge);
},
removeSelectedEdges: function () {
var l = Metamaps.Selected.Edges.length,
i,
edge;
if (Metamaps.Active.Map) {
for (i = l - 1; i >= 0; i -= 1) {
edge = Metamaps.Selected.Edges[i];
Metamaps.Control.removeEdge(edge);
}
Metamaps.Selected.Edges = new Array();
}
},
removeEdge: function (edge) {
// TODO make it so that you select which one, of multiple possible synapses you want
//var mappingid = edge.getData("mappingid");
//Metamaps.Mappings.get(mappingid).destroy();
//Metamaps.Control.hideEdge(edge);
},
hideSelectedEdges: function () {
var edge,
l = Metamaps.Selected.Edges.length,
i;
for (i = l - 1; i >= 0; i -= 1) {
edge = Metamaps.Selected.Edges[i];
Metamaps.Control.hideEdge(edge);
}
Metamaps.Selected.Edges = new Array();
},
hideEdge: function (edge) {
var from = edge.nodeFrom.id;
var to = edge.nodeTo.id;
edge.setData('alpha', 0, 'end');
Metamaps.Visualize.mGraph.fx.animate({
modes: ['edge-property:alpha'],
duration: 500
});
setTimeout(function () {
Metamaps.Visualize.mGraph.graph.removeAdjacence(from, to);
}, 500);
},
updateSelectedPermissions: function (permission) {
var edge, synapse, node, topic;
Metamaps.GlobalUI.notifyUser('Working...');
// variables to keep track of how many nodes and synapses you had the ability to change the permission of
var nCount = 0,
sCount = 0;
// change the permission of the selected synapses, if logged in user is the original creator
var l = Metamaps.Selected.Edges.length;
for (var i = l - 1; i >= 0; i -= 1) {
edge = Metamaps.Selected.Edges[i];
synapse = edge.getData('synapses')[0];
if (synapse.authorizePermissionChange(Metamaps.Active.Mapper)) {
synapse.save({
permission: permission
});
sCount++;
}
}
// change the permission of the selected topics, if logged in user is the original creator
var l = Metamaps.Selected.Nodes.length;
for (var i = l - 1; i >= 0; i -= 1) {
node = Metamaps.Selected.Nodes[i];
topic = node.getData('topic');
if (topic.authorizePermissionChange(Metamaps.Active.Mapper)) {
topic.save({
permission: permission
});
nCount++;
}
}
var nString = nCount == 1 ? (nCount.toString() + ' topic and ') : (nCount.toString() + ' topics and ');
var sString = sCount == 1 ? (sCount.toString() + ' synapse') : (sCount.toString() + ' synapses');
var message = nString + sString + ' you created updated to ' + permission;
Metamaps.GlobalUI.notifyUser(message);
},
}; // end Metamaps.Control
/*
*
* FILTER
*
*/
Metamaps.Filter = {
filters: {
name: "",
metacode: [],
mappers: [],
synapseTypes: []
},
isOpen: false,
timeOut: null,
changing: false,
init: function () {
var self = Metamaps.Filter;
$(".sidebarFilter").hover(self.open, self.close);
// initialize scroll bar for filter by metacode, then hide it and position it correctly again
$("#filter_by_metacode").mCustomScrollbar({
mouseWheelPixels: 200,
advanced: {
updateOnContentResize: true
}
});
$('.sidebarFilterBox').hide().css({
position: 'absolute',
top: '45px',
right: '-36px'
});
$('.sidebarFilterBox .showAll').click(self.filterNoMetacodes);
$('.sidebarFilterBox .hideAll').click(self.filterAllMetacodes);
// toggle visibility of topics with metacodes based on status in the filters list
$('#filter_by_metacode ul li').click(self.toggleMetacode);
},
open: function () {
var self = Metamaps.Filter;
clearTimeout(self.timeOut);
if (!self.isOpen && !self.changing) {
self.changing = true;
$('.sidebarFilterBox').fadeIn(200, function () {
self.changing = false;
self.isOpen = true;
});
}
},
close: function () {
var self = Metamaps.Filter;
self.timeOut = setTimeout(function () {
if (!self.changing) {
self.changing = true;
$('.sidebarFilterBox').fadeOut(200, function () {
self.changing = false;
self.isOpen = false;
});
}
}, 500);
},
filterNoMetacodes: function (e) {
$('#filter_by_metacode ul li').removeClass('toggledOff');
// TODO
/*
showAll();
for (var catVis in categoryVisible) {
categoryVisible[catVis] = true;
}
*/
},
filterAllMetacodes: function (e) {
$('#filter_by_metacode ul li').addClass('toggledOff');
// TODO
/*
hideAll();
for (var catVis in categoryVisible) {
categoryVisible[catVis] = false;
}
*/
},
toggleMetacode: function () {
var category = $(this).children('img').attr('alt');
// TODO
/*switchVisible(category);
// toggle the image and the boolean array value
if (categoryVisible[category] == true) {
$(this).addClass('toggledOff');
categoryVisible[category] = false;
} else if (categoryVisible[category] == false) {
$(this).removeClass('toggledOff');
categoryVisible[category] = true;
}*/
},
passFilters: function (topic) {
var self = Metamaps.Find;
var filters = self.filters;
var passesName = filters.name == "" ? true : false,
passesType = filters.type == [] ? true : false;
//filter by name
if (topic.get('1')[1][0].toLowerCase().indexOf(filters.name) !== -1) {
passesName = true;
}
// filter by type
if (!filters.type == []) {
// get the array of types that your topic 'is'
var metacodes = topic.get('2') ? topic.get('2')[1] : [];
if (_.intersection(filters.type, metacodes).length == 0) passesType = true;
}
if (passesName && passesType) {
return true;
} else {
return false;
}
}
}; // end Metamaps.Filter
/*
*
* LISTENERS
*
*/
Metamaps.Listeners = {
init: function () {
$(document).on('keydown', function (e) {
switch (e.which) {
case 13:
Metamaps.JIT.enterKeyHandler();
e.preventDefault();
break;
case 27:
Metamaps.JIT.escKeyHandler();
break;
default:
break; //alert(e.which);
}
});
//$(window).resize(function () {
// Metamaps.Visualize.mGraph.canvas.resize($(window).width(), $(window).height());
//});
}
}; // end Metamaps.Listeners
/*
*
* ORGANIZE
*
*/
Metamaps.Organize = {
init: function () {
},
arrange: function (layout, centerNode) {
// first option for layout to implement is 'grid', will do an evenly spaced grid with its center at the 0,0 origin
if (layout == 'grid') {
var numNodes = _.size(Metamaps.Visualize.mGraph.graph.nodes); // this will always be an integer, the # of nodes on your graph visualization
var numColumns = Math.floor(Math.sqrt(numNodes)); // the number of columns to make an even grid
var GRIDSPACE = 400;
var row = 0;
var column = 0;
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
if (column == numColumns) {
column = 0;
row += 1;
}
var newPos = new $jit.Complex();
newPos.x = column * GRIDSPACE;
newPos.y = row * GRIDSPACE;
n.setPos(newPos, 'end');
column += 1;
});
Metamaps.Visualize.mGraph.animate(Metamaps.JIT.ForceDirected.animateSavedLayout);
} else if (layout == 'grid_full') {
// this will always be an integer, the # of nodes on your graph visualization
var numNodes = _.size(Metamaps.Visualize.mGraph.graph.nodes);
//var numColumns = Math.floor(Math.sqrt(numNodes)); // the number of columns to make an even grid
//var GRIDSPACE = 400;
var height = Metamaps.Visualize.mGraph.canvas.getSize(0).height;
var width = Metamaps.Visualize.mGraph.canvas.getSize(0).width;
var totalArea = height * width;
var cellArea = totalArea / numNodes;
var ratio = height / width;
var cellWidth = sqrt(cellArea / ratio);
var cellHeight = cellArea / cellWidth;
var row = floor(height / cellHeight);
var column = floor(width / cellWidth);
var totalCells = row * column;
if (totalCells)
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
if (column == numColumns) {
column = 0;
row += 1;
}
var newPos = new $jit.Complex();
newPos.x = column * GRIDSPACE;
newPos.y = row * GRIDSPACE;
n.setPos(newPos, 'end');
column += 1;
});
Metamaps.Visualize.mGraph.animate(Metamaps.JIT.ForceDirected.animateSavedLayout);
} else if (layout == 'radial') {
var centerX = centerNode.getPos().x;
var centerY = centerNode.getPos().y;
centerNode.setPos(centerNode.getPos(), 'end');
console.log(centerNode.adjacencies);
var lineLength = 200;
var usedNodes = {};
usedNodes[centerNode.id] = centerNode;
var radial = function (node, level, degree) {
if (level == 1) {
var numLinksTemp = _.size(node.adjacencies);
var angleTemp = 2 * Math.PI / numLinksTemp;
} else {
angleTemp = 2 * Math.PI / 20
};
node.eachAdjacency(function (a) {
var isSecondLevelNode = (centerNode.adjacencies[a.nodeTo.id] != undefined && level > 1);
if (usedNodes[a.nodeTo.id] == undefined && !isSecondLevelNode) {
var newPos = new $jit.Complex();
newPos.x = level * lineLength * Math.sin(degree) + centerX;
newPos.y = level * lineLength * Math.cos(degree) + centerY;
a.nodeTo.setPos(newPos, 'end');
usedNodes[a.nodeTo.id] = a.nodeTo;
radial(a.nodeTo, level + 1, degree);
degree += angleTemp;
};
});
};
radial(centerNode, 1, 0);
Metamaps.Visualize.mGraph.animate(Metamaps.JIT.ForceDirected.animateSavedLayout);
} else if (layout == 'center_viewport') {
var lowX = 0,
lowY = 0,
highX = 0,
highY = 0;
var oldOriginX = Metamaps.Visualize.mGraph.canvas.translateOffsetX;
var oldOriginY = Metamaps.Visualize.mGraph.canvas.translateOffsetY;
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
if (n.id === 1) {
lowX = n.getPos().x;
lowY = n.getPos().y;
highX = n.getPos().x;
highY = n.getPos().y;
};
if (n.getPos().x < lowX) lowX = n.getPos().x;
if (n.getPos().y < lowY) lowY = n.getPos().y;
if (n.getPos().x > highX) highX = n.getPos().x;
if (n.getPos().y > highY) highY = n.getPos().y;
});
console.log(lowX, lowY, highX, highY);
var newOriginX = (lowX + highX) / 2;
var newOriginY = (lowY + highY) / 2;
} else alert('please call function with a valid layout dammit!');
},
loadSavedLayout: function (id) {
Metamaps.Visualize.computePositions();
Metamaps.Visualize.mGraph.animate(Metamaps.JIT.ForceDirected.animateSavedLayout);
},
}; // end Metamaps.Organize
/*
*
* TOPIC
*
*/
Metamaps.Topic = {
// this function is to retrieve a topic JSON object from the database
// @param id = the id of the topic to retrieve
get: function (id, callback) {
// if the desired topic is not yet in the local topic repository, fetch it
if (Metamaps.Topics.get(id) == undefined) {
//console.log("Ajax call!");
if (!callback) {
var e = $.ajax({
url: "/topics/" + id + ".json",
async: false
});
Metamaps.Topics.add($.parseJSON(e.responseText));
return Metamaps.Topics.get(id);
} else {
return $.ajax({
url: "/topics/" + id + ".json",
success: function (data) {
Metamaps.Topics.add(data);
callback(Metamaps.Topics.get(id));
}
});
}
} else {
if (!callback) {
return Metamaps.Topics.get(id);
} else {
return callback(Metamaps.Topics.get(id));
}
}
},
/*
*
*
*/
renderTopic: function (mapping, topic, createNewInDB) {
var self = Metamaps.Topic;
var nodeOnViz, tempPos;
var newnode = topic.createNode();
if (!$.isEmptyObject(Metamaps.Visualize.mGraph.graph.nodes)) {
Metamaps.Visualize.mGraph.graph.addNode(newnode);
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
n.setData("dim", 25, "start");
n.setData("dim", 25, "end");
});
nodeOnViz = Metamaps.Visualize.mGraph.graph.getNode(newnode.id);
topic.set('node', nodeOnViz);
topic.updateNode(); // links the topic and the mapping to the node
nodeOnViz.setData("dim", 1, "start");
nodeOnViz.setData("dim", 25, "end");
if (Metamaps.Visualize.type === "RGraph") {
tempPos = new $jit.Complex(mapping.get('xloc'), mapping.get('yloc'));
tempPos = tempPos.toPolar();
nodeOnViz.setPos(tempPos, "current");
nodeOnViz.setPos(tempPos, "start");
nodeOnViz.setPos(tempPos, "end");
} else if (Metamaps.Visualize.type === "ForceDirected") {
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), "current");
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), "start");
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), "end");
}
if (Metamaps.Create.newTopic.addSynapse) {
Metamaps.Create.newSynapse.topic1id = tempNode.id;
Metamaps.Create.newSynapse.topic2id = nodeOnViz.id;
Metamaps.Create.newSynapse.open();
Metamaps.Visualize.mGraph.fx.animate({
modes: ["node-property:dim"],
duration: 500,
onComplete: function () {
tempNode = null;
tempNode2 = null;
tempInit = false;
}
});
} else {
Metamaps.Visualize.mGraph.fx.plotNode(nodeOnViz, Metamaps.Visualize.mGraph.canvas);
Metamaps.Visualize.mGraph.fx.animate({
modes: ["node-property:dim"],
duration: 500,
onComplete: function () {
}
});
}
} else {
Metamaps.Visualize.mGraph.loadJSON(newnode);
nodeOnViz = Metamaps.Visualize.mGraph.graph.getNode(newnode.id);
topic.set('node', nodeOnViz);
topic.updateNode(); // links the topic and the mapping to the node
nodeOnViz.setData("dim", 1, "start");
nodeOnViz.setData("dim", 25, "end");
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), "current");
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), "start");
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), "end");
Metamaps.Visualize.mGraph.fx.plotNode(nodeOnViz, Metamaps.Visualize.mGraph.canvas);
Metamaps.Visualize.mGraph.fx.animate({
modes: ["node-property:dim"],
duration: 500,
onComplete: function () {
}
});
}
if (!Metamaps.Settings.sandbox && createNewInDB) {
if (topic.isNew()) {
topic.save(null, {
success: function (topicModel, response) {
if (Metamaps.Active.Map) {
mapping.save({ topic_id: topicModel.id });
}
},
error: function (model, response) {
console.log('error saving topic to database');
}
});
} else if (!topic.isNew() && Metamaps.Active.Map) {
mapping.save();
}
}
},
createTopicLocally: function () {
var self = Metamaps.Topic;
var metacode = Metamaps.Metacodes.findWhere({
name: Metamaps.Create.newTopic.metacode
});
var topic = new Metamaps.Backbone.Topic({
name: Metamaps.Create.newTopic.name,
metacode_id: metacode.id
});
Metamaps.Topics.add(topic);
var mapping = new Metamaps.Backbone.Mapping({
category: "Topic",
xloc: Metamaps.Create.newTopic.x,
yloc: Metamaps.Create.newTopic.y,
topic_id: topic.cid
});
Metamaps.Mappings.add(mapping);
//these can't happen until the value is retrieved, which happens in the line above
Metamaps.Create.newTopic.hide();
self.renderTopic(mapping, topic, true); // this function also includes the creation of the topic in the database
},
getTopicFromAutocomplete: function (id) {
var self = Metamaps.Topic;
Metamaps.Create.newTopic.hide();
var topic = self.get(id);
var mapping = new Metamaps.Backbone.Mapping({
category: "Topic",
xloc: Metamaps.Create.newTopic.x,
yloc: Metamaps.Create.newTopic.y,
topic_id: topic.id
});
Metamaps.Mappings.add(mapping);
self.renderTopic(mapping, topic, false);
}
}; // end Metamaps.Topic
/*
*
* SYNAPSE
*
*/
Metamaps.Synapse = {
// this function is to retrieve a synapse JSON object from the database
// @param id = the id of the synapse to retrieve
get: function (id, callback) {
// if the desired topic is not yet in the local topic repository, fetch it
if (Metamaps.Synapses.get(id) == undefined) {
if (!callback) {
var e = $.ajax({
url: "/synapses/" + id + ".json",
async: false
});
Metamaps.Synapses.add($.parseJSON(e.responseText));
return Metamaps.Synapses.get(id);
} else {
return $.ajax({
url: "/synapses/" + id + ".json",
success: function (data) {
Metamaps.Synapses.add(data);
callback(Metamaps.Synapses.get(id));
}
});
}
} else {
if (!callback) {
return Metamaps.Synapses.get(id);
} else {
return callback(Metamaps.Synapses.get(id));
}
}
},
/*
*
*
*/
renderSynapse: function (mapping, synapse, node1, node2, createNewInDB) {
var self = Metamaps.Synapse;
var edgeOnViz;
var newedge = synapse.createEdge();
Metamaps.Visualize.mGraph.graph.addAdjacence(node1, node2, newedge.data);
edgeOnViz = Metamaps.Visualize.mGraph.graph.getAdjacence(node1.id, node2.id);
synapse.set('edge', edgeOnViz);
synapse.updateEdge(); // links the topic and the mapping to the node
Metamaps.Visualize.mGraph.fx.plotLine(edgeOnViz, Metamaps.Visualize.mGraph.canvas);
Metamaps.Control.selectEdge(edgeOnViz);
if (!Metamaps.Settings.sandbox && createNewInDB) {
if (synapse.isNew()) {
synapse.save(null, {
success: function (synapseModel, response) {
if (Metamaps.Active.Map) {
mapping.save({ synapse_id: synapseModel.id });
}
},
error: function (model, response) {
console.log('error saving synapse to database');
}
});
} else if (!synapse.isNew() && Metamaps.Active.Map) {
mapping.save();
}
}
},
createSynapseLocally: function () {
var self = Metamaps.Synapse,
topic1,
topic2,
node1,
node2,
synapse,
mapping;
//for each node in this array we will create a synapse going to the position2 node.
var synapsesToCreate = [];
node2 = Metamaps.Visualize.mGraph.graph.getNode(Metamaps.Create.newSynapse.topic2id);
topic2 = node2.getData('topic');
var len = Metamaps.Selected.Nodes.length;
if (len == 0) {
synapsesToCreate[0] = Metamaps.Visualize.mGraph.graph.getNode(Metamaps.Create.newSynapse.topic1id);
} else if (len > 0) {
synapsesToCreate = Metamaps.Selected.Nodes;
}
for (var i = 0; i < synapsesToCreate.length; i++) {
node1 = synapsesToCreate[i];
topic1 = node1.getData('topic');
synapse = new Metamaps.Backbone.Synapse({
desc: Metamaps.Create.newSynapse.description,
node1_id: topic1.isNew() ? topic1.cid : topic1.id,
node2_id: topic2.isNew() ? topic2.cid : topic2.id,
});
Metamaps.Synapses.add(synapse);
mapping = new Metamaps.Backbone.Mapping({
category: "Synapse",
synapse_id: synapse.cid
});
Metamaps.Mappings.add(mapping);
// this function also includes the creation of the synapse in the database
self.renderSynapse(mapping, synapse, node1, node2, true);
} // for each in synapsesToCreate
Metamaps.Create.newSynapse.hide();
},
getSynapseFromAutocomplete: function (id) {
var self = Metamaps.Synapse,
node1,
node2;
Metamaps.Create.newSynapse.hide();
var synapse = self.get(id);
var mapping = new Metamaps.Backbone.Mapping({
category: "Synapse",
synapse_id: synapse.id
});
Metamaps.Mappings.add(mapping);
node1 = Metamaps.Visualize.mGraph.graph.getNode(Metamaps.Create.newSynapse.topic1id);
node2 = Metamaps.Visualize.mGraph.graph.getNode(Metamaps.Create.newSynapse.topic2id);
self.renderSynapse(mapping, synapse, node1, node2, false);
}
}; // end Metamaps.Synapse
/*
*
* MAP
*
*/
Metamaps.Map = {
init: function () {
var self = Metamaps.Map;
// prevent right clicks on the main canvas, so as to not get in the way of our right clicks
$('#center-container').bind('contextmenu', function (e) {
return false;
});
$('.sidebarFork').click(function () {
self.fork();
});
Metamaps.GlobalUI.CreateMap.emptyForkMapForm = $('#fork_map').html();
self.InfoBox.init();
self.CheatSheet.init();
},
// this function is to retrieve a map JSON object from the database
// @param id = the id of the map to retrieve
get: function (id, callback) {
// if the desired topic is not yet in the local topic repository, fetch it
if (Metamaps.Maps.get(id) == undefined) {
if (!callback) {
var e = $.ajax({
url: "/maps/" + id + ".json",
async: false
});
Metamaps.Maps.add($.parseJSON(e.responseText));
return Metamaps.Maps.get(id);
} else {
return $.ajax({
url: "/users/" + id + ".json",
success: function (data) {
Metamaps.Maps.add(data);
callback(Metamaps.Maps.get(id));
}
});
}
} else {
if (!callback) {
return Metamaps.Maps.get(id);
} else {
return callback(Metamaps.Maps.get(id));
}
}
},
fork: function () {
Metamaps.GlobalUI.openLightbox('forkmap');
var nodes_data = "",
synapses_data = "";
var synapses_array = new Array();
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
//don't add to the map if it was filtered out
// TODO
//if (categoryVisible[n.getData('metacode')] == false) {
// return;
//}
var x, y;
if (n.pos.x && n.pos.y) {
x = n.pos.x;
y = n.pos.y;
} else {
var x = Math.cos(n.pos.theta) * n.pos.rho;
var y = Math.sin(n.pos.theta) * n.pos.rho;
}
nodes_data += n.id + '/' + x + '/' + y + ',';
n.eachAdjacency(function (adj) {
synapses_array.push(adj.getData("synapses")[0].id); // TODO
});
});
//get unique values only
synapses_array = $.grep(synapses_array, function (value, key) {
return $.inArray(value, synapses_array) === key;
});
synapses_data = synapses_array.join();
nodes_data = nodes_data.slice(0, -1);
Metamaps.GlobalUI.CreateMap.topicsToMap = nodes_data;
Metamaps.GlobalUI.CreateMap.synapsesToMap = synapses_data;
}
};
/*
*
* CHEATSHEET
*
*/
Metamaps.Map.CheatSheet = {
init: function () {
// tab the cheatsheet
$('#cheatSheet').tabs().addClass("ui-tabs-vertical ui-helper-clearfix");
$("#cheatSheet .ui-tabs-nav li").removeClass("ui-corner-top").addClass("ui-corner-left");
}
}; // end Metamaps.Map.CheatSheet
/*
*
* INFOBOX
*
*/
Metamaps.Map.InfoBox = {
isOpen: false,
timeOut: null,
changing: false,
selectingPermission: false,
init: function () {
var self = Metamaps.Map.InfoBox;
// because anyone who can edit the map can change the map title
$('.mapInfoName .best_in_place_name').bind("ajax:success", function () {
var name = $(this).html();
$('.mapName').html(name);
Metamaps.Active.Map.set('name', name);
});
$('.yourMap .mapPermission').click(self.onPermissionClick);
$("div.index").hover(self.open, self.close);
},
open: function (event) {
var self = Metamaps.GlobalUI.Account;
clearTimeout(self.timeOut);
if (!self.isOpen && !self.changing && event.target.className != "openCheatsheet openLightbox") {
self.changing = true;
$('.mapInfoBox').fadeIn(200, function () {
self.changing = false;
self.isOpen = true;
});
}
},
close: function () {
var self = Metamaps.GlobalUI.Account;
self.timeOut = setTimeout(function () {
if (!self.changing) {
self.changing = true;
$('.mapInfoBox').fadeOut(200, function () {
self.changing = false;
self.isOpen = false;
});
}
}, 500);
},
onPermissionClick: function () {
var self = Metamaps.Map.InfoBox;
if (!self.selectingPermission) {
self.selectingPermission = true;
$(this).addClass('minimize'); // this line flips the drop down arrow to a pull up arrow
if ($(this).hasClass('commons')) {
$(this).append('
');
} else if ($(this).hasClass('public')) {
$(this).append('
');
} else if ($(this).hasClass('private')) {
$(this).append('
');
}
$('.mapPermission .permissionSelect li').click(self.selectPermission);
} else {
self.selectingPermission = false;
$(this).removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow
$('.mapPermission .permissionSelect').remove();
}
},
selectPermission: function () {
var self = Metamaps.Map.InfoBox;
self.selectingPermission = false;
var permission = $(this).attr('class');
Metamaps.Active.Map.save({
permission: permission
});
$('.mapPermission').removeClass('commons public private minimize').addClass(permission);
$('.mapPermission .permissionSelect').remove();
event.stopPropagation();
}
}; // end Metamaps.Map.InfoBox
/*
*
* MAPPER
*
*/
Metamaps.Mapper = {
// this function is to retrieve a mapper JSON object from the database
// @param id = the id of the mapper to retrieve
get: function (id, callback) {
// if the desired topic is not yet in the local topic repository, fetch it
if (Metamaps.Mappers.get(id) == undefined) {
if (!callback) {
var e = $.ajax({
url: "/users/" + id + ".json",
async: false
});
Metamaps.Mappers.add($.parseJSON(e.responseText));
return Metamaps.Mappers.get(id);
} else {
return $.ajax({
url: "/users/" + id + ".json",
success: function (data) {
Metamaps.Mappers.add(data);
callback(Metamaps.Mappers.get(id));
}
});
}
} else {
if (!callback) {
return Metamaps.Mappers.get(id);
} else {
return callback(Metamaps.Mappers.get(id));
}
}
},
}; // end Metamaps.Mapper