Merge branch 'develop' of github.com:Connoropolous/metamaps_gen002

This commit is contained in:
Robert Best 2014-08-15 22:47:45 -04:00
commit d55d939971
533 changed files with 71434 additions and 13974 deletions

14
Gemfile
View file

@ -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

View file

@ -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

View file

@ -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'

View file

@ -4,4 +4,4 @@
require File.expand_path('../config/application', __FILE__)
ISSAD::Application.load_tasks
Metamaps::Application.load_tasks

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

BIN
app/assets/images/fork.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

BIN
app/assets/images/junto.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

BIN
app/assets/images/new.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

View file

Before

Width:  |  Height:  |  Size: 180 B

After

Width:  |  Height:  |  Size: 180 B

View file

Before

Width:  |  Height:  |  Size: 178 B

After

Width:  |  Height:  |  Size: 178 B

View file

Before

Width:  |  Height:  |  Size: 120 B

After

Width:  |  Height:  |  Size: 120 B

View file

Before

Width:  |  Height:  |  Size: 105 B

After

Width:  |  Height:  |  Size: 105 B

View file

Before

Width:  |  Height:  |  Size: 111 B

After

Width:  |  Height:  |  Size: 111 B

View file

Before

Width:  |  Height:  |  Size: 110 B

After

Width:  |  Height:  |  Size: 110 B

View file

Before

Width:  |  Height:  |  Size: 119 B

After

Width:  |  Height:  |  Size: 119 B

View file

Before

Width:  |  Height:  |  Size: 101 B

After

Width:  |  Height:  |  Size: 101 B

View file

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

File diff suppressed because it is too large Load diff

View file

@ -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;
}
});
});

View file

@ -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);
}

View file

@ -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;

View file

@ -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) {
// '&amp;' 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) {
// '&amp;' 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

View file

@ -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
}

View file

@ -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";
}

View file

@ -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">&lt;</label>');
$('#edit_synapse').append('<input type="checkbox" id="edit_synapse_right">');
$('#edit_synapse').append('<label class="right">&gt;</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);
}
}

View file

@ -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);
});
}

View file

@ -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

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View 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);

File diff suppressed because one or more lines are too long

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 881 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,009 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,001 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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&deg; 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&deg; 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 &lt; 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>

View file

@ -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&deg; 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&deg; 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 &lt; 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&deg; player UI">default 360&deg; 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>

View file

@ -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;
}

View file

@ -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
}
});
}

View file

@ -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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -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&deg; 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&deg; 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&deg; 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>&lt;div class="<span>ui360</span>"&gt;
&lt;a href="/path/to/an.mp3"&gt;play "an.mp3"&lt;/a&gt;
&lt;/div&gt;</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>&lt;div class="<span>ui360</span>"&gt;
<span><span>&lt;-- dynamically-inserted block --&gt;</span></span>
&lt;div class="<span>ui</span>"&gt;
&lt;canvas class="<span>sm2-canvas</span>"&gt;&lt;/canvas&gt;
&lt;span class="<span>sm2-360btn</span>"&gt;&lt;/span&gt;
&lt;div class="<span>sm2-timing</span>"&gt;&lt;/div&gt;
&lt;div class="<span>sm2-cover</span>"&gt;&lt;/div&gt;
&lt;/div&gt;
<span><span>&lt;-- /UI --&gt;</span></span>
&lt;a href="<span>/path/to/an.mp3</span>"&gt;
&lt;/div&gt;</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&deg; 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>

View file

@ -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];
}
}
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Some files were not shown because too many files have changed in this diff Show more