Mercurial > hg > webaudioevaluationtool
changeset 2481:3c92c732fb05
Added buttonSubmit interface checks. Beautified timeline.js
author | Nicholas Jillings <nicholas.jillings@mail.bcu.ac.uk> |
---|---|
date | Thu, 04 Aug 2016 12:01:39 +0100 |
parents | 713a2d059a16 |
children | e0ca016707a5 |
files | interfaces/timeline.js |
diffstat | 1 files changed, 229 insertions(+), 193 deletions(-) [+] |
line wrap: on
line diff
--- a/interfaces/timeline.js Thu Aug 04 11:34:29 2016 +0100 +++ b/interfaces/timeline.js Thu Aug 04 12:01:39 2016 +0100 @@ -7,14 +7,14 @@ loadInterface(); function loadInterface() { - // Use this to do any one-time page / element construction. For instance, placing any stationary text objects, - // holding div's, or setting up any nodes which are present for the entire test sequence - + // Use this to do any one-time page / element construction. For instance, placing any stationary text objects, + // holding div's, or setting up any nodes which are present for the entire test sequence + interfaceContext.insertPoint.innerHTML = ""; // Clear the current schema - + interfaceContext.insertPoint = document.getElementById("topLevelBody"); var testContent = document.createElement("div"); - + // Create the top div and Title element var title = document.createElement("div"); title.className = "title"; @@ -23,49 +23,49 @@ titleSpan.id = "test-title"; titleSpan.textContent = "Listening Test"; title.appendChild(titleSpan); - + var pagetitle = document.createElement("div"); pagetitle.className = "pageTitle"; pagetitle.align = "center"; titleSpan = document.createElement("span"); titleSpan.id = "page-title"; pagetitle.appendChild(titleSpan); - + // Create Interface buttons var interfaceButtons = document.createElement("div"); interfaceButtons.id = 'interface-buttons'; interfaceButtons.style.height = "25px"; - + // Create playback start/stop points var playback = document.createElement("button"); playback.innerHTML = "Stop"; playback.id = "playback-button"; - playback.onclick = function() { + playback.onclick = function () { if (audioEngineContext.status == 1) { audioEngineContext.stop(); this.innerHTML = "Stop"; var time = audioEngineContext.timer.getTestTime(); - console.log("Stopped at "+time); + console.log("Stopped at " + time); } }; // Create Submit (save) button - var submit = document.createElement("button"); - submit.innerHTML = 'Next'; - submit.onclick = buttonSubmitClick; - submit.id = 'submit-button'; - submit.style.float = 'left'; - // Append the interface buttons into the interfaceButtons object. - interfaceButtons.appendChild(playback); - interfaceButtons.appendChild(submit); - + var submit = document.createElement("button"); + submit.innerHTML = 'Next'; + submit.onclick = buttonSubmitClick; + submit.id = 'submit-button'; + submit.style.float = 'left'; + // Append the interface buttons into the interfaceButtons object. + interfaceButtons.appendChild(playback); + interfaceButtons.appendChild(submit); + // Create outside reference holder var outsideRef = document.createElement("div"); outsideRef.id = "outside-reference-holder"; - + // Create content point var content = document.createElement("div"); content.id = "timeline-test-content"; - + //Inject testContent.appendChild(title); testContent.appendChild(pagetitle); @@ -73,50 +73,47 @@ testContent.appendChild(outsideRef); testContent.appendChild(content); interfaceContext.insertPoint.appendChild(testContent); - + // Load the full interface - testState.initialise(); - testState.advanceState(); + testState.initialise(); + testState.advanceState(); }; -function loadTest(page) -{ - // Called each time a new test page is to be build. The page specification node is the only item passed in +function loadTest(page) { + // Called each time a new test page is to be build. The page specification node is the only item passed in var content = document.getElementById("timeline-test-content"); content.innerHTML = ""; var interfaceObj = page.interfaces; - if (interfaceObj.length > 1) - { + if (interfaceObj.length > 1) { console.log("WARNING - This interface only supports one <interface> node per page. Using first interface node"); } interfaceObj = interfaceObj[0]; - + //Set the page title - if (typeof page.title == "string" && page.title.length > 0) - { + if (typeof page.title == "string" && page.title.length > 0) { document.getElementById("test-title").textContent = page.title; } - + if (interfaceObj.title != null) { document.getElementById("page-title").textContent = interfaceObj.title; } - + // Delete outside reference - var outsideReferenceHolder = document.getElementById("outside-reference-holder"); + var outsideReferenceHolder = document.getElementById("outside-reference-holder"); outsideReferenceHolder.innerHTML = ""; - + var commentBoxPrefix = "Comment on track"; - if (interfaceObj.commentBoxPrefix != undefined) { - commentBoxPrefix = interfaceObj.commentBoxPrefix; - } - - $(page.audioElements).each(function(index,element){ + if (interfaceObj.commentBoxPrefix != undefined) { + commentBoxPrefix = interfaceObj.commentBoxPrefix; + } + + $(page.audioElements).each(function (index, element) { var audioObject = audioEngineContext.newTrack(element); if (page.audioElements.type == 'outside-reference') { - var refNode = interfaceContext.outsideReferenceDOM(audioObject,index,outsideReferenceHolder); + var refNode = interfaceContext.outsideReferenceDOM(audioObject, index, outsideReferenceHolder); audioObject.bindInterface(orNode); } else { - switch(audioObject.specification.parent.label) { + switch (audioObject.specification.parent.label) { case "none": label = ""; break; @@ -127,53 +124,52 @@ label = String.fromCharCode(65 + index); break; default: - label = ""+index; + label = "" + index; break; } - var node = new interfaceObject(audioObject,label); - + var node = new interfaceObject(audioObject, label); + content.appendChild(node.DOM); audioObject.bindInterface(node); } }); - + resizeWindow(); } -function interfaceObject(audioObject,labelstr) -{ - // Each audio object has a waveform guide and self-generated comments +function interfaceObject(audioObject, labelstr) { + // Each audio object has a waveform guide and self-generated comments this.parent = audioObject; this.DOM = document.createElement("div"); this.DOM.className = "timeline-element"; this.DOM.id = audioObject.specification.id; - + var root = document.createElement("div"); root.className = "timeline-element-content"; this.DOM.appendChild(root); - + var label = document.createElement("div"); label.style.textAlign = "center"; var labelSpan = document.createElement("span"); - labelSpan.textContent = "Fragment "+labelstr; + labelSpan.textContent = "Fragment " + labelstr; label.appendChild(labelSpan); root.appendChild(label); - + var canvasHolder = document.createElement("div"); canvasHolder.className = "timeline-element-canvas-holder"; var buttonHolder = document.createElement("div"); buttonHolder.className = "timeline-element-button-holder"; var commentHolder = document.createElement("div"); commentHolder.className = "timeline-element-comment-holder"; - + root.appendChild(canvasHolder); root.appendChild(buttonHolder); root.appendChild(commentHolder); - + this.comments = { parent: this, list: [], - Comment: function(parent,time, str) { + Comment: function (parent, time, str) { this.parent = parent; this.time = time; this.DOM = document.createElement("div"); @@ -184,40 +180,40 @@ if (str != undefined) { this.title.textContent = str; } else { - this.title.textContent = "Time: "+time.toFixed(2)+"s"; + this.title.textContent = "Time: " + time.toFixed(2) + "s"; } titleHolder.appendChild(this.title); this.textarea = document.createElement("textarea"); this.textarea.className = "comment-entry-text"; this.DOM.appendChild(titleHolder); this.DOM.appendChild(this.textarea); - + this.clear = { DOM: document.createElement("button"), parent: this, - handleEvent: function() { + handleEvent: function () { this.parent.parent.deleteComment(this.parent); } } this.clear.DOM.textContent = "Delete"; - this.clear.DOM.addEventListener("click",this.clear); + this.clear.DOM.addEventListener("click", this.clear); titleHolder.appendChild(this.clear.DOM); - - this.resize = function() { + + this.resize = function () { var w = window.innerWidth; - w = Math.min(w,800); - w = Math.max(w,200); + w = Math.min(w, 800); + w = Math.max(w, 200); var elem_w = w / 2.5; - elem_w = Math.max(elem_w,190); - this.DOM.style.width = elem_w+"px"; - this.textarea.style.width = (elem_w-5)+"px"; + elem_w = Math.max(elem_w, 190); + this.DOM.style.width = elem_w + "px"; + this.textarea.style.width = (elem_w - 5) + "px"; } - this.buildXML = function(root) { + this.buildXML = function (root) { //storage.document.createElement(); var node = storage.document.createElement("comment"); var question = storage.document.createElement("question"); var comment = storage.document.createElement("response"); - node.setAttribute("time",this.time); + node.setAttribute("time", this.time); question.textContent = this.title.textContent; comment.textContent = this.textarea.value; node.appendChild(question); @@ -226,31 +222,34 @@ } this.resize(); }, - newComment: function(time) { - var node = new this.Comment(this,time); + newComment: function (time) { + var node = new this.Comment(this, time); this.list.push(node); commentHolder.appendChild(node.DOM); return node; }, - deleteComment: function(comment) { - var index = this.list.findIndex(function(element,index,array){ - if (element == comment) {return true;} return false; - },comment); + deleteComment: function (comment) { + var index = this.list.findIndex(function (element, index, array) { + if (element == comment) { + return true; + } + return false; + }, comment); if (index == -1) { return false; } - var node = this.list.splice(index,1); + var node = this.list.splice(index, 1); comment.DOM.remove(); this.parent.canvas.drawMarkers(); return true; }, - clearList: function() { - while(this.list.length > 0) { + clearList: function () { + while (this.list.length > 0) { this.deleteComment(this.list[0]); } } } - + this.canvas = { parent: this, comments: this.comments, @@ -258,22 +257,22 @@ layer2: document.createElement("canvas"), layer3: document.createElement("canvas"), layer4: document.createElement("canvas"), - resize: function(w) { + resize: function (w) { this.layer1.width = w; this.layer2.width = w; this.layer3.width = w; this.layer4.width = w; - this.layer1.style.width = w+"px"; - this.layer2.style.width = w+"px"; - this.layer3.style.width = w+"px"; - this.layer4.style.width = w+"px"; + this.layer1.style.width = w + "px"; + this.layer2.style.width = w + "px"; + this.layer3.style.width = w + "px"; + this.layer4.style.width = w + "px"; this.drawWaveform(); this.drawMarkers(); }, - handleEvent: function(event) { - switch(event.currentTarget) { + handleEvent: function (event) { + switch (event.currentTarget) { case this.layer1: - switch(event.type) { + switch (event.type) { case "mousemove": this.drawMouse(event); break; @@ -283,15 +282,15 @@ case "click": var rect = this.layer1.getBoundingClientRect(); var pixX = event.clientX - rect.left; - var tpp = this.parent.parent.buffer.buffer.duration/this.layer1.width; - this.comments.newComment(pixX*tpp); + var tpp = this.parent.parent.buffer.buffer.duration / this.layer1.width; + this.comments.newComment(pixX * tpp); this.drawMarkers(); break; } break; } }, - drawWaveform: function() { + drawWaveform: function () { if (this.parent.parent == undefined || this.parent.parent.buffer == undefined) { return; } @@ -299,73 +298,77 @@ var context = this.layer4.getContext("2d"); context.lineWidth = 1; context.strokeStyle = "#888"; - context.clearRect(0,0,this.layer4.width, this.layer4.height); + context.clearRect(0, 0, this.layer4.width, this.layer4.height); var data = buffer.getChannelData(0); - var t_per_pixel = buffer.duration/this.layer4.width; - var s_per_pixel = data.length/this.layer4.width; + var t_per_pixel = buffer.duration / this.layer4.width; + var s_per_pixel = data.length / this.layer4.width; var pixX = 0; while (pixX < this.layer4.width) { - var start = Math.floor(s_per_pixel*pixX); - var end = Math.min(Math.ceil(s_per_pixel*(pixX+1)),data.length); - var frame = data.subarray(start,end); + var start = Math.floor(s_per_pixel * pixX); + var end = Math.min(Math.ceil(s_per_pixel * (pixX + 1)), data.length); + var frame = data.subarray(start, end); var min = frame[0]; var max = min; - for (var n=0; n<frame.length; n++) { - if (frame[n] < min) {min = frame[n];} - if (frame[n] > max) {max = frame[n];} + for (var n = 0; n < frame.length; n++) { + if (frame[n] < min) { + min = frame[n]; + } + if (frame[n] > max) { + max = frame[n]; + } } // Assuming min/max normalised between [-1, 1] to map to [150, 0] context.beginPath(); - context.moveTo(pixX+0.5,(min+1)*-75+150); - context.lineTo(pixX+0.5,(max+1)*-75+150); + context.moveTo(pixX + 0.5, (min + 1) * -75 + 150); + context.lineTo(pixX + 0.5, (max + 1) * -75 + 150); context.stroke(); pixX++; } }, - drawMouse: function(event) { + drawMouse: function (event) { var context = this.layer1.getContext("2d"); - context.clearRect(0,0,this.layer1.width, this.layer1.height); + context.clearRect(0, 0, this.layer1.width, this.layer1.height); var rect = this.layer1.getBoundingClientRect(); var pixX = event.clientX - rect.left; - pixX = Math.floor(pixX)-0.5; + pixX = Math.floor(pixX) - 0.5; context.strokeStyle = "#800"; context.beginPath(); - context.moveTo(pixX,0); - context.lineTo(pixX,this.layer1.height); + context.moveTo(pixX, 0); + context.lineTo(pixX, this.layer1.height); context.stroke(); }, - drawTicker: function() { + drawTicker: function () { var context = this.layer2.getContext("2d"); - context.clearRect(0,0,this.layer2.width, this.layer2.height); + context.clearRect(0, 0, this.layer2.width, this.layer2.height); var time = this.parent.parent.getCurrentPosition(); var ratio = time / this.parent.parent.buffer.buffer.duration; - var pixX = Math.floor(ratio*this.layer2.width)+0.5; + var pixX = Math.floor(ratio * this.layer2.width) + 0.5; context.strokeStyle = "#080"; context.beginPath(); - context.moveTo(pixX,0); - context.lineTo(pixX,this.layer2.height); + context.moveTo(pixX, 0); + context.lineTo(pixX, this.layer2.height); context.stroke(); }, - drawMarkers: function() { + drawMarkers: function () { if (this.parent.parent == undefined || this.parent.parent.buffer == undefined) { return; } var context = this.layer3.getContext("2d"); - context.clearRect(0,0,this.layer3.width, this.layer3.height); + context.clearRect(0, 0, this.layer3.width, this.layer3.height); context.strokeStyle = "#008"; - var tpp = this.parent.parent.buffer.buffer.duration/this.layer1.width; - for (var i=0; i<this.comments.list.length; i++) { + var tpp = this.parent.parent.buffer.buffer.duration / this.layer1.width; + for (var i = 0; i < this.comments.list.length; i++) { var comment = this.comments.list[i]; - var pixX = Math.floor(comment.time/tpp)+0.5; + var pixX = Math.floor(comment.time / tpp) + 0.5; context.beginPath(); - context.moveTo(pixX,0); - context.lineTo(pixX,this.layer3.height); + context.moveTo(pixX, 0); + context.lineTo(pixX, this.layer3.height); context.stroke(); } }, - clearCanvas: function(canvas) { + clearCanvas: function (canvas) { var context = canvas.getContext("2d"); - context.clearRect(0,0,canvas.width, canvas.height); + context.clearRect(0, 0, canvas.width, canvas.height); } } this.canvas.layer1.className = "timeline-element-canvas canvas-layer1 canvas-disabled"; @@ -380,16 +383,16 @@ canvasHolder.appendChild(this.canvas.layer2); canvasHolder.appendChild(this.canvas.layer3); canvasHolder.appendChild(this.canvas.layer4); - this.canvas.layer1.addEventListener("mousemove",this.canvas); - this.canvas.layer1.addEventListener("mouseleave",this.canvas); - this.canvas.layer1.addEventListener("click",this.canvas); - + this.canvas.layer1.addEventListener("mousemove", this.canvas); + this.canvas.layer1.addEventListener("mouseleave", this.canvas); + this.canvas.layer1.addEventListener("click", this.canvas); + var canvasIntervalID = null; - + this.playButton = { parent: this, DOM: document.createElement("button"), - handleEvent: function(event) { + handleEvent: function (event) { var id = this.parent.parent.id; var str = this.DOM.textContent; if (str == "Play") { @@ -399,109 +402,142 @@ } } } - this.playButton.DOM.addEventListener("click",this.playButton); + this.playButton.DOM.addEventListener("click", this.playButton); this.playButton.DOM.className = "timeline-button timeline-button-disabled"; this.playButton.DOM.disabled = true; this.playButton.DOM.textContent = "Wait"; - + buttonHolder.appendChild(this.playButton.DOM); - - this.resize = function() { + + this.resize = function () { var w = window.innerWidth; - w = Math.min(w,800); - w = Math.max(w,200); - root.style.width = w+"px"; - var c_w = w-100; + w = Math.min(w, 800); + w = Math.max(w, 200); + root.style.width = w + "px"; + var c_w = w - 100; this.canvas.resize(c_w); } - - this.enable = function() - { - // This is used to tell the interface object that playback of this node is ready - this.canvas.layer1.addEventListener("click",this.canvas); + + this.enable = function () { + // This is used to tell the interface object that playback of this node is ready + this.canvas.layer1.addEventListener("click", this.canvas); this.canvas.layer1.className = "timeline-element-canvas canvas-layer1"; this.playButton.DOM.className = "timeline-button timeline-button-play"; this.playButton.DOM.textContent = "Play"; this.playButton.DOM.disabled = false; - + this.canvas.drawWaveform(); - }; - this.updateLoading = function(progress) - { - // progress is a value from 0 to 100 indicating the current download state of media files + }; + this.updateLoading = function (progress) { + // progress is a value from 0 to 100 indicating the current download state of media files progress = String(progress); - progress = progress.substr(0,5); - this.playButton.DOM.textContent = "Loading: "+progress+'%'; - }; - this.startPlayback = function() - { + progress = progress.substr(0, 5); + this.playButton.DOM.textContent = "Loading: " + progress + '%'; + }; + this.startPlayback = function () { // Called when playback has begun - canvasIntervalID = window.setInterval(this.canvas.drawTicker.bind(this.canvas),100); + canvasIntervalID = window.setInterval(this.canvas.drawTicker.bind(this.canvas), 100); this.playButton.DOM.textContent = "Stop"; }; - this.stopPlayback = function() - { + this.stopPlayback = function () { // Called when playback has stopped. This gets called even if playback never started! window.clearInterval(canvasIntervalID); this.canvas.clearCanvas(this.canvas.layer2); this.playButton.DOM.textContent = "Play"; }; - this.getValue = function() - { - // Return the current value of the object. If there is no value, return 0 + this.getValue = function () { + // Return the current value of the object. If there is no value, return 0 return 0; - }; - this.getPresentedId = function() - { - // Return the presented ID of the object. For instance, the APE has sliders starting from 0. Whilst AB has alphabetical scale + }; + this.getPresentedId = function () { + // Return the presented ID of the object. For instance, the APE has sliders starting from 0. Whilst AB has alphabetical scale return labelSpan.textContent; - }; - this.canMove = function() - { - // Return either true or false if the interface object can be moved. AB / Reference cannot, whilst sliders can and therefore have a continuous scale. - // These are checked primarily if the interface check option 'fragmentMoved' is enabled. + }; + this.canMove = function () { + // Return either true or false if the interface object can be moved. AB / Reference cannot, whilst sliders can and therefore have a continuous scale. + // These are checked primarily if the interface check option 'fragmentMoved' is enabled. return false; - }; - this.exportXMLDOM = function(audioObject) { - // Called by the audioObject holding this element to export the interface <value> node. - // If there is no value node (such as outside reference), return null - // If there are multiple value nodes (such as multiple scale / 2D scales), return an array of nodes with each value node having an 'interfaceName' attribute - // Use storage.document.createElement('value'); to generate the XML node. - return null; - }; - this.error = function() { + }; + this.exportXMLDOM = function (audioObject) { + // Called by the audioObject holding this element to export the interface <value> node. + // If there is no value node (such as outside reference), return null + // If there are multiple value nodes (such as multiple scale / 2D scales), return an array of nodes with each value node having an 'interfaceName' attribute + // Use storage.document.createElement('value'); to generate the XML node. + return null; + }; + this.error = function () { // If there is an error with the audioObject, this will be called to indicate a failure } }; -function resizeWindow(event) -{ - // Called on every window resize event, use this to scale your page properly - for (var i=0; i<audioEngineContext.audioObjects.length; i++) { +function resizeWindow(event) { + // Called on every window resize event, use this to scale your page properly + for (var i = 0; i < audioEngineContext.audioObjects.length; i++) { audioEngineContext.audioObjects[i].interfaceDOM.resize(); } } -function buttonSubmitClick() -{ - testState.advanceState(); +function buttonSubmitClick() { + if (audioEngineContext.timer.testStarted == false) { + interfaceContext.lightbox.post("Warning", 'You have not started the test! Please click play on a sample to begin the test!'); + return; + } + var checks = []; + checks = checks.concat(testState.currentStateMap.interfaces[0].options); + checks = checks.concat(specification.interfaces.options); + var canContinue = true; + for (var i = 0; i < checks.length; i++) { + var checkState = true; + if (checks[i].type == 'check') { + switch (checks[i].name) { + case 'fragmentPlayed': + //Check if all fragments have been played + checkState = interfaceContext.checkAllPlayed(); + break; + case 'fragmentFullPlayback': + //Check if all fragments have played to their full length + checkState = interfaceContext.checkFragmentsFullyPlayed(); + break; + case 'fragmentComments': + checkState = interfaceContext.checkAllCommented(); + break; + default: + console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface"); + break; + } + if (checkState == false) { + canContinue == false; + } + } + if (!canContinue) { + return; + } + } + + if (canContinue) { + if (audioEngineContext.status == 1) { + var playback = document.getElementById('playback-button'); + playback.click(); + // This function is called when the submit button is clicked. Will check for any further tests to perform, or any post-test options + } + testState.advanceState(); + } } -function pageXMLSave(store, pageSpecification) -{ - // MANDATORY - // Saves a specific test page - // You can use this space to add any extra nodes to your XML <audioHolder> saves - // Get the current <page> information in store (remember to appendChild your data to it) - // pageSpecification is the current page node configuration - // To create new XML nodes, use storage.document.createElement(); - - for (var i=0; i<audioEngineContext.audioObjects.length; i++) { +function pageXMLSave(store, pageSpecification) { + // MANDATORY + // Saves a specific test page + // You can use this space to add any extra nodes to your XML <audioHolder> saves + // Get the current <page> information in store (remember to appendChild your data to it) + // pageSpecification is the current page node configuration + // To create new XML nodes, use storage.document.createElement(); + + for (var i = 0; i < audioEngineContext.audioObjects.length; i++) { var id = audioEngineContext.audioObjects[i].specification.id; var commentsList = audioEngineContext.audioObjects[i].interfaceDOM.comments.list; var root = audioEngineContext.audioObjects[i].storeDOM; - for (var j=0; j<commentsList.length; j++) { + for (var j = 0; j < commentsList.length; j++) { commentsList[j].buildXML(root); } } -} \ No newline at end of file +}