From 753f60c7d4769fa72d3b910e491f37db6f130898 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 2 Aug 2013 17:19:21 -0500 Subject: dymaxion --- .../demo/360-player/script/360player.js | 1270 ++++++++++++++++++++ .../demo/360-player/script/berniecode-animator.js | 674 +++++++++++ .../demo/360-player/script/excanvas.js | 17 + 3 files changed, 1961 insertions(+) create mode 100755 docs/dymaxion/soundmanagerv297a-20101010/demo/360-player/script/360player.js create mode 100755 docs/dymaxion/soundmanagerv297a-20101010/demo/360-player/script/berniecode-animator.js create mode 100755 docs/dymaxion/soundmanagerv297a-20101010/demo/360-player/script/excanvas.js (limited to 'docs/dymaxion/soundmanagerv297a-20101010/demo/360-player/script') diff --git a/docs/dymaxion/soundmanagerv297a-20101010/demo/360-player/script/360player.js b/docs/dymaxion/soundmanagerv297a-20101010/demo/360-player/script/360player.js new file mode 100755 index 0000000..419559c --- /dev/null +++ b/docs/dymaxion/soundmanagerv297a-20101010/demo/360-player/script/360player.js @@ -0,0 +1,1270 @@ +/* + + SoundManager 2 Demo: 360-degree / "donut player" + ------------------------------------------------ + http://schillmania.com/projects/soundmanager2/ + + An inline player with a circular UI. + Based on the original SM2 inline player. + Inspired by Apple's preview feature in the + iTunes music store (iPhone), among others. + + Requires SoundManager 2 Javascript API. + Also uses Bernie's Better Animation Class (BSD): + http://www.berniecode.com/writing/animator.html + +*/ + +function ThreeSixtyPlayer() { + var self = this; + var pl = this; + var sm = soundManager; // soundManager instance + var uA = navigator.userAgent; + var isIE = (uA.match(/msie/i)); + var isOpera = (uA.match(/opera/i)); + var isSafari = (uA.match(/safari/i)); + var isChrome = (uA.match(/chrome/i)); + var isFirefox = (uA.match(/firefox/i)); + var isTouchDevice = (uA.match(/ipad|iphone/i)); + this.excludeClass = 'threesixty-exclude'; // CSS class for ignoring MP3 links + + this.links = []; + this.sounds = []; + this.soundsByURL = []; + this.indexByURL = []; + this.lastSound = null; + this.soundCount = 0; + this.oUITemplate = null; + this.oUIImageMap = null; + this.vuMeter = null; + + this.config = { + + playNext: false, // stop after one sound, or play through list until end + autoPlay: false, // start playing the first sound right away + loadRingColor: '#ccc', // how much has loaded + playRingColor: '#000', // how much has played + backgroundRingColor: '#eee', // color shown underneath load + play ("not yet loaded" color) + + // optional segment/annotation (metadata) stuff.. + segmentRingColor: 'rgba(255,255,255,0.33)', // metadata/annotation (segment) colors + segmentRingColorAlt: 'rgba(0,0,0,0.1)', + loadRingColorMetadata: '#ddd', // "annotations" load color + playRingColorMetadata: 'rgba(96,160,224,0.99)', // how much has played when metadata is present + playRingColorMetadata: 'rgba(128,192,256,0.9)', // how much has played when metadata is present + + circleDiameter: null, // set dynamically according to values from CSS + circleRadius: null, + imageRoot: '', // image path to prepend for transparent .GIF - eg. /images/ + animDuration: 500, + animTransition: Animator.tx.bouncy, // http://www.berniecode.com/writing/animator.html + showHMSTime: false, // hours:minutes:seconds vs. seconds-only + scaleFont: false, // also set the font size (if possible) while animating the circle + + // optional: spectrum or EQ graph in canvas (not supported in IE, too slow via ExCanvas) + useWaveformData: false, + waveformDataColor: '#0099ff', + waveformDataDownsample: 3, // use only one in X (of a set of 256 values) - 1 means all 256 + waveformDataOutside: false, + waveformDataConstrain: false, // if true, +ve values only - keep within inside circle + waveformDataLineRatio: 0.64, + + // "spectrum frequency" option + useEQData: false, + eqDataColor: '#339933', + eqDataDownsample: 4, // use only one in X (of 256 values) + eqDataOutside: true, + eqDataLineRatio: 0.54, + + // enable "amplifier" (canvas pulses like a speaker) effect + usePeakData: true, + peakDataColor: '#ff33ff', + peakDataOutside: true, + peakDataLineRatio: 0.5, + + useAmplifier: true, // "pulse" like a speaker + + fontSizeMax: null, // set according to CSS + + useFavIcon: false // Experimental (also requires usePeakData: true).. Try to draw a "VU Meter" in the favicon area, if browser supports it (Firefox + Opera as of 2009) + + } + + this.css = { + // CSS class names appended to link during various states + sDefault: 'sm2_link', // default state + sBuffering: 'sm2_buffering', + sPlaying: 'sm2_playing', + sPaused: 'sm2_paused' + } + + this.addEventHandler = function(o,evtName,evtHandler) { + typeof(attachEvent)=='undefined'?o.addEventListener(evtName,evtHandler,false):o.attachEvent('on'+evtName,evtHandler); + } + + this.removeEventHandler = function(o,evtName,evtHandler) { + typeof(attachEvent)=='undefined'?o.removeEventListener(evtName,evtHandler,false):o.detachEvent('on'+evtName,evtHandler); + } + + this.hasClass = function(o,cStr) { + return (typeof(o.className)!='undefined'?o.className.match(new RegExp('(\\s|^)'+cStr+'(\\s|$)')):false); + } + + this.addClass = function(o,cStr) { + if (!o || !cStr || self.hasClass(o,cStr)) return false; + o.className = (o.className?o.className+' ':'')+cStr; + } + + this.removeClass = function(o,cStr) { + if (!o || !cStr || !self.hasClass(o,cStr)) return false; + o.className = o.className.replace(new RegExp('( '+cStr+')|('+cStr+')','g'),''); + } + + this.getElementsByClassName = function(className,tagNames,oParent) { + var doc = (oParent||document); + var matches = []; + var i,j; + var nodes = []; + if (typeof tagNames != 'undefined' && typeof tagNames != 'string') { + for (i=tagNames.length; i--;) { + if (!nodes || !nodes[tagNames[i]]) { + nodes[tagNames[i]] = doc.getElementsByTagName(tagNames[i]); + } + } + } else if (tagNames) { + nodes = doc.getElementsByTagName(tagNames); + } else { + nodes = doc.all||doc.getElementsByTagName('*'); + } + if (typeof(tagNames)!='string') { + for (i=tagNames.length; i--;) { + for (j=nodes[tagNames[i]].length; j--;) { + if (self.hasClass(nodes[tagNames[i]][j],className)) { + matches.push(nodes[tagNames[i]][j]); + } + } + } + } else { + for (i=0; i 1) { + // only catch left-clicks + return true; + } + var o = self.getTheDamnLink(e); + if (o.nodeName.toLowerCase() != 'a') { + o = self.isChildOfNode(o,'a'); + if (!o) return true; + } + if (!self.isChildOfClass(o,'ui360')) { + // not a link we're interested in + return true; + } + var sURL = o.getAttribute('href'); + if (!o.href || !sm.canPlayLink(o) || self.hasClass(o,self.excludeClass)) { + return true; // pass-thru for non-MP3/non-links + } + sm._writeDebug('handleClick()'); + var soundURL = (o.href); + var thisSound = self.getSoundByURL(soundURL); + if (thisSound) { + // already exists + if (thisSound == self.lastSound) { + // and was playing (or paused) + thisSound.togglePause(); + } else { + // different sound + thisSound.togglePause(); // start playing current + sm._writeDebug('sound different than last sound: '+self.lastSound.sID); + if (self.lastSound) { + self.stopSound(self.lastSound); + } + } + } else { + // append some dom shiz + + // create sound + thisSound = sm.createSound({ + id:'ui360Sound'+(self.soundCount++), + url:soundURL, + onplay:self.events.play, + onstop:self.events.stop, + onpause:self.events.pause, + onresume:self.events.resume, + onfinish:self.events.finish, + onbufferchange:self.events.bufferchange, + whileloading:self.events.whileloading, + whileplaying:self.events.whileplaying + }); + var oContainer = o.parentNode; + // tack on some custom data + + thisSound._360data = { + oUI360: self.getParentByClassName(o,'ui360'), // the (whole) entire container + oLink: o, // DOM node for reference within SM2 object event handlers + className: self.css.sPlaying, + oUIBox: self.getElementsByClassName('sm2-360ui','div',oContainer)[0], + oCanvas: self.getElementsByClassName('sm2-canvas','canvas',oContainer)[0], + oButton: self.getElementsByClassName('sm2-360btn','img',oContainer)[0], + oTiming: self.getElementsByClassName('sm2-timing','div',oContainer)[0], + oCover: self.getElementsByClassName('sm2-cover','div',oContainer)[0], + lastTime: null, + didFinish: null, + pauseCount:0, + radius:0, + amplifier: (self.config.usePeakData?0.9:1), // TODO: x1 if not being used, else use dynamic "how much to amplify by" value + radiusMax: self.config.circleDiameter*0.175, // circle radius + width:0, + widthMax: self.config.circleDiameter*0.4, // width of the outer ring + lastValues: { + bytesLoaded: 0, + bytesTotal: 0, + position: 0, + durationEstimate: 0 + }, // used to track "last good known" values before sound finish/reset for anim + animating: false, + oAnim: new Animator({ + duration: self.config.animDuration, + transition:self.config.animTransition, + onComplete: function() { + // var thisSound = this; + // thisSound._360data.didFinish = false; // reset full circle + } + }), + oAnimProgress: function(nProgress) { + var thisSound = this; + thisSound._360data.radius = parseInt(thisSound._360data.radiusMax*thisSound._360data.amplifier*nProgress); + thisSound._360data.width = parseInt(thisSound._360data.widthMax*thisSound._360data.amplifier*nProgress); + if (self.config.scaleFont && self.config.fontSizeMax != null) { + thisSound._360data.oTiming.style.fontSize = parseInt(Math.max(1,self.config.fontSizeMax*nProgress))+'px'; + thisSound._360data.oTiming.style.opacity = nProgress; + } + if (thisSound.paused || thisSound.playState == 0 || thisSound._360data.lastValues.bytesLoaded == 0 || thisSound._360data.lastValues.position == 0) { + self.updatePlaying.apply(thisSound); + } + }, + fps: 0 + }; + + // "Metadata" (annotations) + if (typeof self.Metadata != 'undefined' && self.getElementsByClassName('metadata','div',thisSound._360data.oUI360).length) { + thisSound._360data.metadata = new self.Metadata(thisSound,self); + } + + // set the cover width/height to match the canvas + thisSound._360data.oCover.style.width = self.config.circleDiameter+'px'; + thisSound._360data.oCover.style.height = self.config.circleDiameter+'px'; + + // minimize ze font + if (self.config.scaleFont && self.config.fontSizeMax != null) { + thisSound._360data.oTiming.style.fontSize = '1px'; + } + + // set up ze animation + thisSound._360data.oAnim.addSubject(thisSound._360data.oAnimProgress,thisSound); + + // animate the radius out nice + self.refreshCoords(thisSound); + + self.updatePlaying.apply(thisSound); + + self.soundsByURL[soundURL] = thisSound; + self.sounds.push(thisSound); + if (self.lastSound) { + self.stopSound(self.lastSound); + } + thisSound.play(); + } + + self.lastSound = thisSound; // reference for next call + + if (typeof e != 'undefined' && typeof e.preventDefault != 'undefined') { + e.preventDefault(); + } else if (typeof event != 'undefined') { + event.returnValue = false; + } + return false; + } + + this.fanOut = function(oSound) { + var thisSound = oSound; + if (thisSound._360data.animating == 1) { + return false; + } + thisSound._360data.animating = 0; + soundManager._writeDebug('fanOut: '+thisSound.sID+': '+thisSound._360data.oLink.href); + thisSound._360data.oAnim.seekTo(1); // play to end + window.setTimeout(function() { + // oncomplete hack + thisSound._360data.animating = 0; + },self.config.animDuration+20); + } + + this.fanIn = function(oSound) { + var thisSound = oSound; + if (thisSound._360data.animating == -1) { + return false; + } + thisSound._360data.animating = -1; + soundManager._writeDebug('fanIn: '+thisSound.sID+': '+thisSound._360data.oLink.href); + // massive hack + thisSound._360data.oAnim.seekTo(0); // play to end + window.setTimeout(function() { + // reset full 360 fill after animation has completed (oncomplete hack) + thisSound._360data.didFinish = false; + thisSound._360data.animating = 0; + self.resetLastValues(thisSound); + },self.config.animDuration+20); + + } + + this.resetLastValues = function(oSound) { + var oData = oSound._360data; + oData.lastValues.position = 0; + // oData.lastValues.bytesLoaded = 0; // will likely be cached, if file is small + // oData.lastValues.bytesTotal = 0; + // oData.lastValues.durationEstimate = 0; + } + + this.refreshCoords = function(thisSound) { + thisSound._360data.canvasXY = self.findXY(thisSound._360data.oCanvas); + // thisSound._360data.canvasMid = [Math.floor(thisSound._360data.oCanvas.offsetWidth/2), Math.floor(thisSound._360data.oCanvas.offsetHeight/2)]; // doesn't work in IE, w/h are wrong + thisSound._360data.canvasMid = [self.config.circleRadius,self.config.circleRadius]; + thisSound._360data.canvasMidXY = [thisSound._360data.canvasXY[0]+thisSound._360data.canvasMid[0], thisSound._360data.canvasXY[1]+thisSound._360data.canvasMid[1]]; + } + + this.stopSound = function(oSound) { + soundManager._writeDebug('stopSound: '+oSound.sID); + soundManager.stop(oSound.sID); + soundManager.unload(oSound.sID); + } + + this.buttonClick = function(e) { + var o = e?(e.target?e.target:e.srcElement):event.srcElement; + self.handleClick({target:self.getParentByClassName(o,'sm2-360ui').nextSibling}); // link next to the nodes we inserted + return false; + } + + this.buttonMouseDown = function(e) { + // user might decide to drag from here + // watch for mouse move + if (!isTouchDevice) { + document.onmousemove = function(e) { + // should be boundary-checked, really (eg. move 3px first?) + self.mouseDown(e); + } + } else { + self.addEventHandler(document,'touchmove',self.mouseDown); + } + self.stopEvent(e); + return false; + } + + this.mouseDown = function(e) { + if (!self.lastSound) { + self.stopEvent(e); + return false; + } + var thisSound = self.lastSound; + // just in case, update coordinates (maybe the element moved since last time.) + self.refreshCoords(thisSound); + var oData = self.lastSound._360data; + self.addClass(oData.oUIBox,'sm2_dragging'); + oData.pauseCount = (self.lastSound.paused?1:0); + // self.lastSound.pause(); + self.mmh(e?e:event); + if (isTouchDevice) { + self.removeEventHandler(document,'touchmove',self.mouseDown); + self.addEventHandler(document,'touchmove',self.mmh); + self.addEventHandler(document,'touchend',self.mouseUp); + } else { + document.onmousemove = self.mmh; + document.onmouseup = self.mouseUp; + } + self.stopEvent(e); + return false; + } + + this.mouseUp = function(e) { + var oData = self.lastSound._360data; + self.removeClass(oData.oUIBox,'sm2_dragging'); + if (oData.pauseCount == 0) { + self.lastSound.resume(); + } + if (!isTouchDevice) { + document.onmousemove = null; + document.onmouseup = null; + } else { + self.removeEventHandler(document,'touchmove',self.mmh); + self.removeEventHandler(document,'touchend',self.mouseUP); + } + } + + var fullCircle = 360; + + this.mmh = function(e) { + if (typeof e == 'undefined') { + var e = event; + } + var oSound = self.lastSound; + var coords = self.getMouseXY(e); + var x = coords[0]; + var y = coords[1]; + var deltaX = x-oSound._360data.canvasMidXY[0]; + var deltaY = y-oSound._360data.canvasMidXY[1]; + var angle = Math.floor(fullCircle-(self.rad2deg(Math.atan2(deltaX,deltaY))+180)); + oSound.setPosition(oSound.durationEstimate*(angle/fullCircle)); + self.stopEvent(e); + return false; + } + + // assignMouseDown(); + + this.drawSolidArc = function(oCanvas, color, radius, width, radians, startAngle, noClear) { + + // thank you, http://www.snipersystems.co.nz/community/polarclock/tutorial.html + + var x = radius; + var y = radius; + + var canvas = oCanvas; + + if (canvas.getContext){ + // use getContext to use the canvas for drawing + var ctx = canvas.getContext('2d'); + } + + // var startAngle = 0; + var oCanvas = ctx; + + if (!noClear) { + self.clearCanvas(canvas); + } + // ctx.restore(); + + if (color) { + ctx.fillStyle = color; + } else { + // ctx.fillStyle = 'black'; + } + + oCanvas.beginPath(); + + if (isNaN(radians)) { + radians = 0; + } + + var innerRadius = radius-width; + var doesntLikeZero = (isOpera || isSafari); // safari 4 doesn't actually seem to mind. + + if (!doesntLikeZero || (doesntLikeZero && radius > 0)) { + oCanvas.arc(0, 0, radius, startAngle, radians, false); + var endPoint = self.getArcEndpointCoords(innerRadius, radians); + oCanvas.lineTo(endPoint.x, endPoint.y); + oCanvas.arc(0, 0, innerRadius, radians, startAngle, true); + oCanvas.closePath(); + oCanvas.fill(); + } + + } + + this.getArcEndpointCoords = function(radius, radians) { + return { + x: radius * Math.cos(radians), + y: radius * Math.sin(radians) + }; + } + + +this.deg2rad = function(nDeg) { + return (nDeg * Math.PI/180); +} + +this.rad2deg = function(nRad) { + return (nRad * 180/Math.PI); +} + +this.getTime = function(nMSec,bAsString) { + // convert milliseconds to mm:ss, return as object literal or string + var nSec = Math.floor(nMSec/1000); + var min = Math.floor(nSec/60); + var sec = nSec-(min*60); + // if (min == 0 && sec == 0) return null; // return 0:00 as null + return (bAsString?(min+':'+(sec<10?'0'+sec:sec)):{'min':min,'sec':sec}); +} + +this.clearCanvas = function(oCanvas) { + var canvas = oCanvas; + var ctx = null; + if (canvas.getContext){ + // use getContext to use the canvas for drawing + ctx = canvas.getContext('2d'); + } + var width = canvas.offsetWidth; + var height = canvas.offsetHeight; + ctx.clearRect(-(width/2), -(height/2), width, height); +} + + +var fullCircle = (isOpera||isChrome?359.9:360); // I dunno what Opera doesn't like about this. + +this.updatePlaying = function() { + if (this.bytesLoaded) { + this._360data.lastValues.bytesLoaded = this.bytesLoaded; + this._360data.lastValues.bytesTotal = this.bytesTotal; + } + if (this.position) { + this._360data.lastValues.position = this.position; + } + if (this.durationEstimate) { + this._360data.lastValues.durationEstimate = this.durationEstimate; + } + + self.drawSolidArc(this._360data.oCanvas,self.config.backgroundRingColor,this._360data.width,this._360data.radius,self.deg2rad(fullCircle),false); + + self.drawSolidArc(this._360data.oCanvas,(this._360data.metadata?self.config.loadRingColorMetadata:self.config.loadRingColor),this._360data.width,this._360data.radius,self.deg2rad(fullCircle*(this._360data.lastValues.bytesLoaded/this._360data.lastValues.bytesTotal)),0,true); + + if (this._360data.lastValues.position != 0) { + // don't draw if 0 (full black circle in Opera) + self.drawSolidArc(this._360data.oCanvas,(this._360data.metadata?self.config.playRingColorMetadata:self.config.playRingColor),this._360data.width,this._360data.radius,self.deg2rad((this._360data.didFinish==1?fullCircle:fullCircle*(this._360data.lastValues.position/this._360data.lastValues.durationEstimate))),0,true); + } + + // metadata goes here + if (this._360data.metadata) { + this._360data.metadata.events.whileplaying(); + } + + var timeNow = (self.config.showHMSTime?self.getTime(this.position,true):parseInt(this.position/1000)); + + if (timeNow != this._360data.lastTime) { + this._360data.lastTime = timeNow; + this._360data.oTiming.innerHTML = timeNow; + } + + // draw spectrum, if applicable + if (!isIE) { // IE can render maybe 3 or 4 FPS when including the wave/EQ, so don't bother. + self.updateWaveform(this); + // self.updateWaveformOld(this); + } + + if (self.config.useFavIcon && self.vuMeter) { + self.vuMeter.updateVU(this); + } + +} + + this.updateWaveform = function(oSound) { + + if ((!self.config.useWaveformData && !self.config.useEQData) || (!sm.features.waveformData && !sm.features.eqData)) { + // feature not enabled.. + return false; + } + + if (!oSound.waveformData.left.length && !oSound.eqData.length && !oSound.peakData.left) { + // no data (or errored out/paused/unavailable?) + return false; + } + + /* use for testing the data */ + /* + for (i=0; i<256; i++) { + oSound.eqData[i] = 1-(i/256); + } + */ + + var oCanvas = oSound._360data.oCanvas.getContext('2d'); + var offX = 0; + var offY = parseInt(self.config.circleDiameter/2); + var scale = offY/2; // Y axis (+/- this distance from 0) + var lineWidth = Math.floor(self.config.circleDiameter-(self.config.circleDiameter*0.175)/(self.config.circleDiameter/255)); // width for each line + lineWidth = 1; + var lineHeight = 1; + var thisY = 0; + var offset = offY; + + if (self.config.useWaveformData) { + // raw waveform + var downSample = self.config.waveformDataDownsample; // only sample X in 256 (greater number = less sample points) + downSample = Math.max(1,downSample); // make sure it's at least 1 + var dataLength = 256; + var sampleCount = (dataLength/downSample); + var startAngle = 0; + var endAngle = 0; + var waveData = null; + var innerRadius = (self.config.waveformDataOutside?1:(self.config.waveformDataConstrain?0.5:0.565)); + var scale = (self.config.waveformDataOutside?0.7:0.75); + var perItemAngle = self.deg2rad((360/sampleCount)*self.config.waveformDataLineRatio); // 0.85 = clean pixel lines at 150? // self.deg2rad(360*(Math.max(1,downSample-1))/sampleCount); + for (var i=0; i16500 Hz), most stuff won't actually use it. + var sampleCount = (eqSamples/downSample); + var innerRadius = (self.config.eqDataOutside?1:0.565); + var direction = (self.config.eqDataOutside?-1:1); + var scale = (self.config.eqDataOutside?0.5:0.75); + var startAngle = 0; + var endAngle = 0; + var perItemAngle = self.deg2rad((360/sampleCount)*self.config.eqDataLineRatio); // self.deg2rad(360/(sampleCount+1)); + var playedAngle = self.deg2rad((oSound._360data.didFinish==1?360:360*(oSound._360data.lastValues.position/oSound._360data.lastValues.durationEstimate))); + var j=0; + var iAvg = 0; + for (var i=0; iplayedAngle?self.config.eqDataColor:self.config.playRingColor),oSound._360data.width*innerRadius,oSound._360data.radius*scale*(oSound.eqData.left[i]*direction),endAngle,startAngle,true); + } + } + + if (self.config.usePeakData) { + if (!oSound._360data.animating) { + var nPeak = (oSound.peakData.left||oSound.peakData.right); + // GIANT HACK: use EQ spectrum data for bass frequencies + var eqSamples = 3; + for (var i=0; i', + ' ', // note use of imageMap, edit or remove if you use a different-size image. + '
', // + Ever-so-slight Safari horizontal alignment tweak + '
' + ]; + } + + this.init = function() { + sm._writeDebug('threeSixtyPlayer.init()'); + var oItems = self.getElementsByClassName('ui360','div'); + var oLinks = []; + + for (var i=0,j=oItems.length; i0) { + self.addEventHandler(document,'click',self.handleClick); + if (self.config.autoPlay) { + self.handleClick({target:self.links[0],preventDefault:function(){}}); + } + } + sm._writeDebug('threeSixtyPlayer.init(): Found '+foundItems+' relevant items.'); + + if (self.config.useFavIcon && typeof this.VUMeter != 'undefined') { + this.vuMeter = new this.VUMeter(this); + } + + } + +} + +// Optional: VU Meter component + +ThreeSixtyPlayer.prototype.VUMeter = function(oParent) { + + var self = oParent; + var me = this; + this.vuMeterData = []; + this.vuDataCanvas = null; + var _head = document.getElementsByTagName('head')[0]; + var isOpera = (navigator.userAgent.match(/opera/i)); + var isFirefox = (navigator.userAgent.match(/firefox/i)); + + this.setPageIcon = function(sDataURL) { + + if (!self.config.useFavIcon || !self.config.usePeakData || !sDataURL) { + return false; + } + + var link = document.getElementById('sm2-favicon'); + if (link) { + _head.removeChild(link); + link = null; + } + if (!link) { + link = document.createElement('link'); + link.id = 'sm2-favicon'; + link.rel = 'shortcut icon'; + link.type = 'image/png'; + link.href = sDataURL; + document.getElementsByTagName('head')[0].appendChild(link); + } + } + + this.resetPageIcon = function() { + if (!self.config.useFavIcon) { + return false; + } + var link = document.getElementById('favicon'); + if (link) { + link.href = '/favicon.ico'; + } + } + + this.updateVU = function(oSound) { + if (soundManager.flashVersion >= 9 && self.config.useFavIcon && self.config.usePeakData) { + me.setPageIcon(me.vuMeterData[parseInt(16*oSound.peakData.left)][parseInt(16*oSound.peakData.right)]); + } + } + + this.createVUData = function() { + var i=0; + var j=0; + var canvas = me.vuDataCanvas.getContext('2d'); + var vuGrad = canvas.createLinearGradient(0, 16, 0, 0); + vuGrad.addColorStop(0,'rgb(0,192,0)'); + vuGrad.addColorStop(0.30,'rgb(0,255,0)'); + vuGrad.addColorStop(0.625,'rgb(255,255,0)'); + vuGrad.addColorStop(0.85,'rgb(255,0,0)'); + var bgGrad = canvas.createLinearGradient(0, 16, 0, 0); + var outline = 'rgba(0,0,0,0.2)'; + bgGrad.addColorStop(0,outline); + bgGrad.addColorStop(1,'rgba(0,0,0,0.5)'); + for (i=0; i<16; i++) { + me.vuMeterData[i] = []; + } + for (var i=0; i<16; i++) { + for (j=0; j<16; j++) { + // reset/erase canvas + me.vuDataCanvas.setAttribute('width',16); + me.vuDataCanvas.setAttribute('height',16); + // draw new stuffs + canvas.fillStyle = bgGrad; + canvas.fillRect(0,0,7,15); + canvas.fillRect(8,0,7,15); + /* + // shadow + canvas.fillStyle = 'rgba(0,0,0,0.1)'; + canvas.fillRect(1,15-i,7,17-(17-i)); + canvas.fillRect(9,15-j,7,17-(17-j)); + */ + canvas.fillStyle = vuGrad; + canvas.fillRect(0,15-i,7,16-(16-i)); + canvas.fillRect(8,15-j,7,16-(16-j)); + // and now, clear out some bits. + canvas.clearRect(0,3,16,1); + canvas.clearRect(0,7,16,1); + canvas.clearRect(0,11,16,1); + me.vuMeterData[i][j] = me.vuDataCanvas.toDataURL('image/png'); + // for debugging VU images + /* + var o = document.createElement('img'); + o.style.marginRight = '5px'; + o.src = vuMeterData[i][j]; + document.documentElement.appendChild(o); + */ + } + } + }; + + this.testCanvas = function(noOpaque) { + // canvas + toDataURL(); + var c = document.createElement('canvas'); + var ctx = null; + if (!c || typeof c.getContext == 'undefined') { + return null; + } + ctx = c.getContext('2d'); + if (!ctx || typeof c.toDataURL != 'function') { + return null; + } + // just in case.. + try { + var ok = c.toDataURL('image/png'); + } catch(e) { + // no canvas or no toDataURL() + return null; + } + // assume we're all good. + return c; + } + + this.init = function() { + if (self.config.useFavIcon) { + me.vuDataCanvas = me.testCanvas(true); + if (me.vuDataCanvas && (isFirefox || isOpera)) { + // these browsers support dynamically-updating the favicon + me.createVUData(); + } else { + // browser doesn't support doing this + self.config.useFavIcon = false; + } + } + } + + this.init(); + +} + +// completely optional: Metadata/annotations/segments code + +ThreeSixtyPlayer.prototype.Metadata = function(oSound, oParent) { + soundManager._wD('Metadata()'); + var me = this; + var oBox = oSound._360data.oUI360; + var o = oBox.getElementsByTagName('ul')[0]; + var oItems = o.getElementsByTagName('li'); + var isFirefox = (navigator.userAgent.match(/firefox/i)); + this.lastWPExec = 0; + this.refreshInterval = 250; + + var isAlt = false; + + this.events = { + whileplaying: function() { + var width = oSound._360data.width; + var radius = oSound._360data.radius; + var fullDuration = (oSound.durationEstimate||(me.totalTime*1000)); + var isAlt = null; + for (var i=0,j=me.data.length; ime.refreshInterval) { + me.refresh(); + me.lastWPExec = d; + } + } + } + + this.refresh = function() { + // Display info as appropriate + var index = null; + var now = oSound.position; + var metadata = oSound._360data.metadata.data; + for (var i=0, j=metadata.length; i= metadata[i].startTimeMS && now <= metadata[i].endTimeMS) { + index = i; + break; + } + } + if (index != metadata.currentItem && index < metadata.length) { + // update + oSound._360data.oLink.innerHTML = metadata.mainTitle+' '; + // self.setPageTitle(metadata[index].title+' | '+metadata.mainTitle); + metadata.currentItem = index; + } + } + + this.totalTime = 0; + + this.strToTime = function(sTime) { + var segments = sTime.split(':'); + var seconds = 0; + for (var i=segments.length; i--;) { + seconds += parseInt(segments[i])*Math.pow(60,segments.length-1-i,10); // hours, minutes + } + return seconds; + } + + this.data = []; + this.data.givenDuration = null; + this.data.currentItem = null; + this.data.mainTitle = oSound._360data.oLink.innerHTML; + for (var i=0; i= 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 = "# 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 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 section ? 1 : 0); + } + if (this.options.rememberance) { + document.location.hash = this.rememberanceTexts[section]; + } + } +} diff --git a/docs/dymaxion/soundmanagerv297a-20101010/demo/360-player/script/excanvas.js b/docs/dymaxion/soundmanagerv297a-20101010/demo/360-player/script/excanvas.js new file mode 100755 index 0000000..d748873 --- /dev/null +++ b/docs/dymaxion/soundmanagerv297a-20101010/demo/360-player/script/excanvas.js @@ -0,0 +1,17 @@ +// Excanvas (Explorer Canvas) R43 +// http://excanvas.sourceforge.net/ +// Copyright 2006 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +if(!document.createElement("canvas").getContext){(function(){var u=Math;var v=u.round;var r=u.sin;var C=u.cos;var l=u.abs;var B=u.sqrt;var a=10;var n=a/2;function g(){return this.context_||(this.context_=new p(this))}var t=Array.prototype.slice;function D(j,m,E){var i=t.call(arguments,2);return function(){return j.apply(m,i.concat(t.call(arguments)))}}var h={init:function(i){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var j=i||document;j.createElement("canvas");j.attachEvent("onreadystatechange",D(this.init_,this,j))}},init_:function(F){if(!F.namespaces.g_vml_){F.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml","#default#VML")}if(!F.namespaces.g_o_){F.namespaces.add("g_o_","urn:schemas-microsoft-com:office:office","#default#VML")}if(!F.styleSheets.ex_canvas_){var E=F.createStyleSheet();E.owningElement.id="ex_canvas_";E.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}g_vml_\\:*{behavior:url(#default#VML)}g_o_\\:*{behavior:url(#default#VML)}"}var m=F.getElementsByTagName("canvas");for(var j=0;j','","");this.element_.insertAdjacentHTML("BeforeEnd",Y.join(""))};k.stroke=function(ae){var J=[];var K=false;var ap=c(ae?this.fillStyle:this.strokeStyle);var aa=ap.color;var ak=ap.alpha*this.globalAlpha;var F=10;var M=10;J.push("V.x){V.x=ai.x}if(ao.y==null||ai.yV.y){V.y=ai.y}}}J.push(' ">');if(!ae){var U=this.lineScale_*this.lineWidth;if(U<1){ak*=U}J.push("')}else{if(typeof this.fillStyle=="object"){var N=this.fillStyle;var S=0;var ah={x:0,y:0};var ab=0;var Q=1;if(N.type_=="gradient"){var P=N.x0_/this.arcScaleX_;var m=N.y0_/this.arcScaleY_;var O=N.x1_/this.arcScaleX_;var aq=N.y1_/this.arcScaleY_;var am=this.getCoords_(P,m);var al=this.getCoords_(O,aq);var I=al.x-am.x;var G=al.y-am.y;S=Math.atan2(I,G)*180/Math.PI;if(S<0){S+=360}if(S<0.000001){S=0}}else{var am=this.getCoords_(N.x0_,N.y0_);var j=V.x-ao.x;var E=V.y-ao.y;ah={x:(am.x-ao.x)/j,y:(am.y-ao.y)/E};j/=this.arcScaleX_*a;E/=this.arcScaleY_*a;var ag=u.max(j,E);ab=2*N.r0_/ag;Q=2*N.r1_/ag-ab}var Z=N.colors_;Z.sort(function(H,i){return H.offset-i.offset});var T=Z.length;var Y=Z[0].color;var X=Z[T-1].color;var ad=Z[0].alpha*this.globalAlpha;var ac=Z[T-1].alpha*this.globalAlpha;var af=[];for(var aj=0;aj')}else{J.push('')}}J.push("");this.element_.insertAdjacentHTML("beforeEnd",J.join(""))};k.fill=function(){this.stroke(true)};k.closePath=function(){this.currentPath_.push({type:"close"})};k.getCoords_=function(E,j){var i=this.m_;return{x:a*(E*i[0][0]+j*i[1][0]+i[2][0])-n,y:a*(E*i[0][1]+j*i[1][1]+i[2][1])-n}};k.save=function(){var i={};w(this,i);this.aStack_.push(i);this.mStack_.push(this.m_);this.m_=d(q(),this.m_)};k.restore=function(){w(this.aStack_.pop(),this);this.m_=this.mStack_.pop()};k.translate=function(m,j){var i=[[1,0,0],[0,1,0],[m,j,1]];this.m_=d(i,this.m_)};k.rotate=function(j){var E=C(j);var m=r(j);var i=[[E,m,0],[-m,E,0],[0,0,1]];this.m_=d(i,this.m_)};k.scale=function(G,F){this.arcScaleX_*=G;this.arcScaleY_*=F;var j=[[G,0,0],[0,F,0],[0,0,1]];var i=this.m_=d(j,this.m_);var E=i[0][0]*i[1][1]-i[0][1]*i[1][0];this.lineScale_=B(l(E))};k.clip=function(){};k.arcTo=function(){};k.createPattern=function(){return new f};function z(i){this.type_=i;this.x0_=0;this.y0_=0;this.r0_=0;this.x1_=0;this.y1_=0;this.r1_=0;this.colors_=[]}z.prototype.addColorStop=function(j,i){i=c(i);this.colors_.push({offset:j,color:i.color,alpha:i.alpha})};function f(){}G_vmlCanvasManager=h;CanvasRenderingContext2D=p;CanvasGradient=z;CanvasPattern=f})()}; \ No newline at end of file -- cgit v1.2.3-70-g09d2