Compare commits
16 commits
develop
...
feature/pa
Author | SHA1 | Date | |
---|---|---|---|
|
e7a52dc14e | ||
|
149b7ecbd6 | ||
|
b2b5090b28 | ||
|
38c01c4e8f | ||
|
b13ac98c9f | ||
|
4a17d00123 | ||
|
9c13f5a281 | ||
|
616a489ae4 | ||
|
816815d1b5 | ||
|
3ff102b228 | ||
|
bf9b25da9f | ||
|
5ba7ba9355 | ||
|
ce7c88c78c | ||
|
74630c2631 | ||
|
966dd79187 | ||
|
5d04d16590 |
31 changed files with 716 additions and 402 deletions
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
42
app/assets/stylesheets/metacode-select.scss.erb
Normal file
42
app/assets/stylesheets/metacode-select.scss.erb
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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' %>
|
||||
|
||||
|
|
|
@ -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 %>
|
||||
|
|
|
@ -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 %>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Active from '../Active'
|
||||
import Engine from '../Engine'
|
||||
import Filter from '../Filter'
|
||||
import { InfoBox } from '../Map'
|
||||
|
||||
|
|
120
frontend/src/Metamaps/Engine.js
Normal file
120
frontend/src/Metamaps/Engine.js
Normal 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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
},
|
||||
|
|
|
@ -6,6 +6,8 @@ const Mouse = {
|
|||
edgeHoveringOver: false,
|
||||
boxStartCoordinates: false,
|
||||
boxEndCoordinates: false,
|
||||
focusNodeCoords: null,
|
||||
newNodeCoords: { x: 100, y: 0 },
|
||||
synapseStartCoordinates: [],
|
||||
synapseEndCoordinates: null,
|
||||
lastNodeClick: 0,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
125
frontend/src/components/MetacodeSelect.js
Normal file
125
frontend/src/components/MetacodeSelect.js
Normal 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
|
||||
|
|
@ -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) {
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue