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
|
// START METAMAPS CODE
|
||||||
// Add code that makes tab and shift+tab scroll through metacodes
|
// Add code that makes tab and shift+tab scroll through metacodes
|
||||||
$('.new_topic').bind('keydown',this,function(event){
|
$('.new_topic').bind('keydown',this,function(event){
|
||||||
if (event.keyCode == 9) {
|
if (event.keyCode == 9 && event.shiftKey) {
|
||||||
if (event.shiftKey) {
|
$(container).show()
|
||||||
event.data.rotate(-1)
|
event.data.rotate(-1);
|
||||||
} else {
|
event.preventDefault();
|
||||||
event.data.rotate(1)
|
event.stopPropagation();
|
||||||
}
|
} else if (event.keyCode == 9) {
|
||||||
event.preventDefault();
|
$(container).show()
|
||||||
event.stopPropagation();
|
event.data.rotate(1);
|
||||||
Metamaps.Create.newTopic.metacode = $(items[event.data.frontIndex].image).attr('data-id');
|
event.preventDefault();
|
||||||
}
|
event.stopPropagation();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// END METAMAPS CODE
|
// END METAMAPS CODE
|
||||||
|
|
||||||
|
@ -181,14 +182,14 @@ jQuery.browser = browser;
|
||||||
if (options.mouseWheel)
|
if (options.mouseWheel)
|
||||||
{
|
{
|
||||||
// START METAMAPS CODE
|
// START METAMAPS CODE
|
||||||
$('body').bind('mousewheel',this,function(event, delta) {
|
/*$('body').bind('mousewheel',this,function(event, delta) {
|
||||||
if (Metamaps.Create.newTopic.beingCreated &&
|
if (Metamaps.Create.newTopic.beingCreated &&
|
||||||
!Metamaps.Create.isSwitchingSet &&
|
!Metamaps.Create.isSwitchingSet &&
|
||||||
!Metamaps.Create.newTopic.pinned) {
|
!Metamaps.Create.newTopic.pinned) {
|
||||||
event.data.rotate(delta);
|
event.data.rotate(delta);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});*/
|
||||||
// END METAMAPS CODE
|
// END METAMAPS CODE
|
||||||
// ORIGINAL CODE
|
// ORIGINAL CODE
|
||||||
// $(container).bind('mousewheel',this,function(event, delta) {
|
// $(container).bind('mousewheel',this,function(event, delta) {
|
||||||
|
@ -255,8 +256,11 @@ jQuery.browser = browser;
|
||||||
this.showFrontText = function()
|
this.showFrontText = function()
|
||||||
{
|
{
|
||||||
if ( items[this.frontIndex] === undefined ) { return; } // Images might not have loaded yet.
|
if ( items[this.frontIndex] === undefined ) { return; } // Images might not have loaded yet.
|
||||||
$(options.titleBox).html( $(items[this.frontIndex].image).attr('title'));
|
// METAMAPS CODE
|
||||||
$(options.altBox).html( $(items[this.frontIndex].image).attr('alt'));
|
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()
|
this.go = function()
|
||||||
|
@ -269,7 +273,10 @@ jQuery.browser = browser;
|
||||||
this.stop = function()
|
this.stop = function()
|
||||||
{
|
{
|
||||||
clearTimeout(this.controlTimer);
|
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.
|
// If all images have valid widths and heights, we can stop checking.
|
||||||
clearInterval(this.tt);
|
clearInterval(this.tt);
|
||||||
this.showFrontText();
|
// METAMAPS COMMENT this.showFrontText();
|
||||||
this.autoRotate();
|
this.autoRotate();
|
||||||
this.updateAll();
|
this.updateAll();
|
||||||
|
|
||||||
|
|
|
@ -526,23 +526,53 @@ button.button.btn-no:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.new_topic {
|
.new_topic {
|
||||||
/* start it off screen while it initializes the spinner, then it will be hidden with jquery */
|
top: -10000px;
|
||||||
top: -1000px;
|
left: -10000px;
|
||||||
left: -1000px;
|
margin-top: -17px;
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 340px;
|
|
||||||
margin: -40px 0 0 -35px;
|
|
||||||
z-index: 1;
|
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 {
|
#new_topic .twitter-typeahead {
|
||||||
position: absolute !important;
|
|
||||||
top: 45px;
|
|
||||||
left: 41px;
|
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
width: 256px;
|
width: 256px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
|
float: left;
|
||||||
}
|
}
|
||||||
.new_topic #topic_name,
|
.new_topic #topic_name,
|
||||||
.new_topic .tt-hint {
|
.new_topic .tt-hint {
|
||||||
|
@ -552,7 +582,8 @@ button.button.btn-no:hover {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 10px 6px;
|
padding: 10px 6px;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 2px;
|
border-top-right-radius: 2px;
|
||||||
|
border-bottom-right-radius: 2px;
|
||||||
outline: none;
|
outline: none;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
|
@ -569,36 +600,22 @@ button.button.btn-no:hover {
|
||||||
background-image: url(<%= asset_data_uri('metacodesettings_sprite.png') %>);
|
background-image: url(<%= asset_data_uri('metacodesettings_sprite.png') %>);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
top: 20px;
|
top: -16px;
|
||||||
left: 16px;
|
left: -16px;
|
||||||
}
|
}
|
||||||
.openMetacodeSwitcher:hover {
|
.openMetacodeSwitcher:hover {
|
||||||
background-position: -16px 0;
|
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 {
|
#metacodeImg {
|
||||||
height: 120px;
|
height: 120px;
|
||||||
|
width: 380px;
|
||||||
|
display: none;
|
||||||
|
position: absolute !important;
|
||||||
|
top: -30px;
|
||||||
|
z-index: -1;
|
||||||
}
|
}
|
||||||
#metacodeImgTitle {
|
#metacodeImgTitle {
|
||||||
|
display: none;
|
||||||
float: left;
|
float: left;
|
||||||
width: 120px;
|
width: 120px;
|
||||||
text-align: center;
|
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
|
# frozen_string_literal: true
|
||||||
class UsersController < ApplicationController
|
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
|
respond_to :html, :json
|
||||||
|
|
||||||
|
@ -91,6 +91,16 @@ class UsersController < ApplicationController
|
||||||
format.json { render json: @user }
|
format.json { render json: @user }
|
||||||
end
|
end
|
||||||
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
|
private
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,10 @@ module ApplicationHelper
|
||||||
end
|
end
|
||||||
@metacodes.sort! { |m1, m2| m2.name.downcase <=> m1.name.downcase }.rotate!(-1)
|
@metacodes.sort! { |m1, m2| m2.name.downcase <=> m1.name.downcase }.rotate!(-1)
|
||||||
end
|
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
|
def user_most_used_metacodes
|
||||||
@metacodes = current_user.most_used_metacodes.map { |id| Metacode.find(id) }
|
@metacodes = current_user.most_used_metacodes.map { |id| Metacode.find(id) }
|
||||||
|
|
|
@ -8,10 +8,6 @@ class Mapping < ApplicationRecord
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :updated_by, class_name: '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 :map, presence: true
|
||||||
validates :mappable, presence: true
|
validates :mappable, presence: true
|
||||||
|
|
||||||
|
@ -31,7 +27,7 @@ class Mapping < ApplicationRecord
|
||||||
|
|
||||||
def after_created
|
def after_created
|
||||||
if mappable_type == 'Topic'
|
if mappable_type == 'Topic'
|
||||||
meta = {'x': xloc, 'y': yloc, 'mapping_id': id}
|
meta = {'mapping_id': id}
|
||||||
Events::TopicAddedToMap.publish!(mappable, map, user, meta)
|
Events::TopicAddedToMap.publish!(mappable, map, user, meta)
|
||||||
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'topicAdded', topic: mappable.filtered, mapping_id: id
|
ActionCable.server.broadcast 'map_' + map.id.to_s, type: 'topicAdded', topic: mappable.filtered, mapping_id: id
|
||||||
elsif mappable_type == 'Synapse'
|
elsif mappable_type == 'Synapse'
|
||||||
|
|
|
@ -66,6 +66,28 @@ class User < ApplicationRecord
|
||||||
json['rtype'] = 'mapper'
|
json['rtype'] = 'mapper'
|
||||||
json
|
json
|
||||||
end
|
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
|
def all_accessible_maps
|
||||||
maps + shared_maps
|
maps + shared_maps
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
class UserPreference
|
class UserPreference
|
||||||
attr_accessor :metacodes
|
attr_accessor :metacodes, :metacode_focus
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
array = []
|
array = []
|
||||||
|
@ -15,5 +15,6 @@ class UserPreference
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@metacodes = array
|
@metacodes = array
|
||||||
|
@metacode_focus = array[0]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -47,19 +47,6 @@
|
||||||
<%= render :partial => 'layouts/lowermapelements' %>
|
<%= render :partial => 'layouts/lowermapelements' %>
|
||||||
|
|
||||||
<div id="explore"></div>
|
<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>
|
<div id="infovis"></div>
|
||||||
<%= render :partial => 'layouts/mobilemenu' %>
|
<%= render :partial => 'layouts/mobilemenu' %>
|
||||||
|
|
||||||
|
|
|
@ -1,34 +1,37 @@
|
||||||
<% @metacodes = user_metacodes() %>
|
|
||||||
|
|
||||||
<%= form_for Topic.new, url: topics_url, remote: true do |form| %>
|
<%= form_for Topic.new, url: topics_url, remote: true do |form| %>
|
||||||
<div class="openMetacodeSwitcher openLightbox" data-open="switchMetacodes">
|
<div class="openMetacodeSwitcher openLightbox" data-open="switchMetacodes">
|
||||||
<div class="tooltipsAbove">Switch Metacodes</div>
|
<div class="tooltipsAbove">Switch Metacodes</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pinCarousel">
|
|
||||||
<div class="tooltipsAbove helpPin">Pin Open</div>
|
|
||||||
<div class="tooltipsAbove helpUnpin">Unpin</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="metacodeImg">
|
<div id="metacodeImg">
|
||||||
|
<% @metacodes = [user_metacode()].concat(user_metacodes()).uniq %>
|
||||||
|
<% set = metacodeset() %>
|
||||||
<% @metacodes.each do |metacode| %>
|
<% @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 %>" />
|
<img class="cloudcarousel" width="40" height="40" src="<%= asset_path metacode.icon %>" alt="<%= metacode.name %>" title="<%= metacode.name %>" data-id="<%= metacode.id %>" />
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="selectedMetacode">
|
||||||
<%= form.text_field :name, :maxlength => 140, :placeholder => "title..." %>
|
<img src="<%= asset_path user_metacode().icon %>" />
|
||||||
|
<span><%= user_metacode().name %></span>
|
||||||
<div id="metacodeImgTitle"></div>
|
<div class="downArrow"></div>
|
||||||
|
</div>
|
||||||
|
<%= form.text_field :name, :maxlength => 140, :placeholder => "what are you thinking..." %>
|
||||||
<div class="clearfloat"></div>
|
<div class="clearfloat"></div>
|
||||||
|
<div id="metacodeSelector"></div>
|
||||||
<script>
|
<div class="clearfloat"></div>
|
||||||
<% @metacodes.each do |metacode| %>
|
<script>
|
||||||
<% if !metacodeset() %>
|
<% @metacodes.each do |metacode| %>
|
||||||
Metamaps.Create.selectedMetacodes.push("<%= metacode.id %>");
|
Metamaps.Create.selectedMetacodes.push("<%= metacode.id %>");
|
||||||
Metamaps.Create.newSelectedMetacodes.push("<%= metacode.id %>");
|
Metamaps.Create.newSelectedMetacodes.push("<%= metacode.id %>");
|
||||||
Metamaps.Create.selectedMetacodeNames.push("<%= metacode.name %>");
|
Metamaps.Create.selectedMetacodeNames.push("<%= metacode.name %>");
|
||||||
Metamaps.Create.newSelectedMetacodeNames.push("<%= metacode.name %>");
|
Metamaps.Create.newSelectedMetacodeNames.push("<%= metacode.name %>");
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
Metamaps.Create.newTopic.metacode = <%= user_metacode().id %>
|
||||||
</script>
|
<% 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 %>
|
<% end %>
|
||||||
|
|
|
@ -93,12 +93,9 @@
|
||||||
<div id="metacodeSwitchTabsCustom">
|
<div id="metacodeSwitchTabsCustom">
|
||||||
<p class="setDesc">Choose Your Metacodes</p>
|
<p class="setDesc">Choose Your Metacodes</p>
|
||||||
<% @list = '' %>
|
<% @list = '' %>
|
||||||
|
<% metacodesInUse = [user_metacode()].concat(user_metacodes()).uniq %>
|
||||||
<% Metacode.order("name").all.each_with_index do |m, index| %>
|
<% Metacode.order("name").all.each_with_index do |m, index| %>
|
||||||
<% if selectedSet == "custom" %>
|
<% mClass = metacodesInUse.index(m) == nil ? "toggledOff" : "" %>
|
||||||
<% mClass = metacodes.index(m.id.to_s) == nil ? "toggledOff" : "" %>
|
|
||||||
<% else %>
|
|
||||||
<% mClass = "toggledOff" %>
|
|
||||||
<% end %>
|
|
||||||
<% @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>' %>
|
<% @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 %>
|
<% end %>
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,7 @@ Metamaps::Application.routes.draw do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
post 'user/updatemetacodes', to: 'users#updatemetacodes', as: :updatemetacodes
|
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 :api, path: '/api', default: { format: :json } do
|
||||||
namespace :v2, path: '/v2' do
|
namespace :v2, path: '/v2' do
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
import Active from './Active'
|
import Active from './Active'
|
||||||
import Control from './Control'
|
import Control from './Control'
|
||||||
|
import Create from './Create'
|
||||||
import DataModel from './DataModel'
|
import DataModel from './DataModel'
|
||||||
|
import Engine from './Engine'
|
||||||
import Map from './Map'
|
import Map from './Map'
|
||||||
import Mapper from './Mapper'
|
import Mapper from './Mapper'
|
||||||
import Synapse from './Synapse'
|
import Synapse from './Synapse'
|
||||||
|
@ -26,7 +28,7 @@ const Cable = {
|
||||||
},
|
},
|
||||||
unsubscribeFromMap: () => {
|
unsubscribeFromMap: () => {
|
||||||
let self = Cable
|
let self = Cable
|
||||||
self.sub.unsubscribe()
|
self.sub && self.sub.unsubscribe()
|
||||||
delete self.sub
|
delete self.sub
|
||||||
},
|
},
|
||||||
synapseAdded: event => {
|
synapseAdded: event => {
|
||||||
|
@ -51,6 +53,9 @@ const Cable = {
|
||||||
node2 = topic2.get('node')
|
node2 = topic2.get('node')
|
||||||
|
|
||||||
Synapse.renderSynapse(mapping, synapse, node1, node2, false)
|
Synapse.renderSynapse(mapping, synapse, node1, node2, false)
|
||||||
|
if (Create.newSynapse.focusNode === node1) {
|
||||||
|
Engine.setFocusNode(node2)
|
||||||
|
}
|
||||||
} else if (!cancel) {
|
} else if (!cancel) {
|
||||||
setTimeout(waitThenRenderSynapse, 10)
|
setTimeout(waitThenRenderSynapse, 10)
|
||||||
}
|
}
|
||||||
|
@ -132,7 +137,7 @@ const Cable = {
|
||||||
|
|
||||||
function waitThenRenderTopic() {
|
function waitThenRenderTopic() {
|
||||||
if (topic && mapping && mapper) {
|
if (topic && mapping && mapper) {
|
||||||
Topic.renderTopic(mapping, topic, false, false)
|
Topic.renderTopic(mapping, topic, false)
|
||||||
} else if (!cancel) {
|
} else if (!cancel) {
|
||||||
setTimeout(waitThenRenderTopic, 10)
|
setTimeout(waitThenRenderTopic, 10)
|
||||||
}
|
}
|
||||||
|
@ -183,7 +188,7 @@ const Cable = {
|
||||||
},
|
},
|
||||||
topicMoved: event => {
|
topicMoved: event => {
|
||||||
var topic, node, mapping
|
var topic, node, mapping
|
||||||
if (Active.Map) {
|
/*if (Active.Map) {
|
||||||
topic = DataModel.Topics.get(event.id)
|
topic = DataModel.Topics.get(event.id)
|
||||||
mapping = DataModel.Mappings.get(event.mapping_id)
|
mapping = DataModel.Mappings.get(event.mapping_id)
|
||||||
mapping.set('xloc', event.x)
|
mapping.set('xloc', event.x)
|
||||||
|
@ -191,7 +196,7 @@ const Cable = {
|
||||||
if (topic) node = topic.get('node')
|
if (topic) node = topic.get('node')
|
||||||
if (node) node.pos.setc(event.x, event.y)
|
if (node) node.pos.setc(event.x, event.y)
|
||||||
Visualize.mGraph.plot()
|
Visualize.mGraph.plot()
|
||||||
}
|
}*/
|
||||||
},
|
},
|
||||||
topicRemoved: event => {
|
topicRemoved: event => {
|
||||||
var topic = DataModel.Topics.get(event.id)
|
var topic = DataModel.Topics.get(event.id)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import outdent from 'outdent'
|
||||||
|
|
||||||
import Active from './Active'
|
import Active from './Active'
|
||||||
import DataModel from './DataModel'
|
import DataModel from './DataModel'
|
||||||
|
import Engine from './Engine'
|
||||||
import Filter from './Filter'
|
import Filter from './Filter'
|
||||||
import GlobalUI from './GlobalUI'
|
import GlobalUI from './GlobalUI'
|
||||||
import JIT from './JIT'
|
import JIT from './JIT'
|
||||||
|
@ -22,6 +23,7 @@ const Control = {
|
||||||
node.selected = true
|
node.selected = true
|
||||||
node.setData('dim', 30, 'current')
|
node.setData('dim', 30, 'current')
|
||||||
Selected.Nodes.push(node)
|
Selected.Nodes.push(node)
|
||||||
|
Engine.setNodeSleeping(node.getData('body_id'), true)
|
||||||
},
|
},
|
||||||
deselectAllNodes: function() {
|
deselectAllNodes: function() {
|
||||||
var l = Selected.Nodes.length
|
var l = Selected.Nodes.length
|
||||||
|
@ -38,6 +40,7 @@ const Control = {
|
||||||
// remove the node
|
// remove the node
|
||||||
Selected.Nodes.splice(
|
Selected.Nodes.splice(
|
||||||
Selected.Nodes.indexOf(node), 1)
|
Selected.Nodes.indexOf(node), 1)
|
||||||
|
Engine.setNodeSleeping(node.getData('body_id'), false)
|
||||||
},
|
},
|
||||||
deleteSelected: function() {
|
deleteSelected: function() {
|
||||||
if (!Active.Map) return
|
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 DataModel from './DataModel'
|
||||||
|
import MetacodeSelect from '../components/MetacodeSelect'
|
||||||
import Mouse from './Mouse'
|
import Mouse from './Mouse'
|
||||||
import Selected from './Selected'
|
import Selected from './Selected'
|
||||||
import Synapse from './Synapse'
|
import Synapse from './Synapse'
|
||||||
import Topic from './Topic'
|
import Topic from './Topic'
|
||||||
|
import Util from './Util'
|
||||||
import Visualize from './Visualize'
|
import Visualize from './Visualize'
|
||||||
import GlobalUI from './GlobalUI'
|
import GlobalUI from './GlobalUI'
|
||||||
|
|
||||||
|
@ -16,9 +21,11 @@ const Create = {
|
||||||
newSelectedMetacodeNames: [],
|
newSelectedMetacodeNames: [],
|
||||||
selectedMetacodes: [],
|
selectedMetacodes: [],
|
||||||
newSelectedMetacodes: [],
|
newSelectedMetacodes: [],
|
||||||
init: function() {
|
recentMetacodes: [],
|
||||||
|
mostUsedMetacodes: [],
|
||||||
|
init: function (serverData) {
|
||||||
var self = Create
|
var self = Create
|
||||||
self.newTopic.init()
|
self.newTopic.init(serverData)
|
||||||
self.newSynapse.init()
|
self.newSynapse.init()
|
||||||
|
|
||||||
// // SWITCHING METACODE SETS
|
// // SWITCHING METACODE SETS
|
||||||
|
@ -58,10 +65,11 @@ const Create = {
|
||||||
if (!custom) {
|
if (!custom) {
|
||||||
codesToSwitchToIds = $('#metacodeSwitchTabs' + set).attr('data-metacodes').split(',')
|
codesToSwitchToIds = $('#metacodeSwitchTabs' + set).attr('data-metacodes').split(',')
|
||||||
$('.customMetacodeList li').addClass('toggledOff')
|
$('.customMetacodeList li').addClass('toggledOff')
|
||||||
Create.selectedMetacodes = []
|
console.log(codesToSwitchToIds)
|
||||||
Create.selectedMetacodeNames = []
|
Create.selectedMetacodes = codesToSwitchToIds
|
||||||
Create.newSelectedMetacodes = []
|
Create.selectedMetacodeNames = DataModel.Metacodes.filter(m => codesToSwitchToIds.indexOf(m.id) > -1).map(m => m.get('name'))
|
||||||
Create.newSelectedMetacodeNames = []
|
Create.newSelectedMetacodes = codesToSwitchToIds
|
||||||
|
Create.newSelectedMetacodeNames = DataModel.Metacodes.filter(m => codesToSwitchToIds.indexOf(m.id) > -1).map(m => m.get('name'))
|
||||||
} else if (custom) {
|
} else if (custom) {
|
||||||
// uses .slice to avoid setting the two arrays to the same actual array
|
// uses .slice to avoid setting the two arrays to the same actual array
|
||||||
Create.selectedMetacodes = Create.newSelectedMetacodes.slice(0)
|
Create.selectedMetacodes = Create.newSelectedMetacodes.slice(0)
|
||||||
|
@ -70,12 +78,13 @@ const Create = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort by name
|
// sort by name
|
||||||
for (var i = 0; i < codesToSwitchToIds.length; i++) {
|
codesToSwitchToIds.forEach(id => {
|
||||||
metacodeModels.add(DataModel.Metacodes.get(codesToSwitchToIds[i]))
|
const metacode = DataModel.Metacodes.get(id)
|
||||||
}
|
metacodeModels.add(metacode)
|
||||||
|
$('.customMetacodeList #' + id).removeClass('toggledOff')
|
||||||
|
})
|
||||||
metacodeModels.sort()
|
metacodeModels.sort()
|
||||||
|
|
||||||
$('#metacodeImg, #metacodeImgTitle').empty()
|
|
||||||
$('#metacodeImg').removeData('cloudcarousel')
|
$('#metacodeImg').removeData('cloudcarousel')
|
||||||
var newMetacodes = ''
|
var newMetacodes = ''
|
||||||
metacodeModels.each(function(metacode) {
|
metacodeModels.each(function(metacode) {
|
||||||
|
@ -83,16 +92,16 @@ const Create = {
|
||||||
})
|
})
|
||||||
|
|
||||||
$('#metacodeImg').empty().append(newMetacodes).CloudCarousel({
|
$('#metacodeImg').empty().append(newMetacodes).CloudCarousel({
|
||||||
titleBox: $('#metacodeImgTitle'),
|
|
||||||
yRadius: 40,
|
yRadius: 40,
|
||||||
xRadius: 190,
|
xRadius: 190,
|
||||||
xPos: 170,
|
xPos: 170,
|
||||||
yPos: 40,
|
yPos: 40,
|
||||||
speed: 0.3,
|
speed: 0.3,
|
||||||
mouseWheel: true,
|
|
||||||
bringToFront: true
|
bringToFront: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Create.newTopic.setMetacode(metacodeModels.models[0].id)
|
||||||
|
|
||||||
GlobalUI.closeLightbox()
|
GlobalUI.closeLightbox()
|
||||||
$('#topic_name').focus()
|
$('#topic_name').focus()
|
||||||
|
|
||||||
|
@ -119,13 +128,7 @@ const Create = {
|
||||||
var self = Create
|
var self = Create
|
||||||
self.isSwitchingSet = false
|
self.isSwitchingSet = false
|
||||||
|
|
||||||
if (self.selectedMetacodeSet !== 'metacodeset-custom') {
|
if (self.selectedMetacodeSet === 'metacodeset-custom') {
|
||||||
$('.customMetacodeList li').addClass('toggledOff')
|
|
||||||
self.selectedMetacodes = []
|
|
||||||
self.selectedMetacodeNames = []
|
|
||||||
self.newSelectedMetacodes = []
|
|
||||||
self.newSelectedMetacodeNames = []
|
|
||||||
} else { // custom set is selected
|
|
||||||
// reset it to the current actual selection
|
// reset it to the current actual selection
|
||||||
$('.customMetacodeList li').addClass('toggledOff')
|
$('.customMetacodeList li').addClass('toggledOff')
|
||||||
for (var i = 0; i < self.selectedMetacodes.length; i++) {
|
for (var i = 0; i < self.selectedMetacodes.length; i++) {
|
||||||
|
@ -139,27 +142,33 @@ const Create = {
|
||||||
$('#topic_name').focus()
|
$('#topic_name').focus()
|
||||||
},
|
},
|
||||||
newTopic: {
|
newTopic: {
|
||||||
init: function() {
|
init: function (serverData) {
|
||||||
$('#topic_name').keyup(function(e) {
|
const DOWN_ARROW = 40
|
||||||
const ESC = 27
|
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) {
|
if (e.keyCode === ESC) {
|
||||||
Create.newTopic.hide()
|
Create.newTopic.hide()
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
Create.newTopic.name = $(this).val()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
$('.pinCarousel').click(function() {
|
$('.selectedMetacode').click(function() {
|
||||||
if (Create.newTopic.pinned) {
|
if (Create.newTopic.metacodeSelectorOpen) {
|
||||||
$('.pinCarousel').removeClass('isPinned')
|
Create.newTopic.hideSelector()
|
||||||
Create.newTopic.pinned = false
|
$('#topic_name').focus()
|
||||||
} else {
|
} else Create.newTopic.openSelector()
|
||||||
$('.pinCarousel').addClass('isPinned')
|
|
||||||
Create.newTopic.pinned = true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Create.newTopic.initSelector()
|
||||||
|
|
||||||
var topicBloodhound = new Bloodhound({
|
var topicBloodhound = new Bloodhound({
|
||||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
|
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
|
||||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||||
|
@ -200,52 +209,86 @@ const Create = {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
$('#topic_name').click(function() { Create.newTopic.hideSelector() })
|
||||||
|
|
||||||
// initialize metacode spinner and then hide it
|
// initialize metacode spinner and then hide it
|
||||||
$('#metacodeImg').CloudCarousel({
|
$('#metacodeImg').CloudCarousel({
|
||||||
titleBox: $('#metacodeImgTitle'),
|
|
||||||
yRadius: 40,
|
yRadius: 40,
|
||||||
xRadius: 190,
|
xRadius: 190,
|
||||||
xPos: 170,
|
xPos: 170,
|
||||||
yPos: 40,
|
yPos: 40,
|
||||||
speed: 0.3,
|
speed: 0.3,
|
||||||
mouseWheel: true,
|
|
||||||
bringToFront: true
|
bringToFront: true
|
||||||
})
|
})
|
||||||
$('.new_topic').hide()
|
$('#new_topic').hide()
|
||||||
$('#new_topic').attr('oncontextmenu', 'return false') // prevents the mouse up event from opening the default context menu on this element
|
.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,
|
name: null,
|
||||||
newId: 1,
|
newId: 1,
|
||||||
beingCreated: false,
|
beingCreated: false,
|
||||||
|
metacodeSelectorOpen: false,
|
||||||
metacode: null,
|
metacode: null,
|
||||||
x: null,
|
x: null,
|
||||||
y: null,
|
y: null,
|
||||||
addSynapse: false,
|
addSynapse: false,
|
||||||
pinned: false,
|
pinned: false,
|
||||||
open: function() {
|
initSelector: function () {
|
||||||
$('#new_topic').fadeIn('fast', function() {
|
ReactDOM.render(
|
||||||
$('#topic_name').focus()
|
React.createElement(MetacodeSelect, {
|
||||||
})
|
onClick: function (id) {
|
||||||
Create.newTopic.beingCreated = true
|
Create.newTopic.setMetacode(id)
|
||||||
Create.newTopic.name = ''
|
Create.newTopic.hideSelector()
|
||||||
GlobalUI.hideDiv('#instructions')
|
$('#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) {
|
openSelector: function () {
|
||||||
if (force || !Create.newTopic.pinned) {
|
Create.newTopic.initSelector()
|
||||||
$('#new_topic').fadeOut('fast')
|
$('#metacodeSelector').show()
|
||||||
}
|
Create.newTopic.metacodeSelectorOpen = true
|
||||||
if (force) {
|
$('.metacodeFilterInput').focus()
|
||||||
$('.pinCarousel').removeClass('isPinned')
|
$('.selectedMetacode').addClass('isBeingSelected')
|
||||||
Create.newTopic.pinned = false
|
},
|
||||||
}
|
hideSelector: function () {
|
||||||
if (DataModel.Topics.length === 0) {
|
ReactDOM.unmountComponentAtNode(document.getElementById('metacodeSelector'))
|
||||||
GlobalUI.showDiv('#instructions')
|
$('#metacodeSelector').hide()
|
||||||
}
|
Create.newTopic.metacodeSelectorOpen = false
|
||||||
Create.newTopic.beingCreated = 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() {
|
reset: function() {
|
||||||
$('#topic_name').typeahead('val', '')
|
$('#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: {
|
newSynapse: {
|
||||||
|
@ -338,6 +381,7 @@ const Create = {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
focusNode: null,
|
||||||
beingCreated: false,
|
beingCreated: false,
|
||||||
description: null,
|
description: null,
|
||||||
topic1id: null,
|
topic1id: null,
|
||||||
|
@ -356,8 +400,35 @@ const Create = {
|
||||||
Create.newTopic.addSynapse = false
|
Create.newTopic.addSynapse = false
|
||||||
Create.newSynapse.topic1id = 0
|
Create.newSynapse.topic1id = 0
|
||||||
Create.newSynapse.topic2id = 0
|
Create.newSynapse.topic2id = 0
|
||||||
|
Create.newSynapse.node1 = null
|
||||||
|
Create.newSynapse.node2 = null
|
||||||
Mouse.synapseStartCoordinates = []
|
Mouse.synapseStartCoordinates = []
|
||||||
|
Mouse.synapseEndCoordinates = null
|
||||||
if (Visualize.mGraph) Visualize.mGraph.plot()
|
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() {
|
getMap: function(callback) {
|
||||||
return Map.get(this.get('map_id'))
|
Map.get(this.get('map_id'), callback)
|
||||||
},
|
},
|
||||||
getTopic: function() {
|
getMappable: function(callback) {
|
||||||
if (this.get('mappable_type') !== 'Topic') return false
|
if (this.get('mappable_type') === 'Topic') {
|
||||||
return Topic.get(this.get('mappable_id'))
|
Topic.get(this.get('mappable_id'), callback)
|
||||||
},
|
}
|
||||||
getSynapse: function() {
|
else if (this.get('mappable_type') === 'Synapse') {
|
||||||
if (this.get('mappable_type') !== 'Synapse') return false
|
Synapse.get(this.get('mappable_id'), callback)
|
||||||
return Synapse.get(this.get('mappable_id'))
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -88,8 +88,8 @@ const Synapse = Backbone.Model.extend({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Active.Map) {
|
if (Active.Map && providedMapping) {
|
||||||
mapping = providedMapping || this.getMapping()
|
mapping = providedMapping
|
||||||
mappingID = mapping.isNew() ? mapping.cid : mapping.id
|
mappingID = mapping.isNew() ? mapping.cid : mapping.id
|
||||||
edge.data.$mappings = []
|
edge.data.$mappings = []
|
||||||
edge.data.$mappingIDs = [mappingID]
|
edge.data.$mappingIDs = [mappingID]
|
||||||
|
@ -100,10 +100,12 @@ const Synapse = Backbone.Model.extend({
|
||||||
updateEdge: function() {
|
updateEdge: function() {
|
||||||
var mapping
|
var mapping
|
||||||
var edge = this.get('edge')
|
var edge = this.get('edge')
|
||||||
|
edge.data.$synapses = edge.data.$synapses || []
|
||||||
edge.getData('synapses').push(this)
|
edge.getData('synapses').push(this)
|
||||||
|
|
||||||
if (Active.Map) {
|
if (Active.Map) {
|
||||||
mapping = this.getMapping()
|
mapping = this.getMapping()
|
||||||
|
edge.data.$mappings = edge.data.$mappings || []
|
||||||
edge.getData('mappings').push(mapping)
|
edge.getData('mappings').push(mapping)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import Backbone from 'backbone'
|
||||||
try { Backbone.$ = window.$ } catch (err) {}
|
try { Backbone.$ = window.$ } catch (err) {}
|
||||||
|
|
||||||
import Active from '../Active'
|
import Active from '../Active'
|
||||||
|
import Engine from '../Engine'
|
||||||
import Filter from '../Filter'
|
import Filter from '../Filter'
|
||||||
import JIT from '../JIT'
|
import JIT from '../JIT'
|
||||||
import Realtime from '../Realtime'
|
import Realtime from '../Realtime'
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Active from '../Active'
|
import Active from '../Active'
|
||||||
|
import Engine from '../Engine'
|
||||||
import Filter from '../Filter'
|
import Filter from '../Filter'
|
||||||
import { InfoBox } from '../Map'
|
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 Control from './Control'
|
||||||
import Create from './Create'
|
import Create from './Create'
|
||||||
import DataModel from './DataModel'
|
import DataModel from './DataModel'
|
||||||
|
import Engine from './Engine'
|
||||||
import Filter from './Filter'
|
import Filter from './Filter'
|
||||||
import GlobalUI from './GlobalUI'
|
import GlobalUI from './GlobalUI'
|
||||||
import Map from './Map'
|
import Map from './Map'
|
||||||
|
@ -392,7 +393,6 @@ const JIT = {
|
||||||
Visualize.mGraph.busy = false
|
Visualize.mGraph.busy = false
|
||||||
Mouse.boxEndCoordinates = eventInfo.getPos()
|
Mouse.boxEndCoordinates = eventInfo.getPos()
|
||||||
JIT.selectWithBox(e)
|
JIT.selectWithBox(e)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,6 +404,7 @@ const JIT = {
|
||||||
JIT.selectEdgeOnClickHandler(node, e)
|
JIT.selectEdgeOnClickHandler(node, e)
|
||||||
} else if (node && !node.nodeFrom) {
|
} else if (node && !node.nodeFrom) {
|
||||||
JIT.selectNodeOnClickHandler(node, e)
|
JIT.selectNodeOnClickHandler(node, e)
|
||||||
|
Engine.setFocusNode(node)
|
||||||
} else {
|
} else {
|
||||||
JIT.canvasClickHandler(eventInfo.getPos(), e)
|
JIT.canvasClickHandler(eventInfo.getPos(), e)
|
||||||
} // if
|
} // if
|
||||||
|
@ -415,7 +416,6 @@ const JIT = {
|
||||||
|
|
||||||
if (Mouse.boxStartCoordinates) {
|
if (Mouse.boxStartCoordinates) {
|
||||||
Create.newSynapse.hide()
|
Create.newSynapse.hide()
|
||||||
Create.newTopic.hide()
|
|
||||||
Visualize.mGraph.busy = false
|
Visualize.mGraph.busy = false
|
||||||
Mouse.boxEndCoordinates = eventInfo.getPos()
|
Mouse.boxEndCoordinates = eventInfo.getPos()
|
||||||
JIT.selectWithBox(e)
|
JIT.selectWithBox(e)
|
||||||
|
@ -432,7 +432,6 @@ const JIT = {
|
||||||
} else {
|
} else {
|
||||||
// right click open space
|
// right click open space
|
||||||
Create.newSynapse.hide()
|
Create.newSynapse.hide()
|
||||||
Create.newTopic.hide()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -721,11 +720,11 @@ const JIT = {
|
||||||
$('canvas').css('cursor', 'default')
|
$('canvas').css('cursor', 'default')
|
||||||
}
|
}
|
||||||
}, // onMouseMoveHandler
|
}, // onMouseMoveHandler
|
||||||
enterKeyHandler: function() {
|
enterKeyHandler: function(e) {
|
||||||
const creatingMap = GlobalUI.lightbox
|
const creatingMap = GlobalUI.lightbox
|
||||||
if (creatingMap === 'newmap' || creatingMap === 'forkmap') {
|
if (creatingMap === 'newmap' || creatingMap === 'forkmap') {
|
||||||
GlobalUI.CreateMap.submit()
|
GlobalUI.CreateMap.submit()
|
||||||
} else if (Create.newTopic.beingCreated) {
|
} else if (e.target.id === 'topic_name' && !Create.newTopic.metacodeSelectorOpen) {
|
||||||
Topic.createTopicLocally()
|
Topic.createTopicLocally()
|
||||||
} else if (Create.newSynapse.beingCreated) {
|
} else if (Create.newSynapse.beingCreated) {
|
||||||
Synapse.createSynapseLocally()
|
Synapse.createSynapseLocally()
|
||||||
|
@ -850,24 +849,7 @@ const JIT = {
|
||||||
JIT.tempNode = node
|
JIT.tempNode = node
|
||||||
JIT.tempInit = true
|
JIT.tempInit = true
|
||||||
|
|
||||||
Create.newTopic.hide()
|
|
||||||
Create.newSynapse.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 = {
|
Mouse.synapseEndCoordinates = {
|
||||||
x: pos.x,
|
x: pos.x,
|
||||||
y: pos.y
|
y: pos.y
|
||||||
|
@ -894,15 +876,7 @@ const JIT = {
|
||||||
Visualize.mGraph.graph.eachNode(function(n) {
|
Visualize.mGraph.graph.eachNode(function(n) {
|
||||||
n.setData('dim', 25, 'current')
|
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()
|
Visualize.mGraph.plot()
|
||||||
|
|
||||||
Mouse.synapseEndCoordinates = {
|
Mouse.synapseEndCoordinates = {
|
||||||
x: pos.x,
|
x: pos.x,
|
||||||
y: pos.y
|
y: pos.y
|
||||||
|
@ -945,14 +919,13 @@ const JIT = {
|
||||||
self.dragTolerance = 0
|
self.dragTolerance = 0
|
||||||
|
|
||||||
if (JIT.tempInit && JIT.tempNode2 === null) {
|
if (JIT.tempInit && JIT.tempNode2 === null) {
|
||||||
// this means you want to add a new topic, and then a synapse
|
Mouse.synapseEndCoordinates = null
|
||||||
Create.newTopic.addSynapse = true
|
|
||||||
Create.newTopic.open()
|
|
||||||
} else if (JIT.tempInit && JIT.tempNode2 !== null) {
|
} else if (JIT.tempInit && JIT.tempNode2 !== null) {
|
||||||
// this means you want to create a synapse between two existing topics
|
// 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.topic1id = JIT.tempNode.getData('topic').id
|
||||||
Create.newSynapse.topic2id = JIT.tempNode2.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')
|
JIT.tempNode2.setData('dim', 25, 'current')
|
||||||
Visualize.mGraph.plot()
|
Visualize.mGraph.plot()
|
||||||
midpoint.x = JIT.tempNode.pos.getc().x + (JIT.tempNode2.pos.getc().x - JIT.tempNode.pos.getc().x) / 2
|
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)
|
const authorized = Active.Map && Active.Map.authorizeToEdit(Active.Mapper)
|
||||||
|
|
||||||
if (now - storedTime < Mouse.DOUBLE_CLICK_TOLERANCE && !Mouse.didPan) {
|
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
|
// 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) {
|
} else if (!Mouse.didPan) {
|
||||||
// SINGLE CLICK, no pan
|
// SINGLE CLICK, no pan
|
||||||
Filter.close()
|
Filter.close()
|
||||||
TopicCard.hideCard()
|
TopicCard.hideCard()
|
||||||
SynapseCard.hideCard()
|
SynapseCard.hideCard()
|
||||||
Create.newTopic.hide()
|
|
||||||
$('.rightclickmenu').remove()
|
$('.rightclickmenu').remove()
|
||||||
// reset the draw synapse positions to false
|
// reset the draw synapse positions to false
|
||||||
Mouse.synapseStartCoordinates = []
|
Mouse.synapseStartCoordinates = []
|
||||||
|
@ -1038,7 +996,6 @@ const JIT = {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// SINGLE CLICK, resulting from pan
|
// SINGLE CLICK, resulting from pan
|
||||||
Create.newTopic.hide()
|
|
||||||
}
|
}
|
||||||
}, // canvasClickHandler
|
}, // canvasClickHandler
|
||||||
updateTopicPositions: function(node, pos) {
|
updateTopicPositions: function(node, pos) {
|
||||||
|
@ -1067,6 +1024,7 @@ const JIT = {
|
||||||
n.pos.setp(theta, rho)
|
n.pos.setp(theta, rho)
|
||||||
} else {
|
} else {
|
||||||
n.pos.setc(x, y)
|
n.pos.setc(x, y)
|
||||||
|
Engine.setNodePos(n.getData('body_id'), x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Active.Map) {
|
if (Active.Map) {
|
||||||
|
@ -1272,26 +1230,6 @@ const JIT = {
|
||||||
Mouse.boxEndCoordinates = false
|
Mouse.boxEndCoordinates = false
|
||||||
Visualize.mGraph.plot()
|
Visualize.mGraph.plot()
|
||||||
}, // selectWithBox
|
}, // 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) {
|
selectNodeOnClickHandler: function(node, e) {
|
||||||
if (Visualize.mGraph.busy) return
|
if (Visualize.mGraph.busy) return
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ const Listeners = {
|
||||||
case 13: // if enter key is pressed
|
case 13: // if enter key is pressed
|
||||||
// prevent topic creation if sending a message
|
// prevent topic creation if sending a message
|
||||||
if (e.target.className !== 'chat-input') {
|
if (e.target.className !== 'chat-input') {
|
||||||
JIT.enterKeyHandler()
|
JIT.enterKeyHandler(e)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 27: // if esc key is pressed
|
case 27: // if esc key is pressed
|
||||||
|
|
|
@ -8,6 +8,7 @@ import AutoLayout from '../AutoLayout'
|
||||||
import Create from '../Create'
|
import Create from '../Create'
|
||||||
import DataModel from '../DataModel'
|
import DataModel from '../DataModel'
|
||||||
import DataModelMap from '../DataModel/Map'
|
import DataModelMap from '../DataModel/Map'
|
||||||
|
import Engine from '../Engine'
|
||||||
import Filter from '../Filter'
|
import Filter from '../Filter'
|
||||||
import GlobalUI from '../GlobalUI'
|
import GlobalUI from '../GlobalUI'
|
||||||
import JIT from '../JIT'
|
import JIT from '../JIT'
|
||||||
|
@ -143,11 +144,12 @@ const Map = {
|
||||||
$('.rightclickmenu').remove()
|
$('.rightclickmenu').remove()
|
||||||
TopicCard.hideCard()
|
TopicCard.hideCard()
|
||||||
SynapseCard.hideCard()
|
SynapseCard.hideCard()
|
||||||
Create.newTopic.hide(true) // true means force (and override pinned)
|
$('#new_topic').hide()
|
||||||
Create.newSynapse.hide()
|
Create.newSynapse.hide()
|
||||||
Filter.close()
|
Filter.close()
|
||||||
InfoBox.close()
|
InfoBox.close()
|
||||||
Realtime.endActiveMap()
|
Realtime.endActiveMap()
|
||||||
|
Engine.endActiveMap()
|
||||||
$('.viewOnly').removeClass('isViewOnly')
|
$('.viewOnly').removeClass('isViewOnly')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,6 +6,8 @@ const Mouse = {
|
||||||
edgeHoveringOver: false,
|
edgeHoveringOver: false,
|
||||||
boxStartCoordinates: false,
|
boxStartCoordinates: false,
|
||||||
boxEndCoordinates: false,
|
boxEndCoordinates: false,
|
||||||
|
focusNodeCoords: null,
|
||||||
|
newNodeCoords: { x: 100, y: 0 },
|
||||||
synapseStartCoordinates: [],
|
synapseStartCoordinates: [],
|
||||||
synapseEndCoordinates: null,
|
synapseEndCoordinates: null,
|
||||||
lastNodeClick: 0,
|
lastNodeClick: 0,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import Active from './Active'
|
||||||
import Control from './Control'
|
import Control from './Control'
|
||||||
import Create from './Create'
|
import Create from './Create'
|
||||||
import DataModel from './DataModel'
|
import DataModel from './DataModel'
|
||||||
|
import Engine from './Engine'
|
||||||
import JIT from './JIT'
|
import JIT from './JIT'
|
||||||
import Map from './Map'
|
import Map from './Map'
|
||||||
import Selected from './Selected'
|
import Selected from './Selected'
|
||||||
|
@ -28,46 +29,40 @@ const Synapse = {
|
||||||
} else callback(DataModel.Synapses.get(id))
|
} else callback(DataModel.Synapses.get(id))
|
||||||
},
|
},
|
||||||
|
|
||||||
renderSynapse: function(mapping, synapse, node1, node2, createNewInDB) {
|
renderSynapse: function(mapping, synapse, node1, node2, createNewInDB, alreadyAdded) {
|
||||||
var edgeOnViz
|
var edgeOnViz
|
||||||
|
var newedge
|
||||||
|
|
||||||
var newedge = synapse.createEdge(mapping)
|
if (!alreadyAdded) {
|
||||||
|
newedge = synapse.createEdge(mapping)
|
||||||
Visualize.mGraph.graph.addAdjacence(node1, node2, newedge.data)
|
Visualize.mGraph.graph.addAdjacence(node1, node2, newedge.data)
|
||||||
|
}
|
||||||
edgeOnViz = Visualize.mGraph.graph.getAdjacence(node1.id, node2.id)
|
edgeOnViz = Visualize.mGraph.graph.getAdjacence(node1.id, node2.id)
|
||||||
|
if (!alreadyAdded) {
|
||||||
|
Engine.addEdge(edgeOnViz)
|
||||||
|
}
|
||||||
synapse.set('edge', edgeOnViz)
|
synapse.set('edge', edgeOnViz)
|
||||||
synapse.updateEdge() // links the synapse and the mapping to the edge
|
synapse.updateEdge() // links the synapse and the mapping to the edge
|
||||||
|
|
||||||
Control.selectEdge(edgeOnViz)
|
//Control.selectEdge(edgeOnViz)
|
||||||
|
|
||||||
var synapseSuccessCallback = function(synapseModel, response) {
|
var synapseSuccessCallback = function(synapseModel, response) {
|
||||||
if (Active.Map) {
|
if (Active.Map) {
|
||||||
mapping.save({ mappable_id: synapseModel.id }, {
|
mapping.save({ mappable_id: synapseModel.id })
|
||||||
error: function(model, response) {
|
|
||||||
console.log('error saving mapping to database')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Settings.sandbox && createNewInDB) {
|
if (createNewInDB) {
|
||||||
if (synapse.isNew()) {
|
if (synapse.isNew()) {
|
||||||
synapse.save(null, {
|
synapse.save(null, {
|
||||||
success: synapseSuccessCallback,
|
success: synapseSuccessCallback
|
||||||
error: function(model, response) {
|
|
||||||
console.log('error saving synapse to database')
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
} else if (!synapse.isNew() && Active.Map) {
|
} else if (!synapse.isNew() && Active.Map) {
|
||||||
mapping.save(null, {
|
mapping.save(null)
|
||||||
error: function(model, response) {
|
|
||||||
console.log('error saving mapping to database')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
createSynapseLocally: function() {
|
createSynapseLocally: function(alreadyAdded, topic1id, topic2id) {
|
||||||
var self = Synapse
|
var self = Synapse
|
||||||
let topic1
|
let topic1
|
||||||
let topic2
|
let topic2
|
||||||
|
@ -75,43 +70,41 @@ const Synapse = {
|
||||||
let node2
|
let node2
|
||||||
let synapse
|
let synapse
|
||||||
let mapping
|
let mapping
|
||||||
|
|
||||||
$(document).trigger(Map.events.editedByActiveMapper)
|
$(document).trigger(Map.events.editedByActiveMapper)
|
||||||
|
|
||||||
// for each node in this array we will create a synapse going to the position2 node.
|
// for each node in this array we will create a synapse going to the position2 node.
|
||||||
var synapsesToCreate = []
|
var synapsesToCreate = []
|
||||||
|
if (alreadyAdded) {
|
||||||
topic2 = DataModel.Topics.get(Create.newSynapse.topic2id)
|
topic2 = DataModel.Topics.get(topic2id)
|
||||||
node2 = topic2.get('node')
|
node2 = topic2.get('node')
|
||||||
|
topic1 = DataModel.Topics.get(topic1id)
|
||||||
var len = Selected.Nodes.length
|
|
||||||
if (len === 0) {
|
|
||||||
topic1 = DataModel.Topics.get(Create.newSynapse.topic1id)
|
|
||||||
synapsesToCreate[0] = topic1.get('node')
|
synapsesToCreate[0] = topic1.get('node')
|
||||||
} else if (len > 0) {
|
|
||||||
synapsesToCreate = Selected.Nodes
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
for (var i = 0; i < synapsesToCreate.length; i++) {
|
topic2 = DataModel.Topics.get(Create.newSynapse.topic2id)
|
||||||
node1 = synapsesToCreate[i]
|
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')
|
topic1 = node1.getData('topic')
|
||||||
synapse = new DataModel.Synapse({
|
synapse = new DataModel.Synapse({
|
||||||
desc: Create.newSynapse.description,
|
desc: Create.newSynapse.description || '',
|
||||||
topic1_id: topic1.isNew() ? topic1.cid : topic1.id,
|
topic1_id: topic1.isNew() ? topic1.cid : topic1.id,
|
||||||
topic2_id: topic2.isNew() ? topic2.cid : topic2.id
|
topic2_id: topic2.isNew() ? topic2.cid : topic2.id
|
||||||
})
|
})
|
||||||
DataModel.Synapses.add(synapse)
|
DataModel.Synapses.add(synapse)
|
||||||
|
|
||||||
mapping = new DataModel.Mapping({
|
mapping = new DataModel.Mapping({
|
||||||
mappable_type: 'Synapse',
|
mappable_type: 'Synapse',
|
||||||
mappable_id: synapse.cid
|
mappable_id: synapse.cid
|
||||||
})
|
})
|
||||||
DataModel.Mappings.add(mapping)
|
DataModel.Mappings.add(mapping)
|
||||||
|
|
||||||
// this function also includes the creation of the synapse in the database
|
// this function also includes the creation of the synapse in the database
|
||||||
self.renderSynapse(mapping, synapse, node1, node2, true)
|
self.renderSynapse(mapping, synapse, node1, node2, true, alreadyAdded)
|
||||||
} // for each in synapsesToCreate
|
}) // for each in synapsesToCreate
|
||||||
|
|
||||||
Create.newSynapse.hide()
|
Create.newSynapse.hide()
|
||||||
},
|
},
|
||||||
getSynapseFromAutocomplete: function(id) {
|
getSynapseFromAutocomplete: function(id) {
|
||||||
|
|
|
@ -6,13 +6,16 @@ import Active from './Active'
|
||||||
import AutoLayout from './AutoLayout'
|
import AutoLayout from './AutoLayout'
|
||||||
import Create from './Create'
|
import Create from './Create'
|
||||||
import DataModel from './DataModel'
|
import DataModel from './DataModel'
|
||||||
|
import Engine from './Engine'
|
||||||
import Filter from './Filter'
|
import Filter from './Filter'
|
||||||
import GlobalUI from './GlobalUI'
|
import GlobalUI from './GlobalUI'
|
||||||
import JIT from './JIT'
|
import JIT from './JIT'
|
||||||
import Map from './Map'
|
import Map from './Map'
|
||||||
|
import Mouse from './Mouse'
|
||||||
import Router from './Router'
|
import Router from './Router'
|
||||||
import Selected from './Selected'
|
import Selected from './Selected'
|
||||||
import Settings from './Settings'
|
import Settings from './Settings'
|
||||||
|
import Synapse from './Synapse'
|
||||||
import SynapseCard from './SynapseCard'
|
import SynapseCard from './SynapseCard'
|
||||||
import TopicCard from './TopicCard'
|
import TopicCard from './TopicCard'
|
||||||
import Util from './Util'
|
import Util from './Util'
|
||||||
|
@ -165,69 +168,39 @@ const Topic = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// opts is additional options in a hash
|
renderTopic: function(mapping, topic, createNewInDB) {
|
||||||
// TODO: move createNewInDB and permitCreateSynapseAfter into opts
|
var nodeOnViz
|
||||||
renderTopic: function(mapping, topic, createNewInDB, permitCreateSynapseAfter, opts = {}) {
|
|
||||||
var nodeOnViz, tempPos
|
|
||||||
|
|
||||||
var newnode = topic.createNode()
|
var newnode = topic.createNode()
|
||||||
|
const createSynapse = !!Create.newSynapse.focusNode && createNewInDB
|
||||||
var midpoint = {}
|
const connectToId = createSynapse ? Create.newSynapse.focusNode.getData('topic').id : null
|
||||||
var pixelPos
|
|
||||||
|
|
||||||
if (!$.isEmptyObject(Visualize.mGraph.graph.nodes)) {
|
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)
|
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.set('node', nodeOnViz, {silent: true})
|
||||||
topic.updateNode() // links the topic and the mapping to the node
|
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', 1, 'start')
|
||||||
nodeOnViz.setData('dim', 25, 'end')
|
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')), 'current')
|
||||||
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'start')
|
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'start')
|
||||||
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'end')
|
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({
|
Visualize.mGraph.fx.animate({
|
||||||
modes: ['node-property:dim'],
|
modes: ['node-property:dim'],
|
||||||
duration: 500,
|
duration: 500
|
||||||
onComplete: function() {
|
|
||||||
JIT.tempNode = null
|
|
||||||
JIT.tempNode2 = null
|
|
||||||
JIT.tempInit = false
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
Visualize.mGraph.fx.plotNode(nodeOnViz, Visualize.mGraph.canvas)
|
|
||||||
Visualize.mGraph.fx.animate({
|
|
||||||
modes: ['node-property:dim'],
|
|
||||||
duration: 500,
|
|
||||||
onComplete: function() {}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
Engine.run()
|
||||||
Visualize.mGraph.loadJSON(newnode)
|
Visualize.mGraph.loadJSON(newnode)
|
||||||
nodeOnViz = Visualize.mGraph.graph.getNode(newnode.id)
|
nodeOnViz = Visualize.mGraph.graph.getNode(newnode.id)
|
||||||
|
Engine.addNode(nodeOnViz)
|
||||||
topic.set('node', nodeOnViz, {silent: true})
|
topic.set('node', nodeOnViz, {silent: true})
|
||||||
topic.updateNode() // links the topic and the mapping to the node
|
topic.updateNode() // links the topic and the mapping to the node
|
||||||
|
Engine.setFocusNode(nodeOnViz)
|
||||||
nodeOnViz.setData('dim', 1, 'start')
|
nodeOnViz.setData('dim', 1, 'start')
|
||||||
nodeOnViz.setData('dim', 25, 'end')
|
nodeOnViz.setData('dim', 25, 'end')
|
||||||
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'current')
|
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'current')
|
||||||
|
@ -236,46 +209,24 @@ const Topic = {
|
||||||
Visualize.mGraph.fx.plotNode(nodeOnViz, Visualize.mGraph.canvas)
|
Visualize.mGraph.fx.plotNode(nodeOnViz, Visualize.mGraph.canvas)
|
||||||
Visualize.mGraph.fx.animate({
|
Visualize.mGraph.fx.animate({
|
||||||
modes: ['node-property:dim'],
|
modes: ['node-property:dim'],
|
||||||
duration: 500,
|
duration: 500
|
||||||
onComplete: function() {}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var mappingSuccessCallback = function(mappingModel, response, topicModel) {
|
|
||||||
// call a success callback if provided
|
|
||||||
if (opts.success) {
|
|
||||||
opts.success(topicModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var topicSuccessCallback = function(topicModel, response) {
|
var topicSuccessCallback = function(topicModel, response) {
|
||||||
if (Active.Map) {
|
if (Active.Map) {
|
||||||
mapping.save({ mappable_id: topicModel.id }, {
|
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
|
|
||||||
}
|
}
|
||||||
|
createSynapse && Synapse.createSynapseLocally(true, connectToId, topicModel.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Settings.sandbox && createNewInDB) {
|
if (createNewInDB) {
|
||||||
if (topic.isNew()) {
|
if (topic.isNew()) {
|
||||||
topic.save(null, {
|
topic.save(null, {
|
||||||
success: topicSuccessCallback,
|
success: topicSuccessCallback
|
||||||
error: function(model, response) {
|
|
||||||
console.log('error saving topic to database')
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
} else if (!topic.isNew() && Active.Map) {
|
} else if (!topic.isNew() && Active.Map) {
|
||||||
mapping.save(null, {
|
mapping.save(null)
|
||||||
success: mappingSuccessCallback
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -287,9 +238,6 @@ const Topic = {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// hide the 'double-click to add a topic' message
|
|
||||||
GlobalUI.hideDiv('#instructions')
|
|
||||||
|
|
||||||
$(document).trigger(Map.events.editedByActiveMapper)
|
$(document).trigger(Map.events.editedByActiveMapper)
|
||||||
|
|
||||||
var metacode = DataModel.Metacodes.get(Create.newTopic.metacode)
|
var metacode = DataModel.Metacodes.get(Create.newTopic.metacode)
|
||||||
|
@ -301,49 +249,32 @@ const Topic = {
|
||||||
})
|
})
|
||||||
DataModel.Topics.add(topic)
|
DataModel.Topics.add(topic)
|
||||||
|
|
||||||
if (Create.newTopic.pinned) {
|
|
||||||
var nextCoords = AutoLayout.getNextCoord({ mappings: DataModel.Mappings })
|
|
||||||
}
|
|
||||||
var mapping = new DataModel.Mapping({
|
var mapping = new DataModel.Mapping({
|
||||||
xloc: nextCoords ? nextCoords.x : Create.newTopic.x,
|
xloc: Mouse.newNodeCoords.x,
|
||||||
yloc: nextCoords ? nextCoords.y : Create.newTopic.y,
|
yloc: Mouse.newNodeCoords.y,
|
||||||
mappable_id: topic.cid,
|
mappable_id: topic.cid,
|
||||||
mappable_type: 'Topic'
|
mappable_type: 'Topic'
|
||||||
})
|
})
|
||||||
DataModel.Mappings.add(mapping)
|
DataModel.Mappings.add(mapping)
|
||||||
|
|
||||||
// these can't happen until the value is retrieved, which happens in the line above
|
// 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()
|
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) {
|
getTopicFromAutocomplete: function(id) {
|
||||||
var self = Topic
|
var self = Topic
|
||||||
|
|
||||||
// hide the 'double-click to add a topic' message
|
|
||||||
GlobalUI.hideDiv('#instructions')
|
|
||||||
|
|
||||||
$(document).trigger(Map.events.editedByActiveMapper)
|
$(document).trigger(Map.events.editedByActiveMapper)
|
||||||
|
|
||||||
if (!Create.newTopic.pinned) Create.newTopic.hide()
|
|
||||||
Create.newTopic.reset()
|
Create.newTopic.reset()
|
||||||
|
|
||||||
self.get(id, (topic) => {
|
self.get(id, (topic) => {
|
||||||
if (Create.newTopic.pinned) {
|
|
||||||
var nextCoords = AutoLayout.getNextCoord({ mappings: DataModel.Mappings })
|
|
||||||
}
|
|
||||||
var mapping = new DataModel.Mapping({
|
var mapping = new DataModel.Mapping({
|
||||||
xloc: nextCoords ? nextCoords.x : Create.newTopic.x,
|
xloc: Mouse.newNodeCoords.x,
|
||||||
yloc: nextCoords ? nextCoords.y : Create.newTopic.y,
|
yloc: Mouse.newNodeCoords.y,
|
||||||
mappable_type: 'Topic',
|
mappable_type: 'Topic',
|
||||||
mappable_id: topic.id
|
mappable_id: topic.id
|
||||||
})
|
})
|
||||||
DataModel.Mappings.add(mapping)
|
DataModel.Mappings.add(mapping)
|
||||||
|
self.renderTopic(mapping, topic, true)
|
||||||
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
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getMapFromAutocomplete: function(data) {
|
getMapFromAutocomplete: function(data) {
|
||||||
|
@ -361,20 +292,17 @@ const Topic = {
|
||||||
DataModel.Topics.add(topic)
|
DataModel.Topics.add(topic)
|
||||||
|
|
||||||
var mapping = new DataModel.Mapping({
|
var mapping = new DataModel.Mapping({
|
||||||
xloc: Create.newTopic.x,
|
xloc: Mouse.newNodeCoords.x,
|
||||||
yloc: Create.newTopic.y,
|
yloc: Mouse.newNodeCoords.y,
|
||||||
mappable_id: topic.cid,
|
mappable_id: topic.cid,
|
||||||
mappable_type: 'Topic'
|
mappable_type: 'Topic'
|
||||||
})
|
})
|
||||||
DataModel.Mappings.add(mapping)
|
DataModel.Mappings.add(mapping)
|
||||||
|
|
||||||
// these can't happen until the value is retrieved, which happens in the line above
|
// 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()
|
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
|
||||||
// this blocked the enterKeyHandler from creating a new topic as well
|
|
||||||
if (Create.newTopic.pinned) Create.newTopic.beingCreated = true
|
|
||||||
},
|
},
|
||||||
getTopicFromSearch: function(event, id) {
|
getTopicFromSearch: function(event, id) {
|
||||||
var self = Topic
|
var self = Topic
|
||||||
|
@ -390,8 +318,8 @@ const Topic = {
|
||||||
mappable_id: topic.id
|
mappable_id: topic.id
|
||||||
})
|
})
|
||||||
DataModel.Mappings.add(mapping)
|
DataModel.Mappings.add(mapping)
|
||||||
self.renderTopic(mapping, topic, true, true)
|
self.renderTopic(mapping, topic, true)
|
||||||
GlobalUI.notifyUser('Topic was added to your map!')
|
GlobalUI.notifyUser('Topic was added to your map')
|
||||||
})
|
})
|
||||||
|
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
/* global $ */
|
/* global $ */
|
||||||
|
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
import Matter from 'matter-js'
|
||||||
|
|
||||||
import $jit from '../patched/JIT'
|
import $jit from '../patched/JIT'
|
||||||
|
|
||||||
import Active from './Active'
|
import Active from './Active'
|
||||||
import DataModel from './DataModel'
|
import DataModel from './DataModel'
|
||||||
|
import Engine from './Engine'
|
||||||
import JIT from './JIT'
|
import JIT from './JIT'
|
||||||
import Loading from './Loading'
|
import Loading from './Loading'
|
||||||
import Router from './Router'
|
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'))
|
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.setPos(endPos, 'end')
|
||||||
|
n.setData('dim', 1, 'start')
|
||||||
|
n.setData('dim', 25, 'end')
|
||||||
})
|
})
|
||||||
} else if (self.type === 'ForceDirected3D') {
|
} else if (self.type === 'ForceDirected3D') {
|
||||||
self.mGraph.compute()
|
self.mGraph.compute()
|
||||||
|
@ -153,6 +159,8 @@ const Visualize = {
|
||||||
|
|
||||||
function runAnimation() {
|
function runAnimation() {
|
||||||
Loading.hide()
|
Loading.hide()
|
||||||
|
$('#new_topic').show()
|
||||||
|
$('#topic_name').focus()
|
||||||
// load JSON data, if it's not empty
|
// load JSON data, if it's not empty
|
||||||
if (!self.loadLater) {
|
if (!self.loadLater) {
|
||||||
// load JSON data.
|
// load JSON data.
|
||||||
|
@ -170,7 +178,8 @@ const Visualize = {
|
||||||
if (self.type === 'RGraph') {
|
if (self.type === 'RGraph') {
|
||||||
self.mGraph.fx.animate(JIT.RGraph.animate)
|
self.mGraph.fx.animate(JIT.RGraph.animate)
|
||||||
} else if (self.type === 'ForceDirected') {
|
} else if (self.type === 'ForceDirected') {
|
||||||
self.mGraph.animate(JIT.ForceDirected.animateSavedLayout)
|
self.mGraph.plot()
|
||||||
|
Engine.run(true)
|
||||||
} else if (self.type === 'ForceDirected3D') {
|
} else if (self.type === 'ForceDirected3D') {
|
||||||
self.mGraph.animate(JIT.ForceDirected.animateFDLayout)
|
self.mGraph.animate(JIT.ForceDirected.animateFDLayout)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import Control from './Control'
|
||||||
import Create from './Create'
|
import Create from './Create'
|
||||||
import DataModel from './DataModel'
|
import DataModel from './DataModel'
|
||||||
import Debug from './Debug'
|
import Debug from './Debug'
|
||||||
|
import Engine from './Engine'
|
||||||
import Filter from './Filter'
|
import Filter from './Filter'
|
||||||
import GlobalUI, {
|
import GlobalUI, {
|
||||||
Search, CreateMap, ImportDialog, Account as GlobalUIAccount,
|
Search, CreateMap, ImportDialog, Account as GlobalUIAccount,
|
||||||
|
@ -44,6 +45,7 @@ Metamaps.Control = Control
|
||||||
Metamaps.Create = Create
|
Metamaps.Create = Create
|
||||||
Metamaps.DataModel = DataModel
|
Metamaps.DataModel = DataModel
|
||||||
Metamaps.Debug = Debug
|
Metamaps.Debug = Debug
|
||||||
|
Metamaps.Engine = Engine
|
||||||
Metamaps.Filter = Filter
|
Metamaps.Filter = Filter
|
||||||
Metamaps.GlobalUI = GlobalUI
|
Metamaps.GlobalUI = GlobalUI
|
||||||
Metamaps.GlobalUI.Search = Search
|
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)) {
|
if (Metamaps.Mouse.boxStartCoordinates && ((e.button == 0 && e.shiftKey) || (e.button == 0 && e.ctrlKey) || rightClick)) {
|
||||||
Metamaps.Visualize.mGraph.busy = true;
|
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');
|
//console.log('mouse move');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2606,9 +2609,7 @@ Extras.Classes.Navigation = new Class({
|
||||||
this.pressed = false;
|
this.pressed = false;
|
||||||
|
|
||||||
// START METAMAPS CODE
|
// START METAMAPS CODE
|
||||||
if (Metamaps.Mouse.didPan) Metamaps.JIT.SmoothPanning();
|
if (Metamaps.Mouse.didPan) Metamaps.JIT.SmoothPanning();
|
||||||
|
|
||||||
|
|
||||||
// END METAMAPS CODE
|
// 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)) {
|
if (Metamaps.Mouse.boxStartCoordinates && ((e.button == 0 && e.shiftKey) || (e.button == 0 && e.ctrlKey) || rightClick)) {
|
||||||
Metamaps.Visualize.mGraph.busy = true;
|
Metamaps.Visualize.mGraph.busy = true;
|
||||||
Metamaps.JIT.drawSelectBox(eventInfo,e);
|
Metamaps.Mouse.boxEndCoordinates = {
|
||||||
|
x: eventInfo.getPos().x,
|
||||||
|
y: eventInfo.getPos().y
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (rightClick){
|
if (rightClick){
|
||||||
|
@ -7225,7 +7229,7 @@ Graph.Plot = {
|
||||||
var T = !!root.visited;
|
var T = !!root.visited;
|
||||||
|
|
||||||
//START METAMAPS CODE
|
//START METAMAPS CODE
|
||||||
if (Metamaps.Mouse.synapseStartCoordinates.length > 0) {
|
if (Metamaps.Mouse.synapseStartCoordinates.length > 0 && Metamaps.Mouse.synapseEndCoordinates) {
|
||||||
ctx.save();
|
ctx.save();
|
||||||
var start;
|
var start;
|
||||||
var end = Metamaps.Mouse.synapseEndCoordinates;
|
var end = Metamaps.Mouse.synapseEndCoordinates;
|
||||||
|
@ -7238,6 +7242,26 @@ Graph.Plot = {
|
||||||
}
|
}
|
||||||
ctx.restore();
|
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
|
//END METAMAPS CODE
|
||||||
|
|
||||||
aGraph.eachNode(function(node) {
|
aGraph.eachNode(function(node) {
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
"howler": "2.0.2",
|
"howler": "2.0.2",
|
||||||
"json-loader": "0.5.4",
|
"json-loader": "0.5.4",
|
||||||
"lodash": "4.17.2",
|
"lodash": "4.17.2",
|
||||||
|
"matter-js": "0.11.1",
|
||||||
"node-uuid": "1.4.7",
|
"node-uuid": "1.4.7",
|
||||||
"outdent": "0.3.0",
|
"outdent": "0.3.0",
|
||||||
"react": "15.4.1",
|
"react": "15.4.1",
|
||||||
|
|
Loading…
Add table
Reference in a new issue