Merge branch 'develop' of github.com:Connoropolous/metamaps_gen002
14
Gemfile
|
@ -1,12 +1,16 @@
|
|||
source 'https://rubygems.org'
|
||||
#ruby '1.9.3'
|
||||
|
||||
gem 'rails', '3.2.17'
|
||||
|
||||
# Bundle edge Rails instead:
|
||||
# gem 'rails', :git => 'git://github.com/rails/rails.git'
|
||||
|
||||
#gem 'watir'
|
||||
#gem 'phantomjs'
|
||||
|
||||
gem 'devise'
|
||||
gem 'redis'
|
||||
gem 'redis', '2.2.2'
|
||||
gem 'pg'
|
||||
gem 'cancan'
|
||||
gem 'formula'
|
||||
|
@ -14,6 +18,10 @@ gem 'formtastic'
|
|||
gem 'json'
|
||||
gem 'rails3-jquery-autocomplete'
|
||||
gem 'best_in_place'
|
||||
|
||||
gem 'paperclip'
|
||||
gem 'aws-sdk'
|
||||
|
||||
#gem 'therubyracer' #optional
|
||||
#gem 'rb-readline'
|
||||
|
||||
|
@ -29,6 +37,10 @@ group :assets do
|
|||
gem 'uglifier', '>= 1.0.3'
|
||||
end
|
||||
|
||||
group :production do #this is used on heroku
|
||||
#gem 'rmagick'
|
||||
end
|
||||
|
||||
gem 'jquery-rails', '2.1.2'
|
||||
|
||||
# To use ActiveModel has_secure_password
|
||||
|
|
72
Gemfile.lock
|
@ -29,6 +29,9 @@ GEM
|
|||
i18n (~> 0.6, >= 0.6.4)
|
||||
multi_json (~> 1.0)
|
||||
arel (3.0.3)
|
||||
aws-sdk (1.44.0)
|
||||
json (~> 1.4)
|
||||
nokogiri (>= 1.4.4)
|
||||
bcrypt (3.1.7)
|
||||
bcrypt (3.1.7-x86-mingw32)
|
||||
best_in_place (2.1.0)
|
||||
|
@ -36,6 +39,12 @@ GEM
|
|||
rails (~> 3.1)
|
||||
builder (3.0.4)
|
||||
cancan (1.6.10)
|
||||
childprocess (0.5.3)
|
||||
ffi (~> 1.0, >= 1.0.11)
|
||||
climate_control (0.0.3)
|
||||
activesupport (>= 3.0)
|
||||
cocaine (0.5.4)
|
||||
climate_control (>= 0.0.3, < 1.0)
|
||||
coffee-rails (3.2.2)
|
||||
coffee-script (>= 2.2.0)
|
||||
railties (~> 3.2.0)
|
||||
|
@ -43,6 +52,7 @@ GEM
|
|||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.7.0)
|
||||
commonwatir (4.0.0)
|
||||
devise (3.2.4)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
|
@ -51,6 +61,8 @@ GEM
|
|||
warden (~> 1.2.3)
|
||||
erubis (2.7.0)
|
||||
execjs (2.0.2)
|
||||
ffi (1.9.0)
|
||||
ffi (1.9.0-x86-mingw32)
|
||||
formtastic (2.2.1)
|
||||
actionpack (>= 3.0)
|
||||
formula (1.0.1)
|
||||
|
@ -68,10 +80,23 @@ GEM
|
|||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
mime-types (1.25.1)
|
||||
mini_magick (3.5.0)
|
||||
subexec (~> 0.2.1)
|
||||
mini_portile (0.6.0)
|
||||
multi_json (1.10.0)
|
||||
nokogiri (1.6.2.1)
|
||||
mini_portile (= 0.6.0)
|
||||
nokogiri (1.6.2.1-x86-mingw32)
|
||||
mini_portile (= 0.6.0)
|
||||
orm_adapter (0.5.0)
|
||||
paperclip (4.1.1)
|
||||
activemodel (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
cocaine (~> 0.5.3)
|
||||
mime-types
|
||||
pg (0.17.1)
|
||||
pg (0.17.1-x86-mingw32)
|
||||
phantomjs (1.9.7.1)
|
||||
polyglot (0.3.4)
|
||||
rack (1.4.5)
|
||||
rack-cache (1.2)
|
||||
|
@ -98,19 +123,28 @@ GEM
|
|||
rdoc (~> 3.4)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
rake (10.3.2)
|
||||
rautomation (0.15.0)
|
||||
ffi (= 1.9.0)
|
||||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
redis (3.0.7)
|
||||
redis (2.2.2)
|
||||
rubyzip (1.1.6)
|
||||
sass (3.3.7)
|
||||
sass-rails (3.2.6)
|
||||
railties (~> 3.2.0)
|
||||
sass (>= 3.1.10)
|
||||
tilt (~> 1.3)
|
||||
selenium-webdriver (2.42.0)
|
||||
childprocess (>= 0.5.0)
|
||||
multi_json (~> 1.0)
|
||||
rubyzip (~> 1.0)
|
||||
websocket (~> 1.0.4)
|
||||
sprockets (2.2.2)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
subexec (0.2.3)
|
||||
thor (0.19.1)
|
||||
thread_safe (0.3.3)
|
||||
tilt (1.4.1)
|
||||
|
@ -123,12 +157,43 @@ GEM
|
|||
json (>= 1.8.0)
|
||||
warden (1.2.3)
|
||||
rack (>= 1.0)
|
||||
watir (5.0.0)
|
||||
commonwatir (~> 4)
|
||||
watir-webdriver
|
||||
watir (5.0.0-x86-mingw32)
|
||||
commonwatir (~> 4)
|
||||
watir-classic (~> 4.0)
|
||||
watir-webdriver
|
||||
watir-classic (4.0.1)
|
||||
ffi (~> 1.0)
|
||||
multi_json
|
||||
nokogiri (>= 1.5.7.rc3)
|
||||
rautomation (~> 0.7)
|
||||
win32-process (>= 0.5.5)
|
||||
win32screenshot (~> 1.0.9)
|
||||
windows-pr (>= 0.6.6)
|
||||
watir-webdriver (0.6.10)
|
||||
selenium-webdriver (>= 2.18.0)
|
||||
websocket (1.0.7)
|
||||
win32-api (1.5.1-x86-mingw32)
|
||||
win32-process (0.7.4)
|
||||
ffi (>= 1.0.0)
|
||||
win32screenshot (1.0.10)
|
||||
ffi (~> 1.0)
|
||||
mini_magick (~> 3.5.0)
|
||||
rautomation (~> 0.7)
|
||||
windows-api (0.4.2)
|
||||
win32-api (>= 1.4.5)
|
||||
windows-pr (1.2.3)
|
||||
win32-api (>= 1.4.5)
|
||||
windows-api (>= 0.4.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
x86-mingw32
|
||||
|
||||
DEPENDENCIES
|
||||
aws-sdk
|
||||
best_in_place
|
||||
cancan
|
||||
coffee-rails (~> 3.2.1)
|
||||
|
@ -138,9 +203,12 @@ DEPENDENCIES
|
|||
jbuilder (= 0.8.2)
|
||||
jquery-rails (= 2.1.2)
|
||||
json
|
||||
paperclip
|
||||
pg
|
||||
phantomjs
|
||||
rails (= 3.2.17)
|
||||
rails3-jquery-autocomplete
|
||||
redis
|
||||
redis (= 2.2.2)
|
||||
sass-rails
|
||||
uglifier (>= 1.0.3)
|
||||
watir
|
||||
|
|
47
Gemfile~
|
@ -1,47 +0,0 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gem 'rails', '3.2.17'
|
||||
|
||||
# Bundle edge Rails instead:
|
||||
# gem 'rails', :git => 'git://github.com/rails/rails.git'
|
||||
|
||||
gem 'devise'
|
||||
gem 'redis'
|
||||
gem 'pg'
|
||||
gem 'cancan'
|
||||
gem 'formula'
|
||||
gem 'formtastic'
|
||||
gem 'json'
|
||||
gem 'rails3-jquery-autocomplete'
|
||||
gem 'best_in_place'
|
||||
gem 'therubyracer' #optional
|
||||
#gem 'rb-readline'
|
||||
|
||||
# Gems used only for assets and not required
|
||||
# in production environments by default.
|
||||
group :assets do
|
||||
gem 'sass-rails'
|
||||
gem 'coffee-rails', '~> 3.2.1'
|
||||
|
||||
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
|
||||
# gem 'therubyracer'
|
||||
|
||||
gem 'uglifier', '>= 1.0.3'
|
||||
end
|
||||
|
||||
gem 'jquery-rails', '2.1.2'
|
||||
|
||||
# To use ActiveModel has_secure_password
|
||||
# gem 'bcrypt-ruby', '~> 3.0.0'
|
||||
|
||||
# To use Jbuilder templates for JSON
|
||||
gem 'jbuilder', '0.8.2'
|
||||
|
||||
# Use unicorn as the web server
|
||||
# gem 'unicorn'
|
||||
|
||||
# Deploy with Capistrano
|
||||
# gem 'capistrano'
|
||||
|
||||
# To use debugger
|
||||
# gem 'ruby-debug19', :require => 'ruby-debug'
|
2
Rakefile
|
@ -4,4 +4,4 @@
|
|||
|
||||
require File.expand_path('../config/application', __FILE__)
|
||||
|
||||
ISSAD::Application.load_tasks
|
||||
Metamaps::Application.load_tasks
|
||||
|
|
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 445 B |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 588 B |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 370 KiB |
BIN
app/assets/images/filter.png
Normal file
After Width: | Height: | Size: 372 B |
BIN
app/assets/images/fork.png
Executable file
After Width: | Height: | Size: 461 B |
BIN
app/assets/images/junto.png
Executable file
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 15 KiB |
BIN
app/assets/images/new.png
Normal file
After Width: | Height: | Size: 544 B |
BIN
app/assets/images/shattered_@2X.png
Normal file
After Width: | Height: | Size: 186 KiB |
BIN
app/assets/images/synapsevisualize.png
Normal file
After Width: | Height: | Size: 909 B |
Before Width: | Height: | Size: 180 B After Width: | Height: | Size: 180 B |
Before Width: | Height: | Size: 178 B After Width: | Height: | Size: 178 B |
Before Width: | Height: | Size: 120 B After Width: | Height: | Size: 120 B |
Before Width: | Height: | Size: 105 B After Width: | Height: | Size: 105 B |
Before Width: | Height: | Size: 111 B After Width: | Height: | Size: 111 B |
Before Width: | Height: | Size: 110 B After Width: | Height: | Size: 110 B |
Before Width: | Height: | Size: 119 B After Width: | Height: | Size: 119 B |
Before Width: | Height: | Size: 101 B After Width: | Height: | Size: 101 B |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
@ -1,183 +0,0 @@
|
|||
// create filters for maps
|
||||
|
||||
function switchVisible(category, duration) {
|
||||
if (categoryVisible[category] == true) {
|
||||
hideCategory(category, duration);
|
||||
}
|
||||
else if (categoryVisible[category] == false) {
|
||||
showCategory(category, duration);
|
||||
}
|
||||
}
|
||||
|
||||
function hideCategory(category, duration) {
|
||||
if (duration == null) duration = 500;
|
||||
Mconsole.graph.eachNode( function (n) {
|
||||
if (n.getData('metacode') == category) {
|
||||
n.setData('alpha', 0.4, 'end');
|
||||
n.eachAdjacency(function(adj) {
|
||||
adj.setData('alpha', 0.4, 'end');
|
||||
});
|
||||
}
|
||||
});
|
||||
Mconsole.fx.animate({
|
||||
modes: ['node-property:alpha',
|
||||
'edge-property:alpha'],
|
||||
duration: duration
|
||||
});
|
||||
}
|
||||
|
||||
function showCategory(category, duration) {
|
||||
if (duration == null) duration = 500;
|
||||
Mconsole.graph.eachNode( function (n) {
|
||||
if (n.getData('metacode') == category) {
|
||||
n.setData('alpha', 1, 'end');
|
||||
n.eachAdjacency(function(adj) {
|
||||
adj.setData('alpha', 1, 'end');
|
||||
});
|
||||
}
|
||||
});
|
||||
Mconsole.fx.animate({
|
||||
modes: ['node-property:alpha',
|
||||
'edge-property:alpha'],
|
||||
duration: duration
|
||||
});
|
||||
}
|
||||
|
||||
// These functions toggle ALL nodes and synapses on the page
|
||||
function hideAll(duration) {
|
||||
if (duration == null) duration = 500;
|
||||
Mconsole.graph.eachNode( function (n) {
|
||||
n.setData('alpha', 0.4, 'end');
|
||||
n.eachAdjacency(function(adj) {
|
||||
adj.setData('alpha', 0.2, 'end');
|
||||
});
|
||||
});
|
||||
Mconsole.fx.animate({
|
||||
modes: ['node-property:alpha',
|
||||
'edge-property:alpha'],
|
||||
duration: duration
|
||||
});
|
||||
}
|
||||
function showAll(duration) {
|
||||
if (duration == null) duration = 500;
|
||||
Mconsole.graph.eachNode( function (n) {
|
||||
n.setData('alpha', 1, 'end');
|
||||
n.eachAdjacency(function(adj) {
|
||||
adj.setData('alpha', 0.4, 'end');
|
||||
});
|
||||
});
|
||||
Mconsole.fx.animate({
|
||||
modes: ['node-property:alpha',
|
||||
'edge-property:alpha'],
|
||||
duration: duration
|
||||
});
|
||||
}
|
||||
|
||||
function filterTopicsByMap(mapID) {
|
||||
Mconsole.graph.eachNode(function (n) {
|
||||
if (n.getData('inmaps').indexOf(parseInt(mapID)) !== -1) {
|
||||
n.setData('alpha', 1, 'end');
|
||||
}
|
||||
else {
|
||||
n.setData('alpha', 0.4, 'end');
|
||||
}
|
||||
Mconsole.fx.animate({
|
||||
modes: ['node-property:alpha',
|
||||
'edge-property:alpha'],
|
||||
duration: 500
|
||||
});
|
||||
});
|
||||
} // filterTopicsByName
|
||||
|
||||
function filterTopicsByMapper(mapperID) {
|
||||
Mconsole.graph.eachNode(function (n) {
|
||||
if (n.getData('userid').toString() == mapperID) {
|
||||
n.setData('alpha', 1, 'end');
|
||||
}
|
||||
else {
|
||||
n.setData('alpha', 0.4, 'end');
|
||||
}
|
||||
Mconsole.fx.animate({
|
||||
modes: ['node-property:alpha',
|
||||
'edge-property:alpha'],
|
||||
duration: 500
|
||||
});
|
||||
});
|
||||
} // filterTopicsByName
|
||||
|
||||
function filterTopicsByName(searchQuery) {
|
||||
Mconsole.graph.eachNode(function (n) {
|
||||
nodeName = n.name.toLowerCase();
|
||||
if (nodeName.indexOf(searchQuery) !== -1 && searchQuery != "") {
|
||||
n.setData('alpha', 1, 'end');
|
||||
}
|
||||
else {
|
||||
n.setData('alpha', 0.4, 'end');
|
||||
}
|
||||
Mconsole.fx.animate({
|
||||
modes: ['node-property:alpha',
|
||||
'edge-property:alpha'],
|
||||
duration: 500
|
||||
});
|
||||
});
|
||||
} // filterTopicsByName
|
||||
|
||||
function clearCanvas() {
|
||||
Mconsole.graph.eachNode(function(n) {
|
||||
Mconsole.graph.removeNode(n.id);
|
||||
});
|
||||
Mconsole.plot();
|
||||
}
|
||||
|
||||
function clearCanvasExceptRoot() {
|
||||
var ids = new Array();
|
||||
Mconsole.graph.eachNode(function(n) {
|
||||
ids.push(n.id);
|
||||
});
|
||||
|
||||
var root = Mconsole.graph.nodes[Mconsole.root];
|
||||
ids.forEach(function(id, index) {
|
||||
if (id != root.id) {
|
||||
Mconsole.graph.removeNode(id);
|
||||
}
|
||||
});
|
||||
fetchRelatives(root); //also runs Mconsole.plot()
|
||||
}
|
||||
|
||||
/**
|
||||
* Define all the dynamic interactions for the Filter By Metacode using Jquery
|
||||
*/
|
||||
|
||||
$(document).ready(function() {
|
||||
$('.sidebarFilterBox .showAll').click(function(e) {
|
||||
showAll();
|
||||
$('#filter_by_metacode ul li').removeClass('toggledOff');
|
||||
for (var catVis in categoryVisible) {
|
||||
categoryVisible[catVis] = true;
|
||||
}
|
||||
});
|
||||
$('.sidebarFilterBox .hideAll').click(function(e) {
|
||||
hideAll();
|
||||
$('#filter_by_metacode ul li').addClass('toggledOff');
|
||||
for (var catVis in categoryVisible) {
|
||||
categoryVisible[catVis] = false;
|
||||
}
|
||||
});
|
||||
|
||||
// toggle visibility of topics with metacodes based on status in the filters list
|
||||
$('#filter_by_metacode ul li').click(function(event) {
|
||||
|
||||
var category = $(this).children('img').attr('alt');
|
||||
switchVisible(category);
|
||||
|
||||
// toggle the image and the boolean array value
|
||||
if (categoryVisible[category] == true) {
|
||||
$(this).addClass('toggledOff');
|
||||
categoryVisible[category] = false;
|
||||
}
|
||||
else if (categoryVisible[category] == false) {
|
||||
$(this).removeClass('toggledOff');
|
||||
categoryVisible[category] = true;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -1,631 +0,0 @@
|
|||
function selectEdgeOnClickHandler(adj, e) {
|
||||
if (Mconsole.busy) return;
|
||||
|
||||
// catch right click on mac, which is often like ctrl+click
|
||||
if (navigator.platform.indexOf("Mac") != -1 && e.ctrlKey) {
|
||||
selectEdgeOnRightClickHandler(adj, e)
|
||||
return;
|
||||
}
|
||||
|
||||
if (synapseWasDoubleClicked()) {
|
||||
synapseDoubleClickHandler(adj, e);
|
||||
return;
|
||||
}
|
||||
|
||||
var edgeIsSelected = MetamapsModel.selectedEdges.indexOf(adj);
|
||||
if (edgeIsSelected == -1) edgeIsSelected = false;
|
||||
else if (edgeIsSelected != -1) edgeIsSelected = true;
|
||||
|
||||
if (edgeIsSelected && e.shiftKey) {
|
||||
//deselecting an edge with shift
|
||||
deselectEdge(adj);
|
||||
} else if (!edgeIsSelected && e.shiftKey) {
|
||||
//selecting an edge with shift
|
||||
selectEdge(adj);
|
||||
} else if (edgeIsSelected && !e.shiftKey) {
|
||||
//deselecting an edge without shift - unselect all
|
||||
deselectAllEdges();
|
||||
} else if (!edgeIsSelected && !e.shiftKey) {
|
||||
//selecting an edge without shift - unselect all but new one
|
||||
deselectAllEdges();
|
||||
selectEdge(adj);
|
||||
}
|
||||
|
||||
Mconsole.plot();
|
||||
} //selectEdgeOnClickHandler
|
||||
|
||||
function selectEdgeOnRightClickHandler(adj, e) {
|
||||
// the 'node' variable is a JIT node, the one that was clicked on
|
||||
// the 'e' variable is the click event
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (Mconsole.busy) return;
|
||||
|
||||
selectEdge(adj);
|
||||
|
||||
// delete old right click menu
|
||||
$('.rightclickmenu').remove();
|
||||
// create new menu for clicked on node
|
||||
var rightclickmenu = document.createElement("div");
|
||||
rightclickmenu.className = "rightclickmenu";
|
||||
|
||||
// add the proper options to the menu
|
||||
var menustring = '<ul>';
|
||||
|
||||
if (userid != null) menustring += '<li class="rc-delete">Delete</li>';
|
||||
if (mapid && userid != null) menustring += '<li class="rc-remove">Remove from map</li>';
|
||||
menustring += '<li class="rc-hide">Hide until refresh</li>';
|
||||
if (userid) {
|
||||
var options = '<ul><li class="changeP toCommons">commons</li> \
|
||||
<li class="changeP toPublic">public</li> \
|
||||
<li class="changeP toPrivate">private</li> \
|
||||
</ul>';
|
||||
|
||||
menustring += '<li class="rc-permission">Change permissions' + options + '</li>';
|
||||
}
|
||||
|
||||
menustring += '</ul>';
|
||||
rightclickmenu.innerHTML = menustring;
|
||||
|
||||
// position the menu where the click happened
|
||||
$(rightclickmenu).css({
|
||||
left: e.clientX,
|
||||
top: e.clientY
|
||||
});
|
||||
//add the menu to the page
|
||||
$('#center-container').append(rightclickmenu);
|
||||
|
||||
|
||||
// attach events to clicks on the list items
|
||||
|
||||
// delete the selected things from the database
|
||||
$('.rc-delete').click(function () {
|
||||
$('.rightclickmenu').remove();
|
||||
var n = MetamapsModel.selectedNodes.length;
|
||||
var e = MetamapsModel.selectedEdges.length;
|
||||
var ntext = n == 1 ? "1 topic" : n + " topics";
|
||||
var etext = e == 1 ? "1 synapse" : e + " synapses";
|
||||
var text = "You have " + ntext + " and " + etext + " selected. ";
|
||||
|
||||
var r = confirm(text + "Are you sure you want to permanently delete them all? This will remove them from all maps they appear on.");
|
||||
if (r == true) {
|
||||
deleteSelectedEdges();
|
||||
deleteSelectedNodes();
|
||||
}
|
||||
});
|
||||
|
||||
// remove the selected things from the map
|
||||
$('.rc-remove').click(function () {
|
||||
$('.rightclickmenu').remove();
|
||||
removeSelectedEdges();
|
||||
removeSelectedNodes();
|
||||
});
|
||||
|
||||
// hide selected nodes and synapses until refresh
|
||||
$('.rc-hide').click(function () {
|
||||
$('.rightclickmenu').remove();
|
||||
hideSelectedEdges();
|
||||
hideSelectedNodes();
|
||||
});
|
||||
|
||||
// change the permission of all the selected nodes and synapses that you were the originator of
|
||||
$('.rc-permission li').click(function () {
|
||||
$('.rightclickmenu').remove();
|
||||
// $(this).text() will be 'commons' 'public' or 'private'
|
||||
updateSelectedPermissions($(this).text());
|
||||
});
|
||||
|
||||
} //selectEdgeOnRightClickHandler
|
||||
|
||||
|
||||
function synapseDoubleClickHandler(adj, e) {
|
||||
editEdge(adj, e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a boolean saying if the synapse was double clicked in our understanding of the word
|
||||
*/
|
||||
function synapseWasDoubleClicked() {
|
||||
//grab the timestamp of the click
|
||||
var storedTime = MetamapsModel.lastSynapseClick;
|
||||
var now = Date.now(); //not compatible with IE8 FYI
|
||||
MetamapsModel.lastSynapseClick = now;
|
||||
|
||||
if (now - storedTime < MetamapsModel.DOUBLE_CLICK_TOLERANCE) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} //synapseWasDoubleClicked;
|
||||
|
||||
function nodeDoubleClickHandler(node, e) {
|
||||
openNodeShowcard(node);
|
||||
}
|
||||
|
||||
function enterKeyHandler(event) {
|
||||
|
||||
//var selectedNodesCopy = MetamapsModel.selectedNodes.slice(0);
|
||||
//var len = selectedNodesCopy.length;
|
||||
//for (var i = 0; i < len; i += 1) {
|
||||
// n = selectedNodesCopy[i];
|
||||
// keepFromCommons(n);
|
||||
//}//for
|
||||
//Mconsole.plot();
|
||||
} //enterKeyHandler
|
||||
|
||||
function escKeyHandler() {
|
||||
deselectAllEdges();
|
||||
deselectAllNodes();
|
||||
} //escKeyHandler
|
||||
|
||||
/*
|
||||
* Make a node "in the commons" (with a green circle) lose its
|
||||
* green circle so it stays on the console/map/...
|
||||
*/
|
||||
function keepFromCommons(event, id) {
|
||||
if (userid == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('#topic_addSynapse').val("false");
|
||||
$('#topic_x').val(0);
|
||||
$('#topic_y').val(0);
|
||||
$('#topic_grabTopic').val(id);
|
||||
$('.new_topic').submit();
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
} //doubleClickNodeHandler
|
||||
|
||||
/*
|
||||
* Returns a boolean saying if the node was double clicked in our understanding of the word
|
||||
*/
|
||||
function nodeWasDoubleClicked() {
|
||||
//grab the timestamp of the click
|
||||
var storedTime = MetamapsModel.lastNodeClick;
|
||||
var now = Date.now(); //not compatible with IE8 FYI
|
||||
MetamapsModel.lastNodeClick = now;
|
||||
|
||||
if (now - storedTime < MetamapsModel.DOUBLE_CLICK_TOLERANCE) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} //nodeWasDoubleClicked;
|
||||
|
||||
function selectNodeOnClickHandler(node, e) {
|
||||
if (Mconsole.busy) return;
|
||||
|
||||
// catch right click on mac, which is often like ctrl+click
|
||||
if (navigator.platform.indexOf("Mac") != -1 && e.ctrlKey) {
|
||||
selectNodeOnRightClickHandler(node, e)
|
||||
return;
|
||||
}
|
||||
|
||||
// if on a topic page, let alt+click center you on a new topic
|
||||
if (!mapid && e.altKey) {
|
||||
centerOn(node.id);
|
||||
return;
|
||||
}
|
||||
|
||||
var check = nodeWasDoubleClicked();
|
||||
if (check) {
|
||||
nodeDoubleClickHandler(node, e);
|
||||
return;
|
||||
} else {
|
||||
// wait a certain length of time, then check again, then run this code
|
||||
setTimeout(function () {
|
||||
if (!nodeWasDoubleClicked()) {
|
||||
if (!e.shiftKey) {
|
||||
Mconsole.graph.eachNode(function (n) {
|
||||
if (n.id != node.id) {
|
||||
deselectNode(n);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (node.selected) {
|
||||
deselectNode(node);
|
||||
} else {
|
||||
selectNode(node);
|
||||
}
|
||||
//trigger animation to final styles
|
||||
Mconsole.fx.animate({
|
||||
modes: ['edge-property:lineWidth:color:alpha'],
|
||||
duration: 500
|
||||
});
|
||||
Mconsole.plot();
|
||||
}
|
||||
}, MetamapsModel.DOUBLE_CLICK_TOLERANCE);
|
||||
}
|
||||
} //selectNodeOnClickHandler
|
||||
|
||||
function selectNodeOnRightClickHandler(node, e) {
|
||||
// the 'node' variable is a JIT node, the one that was clicked on
|
||||
// the 'e' variable is the click event
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (Mconsole.busy) return;
|
||||
|
||||
selectNode(node);
|
||||
|
||||
// delete old right click menu
|
||||
$('.rightclickmenu').remove();
|
||||
// create new menu for clicked on node
|
||||
var rightclickmenu = document.createElement("div");
|
||||
rightclickmenu.className = "rightclickmenu";
|
||||
|
||||
// add the proper options to the menu
|
||||
var menustring = '<ul>';
|
||||
|
||||
if (userid != null) menustring += '<li class="rc-delete">Delete</li>';
|
||||
if (mapid && userid != null) menustring += '<li class="rc-remove">Remove from map</li>';
|
||||
menustring += '<li class="rc-hide">Hide until refresh</li>';
|
||||
|
||||
if (!mapid) menustring += '<li class="rc-center">Center this topic</li>';
|
||||
menustring += '<li class="rc-popout">Open in new tab</li>';
|
||||
if (userid) {
|
||||
var options = '<ul><li class="changeP toCommons">commons</li> \
|
||||
<li class="changeP toPublic">public</li> \
|
||||
<li class="changeP toPrivate">private</li> \
|
||||
</ul>';
|
||||
|
||||
menustring += '<li class="rc-permission">Change permissions' + options + '</li>';
|
||||
}
|
||||
|
||||
menustring += '</ul>';
|
||||
rightclickmenu.innerHTML = menustring;
|
||||
|
||||
// position the menu where the click happened
|
||||
$(rightclickmenu).css({
|
||||
left: e.clientX,
|
||||
top: e.clientY
|
||||
});
|
||||
//add the menu to the page
|
||||
$('#center-container').append(rightclickmenu);
|
||||
|
||||
|
||||
// attach events to clicks on the list items
|
||||
|
||||
// delete the selected things from the database
|
||||
$('.rc-delete').click(function () {
|
||||
$('.rightclickmenu').remove();
|
||||
var n = MetamapsModel.selectedNodes.length;
|
||||
var e = MetamapsModel.selectedEdges.length;
|
||||
var ntext = n == 1 ? "1 topic" : n + " topics";
|
||||
var etext = e == 1 ? "1 synapse" : e + " synapses";
|
||||
var text = "You have " + ntext + " and " + etext + " selected. ";
|
||||
|
||||
var r = confirm(text + "Are you sure you want to permanently delete them all? This will remove them from all maps they appear on.");
|
||||
if (r == true) {
|
||||
deleteSelectedEdges();
|
||||
deleteSelectedNodes();
|
||||
}
|
||||
});
|
||||
|
||||
// remove the selected things from the map
|
||||
$('.rc-remove').click(function () {
|
||||
$('.rightclickmenu').remove();
|
||||
removeSelectedEdges();
|
||||
removeSelectedNodes();
|
||||
});
|
||||
|
||||
// hide selected nodes and synapses until refresh
|
||||
$('.rc-hide').click(function () {
|
||||
$('.rightclickmenu').remove();
|
||||
hideSelectedEdges();
|
||||
hideSelectedNodes();
|
||||
});
|
||||
|
||||
// when in radial, center on the topic you picked
|
||||
$('.rc-center').click(function () {
|
||||
$('.rightclickmenu').remove();
|
||||
centerOn(node.id);
|
||||
});
|
||||
|
||||
// open the entity in a new tab
|
||||
$('.rc-popout').click(function () {
|
||||
$('.rightclickmenu').remove();
|
||||
var win = window.open('/topics/' + node.id, '_blank');
|
||||
win.focus();
|
||||
});
|
||||
|
||||
// change the permission of all the selected nodes and synapses that you were the originator of
|
||||
$('.rc-permission li').click(function () {
|
||||
$('.rightclickmenu').remove();
|
||||
// $(this).text() will be 'commons' 'public' or 'private'
|
||||
updateSelectedPermissions($(this).text());
|
||||
});
|
||||
|
||||
} //selectNodeOnRightClickHandler
|
||||
|
||||
function canvasDoubleClickHandler(canvasLoc, e) {
|
||||
|
||||
//grab the location and timestamp of the click
|
||||
var storedTime = MetamapsModel.lastCanvasClick;
|
||||
var now = Date.now(); //not compatible with IE8 FYI
|
||||
MetamapsModel.lastCanvasClick = now;
|
||||
|
||||
// if on a public map, disable topic creation
|
||||
if (userid && (mapperm || !mapid)) {
|
||||
if (now - storedTime < MetamapsModel.DOUBLE_CLICK_TOLERANCE) {
|
||||
//pop up node creation :)
|
||||
$('#topic_grabTopic').val("null");
|
||||
$('#topic_addSynapse').val("false");
|
||||
$('#new_topic').css('left', e.clientX + "px");
|
||||
$('#new_topic').css('top', e.clientY + "px");
|
||||
$('#topic_x').val(canvasLoc.x);
|
||||
$('#topic_y').val(canvasLoc.y);
|
||||
$('#new_topic').fadeIn('fast');
|
||||
$('#topic_name').typeahead('setQuery', '').focus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!MetamapsModel.didPan) {
|
||||
$('#new_topic').fadeOut('fast');
|
||||
$('#new_synapse').fadeOut('fast');
|
||||
$('.rightclickmenu').remove();
|
||||
// reset the draw synapse positions to false
|
||||
MetamapsModel.synapseStartCoord = false;
|
||||
MetamapsModel.synapseEndCoord = false;
|
||||
deselectAllNodes();
|
||||
tempInit = false;
|
||||
tempNode = null;
|
||||
tempNode2 = null;
|
||||
Mconsole.plot();
|
||||
}
|
||||
} //canvasDoubleClickHandler
|
||||
|
||||
function handleSelectionBeforeDragging(node, e) {
|
||||
// four cases:
|
||||
// 1 nothing is selected, so pretend you aren't selecting
|
||||
// 2 others are selected only and shift, so additionally select this one
|
||||
// 3 others are selected only, no shift: drag only this one
|
||||
// 4 this node and others were selected, so drag them (just return false)
|
||||
//return value: deselect node again after?
|
||||
if (MetamapsModel.selectedNodes.length == 0) {
|
||||
selectNode(node);
|
||||
return 'deselect';
|
||||
}
|
||||
if (MetamapsModel.selectedNodes.indexOf(node) == -1) {
|
||||
if (e.shiftKey) {
|
||||
selectNode(node);
|
||||
return 'nothing';
|
||||
} else {
|
||||
return 'only-drag-this-one';
|
||||
}
|
||||
}
|
||||
return 'nothing'; //case 4?
|
||||
}
|
||||
|
||||
function onDragMoveTopicHandler(node, eventInfo, e) {
|
||||
if (node && !node.nodeFrom) {
|
||||
$('#new_synapse').fadeOut('fast');
|
||||
$('#new_topic').fadeOut('fast');
|
||||
var pos = eventInfo.getPos();
|
||||
var newPosComplex = new $jit.Complex(pos.x, pos.y);
|
||||
// if it's a left click, or a touch, move the node
|
||||
if (e.touches || (e.button == 0 && !e.altKey && (e.buttons == 0 || e.buttons == 1 || e.buttons == undefined))) {
|
||||
//if the node dragged isn't already selected, select it
|
||||
var whatToDo = handleSelectionBeforeDragging(node, e);
|
||||
if (whatToDo == 'only-drag-this-one' || whatToDo == 'deselect') {
|
||||
if (gType == "centered") {
|
||||
var rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y);
|
||||
var theta = Math.atan2(pos.y, pos.x);
|
||||
node.pos.setp(theta, rho);
|
||||
} else {
|
||||
node.setPos(newPosComplex, 'start');
|
||||
node.setPos(newPosComplex, 'current');
|
||||
node.setPos(newPosComplex, 'end');
|
||||
node.setData('xloc', pos.x);
|
||||
node.setData('yloc', pos.y);
|
||||
}
|
||||
} else {
|
||||
var len = MetamapsModel.selectedNodes.length;
|
||||
|
||||
//first define offset for each node
|
||||
var xOffset = new Array();
|
||||
var yOffset = new Array();
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
var n = MetamapsModel.selectedNodes[i];
|
||||
if (gType == "centered") {
|
||||
xOffset[i] = n.pos.toComplex().x - node.pos.toComplex().x;
|
||||
yOffset[i] = n.pos.toComplex().y - node.pos.toComplex().y;
|
||||
} else {
|
||||
xOffset[i] = n.pos.x - node.pos.x;
|
||||
yOffset[i] = n.pos.y - node.pos.y;
|
||||
}
|
||||
} //for
|
||||
|
||||
for (var i = 0; i < len; i += 1) {
|
||||
var n = MetamapsModel.selectedNodes[i];
|
||||
if (gType == "centered") {
|
||||
var x = pos.x + xOffset[i];
|
||||
var y = pos.y + yOffset[i];
|
||||
var rho = Math.sqrt(x * x + y * y);
|
||||
var theta = Math.atan2(y, x);
|
||||
n.pos.setp(theta, rho);
|
||||
} else {
|
||||
newPosComplex = new $jit.Complex(pos.x + xOffset[i], pos.y + yOffset[i]);
|
||||
n.setPos(newPosComplex, 'start');
|
||||
n.setPos(newPosComplex, 'current');
|
||||
n.setPos(newPosComplex, 'end');
|
||||
n.setData('xloc', pos.x + xOffset[i]);
|
||||
n.setData('yloc', pos.y + yOffset[i]);
|
||||
}
|
||||
} //for
|
||||
} //if
|
||||
|
||||
if (whatToDo == 'deselect') {
|
||||
deselectNode(node);
|
||||
}
|
||||
dragged = node.id;
|
||||
Mconsole.plot();
|
||||
}
|
||||
// if it's a right click or holding down alt, start synapse creation ->third option is for firefox
|
||||
else if ((e.button == 2 || (e.button == 0 && e.altKey) || e.buttons == 2) && userid != null) {
|
||||
|
||||
// if on a public map, disable synapse creation
|
||||
if (mapid && !mapperm) return;
|
||||
|
||||
if (tempInit == false) {
|
||||
tempNode = node;
|
||||
tempInit = true;
|
||||
// set the draw synapse start position
|
||||
MetamapsModel.synapseStartCoord = {
|
||||
x: node.pos.getc().x,
|
||||
y: node.pos.getc().y
|
||||
};
|
||||
}
|
||||
//
|
||||
temp = eventInfo.getNode();
|
||||
if (temp != false && temp.id != node.id) { // this means a Node has been returned
|
||||
tempNode2 = temp;
|
||||
|
||||
// set the draw synapse end position
|
||||
MetamapsModel.synapseEndCoord = {
|
||||
x: temp.pos.getc().x,
|
||||
y: temp.pos.getc().y
|
||||
};
|
||||
|
||||
Mconsole.plot();
|
||||
|
||||
// before making the highlighted one bigger, make sure all the others are regular size
|
||||
Mconsole.graph.eachNode(function (n) {
|
||||
n.setData('dim', 25, 'current');
|
||||
});
|
||||
temp.setData('dim', 35, 'current');
|
||||
Mconsole.fx.plotNode(tempNode, Mconsole.canvas);
|
||||
Mconsole.fx.plotNode(temp, Mconsole.canvas);
|
||||
} else if (!temp) {
|
||||
tempNode2 = null;
|
||||
Mconsole.graph.eachNode(function (n) {
|
||||
n.setData('dim', 25, 'current');
|
||||
});
|
||||
//pop up node creation :)
|
||||
$('#topic_grabTopic').val("null");
|
||||
var myX = e.clientX - 110;
|
||||
var myY = e.clientY - 30;
|
||||
$('#new_topic').css('left', myX + "px");
|
||||
$('#new_topic').css('top', myY + "px");
|
||||
$('#new_synapse').css('left', myX + "px");
|
||||
$('#new_synapse').css('top', myY + "px");
|
||||
$('#topic_x').val(eventInfo.getPos().x);
|
||||
$('#topic_y').val(eventInfo.getPos().y);
|
||||
// set the draw synapse end position
|
||||
MetamapsModel.synapseEndCoord = {
|
||||
x: eventInfo.getPos().x,
|
||||
y: eventInfo.getPos().y
|
||||
};
|
||||
Mconsole.plot();
|
||||
Mconsole.fx.plotNode(tempNode, Mconsole.canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var lastDist = 0;
|
||||
|
||||
function getDistance(p1, p2) {
|
||||
return Math.sqrt(Math.pow((p2.x - p1.x), 2) + Math.pow((p2.y - p1.y), 2));
|
||||
}
|
||||
|
||||
function touchPanZoomHandler(eventInfo, e) {
|
||||
if (e.touches.length == 1) {
|
||||
var thispos = touchPos,
|
||||
currentPos = eventInfo.getPos(),
|
||||
canvas = Mconsole.canvas,
|
||||
ox = canvas.translateOffsetX,
|
||||
oy = canvas.translateOffsetY,
|
||||
sx = canvas.scaleOffsetX,
|
||||
sy = canvas.scaleOffsetY;
|
||||
currentPos.x *= sx;
|
||||
currentPos.y *= sy;
|
||||
currentPos.x += ox;
|
||||
currentPos.y += oy;
|
||||
//var x = currentPos.x - thispos.x,
|
||||
// y = currentPos.y - thispos.y;
|
||||
var x = currentPos.x - thispos.x,
|
||||
y = currentPos.y - thispos.y;
|
||||
touchPos = currentPos;
|
||||
Mconsole.canvas.translate(x * 1 / sx, y * 1 / sy);
|
||||
} else if (e.touches.length == 2) {
|
||||
var touch1 = e.touches[0];
|
||||
var touch2 = e.touches[1];
|
||||
|
||||
var dist = getDistance({
|
||||
x: touch1.clientX,
|
||||
y: touch1.clientY
|
||||
}, {
|
||||
x: touch2.clientX,
|
||||
y: touch2.clientY
|
||||
});
|
||||
|
||||
if (!lastDist) {
|
||||
lastDist = dist;
|
||||
}
|
||||
|
||||
var scale = dist / lastDist;
|
||||
|
||||
console.log(scale);
|
||||
|
||||
if (8 >= Mconsole.canvas.scaleOffsetX * scale && Mconsole.canvas.scaleOffsetX * scale >= 1) {
|
||||
Mconsole.canvas.scale(scale, scale);
|
||||
}
|
||||
if (Mconsole.canvas.scaleOffsetX < 0.5) {
|
||||
Mconsole.canvas.viz.labels.hideLabels(true);
|
||||
} else if (Mconsole.canvas.scaleOffsetX > 0.5) {
|
||||
Mconsole.canvas.viz.labels.hideLabels(false);
|
||||
}
|
||||
lastDist = dist;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function updateSelectedPermissions(permission) {
|
||||
|
||||
|
||||
if ($('.notice.metamaps').length == 0) {
|
||||
$('body').prepend('<div class="notice metamaps" />');
|
||||
}
|
||||
$('.notice.metamaps').hide().html('Working...').fadeIn('fast');
|
||||
|
||||
// variables to keep track of how many nodes and synapses you had the ability to change the permission of
|
||||
var nCount = 0,
|
||||
sCount = 0;
|
||||
|
||||
// change the permission of the selected synapses, if logged in user is the original creator
|
||||
var l = MetamapsModel.selectedEdges.length;
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
var edge = MetamapsModel.selectedEdges[i];
|
||||
|
||||
if (edge.getData('userid') == userid) {
|
||||
updateSynapsePermission(edge, permission);
|
||||
sCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// change the permission of the selected topics, if logged in user is the original creator
|
||||
var l = MetamapsModel.selectedNodes.length;
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
var node = MetamapsModel.selectedNodes[i];
|
||||
|
||||
if (node.getData('userid') == userid) {
|
||||
updateTopicPermission(node, permission);
|
||||
nCount++;
|
||||
}
|
||||
}
|
||||
|
||||
var nString = nCount == 1 ? (nCount.toString() + ' topic and ') : (nCount.toString() + ' topics and ');
|
||||
var sString = sCount == 1 ? (sCount.toString() + ' synapse') : (sCount.toString() + ' synapses');
|
||||
|
||||
$('.notice.metamaps').html(nString + sString + ' you created updated to ' + permission)
|
||||
setTimeout(function () {
|
||||
$('.notice.metamaps').fadeOut('fast');
|
||||
}, 8000);
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* @file
|
||||
* This file holds the Model object that is referenced in other graphsettings
|
||||
* files. It lists selected nodes, selected edges, and stores data about
|
||||
* double clicks on the canvas
|
||||
*/
|
||||
|
||||
var MetamapsModel = new Object();
|
||||
|
||||
MetamapsModel.embed = false;
|
||||
|
||||
// if you're on a map, this will be an object that has a reference to each user that has loaded the map, and whether they are
|
||||
// in realtime or not
|
||||
MetamapsModel.mappersOnMap = {};
|
||||
|
||||
|
||||
MetamapsModel.metacodeScrollerInit = false; // indicates whether the scrollbar in the custom metacode set space has been init
|
||||
|
||||
MetamapsModel.selectedMetacodeSet = null;
|
||||
MetamapsModel.selectedMetacodeSetIndex = null;
|
||||
|
||||
MetamapsModel.selectedMetacodeNames = new Array();
|
||||
MetamapsModel.newSelectedMetacodeNames = new Array();
|
||||
|
||||
MetamapsModel.selectedMetacodes = new Array();
|
||||
MetamapsModel.newSelectedMetacodes = new Array();
|
||||
|
||||
//array of all selected edges, same for nodes
|
||||
MetamapsModel.selectedEdges = new Array();
|
||||
MetamapsModel.selectedNodes = new Array();
|
||||
|
||||
//this stores a value that indicates whether the user panned or simply clicked without panning
|
||||
// used for purposes of knowing whether to close the open card or not (don't if panned)
|
||||
MetamapsModel.didPan = false;
|
||||
|
||||
//is any showcard open right now? which one?
|
||||
MetamapsModel.showcardInUse = null;
|
||||
MetamapsModel.widthOfLabel = null;
|
||||
|
||||
//is an edge card open right now? which one (the id)?
|
||||
MetamapsModel.edgecardInUse = null;
|
||||
|
||||
//is the mouse hovering over an edge? which one?
|
||||
MetamapsModel.edgeHoveringOver = false;
|
||||
|
||||
//coordinates of shift click for using box select
|
||||
MetamapsModel.boxStartCoordinates = false;
|
||||
MetamapsModel.boxEndCoordinates = false;
|
||||
|
||||
//coordinates for drawing edge that's not created yet
|
||||
MetamapsModel.synapseStartCoord = false;
|
||||
MetamapsModel.synapseEndCoord = false;
|
||||
|
||||
//double clicking of nodes or canvas
|
||||
MetamapsModel.lastSynapseClick = 0;
|
||||
MetamapsModel.lastNodeClick = 0;
|
||||
MetamapsModel.lastCanvasClick = 0;
|
||||
MetamapsModel.DOUBLE_CLICK_TOLERANCE = 300;
|
||||
|
||||
//pop-up permission editors timers
|
||||
MetamapsModel.edgePermTimer1 = null;
|
||||
MetamapsModel.edgePermTimer2 = null;
|
||||
MetamapsModel.edgePermSliding = false;
|
||||
MetamapsModel.topicPermTimer1 = null;
|
||||
MetamapsModel.topicPermTimer2 = null;
|
||||
MetamapsModel.topicPermSliding = false;
|
|
@ -1,606 +0,0 @@
|
|||
/*
|
||||
* @file
|
||||
* This function defines all settings and event callbacks for the JIT graph. Some are found in other files
|
||||
* First is the common settings (the same as arranged or chaotic)
|
||||
* Then if it's a centred graph additional settings are added.
|
||||
*/
|
||||
|
||||
function graphSettings(type, embed) {
|
||||
var t = {
|
||||
//id of the visualization container
|
||||
injectInto: 'infovis',
|
||||
//Enable zooming and panning
|
||||
//by scrolling and DnD
|
||||
Navigation: {
|
||||
enable: true,
|
||||
//Enable panning events only if we're dragging the empty
|
||||
//canvas (and not a node).
|
||||
panning: 'avoid nodes',
|
||||
zooming: 28 //zoom speed. higher is more sensible
|
||||
},
|
||||
// Change node and edge styles such as
|
||||
// color and width.
|
||||
// These properties are also set per node
|
||||
// with dollar prefixed data-properties in the
|
||||
// JSON structure.
|
||||
Node: {
|
||||
overridable: true,
|
||||
color: '#2D6A5D',
|
||||
type: 'customNode',
|
||||
dim: 25
|
||||
},
|
||||
Edge: {
|
||||
overridable: true,
|
||||
color: '#222222',
|
||||
type: 'customEdge',
|
||||
lineWidth: 2,
|
||||
alpha: 0.4
|
||||
},
|
||||
//Native canvas text styling
|
||||
Label: {
|
||||
type: 'Native', //Native or HTML
|
||||
size: 20,
|
||||
family: 'arial',
|
||||
textBaseline: 'hanging',
|
||||
color: '#DDD'
|
||||
//style: 'bold'
|
||||
},
|
||||
//Add Tips
|
||||
Tips: {
|
||||
enable: false,
|
||||
onShow: function (tip, node) {}
|
||||
},
|
||||
// Add node events
|
||||
Events: {
|
||||
enable: true,
|
||||
enableForEdges: true,
|
||||
onMouseMove: function (node, eventInfo, e) {
|
||||
onMouseMoveHandler(node, eventInfo, e);
|
||||
},
|
||||
//Update node positions when dragged
|
||||
onDragMove: function (node, eventInfo, e) {
|
||||
onDragMoveTopicHandler(node, eventInfo, e);
|
||||
},
|
||||
onDragEnd: function (node, eventInfo, e) {
|
||||
onDragEndTopicHandler(node, eventInfo, e, false);
|
||||
},
|
||||
onDragCancel: function (node, eventInfo, e) {
|
||||
onDragCancelHandler(node, eventInfo, e, false);
|
||||
},
|
||||
//Implement the same handler for touchscreens
|
||||
onTouchStart: function (node, eventInfo, e) {
|
||||
//$jit.util.event.stop(e); //stop default touchmove event
|
||||
//Mconsole.events.onMouseDown(e, null, eventInfo);
|
||||
Mconsole.events.touched = true;
|
||||
touchPos = eventInfo.getPos();
|
||||
var canvas = Mconsole.canvas,
|
||||
ox = canvas.translateOffsetX;
|
||||
oy = canvas.translateOffsetY,
|
||||
sx = canvas.scaleOffsetX,
|
||||
sy = canvas.scaleOffsetY;
|
||||
touchPos.x *= sx;
|
||||
touchPos.y *= sy;
|
||||
touchPos.x += ox;
|
||||
touchPos.y += oy;
|
||||
|
||||
touchDragNode = node;
|
||||
},
|
||||
//Implement the same handler for touchscreens
|
||||
onTouchMove: function (node, eventInfo, e) {
|
||||
if (touchDragNode) onDragMoveTopicHandler(touchDragNode, eventInfo, e);
|
||||
else {
|
||||
touchPanZoomHandler(eventInfo, e);
|
||||
Mconsole.labels.hideLabel(Mconsole.graph.getNode(MetamapsModel.showcardInUse));
|
||||
}
|
||||
},
|
||||
//Implement the same handler for touchscreens
|
||||
onTouchEnd: function (node, eventInfo, e) {
|
||||
|
||||
},
|
||||
//Implement the same handler for touchscreens
|
||||
onTouchCancel: function (node, eventInfo, e) {
|
||||
|
||||
},
|
||||
//Add also a click handler to nodes
|
||||
onClick: function (node, eventInfo, e) {
|
||||
if (MetamapsModel.boxStartCoordinates) {
|
||||
Mconsole.busy = false;
|
||||
MetamapsModel.boxEndCoordinates = eventInfo.getPos();
|
||||
selectNodesWithBox();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.target.id != "infovis-canvas") return false;
|
||||
|
||||
//clicking on a edge, node, or clicking on blank part of canvas?
|
||||
if (node.nodeFrom) {
|
||||
selectEdgeOnClickHandler(node, e);
|
||||
} else if (node && !node.nodeFrom) {
|
||||
selectNodeOnClickHandler(node, e);
|
||||
} else {
|
||||
//topic and synapse editing cards
|
||||
if (!MetamapsModel.didPan) {
|
||||
hideCards();
|
||||
}
|
||||
canvasDoubleClickHandler(eventInfo.getPos(), e);
|
||||
} //if
|
||||
},
|
||||
onRightClick: function (node, eventInfo, e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (node && !node.nodeFrom) {
|
||||
selectNodeOnRightClickHandler(node, e);
|
||||
} else if (node && node.nodeFrom) { // the variable 'node' is actually an edge/adjacency
|
||||
// open right click menu
|
||||
selectEdgeOnRightClickHandler(node, e);
|
||||
} else {
|
||||
// right click on open canvas, options here?
|
||||
}
|
||||
}
|
||||
},
|
||||
//Number of iterations for the FD algorithm
|
||||
iterations: 200,
|
||||
//Edge length
|
||||
levelDistance: 200
|
||||
};
|
||||
|
||||
if (embed) {
|
||||
t.Edge.type = 'customEdgeEmbed';
|
||||
}
|
||||
|
||||
if (type == "centered") {
|
||||
t.background = {
|
||||
CanvasStyles: {
|
||||
strokeStyle: '#333',
|
||||
lineWidth: 1.5
|
||||
}
|
||||
};
|
||||
t.levelDistance = 280;
|
||||
t.Events.enableForEdges = true;
|
||||
t.Events.onDragEnd = function (node, eventInfo, e) {
|
||||
//different because we can't go realtime
|
||||
onDragEndTopicHandler(node, eventInfo, e, false);
|
||||
};
|
||||
t.Events.onDragCancel = function (node, eventInfo, e) {
|
||||
//different because we're centred
|
||||
onDragCancelHandler(node, eventInfo, e, true);
|
||||
};
|
||||
} //if
|
||||
|
||||
return t;
|
||||
} //graphSettings
|
||||
|
||||
function hideCards() {
|
||||
$('#edit_synapse').hide();
|
||||
MetamapsModel.edgecardInUse = null;
|
||||
hideCurrentCard();
|
||||
// delete right click menu
|
||||
$('.rightclickmenu').remove();
|
||||
}
|
||||
|
||||
// defining code to draw edges with arrows pointing in one direction
|
||||
var renderMidArrow = function (from, to, dim, swap, canvas, placement, newSynapse) {
|
||||
var ctx = canvas.getCtx();
|
||||
// invert edge direction
|
||||
if (swap) {
|
||||
var tmp = from;
|
||||
from = to;
|
||||
to = tmp;
|
||||
}
|
||||
// vect represents a line from tip to tail of the arrow
|
||||
var vect = new $jit.Complex(to.x - from.x, to.y - from.y);
|
||||
// scale it
|
||||
vect.$scale(dim / vect.norm());
|
||||
// compute the midpoint of the edge line
|
||||
var newX = (to.x - from.x) * placement + from.x;
|
||||
var newY = (to.y - from.y) * placement + from.y;
|
||||
var midPoint = new $jit.Complex(newX, newY);
|
||||
|
||||
// move midpoint by half the "length" of the arrow so the arrow is centered on the midpoint
|
||||
var arrowPoint = new $jit.Complex((vect.x / 0.7) + midPoint.x, (vect.y / 0.7) + midPoint.y);
|
||||
// compute the tail intersection point with the edge line
|
||||
var intermediatePoint = new $jit.Complex(arrowPoint.x - vect.x, arrowPoint.y - vect.y);
|
||||
// vector perpendicular to vect
|
||||
var normal = new $jit.Complex(-vect.y / 2, vect.x / 2);
|
||||
var v1 = intermediatePoint.add(normal);
|
||||
var v2 = intermediatePoint.$add(normal.$scale(-1));
|
||||
|
||||
if (newSynapse) {
|
||||
ctx.strokeStyle = "#222222";
|
||||
ctx.lineWidth = 2;
|
||||
ctx.globalAlpha = 0.4;
|
||||
}
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(from.x, from.y);
|
||||
ctx.lineTo(to.x, to.y);
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(v1.x, v1.y);
|
||||
ctx.lineTo(arrowPoint.x, arrowPoint.y);
|
||||
ctx.lineTo(v2.x, v2.y);
|
||||
ctx.stroke();
|
||||
};
|
||||
|
||||
// defining custom node type
|
||||
var nodeSettings = {
|
||||
'customNode': {
|
||||
'render': function (node, canvas) {
|
||||
var pos = node.pos.getc(true),
|
||||
dim = node.getData('dim'),
|
||||
cat = node.getData('metacode'),
|
||||
whiteCircle = node.getData('whiteCircle'),
|
||||
ctx = canvas.getCtx();
|
||||
|
||||
// if the topic is on the Canvas draw a white circle around it
|
||||
if (whiteCircle) {
|
||||
ctx.beginPath();
|
||||
ctx.arc(pos.x, pos.y, dim + 3, 0, 2 * Math.PI, false);
|
||||
if (!MetamapsModel.embed) ctx.strokeStyle = 'white';
|
||||
if (MetamapsModel.embed) ctx.strokeStyle = '#999';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
}
|
||||
ctx.drawImage(imgArray[cat], pos.x - dim, pos.y - dim, dim * 2, dim * 2);
|
||||
|
||||
},
|
||||
'contains': function (node, pos) {
|
||||
var npos = node.pos.getc(true),
|
||||
dim = node.getData('dim');
|
||||
return this.nodeHelper.circle.contains(npos, pos, dim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var renderEdgeArrows = function (edgeHelper, adj) {
|
||||
var canvas = Mconsole.canvas;
|
||||
var directionCat = adj.getData('category');
|
||||
var direction = adj.getData('direction');
|
||||
var pos = adj.nodeFrom.pos.getc(true);
|
||||
var posChild = adj.nodeTo.pos.getc(true);
|
||||
|
||||
//plot arrow edge
|
||||
if (directionCat == "none") {
|
||||
edgeHelper.line.render({
|
||||
x: pos.x,
|
||||
y: pos.y
|
||||
}, {
|
||||
x: posChild.x,
|
||||
y: posChild.y
|
||||
}, canvas);
|
||||
} else if (directionCat == "both") {
|
||||
renderMidArrow({
|
||||
x: pos.x,
|
||||
y: pos.y
|
||||
}, {
|
||||
x: posChild.x,
|
||||
y: posChild.y
|
||||
}, 13, true, canvas, 0.7);
|
||||
renderMidArrow({
|
||||
x: pos.x,
|
||||
y: pos.y
|
||||
}, {
|
||||
x: posChild.x,
|
||||
y: posChild.y
|
||||
}, 13, false, canvas, 0.7);
|
||||
} else if (directionCat == "from-to") {
|
||||
var direction = adj.data.$direction;
|
||||
var inv = (direction && direction.length > 1 && direction[0] != adj.nodeFrom.id);
|
||||
renderMidArrow({
|
||||
x: pos.x,
|
||||
y: pos.y
|
||||
}, {
|
||||
x: posChild.x,
|
||||
y: posChild.y
|
||||
}, 13, inv, canvas, 0.7);
|
||||
renderMidArrow({
|
||||
x: pos.x,
|
||||
y: pos.y
|
||||
}, {
|
||||
x: posChild.x,
|
||||
y: posChild.y
|
||||
}, 13, inv, canvas, 0.3);
|
||||
}
|
||||
} //renderEdgeArrow
|
||||
|
||||
// defining custom edges
|
||||
var edgeSettings = {
|
||||
'customEdge': {
|
||||
'render': function (adj, canvas) {
|
||||
//get nodes cartesian coordinates
|
||||
var pos = adj.nodeFrom.pos.getc(true);
|
||||
var posChild = adj.nodeTo.pos.getc(true);
|
||||
|
||||
var directionCat = adj.getData("category");
|
||||
//label placement on edges
|
||||
renderEdgeArrows(this.edgeHelper, adj);
|
||||
|
||||
//check for edge label in data
|
||||
var desc = adj.getData("desc");
|
||||
var showDesc = adj.getData("showDesc");
|
||||
if (desc != "" && showDesc) {
|
||||
// '&' to '&'
|
||||
desc = decodeEntities(desc);
|
||||
|
||||
//now adjust the label placement
|
||||
var ctx = canvas.getCtx();
|
||||
ctx.font = 'bold 14px arial';
|
||||
ctx.fillStyle = '#FFF';
|
||||
ctx.textBaseline = 'hanging';
|
||||
|
||||
// helper function to determine how many lines are needed
|
||||
// Line Splitter Function
|
||||
// copyright Stephen Chapman, 19th April 2006
|
||||
// you may copy this code but please keep the copyright notice as well
|
||||
function splitLine(st, n) {
|
||||
var b = '';
|
||||
var s = st;
|
||||
while (s.length > n) {
|
||||
var c = s.substring(0, n);
|
||||
var d = c.lastIndexOf(' ');
|
||||
var e = c.lastIndexOf('\n');
|
||||
if (e != -1) d = e;
|
||||
if (d == -1) d = n;
|
||||
b += c.substring(0, d) + '\n';
|
||||
s = s.substring(d + 1);
|
||||
}
|
||||
return b + s;
|
||||
}
|
||||
var arrayOfLabelLines = splitLine(desc, 30).split('\n');
|
||||
var index, lineWidths = [];
|
||||
for (index = 0; index < arrayOfLabelLines.length; ++index) {
|
||||
lineWidths.push(ctx.measureText(arrayOfLabelLines[index]).width)
|
||||
}
|
||||
var width = Math.max.apply(null, lineWidths) + 8;
|
||||
var height = (16 * arrayOfLabelLines.length) + 8;
|
||||
|
||||
var x = (pos.x + posChild.x - width) / 2;
|
||||
var y = ((pos.y + posChild.y) / 2) - height / 2;
|
||||
var radius = 5;
|
||||
|
||||
//render background
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + radius, y);
|
||||
ctx.lineTo(x + width - radius, y);
|
||||
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
|
||||
ctx.lineTo(x + width, y + height - radius);
|
||||
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
|
||||
ctx.lineTo(x + radius, y + height);
|
||||
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
|
||||
ctx.lineTo(x, y + radius);
|
||||
ctx.quadraticCurveTo(x, y, x + radius, y);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
//render text
|
||||
ctx.fillStyle = '#222222';
|
||||
ctx.textAlign = 'center';
|
||||
for (index = 0; index < arrayOfLabelLines.length; ++index) {
|
||||
ctx.fillText(arrayOfLabelLines[index], x + (width / 2), y + 5 + (16 * index));
|
||||
}
|
||||
}
|
||||
},
|
||||
'contains': function (adj, pos) {
|
||||
var from = adj.nodeFrom.pos.getc(true),
|
||||
to = adj.nodeTo.pos.getc(true);
|
||||
return this.edgeHelper.line.contains(from, to, pos, adj.Edge.epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var edgeSettingsEmbed = {
|
||||
'customEdgeEmbed': {
|
||||
'render': function (adj, canvas) {
|
||||
//get nodes cartesian coordinates
|
||||
var pos = adj.nodeFrom.pos.getc(true);
|
||||
var posChild = adj.nodeTo.pos.getc(true);
|
||||
|
||||
var directionCat = adj.getData("category");
|
||||
//label placement on edges
|
||||
renderEdgeArrows(this.edgeHelper, adj);
|
||||
|
||||
//check for edge label in data
|
||||
var desc = adj.getData("desc");
|
||||
var showDesc = adj.getData("showDesc");
|
||||
if (desc != "" && showDesc) {
|
||||
// '&' to '&'
|
||||
desc = decodeEntities(desc);
|
||||
|
||||
//now adjust the label placement
|
||||
var ctx = canvas.getCtx();
|
||||
var radius = canvas.getSize();
|
||||
var x = parseInt((pos.x + posChild.x - (desc.length * 5)) / 2);
|
||||
var y = parseInt((pos.y + posChild.y) / 2);
|
||||
ctx.font = 'bold 14px arial';
|
||||
|
||||
//render background
|
||||
ctx.fillStyle = '#999';
|
||||
var margin = 5;
|
||||
var height = 14 + margin; //font size + margin
|
||||
var CURVE = height / 2; //offset for curvy corners
|
||||
var width = ctx.measureText(desc).width + 2 * margin - 2 * CURVE
|
||||
var labelX = x - margin + CURVE;
|
||||
var labelY = y - height + margin;
|
||||
ctx.fillRect(labelX, labelY, width, height);
|
||||
|
||||
//curvy corners woo - circles in place of last CURVE pixels of rect
|
||||
ctx.beginPath();
|
||||
ctx.arc(labelX, labelY + CURVE, CURVE, 0, 2 * Math.PI, false);
|
||||
ctx.arc(labelX + width, labelY + CURVE, CURVE, 0, 2 * Math.PI, false);
|
||||
ctx.fill();
|
||||
|
||||
//render text
|
||||
ctx.fillStyle = '#000';
|
||||
ctx.fillText(desc, x, y);
|
||||
}
|
||||
},
|
||||
'contains': function (adj, pos) {
|
||||
var from = adj.nodeFrom.pos.getc(true),
|
||||
to = adj.nodeTo.pos.getc(true);
|
||||
return this.edgeHelper.line.contains(from, to, pos, adj.Edge.epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawSelectBox(eventInfo, e) {
|
||||
Mconsole.plot();
|
||||
var ctx = Mconsole.canvas.getCtx();
|
||||
|
||||
var startX = MetamapsModel.boxStartCoordinates.x,
|
||||
startY = MetamapsModel.boxStartCoordinates.y,
|
||||
currX = eventInfo.getPos().x,
|
||||
currY = eventInfo.getPos().y;
|
||||
|
||||
Mconsole.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();
|
||||
}
|
||||
|
||||
function selectNodesWithBox() {
|
||||
|
||||
var sX = MetamapsModel.boxStartCoordinates.x,
|
||||
sY = MetamapsModel.boxStartCoordinates.y,
|
||||
eX = MetamapsModel.boxEndCoordinates.x,
|
||||
eY = MetamapsModel.boxEndCoordinates.y;
|
||||
|
||||
|
||||
Mconsole.graph.eachNode(function (n) {
|
||||
var x = gType == "centered" ? n.pos.toComplex().x : n.pos.x,
|
||||
y = gType == "centered" ? n.pos.toComplex().y : n.pos.y;
|
||||
|
||||
if ((sX < x && x < eX && sY < y && y < eY) || (sX > x && x > eX && sY > y && y > eY) || (sX > x && x > eX && sY < y && y < eY) || (sX < x && x < eX && sY > y && y > eY)) {
|
||||
var nodeIsSelected = MetamapsModel.selectedNodes.indexOf(n);
|
||||
if (nodeIsSelected == -1) selectNode(n); // the node is not selected, so select it
|
||||
else if (nodeIsSelected != -1) deselectNode(n); // the node is selected, so deselect it
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
MetamapsModel.boxStartCoordinates = false;
|
||||
MetamapsModel.boxEndCoordinates = false;
|
||||
Mconsole.plot();
|
||||
}
|
||||
|
||||
function onMouseMoveHandler(node, eventInfo, e) {
|
||||
|
||||
if (Mconsole.busy) return;
|
||||
|
||||
var node = eventInfo.getNode();
|
||||
var edge = eventInfo.getEdge();
|
||||
|
||||
//if we're on top of a node object, act like there aren't edges under it
|
||||
if (node != false) {
|
||||
if (MetamapsModel.edgeHoveringOver) {
|
||||
onMouseLeave(MetamapsModel.edgeHoveringOver);
|
||||
}
|
||||
$('canvas').css('cursor', 'pointer');
|
||||
return;
|
||||
}
|
||||
|
||||
if (edge == false && MetamapsModel.edgeHoveringOver != false) {
|
||||
//mouse not on an edge, but we were on an edge previously
|
||||
onMouseLeave(MetamapsModel.edgeHoveringOver);
|
||||
} else if (edge != false && MetamapsModel.edgeHoveringOver == false) {
|
||||
//mouse is on an edge, but there isn't a stored edge
|
||||
onMouseEnter(edge);
|
||||
} else if (edge != false && MetamapsModel.edgeHoveringOver != edge) {
|
||||
//mouse is on an edge, but a different edge is stored
|
||||
onMouseLeave(MetamapsModel.edgeHoveringOver)
|
||||
onMouseEnter(edge);
|
||||
}
|
||||
|
||||
//could be false
|
||||
MetamapsModel.edgeHoveringOver = edge;
|
||||
|
||||
if (!node && !edge) {
|
||||
$('canvas').css('cursor', 'default');
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseEnter(edge) {
|
||||
$('canvas').css('cursor', 'pointer');
|
||||
var edgeIsSelected = MetamapsModel.selectedEdges.indexOf(edge);
|
||||
//following if statement only executes if the edge being hovered over is not selected
|
||||
if (edgeIsSelected == -1) {
|
||||
edge.setData('showDesc', true, 'current');
|
||||
edge.setDataset('end', {
|
||||
lineWidth: 4,
|
||||
alpha: 1
|
||||
});
|
||||
Mconsole.fx.animate({
|
||||
modes: ['edge-property:lineWidth:color:alpha'],
|
||||
duration: 100
|
||||
});
|
||||
Mconsole.plot();
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseLeave(edge) {
|
||||
$('canvas').css('cursor', 'default');
|
||||
var edgeIsSelected = MetamapsModel.selectedEdges.indexOf(edge);
|
||||
//following if statement only executes if the edge being hovered over is not selected
|
||||
if (edgeIsSelected == -1) {
|
||||
edge.setData('showDesc', false, 'current');
|
||||
edge.setDataset('end', {
|
||||
lineWidth: 2,
|
||||
alpha: 0.4
|
||||
});
|
||||
Mconsole.fx.animate({
|
||||
modes: ['edge-property:lineWidth:color:alpha'],
|
||||
duration: 100
|
||||
});
|
||||
}
|
||||
Mconsole.plot();
|
||||
}
|
||||
|
||||
function onDragEndTopicHandler(node, eventInfo, e, allowRealtime) {
|
||||
if (tempInit && tempNode2 == null) {
|
||||
$('#topic_addSynapse').val("true");
|
||||
$('#new_topic').fadeIn('fast');
|
||||
$('#topic_name').focus();
|
||||
} else if (tempInit && tempNode2 != null) {
|
||||
$('#topic_addSynapse').val("false");
|
||||
$('#synapse_topic1id').val(tempNode.id);
|
||||
$('#synapse_topic2id').val(tempNode2.id);
|
||||
$('#new_synapse').fadeIn('fast');
|
||||
$('#synapse_desc').typeahead('setQuery', '').focus();
|
||||
tempNode = null;
|
||||
tempNode2 = null;
|
||||
tempInit = false;
|
||||
} else if (dragged && dragged != 0 && goRealtime) {
|
||||
saveLayout(dragged);
|
||||
for (var i = 0; i < MetamapsModel.selectedNodes.length; i++) {
|
||||
saveLayout(MetamapsModel.selectedNodes[i].id);
|
||||
}
|
||||
}
|
||||
} //onDragEndTopicHandler
|
||||
|
||||
function onDragCancelHandler(node, eventInfo, e, centred) {
|
||||
tempNode = null;
|
||||
tempNode2 = null;
|
||||
tempInit = false;
|
||||
|
||||
//not sure why this doesn't happen for centred graphs
|
||||
if (!centred) {
|
||||
$('#topic_addSynapse').val("false");
|
||||
$('#topic_topic1id').val(0);
|
||||
$('#topic_topic2id').val(0);
|
||||
}
|
||||
Mconsole.plot();
|
||||
}
|
||||
|
||||
// thanks to http://stackoverflow.com/questions/4338963/
|
||||
// convert-html-character-entities-back-to-regular-text-using-javascript
|
||||
function decodeEntities(desc) {
|
||||
var str, temp = document.createElement('p');
|
||||
temp.innerHTML = desc; //browser handles the entities
|
||||
str = temp.textContent || temp.innerText;
|
||||
temp = null; //delete the element;
|
||||
return str;
|
||||
} //decodeEntities
|
|
@ -1,143 +0,0 @@
|
|||
(function() {
|
||||
var ua = navigator.userAgent,
|
||||
iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
|
||||
typeOfCanvas = typeof HTMLCanvasElement,
|
||||
nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
|
||||
textSupport = nativeCanvasSupport
|
||||
&& (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
|
||||
//I'm setting this based on the fact that ExCanvas provides text support for IE
|
||||
//and that as of today iPhone/iPad current text support is lame
|
||||
labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML';
|
||||
nativeTextSupport = labelType == 'Native';
|
||||
useGradients = nativeCanvasSupport;
|
||||
animate = !(iStuff || !nativeCanvasSupport);
|
||||
})();
|
||||
|
||||
// init custom node type
|
||||
$jit.ForceDirected.Plot.NodeTypes.implement(nodeSettings);
|
||||
//implement an edge type
|
||||
$jit.ForceDirected.Plot.EdgeTypes.implement(edgeSettings);
|
||||
$jit.ForceDirected.Plot.EdgeTypes.implement(edgeSettingsEmbed);
|
||||
// end
|
||||
|
||||
// init custom node type
|
||||
$jit.RGraph.Plot.NodeTypes.implement(nodeSettings);
|
||||
//implement an edge type
|
||||
$jit.RGraph.Plot.EdgeTypes.implement(edgeSettings);
|
||||
// end
|
||||
|
||||
function initialize(type, loadLater, embed){
|
||||
|
||||
if (loadLater == null) {
|
||||
loadlater = false;
|
||||
}
|
||||
if (embed == null) {
|
||||
embed = false;
|
||||
}
|
||||
|
||||
viewMode = "graph";
|
||||
gType = type;
|
||||
|
||||
if ( type == "centered") {
|
||||
// init Rgraph
|
||||
Mconsole = new $jit.RGraph(graphSettings(type));
|
||||
}
|
||||
else if ( type == "arranged" || type == "chaotic" ) {
|
||||
// init ForceDirected
|
||||
Mconsole = new $jit.ForceDirected(graphSettings(type, embed));
|
||||
}
|
||||
else {
|
||||
alert("You didn't specify a type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// load JSON data.
|
||||
if (!loadLater) {
|
||||
Mconsole.busy = true;
|
||||
Mconsole.loadJSON(json);
|
||||
|
||||
// choose how to plot and animate the data onto the screen
|
||||
var chooseAnimate;
|
||||
|
||||
if ( type == "centered") {
|
||||
// compute positions incrementally and animate.
|
||||
//trigger small animation
|
||||
Mconsole.graph.eachNode(function(n) {
|
||||
var pos = n.getPos();
|
||||
pos.setc(-200, -200);
|
||||
});
|
||||
Mconsole.compute('end');
|
||||
|
||||
chooseAnimate = {
|
||||
modes:['polar'],
|
||||
duration: 2000,
|
||||
onComplete: function() {
|
||||
Mconsole.busy = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
else if ( type == "arranged" ) {
|
||||
// compute positions incrementally and animate.
|
||||
Mconsole.graph.eachNode(function(n) {
|
||||
var pos = n.getPos();
|
||||
pos.setc(0, 0);
|
||||
var newPos = new $jit.Complex();
|
||||
newPos.x = n.data.$xloc;
|
||||
newPos.y = n.data.$yloc;
|
||||
n.setPos(newPos, 'end');
|
||||
});
|
||||
|
||||
chooseAnimate = {
|
||||
modes: ['linear'],
|
||||
transition: $jit.Trans.Quad.easeInOut,
|
||||
duration: 2500,
|
||||
onComplete: function() {
|
||||
Mconsole.busy = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
else if ( type == "chaotic" ) {
|
||||
// compute positions incrementally and animate.
|
||||
Mconsole.compute();
|
||||
|
||||
chooseAnimate = {
|
||||
modes: ['linear'],
|
||||
transition: $jit.Trans.Elastic.easeOut,
|
||||
duration: 2500,
|
||||
onComplete: function() {
|
||||
Mconsole.busy = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
if ( type == "centered") {
|
||||
Mconsole.fx.animate(chooseAnimate);
|
||||
}
|
||||
else if ( type == "arranged" || type == "chaotic") {
|
||||
Mconsole.animate(chooseAnimate);
|
||||
}
|
||||
|
||||
// prevent touch events on the canvas from default behaviour
|
||||
$("#infovis-canvas").bind('touchstart', function(event) {
|
||||
event.preventDefault();
|
||||
Mconsole.events.touched = true;
|
||||
});
|
||||
|
||||
// prevent touch events on the canvas from default behaviour
|
||||
$("#infovis-canvas").bind('touchmove', function(event) {
|
||||
//touchPanZoomHandler(event);
|
||||
});
|
||||
|
||||
// prevent touch events on the canvas from default behaviour
|
||||
$("#infovis-canvas").bind('touchend touchcancel', function(event) {
|
||||
lastDist = 0;
|
||||
if (!Mconsole.events.touchMoved && !touchDragNode) hideCurrentCard();
|
||||
Mconsole.events.touched = Mconsole.events.touchMoved = false;
|
||||
touchDragNode = false;
|
||||
});
|
||||
});
|
||||
// end
|
||||
}// if not loadLater
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
|
||||
function authorizeToEdit(obj) {
|
||||
if (userid && (obj.data.$permission == "commons" || obj.data.$userid == userid)) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
function mk_permission(obj) {
|
||||
if (obj.getData("permission") == "commons") return "co";
|
||||
else if (obj.getData("permission") == "public") return "pu";
|
||||
else if (obj.getData("permission") == "private") return "pr";
|
||||
}
|
|
@ -1,439 +0,0 @@
|
|||
function centerOn(nodeid) {
|
||||
if (!Mconsole.busy) {
|
||||
var node = Mconsole.graph.getNode(nodeid);
|
||||
$('div.index img').attr('src', imgArray[node.getData('metacode')].src);
|
||||
$('div.index .mapName').html(node.name);
|
||||
$(document).attr('title', node.name + ' | Metamaps');
|
||||
window.history.pushState(node.name, "Metamaps", "/topics/" + node.id);
|
||||
Mconsole.onClick(node.id, {
|
||||
hideLabels: false,
|
||||
duration: 1000,
|
||||
onComplete: function () {
|
||||
fetchRelatives(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function editEdge(edge, e) {
|
||||
//reset so we don't interfere with other edges, but first, save its x and y
|
||||
var myX = $('#edit_synapse').css('left');
|
||||
var myY = $('#edit_synapse').css('top');
|
||||
$('#edit_synapse').remove();
|
||||
|
||||
//so label is missing while editing
|
||||
deselectEdge(edge);
|
||||
|
||||
//create the wrapper around the form elements, including permissions
|
||||
//classes to make best_in_place happy
|
||||
var edit_div = document.createElement('div');
|
||||
edit_div.setAttribute('id', 'edit_synapse');
|
||||
if (authorizeToEdit(edge)) {
|
||||
edit_div.className = 'permission canEdit';
|
||||
edit_div.className += edge.getData('userid') === userid ? ' yourEdge' : '';
|
||||
} else {
|
||||
edit_div.className = 'permission cannotEdit';
|
||||
}
|
||||
$('.main .wrapper').append(edit_div);
|
||||
|
||||
populateEditEdgeForm(edge);
|
||||
|
||||
//drop it in the right spot, activate it
|
||||
$('#edit_synapse').css('position', 'absolute');
|
||||
if (e) {
|
||||
$('#edit_synapse').css('left', e.clientX);
|
||||
$('#edit_synapse').css('top', e.clientY);
|
||||
} else {
|
||||
$('#edit_synapse').css('left', myX);
|
||||
$('#edit_synapse').css('top', myY);
|
||||
}
|
||||
//$('#edit_synapse_name').click(); //required in case name is empty
|
||||
//$('#edit_synapse_name input').focus();
|
||||
$('#edit_synapse').show();
|
||||
|
||||
MetamapsModel.edgecardInUse = edge.data.$id;
|
||||
}
|
||||
|
||||
function populateEditEdgeForm(edge) {
|
||||
add_name_form(edge);
|
||||
add_user_info(edge);
|
||||
add_perms_form(edge);
|
||||
if (authorizeToEdit(edge)) {
|
||||
add_direction_form(edge);
|
||||
}
|
||||
}
|
||||
|
||||
function add_name_form(edge) {
|
||||
var data_nil = '<span class="gray">Click to add description.</span>';
|
||||
//name editing form
|
||||
$('#edit_synapse').append('<div id="edit_synapse_name"></div>');
|
||||
$('#edit_synapse_name').attr('class', 'best_in_place best_in_place_desc');
|
||||
$('#edit_synapse_name').attr('data-object', 'synapse');
|
||||
$('#edit_synapse_name').attr('data-attribute', 'desc');
|
||||
$('#edit_synapse_name').attr('data-type', 'textarea');
|
||||
$('#edit_synapse_name').attr('data-nil', data_nil);
|
||||
$('#edit_synapse_name').attr('data-url', '/synapses/' + edge.getData("id"));
|
||||
$('#edit_synapse_name').html(edge.getData("desc"));
|
||||
|
||||
//if edge data is blank or just whitespace, populate it with data_nil
|
||||
if ($('#edit_synapse_name').html().trim() == '') {
|
||||
$('#edit_synapse_name').html(data_nil);
|
||||
}
|
||||
|
||||
$('#edit_synapse_name').bind("ajax:success", function () {
|
||||
var desc = $(this).html();
|
||||
if (desc == data_nil) {
|
||||
edge.setData("desc", '');
|
||||
} else {
|
||||
edge.setData("desc", desc);
|
||||
}
|
||||
selectEdge(edge);
|
||||
Mconsole.plot();
|
||||
});
|
||||
}
|
||||
|
||||
function add_user_info(edge) {
|
||||
$('#edit_synapse').append('<div id="edgeUser" class="hoverForTip"><div class="tip">Created by ' + edge.getData("username") + '</div></div>');
|
||||
}
|
||||
|
||||
function add_perms_form(edge) {
|
||||
//permissions - if owner, also allow permission editing
|
||||
$('#edit_synapse').append('<div class="mapPerm ' + mk_permission(edge) + '"></div>');
|
||||
|
||||
// ability to change permission
|
||||
var selectingPermission = false;
|
||||
if (userid == edge.getData('userid')) {
|
||||
$('#edit_synapse.yourEdge .mapPerm').click(function () {
|
||||
if (!selectingPermission) {
|
||||
selectingPermission = true;
|
||||
$(this).addClass('minimize'); // this line flips the drop down arrow to a pull up arrow
|
||||
if ($(this).hasClass('co')) {
|
||||
$(this).append('<ul class="permissionSelect"><li class="public"></li><li class="private"></li></ul>');
|
||||
} else if ($(this).hasClass('pu')) {
|
||||
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="private"></li></ul>');
|
||||
} else if ($(this).hasClass('pr')) {
|
||||
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="public"></li></ul>');
|
||||
}
|
||||
$('#edit_synapse .permissionSelect li').click(function (event) {
|
||||
selectingPermission = false;
|
||||
var permission = $(this).attr('class');
|
||||
updateSynapsePermission(edge, permission);
|
||||
event.stopPropagation();
|
||||
});
|
||||
} else {
|
||||
selectingPermission = false;
|
||||
$(this).removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow
|
||||
$('#edit_synapse .permissionSelect').remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
} //add_perms_form
|
||||
|
||||
function add_direction_form(edge) {
|
||||
//directionality checkboxes
|
||||
$('#edit_synapse').append('<input type="checkbox" id="edit_synapse_left">');
|
||||
$('#edit_synapse').append('<label class="left"><</label>');
|
||||
$('#edit_synapse').append('<input type="checkbox" id="edit_synapse_right">');
|
||||
$('#edit_synapse').append('<label class="right">></label>');
|
||||
|
||||
//determine which node is to the left and the right
|
||||
//if directly in a line, top is left
|
||||
if (edge.nodeFrom.pos.x < edge.nodeTo.pos.x ||
|
||||
edge.nodeFrom.pos.x == edge.nodeTo.pos.x &&
|
||||
edge.nodeFrom.pos.y < edge.nodeTo.pos.y) {
|
||||
var left = edge.nodeTo;
|
||||
var right = edge.nodeFrom;
|
||||
} else {
|
||||
var left = edge.nodeFrom;
|
||||
var right = edge.nodeTo;
|
||||
}
|
||||
|
||||
/*
|
||||
* One node is actually on the left onscreen. Call it left, & the other right.
|
||||
* If category is from-to, and that node is first, check the 'right' checkbox.
|
||||
* Else check the 'left' checkbox since the arrow is incoming.
|
||||
*/
|
||||
|
||||
var directionCat = edge.getData('category'); //both, none, from-to
|
||||
if (directionCat == 'from-to') {
|
||||
var from_to = edge.getData('direction');
|
||||
if (from_to[0] == left.id) {
|
||||
//check left checkbox
|
||||
$('#edit_synapse_left').prop('checked', true);
|
||||
} else {
|
||||
//check right checkbox
|
||||
$('#edit_synapse_right').prop('checked', true);
|
||||
}
|
||||
} else if (directionCat == 'both') {
|
||||
//check both checkboxes
|
||||
$('#edit_synapse_left').prop('checked', true);
|
||||
$('#edit_synapse_right').prop('checked', true);
|
||||
}
|
||||
$('#edit_synapse_left, #edit_synapse_right').click(function () {
|
||||
var leftChecked = $('#edit_synapse_left').is(':checked');
|
||||
var rightChecked = $('#edit_synapse_right').is(':checked');
|
||||
|
||||
var dir = edge.getData('direction');
|
||||
var dirCat = 'none';
|
||||
if (leftChecked && rightChecked) {
|
||||
dirCat = 'both';
|
||||
} else if (!leftChecked && rightChecked) {
|
||||
dirCat = 'from-to';
|
||||
dir = [right.id, left.id];
|
||||
} else if (leftChecked && !rightChecked) {
|
||||
dirCat = 'from-to';
|
||||
dir = [left.id, right.id];
|
||||
}
|
||||
$.ajax({
|
||||
'type': 'PUT',
|
||||
'url': '/synapses/' + edge.getData('id'),
|
||||
'data': {
|
||||
synapse: {
|
||||
category: dirCat
|
||||
},
|
||||
node1_id: {
|
||||
node1: dir[0]
|
||||
},
|
||||
node2_id: {
|
||||
node2: dir[1]
|
||||
}
|
||||
},
|
||||
'success': function (data) {
|
||||
updateEdgeDisplay(edge, dir, dirCat);
|
||||
}
|
||||
});
|
||||
});
|
||||
} //add_direction_form
|
||||
|
||||
function updateEdgeDisplay(edge, dir, dirCat) {
|
||||
edge.setData('category', dirCat);
|
||||
edge.setData('direction', dir);
|
||||
|
||||
//render mid arrow
|
||||
//renderEdgeArrows(Mconsole.fx.edgeHelper, edge);
|
||||
Mconsole.plot();
|
||||
}
|
||||
|
||||
function deselectAllEdges() {
|
||||
var l = MetamapsModel.selectedEdges.length;
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
var edge = MetamapsModel.selectedEdges[i];
|
||||
deselectEdge(edge);
|
||||
}
|
||||
}
|
||||
|
||||
function deselectAllNodes() {
|
||||
var l = MetamapsModel.selectedNodes.length;
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
var node = MetamapsModel.selectedNodes[i];
|
||||
deselectNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
// this is for hiding one topic from your canvas
|
||||
function removeEdge(edge) {
|
||||
var id = edge.getData("id");
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
url: "/synapses/" + id,
|
||||
success: function () {
|
||||
hideEdge(edge);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function hideEdge(edge) {
|
||||
var from = edge.nodeFrom.id;
|
||||
var to = edge.nodeTo.id;
|
||||
edge.setData('alpha', 0, 'end');
|
||||
Mconsole.fx.animate({
|
||||
modes: ['edge-property:alpha'],
|
||||
duration: 1000
|
||||
});
|
||||
Mconsole.graph.removeAdjacence(from, to);
|
||||
Mconsole.plot();
|
||||
}
|
||||
|
||||
function hideSelectedEdges() {
|
||||
var l = MetamapsModel.selectedEdges.length;
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
var edge = MetamapsModel.selectedEdges[i];
|
||||
hideEdge(edge);
|
||||
}
|
||||
MetamapsModel.selectedEdges = new Array();
|
||||
}
|
||||
|
||||
function removeSelectedEdges() {
|
||||
var l = MetamapsModel.selectedEdges.length;
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
if (mapid != null) {
|
||||
var edge = MetamapsModel.selectedEdges[i];
|
||||
var id = edge.getData("id");
|
||||
//delete mapping of id mapid
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/synapses/" + mapid + "/" + id + "/removefrommap",
|
||||
});
|
||||
}
|
||||
hideEdge(edge);
|
||||
}
|
||||
MetamapsModel.selectedEdges = new Array();
|
||||
}
|
||||
|
||||
function deleteSelectedEdges() {
|
||||
var l = MetamapsModel.selectedEdges.length;
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
var edge = MetamapsModel.selectedEdges[i];
|
||||
var id = edge.getData("id");
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
url: "/synapses/" + id,
|
||||
});
|
||||
hideEdge(edge);
|
||||
}
|
||||
MetamapsModel.selectedEdges = new Array();
|
||||
}
|
||||
|
||||
function selectNode(node) {
|
||||
if (MetamapsModel.selectedNodes.indexOf(node) != -1) return;
|
||||
node.selected = true;
|
||||
node.setData('dim', 30, 'current');
|
||||
node.setData('whiteCircle', true);
|
||||
node.eachAdjacency(function (adj) {
|
||||
selectEdge(adj);
|
||||
});
|
||||
MetamapsModel.selectedNodes.push(node);
|
||||
}
|
||||
|
||||
function deselectNode(node) {
|
||||
delete node.selected;
|
||||
node.setData('whiteCircle', false);
|
||||
node.eachAdjacency(function (adj) {
|
||||
deselectEdge(adj);
|
||||
});
|
||||
node.setData('dim', 25, 'current');
|
||||
|
||||
//remove the node
|
||||
MetamapsModel.selectedNodes.splice(
|
||||
MetamapsModel.selectedNodes.indexOf(node), 1);
|
||||
}
|
||||
|
||||
function selectEdge(edge) {
|
||||
if (MetamapsModel.selectedEdges.indexOf(edge) != -1) return;
|
||||
edge.setData('showDesc', true, 'current');
|
||||
if (!MetamapsModel.embed) {
|
||||
edge.setDataset('end', {
|
||||
lineWidth: 4,
|
||||
color: '#FFFFFF',
|
||||
alpha: 1
|
||||
});
|
||||
} else if (MetamapsModel.embed) {
|
||||
edge.setDataset('end', {
|
||||
lineWidth: 4,
|
||||
color: '#999',
|
||||
alpha: 1
|
||||
});
|
||||
}
|
||||
Mconsole.fx.animate({
|
||||
modes: ['edge-property:lineWidth:color:alpha'],
|
||||
duration: 100
|
||||
});
|
||||
MetamapsModel.selectedEdges.push(edge);
|
||||
}
|
||||
|
||||
function deselectEdge(edge) {
|
||||
edge.setData('showDesc', false, 'current');
|
||||
edge.setDataset('end', {
|
||||
lineWidth: 2,
|
||||
color: '#222222',
|
||||
alpha: 0.4
|
||||
});
|
||||
|
||||
if (MetamapsModel.edgeHoveringOver == edge) {
|
||||
edge.setData('showDesc', true, 'current');
|
||||
edge.setDataset('end', {
|
||||
lineWidth: 4,
|
||||
color: '#222222',
|
||||
alpha: 1
|
||||
});
|
||||
}
|
||||
|
||||
Mconsole.fx.animate({
|
||||
modes: ['edge-property:lineWidth:color:alpha'],
|
||||
duration: 100
|
||||
});
|
||||
|
||||
//remove the edge
|
||||
MetamapsModel.selectedEdges.splice(
|
||||
MetamapsModel.selectedEdges.indexOf(edge), 1);
|
||||
}
|
||||
|
||||
// this is for hiding one topic from your canvas
|
||||
function hideNode(nodeid) {
|
||||
var node = Mconsole.graph.getNode(nodeid);
|
||||
if (nodeid == Mconsole.root && gType == "centered") {
|
||||
alert("You can't hide this topic, it is the root of your graph.");
|
||||
return;
|
||||
}
|
||||
|
||||
deselectNode(node);
|
||||
|
||||
node.setData('alpha', 0, 'end');
|
||||
node.eachAdjacency(function (adj) {
|
||||
adj.setData('alpha', 0, 'end');
|
||||
});
|
||||
Mconsole.fx.animate({
|
||||
modes: ['node-property:alpha',
|
||||
'edge-property:alpha'],
|
||||
duration: 1000
|
||||
});
|
||||
Mconsole.graph.removeNode(nodeid);
|
||||
}
|
||||
|
||||
function hideSelectedNodes() {
|
||||
var l = MetamapsModel.selectedNodes.length;
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
var node = MetamapsModel.selectedNodes[i];
|
||||
hideNode(node.id);
|
||||
}
|
||||
}
|
||||
|
||||
function removeNode(nodeid) {
|
||||
var node = Mconsole.graph.getNode(nodeid);
|
||||
deselectNode(node);
|
||||
if (mapperm) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/topics/" + mapid + "/" + nodeid + "/removefrommap",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function removeSelectedNodes() {
|
||||
if (mapperm) {
|
||||
var l = MetamapsModel.selectedNodes.length;
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
var node = MetamapsModel.selectedNodes[i];
|
||||
removeNode(node.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function deleteNode(nodeid) {
|
||||
if (nodeid == Mconsole.root && gType == "centered") {
|
||||
alert("You can't delete this topic, it is the root of your graph.");
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
url: "/topics/" + nodeid,
|
||||
});
|
||||
}
|
||||
|
||||
function deleteSelectedNodes() {
|
||||
var l = MetamapsModel.selectedNodes.length;
|
||||
for (var i = l - 1; i >= 0; i -= 1) {
|
||||
var node = MetamapsModel.selectedNodes[i];
|
||||
deleteNode(node.id);
|
||||
}
|
||||
}
|
|
@ -1,213 +0,0 @@
|
|||
/*
|
||||
* @file
|
||||
* There is a lot of code that goes into creating the "label" of a node
|
||||
* This includes editable cards with all node details, and some controls
|
||||
* onCreateLabelHandler is the main function of this file, and the file
|
||||
* also contains a bunch of helper functions
|
||||
*
|
||||
* html and littleHTML are potentially confusing variables
|
||||
* html is the contents of the card shown when you click on a node's label.
|
||||
* littleHTML creates little controls for removing/hiding nodes from the canvas
|
||||
*
|
||||
* This function features PHP-style variable substitution because the strings
|
||||
* are so damn long. Values are identified by $_id_$, and then a regular
|
||||
* expression is substituted in later (for html, in a separate function).
|
||||
*/
|
||||
|
||||
function buildCardWithHogan(node) {
|
||||
var nodeValues = {};
|
||||
var authorized = authorizeToEdit(node);
|
||||
|
||||
//link is rendered differently if user is logged out or in
|
||||
var go_link, a_tag, close_a_tag;
|
||||
if (!authorized) {
|
||||
go_link = '';
|
||||
if (node.getData("link") != "") {
|
||||
a_tag = '<a href="' + node.getData("link") + '" target="_blank">';
|
||||
close_a_tag = '</a>';
|
||||
} else {
|
||||
a_tag = '';
|
||||
close_a_tag = '';
|
||||
}
|
||||
} else {
|
||||
go_link = '<a href="' + node.getData("link") + '" ' +
|
||||
' class="go-link" target="_blank"></a>';
|
||||
a_tag = '';
|
||||
close_a_tag = '';
|
||||
}
|
||||
|
||||
var desc_nil = "Click to add description...";
|
||||
var link_nil = "Click to add link...";
|
||||
|
||||
nodeValues.permission = node.getData("permission");
|
||||
nodeValues.mk_permission = mk_permission(node);
|
||||
nodeValues.map_count = node.getData("inmaps").length;
|
||||
nodeValues.synapse_count = node.getData("synapseCount");
|
||||
nodeValues.id = node.id;
|
||||
nodeValues.metacode = node.getData("metacode");
|
||||
nodeValues.metacode_class = 'mbg' + node.getData("metacode").replace(/\s/g, '');
|
||||
nodeValues.imgsrc = imgArray[node.getData("metacode")].src;
|
||||
nodeValues.name = node.name;
|
||||
nodeValues.userid = node.getData("userid");
|
||||
nodeValues.username = node.getData("username");
|
||||
nodeValues.date = node.getData("date");
|
||||
|
||||
// the code for this is stored in /views/main/_metacodeOptions.html.erb
|
||||
nodeValues.metacode_select = $('#metacodeOptions').html();
|
||||
nodeValues.go_link = go_link;
|
||||
nodeValues.a_tag = a_tag;
|
||||
nodeValues.close_a_tag = close_a_tag;
|
||||
nodeValues.link_nil = link_nil;
|
||||
nodeValues.link = (node.getData("link") == "" && authorized) ? link_nil : node.getData("link");
|
||||
nodeValues.desc_nil = desc_nil;
|
||||
nodeValues.desc = (node.getData("desc") == "" && authorized) ? desc_nil : node.getData("desc");
|
||||
|
||||
// the code for the template is stored in /views/layouts/_templates.html.erb
|
||||
var hoganTemplate = Hogan.compile($('#topicCardTemplate').html());
|
||||
return hoganTemplate.render(nodeValues);
|
||||
}
|
||||
|
||||
function hideCurrentCard() {
|
||||
if (MetamapsModel.showcardInUse) {
|
||||
var node = Mconsole.graph.getNode(MetamapsModel.showcardInUse);
|
||||
hideCard(node);
|
||||
}
|
||||
}
|
||||
|
||||
function hideCard(node) {
|
||||
var card = '.showcard';
|
||||
|
||||
$(card).fadeOut('fast', function () {
|
||||
//node.setData('dim', 25, 'current');
|
||||
Mconsole.plot();
|
||||
});
|
||||
|
||||
MetamapsModel.showcardInUse = null;
|
||||
}
|
||||
|
||||
function populateShowCard(node) {
|
||||
var showCard = document.getElementById('showcard');
|
||||
|
||||
$(showCard).find('.permission').remove();
|
||||
|
||||
var html = buildCardWithHogan(node);
|
||||
|
||||
if (authorizeToEdit(node)) {
|
||||
var perm = document.createElement('div');
|
||||
|
||||
var string = 'permission canEdit';
|
||||
if (userid == node.data.$userid) string += ' yourTopic';
|
||||
perm.className = string;
|
||||
perm.innerHTML = html;
|
||||
showCard.appendChild(perm);
|
||||
} else {
|
||||
var perm = document.createElement('div');
|
||||
perm.className = 'permission cannotEdit';
|
||||
perm.innerHTML = html;
|
||||
showCard.appendChild(perm);
|
||||
}
|
||||
|
||||
var selectingMetacode = false;
|
||||
// attach the listener that shows the metacode title when you hover over the image
|
||||
$('.showcard .metacodeImage').mouseenter(function () {
|
||||
$('.showcard .icon').css('z-index', '4');
|
||||
$('.showcard .metacodeTitle').show();
|
||||
});
|
||||
$('.showcard .linkItem.icon').mouseleave(function () {
|
||||
if (!selectingMetacode) {
|
||||
$('.showcard .metacodeTitle').hide();
|
||||
$('.showcard .icon').css('z-index', '1');
|
||||
}
|
||||
});
|
||||
|
||||
$('.showcard .metacodeTitle').click(function () {
|
||||
if (!selectingMetacode) {
|
||||
selectingMetacode = true;
|
||||
$(this).addClass('minimize'); // this line flips the drop down arrow to a pull up arrow
|
||||
$('.metacodeSelect').show();
|
||||
// add the scroll bar to the list of metacode select options if it isn't already there
|
||||
if (!$('.metacodeSelect ul').hasClass('mCustomScrollbar')) {
|
||||
$('.metacodeSelect ul').mCustomScrollbar({
|
||||
mouseWheelPixels: 200,
|
||||
advanced: {
|
||||
updateOnContentResize: true
|
||||
}
|
||||
});
|
||||
|
||||
$('.metacodeSelect li').click(function () {
|
||||
selectingMetacode = false;
|
||||
var metacodeName = $(this).find('.mSelectName').text();
|
||||
updateMetacode(node, metacodeName);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
selectingMetacode = false;
|
||||
$(this).removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow
|
||||
$('.metacodeSelect').hide();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// ability to change permission
|
||||
var selectingPermission = false;
|
||||
if (userid == node.data.$userid) {
|
||||
$('.showcard .yourTopic .mapPerm').click(function () {
|
||||
if (!selectingPermission) {
|
||||
selectingPermission = true;
|
||||
$(this).addClass('minimize'); // this line flips the drop down arrow to a pull up arrow
|
||||
if ($(this).hasClass('co')) {
|
||||
$(this).append('<ul class="permissionSelect"><li class="public"></li><li class="private"></li></ul>');
|
||||
} else if ($(this).hasClass('pu')) {
|
||||
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="private"></li></ul>');
|
||||
} else if ($(this).hasClass('pr')) {
|
||||
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="public"></li></ul>');
|
||||
}
|
||||
$('.permissionSelect li').click(function (event) {
|
||||
selectingPermission = false;
|
||||
var permission = $(this).attr('class');
|
||||
updateTopicPermission(node, permission);
|
||||
event.stopPropagation();
|
||||
});
|
||||
} else {
|
||||
selectingPermission = false;
|
||||
$(this).removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow
|
||||
$('.permissionSelect').remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// when you're typing a description, resize the scroll box to have space
|
||||
$('.best_in_place_desc textarea').bind('keyup', function () {
|
||||
var s = $('.showcard').find('.scroll');
|
||||
s.height(s.height()).mCustomScrollbar('update');
|
||||
console.log('working');
|
||||
});
|
||||
|
||||
//bind best_in_place ajax callbacks
|
||||
$(showCard).find('.best_in_place_name').bind("ajax:success", function () {
|
||||
|
||||
var s = $('.showcard').find('.scroll');
|
||||
s.height(s.height()).mCustomScrollbar('update');
|
||||
|
||||
var name = $(this).html();
|
||||
node.name = decodeEntities(name);
|
||||
Mconsole.plot();
|
||||
});
|
||||
|
||||
$(showCard).find('.best_in_place_desc').bind("ajax:success", function () {
|
||||
this.innerHTML = this.innerHTML.replace(/\r/g, '')
|
||||
|
||||
var s = $('.showcard').find('.scroll');
|
||||
s.height(s.height()).mCustomScrollbar('update');
|
||||
|
||||
var desc = $(this).html();
|
||||
node.setData("desc", desc);
|
||||
});
|
||||
|
||||
$(showCard).find('.best_in_place_link').bind("ajax:success", function () {
|
||||
var link = $(this).html();
|
||||
$(showCard).find('.go-link').attr('href', link);
|
||||
node.setData("link", link);
|
||||
});
|
||||
|
||||
}
|
|
@ -10,386 +10,13 @@
|
|||
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
||||
// GO AFTER THE REQUIRES BELOW.
|
||||
//
|
||||
// require autocomplete-rails-uncompressed
|
||||
//
|
||||
//= require jquery
|
||||
//= require jquery-ui
|
||||
//= require jquery.purr
|
||||
//= require jquery.lettering
|
||||
//= require jquery.textillate
|
||||
//= require jquery.roundabout.min
|
||||
//= require bip
|
||||
//= require jquery_ujs
|
||||
//= require_tree .
|
||||
|
||||
// other options are 'graph'
|
||||
var viewMode = "list";
|
||||
|
||||
var labelType, useGradients, nativeTextSupport, animate, json, Mconsole = null,
|
||||
gType, tempNode = null,
|
||||
tempInit = false,
|
||||
tempNode2 = null,
|
||||
metacodeIMGinit = false,
|
||||
goRealtime = false,
|
||||
mapid = null,
|
||||
mapperm = false,
|
||||
touchPos, touchDragNode, mouseIsDown = false;
|
||||
|
||||
|
||||
// this is to save the layout of a map
|
||||
function saveLayoutAll() {
|
||||
$('.sidebarSave .tip').html('Saving...');
|
||||
var coor = "";
|
||||
if (gType == "arranged" || gType == "chaotic") {
|
||||
Mconsole.graph.eachNode(function (n) {
|
||||
coor = coor + n.getData("mappingid") + '/' + n.pos.x + '/' + n.pos.y + ',';
|
||||
});
|
||||
coor = coor.slice(0, -1);
|
||||
$('#map_coordinates').val(coor);
|
||||
$('#saveMapLayout').submit();
|
||||
}
|
||||
}
|
||||
|
||||
// this is to update the location coordinate of a single node on a map
|
||||
function saveLayout(id) {
|
||||
var n = Mconsole.graph.getNode(id);
|
||||
$('#map_coordinates').val(n.getData("mappingid") + '/' + n.pos.x + '/' + n.pos.y);
|
||||
$('#saveMapLayout').submit();
|
||||
dragged = 0;
|
||||
//$('.wandSaveLayout').html('Saved!');
|
||||
//setTimeout(function(){$('.wandSaveLayout').html('Save Layout')},1500);
|
||||
}
|
||||
|
||||
// this is to save your console to a map
|
||||
function saveToMap() {
|
||||
var nodes_data = "",
|
||||
synapses_data = "";
|
||||
var synapses_array = new Array();
|
||||
Mconsole.graph.eachNode(function (n) {
|
||||
//don't add to the map if it was filtered out
|
||||
if (categoryVisible[n.getData('metacode')] == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var x, y;
|
||||
if (n.pos.x && n.pos.y) {
|
||||
x = n.pos.x;
|
||||
y = n.pos.y;
|
||||
} else {
|
||||
var x = Math.cos(n.pos.theta) * n.pos.rho;
|
||||
var y = Math.sin(n.pos.theta) * n.pos.rho;
|
||||
}
|
||||
nodes_data += n.id + '/' + x + '/' + y + ',';
|
||||
n.eachAdjacency(function (adj) {
|
||||
synapses_array.push(adj.getData("id"));
|
||||
});
|
||||
});
|
||||
|
||||
//get unique values only
|
||||
synapses_array = $.grep(synapses_array, function (value, key) {
|
||||
return $.inArray(value, synapses_array) === key;
|
||||
});
|
||||
|
||||
synapses_data = synapses_array.join();
|
||||
nodes_data = nodes_data.slice(0, -1);
|
||||
|
||||
$('#map_topicsToMap').val(nodes_data);
|
||||
$('#map_synapsesToMap').val(synapses_data);
|
||||
openLightbox('forkmap');
|
||||
}
|
||||
|
||||
function fetchRelatives(node) {
|
||||
var myA = $.ajax({
|
||||
type: "Get",
|
||||
url: "/topics/" + node.id + "?format=json",
|
||||
success: function (data) {
|
||||
if (gType == "centered") {
|
||||
Mconsole.busy = true;
|
||||
Mconsole.op.sum(data, {
|
||||
type: 'fade',
|
||||
duration: 500,
|
||||
hideLabels: false
|
||||
});
|
||||
Mconsole.graph.eachNode(function (n) {
|
||||
n.eachAdjacency(function (a) {
|
||||
if (!a.getData('showDesc')) {
|
||||
a.setData('alpha', 0.4, 'start');
|
||||
a.setData('alpha', 0.4, 'current');
|
||||
a.setData('alpha', 0.4, 'end');
|
||||
}
|
||||
});
|
||||
});
|
||||
Mconsole.busy = false;
|
||||
} else {
|
||||
Mconsole.op.sum(data, {
|
||||
type: 'nothing',
|
||||
});
|
||||
Mconsole.plot();
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
console.log('failed to recenter');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// @param node = JIT node object
|
||||
// @param metacode = STRING like "Idea", "Action", etc.
|
||||
function updateMetacode(node, metacode) {
|
||||
var mdata = {
|
||||
"topic": {
|
||||
"metacode": metacode
|
||||
}
|
||||
};
|
||||
$.ajax({
|
||||
type: "PUT",
|
||||
dataType: 'json',
|
||||
url: "/topics/" + node.id,
|
||||
data: mdata,
|
||||
success: function (data) {
|
||||
$('.CardOnGraph').find('.metacodeTitle').text(metacode)
|
||||
.attr('class', 'metacodeTitle mbg' + metacode.replace(/\s/g, ''));
|
||||
$('.CardOnGraph').find('.metacodeImage').css('background-image', 'url(' + imgArray[metacode].src + ')');
|
||||
node.setData("metacode", metacode);
|
||||
Mconsole.plot();
|
||||
$('.metacodeTitle').removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow
|
||||
$('.metacodeSelect').hide();
|
||||
setTimeout(function () {
|
||||
$('.metacodeTitle').hide();
|
||||
$('.showcard .icon').css('z-index', '1');
|
||||
}, 500);
|
||||
},
|
||||
error: function () {
|
||||
console.log('failed to update metacode');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateTopicPermission(node, permission) {
|
||||
var mdata = {
|
||||
"topic": {
|
||||
"permission": permission
|
||||
}
|
||||
};
|
||||
$.ajax({
|
||||
type: "PUT",
|
||||
dataType: 'json',
|
||||
url: "/topics/" + node.id,
|
||||
data: mdata,
|
||||
success: function (data) {
|
||||
$('.showcard .mapPerm').removeClass('co pu pr minimize').addClass(permission.substring(0, 2));
|
||||
$('.permissionSelect').remove();
|
||||
node.setData("permission", permission);
|
||||
},
|
||||
error: function () {
|
||||
console.log('failed to update permission');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateSynapsePermission(edge, permission) {
|
||||
var mdata = {
|
||||
"synapse": {
|
||||
"permission": permission
|
||||
}
|
||||
};
|
||||
$.ajax({
|
||||
type: "PUT",
|
||||
dataType: 'json',
|
||||
url: "/synapses/" + edge.data.$id,
|
||||
data: mdata,
|
||||
success: function (data) {
|
||||
$('#edit_synapse .mapPerm').removeClass('co pu pr minimize').addClass(permission.substring(0, 2));
|
||||
$('#edit_synapse .permissionSelect').remove();
|
||||
edge.setData("permission", permission);
|
||||
},
|
||||
error: function () {
|
||||
console.log('failed to update permission');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateMapPermission(mapid, permission) {
|
||||
var mdata = {
|
||||
"map": {
|
||||
"permission": permission
|
||||
}
|
||||
};
|
||||
$.ajax({
|
||||
type: "PUT",
|
||||
dataType: 'json',
|
||||
url: "/maps/" + mapid,
|
||||
data: mdata,
|
||||
success: function (data) {
|
||||
$('.mapPermission').removeClass('commons public private minimize').addClass(permission);
|
||||
$('.mapPermission .permissionSelect').remove();
|
||||
},
|
||||
error: function () {
|
||||
console.log('failed to update permission');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateMetacodeSet(set, index, custom) {
|
||||
|
||||
if (custom && MetamapsModel.newSelectedMetacodes.length == 0) {
|
||||
alert('Please select at least one metacode to use!');
|
||||
return false;
|
||||
}
|
||||
|
||||
var codesToSwitchTo;
|
||||
MetamapsModel.selectedMetacodeSetIndex = index;
|
||||
MetamapsModel.selectedMetacodeSet = "metacodeset-" + set;
|
||||
|
||||
if (!custom) {
|
||||
codesToSwitchTo = $('#metacodeSwitchTabs' + set).attr('data-metacodes').split(',');
|
||||
$('.customMetacodeList li').addClass('toggledOff');
|
||||
MetamapsModel.selectedMetacodes = [];
|
||||
MetamapsModel.selectedMetacodeNames = [];
|
||||
MetamapsModel.newSelectedMetacodes = [];
|
||||
MetamapsModel.newSelectedMetacodeNames = [];
|
||||
}
|
||||
if (custom) {
|
||||
// uses .slice to avoid setting the two arrays to the same actual array
|
||||
MetamapsModel.selectedMetacodes = MetamapsModel.newSelectedMetacodes.slice(0);
|
||||
MetamapsModel.selectedMetacodeNames = MetamapsModel.newSelectedMetacodeNames.slice(0);
|
||||
codesToSwitchTo = MetamapsModel.selectedMetacodeNames.slice(0);
|
||||
}
|
||||
|
||||
// sort by name
|
||||
codesToSwitchTo.sort();
|
||||
codesToSwitchTo.reverse();
|
||||
|
||||
$('#metacodeImg, #metacodeImgTitle').empty();
|
||||
$('#metacodeImg').removeData('cloudcarousel');
|
||||
var newMetacodes = "";
|
||||
for (var i = 0; i < codesToSwitchTo.length; i++) {
|
||||
newMetacodes += '<img class="cloudcarousel" width="40" height="40" src="' + imgArray[codesToSwitchTo[i]].src + '" title="' + codesToSwitchTo[i] + '" alt="' + codesToSwitchTo[i] + '"/>';
|
||||
};
|
||||
$('#metacodeImg').empty().append(newMetacodes).CloudCarousel({
|
||||
titleBox: $('#metacodeImgTitle'),
|
||||
yRadius: 40,
|
||||
xPos: 150,
|
||||
yPos: 40,
|
||||
speed: 0.3,
|
||||
mouseWheel: true,
|
||||
bringToFront: true
|
||||
});
|
||||
|
||||
$('#lightbox_overlay').hide();
|
||||
$('#topic_name').focus();
|
||||
|
||||
var mdata = {
|
||||
"metacodes": {
|
||||
"value": custom ? MetamapsModel.selectedMetacodes.toString() : MetamapsModel.selectedMetacodeSet
|
||||
}
|
||||
};
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
dataType: 'json',
|
||||
url: "/user/updatemetacodes",
|
||||
data: mdata,
|
||||
success: function (data) {
|
||||
console.log('selected metacodes saved');
|
||||
},
|
||||
error: function () {
|
||||
console.log('failed to save selected metacodes');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cancelMetacodeSetSwitch() {
|
||||
if (MetamapsModel.selectedMetacodeSet != "metacodeset-custom") {
|
||||
$('.customMetacodeList li').addClass('toggledOff');
|
||||
MetamapsModel.selectedMetacodes = [];
|
||||
MetamapsModel.selectedMetacodeNames = [];
|
||||
MetamapsModel.newSelectedMetacodes = [];
|
||||
MetamapsModel.newSelectedMetacodeNames = [];
|
||||
} else { // custom set is selected
|
||||
// reset it to the current actual selection
|
||||
$('.customMetacodeList li').addClass('toggledOff');
|
||||
for (var i = 0; i < MetamapsModel.selectedMetacodes.length; i++) {
|
||||
$('#' + MetamapsModel.selectedMetacodes[i]).removeClass('toggledOff');
|
||||
};
|
||||
// uses .slice to avoid setting the two arrays to the same actual array
|
||||
MetamapsModel.newSelectedMetacodeNames = MetamapsModel.selectedMetacodeNames.slice(0);
|
||||
MetamapsModel.newSelectedMetacodes = MetamapsModel.selectedMetacodes.slice(0);
|
||||
}
|
||||
$('#metacodeSwitchTabs').tabs("select", MetamapsModel.selectedMetacodeSetIndex);
|
||||
$('#topic_name').focus();
|
||||
}
|
||||
|
||||
function MconsoleReset() {
|
||||
|
||||
var tX = Mconsole.canvas.translateOffsetX;
|
||||
var tY = Mconsole.canvas.translateOffsetY;
|
||||
Mconsole.canvas.translate(-tX, -tY);
|
||||
|
||||
var mX = Mconsole.canvas.scaleOffsetX;
|
||||
var mY = Mconsole.canvas.scaleOffsetY;
|
||||
Mconsole.canvas.scale((1 / mX), (1 / mY));
|
||||
}
|
||||
|
||||
function openNodeShowcard(node) {
|
||||
//populate the card that's about to show with the right topics data
|
||||
populateShowCard(node);
|
||||
|
||||
$('.showcard').fadeIn('fast');
|
||||
var s = $('.showcard').find('.scroll');
|
||||
s.height(s.height()).mCustomScrollbar({
|
||||
mouseWheelPixels: 200,
|
||||
advanced: {
|
||||
updateOnContentResize: true
|
||||
}
|
||||
});
|
||||
MetamapsModel.showcardInUse = node.id;
|
||||
}
|
||||
|
||||
function openLightbox(which) {
|
||||
$('.lightboxContent').hide();
|
||||
$('#' + which).show();
|
||||
|
||||
$('#lightbox_overlay').show();
|
||||
$('#lightbox_main').css('margin-top', '-' + ($('#lightbox_main').height() / 2) + 'px');
|
||||
|
||||
if (!MetamapsModel.metacodeScrollerInit) {
|
||||
$('.customMetacodeList, .metacodeSetList').mCustomScrollbar({
|
||||
mouseWheelPixels: 200,
|
||||
advanced: {
|
||||
updateOnContentResize: true
|
||||
}
|
||||
});
|
||||
MetamapsModel.metacodeScrollerInit = true;
|
||||
}
|
||||
if (which == "switchMetacodes") {
|
||||
MetamapsModel.isSwitchingSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
function closeLightbox() {
|
||||
$('#lightbox_overlay').hide();
|
||||
cancelMapCreate('fork_map');
|
||||
cancelMapCreate('new_map');
|
||||
if (MetamapsModel.isSwitchingSet) {
|
||||
cancelMetacodeSetSwitch();
|
||||
MetamapsModel.isSwitchingSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
function cancelMapCreate(id) {
|
||||
|
||||
var form = $('#' + id);
|
||||
|
||||
form.find('#map_name').val('');
|
||||
form.find('#map_desc').val('');
|
||||
form.find('#map_permission').val('commons');
|
||||
|
||||
if (id == "fork_map") {
|
||||
form.find('#map_topicsToMap').val('0');
|
||||
form.find('#map_synapsesToMap').val('0');
|
||||
}
|
||||
form.find('.mapPermIcon').removeClass('selected');
|
||||
form.find('.mapCommonsIcon').addClass('selected');
|
||||
|
||||
return false;
|
||||
}
|
||||
//= require ./orderedLibraries/underscore
|
||||
//= require ./orderedLibraries/backbone
|
||||
//= require_directory ./librariesForAllPages
|
||||
//= require ./metamaps/Metamaps.GlobalUI
|
||||
//= require ./metamaps/Metamaps.Router
|
||||
//= require ./metamaps/Metamaps.Backbone
|
||||
//= require ./metamaps/Metamaps.Views
|
20
app/assets/javascripts/compileMapPages.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
// This is a manifest file that'll be compiled into map.js, which will include all the files
|
||||
// listed below.
|
||||
//
|
||||
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
||||
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
||||
//
|
||||
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||
// the compiled file.
|
||||
//
|
||||
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
||||
// GO AFTER THE REQUIRES BELOW.
|
||||
//
|
||||
//
|
||||
// can't use require directory because underscore needs to come before backbone
|
||||
//
|
||||
//= require ./librariesForMapPages/cloudcarousel
|
||||
//= require ./librariesForMapPages/socket.io
|
||||
//= require ./metamaps/JIT
|
||||
//= require ./metamaps/Metamaps
|
||||
//= require ./metamaps/Metamaps.JIT
|
98
app/assets/javascripts/jquery/AllMappingPages.js
vendored
|
@ -1,98 +0,0 @@
|
|||
/* AllMappingPages means:
|
||||
1. being logged in or logged out and,
|
||||
2. either
|
||||
a. being on a Map page, or
|
||||
b. being on a Topic page
|
||||
|
||||
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
// initialize topic card draggability and resizability
|
||||
$('.showcard').draggable({
|
||||
handle: ".metacodeImage"
|
||||
});
|
||||
$('#showcard').resizable({
|
||||
maxHeight: 500,
|
||||
maxWidth: 500,
|
||||
minHeight: 320,
|
||||
minWidth: 226,
|
||||
resize: function (event, ui) {
|
||||
var p = $('#showcard').find('.scroll');
|
||||
p.height(p.height()).mCustomScrollbar('update');
|
||||
}
|
||||
}).css({
|
||||
display: 'none',
|
||||
top: '300px',
|
||||
left: '100px'
|
||||
});
|
||||
|
||||
function bindFilterHover() {
|
||||
|
||||
var filterIsOpen = false;
|
||||
|
||||
// controls the sliding hover of the bottom left menu
|
||||
var sliding1 = false;
|
||||
var lT;
|
||||
|
||||
var closeFilter = function () {
|
||||
lT = setTimeout(function () {
|
||||
if (!sliding1) {
|
||||
sliding1 = true;
|
||||
$('.sidebarFilterIcon').css('background-color', '#0F1519');
|
||||
$('.sidebarFilterBox').fadeOut(200, function () {
|
||||
sliding1 = false;
|
||||
filterIsOpen = false;
|
||||
});
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
var openFilter = function () {
|
||||
clearTimeout(lT);
|
||||
if (!sliding1) {
|
||||
sliding1 = true;
|
||||
|
||||
// hide the other two
|
||||
$('.sidebarAccountBox').hide();
|
||||
$('.sidebarCollaborateBox').hide();
|
||||
$('.sidebarAccountIcon').css('background-color', '#0F1519');
|
||||
$('.sidebarCollaborateIcon').css('background-color', '#0F1519');
|
||||
|
||||
$('.sidebarFilterIcon').css('background-color', '#000');
|
||||
$('.sidebarFilterBox').fadeIn(200, function () {
|
||||
sliding1 = false;
|
||||
filterIsOpen = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
// bind the hover events
|
||||
$(".sidebarFilter").hover(openFilter, closeFilter);
|
||||
|
||||
} // end bindFilterHover
|
||||
|
||||
bindFilterHover();
|
||||
|
||||
// initialize scroll bar for filter by metacode, then hide it and position it correctly again
|
||||
$("#filter_by_metacode").mCustomScrollbar({
|
||||
mouseWheelPixels: 200,
|
||||
advanced: {
|
||||
updateOnContentResize: true
|
||||
}
|
||||
});
|
||||
$('.sidebarFilterBox').hide().css({
|
||||
position: 'absolute',
|
||||
top: '35px',
|
||||
right: '-36px'
|
||||
});
|
||||
|
||||
// prevent right clicks on the main canvas, so as to not get in the way of our right clicks
|
||||
$('#center-container').bind('contextmenu', function (e) {
|
||||
return false;
|
||||
});
|
||||
|
||||
// tab the cheatsheet
|
||||
$('#cheatSheet').tabs().addClass("ui-tabs-vertical ui-helper-clearfix");
|
||||
$("#cheatSheet .ui-tabs-nav li").removeClass("ui-corner-top").addClass("ui-corner-left");
|
||||
}); // end document.ready
|
|
@ -1,19 +0,0 @@
|
|||
/* AuthAllMappingPages means:
|
||||
1. being logged in and,
|
||||
2. either
|
||||
a. being on a Map page, or
|
||||
b. being on a Topic page
|
||||
|
||||
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
$('.sidebarFork').click(function () {
|
||||
saveToMap();
|
||||
});
|
||||
|
||||
// initialize best_in_place editing
|
||||
$('.authenticated div.permission.canEdit .best_in_place').best_in_place();
|
||||
|
||||
}); // end document.ready
|
|
@ -1,97 +0,0 @@
|
|||
/* authCanEditMapPage means:
|
||||
1. being logged in and,
|
||||
2. being on a Map page and having edit permissions (your map, or commons map)
|
||||
|
||||
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
function bindRealtimeHover() {
|
||||
|
||||
var realtimeIsOpen = false
|
||||
|
||||
// controls the sliding hover of the bottom left menu
|
||||
var sliding1 = false;
|
||||
var lT;
|
||||
|
||||
var closeRealtime = function () {
|
||||
lT = setTimeout(function () {
|
||||
if (!sliding1) {
|
||||
sliding1 = true;
|
||||
$('.sidebarCollaborateIcon').css('background-color', '#0F1519');
|
||||
$('.sidebarCollaborateBox').fadeOut(200, function () {
|
||||
sliding1 = false;
|
||||
realtimeIsOpen = false;
|
||||
});
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
var openRealtime = function () {
|
||||
clearTimeout(lT);
|
||||
if (!sliding1) {
|
||||
sliding1 = true;
|
||||
|
||||
// hide the other two
|
||||
$('.sidebarFilterBox').hide();
|
||||
$('.sidebarAccountBox').hide();
|
||||
$('.sidebarFilterIcon').css('background-color', '#0F1519');
|
||||
$('.sidebarAccountIcon').css('background-color', '#0F1519');
|
||||
|
||||
$('.sidebarCollaborateIcon').css('background-color', '#000');
|
||||
$('.sidebarCollaborateBox').fadeIn(200, function () {
|
||||
sliding1 = false;
|
||||
realtimeIsOpen = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
// bind the hover events
|
||||
$(".sidebarCollaborate").hover(openRealtime, closeRealtime);
|
||||
} // end bindRealtimeHover
|
||||
|
||||
function bindSaveHover() {
|
||||
var closeSave = function () {
|
||||
|
||||
}
|
||||
|
||||
var openSave = function () {
|
||||
// hide the other three
|
||||
$('.sidebarFilterBox, .sidebarAccountBox, .sidebarCollaborateBox').hide();
|
||||
$('.sidebarFilterIcon, .sidebarAccountIcon, .sidebarCollaborateIcon').css('background-color', '#0F1519');
|
||||
}
|
||||
// bind the hover events
|
||||
$(".sidebarSave").hover(openSave, closeSave);
|
||||
} // end bindSaveHover
|
||||
|
||||
// bind hover events
|
||||
bindRealtimeHover();
|
||||
bindSaveHover();
|
||||
|
||||
// because anyone who can edit the map can collaborate on it in realtime
|
||||
$(".realtimeOnOff").click(function (event) {
|
||||
if (!goRealtime) {
|
||||
window.realtime.sendRealtimeOn();
|
||||
$(this).html('ON').removeClass('rtOff').addClass('rtOn');
|
||||
$(".rtMapperSelf").removeClass('littleRtOff').addClass('littleRtOn');
|
||||
} else {
|
||||
window.realtime.sendRealtimeOff();
|
||||
$(this).html('OFF').removeClass('rtOn').addClass('rtOff');
|
||||
$(".rtMapperSelf").removeClass('littleRtOn').addClass('littleRtOff');
|
||||
}
|
||||
goRealtime = !goRealtime;
|
||||
$(".sidebarCollaborateIcon").toggleClass("blue");
|
||||
});
|
||||
|
||||
// because anyone who can edit the map can save a new map layout
|
||||
$('.sidebarSave').click(function () {
|
||||
saveLayoutAll();
|
||||
});
|
||||
|
||||
// because anyone who can edit the map can change the map title
|
||||
$('.mapInfoName .best_in_place_name').bind("ajax:success", function () {
|
||||
var name = $(this).html();
|
||||
$('.mapName').html(name);
|
||||
});
|
||||
|
||||
}); // end document.ready
|
|
@ -1,176 +0,0 @@
|
|||
/* authCanEditMappingPages means:
|
||||
1. being logged in and,
|
||||
2. either
|
||||
a. being on a Map page and having edit permissions (your map, or commons map) or,
|
||||
b. being on a Topic page
|
||||
|
||||
this code adds required jQuery for creating, or pulling in, topics and synapses
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
function bindForkHover() {
|
||||
var closeFork = function () {
|
||||
|
||||
}
|
||||
|
||||
var openFork = function () {
|
||||
// hide the other three
|
||||
$('.sidebarFilterBox, .sidebarAccountBox, .sidebarCollaborateBox').hide();
|
||||
$('.sidebarFilterIcon, .sidebarAccountIcon, .sidebarCollaborateIcon').css('background-color', '#0F1519');
|
||||
}
|
||||
// bind the hover events
|
||||
$(".sidebarFork").hover(openFork, closeFork);
|
||||
} // end bindForkHover
|
||||
|
||||
// bind hover events
|
||||
bindForkHover();
|
||||
|
||||
//////
|
||||
//////
|
||||
//// TOPIC CREATION
|
||||
|
||||
// initialize the autocomplete results for the metacode spinner
|
||||
$('#topic_name').typeahead([
|
||||
{
|
||||
name: 'topic_autocomplete',
|
||||
limit: 8,
|
||||
template: $('#topicAutocompleteTemplate').html(),
|
||||
remote: {
|
||||
url: '/topics/autocomplete_topic?term=%QUERY'
|
||||
},
|
||||
engine: Hogan
|
||||
}
|
||||
]);
|
||||
|
||||
var topicTypeahead = false;
|
||||
// tell the autocomplete to submit the form with the topic you clicked on if you pick from the autocomplete
|
||||
$('#topic_name').bind('typeahead:selected', function (event, datum, dataset) {
|
||||
$('#topic_grabTopic').val(datum.id);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
$('.new_topic').submit();
|
||||
topicTypeahead = true;
|
||||
});
|
||||
$('#topic_name').bind('typeahead:opened', function () {
|
||||
topicTypeahead = false;
|
||||
});
|
||||
|
||||
// bind keyboard handlers
|
||||
$('#topic_name').bind('keyup', function (e) {
|
||||
switch (e.which) {
|
||||
case 13:
|
||||
if (!topicTypeahead) $('.new_topic').submit();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// initialize metacode spinner and then hide it
|
||||
$("#metacodeImg").CloudCarousel({
|
||||
titleBox: $('#metacodeImgTitle'),
|
||||
yRadius: 40,
|
||||
xPos: 150,
|
||||
yPos: 40,
|
||||
speed: 0.3,
|
||||
mouseWheel: true,
|
||||
bringToFront: true
|
||||
});
|
||||
$('.new_topic').hide();
|
||||
|
||||
|
||||
//////
|
||||
//////
|
||||
//// SYNAPSE CREATION
|
||||
|
||||
// initialize the autocomplete results for synapse creation
|
||||
$('#synapse_desc').typeahead([
|
||||
{
|
||||
name: 'synapse_autocomplete',
|
||||
template: "<div>{{label}}</div>",
|
||||
remote: {
|
||||
url: '/search/synapses?term=%QUERY'
|
||||
},
|
||||
engine: Hogan
|
||||
},
|
||||
{
|
||||
name: 'existing_synapses',
|
||||
limit: 50,
|
||||
template: $('#synapseAutocompleteTemplate').html(),
|
||||
remote: {
|
||||
url: '/search/synapses',
|
||||
replace: function () {
|
||||
var q = '/search/synapses?topic1id=' + $('#synapse_topic1id').val() + '&topic2id=' + $('#synapse_topic2id').val();
|
||||
return q;
|
||||
}
|
||||
},
|
||||
engine: Hogan,
|
||||
header: "<h3>Existing Synapses</h3>"
|
||||
},
|
||||
]);
|
||||
|
||||
var synapseTypeahead = false;
|
||||
// tell the autocomplete to submit the form with the topic you clicked on if you pick from the autocomplete
|
||||
$('#synapse_desc').bind('typeahead:selected', function (event, datum, dataset) {
|
||||
if (datum.id) { // if they clicked on an existing synapse get it
|
||||
$('#synapse_grabSynapse').val(datum.id);
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
$('.new_synapse').submit();
|
||||
synapseTypeahead = true;
|
||||
});
|
||||
$('#synapse_desc').bind('typeahead:opened', function () {
|
||||
synapseTypeahead = false;
|
||||
});
|
||||
// bind keyboard handlers
|
||||
$('#synapse_desc').bind('keyup', function (e) {
|
||||
switch (e.which) {
|
||||
case 13:
|
||||
if (!synapseTypeahead) $('.new_synapse').submit();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//////
|
||||
//////
|
||||
//// TOPIC AND SYNAPSE CREATION
|
||||
|
||||
// when either form submits, don't leave the page
|
||||
$('.new_topic, .new_synapse').bind('submit', function (event, data) {
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
// disable right click events on the new topic and new synapse input fields
|
||||
$('#new_topic, #new_synapse').bind('contextmenu', function (e) {
|
||||
return false;
|
||||
});
|
||||
|
||||
//////
|
||||
//////
|
||||
//// SWITCHING METACODE SETS
|
||||
|
||||
$('#metacodeSwitchTabs').tabs({
|
||||
selected: MetamapsModel.selectedMetacodeSetIndex
|
||||
}).addClass("ui-tabs-vertical ui-helper-clearfix");
|
||||
$("#metacodeSwitchTabs .ui-tabs-nav li").removeClass("ui-corner-top").addClass("ui-corner-left");
|
||||
$('.customMetacodeList li').click(function () {
|
||||
if ($(this).attr('class') != 'toggledOff') {
|
||||
$(this).addClass('toggledOff');
|
||||
var value_to_remove = $(this).attr('id');
|
||||
var name_to_remove = $(this).attr('data-name');
|
||||
MetamapsModel.newSelectedMetacodes.splice(MetamapsModel.newSelectedMetacodes.indexOf(value_to_remove), 1);
|
||||
MetamapsModel.newSelectedMetacodeNames.splice(MetamapsModel.newSelectedMetacodeNames.indexOf(name_to_remove), 1);
|
||||
} else if ($(this).attr('class') == 'toggledOff') {
|
||||
$(this).removeClass('toggledOff');
|
||||
MetamapsModel.newSelectedMetacodes.push($(this).attr('id'));
|
||||
MetamapsModel.newSelectedMetacodeNames.push($(this).attr('data-name'));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}); // end document.ready
|
16
app/assets/javascripts/jquery/AuthEveryPage.js
vendored
|
@ -1,16 +0,0 @@
|
|||
/* authEveryPage means:
|
||||
1. being logged in and on any page on metamaps
|
||||
|
||||
this code adds required jQuery for the create map lightBox that can be used from any page on metamaps
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
// bind permission changer events on the createMap form
|
||||
$('.permIcon').click(function () {
|
||||
$(this).siblings('#map_permission').val($(this).attr('data-permission'));
|
||||
$(this).siblings('.permIcon').find('.mapPermIcon').removeClass('selected');
|
||||
$(this).find('.mapPermIcon').addClass('selected');
|
||||
});
|
||||
|
||||
}); // end document.ready
|
|
@ -1,36 +0,0 @@
|
|||
/* AuthMapCreatorMapPage means:
|
||||
1. being on a Map page
|
||||
2. being the original creator of that map
|
||||
|
||||
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
// ability to change permission of the map
|
||||
var selectingPermission = false;
|
||||
$('.yourMap .mapPermission').click(function () {
|
||||
if (!selectingPermission) {
|
||||
selectingPermission = true;
|
||||
$(this).addClass('minimize'); // this line flips the drop down arrow to a pull up arrow
|
||||
if ($(this).hasClass('commons')) {
|
||||
$(this).append('<ul class="permissionSelect"><li class="public"></li><li class="private"></li></ul>');
|
||||
} else if ($(this).hasClass('public')) {
|
||||
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="private"></li></ul>');
|
||||
} else if ($(this).hasClass('private')) {
|
||||
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="public"></li></ul>');
|
||||
}
|
||||
$('.mapPermission .permissionSelect li').click(function (event) {
|
||||
selectingPermission = false;
|
||||
var permission = $(this).attr('class');
|
||||
updateMapPermission(mapid, permission);
|
||||
event.stopPropagation();
|
||||
});
|
||||
} else {
|
||||
selectingPermission = false;
|
||||
$(this).removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow
|
||||
$('.mapPermission .permissionSelect').remove();
|
||||
}
|
||||
});
|
||||
|
||||
}); // end document.ready
|
426
app/assets/javascripts/jquery/EveryPage.js
vendored
|
@ -1,426 +0,0 @@
|
|||
// everything in this document.ready function is here because it is needed on every single page on metamaps
|
||||
$(document).ready(function () {
|
||||
|
||||
function bindMainMenuHover() {
|
||||
|
||||
var menuIsOpen = false
|
||||
|
||||
// controls the sliding hover of the bottom left menu
|
||||
var sliding1 = false;
|
||||
var lT;
|
||||
|
||||
var closeMenu = function () {
|
||||
lT = setTimeout(function () {
|
||||
if (!sliding1) {
|
||||
sliding1 = true;
|
||||
// $('.footer .menu').animate({
|
||||
// height: '0px'
|
||||
// }, 300, function() {
|
||||
// sliding1 = false;
|
||||
// menuIsOpen = false;
|
||||
// });
|
||||
$('.footer').css('border-top-right-radius', '5px');
|
||||
$('.logo').animate({
|
||||
'background-position-x': '-10px'
|
||||
}, 200);
|
||||
$('.footer .menu').fadeOut(200, function () {
|
||||
sliding1 = false;
|
||||
menuIsOpen = false;
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
var openMenu = function () {
|
||||
clearTimeout(lT);
|
||||
if (!sliding1) {
|
||||
sliding1 = true;
|
||||
|
||||
// $('.footer .menu').animate({
|
||||
// height: listLength + 'px'
|
||||
// }, 300, function() {
|
||||
// sliding1 = false;
|
||||
// });
|
||||
$('.footer').css('border-top-right-radius', '0');
|
||||
$('.logo').animate({
|
||||
'background-position-x': '-7px'
|
||||
}, 200);
|
||||
$('.footer .menu').fadeIn(200, function () {
|
||||
sliding1 = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
// bind the hover events
|
||||
$(".logo").hover(openMenu, closeMenu);
|
||||
|
||||
// when on touch screen, make touching on the logo do what hovering does on desktop
|
||||
$("#mainTitle a").bind('touchend', function (evt) {
|
||||
if (!menuIsOpen) {
|
||||
openMenu();
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function bindSearchHover() {
|
||||
|
||||
var searchIsOpen = false
|
||||
|
||||
// controls the sliding hover of the search
|
||||
var sliding1 = false;
|
||||
var lT;
|
||||
|
||||
var openSearch = function () {
|
||||
clearTimeout(lT);
|
||||
if (!sliding1 && !searchIsOpen) {
|
||||
hideCards();
|
||||
sliding1 = true;
|
||||
$('.sidebarSearch .twitter-typeahead, .sidebarSearch .tt-hint, .sidebarSearchField').animate({
|
||||
width: '200px'
|
||||
}, 200, function () {
|
||||
$('.sidebarSearchField, .sidebarSearch .tt-hint').css({
|
||||
padding: '5px 10px',
|
||||
width: '180px'
|
||||
});
|
||||
$('.sidebarSearchField').focus();
|
||||
sliding1 = false
|
||||
searchIsOpen = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
var closeSearch = function (closeAfter, bypass) {
|
||||
lT = setTimeout(function () {
|
||||
if (!sliding1 && searchIsOpen && (bypass || $('.sidebarSearchField').val() == '')) {
|
||||
sliding1 = true;
|
||||
$('.sidebarSearchField, .sidebarSearch .tt-hint').css({
|
||||
padding: '5px 0',
|
||||
width: '200px'
|
||||
});
|
||||
$('.sidebarSearch .twitter-typeahead, .sidebarSearch .tt-hint, .sidebarSearchField').animate({
|
||||
width: '0'
|
||||
}, 200, function () {
|
||||
$('.sidebarSearchField').typeahead('setQuery', '');
|
||||
$('.sidebarSearchField').blur();
|
||||
sliding1 = false;
|
||||
searchIsOpen = false;
|
||||
});
|
||||
}
|
||||
}, closeAfter);
|
||||
}
|
||||
|
||||
// bind the hover events
|
||||
$(".sidebarSearch").hover(function () {
|
||||
openSearch()
|
||||
}, function () {
|
||||
closeSearch(800, false)
|
||||
});
|
||||
|
||||
$('.sidebarSearchIcon').click(function (e) {
|
||||
$('.sidebarSearchField').focus();
|
||||
});
|
||||
$('.sidebarSearch').click(function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
$('body').click(function (e) {
|
||||
closeSearch(0, false);
|
||||
});
|
||||
|
||||
// if the search is closed and user hits ctrl+/
|
||||
// close if they hit ESC
|
||||
$('body').bind('keydown', function (e) {
|
||||
switch (e.which) {
|
||||
case 191:
|
||||
if (e.ctrlKey && !searchIsOpen) {
|
||||
openSearch();
|
||||
}
|
||||
break;
|
||||
case 27:
|
||||
if (searchIsOpen) {
|
||||
closeSearch(0, true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break; //console.log(e.which);
|
||||
}
|
||||
});
|
||||
|
||||
// initialize the search box autocomplete results
|
||||
var mapheader = userid ? '<h3 class="search-header">Maps</h3><input type="checkbox" class="limitToMe" id="limitMapsToMe"></input><label for="limitMapsToMe" class="limitToMeLabel">added by me</label><div class="minimizeResults minimizeMapResults"></div><div class="clearfloat"></div>' : '<h3 class="search-header">Maps</h3><div class="minimizeResults minimizeMapResults"></div><div class="clearfloat"></div>';
|
||||
var topicheader = userid ? '<h3 class="search-header">Topics</h3><input type="checkbox" class="limitToMe" id="limitTopicsToMe"></input><label for="limitTopicsToMe" class="limitToMeLabel">added by me</label><div class="minimizeResults minimizeTopicResults"></div><div class="clearfloat"></div>' : '<h3 class="search-header">Topics</h3><div class="minimizeResults minimizeTopicResults"></div><div class="clearfloat"></div>';
|
||||
$('.sidebarSearchField').typeahead([
|
||||
{
|
||||
name: 'topics',
|
||||
limit: 9999,
|
||||
dupChecker: function (datum1, datum2) {
|
||||
return false;
|
||||
},
|
||||
template: $('#topicSearchTemplate').html(),
|
||||
remote: {
|
||||
url: '/search/topics?term=%QUERY',
|
||||
replace: function () {
|
||||
var q = '/search/topics?term=' + $('.sidebarSearchField').val();
|
||||
if ($("#limitTopicsToMe").is(':checked')) {
|
||||
q += "&user=" + userid.toString();
|
||||
}
|
||||
return q;
|
||||
},
|
||||
filter: function (dataset) {
|
||||
if (dataset.length == 0) {
|
||||
dataset.push({
|
||||
value: "No results",
|
||||
label: "No results",
|
||||
typeImageURL: "/assets/icons/wildcard.png",
|
||||
rtype: "noresult"
|
||||
});
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
},
|
||||
engine: Hogan,
|
||||
header: topicheader
|
||||
},
|
||||
{
|
||||
name: 'maps',
|
||||
limit: 9999,
|
||||
dupChecker: function (datum1, datum2) {
|
||||
return false;
|
||||
},
|
||||
template: $('#mapSearchTemplate').html(),
|
||||
remote: {
|
||||
url: '/search/maps?term=%QUERY',
|
||||
replace: function () {
|
||||
var q = '/search/maps?term=' + $('.sidebarSearchField').val();
|
||||
if ($("#limitMapsToMe").is(':checked')) {
|
||||
q += "&user=" + userid.toString();
|
||||
}
|
||||
return q;
|
||||
},
|
||||
filter: function (dataset) {
|
||||
if (dataset.length == 0) {
|
||||
dataset.push({
|
||||
value: "No results",
|
||||
label: "No results",
|
||||
rtype: "noresult"
|
||||
});
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
},
|
||||
engine: Hogan,
|
||||
header: mapheader
|
||||
},
|
||||
{
|
||||
name: 'mappers',
|
||||
limit: 9999,
|
||||
dupChecker: function (datum1, datum2) {
|
||||
return false;
|
||||
},
|
||||
template: $('#mapperSearchTemplate').html(),
|
||||
remote: {
|
||||
url: '/search/mappers?term=%QUERY',
|
||||
filter: function (dataset) {
|
||||
if (dataset.length == 0) {
|
||||
dataset.push({
|
||||
value: "No results",
|
||||
label: "No results",
|
||||
rtype: "noresult"
|
||||
});
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
},
|
||||
engine: Hogan,
|
||||
header: '<h3 class="search-header">Mappers</h3><div class="minimizeResults minimizeMapperResults"></div><div class="clearfloat"></div>'
|
||||
}
|
||||
]);
|
||||
|
||||
//Set max height of the search results box to prevent it from covering bottom left footer
|
||||
$('.sidebarSearchField').bind('typeahead:opened', function (event) {
|
||||
var h = $(window).height();
|
||||
$(".tt-dropdown-menu").css('max-height', h - 100);
|
||||
});
|
||||
$(window).resize(function () {
|
||||
var h = $(window).height();
|
||||
$(".tt-dropdown-menu").css('max-height', h - 100);
|
||||
});
|
||||
|
||||
|
||||
// tell the autocomplete to launch a new tab with the topic, map, or mapper you clicked on
|
||||
$('.sidebarSearchField').bind('typeahead:selected', function (event, datum, dataset) {
|
||||
console.log(event);
|
||||
if (datum.rtype != "noresult") {
|
||||
var win;
|
||||
if (dataset == "topics") {
|
||||
win = window.open('/topics/' + datum.id, '_blank');
|
||||
} else if (dataset == "maps") {
|
||||
win = window.open('/maps/' + datum.id, '_blank');
|
||||
} else if (dataset == "mappers") {
|
||||
win = window.open('/maps/mappers/' + datum.id, '_blank');
|
||||
}
|
||||
win.focus();
|
||||
closeSearch(0);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var checkboxChangeInit = false,
|
||||
minimizeInit = false;
|
||||
|
||||
$('.sidebarSearchField').bind('keyup', function () {
|
||||
|
||||
// when the user selects 'added by me' resend the query with their userid attached
|
||||
if (!checkboxChangeInit) {
|
||||
$('.limitToMe').bind("change", function (e) {
|
||||
// set the value of the search equal to itself to retrigger the autocomplete event
|
||||
searchIsOpen = false;
|
||||
$('.sidebarSearchField').typeahead('setQuery', $('.sidebarSearchField').val());
|
||||
setTimeout(function () {
|
||||
searchIsOpen = true;
|
||||
}, 2000);
|
||||
});
|
||||
checkboxChangeInit = true;
|
||||
}
|
||||
|
||||
// when the user clicks minimize section, hide the results for that section
|
||||
if (!minimizeInit) {
|
||||
$('.minimizeMapperResults').click(function (e) {
|
||||
var s = $('.tt-dataset-mappers .tt-suggestions');
|
||||
console.log(s.css('height'));
|
||||
if (s.css('height') == '0px') {
|
||||
$('.tt-dataset-mappers .tt-suggestions').css({
|
||||
'height': 'auto',
|
||||
'overflow': 'visible'
|
||||
});
|
||||
$(this).removeClass('maximizeResults').addClass('minimizeResults');
|
||||
} else {
|
||||
$('.tt-dataset-mappers .tt-suggestions').css({
|
||||
'height': '0',
|
||||
'overflow': 'hidden'
|
||||
});
|
||||
$(this).removeClass('minimizeResults').addClass('maximizeResults');
|
||||
}
|
||||
});
|
||||
$('.minimizeTopicResults').click(function (e) {
|
||||
var s = $('.tt-dataset-topics .tt-suggestions');
|
||||
console.log(s.css('height'));
|
||||
if (s.css('height') == '0px') {
|
||||
s.css({
|
||||
'height': 'auto',
|
||||
'border-top': 'none',
|
||||
'overflow': 'visible'
|
||||
});
|
||||
$(this).removeClass('maximizeResults').addClass('minimizeResults');
|
||||
} else {
|
||||
s.css({
|
||||
'height': '0',
|
||||
'border-top': '1px solid rgb(56, 56, 56)',
|
||||
'overflow': 'hidden'
|
||||
});
|
||||
$(this).removeClass('minimizeResults').addClass('maximizeResults');
|
||||
}
|
||||
});
|
||||
$('.minimizeMapResults').click(function (e) {
|
||||
var s = $('.tt-dataset-maps .tt-suggestions');
|
||||
console.log(s.css('height'));
|
||||
if (s.css('height') == '0px') {
|
||||
s.css({
|
||||
'height': 'auto',
|
||||
'border-top': 'none',
|
||||
'overflow': 'visible'
|
||||
});
|
||||
$(this).removeClass('maximizeResults').addClass('minimizeResults');
|
||||
} else {
|
||||
s.css({
|
||||
'height': '0',
|
||||
'border-top': '1px solid rgb(56, 56, 56)',
|
||||
'overflow': 'hidden'
|
||||
});
|
||||
$(this).removeClass('minimizeResults').addClass('maximizeResults');
|
||||
}
|
||||
});
|
||||
minimizeInit = true;
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
$('.sidebarSearch button.addToMap').click(function (event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
} // end bindSearchHover
|
||||
|
||||
function bindAccountHover() {
|
||||
|
||||
var accountIsOpen = false
|
||||
|
||||
// controls the sliding hover of the bottom left menu
|
||||
var sliding1 = false;
|
||||
var lT;
|
||||
|
||||
var closeAccount = function () {
|
||||
lT = setTimeout(function () {
|
||||
if (!sliding1) {
|
||||
sliding1 = true;
|
||||
$('.sidebarAccountIcon').css('background-color', '#0F1519');
|
||||
$('.sidebarAccountBox').fadeOut(200, function () {
|
||||
sliding1 = false;
|
||||
accountIsOpen = false;
|
||||
});
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
var openAccount = function () {
|
||||
clearTimeout(lT);
|
||||
if (!sliding1) {
|
||||
sliding1 = true;
|
||||
|
||||
// hide the other two
|
||||
$('.sidebarFilterBox').hide();
|
||||
$('.sidebarCollaborateBox').hide();
|
||||
$('.sidebarFilterIcon').css('background-color', '#0F1519');
|
||||
$('.sidebarCollaborateIcon').css('background-color', '#0F1519');
|
||||
|
||||
$('.sidebarAccountIcon').css('background-color', '#000');
|
||||
$('.sidebarAccountBox').fadeIn(200, function () {
|
||||
sliding1 = false;
|
||||
accountIsOpen = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
// bind the hover events
|
||||
$(".sidebarAccount").hover(openAccount, closeAccount);
|
||||
} // end bindAccountHover
|
||||
|
||||
// bind hover events
|
||||
bindMainMenuHover();
|
||||
bindSearchHover();
|
||||
bindAccountHover();
|
||||
|
||||
// hide notices after 10 seconds
|
||||
$('.notice.metamaps').delay(10000).fadeOut('fast');
|
||||
$('.alert.metamaps').delay(10000).fadeOut('fast');
|
||||
|
||||
//bind lightbox clicks
|
||||
$('.openLightbox').click(function (event) {
|
||||
openLightbox($(this).attr('data-open'));
|
||||
event.preventDefault();
|
||||
return false;
|
||||
});
|
||||
|
||||
// bind keyboard handlers
|
||||
$('body').bind('keyup', function (e) {
|
||||
switch (e.which) {
|
||||
case 13:
|
||||
enterKeyHandler(e);
|
||||
break;
|
||||
case 27:
|
||||
escKeyHandler();
|
||||
break;
|
||||
default:
|
||||
break; //console.log(e.which);
|
||||
}
|
||||
});
|
||||
|
||||
}); // end document.ready
|
48
app/assets/javascripts/jquery/MapPage.js
vendored
|
@ -1,48 +0,0 @@
|
|||
/* MapPage means:
|
||||
1. being on a Map page
|
||||
|
||||
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
function bindInfoHover() {
|
||||
|
||||
var infoIsOpen = false;
|
||||
|
||||
// controls the sliding hover of the bottom left menu
|
||||
var sliding1 = false;
|
||||
var lT;
|
||||
|
||||
var closeInfo = function () {
|
||||
lT = setTimeout(function () {
|
||||
if (!sliding1) {
|
||||
sliding1 = true;
|
||||
$('.mapInfoBox').fadeOut(200, function () {
|
||||
sliding1 = false;
|
||||
infoIsOpen = false;
|
||||
});
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
var openInfo = function (event) {
|
||||
clearTimeout(lT);
|
||||
if (!sliding1 && event.target.className != "openCheatsheet openLightbox") {
|
||||
sliding1 = true;
|
||||
|
||||
$('.mapInfoBox').fadeIn(200, function () {
|
||||
sliding1 = false;
|
||||
infoIsOpen = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
// bind the hover events
|
||||
$("div.index").hover(openInfo, closeInfo);
|
||||
|
||||
|
||||
} // end bindInfoHover
|
||||
|
||||
bindInfoHover();
|
||||
|
||||
}); // end document.ready
|
12
app/assets/javascripts/librariesForAllPages/canvasloader.min.js
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
(function(w){var k=function(b,c){typeof c=="undefined"&&(c={});this.init(b,c)},a=k.prototype,o,p=["canvas","vml"],f=["oval","spiral","square","rect","roundRect"],x=/^\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/,v=navigator.appVersion.indexOf("MSIE")!==-1&&parseFloat(navigator.appVersion.split("MSIE")[1])===8?true:false,y=!!document.createElement("canvas").getContext,q=true,n=function(b,c,a){var b=document.createElement(b),d;for(d in a)b[d]=a[d];typeof c!=="undefined"&&c.appendChild(b);return b},m=function(b,
|
||||
c){for(var a in c)b.style[a]=c[a];return b},t=function(b,c){for(var a in c)b.setAttribute(a,c[a]);return b},u=function(b,c,a,d){b.save();b.translate(c,a);b.rotate(d);b.translate(-c,-a);b.beginPath()};a.init=function(b,c){if(typeof c.safeVML==="boolean")q=c.safeVML;try{this.mum=document.getElementById(b)!==void 0?document.getElementById(b):document.body}catch(a){this.mum=document.body}c.id=typeof c.id!=="undefined"?c.id:"canvasLoader";this.cont=n("div",this.mum,{id:c.id});if(y)o=p[0],this.can=n("canvas",
|
||||
this.cont),this.con=this.can.getContext("2d"),this.cCan=m(n("canvas",this.cont),{display:"none"}),this.cCon=this.cCan.getContext("2d");else{o=p[1];if(typeof k.vmlSheet==="undefined"){document.getElementsByTagName("head")[0].appendChild(n("style"));k.vmlSheet=document.styleSheets[document.styleSheets.length-1];var d=["group","oval","roundrect","fill"],e;for(e in d)k.vmlSheet.addRule(d[e],"behavior:url(#default#VML); position:absolute;")}this.vml=n("group",this.cont)}this.setColor(this.color);this.draw();
|
||||
m(this.cont,{display:"none"})};a.cont={};a.can={};a.con={};a.cCan={};a.cCon={};a.timer={};a.activeId=0;a.diameter=40;a.setDiameter=function(b){this.diameter=Math.round(Math.abs(b));this.redraw()};a.getDiameter=function(){return this.diameter};a.cRGB={};a.color="#000000";a.setColor=function(b){this.color=x.test(b)?b:"#000000";this.cRGB=this.getRGB(this.color);this.redraw()};a.getColor=function(){return this.color};a.shape=f[0];a.setShape=function(b){for(var c in f)if(b===f[c]){this.shape=b;this.redraw();
|
||||
break}};a.getShape=function(){return this.shape};a.density=40;a.setDensity=function(b){this.density=q&&o===p[1]?Math.round(Math.abs(b))<=40?Math.round(Math.abs(b)):40:Math.round(Math.abs(b));if(this.density>360)this.density=360;this.activeId=0;this.redraw()};a.getDensity=function(){return this.density};a.range=1.3;a.setRange=function(b){this.range=Math.abs(b);this.redraw()};a.getRange=function(){return this.range};a.speed=2;a.setSpeed=function(b){this.speed=Math.round(Math.abs(b))};a.getSpeed=function(){return this.speed};
|
||||
a.fps=24;a.setFPS=function(b){this.fps=Math.round(Math.abs(b));this.reset()};a.getFPS=function(){return this.fps};a.getRGB=function(b){b=b.charAt(0)==="#"?b.substring(1,7):b;return{r:parseInt(b.substring(0,2),16),g:parseInt(b.substring(2,4),16),b:parseInt(b.substring(4,6),16)}};a.draw=function(){var b=0,c,a,d,e,h,k,j,r=this.density,s=Math.round(r*this.range),l,i,q=0;i=this.cCon;var g=this.diameter;if(o===p[0]){i.clearRect(0,0,1E3,1E3);t(this.can,{width:g,height:g});for(t(this.cCan,{width:g,height:g});b<
|
||||
r;){l=b<=s?1-1/s*b:l=0;k=270-360/r*b;j=k/180*Math.PI;i.fillStyle="rgba("+this.cRGB.r+","+this.cRGB.g+","+this.cRGB.b+","+l.toString()+")";switch(this.shape){case f[0]:case f[1]:c=g*0.07;e=g*0.47+Math.cos(j)*(g*0.47-c)-g*0.47;h=g*0.47+Math.sin(j)*(g*0.47-c)-g*0.47;i.beginPath();this.shape===f[1]?i.arc(g*0.5+e,g*0.5+h,c*l,0,Math.PI*2,false):i.arc(g*0.5+e,g*0.5+h,c,0,Math.PI*2,false);break;case f[2]:c=g*0.12;e=Math.cos(j)*(g*0.47-c)+g*0.5;h=Math.sin(j)*(g*0.47-c)+g*0.5;u(i,e,h,j);i.fillRect(e,h-c*0.5,
|
||||
c,c);break;case f[3]:case f[4]:a=g*0.3,d=a*0.27,e=Math.cos(j)*(d+(g-d)*0.13)+g*0.5,h=Math.sin(j)*(d+(g-d)*0.13)+g*0.5,u(i,e,h,j),this.shape===f[3]?i.fillRect(e,h-d*0.5,a,d):(c=d*0.55,i.moveTo(e+c,h-d*0.5),i.lineTo(e+a-c,h-d*0.5),i.quadraticCurveTo(e+a,h-d*0.5,e+a,h-d*0.5+c),i.lineTo(e+a,h-d*0.5+d-c),i.quadraticCurveTo(e+a,h-d*0.5+d,e+a-c,h-d*0.5+d),i.lineTo(e+c,h-d*0.5+d),i.quadraticCurveTo(e,h-d*0.5+d,e,h-d*0.5+d-c),i.lineTo(e,h-d*0.5+c),i.quadraticCurveTo(e,h-d*0.5,e+c,h-d*0.5))}i.closePath();i.fill();
|
||||
i.restore();++b}}else{m(this.cont,{width:g,height:g});m(this.vml,{width:g,height:g});switch(this.shape){case f[0]:case f[1]:j="oval";c=140;break;case f[2]:j="roundrect";c=120;break;case f[3]:case f[4]:j="roundrect",c=300}a=d=c;e=500-d;for(h=-d*0.5;b<r;){l=b<=s?1-1/s*b:l=0;k=270-360/r*b;switch(this.shape){case f[1]:a=d=c*l;e=500-c*0.5-c*l*0.5;h=(c-c*l)*0.5;break;case f[0]:case f[2]:v&&(h=0,this.shape===f[2]&&(e=500-d*0.5));break;case f[3]:case f[4]:a=c*0.95,d=a*0.28,v?(e=0,h=500-d*0.5):(e=500-a,h=
|
||||
-d*0.5),q=this.shape===f[4]?0.6:0}i=t(m(n("group",this.vml),{width:1E3,height:1E3,rotation:k}),{coordsize:"1000,1000",coordorigin:"-500,-500"});i=m(n(j,i,{stroked:false,arcSize:q}),{width:a,height:d,top:h,left:e});n("fill",i,{color:this.color,opacity:l});++b}}this.tick(true)};a.clean=function(){if(o===p[0])this.con.clearRect(0,0,1E3,1E3);else{var b=this.vml;if(b.hasChildNodes())for(;b.childNodes.length>=1;)b.removeChild(b.firstChild)}};a.redraw=function(){this.clean();this.draw()};a.reset=function(){typeof this.timer===
|
||||
"number"&&(this.hide(),this.show())};a.tick=function(b){var a=this.con,f=this.diameter;b||(this.activeId+=360/this.density*this.speed);o===p[0]?(a.clearRect(0,0,f,f),u(a,f*0.5,f*0.5,this.activeId/180*Math.PI),a.drawImage(this.cCan,0,0,f,f),a.restore()):(this.activeId>=360&&(this.activeId-=360),m(this.vml,{rotation:this.activeId}))};a.show=function(){if(typeof this.timer!=="number"){var a=this;this.timer=self.setInterval(function(){a.tick()},Math.round(1E3/this.fps));m(this.cont,{display:"block"})}};
|
||||
a.hide=function(){typeof this.timer==="number"&&(clearInterval(this.timer),delete this.timer,m(this.cont,{display:"none"}))};a.kill=function(){var a=this.cont;typeof this.timer==="number"&&this.hide();o===p[0]?(a.removeChild(this.can),a.removeChild(this.cCan)):a.removeChild(this.vml);for(var c in this)delete this[c]};w.CanvasLoader=k})(window);
|
6
app/assets/javascripts/librariesForAllPages/jquery.embedly.min.js
vendored
Normal file
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,71 @@
|
|||
== SoundManager 2: JavaScript Sound for the Web
|
||||
|
||||
By wrapping and extending HTML5 and Flash Audio APIs, SoundManager 2 brings reliable cross-platform audio to JavaScript.
|
||||
|
||||
== HTML5 Audio() Support
|
||||
|
||||
* 100% Flash-free MP3 + MP4/AAC where supported
|
||||
* Compatible with Apple iPad 3.2, iPhone/iOS 4 and newer
|
||||
* Fallback to Flash for MP3/MP4 support, as needed
|
||||
* SM2 API is transparent; HTML5/flash switching handled internally
|
||||
* HTML5 API support approximates Flash 8 API features
|
||||
* Some other formats (WAV/OGG) supported via HTML5, depending on browser
|
||||
* See "useHTML5Audio" property for implementation details
|
||||
|
||||
== Basic API Features (Flash 8)
|
||||
|
||||
* Load, stop, play, pause, mute, seek, pan and volume control of sounds from Javascript
|
||||
* Events: onload, whileloading, whileplaying, onfinish and more
|
||||
* ID3V1 and ID3V2 tag support for MP3s (title, artist, genre etc.)
|
||||
|
||||
== Shiny Flash 9 Features
|
||||
|
||||
* RTMP / Flash Media Server streaming support (new, experimental)
|
||||
* MPEG-4 (AAC, HE-AAC, H.264) audio support
|
||||
* "MultiShot" play (layered/chorusing effects)
|
||||
* Waveform/frequency spectrum data
|
||||
* Peak (L/R channel volume) data
|
||||
* Audio buffering state/event handling
|
||||
|
||||
== General Tech Stuff
|
||||
|
||||
* Full API Documentation with examples and notes
|
||||
* console.log()-style debug output and troubleshooting tools
|
||||
* Community-based discussion/support
|
||||
|
||||
== As Heard On The Internets
|
||||
|
||||
A few nifty sites that have implemented SM2 for driving audio:
|
||||
|
||||
* SoundCloud / The Cloud Player
|
||||
* last.fm
|
||||
* Opera (media player component)
|
||||
* 8tracks
|
||||
* Discogs
|
||||
* The Hype Machine
|
||||
* nyan.cat
|
||||
* turntable.fm
|
||||
* AudioGalaxy
|
||||
|
||||
== Project home, documentation, live demos etc.:
|
||||
|
||||
http://www.schillmania.com/projects/soundmanager2/
|
||||
|
||||
== Compiling JS builds (-nodebug, -jsmin) and Flash components, AS2/AS3 to SWF
|
||||
|
||||
An Ant build file defines the tasks for compiling JS and SWF components, useful if you make changes to the SM2 source and want to recompile.
|
||||
Google's Closure Compiler is used for the JS. AS2 compilation is done by MTASC, and AS3 is handled by Adobe's Open Source Flex SDK (mxmlc) compiler.
|
||||
Refer to the build.xml file for compiler downloads and path definitions.
|
||||
|
||||
== Versioning / Development Notes
|
||||
|
||||
Releases are versioned by date, e.g., V2.97a.20110424 and are tagged as such.*
|
||||
The latest official release is always on trunk/master.
|
||||
Post-release development builds may be available on the appropriate +DEV branch, eg., V2.97a.20110801+DEV
|
||||
|
||||
== Forks and Pull Requests
|
||||
|
||||
Firstly, thank you for wanting to contribute! Bug fixes and tweaks are welcomed, particularly if they follow the general coding style of the project.
|
||||
If making a pull request, use the project's current +DEV development branch as the merge target instead of "master", if possible (please and thank-you.)
|
||||
|
||||
* SoundManager 2 has been at "version" 2.97 for a long time, because 2.97 was arguably the best llama-ass-whipping version of WinAmp. (WinAmp 3 was not as good, and WinAmp 5 was "the best of 2 and 3 combined.") This MP3 player was my favourite Windows app during the 90's, and is missed as there's nothing quite like it on OS X where I spend most of my time these days.
|
After Width: | Height: | Size: 329 B |
After Width: | Height: | Size: 422 B |
After Width: | Height: | Size: 329 B |
After Width: | Height: | Size: 339 B |
After Width: | Height: | Size: 441 B |
After Width: | Height: | Size: 477 B |
After Width: | Height: | Size: 441 B |
After Width: | Height: | Size: 368 B |
After Width: | Height: | Size: 889 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 881 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1,009 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1,001 B |
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,156 @@
|
|||
/* larger canvas, spectrum + EQ visualization and other items */
|
||||
|
||||
.ui360-vis,
|
||||
.ui360-vis .sm2-360ui,
|
||||
.sm2-inline-list .ui360-vis {
|
||||
/* size of the container for the circle, etc. */
|
||||
width:256px;
|
||||
height:256px;
|
||||
}
|
||||
|
||||
.ui360-vis {
|
||||
position:relative;
|
||||
/* a little extra spacing */
|
||||
padding-top:1px;
|
||||
padding-bottom:1px;
|
||||
margin-bottom:-18px; /* approximate "line height" we want */
|
||||
padding-left:248px;
|
||||
margin-left:0px;
|
||||
background-position:22.6% 50%; /* (~109px) initial play button position */
|
||||
}
|
||||
|
||||
.sm2-inline-list .ui360-vis {
|
||||
cursor:pointer
|
||||
}
|
||||
|
||||
.ui360-vis a {
|
||||
font:14px "helvetica neue",helvetica,monaco,lucida,terminal,monospace;
|
||||
white-space:nowrap;
|
||||
text-indent:0px; /* undo inline style */
|
||||
top:46%; /* ehh. */
|
||||
}
|
||||
|
||||
.sm2-inline-list .ui360-vis a {
|
||||
line-height:256px;
|
||||
top:auto;
|
||||
}
|
||||
|
||||
.ui360-vis .sm2-360ui {
|
||||
margin-left:-256px;
|
||||
}
|
||||
|
||||
.ui360-vis .sm2-timing {
|
||||
font:bold 24px "helvetica neue",helvetica,monaco,lucida,terminal,monospace;
|
||||
color:#333;
|
||||
text-align:center;
|
||||
line-height:256px;
|
||||
text-indent:0px;
|
||||
}
|
||||
|
||||
.sm2-inline-list .ui360-vis,
|
||||
.sm2-inline-list .ui360-vis .sm2-360ui {
|
||||
margin-left:0px;
|
||||
}
|
||||
|
||||
.sm2-inline-list .ui360-vis {
|
||||
margin:8px 13px 7px 0px;
|
||||
padding-left:0px;
|
||||
background-position:50% 50%; /* initial play button position */
|
||||
}
|
||||
|
||||
.sm2-inline-list .ui360-vis .sm2-360ui {
|
||||
border:1px solid #eee;
|
||||
/* offset the border */
|
||||
margin-left:-1px;
|
||||
margin-top:-1px;
|
||||
}
|
||||
|
||||
.sm2-inline-list .ui360-vis a {
|
||||
position:absolute;
|
||||
display:inline;
|
||||
left:0px;
|
||||
bottom:0px;
|
||||
top:1px;
|
||||
width:100%; /* 2px padding in box */
|
||||
height:99%; /* dumb vertical hack */
|
||||
*height:256px; /* IE is dumb. */
|
||||
overflow:hidden;
|
||||
font-size:small;
|
||||
font-weight:300;
|
||||
color:#333;
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
line-height:488px; /* bottom vertical alignment for text */
|
||||
*line-height:480px; /* IE again */
|
||||
text-align:center;
|
||||
border-radius:0px;
|
||||
}
|
||||
|
||||
.sm2-inline-list .ui360 a:hover {
|
||||
background-color:transparent; /* reset */
|
||||
}
|
||||
|
||||
.sm2-inline-list .ui360-vis:hover .sm2-360ui,
|
||||
.sm2-inline-list .ui360-vis a.sm2_link:hover,
|
||||
.sm2-inline-list .ui360-vis a.sm2_link:active,
|
||||
.sm2-inline-list .ui360-vis a.sm2_link:focus {
|
||||
background-color:transparent;
|
||||
}
|
||||
|
||||
.sm2-inline-list .ui360-vis:hover a.sm2_link {
|
||||
background-color:#fafafa;
|
||||
*background-color:transparent; /* eh, screw IE. */
|
||||
}
|
||||
|
||||
/* Use a bigger loading image for this layout */
|
||||
|
||||
.ui360-vis .sm2-360btn,
|
||||
.ui360-vis .sm2-360ui.sm2_paused .sm2-360btn,
|
||||
.ui360-vis .sm2-360ui.sm2_playing .sm2-360btn {
|
||||
width:48px;
|
||||
height:48px;
|
||||
margin-left:-24px;
|
||||
margin-top:-24px;
|
||||
border-radius: none;
|
||||
}
|
||||
|
||||
.ui360-vis,
|
||||
.ui360-vis .sm2-360ui.sm2_paused .sm2-360btn,
|
||||
.ui360-vis .sm2-360btn-default {
|
||||
background:transparent url(360-button-vis-play.png) no-repeat 50% 50%;
|
||||
background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAABuVBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADv7++lpaXr6+uAgIDk5OQzMzPt7e1tbW3n5+dgYGDW1tZNTU10dHQ5OTnw8PCvr6/e3t6JiYlAQEDb29vo6OgrKyuqqqrq6uq4uLjf399AQEDGxsbq6uqAgIDY2Nje3t61tbXp6enU1NTu7u7r6+vl5eXt7e2fn5/n5+fDw8Ph4eHv7+/t7e3CwsLW1tbu7u7b29vw8PDm5uYgICDp6enY2Nji4uLo6Ojm5uakpKTS0tLPz8/h4eHw8PDs7Ozj4+Pa2trg4ODx8fHT09Pk5OTPz8/S0tLBwcGmpqawsLCOjo7h4eHn5+fo6OgAAADY2NjNzc3n5+cAAADd3d3Gxsbu7u7t7e0AAADX19fl5eXi4uLf39/Hx8fn5+fs7Ozg4ODR0dHX19e4uLjv7+/z8/P09PTy8vL19fXv7+/n5+fx8fH29vbs7Ozq6urm5ubo6Ojw8PDu7u7p6enr6+sAAAB/f3/Z2dn39/fh4eGOjo4ODg7t7e3l5eWWlpba2tqjo6NVVVXk5OTe3t65ubnMzMzExMTf39/GxsampqZiYmJNcTiZAAAAbXRSTlMAAQIEAwcFCAb5EdAImAXpB6oIUAoLCfsgZQ0EVrsGEr4ZYQgbsgpUYxikNd/aatQQli+R7rlUUdas6+8I+VaFruoOOV/S8Nq5sWL8UqmKUFsuHyTcrtsJm0z7C49V3NMKkdKXuk7S7oVeVSv7tAAEVwAAAu5JREFUeF6llmVz3DwURmNLsr1pmJmZmZmxzMwsybS8gXJfhl9cKXbHEK+TmZ4P/nDnOXN1NbalHD8CQ7QRGDmhnIQhBDYQnkhheRECSVIQQrLMHookAciUkHhBw1zVwuLShcJIpPDC0uJC1VxDQTaFx1srSvM3DUxU1TRVlWBjM7+0opUrQaupLSnrLK7ELIepwaCYmbiyuLOspJY38eeLykdGxzDhYQfKCmOjI+VFPkMQYF7NZD0l2DgFJrR+siYPegxBzBvqeoQxpgGw8qOuoTz3HGw9udUPCaFZIORhdS5blZOHjXWDBIdABusanb0S4MpqEw4XcNPqCrQFQQTN+XwPQ8CY5jcDUbB3KLdlg6hnQDZacqEgWA3a2rF6Jri9zWohwI6dXXK2QHZ3OqBw0qC7B6vnAPd0sxZMkHr7VNPD34YZgNrXK3EBSgPU9HJ4eIQDDDogQS4ow4QJxy4+MmKs4oYJZFhhggjQuMoKHoHzn3bsQx1HQOTClOkXLP6lviZTtjCjmn7B5g/izqszliBHTB+HDhl3PSJbwnxSS3n45HDkVLXkvCWg5Uws7eHgJ98/uKqxzLI9w3o6oXuwhd+OPNVEet0WtnU9/sWNJfz1u6cY1/VtLghQuRgk/PmBmT7hogJPXo3L8YQed3Nw8PWfuB89Eb8scUGUrl33DfH/N93BGeH6NUnkArh1O5FOuNETp2GR27cAE/iaJu6mz8HdCQnan+i96XQmdgaZ9PQ9+xMVoPJgNhrNhBKNzj5Q+E/AavH4SSz6OZRo7Mlj3oDDp7jyPJoKJfr8CpvAOUrQi6eppJaVZOrpCwTdP1cgr93UjKxoN9dka2KX8ealZtBADO3lG2+e7xRAd7Y0igOg2tYdBKD/CBIBenf/lYGJD2y8uv8OgaBDDkry3v57SlQXhL7f35OlwJOXGUBBl571JykmzCIE02T/s0tIASyf/R6Arr59fcM62G+8fnsVhdwFwq4Ov345Of/15wd0RYY81HHUTQAAAABJRU5ErkJggg==);
|
||||
*background-image:url(360-button-vis-play.png);
|
||||
_background:transparent url(360-button-vis-play.gif) no-repeat 50% 50%;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.ui360-vis:hover .sm2-360btn,
|
||||
.ui360-vis .sm2-360btn-default:hover,
|
||||
.ui360-vis .sm2-360ui.sm2_paused .sm2-360btn:hover {
|
||||
background:transparent url(360-button-vis-play-light.png) no-repeat 50% 50%;
|
||||
_background:transparent url(360-button-vis-play.gif) no-repeat 50% 50%;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
|
||||
.ui360-vis .sm2-360ui.sm2_playing .sm2-360btn:hover,
|
||||
.ui360-vis .sm2-360btn-playing:hover {
|
||||
background:transparent url(360-button-vis-pause-light.png) no-repeat 50% 50%;
|
||||
_background:transparent url(360-button-vis-pause-light.gif) no-repeat 50% 50%;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.ui360-vis {
|
||||
/* non-JS / before-loaded state */
|
||||
background-position: 21% 50%;
|
||||
_background:transparent url(360-button-vis-play.gif) no-repeat 21% 50%; /* IE 6-only: special crap GIF */
|
||||
}
|
||||
|
||||
.ui360-vis .sm2-360btn-default {
|
||||
/* real button, post-loaded state */
|
||||
_background:transparent url(360-button-vis-play.gif) no-repeat 50% 50%; /* IE 6-only: special crap GIF */
|
||||
}
|
||||
|
||||
.ui360-vis .sm2-360ui.sm2_dragging .sm2-360btn {
|
||||
visibility: hidden;
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
/* General warning: Beta-ish. Code could be a bit cleaner. */
|
||||
|
||||
.ui360, /* entire UI */
|
||||
.sm2-360ui { /* canvas container */
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.ui360,
|
||||
.sm2-360ui {
|
||||
min-width:50px; /* should always be at least this. */
|
||||
min-height:50px;
|
||||
}
|
||||
|
||||
.sm2-360ui {
|
||||
width:50px;
|
||||
height:50px;
|
||||
}
|
||||
|
||||
.ui360,
|
||||
.ui360 * {
|
||||
vertical-align:middle;
|
||||
}
|
||||
|
||||
.sm2-360ui {
|
||||
position:relative;
|
||||
display:inline-block; /* firefox 3 et al */
|
||||
float:left; /* IE 6+7, firefox 2 needs this, inline-block would work with fx3 and others */
|
||||
*display:inline;
|
||||
/*
|
||||
clear:left;
|
||||
*/
|
||||
}
|
||||
|
||||
.sm2-360ui.sm2_playing,
|
||||
.sm2-360ui.sm2_paused {
|
||||
/* bump on top when active */
|
||||
z-index:10;
|
||||
}
|
||||
|
||||
.ui360 a { /* .sm2_link class added to playable links by SM2 */
|
||||
float:left;
|
||||
display:inline;
|
||||
position:relative;
|
||||
color:#000;
|
||||
text-decoration:none;
|
||||
left:3px; /* slight spacing on left UI */
|
||||
top:18px; /* vertical align */
|
||||
text-indent:50px; /* make room for UI at left */
|
||||
}
|
||||
|
||||
.ui360 a.sm2_link { /* SM2 has now started */
|
||||
text-indent:0px; /* UI now in place. */
|
||||
}
|
||||
|
||||
.ui360 a,
|
||||
.ui360 a:hover,
|
||||
.ui360 a:focus {
|
||||
padding:2px;
|
||||
margin-left:-2px;
|
||||
margin-top:-2px;
|
||||
}
|
||||
|
||||
.ui360 a:hover,
|
||||
.ui360 a:focus {
|
||||
background:#eee;
|
||||
border-radius:3px;
|
||||
outline:none;
|
||||
}
|
||||
|
||||
.ui360 .sm2-canvas {
|
||||
position:absolute;
|
||||
left:0px;
|
||||
top:0px;
|
||||
}
|
||||
|
||||
.ui360 .sm2-timing {
|
||||
position:absolute;
|
||||
display:block;
|
||||
left:0px;
|
||||
top:0px;
|
||||
width:100%;
|
||||
height:100%;
|
||||
margin:0px;
|
||||
font:11px "helvetica neue",helvetica,monaco,lucida,terminal,monospace;
|
||||
color:#666;
|
||||
text-align:center;
|
||||
line-height:50px;
|
||||
}
|
||||
|
||||
.ui360 .sm2-timing.alignTweak {
|
||||
text-indent:1px; /* devious center-alignment tweak for Safari (might break things for others.) */
|
||||
}
|
||||
|
||||
.ui360 .sm2-cover {
|
||||
position:absolute;
|
||||
left:0px;
|
||||
top:0px;
|
||||
width:100%;
|
||||
height:100%;
|
||||
z-index:2;
|
||||
display:none;
|
||||
background-image: url(data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==); /* old-skool bug: IE 9 won't catch mouse events otherwise. /smash */
|
||||
}
|
||||
|
||||
.ui360 .sm2-360btn {
|
||||
position:absolute;
|
||||
display:block;
|
||||
top:50%;
|
||||
left:50%;
|
||||
/*
|
||||
width:22px;
|
||||
height:22px;
|
||||
margin-left:-11px;
|
||||
margin-top:-11px;
|
||||
*/
|
||||
/* by default, cover whole space. make smaller when playing. */
|
||||
width:50px;
|
||||
height:50px;
|
||||
margin-left:-25px;
|
||||
margin-top:-25px;
|
||||
border-radius: 25px;
|
||||
cursor:pointer;
|
||||
z-index:3;
|
||||
}
|
||||
|
||||
.ui360 .sm2-360data {
|
||||
display:inline-block;
|
||||
font-family:helvetica;
|
||||
}
|
||||
|
||||
.sm2-inline-block .ui360 .sm2-360btn,
|
||||
.ui360 .sm2-360ui.sm2_playing .sm2-360btn,
|
||||
.ui360 .sm2-360ui.sm2_paused .sm2-360btn {
|
||||
/* smaller clickable button, in center */
|
||||
width:22px;
|
||||
height:22px;
|
||||
margin-left:-11px;
|
||||
margin-top:-11px;
|
||||
}
|
||||
|
||||
.ui360 .sm2-360ui.sm2_playing .sm2-cover,
|
||||
.ui360 .sm2-360ui.sm2_paused .sm2-cover {
|
||||
display:block;
|
||||
}
|
||||
|
||||
/* this could be optimized a fair bit. */
|
||||
|
||||
.ui360,
|
||||
.ui360 .sm2-360btn-default,
|
||||
.ui360 .sm2-360ui.sm2_paused .sm2-360btn {
|
||||
background:transparent url(360-button-play.png) no-reoeat;
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAABoUlEQVR42sWVu2oCQRhGU/s8gpVYJeQJNkZSbiH4QNuLlQZS21sJayGYaOEFVFDxNiremj9zig2uzk5YQpKFg8PMd75ZZle9E5Ff4e+Ll8tlQuNoPI2vUcCYOdbIxCmm9F5T0YgNMmS/LebSwWdNa7VayXq9ls1mI9vtVna7nQBj5lgjQxYHN7KY3QkiUbDf7+V4PMrpdArBHGtkyOJc3/n1mVaUUl+F5/PZSrABDi4dpmKH3QkixQEHlw5TsccZmsRCoSD1et1ajkuHqdg/HA5GKZPJCOTzeanVasYMLh2mYsXDIGAoDuG6rlSr1WCdBxrcsTIWazgrQiHS6bSRYJ3XDzeq2O/3+9Ltdm9IpVIhstmslEqlUAY36ii8ZrMpjUbjhmQyKeA4jhSLRWMGN+rhOZ1Oh8ANuVxOyuUy40hwo163RK/XeyPQbrdjgYNr/ILAYDB41Gf1wZnFAQfX+iM0HA5fxuPx+2g0Ej22QoYsDq61mGsymTxMp9NX/Sk2yJDFsRZfXpzXbDZ7WiwW3nw+9zUKGDPHGpkL5V//mn7OJyJZApyzeUS5AAAAAElFTkSuQmCC);
|
||||
*background-image: url(360-button-play.png);
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.ui360 {
|
||||
/*
|
||||
"fake" button shown before SM2 has started, non-JS/non-SM2 case etc.
|
||||
background image will be removed via JS, in threeSixyPlayer.init()
|
||||
*/
|
||||
background-position: 14px 50%;
|
||||
_background:transparent url(360-button-play.gif) no-repeat 14px 50%; /* IE 6-only: special crap GIF */
|
||||
}
|
||||
|
||||
.ui360 .sm2-360btn-default,
|
||||
.ui360 .sm2-360ui.sm2_paused .sm2-360btn {
|
||||
background-position:50% 50%;
|
||||
_background:transparent url(360-button-play.gif) no-repeat 50% 50%; /* IE 6-only: special crap GIF */
|
||||
}
|
||||
|
||||
.ui360 .sm2-360btn-default,
|
||||
.ui360 .sm2-360ui.sm2_paused .sm2-360btn {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.ui360 .sm2-360btn-default:hover,
|
||||
.ui360 .sm2-360ui.sm2_paused .sm2-360btn:hover {
|
||||
background:transparent url(360-button-play-light.png) no-repeat 50% 50%;
|
||||
_background:transparent url(360-button-play.gif) no-repeat 50% 50%;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.ui360 .sm2-360ui.sm2_playing .sm2-360btn:hover,
|
||||
.ui360 .sm2-360btn-playing:hover {
|
||||
background:transparent url(360-button-pause-light.png) no-repeat 50% 50%;
|
||||
_background:transparent url(360-button-pause-light.gif) no-repeat 50% 50%;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.ui360 .sm2-360ui.sm2_playing .sm2-timing {
|
||||
visibility:visible;
|
||||
}
|
||||
|
||||
.ui360 .sm2-360ui.sm2_buffering .sm2-timing {
|
||||
visibility:hidden;
|
||||
}
|
||||
|
||||
.ui360 .sm2-360ui .sm2-timing,
|
||||
.ui360 .sm2-360ui .sm2-360btn:hover + .sm2-timing,
|
||||
.ui360 .sm2-360ui.sm2_paused .sm2-timing {
|
||||
visibility:hidden;
|
||||
}
|
||||
|
||||
.ui360 .sm2-360ui.sm2_dragging .sm2-timing,
|
||||
.ui360 .sm2-360ui.sm2_dragging .sm2-360btn:hover + .sm2-timing {
|
||||
/* paused + dragging */
|
||||
visibility:visible;
|
||||
}
|
||||
|
||||
.ui360 .sm2-360ui.sm2_playing .sm2-360btn,
|
||||
.ui360 .sm2-360ui.sm2_dragging .sm2-360btn,
|
||||
.ui360 .sm2-360ui.sm2_dragging .sm2-360btn:hover,
|
||||
.ui360 .sm2-360ui.sm2_dragging .sm2-360btn-playing:hover {
|
||||
/* don't let pause button show on hover when dragging (or paused and dragging) */
|
||||
background:transparent;
|
||||
cursor:auto;
|
||||
}
|
||||
|
||||
.ui360 .sm2-360ui.sm2_buffering .sm2-360btn,
|
||||
.ui360 .sm2-360ui.sm2_buffering .sm2-360btn:hover {
|
||||
background:transparent url(icon_loading_spinner.gif) no-repeat 50% 50%;
|
||||
opacity:0.5;
|
||||
visibility:visible;
|
||||
}
|
||||
|
||||
/* inline list style */
|
||||
|
||||
.sm2-inline-list .ui360,
|
||||
.sm2-inline-block .ui360 {
|
||||
position:relative;
|
||||
display:inline-block;
|
||||
float:left;
|
||||
_display:inline;
|
||||
margin-bottom:-15px;
|
||||
}
|
||||
|
||||
.sm2-inline-list .ui360 {
|
||||
/* inline player: minor tweak, tighten spacing */
|
||||
margin-right:-2px;
|
||||
}
|
||||
|
||||
.sm2-inline-block .ui360 {
|
||||
margin-right:8px;
|
||||
}
|
||||
|
||||
.sm2-inline-list .ui360 a {
|
||||
display:none;
|
||||
}
|
||||
|
||||
/* annotations */
|
||||
|
||||
ul.ui360playlist {
|
||||
list-style-type:none;
|
||||
}
|
||||
|
||||
ul.ui360playlist,
|
||||
ul.ui360playlist li {
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
}
|
||||
|
||||
div.ui360 div.metadata {
|
||||
display:none;
|
||||
}
|
||||
|
||||
div.ui360 a span.metadata,
|
||||
div.ui360 a span.metadata * {
|
||||
/* name of track, note etc. */
|
||||
vertical-align:baseline;
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
||||
<head>
|
||||
<title>360° MP3 player UI demo (SoundManager 2): Javascript + Canvas Visualization, basic example</title>
|
||||
<meta name="robots" content="noindex" />
|
||||
<meta name="description" content="Basic example of 360-degree circular control for MP3 links, with EQ and spectrum visualization options" />
|
||||
<!-- demo: make the fonts nicer etc. -->
|
||||
<link rel="stylesheet" type="text/css" href="../index.css" />
|
||||
|
||||
<!-- soundManager.useFlashBlock: related CSS -->
|
||||
<link rel="stylesheet" type="text/css" href="../flashblock/flashblock.css" />
|
||||
|
||||
<!-- required -->
|
||||
<link rel="stylesheet" type="text/css" href="360player.css" />
|
||||
<link rel="stylesheet" type="text/css" href="360player-visualization.css" />
|
||||
|
||||
<!-- special IE-only canvas fix -->
|
||||
<!--[if IE]><script type="text/javascript" src="script/excanvas.js"></script><![endif]-->
|
||||
|
||||
<!-- Apache-licensed animation library -->
|
||||
<script type="text/javascript" src="script/berniecode-animator.js"></script>
|
||||
|
||||
<!-- the core stuff -->
|
||||
<script type="text/javascript" src="../../script/soundmanager2.js"></script>
|
||||
<script type="text/javascript" src="script/360player.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
soundManager.setup({
|
||||
// path to directory containing SM2 SWF
|
||||
url: '../../swf/'
|
||||
});
|
||||
|
||||
threeSixtyPlayer.config.scaleFont = (navigator.userAgent.match(/msie/i)?false:true);
|
||||
threeSixtyPlayer.config.showHMSTime = true;
|
||||
|
||||
// enable some spectrum stuffs
|
||||
|
||||
threeSixtyPlayer.config.useWaveformData = true;
|
||||
threeSixtyPlayer.config.useEQData = true;
|
||||
|
||||
// enable this in SM2 as well, as needed
|
||||
|
||||
if (threeSixtyPlayer.config.useWaveformData) {
|
||||
soundManager.flash9Options.useWaveformData = true;
|
||||
}
|
||||
if (threeSixtyPlayer.config.useEQData) {
|
||||
soundManager.flash9Options.useEQData = true;
|
||||
}
|
||||
if (threeSixtyPlayer.config.usePeakData) {
|
||||
soundManager.flash9Options.usePeakData = true;
|
||||
}
|
||||
|
||||
if (threeSixtyPlayer.config.useWaveformData || threeSixtyPlayer.flash9Options.useEQData || threeSixtyPlayer.flash9Options.usePeakData) {
|
||||
// even if HTML5 supports MP3, prefer flash so the visualization features can be used.
|
||||
soundManager.preferFlash = true;
|
||||
}
|
||||
|
||||
// favicon is expensive CPU-wise, but can be enabled.
|
||||
threeSixtyPlayer.config.useFavIcon = false;
|
||||
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="demo.css" />
|
||||
<style type="text/css">
|
||||
|
||||
#left h2 {
|
||||
padding-top:0px;
|
||||
margin-bottom:0.25em;
|
||||
color:#666;
|
||||
}
|
||||
|
||||
pre.block {
|
||||
margin-top:0.5em;
|
||||
}
|
||||
|
||||
/* special case */
|
||||
|
||||
#left {
|
||||
width:auto;
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="left">
|
||||
|
||||
<h1><a href="http://schillmania.com/projects/soundmanager2/demo/360-player/">360° Player Demo</a> - Visualization Example, Basic Template</h1>
|
||||
|
||||
<p class="note" style="color:#666;margin-bottom:0.5em">Canvas-based UI with visualization options. <b>Note: No EQ/spectrum support for IE < 9 (too slow.) Data not implemented in HTML5.</b></p>
|
||||
|
||||
<div style="clear:left"></div>
|
||||
|
||||
<div id="sm2-container">
|
||||
<!-- sm2 flash goes here -->
|
||||
</div>
|
||||
|
||||
<!-- here are the MP3 links, which are decorated with the 360 canvas element/UI etc. -->
|
||||
|
||||
<h2 style="margin-top:1em">Inline list</h2>
|
||||
|
||||
<div class="sm2-inline-list"> <!-- remove this class to have one item per line -->
|
||||
|
||||
<div class="ui360 ui360-vis"><a href="../../demo/mpc/audio/CRASH_1.mp3">Crash 1</a></div>
|
||||
<div class="ui360 ui360-vis"><a href="../../demo/mpc/audio/CRASH_5.mp3">Crash 5</a></div>
|
||||
<div class="ui360 ui360-vis"><a href="../../demo/mpc/audio/CRASH_6.mp3">Crash 6</a></div>
|
||||
<div class="ui360 ui360-vis"><a href="../../demo/mpc/audio/CHINA_1.mp3">China 1</a></div>
|
||||
|
||||
</div>
|
||||
|
||||
<h2 style="clear:both;padding-top:1em">Block list</h2>
|
||||
|
||||
<div>
|
||||
<div class="ui360 ui360-vis"><a href="../../demo/_mp3/sine,%20square,%20sawtooth,%20rando.mp3">Sine, Square, Sawtooth, Wave (Warning: LOUD)</a></div>
|
||||
<div class="ui360 ui360-vis"><a href="../../demo/_mp3/1hz-10khz-sweep.mp3">1-10 Khz Sweep (Warning: LOUD)</a></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<p style="margin-left:1em">
|
||||
<a href="http://www.schillmania.com/projects/soundmanager2/" title="SoundManager 2 home">SoundManager 2 project page</a> (not an MP3 link)
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,359 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
||||
<head>
|
||||
<title>360° MP3 player UI demo (SoundManager 2): Javascript + Canvas Visualization</title>
|
||||
<meta name="robots" content="noindex" />
|
||||
<meta name="description" content="Javascript + Canvas + SoundManager 2: 360-degree circular control / jog wheel example for playing MP3 links, with EQ and spectrum visualization options" />
|
||||
<!-- demo, make the fonts nicer etc. -->
|
||||
<link rel="stylesheet" type="text/css" href="../index.css" />
|
||||
|
||||
<!-- soundManager.useFlashBlock: related CSS -->
|
||||
<link rel="stylesheet" type="text/css" href="../flashblock/flashblock.css" />
|
||||
|
||||
<!-- required -->
|
||||
<link rel="stylesheet" type="text/css" href="360player.css" />
|
||||
<link rel="stylesheet" type="text/css" href="360player-visualization.css" />
|
||||
|
||||
<!-- special IE-only canvas fix -->
|
||||
<!--[if IE]><script type="text/javascript" src="script/excanvas.js"></script><![endif]-->
|
||||
|
||||
<!-- Apache-licensed animation library -->
|
||||
<script type="text/javascript" src="script/berniecode-animator.js"></script>
|
||||
|
||||
<!-- the core stuff -->
|
||||
<script type="text/javascript" src="../../script/soundmanager2.js"></script>
|
||||
<script type="text/javascript" src="script/360player.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
soundManager.setup({
|
||||
// path to directory containing SM2 SWF
|
||||
url: '../../swf/'
|
||||
});
|
||||
|
||||
threeSixtyPlayer.config.scaleFont = (navigator.userAgent.match(/msie/i)?false:true);
|
||||
threeSixtyPlayer.config.showHMSTime = true;
|
||||
|
||||
// enable some spectrum stuffs
|
||||
|
||||
threeSixtyPlayer.config.useWaveformData = true;
|
||||
threeSixtyPlayer.config.useEQData = true;
|
||||
|
||||
// enable this in SM2 as well, as needed
|
||||
|
||||
if (threeSixtyPlayer.config.useWaveformData) {
|
||||
soundManager.flash9Options.useWaveformData = true;
|
||||
}
|
||||
if (threeSixtyPlayer.config.useEQData) {
|
||||
soundManager.flash9Options.useEQData = true;
|
||||
}
|
||||
if (threeSixtyPlayer.config.usePeakData) {
|
||||
soundManager.flash9Options.usePeakData = true;
|
||||
}
|
||||
|
||||
if (threeSixtyPlayer.config.useWaveformData || threeSixtyPlayer.flash9Options.useEQData || threeSixtyPlayer.flash9Options.usePeakData) {
|
||||
// even if HTML5 supports MP3, prefer flash so the visualization features can be used.
|
||||
soundManager.preferFlash = true;
|
||||
}
|
||||
|
||||
// favicon is expensive CPU-wise, but can be used.
|
||||
if (window.location.href.match(/hifi/i)) {
|
||||
threeSixtyPlayer.config.useFavIcon = true;
|
||||
}
|
||||
|
||||
if (window.location.href.match(/html5/i)) {
|
||||
// for testing IE 9, etc.
|
||||
soundManager.useHTML5Audio = true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<!-- DEMO only, customization UI: Yahoo! YUI colorpicker stuff -->
|
||||
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.7.0/build/slider/assets/skins/sam/slider.css" />
|
||||
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.7.0/build/colorpicker/assets/skins/sam/colorpicker.css" />
|
||||
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/yahoo-dom-event/yahoo-dom-event.js"></script>
|
||||
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/animation/animation-min.js"></script>
|
||||
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/dragdrop/dragdrop-min.js"></script>
|
||||
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/slider/slider-min.js"></script>
|
||||
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/element/element-min.js"></script>
|
||||
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/colorpicker/colorpicker-min.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="demo.css" />
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
#left h2 {
|
||||
padding-top:0px;
|
||||
margin-bottom:0.25em;
|
||||
color:#666;
|
||||
}
|
||||
|
||||
pre.block {
|
||||
margin-top:0.5em;
|
||||
}
|
||||
|
||||
/* special case */
|
||||
|
||||
#left {
|
||||
width:auto;
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
.ui360 span {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<!-- demo configuration stuff, you don't need this -->
|
||||
<link rel="stylesheet" type="text/css" href="demo-slider-controls.css" />
|
||||
<script type="text/javascript" src="demo-slider-controls.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="left">
|
||||
|
||||
<h1><a href="http://www.schillmania.com/projects/soundmanager2/" title="Javascript MP3 player project home">SoundManager 2</a> / <a href="http://schillmania.com/projects/soundmanager2/demo/360-player/">360° Player Demo</a>: JS + Canvas Visualization</h1>
|
||||
|
||||
<p class="note" style="color:#666;margin-top:0.5em;margin-bottom:0.5em">Canvas-based UI with visualization options. <b>Note: Spectrum/EQ visualizations disabled for IE < 9 (too slow.) Data is not implemented under HTML5.</b></p>
|
||||
<p class="note" style="color:#666;margin-bottom:0.5em">You can also <a href="#debug=1" onclick="window.location.href = this.href;window.location.reload()" title="Enable debug mode, show frames per second">show FPS</a><span id="config-link"> or <a href="#customize" onclick="window.location.href=this.href;window.location.reload()">customize the UI</a></span><span id="hifi">, or see the <a href="#hifi=1" onclick="window.location.href=this.href;window.location.reload()">hi-fi version</a></span>. Check the <a href="canvas-visualization-basic.html">basic template</a> for a minimal code example; also see the <a href="../360-player/" title="360° player UI">default 360° UI</a>.</p>
|
||||
|
||||
<!-- customization crap -->
|
||||
|
||||
<div id="config-ui" style="clear:both;position:relative;max-width:1110px;margin-top:1em;display:none">
|
||||
|
||||
<div style="position:relative">
|
||||
|
||||
<form action="#" method="get">
|
||||
|
||||
<div id="controls">
|
||||
|
||||
<div class="checkbox">
|
||||
<div>
|
||||
<input id="use-waveform" type="checkbox" checked="checked" title="Enable waveform feature." onclick="controller.updateExample();controller.updateExampleCode()" value="Apply" /> Waveform
|
||||
<input id="disabled-1" type="checkbox" title="Enable EQ (spectrum) feature." onclick="controller.updateExample();controller.updateExampleCode()" value="Apply" style="margin-left:1em" checked="checked" /> EQ
|
||||
<input type="checkbox" name="use-amplifier" id="use-amplifier" checked="checked" onclick="controller.updateExample();controller.updateExampleCode()" style="margin-left:1em"> Amplifier
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="clear:left"></div>
|
||||
|
||||
<dl class="col">
|
||||
|
||||
<dt>Circle Diameter</dt>
|
||||
<dd class="title">Size</dd>
|
||||
<dd>1-256</dd>
|
||||
<dd class="control">
|
||||
<div class="bar" title="Click to move here"></div>
|
||||
<div class="slider" title="Size of circle"></div>
|
||||
</dd>
|
||||
|
||||
<dt>Waveform Thickness</dt>
|
||||
<dd class="title">thickness</dd>
|
||||
<dd>1-100</dd>
|
||||
<dd class="control">
|
||||
<div class="bar" title="Click to move here"></div>
|
||||
<div class="slider" title="Thickness of line"></div>
|
||||
</dd>
|
||||
|
||||
<dt>Wave Downsample</dt>
|
||||
<dd class="title">(Scale)</dd>
|
||||
<dd>1-16</dd>
|
||||
<dd class="control">
|
||||
<div class="bar" title="Click to move here"></div>
|
||||
<div class="slider" title="Amount to downsample waveform data by"></div>
|
||||
</dd>
|
||||
|
||||
<dt>EQ Thickness</dt>
|
||||
<dd class="title">thickness</dd>
|
||||
<dd>1-50</dd>
|
||||
<dd class="control">
|
||||
<div class="bar" title="Click to move here"></div>
|
||||
<div class="slider" title="Thickness of line"></div>
|
||||
</dd>
|
||||
|
||||
<dt>EQ Downsample</dt>
|
||||
<dd class="title">(Scale)</dd>
|
||||
<dd>1-16</dd>
|
||||
<dd class="control">
|
||||
<div class="bar" title="Click to move here"></div>
|
||||
<div class="slider" title="Amount to downsample EQ data by"></div>
|
||||
</dd>
|
||||
|
||||
<dt>Ring Thickness</dt>
|
||||
<dd class="title">(Scale)</dd>
|
||||
<dd>1-200</dd>
|
||||
<dd class="control">
|
||||
<div class="bar" title="Click to move here"></div>
|
||||
<div class="slider" title="Scale factor for the ring width"></div>
|
||||
</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
<div id="options" class="col">
|
||||
|
||||
<div>
|
||||
Waveform position:
|
||||
<input type="radio" name="waveform-inside" id="waveform-inside" value="true" checked="checked" onclick="controller.updateExample();controller.updateExampleCode()"> Inside | <input type="radio" name="waveform-inside" id="waveform-inside" value="false" onclick="controller.updateExample();controller.updateExampleCode()"> Outside
|
||||
</div>
|
||||
|
||||
<div>
|
||||
EQ position:
|
||||
<input type="radio" name="eq-inside" id="eq-inside" value="true" onclick="controller.updateExample();controller.updateExampleCode()"> Inside | <input type="radio" name="eq-inside" id="eq-inside" value="false" checked="checked" onclick="controller.updateExample();controller.updateExampleCode()"> Outside
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Waveform color:
|
||||
<input type="text" name="waveform-color" id="waveform-color" value="#000000" onclick="createCP(this,setWaveformColor)" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
EQ color:
|
||||
<input type="text" name="eq-color" id="eq-color" value="#000000" onclick="createCP(this,setEQColor)" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Loaded ring color:
|
||||
<input type="text" name="loaded-ring-color" id="loaded-ring-color" value="#000000" onclick="createCP(this,setLoadedRingColor)" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Progress ring color:
|
||||
<input type="text" name="progress-ring-color" id="progress-ring-color" value="#000000" onclick="createCP(this,setProgressRingColor)" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Background ring color:
|
||||
<input type="text" name="bg-ring-color" id="bg-ring-color" value="#000000" onclick="createCP(this,setBackgroundRingColor)" />
|
||||
</div>
|
||||
|
||||
<p class="compact">
|
||||
<input type="button" onclick="controller.randomize()" value="Randomize controls" title="Assign random control values" style="font-size:x-small" />
|
||||
</p>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="cp-container">
|
||||
<!-- color picker stuff goes here -->
|
||||
</div>
|
||||
|
||||
<div id="config-code-block" style="float:right;display:inline;margin-left:1em;margin-top:-0.7em">
|
||||
<!--
|
||||
<pre id="config-link" class="block"><code style="cursor:pointer" onclick="document.getElementById('config-link').style.display='none';document.getElementById('config-pre-block').style.display='block';return false"> [click to show code] </code></pre>
|
||||
-->
|
||||
<pre id="config-pre-block" class="block"><code id="config-code">Code goes here</code></pre>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<p style="clear:left">Get a sound playing, then adjust the values to see real-time updates.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- here are the MP3 links, which are decorated with the 360 canvas element/UI etc. -->
|
||||
|
||||
<div id="sm2-container">
|
||||
<!-- sm2 flash goes here -->
|
||||
</div>
|
||||
|
||||
<h2 style="margin-top:1em">Inline list</h2>
|
||||
|
||||
<div class="sm2-inline-list"> <!-- remove this class to have one item per line -->
|
||||
|
||||
<div class="ui360 ui360-vis"><a href="http://freshly-ground.com/data/audio/sm2/The%20Fugitives%20-%20Graffiti%20Sex.mp3">The Fugitives - Graffiti Sex</a></div>
|
||||
<div class="ui360 ui360-vis"><a href="http://freshly-ground.com/data/audio/sm2/Adrian%20Glynn%20-%20Blue%20Belle%20Lament.mp3">Adrian Glynn - Blue Belle Lament</a></div>
|
||||
<div class="ui360 ui360-vis"><a href="http://freshly-ground.com/data/audio/sm2/SonReal%20-%20I%20Tried.mp3">SonReal - I Tried</a></div>
|
||||
<div class="ui360 ui360-vis"><a href="http://freshly-ground.com/data/audio/sm2/SonReal%20-%20People%20Asking.mp3">SonReal - People Asking</a></div>
|
||||
<div class="ui360 ui360-vis"><a href="http://freshly-ground.com/data/audio/mpc/20060826%20-%20Armstrong.mp3">20060826 - Armstrong Groove</a></div>
|
||||
|
||||
</div>
|
||||
|
||||
<p class="note medium-note" style="clear:both"><b>Artist thank-yous</b>: "Graffiti Sex" courtesy of <a href="http://www.fugitives.ca/" title="A group of musicians, poets, and multi-instrumentalists from Vancouver, Canada">The Fugitives</a>. "Blue Belle Lament" courtesy of <a href="http://www.adrianglynn.com/" title="Adrian Glynn, Vancouver-based Singer/Songwriter">Adrian Glynn</a>. "I Tried" and "People Asking" courtesy of <a href="http://sonreal.bandcamp.com/album/the-lightyear-mixtape" title="The Lightyear Mixtape from SonReal, Vancouver-based hip-hop artist">SonReal</a>.</p>
|
||||
|
||||
<h2 style="clear:left;padding-top:1em">Block list</h2>
|
||||
|
||||
<div>
|
||||
<div class="ui360 ui360-vis"><a href="http://freshly-ground.com/data/audio/mpc/20090207%20-%20Loverman.mp3">20090207 - Loverman</a></div>
|
||||
<div class="ui360 ui360-vis"><a href="http://freshly-ground.com/data/audio/sm2/dialup.mp3">56K Modem dial-up sound (Warning: <span style="color:#ff3333">LOUD</span>)</a></div>
|
||||
<div class="ui360 ui360-vis"><a href="../../demo/_mp3/1hz-10khz-sweep.mp3">1-10 Khz Sweep (Warning: <span style="color:#ff3333">LOUD</span>)</a></div>
|
||||
<div class="ui360 ui360-vis"><a href="../../demo/_mp3/sine,%20square,%20sawtooth,%20rando.mp3">Sine, Square, Sawtooth, Wave (Warning: <span style="color:#ff3333">LOUD</span>)</a></div>
|
||||
</div>
|
||||
|
||||
<p class="note medium-note" style="clear:left">56K Modem sound (Creative Commons license) via <a href="http://www.freesound.org/samplesViewSingle.php?id=16475">dialup.mp3</a>, from freesound.org user <a href="http://www.freesound.org/usersViewSingle.php?id=54447">Jlew</a>.</p>
|
||||
|
||||
|
||||
<h2 style="clear:left;padding-top:1em">Variant: Annotations/meta-data</h2>
|
||||
|
||||
|
||||
<ul class="ui360playlist">
|
||||
|
||||
<li>
|
||||
|
||||
<div class="ui360 ui360-vis">
|
||||
<a href="http://freshly-ground.com/data/audio/binaural/A%20Virtual%20Haircut%20in%20San%20Francisco%20%283%20Scenes%29.mp3">A Virtual Haircut (3 scenes)</a>
|
||||
<div class="metadata">
|
||||
<div class="duration">4:43</div> <!-- total track time (for positioning while loading, until determined -->
|
||||
<ul>
|
||||
<li><p>Electric razor</p><span>0:00</span></li> <!-- first scene -->
|
||||
<li><p>Water, scissors</p><span>2:41</span></li> <!-- start time of second scene -->
|
||||
<li><p>More razor work</p><span>4:00</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
||||
<div class="ui360 ui360-vis">
|
||||
<a href="http://freshly-ground.com/data/audio/binaural/Rubber%20Chicken%20Launch%20%28office%29.mp3">Rubber Chicken Launch (Office)</a>
|
||||
|
||||
<div class="metadata">
|
||||
<div class="duration">0:47</div>
|
||||
<ul>
|
||||
<li><p>First attempt</p><span>0:00</span></li>
|
||||
<li><p>Fire!</p><span>0:02</span></li>
|
||||
<li><p>"Too much angle"</p><span>0:05</span></li>
|
||||
<li><p>Random chicken noise</p><span>0:18</span></li>
|
||||
<li><p>"Wait a second"</p><span>0:31</span></li>
|
||||
<li><p>Derrr..</p><span>0:34</span></li>
|
||||
<li><p>Launch attempt #2</p><span>0:36</span></li>
|
||||
<li><p>"Wrong angle"</p><span>0:39</span></li>
|
||||
<li><p>"Fail"</p><span>0:42</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<div style="clear:both"></div>
|
||||
|
||||
<p style="margin-left:1em">
|
||||
<a href="http://www.schillmania.com/projects/soundmanager2/" title="SoundManager 2 home">SoundManager 2 project page</a> (not an MP3 link)
|
||||
</p>
|
||||
|
||||
<script type="text/javascript">
|
||||
if (window.location.toString().match(/#customize/i)) {
|
||||
document.getElementById('config-link').style.display = 'none';
|
||||
document.getElementById('config-ui').style.display = 'block';
|
||||
}
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,179 @@
|
|||
#cp-container { position:relative;float:left;display:inline; margin-left:1em;padding: 6px; background-color: #f6f6f6; border:1px solid #eee; width: 320px; height:180px;z-index:2; }
|
||||
|
||||
.yui-picker-controls li,
|
||||
.yui-picker-controls input {
|
||||
font-size:1em;
|
||||
font-family:"helvetica neue",helvetica,arial,verdana;
|
||||
}
|
||||
|
||||
#controls {
|
||||
position:relative;
|
||||
margin-top:1.5em;
|
||||
font-size:0.85em;
|
||||
}
|
||||
|
||||
#options {
|
||||
float:left;
|
||||
display:inline;
|
||||
margin-bottom:0.5em;
|
||||
margin-top:-1.2em;
|
||||
}
|
||||
|
||||
#controls .checkbox {
|
||||
float:left;
|
||||
display:inline;
|
||||
width:21.2em;
|
||||
margin-right:2.5em;
|
||||
}
|
||||
|
||||
#controls .checkbox div {
|
||||
/* tab */
|
||||
width:auto;
|
||||
padding:0.4em;
|
||||
border:1px solid #ddd;
|
||||
border-bottom:none;
|
||||
background:#eee;
|
||||
}
|
||||
|
||||
#controls .checkbox div,
|
||||
#controls .checkbox input {
|
||||
font-family:arial,tahoma,verdana,"sans serif";
|
||||
font-size:1em;
|
||||
vertical-align:middle;
|
||||
}
|
||||
|
||||
#controls dl {
|
||||
width:21em;
|
||||
}
|
||||
|
||||
#controls dl.col {
|
||||
position:relative;
|
||||
float:left;
|
||||
display:inline;
|
||||
margin:0px;
|
||||
margin-right:1em;
|
||||
padding:0.75em;
|
||||
/*
|
||||
height:12.4em;
|
||||
*/
|
||||
height:auto;
|
||||
border:1px solid #ddd;
|
||||
background:#f6f6f6;
|
||||
}
|
||||
|
||||
#controls .disabled {
|
||||
color:#ccc;
|
||||
}
|
||||
|
||||
#controls .disabled dt,
|
||||
#controls .disabled dd {
|
||||
color:#999;
|
||||
opacity:0.5;
|
||||
}
|
||||
|
||||
#controls dl dd p {
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
}
|
||||
|
||||
#controls dt,
|
||||
#controls dd {
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
}
|
||||
|
||||
#controls dt {
|
||||
border-bottom:none;
|
||||
}
|
||||
|
||||
#controls dt {
|
||||
float:left;
|
||||
display:inline;
|
||||
background:transparent;
|
||||
padding-right:0.7em;
|
||||
margin-right:0.7em;
|
||||
border-right:1px solid #ccc;
|
||||
font-size:1.1em;
|
||||
color:#333;
|
||||
font-family:"helvetica neue",helvetica,verdana,arial,"sans serif";
|
||||
}
|
||||
|
||||
#controls dd {
|
||||
margin:0px;
|
||||
padding:0px;
|
||||
font-size:0.9em;
|
||||
vertical-align:middle;
|
||||
color:#666;
|
||||
}
|
||||
|
||||
#controls .title {
|
||||
float:left;
|
||||
display:inline;
|
||||
margin-right:0.6em;
|
||||
color:#333;
|
||||
}
|
||||
|
||||
/* those slider bits you might be wondering about */
|
||||
|
||||
#controls .control {
|
||||
position:relative;
|
||||
border-left:0px;
|
||||
width:214px;
|
||||
height:20px;
|
||||
}
|
||||
|
||||
#controls .control .bar {
|
||||
position:absolute;
|
||||
left:0px;
|
||||
top:0px;
|
||||
width:214px;
|
||||
height:20px;
|
||||
background:transparent url(../_image/slider-bar.gif) no-repeat 0px 9px;
|
||||
cursor:pointer;
|
||||
cursor:hand;
|
||||
}
|
||||
|
||||
#controls .control .slider {
|
||||
position:absolute;
|
||||
left:0px;
|
||||
top:0px;
|
||||
width:20px;
|
||||
height:20px;
|
||||
background:transparent url(../_image/slider.png) no-repeat 0px 0px;
|
||||
*background:none;
|
||||
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=crop,src='../_image/slider.png');
|
||||
cursor:pointer;
|
||||
cursor:hand;
|
||||
}
|
||||
|
||||
#controls .control .slider:hover {
|
||||
background:transparent url(../_image/slider-1.png) no-repeat 0px 0px;
|
||||
*background:none;
|
||||
}
|
||||
|
||||
#controls .control .slider.hover {
|
||||
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=crop,src='../_image/slider-1.png');
|
||||
}
|
||||
|
||||
#controls .disabled .control .slider {
|
||||
background:transparent url(../_image/slider-disabled.png) no-repeat 0px 0px;
|
||||
*background:none;
|
||||
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=crop,src='../_image/slider-disabled.png');
|
||||
}
|
||||
|
||||
#controls .disabled .control .slider:hover {
|
||||
background:transparent url(../_image/slider-disabled-1.png) no-repeat 0px 0px;
|
||||
*background:none;
|
||||
}
|
||||
|
||||
#controls .disabled .control .slider.hover {
|
||||
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=crop,src='../_image/slider-disabled-1.png');
|
||||
}
|
||||
|
||||
#controls input[type=text] {
|
||||
width:5em;
|
||||
}
|
||||
|
||||
#options div {
|
||||
margin-bottom:0.25em;
|
||||
}
|
|
@ -0,0 +1,750 @@
|
|||
/*
|
||||
Ancient fireworks slider control code (2005)
|
||||
Kinda/sorta refactored for SM2 360 demo
|
||||
http://schillmania.com/projects/fireworks/
|
||||
--------------------------------------------
|
||||
Not required for your use!
|
||||
*/
|
||||
|
||||
function Animator2() {
|
||||
var self = this;
|
||||
this.tweens = [];
|
||||
this.tweens['default'] = [1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1];
|
||||
this.tweens['blast'] = [12,12,11,10,10,9,8,7,6,5,4,3,2,1];
|
||||
this.tweens['fade'] = [10,10,10,10,10,10,10,10,10,10];
|
||||
this.queue = [];
|
||||
this.queue.IDs = [];
|
||||
this.active = false;
|
||||
this.timer = null;
|
||||
|
||||
this.createTween = function(start,end,type) {
|
||||
// return array of tween coordinate data (start->end)
|
||||
type = type||'default';
|
||||
var tween = [start];
|
||||
var tmp = start;
|
||||
var diff = end-start;
|
||||
var x = self.tweens[type].length;
|
||||
for (var i=0; i<x; i++) {
|
||||
tmp += diff*self.tweens[type][i]*0.01;
|
||||
tween[i] = new Object();
|
||||
tween[i].data = tmp;
|
||||
tween[i].event = null;
|
||||
}
|
||||
return tween;
|
||||
}
|
||||
|
||||
this.enqueue = function(o,fMethod,fOnComplete) {
|
||||
// add object and associated methods to animation queue
|
||||
// writeDebug('animator.enqueue()');
|
||||
if (!fMethod) {
|
||||
// writeDebug('animator.enqueue(): missing fMethod');
|
||||
}
|
||||
if (typeof(self.queue.IDs[o.oID])=='undefined') {
|
||||
// writeDebug('animator.enqueue(): added '+o.oID);
|
||||
var i = self.queue.length;
|
||||
self.queue.IDs[o.oID] = i;
|
||||
self.queue[i] = o;
|
||||
} else {
|
||||
// writeDebug('animator.enqueue(): '+o.oID+' already queued');
|
||||
var i = self.queue.IDs[o.oID]; // retrieve queue index
|
||||
self.queue[i].active = true;
|
||||
self.queue[i].frame = 0;
|
||||
}
|
||||
o.active = true; // flag for animation
|
||||
self.queue[i]._method = fMethod;
|
||||
self.queue[i]._oncomplete = fOnComplete?fOnComplete:null;
|
||||
}
|
||||
|
||||
this.animate = function() {
|
||||
var active = 0;
|
||||
for (var i=self.queue.length; i--;) {
|
||||
if (self.queue[i].active) {
|
||||
self.queue[i]._method();
|
||||
active++;
|
||||
}
|
||||
}
|
||||
if (active==0 && self.timer) {
|
||||
// all animations finished
|
||||
self.stop();
|
||||
} else {
|
||||
// writeDebug(active+' active');
|
||||
}
|
||||
}
|
||||
|
||||
this.start = function() {
|
||||
if (self.timer || self.active) {
|
||||
// writeDebug('animator.start(): already active');
|
||||
return false;
|
||||
}
|
||||
// writeDebug('animator.start()'); // report only if started
|
||||
self.active = true;
|
||||
self.timer = setInterval(self.animate,mc.intervalRate);
|
||||
}
|
||||
|
||||
this.stop = function() {
|
||||
// writeDebug('animator.stop()',true);
|
||||
clearInterval(self.timer);
|
||||
self.timer = null;
|
||||
self.active = false;
|
||||
self.queue = [];
|
||||
self.queue.IDs = [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function MainController() {
|
||||
var self = this;
|
||||
this.intervalRate = 20; // rate (ms) to run animation at, general best default = 20
|
||||
this.DEBUG = true; // debug mode disabled by default
|
||||
this.oFW = null;
|
||||
this.isIE = (navigator.appVersion.indexOf('MSIE')+1);
|
||||
this.isOpera = (navigator.userAgent.toLowerCase().indexOf('opera')+1);
|
||||
if (this.isOpera) this.isIE = false; // no impersonation allowed here!
|
||||
this.animator = null;
|
||||
this.gOID = 0; // global object ID counter (for animation queue)
|
||||
this.particleTypes = 6;
|
||||
this.particleXY = 10;
|
||||
this.tweenFade = [100,90,80,70,60,50,40,30,20,10,0];
|
||||
this.isSafari = (navigator.appVersion.toLowerCase().indexOf('safari')+1?1:0);
|
||||
this.canvasX = null;
|
||||
this.canvasY = null;
|
||||
this.screenY = null; // screen area (not entire page)
|
||||
self.scrollY = null;
|
||||
|
||||
self.getWindowCoords = function() {
|
||||
self.canvasX = (document.documentElement.clientWidth||document.body.clientWidth||document.body.scrollWidth);
|
||||
self.canvasY = (document.documentElement.clientHeight||document.body.clientHeight||document.body.scrollHeight);
|
||||
self.screenY = self.canvasY;
|
||||
self.scrollY = parseInt(window.scrollY||document.documentElement.scrollTop||document.body.scrollTop);
|
||||
self.canvasY += self.scrollY;
|
||||
}
|
||||
|
||||
this.getWindowCoordsAlt = function() {
|
||||
self.canvasX = window.innerWidth;
|
||||
self.canvasY = window.innerHeight;
|
||||
self.screenY = self.canvasY;
|
||||
self.scrollY = parseInt(window.scrollY||document.documentElement.scrollTop||document.body.scrollTop);
|
||||
self.canvasY += self.scrollY;
|
||||
}
|
||||
|
||||
this.getPanX = function(x) {
|
||||
x = parseInt(x);
|
||||
var pos = x/self.canvasX;
|
||||
if (pos<0.4) {
|
||||
pos *= -1;
|
||||
} else if (pos >= 0.4 && pos <= 0.6) {
|
||||
pos = 0.5;
|
||||
}
|
||||
pos = parseInt(pos*100);
|
||||
// writeDebug('getPanX('+x+'): '+pos+'%');
|
||||
return pos;
|
||||
}
|
||||
|
||||
this.isEmpty = function(o) {
|
||||
// needs further hacking
|
||||
return (typeof(o)=='undefined'||(o==null&&o!=0)||(o==''&&o!=0)||o=='null');
|
||||
}
|
||||
|
||||
this.init = function() {
|
||||
// self.oFW = document.getElementById('fw');
|
||||
// self.oFP = document.getElementById('fp');
|
||||
// if (typeof(enableDebugMode)!='undefined' && (self.DEBUG||window.location.toString().toLowerCase().indexOf('debug')>=0)) enableDebugMode();
|
||||
self.getWindowCoords();
|
||||
self.animator = new Animator2();
|
||||
}
|
||||
|
||||
this.destructor = function() {
|
||||
/*
|
||||
for (var i=self.fireworks.length; i--;) {
|
||||
self.fireworks[i] = null;
|
||||
}
|
||||
self.fireworks = null;
|
||||
if (soundManager) {
|
||||
soundManager.destructor();
|
||||
soundManager = null;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if (this.isSafari || this.isOpera) this.getWindowCoords = this.getWindowCoordsAlt;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function Controller(o) {
|
||||
var self = this;
|
||||
this.o = o;
|
||||
this.controls = [];
|
||||
this.cb = [];
|
||||
this.options = [];
|
||||
this.functionExample = document.getElementById('function-example');
|
||||
this.fbIE = null;
|
||||
|
||||
this.randomize = function() {
|
||||
for (var i=1; i<self.controls.length; i++) {
|
||||
setTimeout(self.controls[i].randomize,20+(20*i+1));
|
||||
}
|
||||
}
|
||||
|
||||
this.cbClick = function(nIndex) {
|
||||
document.getElementById('controls').getElementsByTagName('dl')[nIndex].className = 'col'+(this.checked==false||this.checked==''?' disabled':'');
|
||||
self.updateExample();
|
||||
self.updateExampleCode();
|
||||
}
|
||||
|
||||
this.updateExample = function() {
|
||||
if (threeSixtyPlayer) {
|
||||
var val = self.controls[0].value;
|
||||
threeSixtyPlayer.config.circleDiameter = self.controls[0].value;
|
||||
|
||||
threeSixtyPlayer.config.circleRadius = self.controls[0].value/2;
|
||||
// update some stuff
|
||||
|
||||
// set the cover width/height to match the canvas
|
||||
if (threeSixtyPlayer.lastSound) {
|
||||
// always set cover to max area?
|
||||
// threeSixtyPlayer.lastSound._data.oCover.style.width = 250+'px';
|
||||
// threeSixtyPlayer.lastSound._data.oCover.style.height = 250+'px';
|
||||
// threeSixtyPlayer.lastSound._data.oCover.style.width = threeSixtyPlayer.config.circleDiameter+'px';
|
||||
// threeSixtyPlayer.lastSound._data.oCover.style.height = threeSixtyPlayer.config.circleDiameter+'px';
|
||||
threeSixtyPlayer.refreshCoords(threeSixtyPlayer.lastSound);
|
||||
}
|
||||
|
||||
threeSixtyPlayer.config.waveformDataLineRatio = (self.controls[1].value/100)*2;
|
||||
|
||||
threeSixtyPlayer.config.waveformDataDownsample = (self.controls[2].value);
|
||||
|
||||
threeSixtyPlayer.config.eqDataLineRatio = parseInt((self.controls[3].value/100)*3*1000)/1000;
|
||||
|
||||
threeSixtyPlayer.config.eqDataDownsample = (self.controls[4].value);
|
||||
|
||||
threeSixtyPlayer.config.scaleArcWidth = (self.controls[5].value/100);
|
||||
|
||||
threeSixtyPlayer.config.useEQData = (document.getElementById('disabled-1').checked?true:false);
|
||||
|
||||
// radio buttons
|
||||
|
||||
threeSixtyPlayer.config.useWaveformData=(document.getElementById('use-waveform').checked?true:false);
|
||||
|
||||
threeSixtyPlayer.config.waveformDataOutside = document.getElementById('waveform-inside').checked?false:true;
|
||||
|
||||
threeSixtyPlayer.config.eqDataOutside = document.getElementById('eq-inside').checked?false:true;
|
||||
|
||||
threeSixtyPlayer.config.useAmplifier = (document.getElementById('use-amplifier').checked?true:false);
|
||||
|
||||
// threeSixtyPlayer.refreshCoords();
|
||||
}
|
||||
|
||||
if (threeSixtyPlayer.lastSound) {
|
||||
|
||||
threeSixtyPlayer.lastSound._360data.circleDiameter = self.controls[0].value;
|
||||
|
||||
threeSixtyPlayer.lastSound._360data.circleRadius = self.controls[0].value/2;
|
||||
|
||||
threeSixtyPlayer.lastSound._360data.waveformDataLineRatio = (self.controls[1].value/100)*2;
|
||||
|
||||
threeSixtyPlayer.lastSound._360data.waveformDataDownsample = (self.controls[2].value);
|
||||
|
||||
threeSixtyPlayer.lastSound._360data.eqDataLineRatio = parseInt((self.controls[3].value/100)*3*1000)/1000;
|
||||
|
||||
threeSixtyPlayer.lastSound._360data.eqDataDownsample = (self.controls[4].value);
|
||||
|
||||
threeSixtyPlayer.lastSound._360data.useEQData = (document.getElementById('disabled-1').checked?true:false);
|
||||
|
||||
// radio buttons
|
||||
|
||||
threeSixtyPlayer.lastSound._360data.useWaveformData=(document.getElementById('use-waveform').checked?true:false);
|
||||
|
||||
threeSixtyPlayer.lastSound._360data.waveformDataOutside = document.getElementById('waveform-inside').checked?false:true;
|
||||
|
||||
threeSixtyPlayer.lastSound._360data.eqDataOutside = document.getElementById('eq-inside').checked?false:true;
|
||||
|
||||
threeSixtyPlayer.lastSound._360data.useAmplifier = (document.getElementById('use-amplifier').checked?true:false);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.updateExampleCode = function() {
|
||||
// set innerHTML
|
||||
document.getElementById('config-code').innerHTML = "\
|
||||
// 360player.js, config section\n\
|
||||
\n\
|
||||
this.config = {\n\
|
||||
\n\
|
||||
playNext: <span>"+threeSixtyPlayer.config.playNext+"</span>,\n\
|
||||
autoPlay: <span>"+threeSixtyPlayer.config.autoPlay+"</span>,\n\
|
||||
allowMultiple: <span>"+threeSixtyPlayer.config.allowMultiple+"</span>,\n\
|
||||
loadRingColor: <span>'"+threeSixtyPlayer.config.loadRingColor+"'</span>,\n\
|
||||
playRingColor: <span>'"+threeSixtyPlayer.config.playRingColor+"'</span>,\n\
|
||||
backgroundRingColor: <span>'"+threeSixtyPlayer.config.backgroundRingColor+"'</span>,\n\
|
||||
circleDiameter: <span>"+threeSixtyPlayer.config.circleDiameter+"</span>,\n\
|
||||
circleRadius: <span>"+threeSixtyPlayer.config.circleRadius+"</span>,\n\
|
||||
animDuration: <span>"+threeSixtyPlayer.config.animDuration+"</span>,\n\
|
||||
animTransition: <span>Animator.tx.bouncy</span>,\n\
|
||||
showHMSTime: <span>"+threeSixtyPlayer.config.showHMSTime+"</span>,\n\
|
||||
\n\
|
||||
useWaveformData: <span>"+threeSixtyPlayer.config.useWaveformData+"</span>,\n\
|
||||
waveformDataColor: <span>'"+threeSixtyPlayer.config.waveformDataColor+"'</span>,\n\
|
||||
waveformDataDownsample: <span>"+threeSixtyPlayer.config.waveformDataDownsample+"</span>,\n\
|
||||
waveformDataOutside: <span>"+threeSixtyPlayer.config.waveformDataOutside+"</span>,\n\
|
||||
waveformDataConstrain: <span>false</span>,\n\
|
||||
waveformDataLineRatio: <span>"+threeSixtyPlayer.config.waveformDataLineRatio+"</span>,\n\
|
||||
\n\
|
||||
useEQData: <span>"+threeSixtyPlayer.config.useEQData+"</span>,\n\
|
||||
eqDataColor: <span>'"+threeSixtyPlayer.config.eqDataColor+"'</span>,\n\
|
||||
eqDataDownsample: <span>"+threeSixtyPlayer.config.eqDataDownsample+"</span>,\n\
|
||||
eqDataOutside: <span>"+threeSixtyPlayer.config.eqDataOutside+"</span>,\n\
|
||||
eqDataLineRatio: <span>"+threeSixtyPlayer.config.eqDataLineRatio+"</span>,\n\
|
||||
\n\
|
||||
usePeakData: <span>"+threeSixtyPlayer.config.usePeakData+"</span>,\n\
|
||||
peakDataColor: <span>'"+threeSixtyPlayer.config.peakDataColor+"'</span>,\n\
|
||||
peakDataOutside: <span>"+threeSixtyPlayer.config.peakDataOutside+"</span>,\n\
|
||||
peakDataLineRatio: <span>"+threeSixtyPlayer.config.peakDataLineRatio+"</span>,\n\
|
||||
\n\
|
||||
useAmplifier: <span>"+threeSixtyPlayer.config.useAmplifier+"</span>\n\
|
||||
\n\
|
||||
}";
|
||||
document.getElementById('config-code').style.display = 'block'; // weird Fx fix
|
||||
}
|
||||
|
||||
this.createCustomFirework = function() {
|
||||
}
|
||||
|
||||
this.destructor = function() {
|
||||
for (var i=self.controls.length; i--;) {
|
||||
self.controls[i].destructor();
|
||||
}
|
||||
for (i=self.cb.length; i--;) {
|
||||
self.cb.onclick = null;
|
||||
self.cb[i] = null;
|
||||
}
|
||||
for (i=self.options.length; i--;) {
|
||||
self.options[i] = null;
|
||||
}
|
||||
if (navigator.userAgent.match(/msie/i)) {
|
||||
self.fbIE.onmouseover = null;
|
||||
self.fbIE.onmouseout = null;
|
||||
self.fbIE = null;
|
||||
}
|
||||
self.cb = null;
|
||||
self.options = null;
|
||||
self.controls = null;
|
||||
self.functionExample = null;
|
||||
self.o = null;
|
||||
}
|
||||
|
||||
var items = parseInt(this.o.length/3);
|
||||
for (var i=0; i<items; i++) {
|
||||
this.controls[this.controls.length] = new Slider(this.o[(3*i)+2].getElementsByTagName('div')[1],this.o[(3*i)+1],this.o[(3*i)+2].getElementsByTagName('div')[0]);
|
||||
}
|
||||
this.cb = [document.getElementById('disabled-0'),document.getElementById('disabled-1')];
|
||||
/*
|
||||
for (i=this.cb.length; i--;) {
|
||||
this.cb[i]._index = i;
|
||||
this.cb[i].onclick = this.cbClick;
|
||||
}
|
||||
*/
|
||||
this.options = [];
|
||||
/*
|
||||
this.cb[1].checked = false;
|
||||
this.options = [document.getElementById('opt-random0'),document.getElementById('opt-random1')];
|
||||
this.options[0].checked = false;
|
||||
this.options[1].checked = true;
|
||||
if (navigator.userAgent.match(/msie/i)) {
|
||||
this.fbIE = document.getElementById('fireButton');
|
||||
this.fbIE.onmouseover = function() {this.className='hover';}
|
||||
this.fbIE.onmouseout = function() {this.className='';}
|
||||
}
|
||||
*/
|
||||
|
||||
setTimeout(function(){
|
||||
// default values for controls
|
||||
var values = [
|
||||
256,
|
||||
65,
|
||||
40,
|
||||
72,
|
||||
48,
|
||||
100
|
||||
];
|
||||
for (var i=0; i<values.length; i++) {
|
||||
self.controls[i].setValue(values[i]); // defaults
|
||||
}
|
||||
},1);
|
||||
}
|
||||
|
||||
function Slider(o,oV,oB) {
|
||||
var self = this;
|
||||
this.o = o;
|
||||
this.oV = oV;
|
||||
this.oB = oB;
|
||||
this.scale = parseInt(oV.innerHTML.toString().substr(2));
|
||||
this.oID = 'sc'+(gOID++);
|
||||
this.offX = 0;
|
||||
this.x = 0;
|
||||
this.xMin = 0-10;
|
||||
this.xMax = self.o.parentNode.offsetWidth-10;
|
||||
this.value = 0;
|
||||
this.timer = null;
|
||||
this._className = this.o.className;
|
||||
this.tween = [];
|
||||
this.frame = 0;
|
||||
|
||||
this.over = function() {
|
||||
this.className = self._className+' hover';
|
||||
event.cancelBubble=true;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.out = function() {
|
||||
this.className = self._className;
|
||||
event.cancelBubble=true;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.down = function(e) {
|
||||
var e = e?e:event;
|
||||
self.offX = e.clientX-self.o.offsetLeft;
|
||||
addEvent(document,'mousemove',self.move);
|
||||
addEvent(document,'mouseup',self.up);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.barClick = function(e) {
|
||||
var e=e?e:event;
|
||||
self.slide(self.x,e.clientX-self.o.parentNode.parentNode.offsetLeft-self.o.offsetWidth);
|
||||
}
|
||||
|
||||
this.move = function(e) {
|
||||
var e=e?e:event;
|
||||
var x = e.clientX-self.offX;
|
||||
if (x>self.xMax) {
|
||||
x = self.xMax;
|
||||
} else if (x<self.xMin) {
|
||||
x = self.xMin;
|
||||
}
|
||||
if (x != self.x) {
|
||||
self.moveTo(x);
|
||||
self.doUpdate();
|
||||
controller.updateExample();
|
||||
controller.updateExampleCode();
|
||||
}
|
||||
e.stopPropgation?e.stopPropagation():e.cancelBubble=true;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.up = function(e) {
|
||||
removeEvent(document,'mousemove',self.move);
|
||||
removeEvent(document,'mouseup',self.up);
|
||||
// controller.updateExample();
|
||||
controller.updateExampleCode();
|
||||
}
|
||||
|
||||
this.slide = function(x0,x1) {
|
||||
self.tween = mc.animator.createTween(x0,x1);
|
||||
mc.animator.enqueue(self,self.animate,function(){
|
||||
controller.updateExample()
|
||||
controller.updateExampleCode();
|
||||
});
|
||||
mc.animator.start();
|
||||
}
|
||||
|
||||
this.moveTo = function(x) {
|
||||
self.x = x;
|
||||
self.o.style.marginLeft = x+'px';
|
||||
}
|
||||
|
||||
this.animate = function() {
|
||||
self.moveTo(self.tween[self.frame].data);
|
||||
self.doUpdate(50);
|
||||
controller.updateExample();
|
||||
if (self.frame++>=self.tween.length-1) {
|
||||
self.active = false;
|
||||
self.frame = 0;
|
||||
if (self._oncomplete) self._oncomplete();
|
||||
// self.doUpdate();
|
||||
return false;
|
||||
}
|
||||
self.doUpdate();
|
||||
return true;
|
||||
}
|
||||
|
||||
this.doUpdate = function(t) {
|
||||
// if (!self.timer) self.timer = setTimeout(self.update,t||20);
|
||||
self.update();
|
||||
}
|
||||
|
||||
this.update = function() {
|
||||
self.timer = null;
|
||||
self.value = 1+parseInt(self.x/self.xMax*(self.scale-1));
|
||||
if (self.value<1) self.value = 1;
|
||||
// if (self.oV.innerHTML != self.value) self.oV.innerHTML = self.value;
|
||||
// self.oV.innerHTML = self.value;
|
||||
}
|
||||
|
||||
this.setValue = function(x) {
|
||||
self.slide(self.x,Math.min(self.xMax,x));
|
||||
}
|
||||
|
||||
this.randomize = function() {
|
||||
self.slide(self.x,parseInt(Math.random()*self.xMax));
|
||||
}
|
||||
|
||||
this.destructor = function() {
|
||||
self.o.onmouseover = null;
|
||||
self.o.onmouseout = null;
|
||||
self.o.onmousedown = null;
|
||||
self.o = null;
|
||||
self.oV = null;
|
||||
self.oB.onclick = null;
|
||||
self.oB = null;
|
||||
}
|
||||
|
||||
if (soundManager.isIE) {
|
||||
// IE is lame, no :hover
|
||||
this.o.onmouseover = this.over;
|
||||
this.o.onmouseout = this.out;
|
||||
}
|
||||
|
||||
this.o.onmousedown = this.down;
|
||||
this.oB.onclick = this.barClick;
|
||||
self.update();
|
||||
|
||||
}
|
||||
|
||||
var gOID = 0;
|
||||
|
||||
function demoInit() {
|
||||
controller = new Controller(document.getElementById('controls').getElementsByTagName('dd'));
|
||||
}
|
||||
|
||||
function demoDestuctor() {
|
||||
controller.destructor();
|
||||
controller = null;
|
||||
}
|
||||
|
||||
var controller = null;
|
||||
|
||||
var mc = new MainController();
|
||||
// create null objects if APIs not present
|
||||
|
||||
function createCP(oInput,oHandler) {
|
||||
var Event = YAHOO.util.Event;
|
||||
|
||||
cpHandler = oHandler;
|
||||
if (picker != null) {
|
||||
// picker.showcontrols(true);
|
||||
var c = oInput.value.substr(1);
|
||||
picker.setValue(hex2decArray([c.substr(0,2),c.substr(2,2),c.substr(4,2)]),true); // be silent
|
||||
return false;
|
||||
}
|
||||
|
||||
Event.onDOMReady(function() {
|
||||
picker = new YAHOO.widget.ColorPicker("cp-container", {
|
||||
showhsvcontrols: true,
|
||||
showhexcontrols: true,
|
||||
images: {
|
||||
PICKER_THUMB: "../_image/picker_thumb.png",
|
||||
HUE_THUMB: "../_image/hue_thumb.png"
|
||||
}
|
||||
});
|
||||
|
||||
// picker.showcontrols(false);
|
||||
//a listener for logging RGB color changes;
|
||||
//this will only be visible if logger is enabled:
|
||||
var onRgbChange = function(o) {
|
||||
/*o is an object
|
||||
{ newValue: (array of R, G, B values),
|
||||
prevValue: (array of R, G, B values),
|
||||
type: "rgbChange"
|
||||
}
|
||||
*/
|
||||
cpHandler(o.newValue);
|
||||
controller.updateExampleCode();
|
||||
}
|
||||
|
||||
//subscribe to the rgbChange event;
|
||||
picker.on("rgbChange", onRgbChange);
|
||||
|
||||
//use setValue to reset the value to white:
|
||||
Event.on("reset", "click", function(e) {
|
||||
picker.setValue([255, 255, 255], false); //false here means that rgbChange
|
||||
//wil fire; true would silence it
|
||||
});
|
||||
|
||||
//use the "get" method to get the current value
|
||||
//of one of the Color Picker's properties; in
|
||||
//this case, we'll get the hex value and write it
|
||||
//to the log:
|
||||
Event.on("gethex", "click", function(e) {
|
||||
console.log("Current hex value: " + picker.get("hex"));
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
var picker = null;
|
||||
|
||||
cpHandler = function() {
|
||||
}
|
||||
|
||||
|
||||
// hex -> dec / dec -> hex
|
||||
// http://www.southwest.com.au/~jfuller/binary/converter.htm
|
||||
|
||||
function dec2hex(cval) {
|
||||
if (cval > 255) cval = 255;
|
||||
var hexascii = "0123456789ABCDEF";
|
||||
var cval0 = Math.floor(cval/16);
|
||||
var cval1 = cval-(cval0*16);
|
||||
var c1 = hexascii.charAt(cval0);
|
||||
var c2 = hexascii.charAt(cval1);
|
||||
return (c1+c2);
|
||||
}
|
||||
|
||||
function hex2dec(cval) {
|
||||
cval = cval.toUpperCase();
|
||||
var tval = 0;
|
||||
var hexascii = "0123456789ABCDEF";
|
||||
var mychar, ch;
|
||||
for (var c=0; c<cval.length; c++) {
|
||||
mychar = cval.charAt(c);
|
||||
for (ch=0; ch<16; ch++) {
|
||||
if (mychar == hexascii.charAt(ch)) {
|
||||
tval += ch;
|
||||
if (c<cval.length-1) tval *= 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tval;
|
||||
}
|
||||
|
||||
function hex2decArray(hArray) {
|
||||
var result = [];
|
||||
for (var i=0,j=hArray.length; i<j; i++) {
|
||||
result[i] = hex2dec(hArray[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function dec2hexArray(dArray) {
|
||||
var result = [];
|
||||
for (var i=0,j=dArray.length; i<j; i++) {
|
||||
result[i] = dec2hex(dArray[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
threeSixtyPlayer.config.waveformDataColor = '#'+dec2hexArray([self.controls[5].value,self.controls[6].value,self.controls[7].value]).join('');
|
||||
|
||||
threeSixtyPlayer.config.eqDataColor = '#'+dec2hexArray([self.controls[8].value,self.controls[9].value,self.controls[10].value]).join('');
|
||||
|
||||
threeSixtyPlayer.config.loadRingColor = '#'+dec2hexArray([self.controls[11].value,self.controls[12].value,self.controls[13].value]).join('');
|
||||
|
||||
threeSixtyPlayer.config.playRingColor = '#'+dec2hexArray([self.controls[14].value,self.controls[15].value,self.controls[16].value]).join('');
|
||||
|
||||
threeSixtyPlayer.config.waveformDataLineRatio = (self.controls[1].value/100)*2;
|
||||
|
||||
threeSixtyPlayer.config.waveformDataDownsample = (self.controls[2].value);
|
||||
|
||||
threeSixtyPlayer.config.eqDataLineRatio = (self.controls[3].value/100)*3;
|
||||
|
||||
threeSixtyPlayer.config.eqDataDownsample = (self.controls[4].value);
|
||||
|
||||
*/
|
||||
|
||||
function _id(sID) {
|
||||
return document.getElementById(sID);
|
||||
}
|
||||
|
||||
function setWaveformColor(sColor) {
|
||||
var value = '#'+(dec2hexArray(sColor).join(''));
|
||||
threeSixtyPlayer.config.waveformDataColor = value;
|
||||
_id('waveform-color').value = value;
|
||||
}
|
||||
|
||||
function setEQColor(sColor) {
|
||||
var value = '#'+dec2hexArray(sColor).join('');
|
||||
_id('eq-color').value = value;
|
||||
threeSixtyPlayer.config.eqDataColor = value;
|
||||
}
|
||||
|
||||
function setLoadedRingColor(sColor) {
|
||||
var value = '#'+dec2hexArray(sColor).join('');
|
||||
_id('loaded-ring-color').value = value;
|
||||
threeSixtyPlayer.config.loadRingColor = value;
|
||||
}
|
||||
|
||||
function setProgressRingColor(sColor) {
|
||||
var value = '#'+dec2hexArray(sColor).join('');
|
||||
_id('progress-ring-color').value = value;
|
||||
threeSixtyPlayer.config.playRingColor = value;
|
||||
}
|
||||
|
||||
function setBackgroundRingColor(sColor) {
|
||||
var value = '#'+dec2hexArray(sColor).join('');
|
||||
_id('bg-ring-color').value = value;
|
||||
threeSixtyPlayer.config.backgroundRingColor = value;
|
||||
}
|
||||
|
||||
function addEvent(o,evtName,evtHandler) {
|
||||
typeof window.addEventListener !== 'undefined' ? o.addEventListener(evtName,evtHandler,false) : o.attachEvent('on'+evtName,evtHandler);
|
||||
}
|
||||
|
||||
function removeEvent(o,evtName,evtHandler) {
|
||||
typeof window.removeEventListener !== 'undefined' ? o.removeEventListener(evtName,evtHandler,false) : o.detachEvent('on'+evtName,evtHandler);
|
||||
}
|
||||
|
||||
if (window.location.toString().match(/#customize/i)) {
|
||||
addEvent(window,'resize',mc.getWindowCoords);
|
||||
addEvent(window,'scroll',mc.getWindowCoords);
|
||||
addEvent(window,'load',mc.init);
|
||||
addEvent(window,'load',demoInit);
|
||||
}
|
||||
|
||||
if (window.location.toString().match(/hifi/i)) {
|
||||
soundManager.onready(function(){
|
||||
document.getElementById('hifi').style.display = 'none';
|
||||
|
||||
threeSixtyPlayer.config = {
|
||||
|
||||
playNext: false,
|
||||
autoPlay: false,
|
||||
loadRingColor: '#ccc',
|
||||
playRingColor: '#000',
|
||||
backgroundRingColor: '#eee',
|
||||
circleDiameter: 256,
|
||||
circleRadius: 128,
|
||||
animDuration: 500,
|
||||
animTransition: Animator.tx.bouncy,
|
||||
showHMSTime: true,
|
||||
|
||||
useWaveformData: true,
|
||||
waveformDataColor: '#0099ff',
|
||||
waveformDataDownsample: 1,
|
||||
waveformDataOutside: true,
|
||||
waveformDataConstrain: false,
|
||||
waveformDataLineRatio: 0.56,
|
||||
|
||||
useEQData: true,
|
||||
eqDataColor: '#339933',
|
||||
eqDataDownsample: 1,
|
||||
eqDataOutside: true,
|
||||
eqDataLineRatio: 0.72,
|
||||
|
||||
usePeakData: true,
|
||||
peakDataColor: '#ff33ff',
|
||||
peakDataOutside: true,
|
||||
peakDataLineRatio: 0.5,
|
||||
scaleArcWidth: 1, // thickness factor of playback progress ring
|
||||
useAmplifier: true
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* In-page demo CSS - see external CSS for actual relevant stuff.
|
||||
*/
|
||||
|
||||
#soundmanager-debug {
|
||||
/* SM2 debug container (optional, makes debug more useable) */
|
||||
position:absolute;position:fixed;*position:absolute;bottom:10px;right:10px;width:50em;height:18em;overflow:auto;background:#fff;margin:1em;padding:1em;border:1px solid #999;font-family:"lucida console",verdana,tahoma,"sans serif";font-size:x-small;line-height:1.5em;opacity:0.9;filter:alpha(opacity=90);
|
||||
}
|
||||
|
||||
body {
|
||||
font:75% normal verdana,arial,tahoma,"sans serif";
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
font:3em arial,tahoma,verdana;
|
||||
font-weight:normal;
|
||||
margin-bottom:0px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top:0.25em;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
letter-spacing: -0.005em; /* zomg web x.0! ;) */
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size:2em;
|
||||
margin-top:0px;
|
||||
margin-bottom:0.1em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size:1.5em;
|
||||
margin-bottom:1em;
|
||||
}
|
||||
|
||||
h1 a,
|
||||
h1 a:hover {
|
||||
color:#000;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
h1 a:hover {
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
ul.notes {
|
||||
margin-left:0px;
|
||||
padding-left:1.5em;
|
||||
}
|
||||
|
||||
.note {
|
||||
margin-top:0px;
|
||||
font-style:italic;
|
||||
color:#999;
|
||||
margin-bottom:0px;
|
||||
}
|
||||
|
||||
#left {
|
||||
max-width:56em;
|
||||
margin-left:1em;
|
||||
}
|
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 493 B |
After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1,173 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
||||
<head>
|
||||
<title>360° MP3 player UI demo (SoundManager 2)</title>
|
||||
<meta name="robots" content="noindex" />
|
||||
<meta name="description" content="Javascript-driven sound, canvas-based MP3 player UI demo: 360-degree circular control / jog wheel example for playing MP3 links using SoundManager 2, Javascript and Canvas.">
|
||||
|
||||
<!-- required -->
|
||||
<link rel="stylesheet" type="text/css" href="360player.css" />
|
||||
|
||||
<!-- special IE-only canvas fix -->
|
||||
<!--[if IE]><script type="text/javascript" src="script/excanvas.js"></script><![endif]-->
|
||||
|
||||
<!-- Apache-licensed animation library -->
|
||||
<script type="text/javascript" src="script/berniecode-animator.js"></script>
|
||||
|
||||
<!-- the core stuff -->
|
||||
<script type="text/javascript" src="../../script/soundmanager2.js"></script>
|
||||
<script type="text/javascript" src="script/360player.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
soundManager.setup({
|
||||
// path to directory containing SM2 SWF
|
||||
url: '../../swf/'
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- stuff you don't need -->
|
||||
<!-- makes the fonts nicer etc. -->
|
||||
<link rel="stylesheet" type="text/css" href="../index.css" />
|
||||
<link rel="stylesheet" type="text/css" href="demo.css" />
|
||||
|
||||
<!-- soundManager.useFlashBlock: related CSS -->
|
||||
<link rel="stylesheet" type="text/css" href="../flashblock/flashblock.css" />
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
/* Demo page, general layout */
|
||||
|
||||
body {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
#left {
|
||||
position:relative;
|
||||
width:950px;
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
#left h2 {
|
||||
padding-top:0px;
|
||||
margin-bottom:0.25em;
|
||||
color:#666;
|
||||
}
|
||||
|
||||
pre.block {
|
||||
margin-top:0.5em;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="left">
|
||||
|
||||
<h1><a href="http://www.schillmania.com/projects/soundmanager2/" title="Javascript MP3 player project home">SoundManager 2</a> / <a href="http://schillmania.com/projects/soundmanager2/demo/360-player/">360° Player</a>: JavaScript + Canvas UI</h1>
|
||||
|
||||
<p class="note" style="color:#666;margin-top:0.5em;margin-bottom:0.5em">Canvas-based UI. Load progress, seek, play/pause etc. Also see <a href="canvas-visualization.html" title="Javascript canvas visualization with waveform/eq data">360° UI visualization</a> demo.</p>
|
||||
|
||||
<div id="sm2-container">
|
||||
<!-- flash movie is added here -->
|
||||
</div>
|
||||
|
||||
<div style="margin-top:1.25em">
|
||||
|
||||
<div style="float:left;display:inline;min-width:200px"> <!-- float is just for this demo layout, you don't need it. -->
|
||||
|
||||
<div class="ui360" style="margin-top:-0.55em"><a href="../_mp3/rain.mp3">Rain</a></div>
|
||||
|
||||
<div class="ui360"><a href="http://freshly-ground.com/data/audio/mpc/20090119%20-%20Untitled%20Groove.mp3">20090119 - Untitled Groove</a></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div style="float:left;display:inline;margin-left:40px;border-left:1px solid #ccc;padding-left:30px;width:152px">
|
||||
|
||||
<p style="margin-top:1em;margin-bottom:0px">Alternate style: inline</p>
|
||||
|
||||
<div class="sm2-inline-list" style="margin-bottom:10px"> <!-- note the CSS class, changes the layout -->
|
||||
|
||||
<div class="ui360"><a href="http://www.freshly-ground.com/data/audio/binaural/Mak.mp3">Angry cow sound?</a></div>
|
||||
<div class="ui360"><a href="http://www.freshly-ground.com/data/audio/binaural/Things that open, close and roll.mp3">Things that open, close and roll</a></div>
|
||||
<div class="ui360"><a href="http://www.freshly-ground.com/misc/music/20060826%20-%20Armstrong.mp3">20060826 - Armstrong</a></div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="clear:both"></div>
|
||||
|
||||
|
||||
<h3>How This Works</h3>
|
||||
|
||||
<p>The script looks for a container element matching <code>div.<span>ui360</span></code>, and then the first link inside of it.</p>
|
||||
|
||||
<div>
|
||||
|
||||
<pre class="block"><code><div class="<span>ui360</span>">
|
||||
<a href="/path/to/an.mp3">play "an.mp3"</a>
|
||||
</div></code></pre>
|
||||
|
||||
</div>
|
||||
|
||||
<p>When the 360 player script loads, it adds a <code>UI</code> template to the block, prepending it in front of the MP3 link:</p>
|
||||
|
||||
<pre class="block"><code><div class="<span>ui360</span>">
|
||||
<span><span><-- dynamically-inserted block --></span></span>
|
||||
<div class="<span>ui</span>">
|
||||
<canvas class="<span>sm2-canvas</span>"></canvas>
|
||||
<span class="<span>sm2-360btn</span>"></span>
|
||||
<div class="<span>sm2-timing</span>"></div>
|
||||
<div class="<span>sm2-cover</span>"></div>
|
||||
</div>
|
||||
<span><span><-- /UI --></span></span>
|
||||
<a href="<span>/path/to/an.mp3</span>">
|
||||
</div></code></pre>
|
||||
|
||||
<h3>Customizing the UI</h3>
|
||||
|
||||
<p>The player's default 50x50-pixel canvas is defined both within JavaScript and CSS. For an example with different values, see this <a href="canvas-visualization.html" title="360° UI: larger version">larger version</a>.</p>
|
||||
|
||||
<pre class="block"><code>threeSixtyPlayer.config = {
|
||||
playNext: <span>false</span>, <span><span>// stop after one sound, or play through list until end</span></span>
|
||||
autoPlay: <span>false</span>, <span><span>// start playing the first sound right away</span></span>
|
||||
allowMultiple: <span>true</span>, <span><span>// let many sounds play at once (false = one at a time)</span></span>
|
||||
loadRingColor: <span>'#ccc',</span> <span><span>// amount of sound which has loaded</span></span>
|
||||
playRingColor: <span>'#000'</span>, <span><span>// amount of sound which has played</span></span>
|
||||
backgroundRingColor: <span>'#eee', </span><span><span>// "default" color shown underneath everything else</span></span>
|
||||
animDuration: <span>500</span>,
|
||||
animTransition: <span>Animator.tx.bouncy</span> <span><span>// http://www.berniecode.com/writing/animator.html</span></span>
|
||||
}</code></pre>
|
||||
|
||||
<p>The CSS for the canvas UI block is a bit ugly, but JavaScript reads the width of the <code>.sm2-360ui</code> element in the DOM as set by CSS and uses that to later draw and update the canvas element while playing.</p>
|
||||
|
||||
<pre class="block"><code>.ui360,
|
||||
.sm2-360ui {
|
||||
<span><span>/* size of the container for the circle, etc. */</span></span>
|
||||
width:<span>50px</span>;
|
||||
height:<span>50px</span>;
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<h3>Third-party Components</h3>
|
||||
|
||||
<p>This demo includes use of <a href="http://www.berniecode.com/writing/animator.html">Bernie's Better Animation Class</a> (Apache licensed) for some animation effects.</p>
|
||||
<p>Also, some loader/spinner icons from <a href="http://ajaxload.info">ajaxload.info</a> are used for showing loading/buffering states.</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<p>
|
||||
<a href="http://www.schillmania.com/projects/soundmanager2/" title="SoundManager 2 home">SoundManager 2 project page</a> (not an MP3 link)
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,674 @@
|
|||
/** @license
|
||||
Animator.js 1.1.9
|
||||
|
||||
This library is released under the BSD license:
|
||||
|
||||
Copyright (c) 2006, Bernard Sumption. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer. Redistributions in binary
|
||||
form must reproduce the above copyright notice, this list of conditions and
|
||||
the following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution. Neither the name BernieCode nor
|
||||
the names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
// http://www.berniecode.com/writing/animator.html
|
||||
|
||||
// Applies a sequence of numbers between 0 and 1 to a number of subjects
|
||||
// construct - see setOptions for parameters
|
||||
function Animator(options) {
|
||||
this.setOptions(options);
|
||||
var _this = this;
|
||||
this.timerDelegate = function(){_this.onTimerEvent()};
|
||||
this.subjects = [];
|
||||
this.subjectScopes = [];
|
||||
this.target = 0;
|
||||
this.state = 0;
|
||||
this.lastTime = null;
|
||||
};
|
||||
Animator.prototype = {
|
||||
// apply defaults
|
||||
setOptions: function(options) {
|
||||
this.options = Animator.applyDefaults({
|
||||
interval: 20, // time between animation frames
|
||||
duration: 400, // length of animation
|
||||
onComplete: function(){},
|
||||
onStep: function(){},
|
||||
transition: Animator.tx.easeInOut
|
||||
}, options);
|
||||
},
|
||||
// animate from the current state to provided value
|
||||
seekTo: function(to) {
|
||||
this.seekFromTo(this.state, to);
|
||||
},
|
||||
// animate from the current state to provided value
|
||||
seekFromTo: function(from, to) {
|
||||
this.target = Math.max(0, Math.min(1, to));
|
||||
this.state = Math.max(0, Math.min(1, from));
|
||||
this.lastTime = new Date().getTime();
|
||||
if (!this.intervalId) {
|
||||
this.intervalId = window.setInterval(this.timerDelegate, this.options.interval);
|
||||
}
|
||||
},
|
||||
// animate from the current state to provided value
|
||||
jumpTo: function(to) {
|
||||
this.target = this.state = Math.max(0, Math.min(1, to));
|
||||
this.propagate();
|
||||
},
|
||||
// seek to the opposite of the current target
|
||||
toggle: function() {
|
||||
this.seekTo(1 - this.target);
|
||||
},
|
||||
// add a function or an object with a method setState(state) that will be called with a number
|
||||
// between 0 and 1 on each frame of the animation
|
||||
addSubject: function(subject,scope) {
|
||||
this.subjects[this.subjects.length] = subject;
|
||||
this.subjectScopes[this.subjectScopes.length] = scope;
|
||||
return this;
|
||||
},
|
||||
// remove all subjects
|
||||
clearSubjects: function() {
|
||||
this.subjects = [];
|
||||
this.subjectScopes = [];
|
||||
},
|
||||
// forward the current state to the animation subjects
|
||||
propagate: function() {
|
||||
var value = this.options.transition(this.state);
|
||||
for (var i=0; i<this.subjects.length; i++) {
|
||||
if (this.subjects[i].setState) {
|
||||
this.subjects[i].setState(value);
|
||||
} else {
|
||||
this.subjects[i].apply(this.subjectScopes[i],[value]);
|
||||
}
|
||||
}
|
||||
},
|
||||
// called once per frame to update the current state
|
||||
onTimerEvent: function() {
|
||||
var now = new Date().getTime();
|
||||
var timePassed = now - this.lastTime;
|
||||
this.lastTime = now;
|
||||
var movement = (timePassed / this.options.duration) * (this.state < this.target ? 1 : -1);
|
||||
if (Math.abs(movement) >= Math.abs(this.state - this.target)) {
|
||||
this.state = this.target;
|
||||
} else {
|
||||
this.state += movement;
|
||||
}
|
||||
|
||||
try {
|
||||
this.propagate();
|
||||
} finally {
|
||||
this.options.onStep.call(this);
|
||||
if (this.target == this.state) {
|
||||
window.clearInterval(this.intervalId);
|
||||
this.intervalId = null;
|
||||
this.options.onComplete.call(this);
|
||||
}
|
||||
}
|
||||
},
|
||||
// shortcuts
|
||||
play: function() {this.seekFromTo(0, 1)},
|
||||
reverse: function() {this.seekFromTo(1, 0)},
|
||||
// return a string describing this Animator, for debugging
|
||||
inspect: function() {
|
||||
var str = "#<Animator:\n";
|
||||
for (var i=0; i<this.subjects.length; i++) {
|
||||
str += this.subjects[i].inspect();
|
||||
}
|
||||
str += ">";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
// merge the properties of two objects
|
||||
Animator.applyDefaults = function(defaults, prefs) {
|
||||
prefs = prefs || {};
|
||||
var prop, result = {};
|
||||
for (prop in defaults) result[prop] = prefs[prop] !== undefined ? prefs[prop] : defaults[prop];
|
||||
return result;
|
||||
}
|
||||
// make an array from any object
|
||||
Animator.makeArray = function(o) {
|
||||
if (o == null) return [];
|
||||
if (!o.length) return [o];
|
||||
var result = [];
|
||||
for (var i=0; i<o.length; i++) result[i] = o[i];
|
||||
return result;
|
||||
}
|
||||
// convert a dash-delimited-property to a camelCaseProperty (c/o Prototype, thanks Sam!)
|
||||
Animator.camelize = function(string) {
|
||||
var oStringList = string.split('-');
|
||||
if (oStringList.length == 1) return oStringList[0];
|
||||
|
||||
var camelizedString = string.indexOf('-') == 0
|
||||
? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
|
||||
: oStringList[0];
|
||||
|
||||
for (var i = 1, len = oStringList.length; i < len; i++) {
|
||||
var s = oStringList[i];
|
||||
camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
|
||||
}
|
||||
return camelizedString;
|
||||
}
|
||||
// syntactic sugar for creating CSSStyleSubjects
|
||||
Animator.apply = function(el, style, options) {
|
||||
if (style instanceof Array) {
|
||||
return new Animator(options).addSubject(new CSSStyleSubject(el, style[0], style[1]));
|
||||
}
|
||||
return new Animator(options).addSubject(new CSSStyleSubject(el, style));
|
||||
}
|
||||
// make a transition function that gradually accelerates. pass a=1 for smooth
|
||||
// gravitational acceleration, higher values for an exaggerated effect
|
||||
Animator.makeEaseIn = function(a) {
|
||||
return function(state) {
|
||||
return Math.pow(state, a*2);
|
||||
}
|
||||
}
|
||||
// as makeEaseIn but for deceleration
|
||||
Animator.makeEaseOut = function(a) {
|
||||
return function(state) {
|
||||
return 1 - Math.pow(1 - state, a*2);
|
||||
}
|
||||
}
|
||||
// make a transition function that, like an object with momentum being attracted to a point,
|
||||
// goes past the target then returns
|
||||
Animator.makeElastic = function(bounces) {
|
||||
return function(state) {
|
||||
state = Animator.tx.easeInOut(state);
|
||||
return ((1-Math.cos(state * Math.PI * bounces)) * (1 - state)) + state;
|
||||
}
|
||||
}
|
||||
// make an Attack Decay Sustain Release envelope that starts and finishes on the same level
|
||||
//
|
||||
Animator.makeADSR = function(attackEnd, decayEnd, sustainEnd, sustainLevel) {
|
||||
if (sustainLevel == null) sustainLevel = 0.5;
|
||||
return function(state) {
|
||||
if (state < attackEnd) {
|
||||
return state / attackEnd;
|
||||
}
|
||||
if (state < decayEnd) {
|
||||
return 1 - ((state - attackEnd) / (decayEnd - attackEnd) * (1 - sustainLevel));
|
||||
}
|
||||
if (state < sustainEnd) {
|
||||
return sustainLevel;
|
||||
}
|
||||
return sustainLevel * (1 - ((state - sustainEnd) / (1 - sustainEnd)));
|
||||
}
|
||||
}
|
||||
// make a transition function that, like a ball falling to floor, reaches the target and/
|
||||
// bounces back again
|
||||
Animator.makeBounce = function(bounces) {
|
||||
var fn = Animator.makeElastic(bounces);
|
||||
return function(state) {
|
||||
state = fn(state);
|
||||
return state <= 1 ? state : 2-state;
|
||||
}
|
||||
}
|
||||
|
||||
// pre-made transition functions to use with the 'transition' option
|
||||
Animator.tx = {
|
||||
easeInOut: function(pos){
|
||||
return ((-Math.cos(pos*Math.PI)/2) + 0.5);
|
||||
},
|
||||
linear: function(x) {
|
||||
return x;
|
||||
},
|
||||
easeIn: Animator.makeEaseIn(1.5),
|
||||
easeOut: Animator.makeEaseOut(1.5),
|
||||
strongEaseIn: Animator.makeEaseIn(2.5),
|
||||
strongEaseOut: Animator.makeEaseOut(2.5),
|
||||
elastic: Animator.makeElastic(1),
|
||||
veryElastic: Animator.makeElastic(3),
|
||||
bouncy: Animator.makeBounce(1),
|
||||
veryBouncy: Animator.makeBounce(3)
|
||||
}
|
||||
|
||||
// animates a pixel-based style property between two integer values
|
||||
function NumericalStyleSubject(els, property, from, to, units) {
|
||||
this.els = Animator.makeArray(els);
|
||||
if (property == 'opacity' && window.ActiveXObject) {
|
||||
this.property = 'filter';
|
||||
} else {
|
||||
this.property = Animator.camelize(property);
|
||||
}
|
||||
this.from = parseFloat(from);
|
||||
this.to = parseFloat(to);
|
||||
this.units = units != null ? units : 'px';
|
||||
}
|
||||
NumericalStyleSubject.prototype = {
|
||||
setState: function(state) {
|
||||
var style = this.getStyle(state);
|
||||
var visibility = (this.property == 'opacity' && state == 0) ? 'hidden' : '';
|
||||
var j=0;
|
||||
for (var i=0; i<this.els.length; i++) {
|
||||
try {
|
||||
this.els[i].style[this.property] = style;
|
||||
} catch (e) {
|
||||
// ignore fontWeight - intermediate numerical values cause exeptions in firefox
|
||||
if (this.property != 'fontWeight') throw e;
|
||||
}
|
||||
if (j++ > 20) return;
|
||||
}
|
||||
},
|
||||
getStyle: function(state) {
|
||||
state = this.from + ((this.to - this.from) * state);
|
||||
if (this.property == 'filter') return "alpha(opacity=" + Math.round(state*100) + ")";
|
||||
if (this.property == 'opacity') return state;
|
||||
return Math.round(state) + this.units;
|
||||
},
|
||||
inspect: function() {
|
||||
return "\t" + this.property + "(" + this.from + this.units + " to " + this.to + this.units + ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
// animates a colour based style property between two hex values
|
||||
function ColorStyleSubject(els, property, from, to) {
|
||||
this.els = Animator.makeArray(els);
|
||||
this.property = Animator.camelize(property);
|
||||
this.to = this.expandColor(to);
|
||||
this.from = this.expandColor(from);
|
||||
this.origFrom = from;
|
||||
this.origTo = to;
|
||||
}
|
||||
|
||||
ColorStyleSubject.prototype = {
|
||||
// parse "#FFFF00" to [256, 256, 0]
|
||||
expandColor: function(color) {
|
||||
var hexColor, red, green, blue;
|
||||
hexColor = ColorStyleSubject.parseColor(color);
|
||||
if (hexColor) {
|
||||
red = parseInt(hexColor.slice(1, 3), 16);
|
||||
green = parseInt(hexColor.slice(3, 5), 16);
|
||||
blue = parseInt(hexColor.slice(5, 7), 16);
|
||||
return [red,green,blue]
|
||||
}
|
||||
if (window.DEBUG) {
|
||||
alert("Invalid colour: '" + color + "'");
|
||||
}
|
||||
},
|
||||
getValueForState: function(color, state) {
|
||||
return Math.round(this.from[color] + ((this.to[color] - this.from[color]) * state));
|
||||
},
|
||||
setState: function(state) {
|
||||
var color = '#'
|
||||
+ ColorStyleSubject.toColorPart(this.getValueForState(0, state))
|
||||
+ ColorStyleSubject.toColorPart(this.getValueForState(1, state))
|
||||
+ ColorStyleSubject.toColorPart(this.getValueForState(2, state));
|
||||
for (var i=0; i<this.els.length; i++) {
|
||||
this.els[i].style[this.property] = color;
|
||||
}
|
||||
},
|
||||
inspect: function() {
|
||||
return "\t" + this.property + "(" + this.origFrom + " to " + this.origTo + ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
// return a properly formatted 6-digit hex colour spec, or false
|
||||
ColorStyleSubject.parseColor = function(string) {
|
||||
var color = '#', match;
|
||||
if(match = ColorStyleSubject.parseColor.rgbRe.exec(string)) {
|
||||
var part;
|
||||
for (var i=1; i<=3; i++) {
|
||||
part = Math.max(0, Math.min(255, parseInt(match[i])));
|
||||
color += ColorStyleSubject.toColorPart(part);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
if (match = ColorStyleSubject.parseColor.hexRe.exec(string)) {
|
||||
if(match[1].length == 3) {
|
||||
for (var i=0; i<3; i++) {
|
||||
color += match[1].charAt(i) + match[1].charAt(i);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
return '#' + match[1];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// convert a number to a 2 digit hex string
|
||||
ColorStyleSubject.toColorPart = function(number) {
|
||||
if (number > 255) number = 255;
|
||||
var digits = number.toString(16);
|
||||
if (number < 16) return '0' + digits;
|
||||
return digits;
|
||||
}
|
||||
ColorStyleSubject.parseColor.rgbRe = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i;
|
||||
ColorStyleSubject.parseColor.hexRe = /^\#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
||||
|
||||
// Animates discrete styles, i.e. ones that do not scale but have discrete values
|
||||
// that can't be interpolated
|
||||
function DiscreteStyleSubject(els, property, from, to, threshold) {
|
||||
this.els = Animator.makeArray(els);
|
||||
this.property = Animator.camelize(property);
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.threshold = threshold || 0.5;
|
||||
}
|
||||
|
||||
DiscreteStyleSubject.prototype = {
|
||||
setState: function(state) {
|
||||
var j=0;
|
||||
for (var i=0; i<this.els.length; i++) {
|
||||
this.els[i].style[this.property] = state <= this.threshold ? this.from : this.to;
|
||||
}
|
||||
},
|
||||
inspect: function() {
|
||||
return "\t" + this.property + "(" + this.from + " to " + this.to + " @ " + this.threshold + ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
// animates between two styles defined using CSS.
|
||||
// if style1 and style2 are present, animate between them, if only style1
|
||||
// is present, animate between the element's current style and style1
|
||||
function CSSStyleSubject(els, style1, style2) {
|
||||
els = Animator.makeArray(els);
|
||||
this.subjects = [];
|
||||
if (els.length == 0) return;
|
||||
var prop, toStyle, fromStyle;
|
||||
if (style2) {
|
||||
fromStyle = this.parseStyle(style1, els[0]);
|
||||
toStyle = this.parseStyle(style2, els[0]);
|
||||
} else {
|
||||
toStyle = this.parseStyle(style1, els[0]);
|
||||
fromStyle = {};
|
||||
for (prop in toStyle) {
|
||||
fromStyle[prop] = CSSStyleSubject.getStyle(els[0], prop);
|
||||
}
|
||||
}
|
||||
// remove unchanging properties
|
||||
var prop;
|
||||
for (prop in fromStyle) {
|
||||
if (fromStyle[prop] == toStyle[prop]) {
|
||||
delete fromStyle[prop];
|
||||
delete toStyle[prop];
|
||||
}
|
||||
}
|
||||
// discover the type (numerical or colour) of each style
|
||||
var prop, units, match, type, from, to;
|
||||
for (prop in fromStyle) {
|
||||
var fromProp = String(fromStyle[prop]);
|
||||
var toProp = String(toStyle[prop]);
|
||||
if (toStyle[prop] == null) {
|
||||
if (window.DEBUG) alert("No to style provided for '" + prop + '"');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (from = ColorStyleSubject.parseColor(fromProp)) {
|
||||
to = ColorStyleSubject.parseColor(toProp);
|
||||
type = ColorStyleSubject;
|
||||
} else if (fromProp.match(CSSStyleSubject.numericalRe)
|
||||
&& toProp.match(CSSStyleSubject.numericalRe)) {
|
||||
from = parseFloat(fromProp);
|
||||
to = parseFloat(toProp);
|
||||
type = NumericalStyleSubject;
|
||||
match = CSSStyleSubject.numericalRe.exec(fromProp);
|
||||
var reResult = CSSStyleSubject.numericalRe.exec(toProp);
|
||||
if (match[1] != null) {
|
||||
units = match[1];
|
||||
} else if (reResult[1] != null) {
|
||||
units = reResult[1];
|
||||
} else {
|
||||
units = reResult;
|
||||
}
|
||||
} else if (fromProp.match(CSSStyleSubject.discreteRe)
|
||||
&& toProp.match(CSSStyleSubject.discreteRe)) {
|
||||
from = fromProp;
|
||||
to = toProp;
|
||||
type = DiscreteStyleSubject;
|
||||
units = 0; // hack - how to get an animator option down to here
|
||||
} else {
|
||||
if (window.DEBUG) {
|
||||
alert("Unrecognised format for value of "
|
||||
+ prop + ": '" + fromStyle[prop] + "'");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
this.subjects[this.subjects.length] = new type(els, prop, from, to, units);
|
||||
}
|
||||
}
|
||||
|
||||
CSSStyleSubject.prototype = {
|
||||
// parses "width: 400px; color: #FFBB2E" to {width: "400px", color: "#FFBB2E"}
|
||||
parseStyle: function(style, el) {
|
||||
var rtn = {};
|
||||
// if style is a rule set
|
||||
if (style.indexOf(":") != -1) {
|
||||
var styles = style.split(";");
|
||||
for (var i=0; i<styles.length; i++) {
|
||||
var parts = CSSStyleSubject.ruleRe.exec(styles[i]);
|
||||
if (parts) {
|
||||
rtn[parts[1]] = parts[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
// else assume style is a class name
|
||||
else {
|
||||
var prop, value, oldClass;
|
||||
oldClass = el.className;
|
||||
el.className = style;
|
||||
for (var i=0; i<CSSStyleSubject.cssProperties.length; i++) {
|
||||
prop = CSSStyleSubject.cssProperties[i];
|
||||
value = CSSStyleSubject.getStyle(el, prop);
|
||||
if (value != null) {
|
||||
rtn[prop] = value;
|
||||
}
|
||||
}
|
||||
el.className = oldClass;
|
||||
}
|
||||
return rtn;
|
||||
|
||||
},
|
||||
setState: function(state) {
|
||||
for (var i=0; i<this.subjects.length; i++) {
|
||||
this.subjects[i].setState(state);
|
||||
}
|
||||
},
|
||||
inspect: function() {
|
||||
var str = "";
|
||||
for (var i=0; i<this.subjects.length; i++) {
|
||||
str += this.subjects[i].inspect();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
// get the current value of a css property,
|
||||
CSSStyleSubject.getStyle = function(el, property){
|
||||
var style;
|
||||
if(document.defaultView && document.defaultView.getComputedStyle){
|
||||
style = document.defaultView.getComputedStyle(el, "").getPropertyValue(property);
|
||||
if (style) {
|
||||
return style;
|
||||
}
|
||||
}
|
||||
property = Animator.camelize(property);
|
||||
if(el.currentStyle){
|
||||
style = el.currentStyle[property];
|
||||
}
|
||||
return style || el.style[property]
|
||||
}
|
||||
|
||||
|
||||
CSSStyleSubject.ruleRe = /^\s*([a-zA-Z\-]+)\s*:\s*(\S(.+\S)?)\s*$/;
|
||||
CSSStyleSubject.numericalRe = /^-?\d+(?:\.\d+)?(%|[a-zA-Z]{2})?$/;
|
||||
CSSStyleSubject.discreteRe = /^\w+$/;
|
||||
|
||||
// required because the style object of elements isn't enumerable in Safari
|
||||
/*
|
||||
CSSStyleSubject.cssProperties = ['background-color','border','border-color','border-spacing',
|
||||
'border-style','border-top','border-right','border-bottom','border-left','border-top-color',
|
||||
'border-right-color','border-bottom-color','border-left-color','border-top-width','border-right-width',
|
||||
'border-bottom-width','border-left-width','border-width','bottom','color','font-size','font-size-adjust',
|
||||
'font-stretch','font-style','height','left','letter-spacing','line-height','margin','margin-top',
|
||||
'margin-right','margin-bottom','margin-left','marker-offset','max-height','max-width','min-height',
|
||||
'min-width','orphans','outline','outline-color','outline-style','outline-width','overflow','padding',
|
||||
'padding-top','padding-right','padding-bottom','padding-left','quotes','right','size','text-indent',
|
||||
'top','width','word-spacing','z-index','opacity','outline-offset'];*/
|
||||
|
||||
|
||||
CSSStyleSubject.cssProperties = ['azimuth','background','background-attachment','background-color','background-image','background-position','background-repeat','border-collapse','border-color','border-spacing','border-style','border-top','border-top-color','border-right-color','border-bottom-color','border-left-color','border-top-style','border-right-style','border-bottom-style','border-left-style','border-top-width','border-right-width','border-bottom-width','border-left-width','border-width','bottom','clear','clip','color','content','cursor','direction','display','elevation','empty-cells','css-float','font','font-family','font-size','font-size-adjust','font-stretch','font-style','font-variant','font-weight','height','left','letter-spacing','line-height','list-style','list-style-image','list-style-position','list-style-type','margin','margin-top','margin-right','margin-bottom','margin-left','max-height','max-width','min-height','min-width','orphans','outline','outline-color','outline-style','outline-width','overflow','padding','padding-top','padding-right','padding-bottom','padding-left','pause','position','right','size','table-layout','text-align','text-decoration','text-indent','text-shadow','text-transform','top','vertical-align','visibility','white-space','width','word-spacing','z-index','opacity','outline-offset','overflow-x','overflow-y'];
|
||||
|
||||
|
||||
// chains several Animator objects together
|
||||
function AnimatorChain(animators, options) {
|
||||
this.animators = animators;
|
||||
this.setOptions(options);
|
||||
for (var i=0; i<this.animators.length; i++) {
|
||||
this.listenTo(this.animators[i]);
|
||||
}
|
||||
this.forwards = false;
|
||||
this.current = 0;
|
||||
}
|
||||
|
||||
AnimatorChain.prototype = {
|
||||
// apply defaults
|
||||
setOptions: function(options) {
|
||||
this.options = Animator.applyDefaults({
|
||||
// by default, each call to AnimatorChain.play() calls jumpTo(0) of each animator
|
||||
// before playing, which can cause flickering if you have multiple animators all
|
||||
// targeting the same element. Set this to false to avoid this.
|
||||
resetOnPlay: true
|
||||
}, options);
|
||||
},
|
||||
// play each animator in turn
|
||||
play: function() {
|
||||
this.forwards = true;
|
||||
this.current = -1;
|
||||
if (this.options.resetOnPlay) {
|
||||
for (var i=0; i<this.animators.length; i++) {
|
||||
this.animators[i].jumpTo(0);
|
||||
}
|
||||
}
|
||||
this.advance();
|
||||
},
|
||||
// play all animators backwards
|
||||
reverse: function() {
|
||||
this.forwards = false;
|
||||
this.current = this.animators.length;
|
||||
if (this.options.resetOnPlay) {
|
||||
for (var i=0; i<this.animators.length; i++) {
|
||||
this.animators[i].jumpTo(1);
|
||||
}
|
||||
}
|
||||
this.advance();
|
||||
},
|
||||
// if we have just play()'d, then call reverse(), and vice versa
|
||||
toggle: function() {
|
||||
if (this.forwards) {
|
||||
this.seekTo(0);
|
||||
} else {
|
||||
this.seekTo(1);
|
||||
}
|
||||
},
|
||||
// internal: install an event listener on an animator's onComplete option
|
||||
// to trigger the next animator
|
||||
listenTo: function(animator) {
|
||||
var oldOnComplete = animator.options.onComplete;
|
||||
var _this = this;
|
||||
animator.options.onComplete = function() {
|
||||
if (oldOnComplete) oldOnComplete.call(animator);
|
||||
_this.advance();
|
||||
}
|
||||
},
|
||||
// play the next animator
|
||||
advance: function() {
|
||||
if (this.forwards) {
|
||||
if (this.animators[this.current + 1] == null) return;
|
||||
this.current++;
|
||||
this.animators[this.current].play();
|
||||
} else {
|
||||
if (this.animators[this.current - 1] == null) return;
|
||||
this.current--;
|
||||
this.animators[this.current].reverse();
|
||||
}
|
||||
},
|
||||
// this function is provided for drop-in compatibility with Animator objects,
|
||||
// but only accepts 0 and 1 as target values
|
||||
seekTo: function(target) {
|
||||
if (target <= 0) {
|
||||
this.forwards = false;
|
||||
this.animators[this.current].seekTo(0);
|
||||
} else {
|
||||
this.forwards = true;
|
||||
this.animators[this.current].seekTo(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// an Accordion is a class that creates and controls a number of Animators. An array of elements is passed in,
|
||||
// and for each element an Animator and a activator button is created. When an Animator's activator button is
|
||||
// clicked, the Animator and all before it seek to 0, and all Animators after it seek to 1. This can be used to
|
||||
// create the classic Accordion effect, hence the name.
|
||||
// see setOptions for arguments
|
||||
function Accordion(options) {
|
||||
this.setOptions(options);
|
||||
var selected = this.options.initialSection, current;
|
||||
if (this.options.rememberance) {
|
||||
current = document.location.hash.substring(1);
|
||||
}
|
||||
this.rememberanceTexts = [];
|
||||
this.ans = [];
|
||||
var _this = this;
|
||||
for (var i=0; i<this.options.sections.length; i++) {
|
||||
var el = this.options.sections[i];
|
||||
var an = new Animator(this.options.animatorOptions);
|
||||
var from = this.options.from + (this.options.shift * i);
|
||||
var to = this.options.to + (this.options.shift * i);
|
||||
an.addSubject(new NumericalStyleSubject(el, this.options.property, from, to, this.options.units));
|
||||
an.jumpTo(0);
|
||||
var activator = this.options.getActivator(el);
|
||||
activator.index = i;
|
||||
activator.onclick = function(){_this.show(this.index)};
|
||||
this.ans[this.ans.length] = an;
|
||||
this.rememberanceTexts[i] = activator.innerHTML.replace(/\s/g, "");
|
||||
if (this.rememberanceTexts[i] === current) {
|
||||
selected = i;
|
||||
}
|
||||
}
|
||||
this.show(selected);
|
||||
}
|
||||
|
||||
Accordion.prototype = {
|
||||
// apply defaults
|
||||
setOptions: function(options) {
|
||||
this.options = Object.extend({
|
||||
// REQUIRED: an array of elements to use as the accordion sections
|
||||
sections: null,
|
||||
// a function that locates an activator button element given a section element.
|
||||
// by default it takes a button id from the section's "activator" attibute
|
||||
getActivator: function(el) {return document.getElementById(el.getAttribute("activator"))},
|
||||
// shifts each animator's range, for example with options {from:0,to:100,shift:20}
|
||||
// the animators' ranges will be 0-100, 20-120, 40-140 etc.
|
||||
shift: 0,
|
||||
// the first page to show
|
||||
initialSection: 0,
|
||||
// if set to true, document.location.hash will be used to preserve the open section across page reloads
|
||||
rememberance: true,
|
||||
// constructor arguments to the Animator objects
|
||||
animatorOptions: {}
|
||||
}, options || {});
|
||||
},
|
||||
show: function(section) {
|
||||
for (var i=0; i<this.ans.length; i++) {
|
||||
this.ans[i].seekTo(i > section ? 1 : 0);
|
||||
}
|
||||
if (this.options.rememberance) {
|
||||
document.location.hash = this.rememberanceTexts[section];
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 12 KiB |