Compare commits

...

16 commits

Author SHA1 Message Date
Connor Turland
e7a52dc14e bugs 2017-01-12 14:11:01 -05:00
Connor Turland
149b7ecbd6 include matter-js in package json 2017-01-12 12:37:16 -05:00
Connor Turland
b2b5090b28 still make it work for logged out users 2017-01-12 12:31:08 -05:00
Connor Turland
38c01c4e8f fix the carousel 2017-01-12 12:19:54 -05:00
Connor Turland
b13ac98c9f chat iss working 2017-01-12 04:55:57 -05:00
Connor Turland
4a17d00123 stuff with metacodes working well again 2017-01-12 04:00:52 -05:00
Connor Turland
9c13f5a281 metacode selector working nicely 2017-01-12 00:04:49 -05:00
Connor Turland
616a489ae4 Merge branch 'feature/better.select' into feature/particles 2017-01-11 23:18:26 -05:00
Connor Turland
816815d1b5 awesome 2017-01-11 23:17:57 -05:00
Connor Turland
3ff102b228 initial particle test 2017-01-05 00:05:18 -05:00
Connor Turland
bf9b25da9f merge develop 2017-01-04 10:50:59 -05:00
Connor Turland
5ba7ba9355 don't commit swp 2016-09-20 12:28:41 -04:00
Connor Turland
ce7c88c78c add more space between nodes using auto-layout 2016-09-20 12:27:46 -04:00
Connor Turland
74630c2631 messed up comment 2016-09-20 12:04:42 -04:00
Connor Turland
966dd79187 Merge branch 'develop' into feature/better.select 2016-09-20 11:55:25 -04:00
Connor Turland
5d04d16590 create MetacodeSelect component 2016-09-18 15:22:51 +00:00
31 changed files with 716 additions and 402 deletions

View file

@ -164,16 +164,17 @@ jQuery.browser = browser;
// START METAMAPS CODE
// Add code that makes tab and shift+tab scroll through metacodes
$('.new_topic').bind('keydown',this,function(event){
if (event.keyCode == 9) {
if (event.shiftKey) {
event.data.rotate(-1)
} else {
event.data.rotate(1)
}
event.preventDefault();
event.stopPropagation();
Metamaps.Create.newTopic.metacode = $(items[event.data.frontIndex].image).attr('data-id');
}
if (event.keyCode == 9 && event.shiftKey) {
$(container).show()
event.data.rotate(-1);
event.preventDefault();
event.stopPropagation();
} else if (event.keyCode == 9) {
$(container).show()
event.data.rotate(1);
event.preventDefault();
event.stopPropagation();
}
});
// END METAMAPS CODE
@ -181,14 +182,14 @@ jQuery.browser = browser;
if (options.mouseWheel)
{
// START METAMAPS CODE
$('body').bind('mousewheel',this,function(event, delta) {
if (Metamaps.Create.newTopic.beingCreated &&
!Metamaps.Create.isSwitchingSet &&
!Metamaps.Create.newTopic.pinned) {
event.data.rotate(delta);
return false;
}
});
/*$('body').bind('mousewheel',this,function(event, delta) {
if (Metamaps.Create.newTopic.beingCreated &&
!Metamaps.Create.isSwitchingSet &&
!Metamaps.Create.newTopic.pinned) {
event.data.rotate(delta);
return false;
}
});*/
// END METAMAPS CODE
// ORIGINAL CODE
// $(container).bind('mousewheel',this,function(event, delta) {
@ -255,8 +256,11 @@ jQuery.browser = browser;
this.showFrontText = function()
{
if ( items[this.frontIndex] === undefined ) { return; } // Images might not have loaded yet.
$(options.titleBox).html( $(items[this.frontIndex].image).attr('title'));
$(options.altBox).html( $(items[this.frontIndex].image).attr('alt'));
// METAMAPS CODE
Metamaps.Create.newTopic.setMetacode($(items[this.frontIndex].image).attr('data-id'))
// NOT METAMAPS CODE
//$(options.titleBox).html( $(items[this.frontIndex].image).attr('title'));
//$(options.altBox).html( $(items[this.frontIndex].image).attr('alt'));
};
this.go = function()
@ -269,7 +273,10 @@ jQuery.browser = browser;
this.stop = function()
{
clearTimeout(this.controlTimer);
this.controlTimer = 0;
this.controlTimer = 0;
// METAMAPS CODE
$(container).hide()
// END METAMAPS CODE
};
@ -390,7 +397,7 @@ jQuery.browser = browser;
}
// If all images have valid widths and heights, we can stop checking.
clearInterval(this.tt);
this.showFrontText();
// METAMAPS COMMENT this.showFrontText();
this.autoRotate();
this.updateAll();

View file

@ -526,23 +526,53 @@ button.button.btn-no:hover {
}
.new_topic {
/* start it off screen while it initializes the spinner, then it will be hidden with jquery */
top: -1000px;
left: -1000px;
top: -10000px;
left: -10000px;
margin-top: -17px;
display: block;
position: absolute;
width: 340px;
margin: -40px 0 0 -35px;
z-index: 1;
}
.selectedMetacode {
float: left;
background: #FFF;
border-top-left-radius: 2px;
border-bottom-left-radius: 2px;
padding: 5px 10px 5px 6px;
vertical-align: top;
border-right: 1px solid #DDD;
cursor: pointer;
}
.selectedMetacode:hover, .selectedMetacode.isBeingSelected {
background: #EDEDED;
}
.selectedMetacode img {
width: 24px;
height: 24px;
display: inline-block;
vertical-align: middle;
}
.selectedMetacode span {
vertical-align: middle;
}
.selectedMetacode .downArrow {
display: inline-block;
vertical-align: middle;
width: 0;
height: 0;
border-style: solid;
border-width: 8px 6px 0 6px;
border-color: #777 transparent transparent transparent;
margin-left: 2px;
margin-top: 4px;
}
#new_topic .twitter-typeahead {
position: absolute !important;
top: 45px;
left: 41px;
z-index: 9999;
width: 256px;
height: 34px;
float: left;
}
.new_topic #topic_name,
.new_topic .tt-hint {
@ -552,7 +582,8 @@ button.button.btn-no:hover {
margin: 0;
padding: 10px 6px;
border: none;
border-radius: 2px;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
outline: none;
font-size: 14px;
line-height: 14px;
@ -569,36 +600,22 @@ button.button.btn-no:hover {
background-image: url(<%= asset_data_uri('metacodesettings_sprite.png') %>);
position: absolute;
z-index: 2;
top: 20px;
left: 16px;
top: -16px;
left: -16px;
}
.openMetacodeSwitcher:hover {
background-position: -16px 0;
}
.pinCarousel {
cursor: pointer;
display: block;
height: 16px;
width: 16px;
background-image: url(<%= asset_data_uri('pincarousel_sprite.png') %>);
position: absolute;
z-index: 2;
top: 20px;
right: 16px;
}
.pinCarousel:hover {
background-position: 0 -16px;
}
.pinCarousel.isPinned {
background-position: -16px 0;
}
.pinCarousel.isPinned:hover {
background-position: -16px -16px;
}
#metacodeImg {
height: 120px;
width: 380px;
display: none;
position: absolute !important;
top: -30px;
z-index: -1;
}
#metacodeImgTitle {
display: none;
float: left;
width: 120px;
text-align: center;

View file

@ -0,0 +1,42 @@
#metacodeSelector {
display: none;
}
.metacodeSelect {
border-top: 1px solid #DDD;
padding: 0;
background: #FFF;
.metacodeFilterInput {
width: 100px;
outline: none;
border: 0;
padding: 8px;
font-size: 14px;
line-height: 14px;
color: #424242;
font-family: 'din-medium', helvetica, sans-serif;
}
.metacodeList {
list-style: none;
background: #FFF;
li {
padding: 8px;
cursor: pointer;
&:hover, &.keySelect {
background: #4CAF50;
}
}
img {
width: 24px;
height: 24px;
display: inline-block;
vertical-align: middle;
padding-right: 6px;
}
}
}

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
class UsersController < ApplicationController
before_action :require_user, only: [:edit, :update, :updatemetacodes]
before_action :require_user, only: [:edit, :update, :updatemetacodes, :update_metacode_focus]
respond_to :html, :json
@ -91,6 +91,16 @@ class UsersController < ApplicationController
format.json { render json: @user }
end
end
# PUT /user/update_metacode_focus
def update_metacode_focus
@user = current_user
@user.settings.metacode_focus = params[:value]
@user.save
respond_to do |format|
format.json { render json: { success: "success" }}
end
end
private

View file

@ -25,6 +25,10 @@ module ApplicationHelper
end
@metacodes.sort! { |m1, m2| m2.name.downcase <=> m1.name.downcase }.rotate!(-1)
end
def user_metacode
current_user.settings.metacode_focus ? Metacode.find(current_user.settings.metacode_focus.to_i) || user_metacodes()[0] : user_metacodes()[0]
end
def user_most_used_metacodes
@metacodes = current_user.most_used_metacodes.map { |id| Metacode.find(id) }

View file

@ -8,10 +8,6 @@ class Mapping < ApplicationRecord
belongs_to :user
belongs_to :updated_by, class_name: 'User'
validates :xloc, presence: true,
unless: proc { |m| m.mappable_type == 'Synapse' }
validates :yloc, presence: true,
unless: proc { |m| m.mappable_type == 'Synapse' }
validates :map, presence: true
validates :mappable, presence: true
@ -31,7 +27,7 @@ class Mapping < ApplicationRecord
def after_created
if mappable_type == 'Topic'
meta = {'x': xloc, 'y': yloc, 'mapping_id': id}
meta = {'mapping_id': id}
Events::TopicAddedToMap.publish!(mappable, map, user, meta)
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'topicAdded', topic: mappable.filtered, mapping_id: id
elsif mappable_type == 'Synapse'

View file

@ -66,6 +66,28 @@ class User < ApplicationRecord
json['rtype'] = 'mapper'
json
end
def recentMetacodes
array = []
self.topics.sort{|a,b| b.created_at <=> a.created_at }.each do |t|
if array.length < 5 and array.index(t.metacode_id) == nil
array.push(t.metacode_id)
end
end
array
end
def mostUsedMetacodes
self.topics.to_a.reduce({}) { |memo, topic|
if memo[topic.metacode_id] == nil
memo[topic.metacode_id] = 1
else
memo[topic.metacode_id] = memo[topic.metacode_id] + 1
end
memo
}.to_a.sort{ |a, b| b[1] <=> a[1] }.map{|i| i[0]}.slice(0, 5)
end
def all_accessible_maps
maps + shared_maps

View file

@ -1,6 +1,6 @@
# frozen_string_literal: true
class UserPreference
attr_accessor :metacodes
attr_accessor :metacodes, :metacode_focus
def initialize
array = []
@ -15,5 +15,6 @@ class UserPreference
end
end
@metacodes = array
@metacode_focus = array[0]
end
end

View file

@ -47,19 +47,6 @@
<%= render :partial => 'layouts/lowermapelements' %>
<div id="explore"></div>
<div id="instructions">
<div class="addTopic">
Double-click to<br>add a topic
</div>
<div class="tabKey">
Use Tab & Shift+Tab to select a metacode
</div>
<div class="enterKey">
Press Enter to add the topic
</div>
</div>
<div id="infovis"></div>
<%= render :partial => 'layouts/mobilemenu' %>

View file

@ -1,34 +1,37 @@
<% @metacodes = user_metacodes() %>
<%= form_for Topic.new, url: topics_url, remote: true do |form| %>
<div class="openMetacodeSwitcher openLightbox" data-open="switchMetacodes">
<div class="tooltipsAbove">Switch Metacodes</div>
</div>
<div class="pinCarousel">
<div class="tooltipsAbove helpPin">Pin Open</div>
<div class="tooltipsAbove helpUnpin">Unpin</div>
</div>
<div id="metacodeImg">
<% @metacodes = [user_metacode()].concat(user_metacodes()).uniq %>
<% set = metacodeset() %>
<% @metacodes.each do |metacode| %>
<img class="cloudcarousel" width="40" height="40" src="<%= asset_path metacode.icon %>" alt="<%= metacode.name %>" title="<%= metacode.name %>" data-id="<%= metacode.id %>" />
<% end %>
</div>
<%= form.text_field :name, :maxlength => 140, :placeholder => "title..." %>
<div id="metacodeImgTitle"></div>
</div>
<div class="selectedMetacode">
<img src="<%= asset_path user_metacode().icon %>" />
<span><%= user_metacode().name %></span>
<div class="downArrow"></div>
</div>
<%= form.text_field :name, :maxlength => 140, :placeholder => "what are you thinking..." %>
<div class="clearfloat"></div>
<script>
<% @metacodes.each do |metacode| %>
<% if !metacodeset() %>
Metamaps.Create.selectedMetacodes.push("<%= metacode.id %>");
Metamaps.Create.newSelectedMetacodes.push("<%= metacode.id %>");
Metamaps.Create.selectedMetacodeNames.push("<%= metacode.name %>");
Metamaps.Create.newSelectedMetacodeNames.push("<%= metacode.name %>");
<% end %>
<% end %>
</script>
<div id="metacodeSelector"></div>
<div class="clearfloat"></div>
<script>
<% @metacodes.each do |metacode| %>
Metamaps.Create.selectedMetacodes.push("<%= metacode.id %>");
Metamaps.Create.newSelectedMetacodes.push("<%= metacode.id %>");
Metamaps.Create.selectedMetacodeNames.push("<%= metacode.name %>");
Metamaps.Create.newSelectedMetacodeNames.push("<%= metacode.name %>");
<% end %>
Metamaps.Create.newTopic.metacode = <%= user_metacode().id %>
<% current_user.recentMetacodes.each do |id| %>
Metamaps.Create.recentMetacodes.push(<%= id %>);
<% end %>
<% current_user.mostUsedMetacodes.each do |id| %>
Metamaps.Create.mostUsedMetacodes.push(<%= id %>);
<% end %>
</script>
<% end %>

View file

@ -93,12 +93,9 @@
<div id="metacodeSwitchTabsCustom">
<p class="setDesc">Choose Your Metacodes</p>
<% @list = '' %>
<% metacodesInUse = [user_metacode()].concat(user_metacodes()).uniq %>
<% Metacode.order("name").all.each_with_index do |m, index| %>
<% if selectedSet == "custom" %>
<% mClass = metacodes.index(m.id.to_s) == nil ? "toggledOff" : "" %>
<% else %>
<% mClass = "toggledOff" %>
<% end %>
<% mClass = metacodesInUse.index(m) == nil ? "toggledOff" : "" %>
<% @list += '<li id="' + m.id.to_s + '" data-name="' + m.name + '" class="' + mClass + '"><img src="' + asset_path(m.icon) + '" alt="' + m.name + '" /><p>' + m.name.downcase + '</p><div class="clearfloat"></div></li>' %>
<% end %>

View file

@ -104,6 +104,7 @@ Metamaps::Application.routes.draw do
end
end
post 'user/updatemetacodes', to: 'users#updatemetacodes', as: :updatemetacodes
post 'user/update_metacode_focus', to: 'users#update_metacode_focus'
namespace :api, path: '/api', default: { format: :json } do
namespace :v2, path: '/v2' do

View file

@ -2,7 +2,9 @@
import Active from './Active'
import Control from './Control'
import Create from './Create'
import DataModel from './DataModel'
import Engine from './Engine'
import Map from './Map'
import Mapper from './Mapper'
import Synapse from './Synapse'
@ -26,7 +28,7 @@ const Cable = {
},
unsubscribeFromMap: () => {
let self = Cable
self.sub.unsubscribe()
self.sub && self.sub.unsubscribe()
delete self.sub
},
synapseAdded: event => {
@ -51,6 +53,9 @@ const Cable = {
node2 = topic2.get('node')
Synapse.renderSynapse(mapping, synapse, node1, node2, false)
if (Create.newSynapse.focusNode === node1) {
Engine.setFocusNode(node2)
}
} else if (!cancel) {
setTimeout(waitThenRenderSynapse, 10)
}
@ -132,7 +137,7 @@ const Cable = {
function waitThenRenderTopic() {
if (topic && mapping && mapper) {
Topic.renderTopic(mapping, topic, false, false)
Topic.renderTopic(mapping, topic, false)
} else if (!cancel) {
setTimeout(waitThenRenderTopic, 10)
}
@ -183,7 +188,7 @@ const Cable = {
},
topicMoved: event => {
var topic, node, mapping
if (Active.Map) {
/*if (Active.Map) {
topic = DataModel.Topics.get(event.id)
mapping = DataModel.Mappings.get(event.mapping_id)
mapping.set('xloc', event.x)
@ -191,7 +196,7 @@ const Cable = {
if (topic) node = topic.get('node')
if (node) node.pos.setc(event.x, event.y)
Visualize.mGraph.plot()
}
}*/
},
topicRemoved: event => {
var topic = DataModel.Topics.get(event.id)

View file

@ -5,6 +5,7 @@ import outdent from 'outdent'
import Active from './Active'
import DataModel from './DataModel'
import Engine from './Engine'
import Filter from './Filter'
import GlobalUI from './GlobalUI'
import JIT from './JIT'
@ -22,6 +23,7 @@ const Control = {
node.selected = true
node.setData('dim', 30, 'current')
Selected.Nodes.push(node)
Engine.setNodeSleeping(node.getData('body_id'), true)
},
deselectAllNodes: function() {
var l = Selected.Nodes.length
@ -38,6 +40,7 @@ const Control = {
// remove the node
Selected.Nodes.splice(
Selected.Nodes.indexOf(node), 1)
Engine.setNodeSleeping(node.getData('body_id'), false)
},
deleteSelected: function() {
if (!Active.Map) return

View file

@ -1,10 +1,15 @@
/* global $, Hogan, Bloodhound */
/* global Metamaps, $, Hogan, Bloodhound */
import React from 'react'
import ReactDOM from 'react-dom'
import DataModel from './DataModel'
import MetacodeSelect from '../components/MetacodeSelect'
import Mouse from './Mouse'
import Selected from './Selected'
import Synapse from './Synapse'
import Topic from './Topic'
import Util from './Util'
import Visualize from './Visualize'
import GlobalUI from './GlobalUI'
@ -16,9 +21,11 @@ const Create = {
newSelectedMetacodeNames: [],
selectedMetacodes: [],
newSelectedMetacodes: [],
init: function() {
recentMetacodes: [],
mostUsedMetacodes: [],
init: function (serverData) {
var self = Create
self.newTopic.init()
self.newTopic.init(serverData)
self.newSynapse.init()
// // SWITCHING METACODE SETS
@ -58,10 +65,11 @@ const Create = {
if (!custom) {
codesToSwitchToIds = $('#metacodeSwitchTabs' + set).attr('data-metacodes').split(',')
$('.customMetacodeList li').addClass('toggledOff')
Create.selectedMetacodes = []
Create.selectedMetacodeNames = []
Create.newSelectedMetacodes = []
Create.newSelectedMetacodeNames = []
console.log(codesToSwitchToIds)
Create.selectedMetacodes = codesToSwitchToIds
Create.selectedMetacodeNames = DataModel.Metacodes.filter(m => codesToSwitchToIds.indexOf(m.id) > -1).map(m => m.get('name'))
Create.newSelectedMetacodes = codesToSwitchToIds
Create.newSelectedMetacodeNames = DataModel.Metacodes.filter(m => codesToSwitchToIds.indexOf(m.id) > -1).map(m => m.get('name'))
} else if (custom) {
// uses .slice to avoid setting the two arrays to the same actual array
Create.selectedMetacodes = Create.newSelectedMetacodes.slice(0)
@ -70,12 +78,13 @@ const Create = {
}
// sort by name
for (var i = 0; i < codesToSwitchToIds.length; i++) {
metacodeModels.add(DataModel.Metacodes.get(codesToSwitchToIds[i]))
}
codesToSwitchToIds.forEach(id => {
const metacode = DataModel.Metacodes.get(id)
metacodeModels.add(metacode)
$('.customMetacodeList #' + id).removeClass('toggledOff')
})
metacodeModels.sort()
$('#metacodeImg, #metacodeImgTitle').empty()
$('#metacodeImg').removeData('cloudcarousel')
var newMetacodes = ''
metacodeModels.each(function(metacode) {
@ -83,16 +92,16 @@ const Create = {
})
$('#metacodeImg').empty().append(newMetacodes).CloudCarousel({
titleBox: $('#metacodeImgTitle'),
yRadius: 40,
xRadius: 190,
xPos: 170,
yPos: 40,
speed: 0.3,
mouseWheel: true,
bringToFront: true
})
Create.newTopic.setMetacode(metacodeModels.models[0].id)
GlobalUI.closeLightbox()
$('#topic_name').focus()
@ -119,13 +128,7 @@ const Create = {
var self = Create
self.isSwitchingSet = false
if (self.selectedMetacodeSet !== 'metacodeset-custom') {
$('.customMetacodeList li').addClass('toggledOff')
self.selectedMetacodes = []
self.selectedMetacodeNames = []
self.newSelectedMetacodes = []
self.newSelectedMetacodeNames = []
} else { // custom set is selected
if (self.selectedMetacodeSet === 'metacodeset-custom') {
// reset it to the current actual selection
$('.customMetacodeList li').addClass('toggledOff')
for (var i = 0; i < self.selectedMetacodes.length; i++) {
@ -139,27 +142,33 @@ const Create = {
$('#topic_name').focus()
},
newTopic: {
init: function() {
$('#topic_name').keyup(function(e) {
const ESC = 27
init: function (serverData) {
const DOWN_ARROW = 40
const ESC = 27
if (!serverData.ActiveMapper) return
$('#topic_name').keyup(function (e) {
Create.newTopic.name = $(this).val()
if (e.which == DOWN_ARROW && !Create.newTopic.name.length) {
Create.newTopic.openSelector()
}
if (e.keyCode === ESC) {
Create.newTopic.hide()
} // if
Create.newTopic.name = $(this).val()
})
$('.pinCarousel').click(function() {
if (Create.newTopic.pinned) {
$('.pinCarousel').removeClass('isPinned')
Create.newTopic.pinned = false
} else {
$('.pinCarousel').addClass('isPinned')
Create.newTopic.pinned = true
}
$('.selectedMetacode').click(function() {
if (Create.newTopic.metacodeSelectorOpen) {
Create.newTopic.hideSelector()
$('#topic_name').focus()
} else Create.newTopic.openSelector()
})
Create.newTopic.initSelector()
var topicBloodhound = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
@ -200,52 +209,86 @@ const Create = {
})
}
})
$('#topic_name').click(function() { Create.newTopic.hideSelector() })
// initialize metacode spinner and then hide it
$('#metacodeImg').CloudCarousel({
titleBox: $('#metacodeImgTitle'),
yRadius: 40,
xRadius: 190,
xPos: 170,
yPos: 40,
speed: 0.3,
mouseWheel: true,
bringToFront: true
})
$('.new_topic').hide()
$('#new_topic').attr('oncontextmenu', 'return false') // prevents the mouse up event from opening the default context menu on this element
$('#new_topic').hide()
.css({ left: '50%', top: '50%' })
.attr('oncontextmenu', 'return false') // prevents the mouse up event from opening the default context menu on this element
},
name: null,
newId: 1,
beingCreated: false,
metacodeSelectorOpen: false,
metacode: null,
x: null,
y: null,
addSynapse: false,
pinned: false,
open: function() {
$('#new_topic').fadeIn('fast', function() {
$('#topic_name').focus()
})
Create.newTopic.beingCreated = true
Create.newTopic.name = ''
GlobalUI.hideDiv('#instructions')
initSelector: function () {
ReactDOM.render(
React.createElement(MetacodeSelect, {
onClick: function (id) {
Create.newTopic.setMetacode(id)
Create.newTopic.hideSelector()
$('#topic_name').focus()
},
close: function () {
Create.newTopic.hideSelector()
$('#topic_name').focus()
},
metacodes: DataModel.Metacodes.filter(m => Create.selectedMetacodes.indexOf(m.id.toString()) > -1)
}),
document.getElementById('metacodeSelector')
)
},
hide: function(force) {
if (force || !Create.newTopic.pinned) {
$('#new_topic').fadeOut('fast')
}
if (force) {
$('.pinCarousel').removeClass('isPinned')
Create.newTopic.pinned = false
}
if (DataModel.Topics.length === 0) {
GlobalUI.showDiv('#instructions')
}
Create.newTopic.beingCreated = false
openSelector: function () {
Create.newTopic.initSelector()
$('#metacodeSelector').show()
Create.newTopic.metacodeSelectorOpen = true
$('.metacodeFilterInput').focus()
$('.selectedMetacode').addClass('isBeingSelected')
},
hideSelector: function () {
ReactDOM.unmountComponentAtNode(document.getElementById('metacodeSelector'))
$('#metacodeSelector').hide()
Create.newTopic.metacodeSelectorOpen = false
$('.selectedMetacode').removeClass('isBeingSelected')
},
setMetacode: function (id) {
Create.newTopic.metacode = id
var metacode = DataModel.Metacodes.get(id)
$('.selectedMetacode img').attr('src', metacode.get('icon'))
$('.selectedMetacode span').html(metacode.get('name'))
$.ajax({
type: 'POST',
dataType: 'json',
url: '/user/update_metacode_focus',
data: { value: id },
success: function (data) {},
error: function () {
console.log('failed to save metacode focus')
}
})
},
reset: function() {
$('#topic_name').typeahead('val', '')
Create.newTopic.hideSelector()
},
position: function() {
const pixels = Util.coordsToPixels(Visualize.mGraph, Mouse.newNodeCoords)
$('#new_topic').css({
left: pixels.x,
top: pixels.y
})
}
},
newSynapse: {
@ -338,6 +381,7 @@ const Create = {
}
})
},
focusNode: null,
beingCreated: false,
description: null,
topic1id: null,
@ -356,8 +400,35 @@ const Create = {
Create.newTopic.addSynapse = false
Create.newSynapse.topic1id = 0
Create.newSynapse.topic2id = 0
Create.newSynapse.node1 = null
Create.newSynapse.node2 = null
Mouse.synapseStartCoordinates = []
Mouse.synapseEndCoordinates = null
if (Visualize.mGraph) Visualize.mGraph.plot()
},
updateForm: function() {
// set the draw synapse start positions
Mouse.synapseStartCoordinates = []
for (let i = Selected.Nodes.length - 1; i >= 0; i -= 1) {
const n = Selected.Nodes[i]
Mouse.synapseStartCoordinates.push({
x: n.pos.getc().x,
y: n.pos.getc().y
})
}
let pixelPos, midpoint = {}
if (Create.newSynapse.beingCreated) {
Mouse.synapseEndCoordinates = {
x: Create.newSynapse.node2.pos.getc().x,
y: Create.newSynapse.node2.pos.getc().y
}
// position the form
midpoint.x = Create.newSynapse.node1.pos.getc().x + (Create.newSynapse.node2.pos.getc().x - Create.newSynapse.node1.pos.getc().x) / 2
midpoint.y = Create.newSynapse.node1.pos.getc().y + (Create.newSynapse.node2.pos.getc().y - Create.newSynapse.node1.pos.getc().y) / 2
pixelPos = Util.coordsToPixels(Visualize.mGraph, midpoint)
$('#new_synapse').css('left', pixelPos.x + 'px')
$('#new_synapse').css('top', pixelPos.y + 'px')
}
}
}
}

View file

@ -21,16 +21,16 @@ const Mapping = Backbone.Model.extend({
})
}
},
getMap: function() {
return Map.get(this.get('map_id'))
getMap: function(callback) {
Map.get(this.get('map_id'), callback)
},
getTopic: function() {
if (this.get('mappable_type') !== 'Topic') return false
return Topic.get(this.get('mappable_id'))
},
getSynapse: function() {
if (this.get('mappable_type') !== 'Synapse') return false
return Synapse.get(this.get('mappable_id'))
getMappable: function(callback) {
if (this.get('mappable_type') === 'Topic') {
Topic.get(this.get('mappable_id'), callback)
}
else if (this.get('mappable_type') === 'Synapse') {
Synapse.get(this.get('mappable_id'), callback)
}
}
})

View file

@ -88,8 +88,8 @@ const Synapse = Backbone.Model.extend({
}
}
if (Active.Map) {
mapping = providedMapping || this.getMapping()
if (Active.Map && providedMapping) {
mapping = providedMapping
mappingID = mapping.isNew() ? mapping.cid : mapping.id
edge.data.$mappings = []
edge.data.$mappingIDs = [mappingID]
@ -100,10 +100,12 @@ const Synapse = Backbone.Model.extend({
updateEdge: function() {
var mapping
var edge = this.get('edge')
edge.data.$synapses = edge.data.$synapses || []
edge.getData('synapses').push(this)
if (Active.Map) {
mapping = this.getMapping()
edge.data.$mappings = edge.data.$mappings || []
edge.getData('mappings').push(mapping)
}

View file

@ -5,6 +5,7 @@ import Backbone from 'backbone'
try { Backbone.$ = window.$ } catch (err) {}
import Active from '../Active'
import Engine from '../Engine'
import Filter from '../Filter'
import JIT from '../JIT'
import Realtime from '../Realtime'

View file

@ -1,4 +1,5 @@
import Active from '../Active'
import Engine from '../Engine'
import Filter from '../Filter'
import { InfoBox } from '../Map'

View file

@ -0,0 +1,120 @@
import Matter, { Vector, Sleeping, World, Constraint, Composite, Runner, Common, Body, Bodies, Events } from 'matter-js'
import { last, sortBy, values } from 'lodash'
import $jit from '../patched/JIT'
import Active from './Active'
import Create from './Create'
import DataModel from './DataModel'
import Mouse from './Mouse'
import JIT from './JIT'
import Visualize from './Visualize'
const Engine = {
focusBody: null,
newNodeConstraint: null,
newNodeBody: Bodies.circle(Mouse.newNodeCoords.x, Mouse.newNodeCoords.y, 1),
init: (serverData) => {
Engine.engine = Matter.Engine.create()
Events.on(Engine.engine, 'afterUpdate', Engine.callUpdate)
if (!serverData.ActiveMapper) Engine.engine.world.gravity.scale = 0
else {
Engine.engine.world.gravity.y = 0
Engine.engine.world.gravity.x = -1
Body.setStatic(Engine.newNodeBody, true)
}
},
run: init => {
if (init) {
if (Active.Mapper) World.addBody(Engine.engine.world, Engine.newNodeBody)
Visualize.mGraph.graph.eachNode(Engine.addNode)
DataModel.Synapses.each(s => Engine.addEdge(s.get('edge')))
if (Active.Mapper && Object.keys(Visualize.mGraph.graph.nodes).length) {
Engine.setFocusNode(Engine.findFocusNode(Visualize.mGraph.graph.nodes))
}
}
Engine.runner = Matter.Runner.run(Engine.engine)
},
endActiveMap: () => {
Engine.runner && Runner.stop(Engine.runner)
Matter.Engine.clear(Engine.engine)
},
setNodePos: (id, x, y) => {
const body = Composite.get(Engine.engine.world, id, 'body')
Body.setPosition(body, { x, y })
Body.setVelocity(body, Vector.create(0, 0))
Body.setAngularVelocity(body, 0)
Body.setAngle(body, 0)
},
setNodeSleeping: (id, isSleeping) => {
const body = Composite.get(Engine.engine.world, id, 'body')
Sleeping.set(body, isSleeping)
if (!isSleeping) {
Body.setVelocity(body, Vector.create(0, 0))
Body.setAngularVelocity(body, 0)
Body.setAngle(body, 0)
}
},
addNode: node => {
let body = Bodies.circle(node.pos.x, node.pos.y, 100)
body.node_id = node.id
node.setData('body_id', body.id)
World.addBody(Engine.engine.world, body)
},
removeNode: node => {
},
findFocusNode: nodes => {
return last(sortBy(values(nodes), n => new Date(n.getData('topic').get('created_at'))))
},
setFocusNode: node => {
if (!Active.Mapper) return
Create.newSynapse.focusNode = node
const body = Composite.get(Engine.engine.world, node.getData('body_id'), 'body')
Engine.focusBody = body
let constraint
if (Engine.newNodeConstraint) {
Engine.newNodeConstraint.bodyA = body
}
else {
constraint = Constraint.create({
bodyA: body,
bodyB: Engine.newNodeBody,
length: JIT.ForceDirected.graphSettings.levelDistance,
stiffness: 0.2
})
World.addConstraint(Engine.engine.world, constraint)
Engine.newNodeConstraint = constraint
}
},
addEdge: edge => {
const bodyA = Composite.get(Engine.engine.world, edge.nodeFrom.getData('body_id'), 'body')
const bodyB = Composite.get(Engine.engine.world, edge.nodeTo.getData('body_id'), 'body')
let constraint = Constraint.create({
bodyA,
bodyB,
length: JIT.ForceDirected.graphSettings.levelDistance,
stiffness: 0.2
})
edge.setData('constraint_id', constraint.id)
World.addConstraint(Engine.engine.world, constraint)
},
removeEdge: synapse => {
},
callUpdate: () => {
Engine.engine.world.bodies.forEach(b => {
const node = Visualize.mGraph.graph.getNode(b.node_id)
const newPos = new $jit.Complex(b.position.x, b.position.y)
node && node.setPos(newPos, 'current')
})
if (Active.Mapper) {
if (Engine.focusBody) Mouse.focusNodeCoords = Engine.focusBody.position
Create.newSynapse.updateForm()
Create.newTopic.position()
}
Visualize.mGraph.plot()
}
}
export default Engine

View file

@ -9,6 +9,7 @@ import Active from './Active'
import Control from './Control'
import Create from './Create'
import DataModel from './DataModel'
import Engine from './Engine'
import Filter from './Filter'
import GlobalUI from './GlobalUI'
import Map from './Map'
@ -392,7 +393,6 @@ const JIT = {
Visualize.mGraph.busy = false
Mouse.boxEndCoordinates = eventInfo.getPos()
JIT.selectWithBox(e)
return
}
}
@ -404,6 +404,7 @@ const JIT = {
JIT.selectEdgeOnClickHandler(node, e)
} else if (node && !node.nodeFrom) {
JIT.selectNodeOnClickHandler(node, e)
Engine.setFocusNode(node)
} else {
JIT.canvasClickHandler(eventInfo.getPos(), e)
} // if
@ -415,7 +416,6 @@ const JIT = {
if (Mouse.boxStartCoordinates) {
Create.newSynapse.hide()
Create.newTopic.hide()
Visualize.mGraph.busy = false
Mouse.boxEndCoordinates = eventInfo.getPos()
JIT.selectWithBox(e)
@ -432,7 +432,6 @@ const JIT = {
} else {
// right click open space
Create.newSynapse.hide()
Create.newTopic.hide()
}
}
},
@ -721,11 +720,11 @@ const JIT = {
$('canvas').css('cursor', 'default')
}
}, // onMouseMoveHandler
enterKeyHandler: function() {
enterKeyHandler: function(e) {
const creatingMap = GlobalUI.lightbox
if (creatingMap === 'newmap' || creatingMap === 'forkmap') {
GlobalUI.CreateMap.submit()
} else if (Create.newTopic.beingCreated) {
} else if (e.target.id === 'topic_name' && !Create.newTopic.metacodeSelectorOpen) {
Topic.createTopicLocally()
} else if (Create.newSynapse.beingCreated) {
Synapse.createSynapseLocally()
@ -850,24 +849,7 @@ const JIT = {
JIT.tempNode = node
JIT.tempInit = true
Create.newTopic.hide()
Create.newSynapse.hide()
// set the draw synapse start positions
var l = Selected.Nodes.length
if (l > 0) {
for (let i = l - 1; i >= 0; i -= 1) {
const n = Selected.Nodes[i]
Mouse.synapseStartCoordinates.push({
x: n.pos.getc().x,
y: n.pos.getc().y
})
}
} else {
Mouse.synapseStartCoordinates = [{
x: JIT.tempNode.pos.getc().x,
y: JIT.tempNode.pos.getc().y
}]
}
Mouse.synapseEndCoordinates = {
x: pos.x,
y: pos.y
@ -894,15 +876,7 @@ const JIT = {
Visualize.mGraph.graph.eachNode(function(n) {
n.setData('dim', 25, 'current')
})
// pop up node creation :)
var myX = e.clientX - 110
var myY = e.clientY - 30
$('#new_topic').css('left', myX + 'px')
$('#new_topic').css('top', myY + 'px')
Create.newTopic.x = eventInfo.getPos().x
Create.newTopic.y = eventInfo.getPos().y
Visualize.mGraph.plot()
Mouse.synapseEndCoordinates = {
x: pos.x,
y: pos.y
@ -945,14 +919,13 @@ const JIT = {
self.dragTolerance = 0
if (JIT.tempInit && JIT.tempNode2 === null) {
// this means you want to add a new topic, and then a synapse
Create.newTopic.addSynapse = true
Create.newTopic.open()
Mouse.synapseEndCoordinates = null
} else if (JIT.tempInit && JIT.tempNode2 !== null) {
// this means you want to create a synapse between two existing topics
Create.newTopic.addSynapse = false
Create.newSynapse.topic1id = JIT.tempNode.getData('topic').id
Create.newSynapse.topic2id = JIT.tempNode2.getData('topic').id
Create.newSynapse.node1 = JIT.tempNode
Create.newSynapse.node2 = JIT.tempNode2
JIT.tempNode2.setData('dim', 25, 'current')
Visualize.mGraph.plot()
midpoint.x = JIT.tempNode.pos.getc().x + (JIT.tempNode2.pos.getc().x - JIT.tempNode.pos.getc().x) / 2
@ -1004,27 +977,12 @@ const JIT = {
const authorized = Active.Map && Active.Map.authorizeToEdit(Active.Mapper)
if (now - storedTime < Mouse.DOUBLE_CLICK_TOLERANCE && !Mouse.didPan) {
if (Active.Map && !authorized) {
GlobalUI.notifyUser('Cannot edit Public map.')
return
} else if (Active.Topic) {
GlobalUI.notifyUser('Cannot create in Topic view.')
return
}
// DOUBLE CLICK
// pop up node creation :)
Create.newTopic.addSynapse = false
Create.newTopic.x = canvasLoc.x
Create.newTopic.y = canvasLoc.y
$('#new_topic').css('left', e.clientX + 'px')
$('#new_topic').css('top', e.clientY + 'px')
Create.newTopic.open()
} else if (!Mouse.didPan) {
// SINGLE CLICK, no pan
Filter.close()
TopicCard.hideCard()
SynapseCard.hideCard()
Create.newTopic.hide()
$('.rightclickmenu').remove()
// reset the draw synapse positions to false
Mouse.synapseStartCoordinates = []
@ -1038,7 +996,6 @@ const JIT = {
}
} else {
// SINGLE CLICK, resulting from pan
Create.newTopic.hide()
}
}, // canvasClickHandler
updateTopicPositions: function(node, pos) {
@ -1067,6 +1024,7 @@ const JIT = {
n.pos.setp(theta, rho)
} else {
n.pos.setc(x, y)
Engine.setNodePos(n.getData('body_id'), x, y)
}
if (Active.Map) {
@ -1272,26 +1230,6 @@ const JIT = {
Mouse.boxEndCoordinates = false
Visualize.mGraph.plot()
}, // selectWithBox
drawSelectBox: function(eventInfo, e) {
const ctx = Visualize.mGraph.canvas.getCtx()
const startX = Mouse.boxStartCoordinates.x
const startY = Mouse.boxStartCoordinates.y
const currX = eventInfo.getPos().x
const currY = eventInfo.getPos().y
Visualize.mGraph.canvas.clear()
Visualize.mGraph.plot()
ctx.beginPath()
ctx.moveTo(startX, startY)
ctx.lineTo(startX, currY)
ctx.lineTo(currX, currY)
ctx.lineTo(currX, startY)
ctx.lineTo(startX, startY)
ctx.strokeStyle = 'black'
ctx.stroke()
}, // drawSelectBox
selectNodeOnClickHandler: function(node, e) {
if (Visualize.mGraph.busy) return

View file

@ -24,7 +24,7 @@ const Listeners = {
case 13: // if enter key is pressed
// prevent topic creation if sending a message
if (e.target.className !== 'chat-input') {
JIT.enterKeyHandler()
JIT.enterKeyHandler(e)
}
break
case 27: // if esc key is pressed

View file

@ -8,6 +8,7 @@ import AutoLayout from '../AutoLayout'
import Create from '../Create'
import DataModel from '../DataModel'
import DataModelMap from '../DataModel/Map'
import Engine from '../Engine'
import Filter from '../Filter'
import GlobalUI from '../GlobalUI'
import JIT from '../JIT'
@ -143,11 +144,12 @@ const Map = {
$('.rightclickmenu').remove()
TopicCard.hideCard()
SynapseCard.hideCard()
Create.newTopic.hide(true) // true means force (and override pinned)
$('#new_topic').hide()
Create.newSynapse.hide()
Filter.close()
InfoBox.close()
Realtime.endActiveMap()
Engine.endActiveMap()
$('.viewOnly').removeClass('isViewOnly')
}
},

View file

@ -6,6 +6,8 @@ const Mouse = {
edgeHoveringOver: false,
boxStartCoordinates: false,
boxEndCoordinates: false,
focusNodeCoords: null,
newNodeCoords: { x: 100, y: 0 },
synapseStartCoordinates: [],
synapseEndCoordinates: null,
lastNodeClick: 0,

View file

@ -4,6 +4,7 @@ import Active from './Active'
import Control from './Control'
import Create from './Create'
import DataModel from './DataModel'
import Engine from './Engine'
import JIT from './JIT'
import Map from './Map'
import Selected from './Selected'
@ -28,46 +29,40 @@ const Synapse = {
} else callback(DataModel.Synapses.get(id))
},
renderSynapse: function(mapping, synapse, node1, node2, createNewInDB) {
renderSynapse: function(mapping, synapse, node1, node2, createNewInDB, alreadyAdded) {
var edgeOnViz
var newedge
var newedge = synapse.createEdge(mapping)
Visualize.mGraph.graph.addAdjacence(node1, node2, newedge.data)
if (!alreadyAdded) {
newedge = synapse.createEdge(mapping)
Visualize.mGraph.graph.addAdjacence(node1, node2, newedge.data)
}
edgeOnViz = Visualize.mGraph.graph.getAdjacence(node1.id, node2.id)
if (!alreadyAdded) {
Engine.addEdge(edgeOnViz)
}
synapse.set('edge', edgeOnViz)
synapse.updateEdge() // links the synapse and the mapping to the edge
Control.selectEdge(edgeOnViz)
//Control.selectEdge(edgeOnViz)
var synapseSuccessCallback = function(synapseModel, response) {
if (Active.Map) {
mapping.save({ mappable_id: synapseModel.id }, {
error: function(model, response) {
console.log('error saving mapping to database')
}
})
mapping.save({ mappable_id: synapseModel.id })
}
}
if (!Settings.sandbox && createNewInDB) {
if (createNewInDB) {
if (synapse.isNew()) {
synapse.save(null, {
success: synapseSuccessCallback,
error: function(model, response) {
console.log('error saving synapse to database')
}
success: synapseSuccessCallback
})
} else if (!synapse.isNew() && Active.Map) {
mapping.save(null, {
error: function(model, response) {
console.log('error saving mapping to database')
}
})
mapping.save(null)
}
}
},
createSynapseLocally: function() {
createSynapseLocally: function(alreadyAdded, topic1id, topic2id) {
var self = Synapse
let topic1
let topic2
@ -75,43 +70,41 @@ const Synapse = {
let node2
let synapse
let mapping
$(document).trigger(Map.events.editedByActiveMapper)
// for each node in this array we will create a synapse going to the position2 node.
var synapsesToCreate = []
topic2 = DataModel.Topics.get(Create.newSynapse.topic2id)
node2 = topic2.get('node')
var len = Selected.Nodes.length
if (len === 0) {
topic1 = DataModel.Topics.get(Create.newSynapse.topic1id)
if (alreadyAdded) {
topic2 = DataModel.Topics.get(topic2id)
node2 = topic2.get('node')
topic1 = DataModel.Topics.get(topic1id)
synapsesToCreate[0] = topic1.get('node')
} else if (len > 0) {
synapsesToCreate = Selected.Nodes
}
for (var i = 0; i < synapsesToCreate.length; i++) {
node1 = synapsesToCreate[i]
else {
topic2 = DataModel.Topics.get(Create.newSynapse.topic2id)
node2 = topic2.get('node')
if (Selected.Nodes.length === 0) {
topic1 = DataModel.Topics.get(Create.newSynapse.topic1id)
synapsesToCreate[0] = topic1.get('node')
} else {
synapsesToCreate = Selected.Nodes
}
}
synapsesToCreate.forEach(node1 => {
topic1 = node1.getData('topic')
synapse = new DataModel.Synapse({
desc: Create.newSynapse.description,
desc: Create.newSynapse.description || '',
topic1_id: topic1.isNew() ? topic1.cid : topic1.id,
topic2_id: topic2.isNew() ? topic2.cid : topic2.id
})
DataModel.Synapses.add(synapse)
mapping = new DataModel.Mapping({
mappable_type: 'Synapse',
mappable_id: synapse.cid
})
DataModel.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
self.renderSynapse(mapping, synapse, node1, node2, true, alreadyAdded)
}) // for each in synapsesToCreate
Create.newSynapse.hide()
},
getSynapseFromAutocomplete: function(id) {

View file

@ -6,13 +6,16 @@ import Active from './Active'
import AutoLayout from './AutoLayout'
import Create from './Create'
import DataModel from './DataModel'
import Engine from './Engine'
import Filter from './Filter'
import GlobalUI from './GlobalUI'
import JIT from './JIT'
import Map from './Map'
import Mouse from './Mouse'
import Router from './Router'
import Selected from './Selected'
import Settings from './Settings'
import Synapse from './Synapse'
import SynapseCard from './SynapseCard'
import TopicCard from './TopicCard'
import Util from './Util'
@ -165,69 +168,39 @@ const Topic = {
})
},
// opts is additional options in a hash
// TODO: move createNewInDB and permitCreateSynapseAfter into opts
renderTopic: function(mapping, topic, createNewInDB, permitCreateSynapseAfter, opts = {}) {
var nodeOnViz, tempPos
renderTopic: function(mapping, topic, createNewInDB) {
var nodeOnViz
var newnode = topic.createNode()
var midpoint = {}
var pixelPos
const createSynapse = !!Create.newSynapse.focusNode && createNewInDB
const connectToId = createSynapse ? Create.newSynapse.focusNode.getData('topic').id : null
if (!$.isEmptyObject(Visualize.mGraph.graph.nodes)) {
Visualize.mGraph.graph.addNode(newnode)
// this will also add the new node
if (createSynapse) Visualize.mGraph.graph.addAdjacence(Create.newSynapse.focusNode, newnode)
else Visualize.mGraph.graph.addNode(newnode)
nodeOnViz = Visualize.mGraph.graph.getNode(newnode.id)
Engine.addNode(nodeOnViz)
if (createSynapse) Engine.addEdge(Visualize.mGraph.graph.getAdjacence(Create.newSynapse.focusNode.id, nodeOnViz.id))
topic.set('node', nodeOnViz, {silent: true})
topic.updateNode() // links the topic and the mapping to the node
if (createNewInDB) Engine.setFocusNode(nodeOnViz) // means this user created it
nodeOnViz.setData('dim', 1, 'start')
nodeOnViz.setData('dim', 25, 'end')
if (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 (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 (Create.newTopic.addSynapse && permitCreateSynapseAfter) {
Create.newSynapse.topic1id = JIT.tempNode.getData('topic').id
// position the form
midpoint.x = JIT.tempNode.pos.getc().x + (nodeOnViz.pos.getc().x - JIT.tempNode.pos.getc().x) / 2
midpoint.y = JIT.tempNode.pos.getc().y + (nodeOnViz.pos.getc().y - JIT.tempNode.pos.getc().y) / 2
pixelPos = Util.coordsToPixels(Visualize.mGraph, midpoint)
$('#new_synapse').css('left', pixelPos.x + 'px')
$('#new_synapse').css('top', pixelPos.y + 'px')
// show the form
Create.newSynapse.open()
Visualize.mGraph.fx.animate({
modes: ['node-property:dim'],
duration: 500,
onComplete: function() {
JIT.tempNode = null
JIT.tempNode2 = null
JIT.tempInit = false
}
duration: 500
})
} else {
Visualize.mGraph.fx.plotNode(nodeOnViz, Visualize.mGraph.canvas)
Visualize.mGraph.fx.animate({
modes: ['node-property:dim'],
duration: 500,
onComplete: function() {}
})
}
} else {
Engine.run()
Visualize.mGraph.loadJSON(newnode)
nodeOnViz = Visualize.mGraph.graph.getNode(newnode.id)
Engine.addNode(nodeOnViz)
topic.set('node', nodeOnViz, {silent: true})
topic.updateNode() // links the topic and the mapping to the node
Engine.setFocusNode(nodeOnViz)
nodeOnViz.setData('dim', 1, 'start')
nodeOnViz.setData('dim', 25, 'end')
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'current')
@ -236,46 +209,24 @@ const Topic = {
Visualize.mGraph.fx.plotNode(nodeOnViz, Visualize.mGraph.canvas)
Visualize.mGraph.fx.animate({
modes: ['node-property:dim'],
duration: 500,
onComplete: function() {}
duration: 500
})
}
var mappingSuccessCallback = function(mappingModel, response, topicModel) {
// call a success callback if provided
if (opts.success) {
opts.success(topicModel)
}
}
var topicSuccessCallback = function(topicModel, response) {
if (Active.Map) {
mapping.save({ mappable_id: topicModel.id }, {
success: function(model, response) {
mappingSuccessCallback(model, response, topicModel)
},
error: function(model, response) {
console.log('error saving mapping to database')
}
})
}
if (Create.newTopic.addSynapse) {
Create.newSynapse.topic2id = topicModel.id
mapping.save({ mappable_id: topicModel.id })
}
createSynapse && Synapse.createSynapseLocally(true, connectToId, topicModel.id)
}
if (!Settings.sandbox && createNewInDB) {
if (createNewInDB) {
if (topic.isNew()) {
topic.save(null, {
success: topicSuccessCallback,
error: function(model, response) {
console.log('error saving topic to database')
}
success: topicSuccessCallback
})
} else if (!topic.isNew() && Active.Map) {
mapping.save(null, {
success: mappingSuccessCallback
})
mapping.save(null)
}
}
},
@ -287,9 +238,6 @@ const Topic = {
return
}
// hide the 'double-click to add a topic' message
GlobalUI.hideDiv('#instructions')
$(document).trigger(Map.events.editedByActiveMapper)
var metacode = DataModel.Metacodes.get(Create.newTopic.metacode)
@ -301,49 +249,32 @@ const Topic = {
})
DataModel.Topics.add(topic)
if (Create.newTopic.pinned) {
var nextCoords = AutoLayout.getNextCoord({ mappings: DataModel.Mappings })
}
var mapping = new DataModel.Mapping({
xloc: nextCoords ? nextCoords.x : Create.newTopic.x,
yloc: nextCoords ? nextCoords.y : Create.newTopic.y,
xloc: Mouse.newNodeCoords.x,
yloc: Mouse.newNodeCoords.y,
mappable_id: topic.cid,
mappable_type: 'Topic'
})
DataModel.Mappings.add(mapping)
// these can't happen until the value is retrieved, which happens in the line above
if (!Create.newTopic.pinned) Create.newTopic.hide()
Create.newTopic.reset()
self.renderTopic(mapping, topic, true, true) // this function also includes the creation of the topic in the database
self.renderTopic(mapping, topic, true) // this function also includes the creation of the topic in the database
},
getTopicFromAutocomplete: function(id) {
var self = Topic
// hide the 'double-click to add a topic' message
GlobalUI.hideDiv('#instructions')
$(document).trigger(Map.events.editedByActiveMapper)
if (!Create.newTopic.pinned) Create.newTopic.hide()
Create.newTopic.reset()
self.get(id, (topic) => {
if (Create.newTopic.pinned) {
var nextCoords = AutoLayout.getNextCoord({ mappings: DataModel.Mappings })
}
var mapping = new DataModel.Mapping({
xloc: nextCoords ? nextCoords.x : Create.newTopic.x,
yloc: nextCoords ? nextCoords.y : Create.newTopic.y,
xloc: Mouse.newNodeCoords.x,
yloc: Mouse.newNodeCoords.y,
mappable_type: 'Topic',
mappable_id: topic.id
})
DataModel.Mappings.add(mapping)
self.renderTopic(mapping, topic, true, true)
// this blocked the enterKeyHandler from creating a new topic as well
if (Create.newTopic.pinned) Create.newTopic.beingCreated = true
self.renderTopic(mapping, topic, true)
})
},
getMapFromAutocomplete: function(data) {
@ -361,20 +292,17 @@ const Topic = {
DataModel.Topics.add(topic)
var mapping = new DataModel.Mapping({
xloc: Create.newTopic.x,
yloc: Create.newTopic.y,
xloc: Mouse.newNodeCoords.x,
yloc: Mouse.newNodeCoords.y,
mappable_id: topic.cid,
mappable_type: 'Topic'
})
DataModel.Mappings.add(mapping)
// these can't happen until the value is retrieved, which happens in the line above
if (!Create.newTopic.pinned) Create.newTopic.hide()
Create.newTopic.reset()
self.renderTopic(mapping, topic, true, true) // this function also includes the creation of the topic in the database
// this blocked the enterKeyHandler from creating a new topic as well
if (Create.newTopic.pinned) Create.newTopic.beingCreated = true
self.renderTopic(mapping, topic, true) // this function also includes the creation of the topic in the database
},
getTopicFromSearch: function(event, id) {
var self = Topic
@ -390,8 +318,8 @@ const Topic = {
mappable_id: topic.id
})
DataModel.Mappings.add(mapping)
self.renderTopic(mapping, topic, true, true)
GlobalUI.notifyUser('Topic was added to your map!')
self.renderTopic(mapping, topic, true)
GlobalUI.notifyUser('Topic was added to your map')
})
event.stopPropagation()

View file

@ -1,11 +1,13 @@
/* global $ */
import _ from 'lodash'
import Matter from 'matter-js'
import $jit from '../patched/JIT'
import Active from './Active'
import DataModel from './DataModel'
import Engine from './Engine'
import JIT from './JIT'
import Loading from './Loading'
import Router from './Router'
@ -94,10 +96,14 @@ const Visualize = {
}
})
const startPos = new $jit.Complex(0, 0)
//const startPos = new $jit.Complex(0, 0)
const endPos = new $jit.Complex(mapping.get('xloc'), mapping.get('yloc'))
n.setPos(startPos, 'start')
//n.setPos(startPos, 'start')
//n.setPos(endPos, 'end')
n.setPos(endPos, 'current')
n.setPos(endPos, 'end')
n.setData('dim', 1, 'start')
n.setData('dim', 25, 'end')
})
} else if (self.type === 'ForceDirected3D') {
self.mGraph.compute()
@ -153,6 +159,8 @@ const Visualize = {
function runAnimation() {
Loading.hide()
$('#new_topic').show()
$('#topic_name').focus()
// load JSON data, if it's not empty
if (!self.loadLater) {
// load JSON data.
@ -170,7 +178,8 @@ const Visualize = {
if (self.type === 'RGraph') {
self.mGraph.fx.animate(JIT.RGraph.animate)
} else if (self.type === 'ForceDirected') {
self.mGraph.animate(JIT.ForceDirected.animateSavedLayout)
self.mGraph.plot()
Engine.run(true)
} else if (self.type === 'ForceDirected3D') {
self.mGraph.animate(JIT.ForceDirected.animateFDLayout)
}

View file

@ -7,6 +7,7 @@ import Control from './Control'
import Create from './Create'
import DataModel from './DataModel'
import Debug from './Debug'
import Engine from './Engine'
import Filter from './Filter'
import GlobalUI, {
Search, CreateMap, ImportDialog, Account as GlobalUIAccount,
@ -44,6 +45,7 @@ Metamaps.Control = Control
Metamaps.Create = Create
Metamaps.DataModel = DataModel
Metamaps.Debug = Debug
Metamaps.Engine = Engine
Metamaps.Filter = Filter
Metamaps.GlobalUI = GlobalUI
Metamaps.GlobalUI.Search = Search

View file

@ -0,0 +1,125 @@
/* global $ */
import React, { Component, PropTypes } from 'react'
const ENTER_KEY = 13
const LEFT_ARROW = 37
const UP_ARROW = 38
const RIGHT_ARROW = 39
const DOWN_ARROW = 40
const Metacode = (props) => {
const { m, onClick, underCursor } = props
return (
<li onClick={() => onClick(m.id) } className={ underCursor ? 'keySelect' : '' }>
<img src={ m.get('icon') } />
<span>{ m.get('name') }</span>
</li>
)
}
class MetacodeSelect extends Component {
constructor (props) {
super(props)
this.state = {
filterText: '',
selectingSection: true,
underCursor: 0
}
}
componentDidMount() {
const self = this
setTimeout(function() {
$(document.body).on('keyup.metacodeSelect', self.handleKeyUp.bind(self))
}, 10)
}
componentWillUnmount() {
$(document.body).off('.metacodeSelect')
}
changeFilterText (e) {
this.setState({ filterText: e.target.value, underCursor: 0 })
}
getSelectMetacodes () {
const { metacodes, recent, mostUsed } = this.props
const { filterText, activeTab } = this.state
let selectMetacodes = metacodes
if (filterText.length > 1) { // search
selectMetacodes = filterText.length > 1 ? metacodes.filter(m => {
return m.get('name').toLowerCase().search(filterText.toLowerCase()) > -1
}) : []
}
return selectMetacodes
}
handleKeyUp (e) {
const { close } = this.props
const { underCursor } = this.state
const selectMetacodes = this.getSelectMetacodes()
let nextIndex
switch (e.which) {
case ENTER_KEY:
if (selectMetacodes.length) this.resetAndClick(selectMetacodes[underCursor].id)
break
case UP_ARROW:
if (underCursor == 0) {
close()
break
}
nextIndex = underCursor == 0 ? selectMetacodes.length - 1 : underCursor - 1
this.setState({ underCursor: nextIndex })
break
case DOWN_ARROW:
nextIndex = underCursor == selectMetacodes.length - 1 ? 0 : underCursor + 1
this.setState({ underCursor: nextIndex })
break
}
}
resetAndClick (id) {
const { onClick } = this.props
this.setState({ filterText: '', underCursor: 0 })
onClick(id)
}
render () {
const { onClick, close } = this.props
const { filterText, underCursor } = this.state
const selectMetacodes = this.getSelectMetacodes()
return <div className='metacodeSelect'>
<div className='tabList'>
<input type='text'
className='metacodeFilterInput'
placeholder='Search...'
ref='input'
value={ filterText }
onChange={ this.changeFilterText.bind(this) } />
<ul className='metacodeList'>
{ selectMetacodes.map((m, index) => {
return <Metacode underCursor={underCursor == index}
key={m.id}
m={m}
onClick={this.resetAndClick.bind(this)} />
})}
</ul>
<div className='clearfloat'></div>
</div>
</div>
}
}
MetacodeSelect.propTypes = {
onClick: PropTypes.func.isRequired,
close: PropTypes.func.isRequired,
metacodes: PropTypes.array.isRequired,
}
export default MetacodeSelect

View file

@ -2560,7 +2560,10 @@ Extras.Classes.Navigation = new Class({
}
if (Metamaps.Mouse.boxStartCoordinates && ((e.button == 0 && e.shiftKey) || (e.button == 0 && e.ctrlKey) || rightClick)) {
Metamaps.Visualize.mGraph.busy = true;
Metamaps.JIT.drawSelectBox(eventInfo,e);
Metamaps.Mouse.boxEndCoordinates = {
x: eventInfo.getPos().x,
y: eventInfo.getPos().y
}
//console.log('mouse move');
return;
}
@ -2606,9 +2609,7 @@ Extras.Classes.Navigation = new Class({
this.pressed = false;
// START METAMAPS CODE
if (Metamaps.Mouse.didPan) Metamaps.JIT.SmoothPanning();
if (Metamaps.Mouse.didPan) Metamaps.JIT.SmoothPanning();
// END METAMAPS CODE
},
@ -2651,7 +2652,10 @@ Extras.Classes.Navigation = new Class({
}
if (Metamaps.Mouse.boxStartCoordinates && ((e.button == 0 && e.shiftKey) || (e.button == 0 && e.ctrlKey) || rightClick)) {
Metamaps.Visualize.mGraph.busy = true;
Metamaps.JIT.drawSelectBox(eventInfo,e);
Metamaps.Mouse.boxEndCoordinates = {
x: eventInfo.getPos().x,
y: eventInfo.getPos().y
}
return;
}
if (rightClick){
@ -7225,7 +7229,7 @@ Graph.Plot = {
var T = !!root.visited;
//START METAMAPS CODE
if (Metamaps.Mouse.synapseStartCoordinates.length > 0) {
if (Metamaps.Mouse.synapseStartCoordinates.length > 0 && Metamaps.Mouse.synapseEndCoordinates) {
ctx.save();
var start;
var end = Metamaps.Mouse.synapseEndCoordinates;
@ -7238,6 +7242,26 @@ Graph.Plot = {
}
ctx.restore();
}
if (Metamaps.Mouse.focusNodeCoords) {
ctx.save();
Metamaps.JIT.renderMidArrow(Metamaps.Mouse.focusNodeCoords, Metamaps.Mouse.newNodeCoords, 13, false, canvas, 0.3, true);
Metamaps.JIT.renderMidArrow(Metamaps.Mouse.focusNodeCoords, Metamaps.Mouse.newNodeCoords, 13, false, canvas, 0.7, true);
ctx.restore();
}
if (Metamaps.Mouse.boxStartCoordinates && Metamaps.Mouse.boxEndCoordinates) {
ctx.save();
ctx.beginPath()
ctx.moveTo(Metamaps.Mouse.boxStartCoordinates.x, Metamaps.Mouse.boxStartCoordinates.y)
ctx.lineTo(Metamaps.Mouse.boxStartCoordinates.x, Metamaps.Mouse.boxEndCoordinates.y)
ctx.lineTo(Metamaps.Mouse.boxEndCoordinates.x, Metamaps.Mouse.boxEndCoordinates.y)
ctx.lineTo(Metamaps.Mouse.boxEndCoordinates.x, Metamaps.Mouse.boxStartCoordinates.y)
ctx.lineTo(Metamaps.Mouse.boxStartCoordinates.x, Metamaps.Mouse.boxStartCoordinates.y)
ctx.strokeStyle = 'black'
ctx.stroke()
ctx.restore()
}
//END METAMAPS CODE
aGraph.eachNode(function(node) {

View file

@ -35,6 +35,7 @@
"howler": "2.0.2",
"json-loader": "0.5.4",
"lodash": "4.17.2",
"matter-js": "0.11.1",
"node-uuid": "1.4.7",
"outdent": "0.3.0",
"react": "15.4.1",