From def8eb472c34d6599893832adb1da7f6baf4dd16 Mon Sep 17 00:00:00 2001 From: Valera Rozuvan Date: Tue, 8 Jan 2013 17:17:29 +0200 Subject: [PATCH] Refactoring. Added ability to add dynamic element output to graph labels. Updated 2 demos for GST. "Falsified Clinic Data", and "Sample Size and Power". --- .../js/src/graphical_slider_tool/el_output.js | 39 ++++--- .../js/src/graphical_slider_tool/graph.js | 107 +++++++++++++----- .../js/src/graphical_slider_tool/gst_main.js | 6 +- .../js/src/graphical_slider_tool/state.js | 41 +++++-- 4 files changed, 138 insertions(+), 55 deletions(-) diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/el_output.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/el_output.js index 901989b2af..146d8a9f7f 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/el_output.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/el_output.js @@ -25,15 +25,14 @@ define('ElOutput', ['logme'], function (logme) { return; function processFuncObj(obj) { - var outputEl, paramNames, funcString, func; + var paramNames, funcString, func, special, el; // We are only interested in functions that are meant for output to an // element. - if (typeof obj['@output'] !== 'string') { - return; - } - - if (obj['@output'].toLowerCase() !== 'element') { + if ( + (typeof obj['@output'] !== 'string') || + (obj['@output'].toLowerCase() !== 'element') + ) { return; } @@ -55,14 +54,6 @@ define('ElOutput', ['logme'], function (logme) { // ASCII text equivalents. funcString = $('
').html(funcString).text(); - outputEl = $('#' + obj['@el_id']); - - if (outputEl.length !== 1) { - logme('ERROR: The element with id "' + obj['@el_id'] + '" was not found.'); - - return; - } - paramNames = state.getAllParameterNames(); paramNames.push(funcString); @@ -86,9 +77,25 @@ define('ElOutput', ['logme'], function (logme) { paramNames.pop(); - outputEl.html(func.apply(window, state.getAllParameterValues())); + special = false; + if (obj['@el_id'][0] === '_') { + special = true; + } else { + el = $('#' + obj['@el_id']); - state.addDynamicEl(outputEl, func); + if (el.length !== 1) { + logme( + 'ERROR: DOM element with ID "' + obj['@el_id'] + '" ' + + 'not found. Dynamic element not created.' + ); + + return; + } + + el.html(func.apply(window, state.getAllParameterValues())); + } + + state.addDynamicEl(el, func, obj['@el_id'], special); } } diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js index 65511e1599..8756f03aef 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/graph.js @@ -8,7 +8,9 @@ define('Graph', ['logme'], function (logme) { function Graph(gstId, config, state) { var plotDiv, dataSeries, functions, xaxis, yaxis, numPoints, xrange, - asymptotes; + asymptotes, plotObj; + + plotObj = null; state.barsConfig = { 'N': 0, @@ -519,7 +521,7 @@ define('Graph', ['logme'], function (logme) { function addFunction(funcString, color, line, dot, label, pointSize, fillArea, bar, disableAutoReturn) { - var newFunctionObject, func, paramNames; + var newFunctionObject, func, paramNames, matches; // The main requirement is function string. Without it we can't // create a function, and the series cannot be calculated. @@ -671,6 +673,17 @@ define('Graph', ['logme'], function (logme) { } if (typeof label === 'string') { + matches = label.match(/%%_[^%]*%%/g); + + if ( + ($.isArray(matches) === true) && + (matches.length > 0) + ) { + newFunctionObject['specialLabel'] = true; + } else { + newFunctionObject['specialLabel'] = false; + } + newFunctionObject['label'] = label; } @@ -688,7 +701,7 @@ define('Graph', ['logme'], function (logme) { function generateData() { var c0, c1, functionObj, seriesObj, dataPoints, paramValues, x, y, - start, end, step, tempX; + start, end, step, tempX, matches; paramValues = state.getAllParameterValues(); @@ -801,7 +814,35 @@ define('Graph', ['logme'], function (logme) { // See if a user defined a label for this function. if (functionObj.hasOwnProperty('label') === true) { - seriesObj.label = functionObj.label; + if (functionObj.specialLabel === true) { + matches = functionObj.label.match(/%%_[^%]*%%/g); + + if ($.isArray(matches) === true) { + (function (c1) { + var el_id, func, tempLabel; + + tempLabel = functionObj.label; + + while (c1 < matches.length) { + el_id = matches[c1].replace(/%/g, ''); + func = state.getFuncForSpecialLabel(el_id); + + if (func !== null) { + tempLabel = tempLabel.replace( + matches[c1], + func.apply(window, state.getAllParameterValues()) + ); + } + + c1 += 1; + } + + seriesObj.label = tempLabel; + }(0)); + } + } else { + seriesObj.label = functionObj.label; + } } // Should the data points be connected by a line? @@ -841,33 +882,41 @@ define('Graph', ['logme'], function (logme) { paramValues = state.getAllParameterValues(); - // Tell Flot to draw the graph to our specification. + // Tell Flot to draw the graph to our specification. If this is the + // first time, then call $.plot. + if (plotObj === null) { + plotObj = $.plot( + plotDiv, + dataSeries, + { + 'xaxis': xaxis, + 'yaxis': yaxis, + 'legend': { - $.plot( - plotDiv, - dataSeries, - { - 'xaxis': xaxis, - 'yaxis': yaxis, - 'legend': { + // To show the legend or not. Note, even if 'show' is + // 'true', the legend will only show if labels are + // provided for at least one of the series that are + // going to be plotted. + 'show': true, - // To show the legend or not. Note, even if 'show' is - // 'true', the legend will only show if labels are - // provided for at least one of the series that are - // going to be plotted. - 'show': true, + // A floating point number in the range [0, 1]. The + // smaller the number, the more transparent will the + // legend background become. + 'backgroundOpacity': 0 - // A floating point number in the range [0, 1]. The - // smaller the number, the more transparent will the - // legend background become. - 'backgroundOpacity': 0 - - }, - 'grid': { - 'markings': generateMarkings() + }, + 'grid': { + 'markings': generateMarkings() + } } - } - ); + ); + } + // Otherwise, use stored plot object. + else { + plotObj.setData(dataSeries); + plotObj.setupGrid(); + plotObj.draw(); + } // The first time that the graph gets added to the page, the legend // is created from scratch. When it appears, MathJax works some @@ -909,7 +958,7 @@ define('Graph', ['logme'], function (logme) { if (asymptote.type === 'x') { markings.push({ 'color': asymptote.color, - 'lineWidth': 1, + 'lineWidth': 2, 'xaxis': { 'from': val, 'to': val @@ -918,7 +967,7 @@ define('Graph', ['logme'], function (logme) { } else { markings.push({ 'color': asymptote.color, - 'lineWidth': 1, + 'lineWidth': 2, 'yaxis': { 'from': val, 'to': val diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst_main.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst_main.js index bdbe317f36..71f946e312 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst_main.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/gst_main.js @@ -64,12 +64,12 @@ define( Sliders(gstId, state); Inputs(gstId, gstClass, state); + // Configure functions that output to an element instead of the graph. + ElOutput(config, state); + // Configure and display the graph. Attach event for the graph to be // updated on any change of a slider or a text input. Graph(gstId, config, state); - - // Configure functions that output to an element instead of the graph. - ElOutput(config, state); } }); diff --git a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js index 77423d2a20..3aea34ceb5 100644 --- a/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js +++ b/common/lib/xmodule/xmodule/js/src/graphical_slider_tool/state.js @@ -18,9 +18,10 @@ define('State', ['logme'], function (logme) { function State(gstId, config) { var parameters, allParameterNames, allParameterValues, - plotDiv, dynamicEl; + plotDiv, dynamicEl, dynamicElByElId; dynamicEl = []; + dynamicElByElId = {}; stateInst += 1; logme('MESSAGE: Creating state instance # ' + stateInst + '.'); @@ -95,7 +96,9 @@ define('State', ['logme'], function (logme) { 'getAllParameterValues': getAllParameterValues, 'bindUpdatePlotEvent': bindUpdatePlotEvent, - 'addDynamicEl': addDynamicEl + 'addDynamicEl': addDynamicEl, + + 'getFuncForSpecialLabel': getFuncForSpecialLabel }; function getAllParameterNames() { @@ -122,11 +125,33 @@ define('State', ['logme'], function (logme) { plotDiv.bind('update_plot', callback); } - function addDynamicEl(outputEl, func) { - dynamicEl.push({ - 'outputEl': outputEl, - 'func': func + function addDynamicEl(el, func, elId, special) { + var newLength; + + newLength = dynamicEl.push({ + 'el': el, + 'func': func, + 'elId': elId, + 'special': special }); + + if (typeof dynamicElByElId[elId] !== 'undefined') { + logme( + 'ERROR: Duplicate dynamic element ID "' + elId + '" found.' + ); + } else { + dynamicElByElId[elId] = dynamicEl[newLength - 1]; + } + } + + function getFuncForSpecialLabel(elId) { + if (typeof dynamicElByElId[elId] === 'undefined') { + logme('ERROR: Special label with ID "' + elId + '" does not exist.'); + + return null; + } + + return dynamicElByElId[elId].func; } function getParameterValue(paramName) { @@ -221,7 +246,9 @@ define('State', ['logme'], function (logme) { allParameterValues[parameters[paramName].helperArrayIndex] = paramValueNum; for (c1 = 0; c1 < dynamicEl.length; c1++) { - dynamicEl[c1].outputEl.html(dynamicEl[c1].func.apply(window, allParameterValues)); + if (dynamicEl[c1].special !== true) { + dynamicEl[c1].el.html(dynamicEl[c1].func.apply(window, allParameterValues)); + } } // If we have a plot DIV to work with, tell to update.